diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDataAdapter.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDataAdapter.java
index 34e2273989..71703dc0bd 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDataAdapter.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDataAdapter.java
@@ -20,6 +20,7 @@ import java.util.Collection;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.Address;
+import ghidra.program.model.data.TypeDefSettingsDefinition;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.SourceType;
import ghidra.trace.database.data.DBTraceDataSettingsOperations;
@@ -68,6 +69,15 @@ public interface DBTraceDataAdapter extends DBTraceCodeUnitAdapter, DataAdapterM
DBTraceDataSettingsOperations getSettingsSpace(boolean createIfAbsent);
+ @Override
+ default boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
+ if (settingsDefinition instanceof TypeDefSettingsDefinition) {
+ return false;
+ }
+ // assume instance setting allowed if default setting allowed
+ return getDefaultSettings().isChangeAllowed(settingsDefinition);
+ }
+
@Override
default void setLong(String name, long value) {
try (LockHold hold = getTrace().lockWrite()) {
diff --git a/Ghidra/Features/Base/build.gradle b/Ghidra/Features/Base/build.gradle
index 5b67b3061f..e5340b1370 100644
--- a/Ghidra/Features/Base/build.gradle
+++ b/Ghidra/Features/Base/build.gradle
@@ -65,6 +65,7 @@ dependencies {
testImplementation project(path: ':Generic', configuration: 'testArtifacts')
testImplementation project(path: ':Project', configuration: 'testArtifacts')
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
+ testImplementation project(path: ':DB', configuration: 'testArtifacts')
javacc 'net.java.dev.javacc:javacc:5.0'
}
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
index 715387aaad..d0694af781 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
@@ -800,7 +800,16 @@
A Typedef created with a Pointer base type will allow additional Settings to be made
which can influence how such a pointer should be interpretted
- (see Pointer-Typedef Settings).
+ (see Pointer-Typedef Settings).
+ If no name is assigned to a new Pointer-Typedef is will be treated as an "auto-typedef"
+ where a dynamic name will be assigned based upon the underlying pointer and assigned
+ typedef attribute settings. Examples:
+
+ - char * __((space(ram)))
+ - int * __((offset(0x8)))
+ - pointer __((image-base-relative))
+
+
Creating a Pointer
To create a pointer, you can click New
The following Pointer-Typedef settings are currently supported:
- Address Space (case-sensitive string) - Allows a specific address space to be associated with a pointer.
- If an unknown name is used it will be silently ignored.
+ If an unknown name is used it will be silently ignored. Auto name attribute format: __((space(name))
- Component Offset (signed value) - Allows a base-relative offset to be specified. When applied
to memory an Offset Reference will be generated. I addition, type analysis may use the offset to identify
- a component relative to the pointer's base-datatype (e.g., structure).
+ a component relative to the pointer's base-datatype (e.g., structure). Auto name attribute format: __((offset(signed_value))
- Offset Mask (64-bit mask) - Allows a bit-mask to be applied to a stored value when computing the
- absolute memory offset. This bit-mask will be applied prior to any applied bit-shift.
+ absolute memory offset. This bit-mask will be applied prior to any applied bit-shift. Auto name attribute format: __((mask(hex_mask))
- Offset Shift (-64..0..64) - Allows a bit-shift (left=negative, right=positive) to be applied to a
- stored value when computing the absolute memory offset.
- - Pointer Type (default, IBO, relative, file-offset) - allows the overall interpretation of a
+ stored value when computing the absolute memory offset. Auto name attribute format: __((shift(bitshift_amount))
+ - Pointer Type (default, image-base-relative, relative, file-offset) - allows the overall interpretation of a
pointer to be specified. The relative pointer type has limited applicabaility and is only
intended to be applied to pointers stored in memory since their storage location is used in computing
- the absolute address that the pointer refers to. (IBO: Image Base Offset Relative).
+ the absolute address that the pointer refers to.
All Typedef Settings must be established on
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
index 84b6f91a50..4f8e5c9aeb 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
@@ -665,7 +665,6 @@ public class DataTypeMergeManager implements MergeResolver {
* in RESULT; false if the data type did not have to be added
*/
private boolean dataTypeRenamedOrMoved(long id) {
-
DataType newDt = null;
switch (conflictOption) {
@@ -700,7 +699,7 @@ public class DataTypeMergeManager implements MergeResolver {
DataType resultDt = dtms[RESULT].getDataType(id);
DataType newDt = null;
if (resultDt != null) {
- setDataTypeName(resultDt, dt.getName());
+ setDataTypeName(resultDt, dt);
setCategoryPath(resultDt, dt.getCategoryPath());
}
else {
@@ -1645,8 +1644,12 @@ public class DataTypeMergeManager implements MergeResolver {
return;
}
}
- String name = category.getName();
- String newName = name;
+ String newName = category.getName();
+ String baseName = newName;
+ int index = newName.indexOf(DataType.CONFLICT_SUFFIX);
+ if (index > 0) {
+ baseName = newName.substring(0, index);
+ }
int oneUpNumber = 0;
while (true) {
try {
@@ -1656,7 +1659,7 @@ public class DataTypeMergeManager implements MergeResolver {
return;
}
++oneUpNumber;
- newName = name + DataType.CONFLICT_SUFFIX + oneUpNumber;
+ newName = baseName + DataType.CONFLICT_SUFFIX + oneUpNumber;
}
catch (DuplicateNameException e) {
throw new AssertException("Got DuplicateNameException");
@@ -1673,6 +1676,11 @@ public class DataTypeMergeManager implements MergeResolver {
return;
}
String name = newName;
+ String baseName = newName;
+ int index = newName.indexOf(DataType.CONFLICT_SUFFIX);
+ if (index > 0) {
+ baseName = newName.substring(0, index);
+ }
int oneUpNumber = 0;
while (true) {
try {
@@ -1681,7 +1689,7 @@ public class DataTypeMergeManager implements MergeResolver {
}
catch (DuplicateNameException e) {
++oneUpNumber;
- name = newName + DataType.CONFLICT_SUFFIX + oneUpNumber;
+ name = baseName + DataType.CONFLICT_SUFFIX + oneUpNumber;
}
catch (InvalidNameException e) {
throw new AssertException("Got InvalidNameException: " + e);
@@ -1689,20 +1697,31 @@ public class DataTypeMergeManager implements MergeResolver {
}
}
- private void setDataTypeName(DataType dt, String newName) {
+ private void setDataTypeName(DataType dt, DataType dtToCopy) {
+ if (isAutoNamedTypedef(dtToCopy)) {
+ if (dt instanceof TypeDef) {
+ ((TypeDef) dt).enableAutoNaming();
+ return;
+ }
+ }
+ String newName = dtToCopy.getName();
if (dt.getName().equals(newName)) {
return;
}
- String name = newName;
+ String baseName = newName;
+ int index = newName.indexOf(DataType.CONFLICT_SUFFIX);
+ if (index > 0) {
+ baseName = newName.substring(0, index);
+ }
int oneUpNumber = 0;
while (true) {
try {
- dt.setName(name);
+ dt.setName(newName);
return;
}
catch (DuplicateNameException e) {
++oneUpNumber;
- name = newName + DataType.CONFLICT_SUFFIX + oneUpNumber;
+ newName = baseName + DataType.CONFLICT_SUFFIX + oneUpNumber;
}
catch (InvalidNameException e) {
throw new AssertException("Got InvalidNameException: " + e);
@@ -1710,6 +1729,7 @@ public class DataTypeMergeManager implements MergeResolver {
}
}
+
private boolean categoryWasMoved(long id, DataTypeManager dtm1, DataTypeManager dtm2) {
Category cat1 = dtm1.getCategory(id);
Category cat2 = dtm2.getCategory(id);
@@ -1765,10 +1785,24 @@ public class DataTypeMergeManager implements MergeResolver {
return dataTypeWasRenamed(id, dtms[ORIGINAL], dtm);
}
+ private boolean isAutoNamedTypedef(DataType dt) {
+ if (dt instanceof TypeDef) {
+ TypeDef td = (TypeDef) dt;
+ return td.isAutoNamed();
+ }
+ return false;
+ }
+
private boolean dataTypeWasRenamed(long id, DataTypeManager dtm1, DataTypeManager dtm2) {
DataType dt1 = dtm1.getDataType(id);
DataType dt2 = dtm2.getDataType(id);
if (dt1 != null && dt2 != null) {
+ if (isAutoNamedTypedef(dt1)) {
+ return isAutoNamedTypedef(dt2);
+ }
+ else if (isAutoNamedTypedef(dt2)) {
+ return false;
+ }
String name1 = dt1.getName();
String name2 = dt2.getName();
return !name1.equals(name2);
@@ -2695,7 +2729,7 @@ public class DataTypeMergeManager implements MergeResolver {
DataType dt = dtms[RESULT].getDataType(id);
if (dataTypeWasRenamed(id, dtms[MY])) {
if (dt != null) {
- setDataTypeName(dt, myDt.getName());
+ setDataTypeName(dt, myDt);
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/propertylist/PropertyListMergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/propertylist/PropertyListMergeManager.java
index 9c1550817d..c24c055bac 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/propertylist/PropertyListMergeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/propertylist/PropertyListMergeManager.java
@@ -57,7 +57,6 @@ public class PropertyListMergeManager implements MergeResolver {
private int currentConflict;
private int totalConflictCount;
private ProgramMultiUserMergeManager mergeManager;
- private int progressIndex;
private int propertyListChoice = ASK_USER;
/**
@@ -157,7 +156,7 @@ public class PropertyListMergeManager implements MergeResolver {
}
}
mergeManager.updateProgress(100);
- currentMonitor.initialize(myNamesCount);
+
try {
processConflicts();
commit = true;
@@ -193,7 +192,6 @@ public class PropertyListMergeManager implements MergeResolver {
return;
}
addProperty(list, resultList, optionName);
- currentMonitor.setProgress(++progressIndex);
}
}
@@ -251,7 +249,6 @@ public class PropertyListMergeManager implements MergeResolver {
if (latestValue.equals(origValue)) {
latestList.removeOption(propertyName);
- currentMonitor.setProgress(++progressIndex);
}
else {
String listName = latestList.getName();
@@ -275,25 +272,28 @@ public class PropertyListMergeManager implements MergeResolver {
Object resultValue = getValue(resultList, propertyName);
Object origValue = getValue(origList, propertyName);
- if (!SystemUtilities.isEqual(resultValue, myValue)) {
- if (propertyName.equals(Program.ANALYZED) && (myValue instanceof Boolean)) {
- // If latest or my version sets "Analyzed" to true, then it should result in true.
- setValue(resultList, propertyName, myList.getType(propertyName), Boolean.TRUE);
- currentMonitor.setProgress(++progressIndex);
- return;
- }
- if (SystemUtilities.isEqual(resultValue, origValue)) {
- setValue(resultList, propertyName, myList.getType(propertyName), myValue);
- currentMonitor.setProgress(++progressIndex);
- }
- else {
- String listName = resultList.getName();
- ArrayList mapList = getConflictList(listName);
- mapList.add(new ConflictInfo(listName, propertyName,
- resultList.getType(propertyName), myList.getType(propertyName),
- origList.getType(propertyName), resultValue, myValue, origValue));
- ++totalConflictCount;
- }
+ if (SystemUtilities.isEqual(origValue, myValue) ||
+ SystemUtilities.isEqual(resultValue, myValue)) {
+ // value was not modified in my program or it was changed the same as in latest
+ return;
+ }
+ if (propertyName.equals(Program.ANALYZED) && Boolean.TRUE.equals(myValue)) {
+ // If my version sets "Analyzed" to true, then it should result in true.
+ setValue(resultList, propertyName, myList.getType(propertyName), Boolean.TRUE);
+ return;
+ }
+ if (SystemUtilities.isEqual(resultValue, origValue)) {
+ // no change by latest - use my value
+ setValue(resultList, propertyName, myList.getType(propertyName), myValue);
+ }
+ else {
+ // my change conflicts with latest change
+ String listName = resultList.getName();
+ ArrayList mapList = getConflictList(listName);
+ mapList.add(new ConflictInfo(listName, propertyName,
+ resultList.getType(propertyName), myList.getType(propertyName),
+ origList.getType(propertyName), resultValue, myValue, origValue));
+ ++totalConflictCount;
}
}
@@ -322,7 +322,6 @@ public class PropertyListMergeManager implements MergeResolver {
if (!myValue.equals(origValue)) {
setValue(resultList, propertyName, myList.getType(propertyName), myValue);
- currentMonitor.setProgress(++progressIndex);
}
}
@@ -412,7 +411,7 @@ public class PropertyListMergeManager implements MergeResolver {
String currentListName) throws CancelledException {
for (int i = 0; i < conflictList.size(); i++) {
- currentMonitor.setProgress(++progressIndex);
+ currentMonitor.setProgress(i);
ConflictInfo info = conflictList.get(i);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/AbstractSettingsDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/AbstractSettingsDialog.java
index aadd6ecd3e..8af34f0823 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/AbstractSettingsDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/AbstractSettingsDialog.java
@@ -67,7 +67,11 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
Settings originalSettings) {
super(title, true, false, true, false);
this.settingsDefinitions = settingDefinitions;
- settings = new SettingsImpl(originalSettings);
+ settings = new SettingsImpl(originalSettings) {
+ public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
+ return originalSettings.isChangeAllowed(settingsDefinition);
+ }
+ };
defaultSettings = settings.getDefaultSettings();
if (originalSettings != null && defaultSettings == null) {
// ensure we have defaults to facilitate revert to default
@@ -206,6 +210,17 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
workPanel.add(scrollpane, BorderLayout.CENTER);
+ boolean hasImmutableSettings = false;
+ for (SettingsDefinition def : settingsDefinitions) {
+ if (!settings.isChangeAllowed(def)) {
+ hasImmutableSettings = true;
+ break;
+ }
+ }
+ if (hasImmutableSettings) {
+ workPanel.add(new JLabel("* Immutable setting"), BorderLayout.SOUTH);
+ }
+
return workPanel;
}
@@ -366,6 +381,10 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
return definition.getName();
}
+ boolean isEditable() {
+ return settings.isChangeAllowed(definition);
+ }
+
Object getSettingsObject() {
if (definition instanceof EnumSettingsDefinition) {
StringChoices choices = getChoices((EnumSettingsDefinition) definition);
@@ -464,7 +483,11 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
@Override
public boolean isCellEditable(int row, int col) {
- return col != 0;
+ if (col == 0) {
+ return false;
+ }
+ SettingsRowObject rowObject = rows.get(row);
+ return rowObject.isEditable();
}
@Override
@@ -503,7 +526,11 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
public Object getColumnValueForRow(SettingsRowObject t, int columnIndex) {
switch (columnIndex) {
case 0:
- return t.getName();
+ String name = t.getName();
+ if (!t.isEditable()) {
+ name += "*"; // append immutable indicator
+ }
+ return name;
case 1:
return t.getSettingsObject();
case 2:
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/DataTypeSettingsDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/DataTypeSettingsDialog.java
index 66a8429673..206f67ec26 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/DataTypeSettingsDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/DataTypeSettingsDialog.java
@@ -63,6 +63,8 @@ public class DataTypeSettingsDialog extends AbstractSettingsDialog {
if (dtm instanceof DataTypeManagerDB) {
long id = dtm.getID(dt);
if (id > 0) {
+ // FIXME: this does not handle re-mapped BuiltIn datatypes
+ // since multiple instances may be defined
if (dt == dtm.getDataType(id)) {
return; // valid original instance
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncInfo.java
index 3e4fb55ce8..9045246d16 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncInfo.java
@@ -144,7 +144,7 @@ public class DataTypeSyncInfo {
}
public String getRefDtPath() {
- return refDt.getPathName();
+ return refDt.getCategoryPath().getPath();
}
public long getLastChangeTime(boolean useSource) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java
index 30bf283847..3e6a3a15b1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java
@@ -119,7 +119,7 @@ public class DataTypeSynchronizer {
long lastChangeTime = refDT.getLastChangeTime();
DataType sourceDT = sourceDTM.resolve(refDT, DataTypeConflictHandler.REPLACE_HANDLER);
if (!namesAreEquivalent(refDT, sourceDT)) {
- renameDataType(sourceDTM, sourceDT, refDT.getName());
+ renameDataType(sourceDTM, sourceDT, refDT);
}
if (!StringUtils.equals(refDT.getDescription(), sourceDT.getDescription())) {
sourceDT.setDescription(refDT.getDescription());
@@ -132,7 +132,7 @@ public class DataTypeSynchronizer {
long lastChangeTime = sourceDT.getLastChangeTime();
DataType refDT = refDTM.resolve(sourceDT, DataTypeConflictHandler.REPLACE_HANDLER);
if (!namesAreEquivalent(refDT, sourceDT)) {
- renameDataType(refDTM, refDT, sourceDT.getName());
+ renameDataType(refDTM, refDT, sourceDT);
}
if (!StringUtils.equals(sourceDT.getDescription(), refDT.getDescription())) {
refDT.setDescription(sourceDT.getDescription());
@@ -231,7 +231,15 @@ public class DataTypeSynchronizer {
}
}
- private static void renameDataType(DataTypeManager sourceDTM, DataType sourceDT, String name) {
+ private static void renameDataType(DataTypeManager sourceDTM, DataType sourceDT,
+ DataType dtToCopy) {
+ if (isAutoNamedTypedef(dtToCopy)) {
+ if (sourceDT instanceof TypeDef) {
+ ((TypeDef) sourceDT).enableAutoNaming();
+ return;
+ }
+ }
+ String name = dtToCopy.getName();
int index = name.indexOf(DataType.CONFLICT_SUFFIX);
if (index > 0) {
name = name.substring(0, index);
@@ -254,7 +262,21 @@ public class DataTypeSynchronizer {
}
}
+ private static boolean isAutoNamedTypedef(DataType dt) {
+ if (dt instanceof TypeDef) {
+ TypeDef td = (TypeDef) dt;
+ return td.isAutoNamed();
+ }
+ return false;
+ }
+
public static boolean namesAreEquivalent(DataType dt1, DataType dt2) {
+ if (isAutoNamedTypedef(dt1)) {
+ return isAutoNamedTypedef(dt2);
+ }
+ else if (isAutoNamedTypedef(dt2)) {
+ return false;
+ }
String name1 = dt1.getName();
String name2 = dt2.getName();
if (name1.equals(name2)) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/AbstractTypeDefAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/AbstractTypeDefAction.java
index 92695f11fa..4c9d9582f4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/AbstractTypeDefAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/AbstractTypeDefAction.java
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
- * REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,16 +15,17 @@
*/
package ghidra.app.plugin.core.datamgr.actions;
-import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
-import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
-import ghidra.program.model.data.*;
-
import java.awt.Component;
+import org.apache.commons.lang3.StringUtils;
+
import docking.ActionContext;
import docking.ComponentProvider;
import docking.action.DockingAction;
import docking.widgets.tree.GTreeNode;
+import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
+import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
+import ghidra.program.model.data.*;
abstract class AbstractTypeDefAction extends DockingAction {
@@ -55,15 +55,27 @@ abstract class AbstractTypeDefAction extends DockingAction {
return null;
}
- return createNewDataType(gTree, dataType, categoryPath, dataTypeManager, typeDefName);
+ if (StringUtils.isBlank(typeDefName)) {
+ // use auto-naming for pointer-typedef
+ if (dataType instanceof Pointer) {
+ // category ignored
+ TypeDef typedef = new PointerTypedef(null, (Pointer) dataType, dataTypeManager);
+ return createNewTypeDef(gTree, typedef, categoryPath, dataTypeManager);
+ }
+ // generate default typedef name
+ String baseName = getBaseName(dataType) + "Typedef";
+ typeDefName = dataTypeManager.getUniqueName(dataType.getCategoryPath(), baseName);
+ }
+
+ TypeDef typedef = new TypedefDataType(categoryPath, typeDefName, dataType);
+ return createNewTypeDef(gTree, typedef, categoryPath, dataTypeManager);
}
- private DataType createNewDataType(Component parentComponent, DataType dataType,
- CategoryPath categoryPath, DataTypeManager dataTypeManager, String name) {
+ private DataType createNewTypeDef(Component parentComponent, TypeDef typedef,
+ CategoryPath categoryPath, DataTypeManager dataTypeManager) {
DataType newdt = null;
int transactionID = dataTypeManager.startTransaction("Create Typedef");
try {
- DataType typedef = new TypedefDataType(categoryPath, name, dataType);
newdt = dataTypeManager.addDataType(typedef, plugin.getConflictHandler());
}
finally {
@@ -72,4 +84,16 @@ abstract class AbstractTypeDefAction extends DockingAction {
return newdt;
}
+
+ protected static String getBaseName(DataType dt) {
+ if (dt instanceof Pointer) {
+ DataType dataType = ((Pointer) dt).getDataType();
+ if (dataType == null) {
+ // must be a generic pointer type
+ return dt.getName();
+ }
+ return getBaseName(dataType) + "Ptr";
+ }
+ return dt.getDisplayName();
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateTypeDefAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateTypeDefAction.java
index 22e5fa35f1..2e6a1793a7 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateTypeDefAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateTypeDefAction.java
@@ -113,16 +113,15 @@ public class CreateTypeDefAction extends AbstractTypeDefAction {
DataTypeNode dataTypeNode = (DataTypeNode) selectionPaths[0].getLastPathComponent();
DataType dataType = dataTypeNode.getDataType();
- String baseName = getBaseName(dataType) + "Typedef";
+
DerivativeDataTypeInfo info =
new DerivativeDataTypeInfo(plugin, gTree, dataTypeNode, dataType);
DataTypeManager dataTypeManager = info.getDataTypeManager();
- String name = dataTypeManager.getUniqueName(dataType.getCategoryPath(), baseName);
CategoryPath categoryPath = info.getCategoryPath();
DataType newTypeDef = createTypeDef(dataTypeManager, dataType, categoryPath, context,
- dataTypeNode.getParent(), name);
+ dataTypeNode.getParent(), null);
if (newTypeDef == null) {
return;
}
@@ -133,15 +132,5 @@ public class CreateTypeDefAction extends AbstractTypeDefAction {
gTree.startEditing(finalParentNode, newNodeName);
}
- private static String getBaseName(DataType dt) {
- if (dt instanceof Pointer) {
- DataType dataType = ((Pointer) dt).getDataType();
- if (dataType == null) {
- // must be a generic pointer type
- return dt.getName();
- }
- return getBaseName(dataType) + "Ptr";
- }
- return dt.getDisplayName();
- }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/hover/AbstractReferenceHover.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/hover/AbstractReferenceHover.java
index 0da7e2667a..c69538acc8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/hover/AbstractReferenceHover.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/hover/AbstractReferenceHover.java
@@ -176,6 +176,13 @@ public abstract class AbstractReferenceHover extends AbstractConfigurableHover {
return null;
}
+ if (programLocation instanceof MnemonicFieldLocation) {
+ CodeUnit cu = program.getListing().getCodeUnitAt(programLocation.getAddress());
+ if (!(cu instanceof Instruction)) {
+ return null; // defer to mnemonic hover for Data
+ }
+ }
+
Address refAddr = programLocation.getRefAddress();
if (refAddr != null && refAddr.isExternalAddress()) {
return createExternalToolTipComponent(program, refAddr);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerComponent.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerComponent.java
index 436a21a894..b49678f762 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerComponent.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerComponent.java
@@ -118,7 +118,6 @@ class DbViewerComponent extends JPanel {
if (dbh == null) {
return;
}
- Msg.info(this, "Updating dbViewer...");
synchronized (dbh) {
updateTableChoices((TableItem) combo.getSelectedItem());
updateTable();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/StructConverter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/StructConverter.java
index 23259ebcfe..68b779cf61 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/StructConverter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/StructConverter.java
@@ -70,11 +70,11 @@ public interface StructConverter {
/**
* Reusable 32-bit image base offset datatype.
*/
- public final static DataType IBO32 = new ImageBaseOffset32DataType();
+ public final static DataType IBO32 = IBO32DataType.dataType;
/**
* Reusable 64-bit image base offset datatype.
*/
- public final static DataType IBO64 = new ImageBaseOffset64DataType();
+ public final static DataType IBO64 = IBO64DataType.dataType;
/**
* Returns a structure datatype representing the
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ControlFlowGuard.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ControlFlowGuard.java
index 35048f503f..5f227d7296 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ControlFlowGuard.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ControlFlowGuard.java
@@ -173,7 +173,7 @@ public class ControlFlowGuard {
IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT;
// Pre-define base data types used to define table entry data type
- DataType ibo32 = new ImageBaseOffset32DataType();
+ DataType ibo32 = new IBO32DataType();
DataType byteType = ByteDataType.dataType;
CategoryPath categoryPath = new CategoryPath(CategoryPath.ROOT, "CFG");
@@ -255,7 +255,7 @@ public class ControlFlowGuard {
program.getSymbolTable()
.createLabel(tableAddr, GuardCFAddressTakenIatTableName, SourceType.IMPORTED);
// Each table entry is an RVA (32-bit image base offset)
- DataType ibo32 = new ImageBaseOffset32DataType();
+ DataType ibo32 = new IBO32DataType();
for (long i = 0; i < functionCount; i++) {
Data d =
PeUtils.createData(program, tableAddr.add(i * ibo32.getLength()), ibo32, log);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/DelayImportDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/DelayImportDescriptor.java
index ae65465baa..1c104676d4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/DelayImportDescriptor.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/DelayImportDescriptor.java
@@ -299,7 +299,7 @@ public class DelayImportDescriptor implements StructConverter {
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
- DataType ibo32 = new ImageBaseOffset32DataType();
+ DataType ibo32 = new IBO32DataType();
StructureDataType struct = new StructureDataType(NAME, 0);
struct.add(DWORD, "grAttrs", null);
struct.add(ibo32, "szName", null);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDataDirectory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDataDirectory.java
index c7ee77b6d8..6ad74e69e7 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDataDirectory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDataDirectory.java
@@ -84,7 +84,8 @@ public class LoadConfigDataDirectory extends DataDirectory {
if (monitor.isCancelled()) {
return;
}
- DataType dt = ntHeader.getOptionalHeader().is64bit() ? new ImageBaseOffset64DataType() : new ImageBaseOffset32DataType();
+ DataType dt = ntHeader.getOptionalHeader().is64bit() ? IBO64DataType.dataType
+ : IBO32DataType.dataType;
PeUtils.createData(program, addr, dt, log);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java
index 7d74a0bf4c..f6b71959d8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java
@@ -34,7 +34,7 @@ public class PEx64UnwindInfoDataType extends DynamicDataType {
private final static int UNWIND_OP_INFO_FIELD_LENGTH = 0x04;
private final static DataType BYTE = ByteDataType.dataType;
- private final static DataType IBO32 = new ImageBaseOffset32DataType();
+ private final static DataType IBO32 = new IBO32DataType();
public PEx64UnwindInfoDataType() {
this(null);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/MSDataTypeUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/MSDataTypeUtils.java
index 7b56c34661..d5b8ddbe43 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/MSDataTypeUtils.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/MSDataTypeUtils.java
@@ -273,7 +273,7 @@ public class MSDataTypeUtils {
*/
public static DataType getReferenceDataType(Program program, DataType referredToDataType) {
DataTypeManager dtm = program.getDataTypeManager();
- return is64Bit(program) ? new ImageBaseOffset32DataType(dtm)
+ return is64Bit(program) ? new IBO32DataType(dtm)
: new PointerDataType(referredToDataType);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/TypeDefDataTypeHTMLRepresentation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/TypeDefDataTypeHTMLRepresentation.java
index a60b5fdfb9..38b7445ef1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/TypeDefDataTypeHTMLRepresentation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/TypeDefDataTypeHTMLRepresentation.java
@@ -86,9 +86,6 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
DataType basedataType = dataType;
while (basedataType instanceof TypeDef) {
basedataType = ((TypeDef) basedataType).getDataType();
- while (basedataType instanceof Pointer) {
- basedataType = ((Pointer) basedataType).getDataType();
- }
}
return basedataType;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/ByteCountSettingsDefinition.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/ByteCountSettingsDefinition.java
index 537bc1e877..f698a23633 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/ByteCountSettingsDefinition.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/ByteCountSettingsDefinition.java
@@ -71,6 +71,11 @@ public class ByteCountSettingsDefinition implements EnumSettingsDefinition {
return BYTE_COUNT;
}
+ @Override
+ public String getStorageKey() {
+ return BYTE_COUNT;
+ }
+
@Override
public String getDescription() {
return "Selects the number of bytes to display";
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/CodeUnitCountSettingsDefinition.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/CodeUnitCountSettingsDefinition.java
index 53c2968ee3..10cb074c9a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/CodeUnitCountSettingsDefinition.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/CodeUnitCountSettingsDefinition.java
@@ -90,6 +90,11 @@ public class CodeUnitCountSettingsDefinition implements EnumSettingsDefinition {
return CODE_UNIT_COUNT;
}
+ @Override
+ public String getStorageKey() {
+ return CODE_UNIT_COUNT;
+ }
+
@Override
public String getDescription() {
return "Selects the number of bytes to display";
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/CodeUnitOffsetSettingsDefinition.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/CodeUnitOffsetSettingsDefinition.java
index 93996d63d0..0921e229b5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/CodeUnitOffsetSettingsDefinition.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/CodeUnitOffsetSettingsDefinition.java
@@ -92,6 +92,11 @@ public class CodeUnitOffsetSettingsDefinition implements EnumSettingsDefinition
return MEMORY_OFFSET;
}
+ @Override
+ public String getStorageKey() {
+ return MEMORY_OFFSET;
+ }
+
@Override
public String getDescription() {
return "Selects the relative byte offset from which to display";
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionInlineSettingsDefinition.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionInlineSettingsDefinition.java
index 9f9ae3f3ee..fee69246e8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionInlineSettingsDefinition.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionInlineSettingsDefinition.java
@@ -77,6 +77,11 @@ public class FunctionInlineSettingsDefinition implements BooleanSettingsDefiniti
return NAME;
}
+ @Override
+ public String getStorageKey() {
+ return INLINE;
+ }
+
@Override
public boolean hasValue(Settings settings) {
return settings.getValue(INLINE) != null;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionNoReturnSettingsDefinition.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionNoReturnSettingsDefinition.java
index 1760178a24..38c2baa4e4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionNoReturnSettingsDefinition.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionNoReturnSettingsDefinition.java
@@ -77,6 +77,11 @@ public class FunctionNoReturnSettingsDefinition implements BooleanSettingsDefini
return NAME;
}
+ @Override
+ public String getStorageKey() {
+ return NORETURN;
+ }
+
@Override
public boolean hasValue(Settings settings) {
return settings.getValue(NORETURN) != null;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionThunkSettingsDefinition.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionThunkSettingsDefinition.java
index 138473874d..aaad3631bd 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionThunkSettingsDefinition.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/FunctionThunkSettingsDefinition.java
@@ -76,6 +76,11 @@ public class FunctionThunkSettingsDefinition implements BooleanSettingsDefinitio
return NAME;
}
+ @Override
+ public String getStorageKey() {
+ return THUNK;
+ }
+
@Override
public boolean hasValue(Settings settings) {
return settings.getValue(THUNK) != null;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/MemoryOffsetSettingsDefinition.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/MemoryOffsetSettingsDefinition.java
index 046c589c45..f9d923c4bc 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/MemoryOffsetSettingsDefinition.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/MemoryOffsetSettingsDefinition.java
@@ -91,6 +91,11 @@ public class MemoryOffsetSettingsDefinition implements EnumSettingsDefinition {
return MEMORY_OFFSET;
}
+ @Override
+ public String getStorageKey() {
+ return MEMORY_OFFSET;
+ }
+
@Override
public String getDescription() {
return "Selects the relative byte offset from which to display";
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge5Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge5Test.java
index a28f076ec9..dd943adc02 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge5Test.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge5Test.java
@@ -24,6 +24,7 @@ import org.junit.Test;
import ghidra.docking.settings.Settings;
import ghidra.program.database.*;
+import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.util.InvalidNameException;
@@ -1433,7 +1434,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
// NOTE: these are not viable settings but are intended to exercise all of them
Settings settings = td.getDefaultSettings();
PointerTypeSettingsDefinition.DEF.setType(settings,
- PointerType.IBO);
+ PointerType.IMAGE_BASE_RELATIVE);
AddressSpaceSettingsDefinition.DEF.setValue(settings, "ROM");
ComponentOffsetSettingsDefinition.DEF.setValue(settings, 0x10);
OffsetMaskSettingsDefinition.DEF.setValue(settings, 0x1234);
@@ -1515,6 +1516,211 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
checkConflictCount(0);
}
+ private static String formatAttributes(String attrs) {
+ StringBuilder buf = new StringBuilder(DataType.TYPEDEF_ATTRIBUTE_PREFIX);
+ buf.append(attrs);
+ buf.append(DataType.TYPEDEF_ATTRIBUTE_SUFFIX);
+ return buf.toString();
+ }
+
+ @Test
+ public void testTypeDefs11() throws Exception {
+
+ // Exercise pointer-typedef auto-naming with setting changes
+
+ mtf.initialize("notepad2", new OriginalProgramModifierListener() {
+
+ @Override
+ public void modifyOriginal(ProgramDB program) throws Exception {
+ boolean commit = false;
+ DataTypeManager dtm = program.getDataTypeManager();
+ int transactionID = program.startTransaction("test");
+ try {
+ // must specify datatype manager when constructing to allow for settings to be made
+ Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
+ PointerTypedef td =
+ new PointerTypedef(null, foo, -1, dtm, PointerType.IMAGE_BASE_RELATIVE);
+ DataType dt = dtm.resolve(td, DataTypeConflictHandler.DEFAULT_HANDLER);
+ assertEquals("Foo * " + formatAttributes("image-base-relative"), dt.getName());
+ commit = true;
+ }
+ finally {
+ program.endTransaction(transactionID, commit);
+ }
+ }
+
+ @Override
+ public void modifyLatest(ProgramDB program) {
+ boolean commit = false;
+ DataTypeManager dtm = program.getDataTypeManager();
+ int transactionID = program.startTransaction("test");
+ try {
+ TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"),
+ "Foo * " + formatAttributes("image-base-relative"));
+ assertNotNull(td);
+ td.setName("Bob_Ptr_Td");
+
+ Settings settings = td.getDefaultSettings();
+ PointerTypeSettingsDefinition.DEF.setType(settings,
+ PointerType.RELATIVE);
+
+ Structure st = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
+ st.setName("Bob");
+
+ commit = true;
+ }
+ catch (InvalidNameException | DuplicateNameException e) {
+ failWithException("unexpected", e);
+ }
+ finally {
+ program.endTransaction(transactionID, commit);
+ }
+ }
+
+ @Override
+ public void modifyPrivate(ProgramDB program) {
+ boolean commit = false;
+ DataTypeManager dtm = program.getDataTypeManager();
+ int transactionID = program.startTransaction("test");
+ try {
+ TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"),
+ "Foo * " + formatAttributes("image-base-relative"));
+ assertNotNull(td);
+
+ Settings settings = td.getDefaultSettings();
+ ComponentOffsetSettingsDefinition.DEF.setValue(settings, 0x123);
+
+ Structure st = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
+ st.setName("Bill");
+
+ commit = true;
+ }
+ catch (InvalidNameException | DuplicateNameException e) {
+ failWithException("unexpected", e);
+ }
+ finally {
+ program.endTransaction(transactionID, commit);
+ }
+ }
+ });
+ executeMerge();
+
+ chooseOption(DataTypeMergeManager.OPTION_MY); // choose Bill rename of Foo
+ chooseOption(DataTypeMergeManager.OPTION_LATEST); // choose RELATIVE setting and Bob_Ptr_Td rename
+
+ waitForCompletion();
+
+ DataTypeManager dtm = resultProgram.getDataTypeManager();
+ TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "Bob_Ptr_Td");
+ assertNotNull(td);
+
+ DataType dt = DataTypeUtilities.getBaseDataType(td.getDataType());
+ assertTrue(dt instanceof Structure);
+ assertEquals("Bill", dt.getName());
+
+ Settings settings = td.getDefaultSettings();
+ assertEquals(
+ "Expected pointer-typedef type: relative",
+ PointerType.RELATIVE, PointerTypeSettingsDefinition.DEF.getType(settings));
+ assertFalse(
+ "Unexpected setting: " +
+ ComponentOffsetSettingsDefinition.DEF.getAttributeSpecification(settings),
+ ComponentOffsetSettingsDefinition.DEF.hasValue(settings));
+
+ checkConflictCount(0);
+ }
+
+ @Test
+ public void testTypeDefs12() throws Exception {
+
+ // Exercise pointer-typedef auto-naming with setting changes
+
+ mtf.initialize("notepad2", new OriginalProgramModifierListener() {
+
+ @Override
+ public void modifyOriginal(ProgramDB program) throws Exception {
+ boolean commit = false;
+ DataTypeManager dtm = program.getDataTypeManager();
+ int transactionID = program.startTransaction("test");
+ try {
+ // must specify datatype manager when constructing to allow for settings to be made
+ Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
+ PointerTypedef td =
+ new PointerTypedef(null, foo, -1, dtm, PointerType.IMAGE_BASE_RELATIVE);
+ DataType dt = dtm.resolve(td, DataTypeConflictHandler.DEFAULT_HANDLER);
+ assertEquals("Foo * " + formatAttributes("image-base-relative"), dt.getName());
+ commit = true;
+ }
+ finally {
+ program.endTransaction(transactionID, commit);
+ }
+ }
+
+ @Override
+ public void modifyLatest(ProgramDB program) {
+ boolean commit = false;
+ DataTypeManager dtm = program.getDataTypeManager();
+ int transactionID = program.startTransaction("test");
+ try {
+ TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"),
+ "Foo * " + formatAttributes("image-base-relative"));
+ assertNotNull(td);
+ td.setName("Bob_Ptr_Td");
+
+ Settings settings = td.getDefaultSettings();
+ PointerTypeSettingsDefinition.DEF.setType(settings,
+ PointerType.RELATIVE);
+
+ commit = true;
+ }
+ catch (InvalidNameException | DuplicateNameException e) {
+ failWithException("unexpected", e);
+ }
+ finally {
+ program.endTransaction(transactionID, commit);
+ }
+ }
+
+ @Override
+ public void modifyPrivate(ProgramDB program) {
+ boolean commit = false;
+ DataTypeManager dtm = program.getDataTypeManager();
+ int transactionID = program.startTransaction("test");
+ try {
+ Structure st = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
+ st.setName("Bill");
+ commit = true;
+ }
+ catch (InvalidNameException | DuplicateNameException e) {
+ failWithException("unexpected", e);
+ }
+ finally {
+ program.endTransaction(transactionID, commit);
+ }
+ }
+ });
+ executeMerge(true);
+
+ DataTypeManager dtm = resultProgram.getDataTypeManager();
+ TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "Bob_Ptr_Td");
+ assertNotNull(td);
+
+ DataType dt = DataTypeUtilities.getBaseDataType(td.getDataType());
+ assertTrue(dt instanceof Structure);
+ assertEquals("Bill", dt.getName());
+
+ Settings settings = td.getDefaultSettings();
+ assertEquals(
+ "Expected pointer-typedef type: relative",
+ PointerType.RELATIVE, PointerTypeSettingsDefinition.DEF.getType(settings));
+ assertFalse(
+ "Unexpected setting: " +
+ ComponentOffsetSettingsDefinition.DEF.getAttributeSpecification(settings),
+ ComponentOffsetSettingsDefinition.DEF.hasValue(settings));
+
+ checkConflictCount(0);
+ }
+
@Test
public void testArrays() throws Exception {
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/ProgramContextMergeManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/ProgramContextMergeManagerTest.java
index 0666acc30c..0441079c0a 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/ProgramContextMergeManagerTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/ProgramContextMergeManagerTest.java
@@ -15,8 +15,7 @@
*/
package ghidra.app.merge.listing;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.*;
import java.awt.Window;
import java.math.BigInteger;
@@ -1165,7 +1164,7 @@ public class ProgramContextMergeManagerTest extends AbstractListingMergeManagerT
*/
@Override
public Address addr(String address) {
- return mtf.getResultProgram().getAddressFactory().getAddress(address);
+ return mtf.getOriginalProgram().getAddressFactory().getAddress(address);
}
private void setRegValue(ProgramContext pc, Address start, Address end, Register reg,
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/propertylist/PropertyListMergeManager2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/propertylist/PropertyListMergeManager2Test.java
index 198f43d9e7..0be82b314a 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/propertylist/PropertyListMergeManager2Test.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/propertylist/PropertyListMergeManager2Test.java
@@ -522,19 +522,7 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
@Test
public void testAnalyzedFalseInLatest() throws Exception {
- mtf.initialize("notepad", new OriginalProgramModifierListener() {
-
- @Override
- public void modifyOriginal(ProgramDB program) throws Exception {
- int transactionID = program.startTransaction("test");
- try {
- Options list = program.getOptions("Program Information");
- list.setBoolean("Analyzed", false);
- }
- finally {
- program.endTransaction(transactionID, true);
- }
- }
+ mtf.initialize("notepad", new ProgramModifierListener() {
@Override
public void modifyLatest(ProgramDB program) {
@@ -605,19 +593,7 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
@Test
public void testAnalyzedFalseInMy() throws Exception {
- mtf.initialize("notepad", new OriginalProgramModifierListener() {
-
- @Override
- public void modifyOriginal(ProgramDB program) throws Exception {
- int transactionID = program.startTransaction("test");
- try {
- Options list = program.getOptions("Program Information");
- list.setBoolean("Analyzed", false);
- }
- finally {
- program.endTransaction(transactionID, true);
- }
- }
+ mtf.initialize("notepad", new ProgramModifierListener() {
@Override
public void modifyLatest(ProgramDB program) {
@@ -734,10 +710,20 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
public void testAnalyzedTrueInLatestFalseInMy() throws Exception {
// test case: conflict because both values changed
// Choose 'latest'
- mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+ mtf.initialize("notepad", new OriginalProgramModifierListener() {
+
+ @Override
+ public void modifyOriginal(ProgramDB program) throws Exception {
+ int transactionID = program.startTransaction("test");
+ try {
+ Options list = program.getOptions("Program Information");
+ list.setBoolean("Analyzed", false); // revert to default state
+ }
+ finally {
+ program.endTransaction(transactionID, true);
+ }
+ }
+
@Override
public void modifyLatest(ProgramDB program) {
int transactionID = program.startTransaction("test");
@@ -777,10 +763,20 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
public void testAnalyzedFalseInLatestTrueInMy() throws Exception {
// test case: conflict because both values changed
// Choose 'latest'
- mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+ mtf.initialize("notepad", new OriginalProgramModifierListener() {
+
+ @Override
+ public void modifyOriginal(ProgramDB program) throws Exception {
+ int transactionID = program.startTransaction("test");
+ try {
+ Options list = program.getOptions("Program Information");
+ list.setBoolean("Analyzed", false); // revert to default value
+ }
+ finally {
+ program.endTransaction(transactionID, true);
+ }
+ }
+
@Override
public void modifyLatest(ProgramDB program) {
int transactionID = program.startTransaction("test");
@@ -793,9 +789,6 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
int transactionID = program.startTransaction("test");
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MoveBlockModelTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MoveBlockModelTest.java
index f18dcd8a4f..aeb266dde1 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MoveBlockModelTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/memory/MoveBlockModelTest.java
@@ -25,6 +25,8 @@ import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.ProgramBasedDataTypeManager;
+import ghidra.program.model.data.StringDataType;
+import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
@@ -44,6 +46,10 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
private volatile boolean success;
private volatile String errMsg;
+ // Suitable settings allowed for StringDataType data
+ private static String LONG_SETTING_NAME = "mutability";
+ private static String STRING_SETTING_NAME = "charset";
+
private Program buildProgram1(String programName) throws Exception {
ProgramBuilder builder = new ProgramBuilder(programName, ProgramBuilder._TOY);
builder.createMemory(".text", Long.toHexString(0x1001000), 0x6600);
@@ -80,11 +86,13 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
model.initialize(block);
int transactionID = x8051.startTransaction("Set settings");
+
ProgramBasedDataTypeManager dtm = x8051.getDataTypeManager();
for (int i = 0; i < 10; i++) {
Address a = getAddr(x8051, "BITS", i);
- dtm.setStringSettingsValue(a, "color", "red" + i);
- dtm.setLongSettingsValue(a, "someLongValue", i);
+ Data d = x8051.getListing().createData(a, StringDataType.dataType, 1);
+ dtm.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
+ dtm.setLongSettingsValue(d, LONG_SETTING_NAME, i);
}
x8051.endTransaction(transactionID, true);
}
@@ -198,11 +206,13 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
ProgramBasedDataTypeManager dtm = x8051.getDataTypeManager();
for (int i = 0; i < 10; i++) {
Address a = getAddr(x8051, "CODE", 0x2000 + i);
+ Data d = x8051.getListing().getDataAt(a);
+ assertNotNull(d);
- String s = dtm.getStringSettingsValue(a, "color");
+ String s = dtm.getStringSettingsValue(d, STRING_SETTING_NAME);
assertEquals("red" + i, s);
- Long lvalue = dtm.getLongSettingsValue(a, "someLongValue");
+ Long lvalue = dtm.getLongSettingsValue(d, LONG_SETTING_NAME);
assertEquals(i, lvalue.longValue());
}
}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/ArrayTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/ArrayTest.java
index d34ca2ef19..7668dadd3f 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/ArrayTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/ArrayTest.java
@@ -17,6 +17,8 @@ package ghidra.program.database.data;
import static org.junit.Assert.*;
+import org.junit.*;
+
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
@@ -29,8 +31,6 @@ import ghidra.program.model.mem.Memory;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.task.TaskMonitorAdapter;
-import org.junit.*;
-
/**
*
* To change the template for this generated type comment go to
@@ -171,15 +171,15 @@ public class ArrayTest extends AbstractGhidraHeadedIntegrationTest {
for (int i = 0; i < 10; i++) {
Data comp = data.getComponent(i);
- assertEquals(null, comp.getLong("MySetting"));
+ assertEquals(null, comp.getLong("format"));
}
Data component4 = data.getComponent(4);
- component4.setLong("MySetting", 10L);
+ component4.setLong("format", 10L);
for (int i = 0; i < 10; i++) {
Data comp = data.getComponent(i);
- assertEquals((Long) 10L, comp.getLong("MySetting"));
+ assertEquals((Long) 10L, comp.getLong("format"));
}
}
@@ -199,15 +199,15 @@ public class ArrayTest extends AbstractGhidraHeadedIntegrationTest {
for (int i = 0; i < 10; i++) {
Data comp = subData.getComponent(i);
- assertEquals(null, comp.getLong("MySetting"));
+ assertEquals(null, comp.getLong("format"));
}
Data component4 = subData.getComponent(4);
- component4.setLong("MySetting", 10L);
+ component4.setLong("format", 10L);
for (int i = 0; i < 10; i++) {
Data comp = subData.getComponent(i);
- assertEquals((Long) 10L, comp.getLong("MySetting"));
+ assertEquals((Long) 10L, comp.getLong("format"));
}
}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java
index 87545151e9..f06e93686d 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java
@@ -27,6 +27,7 @@ import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.mem.Memory;
@@ -47,6 +48,10 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
private AddressSpace space;
private int transactionID;
+ // Suitable settings allowed for StringDataType data
+ private static String LONG_SETTING_NAME = "mutability";
+ private static String STRING_SETTING_NAME = "charset";
+
// NOTE: Datatypes must be resolved before settings may be changed
// with the exception of TypeDefDataType which does permit
// TypeDefSettingsDefinition settings defined by the base-datatype.
@@ -63,6 +68,16 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
listing = program.getListing();
transactionID = program.startTransaction("Test");
addBlock();
+ // pointer-typedef has the largest
+// System.out.println("Defined string settings:");
+// for (SettingsDefinition def : StringDataType.dataType.getSettingsDefinitions()) {
+// System.out.println(def.getStorageKey());
+// }
+
+ for (int i = 0; i < 40; i++) {
+ DataUtilities.createData(program, addr(i), StringDataType.dataType, 1, false,
+ ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
+ }
}
@After
@@ -76,31 +91,33 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testSetDefaultSettings() throws Exception {
- DataType dt = ByteDataType.dataType;
+ DataType dt = StringDataType.dataType;
Settings defaultSettings = dt.getDefaultSettings();
- defaultSettings.setString("color", "red");
- defaultSettings.setLong("someLongValue", 10);
- assertNull(defaultSettings.getString("color"));
- assertNull(defaultSettings.getLong("someLongValue"));
+ // immutable warnings expected
+ defaultSettings.setString(STRING_SETTING_NAME, "red");
+ defaultSettings.setLong(LONG_SETTING_NAME, 10);
+
+ assertNull(defaultSettings.getString(STRING_SETTING_NAME));
+ assertNull(defaultSettings.getLong(LONG_SETTING_NAME));
// May modify byte default settings after resolve
dt = dataMgr.resolve(dt, null);
defaultSettings = dt.getDefaultSettings();
- defaultSettings.setString("color", "red");
- defaultSettings.setLong("someLongValue", 10);
+ defaultSettings.setString(STRING_SETTING_NAME, "red");
+ defaultSettings.setLong(LONG_SETTING_NAME, 10);
- assertEquals("red", defaultSettings.getString("color"));
- Long lv = defaultSettings.getLong("someLongValue");
+ assertEquals("red", defaultSettings.getString(STRING_SETTING_NAME));
+ Long lv = defaultSettings.getLong(LONG_SETTING_NAME);
assertNotNull(lv);
assertEquals(10, lv.longValue());
- defaultSettings.setValue("long", 10L);
- Object obj = defaultSettings.getValue("long");
- assertNotNull(obj);
- assertEquals(10, ((Long) obj).longValue());
+ defaultSettings.setValue(LONG_SETTING_NAME, 20L);
+ Object obj = defaultSettings.getValue(LONG_SETTING_NAME);
+ assertTrue(obj instanceof Long);
+ assertEquals(20, ((Long) obj).longValue());
}
@Test
@@ -112,31 +129,32 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(0, ByteDataType.dataType.getTypeDefSettingsDefinitions().length);
Settings defaultSettings = typeDef.getDefaultSettings();
- defaultSettings.setString("color", "red");
- defaultSettings.setLong("someLongValue", 10);
- assertNull(defaultSettings.getString("color"));
- assertNull(defaultSettings.getLong("someLongValue"));
+ // immutable warnings expected
+ FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.CHAR);
+ EndianSettingsDefinition.DEF.setBigEndian(defaultSettings, false);
+ PaddingSettingsDefinition.DEF.setPadded(defaultSettings, true);
+
+ assertNull(defaultSettings.getLong("format"));
+ assertNull(defaultSettings.getLong("endian"));
+ assertNull(defaultSettings.getLong("padding"));
// May modify arbitrary typedef default settings after resolve
typeDef = (TypeDef) dataMgr.resolve(typeDef, null);
defaultSettings = typeDef.getDefaultSettings();
- defaultSettings.setString("color", "red");
- defaultSettings.setLong("someLongValue", 10);
+ FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.CHAR);
+ EndianSettingsDefinition.DEF.setBigEndian(defaultSettings, false);
+ PaddingSettingsDefinition.DEF.setPadded(defaultSettings, true);
- assertEquals("red", defaultSettings.getString("color"));
- Long lv = defaultSettings.getLong("someLongValue");
- assertNotNull(lv);
- assertEquals(10, lv.longValue());
-
- defaultSettings.setValue("long", 10L);
- Object obj = defaultSettings.getValue("long");
- assertNotNull(obj);
- assertEquals(10, ((Long) obj).longValue());
+ assertEquals(FormatSettingsDefinition.CHAR, defaultSettings.getLong("format").longValue());
+ assertEquals(EndianSettingsDefinition.LITTLE,
+ defaultSettings.getLong("endian").longValue());
+ assertEquals(PaddingSettingsDefinition.PADDED_VALUE,
+ defaultSettings.getLong("padded").longValue());
try {
- defaultSettings.setValue("color", Color.RED);
+ defaultSettings.setValue("format", Color.RED);
Assert.fail("Should not be able to set arbitrary objects");
}
catch (IllegalArgumentException e) {
@@ -147,10 +165,10 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testIsEmpty() throws Exception {
- DataType dt = dataMgr.resolve(ByteDataType.dataType, null);
- Settings defaultSettings = dt.getDefaultSettings();
- defaultSettings.setString("color", "red");
- defaultSettings.setLong("someLongValue", 10);
+ Data data = listing.getDataAt(addr(10));
+ Settings defaultSettings = data.getDataType().getDefaultSettings();
+ defaultSettings.setString(STRING_SETTING_NAME, "red");
+ defaultSettings.setLong(LONG_SETTING_NAME, 10);
assertTrue(!defaultSettings.isEmpty());
@@ -161,107 +179,99 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testGetNames() throws Exception {
- DataType dt = dataMgr.resolve(ByteDataType.dataType, null);
+ DataType dt = dataMgr.resolve(StringDataType.dataType, null);
Settings defaultSettings = dt.getDefaultSettings();
- defaultSettings.setString("color", "red");
- defaultSettings.setLong("someLongValue", 10);
- defaultSettings.setString("endian", "big Endian");
+ defaultSettings.setString(STRING_SETTING_NAME, "red");
+ defaultSettings.setLong(LONG_SETTING_NAME, 10);
String[] names = defaultSettings.getNames();
- assertEquals(3, names.length);
+ assertEquals(2, names.length);
}
@Test
public void testClearSetting() throws Exception {
- DataType dt = dataMgr.resolve(ByteDataType.dataType, null);
+ DataType dt = dataMgr.resolve(StringDataType.dataType, null);
Settings defaultSettings = dt.getDefaultSettings();
- defaultSettings.setString("color", "red");
- defaultSettings.setLong("someLongValue", 10);
+ defaultSettings.setString(STRING_SETTING_NAME, "red");
+ defaultSettings.setLong(LONG_SETTING_NAME, 10);
- defaultSettings.clearSetting("color");
- assertNull(defaultSettings.getString("color"));
+ defaultSettings.clearSetting(STRING_SETTING_NAME);
+ assertNull(defaultSettings.getString(STRING_SETTING_NAME));
}
@Test
public void testInstanceSettings() throws Exception {
- listing.createData(addr(10), new ByteDataType(), 1);
- Data data = listing.getDataAt(addr(10));
- ByteDataType dt = (ByteDataType) data.getDataType();
+ Data data = DataUtilities.createData(program, addr(10), ByteDataType.dataType, 1, false,
+ ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
+
+ DataType dt = data.getDataType();
Settings defaultSettings = dt.getDefaultSettings();
- defaultSettings.setLong("format", FormatSettingsDefinition.CHAR);
- defaultSettings.setLong("signed", 0);
- defaultSettings.setLong("padded", 1);
+ FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.CHAR);
+ EndianSettingsDefinition.DEF.setBigEndian(defaultSettings, false);
+ PaddingSettingsDefinition.DEF.setPadded(defaultSettings, true);
- SettingsDefinition[] defs = dt.getSettingsDefinitions();
- for (int i = 0; i < defs.length; i++) {
+ assertEquals(FormatSettingsDefinition.CHAR, data.getLong("format").longValue());
+ FormatSettingsDefinition.DEF.setChoice(data, FormatSettingsDefinition.DECIMAL);
+ assertEquals(FormatSettingsDefinition.DECIMAL, data.getLong("format").longValue());
- if (defs[i] instanceof EnumSettingsDefinition) {
- EnumSettingsDefinition enumDef = (EnumSettingsDefinition) defs[i];
- int value = enumDef.getChoice(data);
- enumDef.setChoice(data, value);
- if (i == 0) {
- assertEquals(FormatSettingsDefinition.CHAR, data.getLong("format").longValue());
- }
- else if (i == 1) {
- assertEquals(0, data.getLong("signed").longValue());
- }
- else if (i == 2) {
- assertEquals(1, data.getLong("padded").longValue());
- }
+ assertEquals(EndianSettingsDefinition.LITTLE, data.getLong("endian").longValue());
+ EndianSettingsDefinition.DEF.setChoice(data, EndianSettingsDefinition.BIG);
+ assertEquals(EndianSettingsDefinition.BIG, data.getLong("endian").longValue());
- }
- }
+ assertEquals(PaddingSettingsDefinition.PADDED_VALUE, data.getLong("padded").longValue());
+ PaddingSettingsDefinition.DEF.setChoice(data, PaddingSettingsDefinition.UNPADDED_VALUE);
+ assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE, data.getLong("padded").longValue());
+
+ FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.HEX);
+ EndianSettingsDefinition.DEF.clear(defaultSettings);
+ PaddingSettingsDefinition.DEF.clear(defaultSettings);
+
+ assertEquals(FormatSettingsDefinition.DECIMAL, data.getLong("format").longValue());
+ assertEquals(EndianSettingsDefinition.BIG, data.getLong("endian").longValue());
+ assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE, data.getLong("padded").longValue());
}
@Test
public void testGetInstanceNames() throws Exception {
- listing.createData(addr(10), new ByteDataType(), 1);
Data data = listing.getDataAt(addr(10));
- data.setString("color", "red");
- data.setLong("someLongValue", 10);
- data.setString("endian", "big Endian");
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
String[] names = data.getNames();
- assertEquals(3, names.length);
+ assertEquals(2, names.length);
}
@Test
public void testClearInstanceSettings() throws Exception {
- listing.createData(addr(10), new ByteDataType(), 1);
Data data = listing.getDataAt(addr(10));
- data.setString("color", "red");
- data.setLong("someLongValue", 10);
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
- data.clearSetting("color");
- assertNull(data.getString("color"));
+ data.clearSetting(STRING_SETTING_NAME);
+ assertNull(data.getString(STRING_SETTING_NAME));
}
@Test
public void testClearAllInstanceSettings() throws Exception {
- listing.createData(addr(10), new ByteDataType(), 1);
Data data = listing.getDataAt(addr(10));
- data.setString("color", "red");
- data.setLong("someLongValue", 10);
- data.setString("endian", "big Endian");
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
data.clearAllSettings();
- assertNull(data.getString("color"));
- assertNull(data.getLong("someLongValue"));
- assertNull(data.getString("endian"));
+ assertNull(data.getString(STRING_SETTING_NAME));
+ assertNull(data.getLong(LONG_SETTING_NAME));
}
@Test
public void testIsEmptyInstanceSettings() throws Exception {
- listing.createData(addr(10), new ByteDataType(), 1);
Data data = listing.getDataAt(addr(10));
- data.setString("color", "red");
- data.setLong("someLongValue", 10);
- data.setString("endian", "big Endian");
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
assertTrue(!data.isEmpty());
data.clearAllSettings();
@@ -269,23 +279,29 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(data.isEmpty());
}
+ private Data getDataAt(long offset) {
+ Data data = listing.getDataAt(addr(offset));
+ assertNotNull("expected data at address 0x" + Long.toHexString(offset));
+ return data;
+ }
+
@Test
public void testMoveSettings() throws Exception {
for (int i = 0; i < 10; i++) {
- Address a = addr(i);
- dataMgr.setStringSettingsValue(a, "color", "red" + i);
- dataMgr.setLongSettingsValue(a, "someLongValue", i);
+ Data d = getDataAt(i);
+ dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
+ dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
}
dataMgr.moveAddressRange(addr(0), addr(20), 10, TaskMonitor.DUMMY);
int j = 0;
for (int i = 20; i < 30; i++, j++) {
- Address a = addr(i);
+ Data d = getDataAt(i);
- String s = dataMgr.getStringSettingsValue(a, "color");
+ String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
assertEquals("red" + j, s);
- Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue");
+ Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
assertEquals(j, lvalue.longValue());
}
}
@@ -294,9 +310,9 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
public void testMoveSettings2() {
for (int i = 0; i < 10; i++) {
- Address a = addr(i);
- dataMgr.setStringSettingsValue(a, "color", "red" + i);
- dataMgr.setLongSettingsValue(a, "someLongValue", i);
+ Data d = getDataAt(i);
+ dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
+ dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
}
try {
dataMgr.moveAddressRange(addr(0), addr(5), 10, TaskMonitor.DUMMY);
@@ -307,12 +323,12 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
int j = 0;
for (int i = 5; i < 15; i++, j++) {
- Address a = addr(i);
+ Data d = getDataAt(i);
- String s = dataMgr.getStringSettingsValue(a, "color");
+ String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
assertEquals("red" + j, s);
- Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue");
+ Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
assertEquals(j, lvalue.longValue());
}
}
@@ -322,9 +338,9 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
int j = 20;
for (int i = 20; i < 30; i++, j++) {
- Address a = addr(i);
- dataMgr.setStringSettingsValue(a, "color", "red" + i);
- dataMgr.setLongSettingsValue(a, "someLongValue", i);
+ Data d = getDataAt(i);
+ dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
+ dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
}
j = 20;
try {
@@ -334,12 +350,12 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
Assert.fail("Unexpected cancelled exception");
}
for (int i = 5; i < 15; i++, j++) {
- Address a = addr(i);
+ Data d = getDataAt(i);
- String s = dataMgr.getStringSettingsValue(a, "color");
+ String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
assertEquals("red" + j, s);
- Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue");
+ Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
assertEquals(j, lvalue.longValue());
}
@@ -378,8 +394,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
SettingsDefinition[] settingsDefinitions = byteDT.getSettingsDefinitions();
Settings settings = byteDT.getDefaultSettings();
- settings.setLong("format", FormatSettingsDefinition.OCTAL);
- settings.setString("color", "red");
+ FormatSettingsDefinition.DEF.setChoice(settings, FormatSettingsDefinition.OCTAL);
TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT);
TypeDef td = (TypeDef) dataMgr.addDataType(tdt, null);
@@ -388,11 +403,18 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(sdefs.length >= settingsDefinitions.length); // TypeDef may add some of its own
Settings defSettings = td.getDefaultSettings();
- defSettings.setLong("someLongValue", 10);
+ assertEquals(FormatSettingsDefinition.OCTAL,
+ FormatSettingsDefinition.DEF.getChoice(defSettings));
+
+ FormatSettingsDefinition.DEF.setChoice(defSettings, FormatSettingsDefinition.DECIMAL);
+ assertEquals(FormatSettingsDefinition.DECIMAL,
+ FormatSettingsDefinition.DEF.getChoice(defSettings));
+
+ FormatSettingsDefinition.DEF.setChoice(settings, FormatSettingsDefinition.HEX);
+
+ assertEquals(FormatSettingsDefinition.DECIMAL,
+ FormatSettingsDefinition.DEF.getChoice(defSettings)); // unchanged
- assertEquals((long) FormatSettingsDefinition.OCTAL, defSettings.getValue("format")); // inherits from byteDt
- assertEquals("red", defSettings.getValue("color")); // inherits from byteDt
- assertEquals(10L, defSettings.getValue("someLongValue"));
}
@Test
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/model/data/PointerTypedefDataTypeTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/model/data/PointerTypedefDataTypeTest.java
index 31d18f0d6e..b24c469385 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/model/data/PointerTypedefDataTypeTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/model/data/PointerTypedefDataTypeTest.java
@@ -19,6 +19,8 @@ import static org.junit.Assert.*;
import org.junit.*;
+import ghidra.docking.settings.Settings;
+import ghidra.program.database.DatabaseObject;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.data.PointerTypedefInspector;
import ghidra.program.model.address.AddressSpace;
@@ -52,7 +54,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
program = buildProgram("notepad");
dtm = program.getDataTypeManager();
builtInDtm = BuiltInDataTypeManager.getDataTypeManager();
-
+
program.startTransaction("TEST");
}
@@ -63,75 +65,241 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
}
@Test
- public void testIBOBuiltIn() throws Exception {
+ public void testBuiltInIBODataTypes() throws Exception {
DataType dt = builtInDtm.getDataType(CategoryPath.ROOT, IBO32DataType.NAME);
- assertTrue(dt instanceof TypeDef);
- assertFalse(dt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
+ assertTrue(dt instanceof IBO32DataType);
assertEquals(IBO32DataType.NAME, dt.getName());
assertFalse(dt.hasLanguageDependantLength());
- assertTrue(dt.isEquivalent(dtm.resolve(dt, null)));
-
- dt = new IBO32DataType(CharDataType.dataType, dtm);
- assertTrue(dt instanceof TypeDef);
- assertTrue(dt instanceof BuiltIn);
- assertEquals("char *32 __attribute__((image-base-relative))", dt.getName());
DataType dbDt = dtm.resolve(dt, null);
- assertTrue(dbDt instanceof TypeDef);
- assertFalse(dbDt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
+ assertTrue(dbDt instanceof IBO32DataType);
assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
dt = builtInDtm.getDataType(CategoryPath.ROOT, IBO64DataType.NAME);
- assertTrue(dt instanceof TypeDef);
- assertFalse(dt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
+ assertTrue(dt instanceof IBO64DataType);
assertEquals(IBO64DataType.NAME, dt.getName());
assertFalse(dt.hasLanguageDependantLength());
- assertTrue(dt.isEquivalent(dtm.resolve(dt, null)));
-
- dt = new IBO64DataType(CharDataType.dataType, dtm);
- assertTrue(dt instanceof TypeDef);
- assertTrue(dt instanceof BuiltIn);
- assertEquals("char *64 __attribute__((image-base-relative))", dt.getName());
dbDt = dtm.resolve(dt, null);
- assertTrue(dbDt instanceof TypeDef);
- assertFalse(dbDt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
+ assertTrue(dbDt instanceof IBO64DataType);
assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
}
@Test
public void testPointerTypedef() throws Exception {
- DataType dt = new PointerTypedef(null, CharDataType.dataType, -1, dtm,
- program.getAddressFactory().getRegisterSpace());
+ DataType dt = new PointerTypedef(null, CharDataType.dataType, -1, dtm, 0x8);
assertTrue(dt.hasLanguageDependantLength());
assertEquals(4, dt.getLength());
assertTrue(dt instanceof TypeDef);
- assertTrue(dt instanceof BuiltIn);
- assertEquals("char * __attribute__((space(register)))", dt.getName());
+ assertEquals("char * " + formatAttributes("offset(0x8)"), dt.getName());
DataType dbDt = dtm.resolve(dt, null);
assertTrue(dbDt instanceof TypeDef);
- assertFalse(dbDt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
+ assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
AddressSpace space = PointerTypedefInspector.getPointerAddressSpace((TypeDef) dbDt,
program.getAddressFactory());
- assertTrue(program.getAddressFactory().getRegisterSpace().equals(space));
+ assertNull(space);
dt = new PointerTypedef(null, CharDataType.dataType, -1, dtm,
PointerType.RELATIVE);
assertTrue(dt.hasLanguageDependantLength());
assertEquals(4, dt.getLength());
assertTrue(dt instanceof TypeDef);
- assertTrue(dt instanceof BuiltIn);
- assertEquals("char * __attribute__((relative))", dt.getName());
+ assertEquals("char * " + formatAttributes("relative"), dt.getName());
dbDt = dtm.resolve(dt, null);
assertTrue(dbDt instanceof TypeDef);
- assertFalse(dbDt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
+ assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
assertEquals(PointerType.RELATIVE, PointerTypedefInspector.getPointerType((TypeDef) dbDt));
}
+ @Test
+ public void testPointerTypedefWithAddrSpace() throws Exception {
+ DataType dt = new PointerTypedef(null, CharDataType.dataType, -1, dtm,
+ program.getAddressFactory().getRegisterSpace());
+ assertFalse(dt.hasLanguageDependantLength());
+ assertEquals(2, dt.getLength());
+ assertTrue(dt instanceof TypeDef);
+ assertEquals("char *16 " + formatAttributes("space(register)"), dt.getName());
+ DataType dbDt = dtm.resolve(dt, null);
+ assertTrue(dbDt instanceof TypeDef);
+ assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
+ assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
+
+ AddressSpace space = PointerTypedefInspector.getPointerAddressSpace((TypeDef) dbDt,
+ program.getAddressFactory());
+ assertTrue(program.getAddressFactory().getRegisterSpace().equals(space));
+
+ dt = new PointerTypedef(null, CharDataType.dataType, 4, dtm,
+ program.getAddressFactory().getRegisterSpace());
+ assertFalse(dt.hasLanguageDependantLength());
+ assertEquals(4, dt.getLength());
+ assertTrue(dt instanceof TypeDef);
+ assertEquals("char *32 " + formatAttributes("space(register)"), dt.getName());
+ dbDt = dtm.resolve(dt, null);
+ assertTrue(dbDt instanceof TypeDef);
+ assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
+ assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
+
+ space = PointerTypedefInspector.getPointerAddressSpace((TypeDef) dbDt,
+ program.getAddressFactory());
+ assertTrue(program.getAddressFactory().getRegisterSpace().equals(space));
+ }
+
+ @Test
+ public void testPointerTypedefAutoNaming() throws Exception {
+
+ DataType st = dtm.resolve(new StructureDataType("foo", 10), null);
+
+ DataType dt = new PointerTypedef(null, st, -1, dtm,
+ program.getAddressFactory().getRegisterSpace());
+ assertFalse(dt.hasLanguageDependantLength());
+ assertEquals(2, dt.getLength());
+ assertTrue(dt instanceof TypeDef);
+ assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
+ DataType dbDt = dtm.resolve(dt, null);
+ assertTrue(dbDt instanceof TypeDef);
+ assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
+ assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
+
+ st.setName("bob");
+
+ // auto-name should update
+ assertEquals("bob *16 " + formatAttributes("space(register)"), dbDt.getName());
+
+ Settings settings = dbDt.getDefaultSettings();
+
+ OffsetMaskSettingsDefinition.DEF.setValue(settings, 0x123456789abcdef0L);
+ assertEquals("bob *16 " + formatAttributes("space(register),mask(0x123456789abcdef0)"),
+ dbDt.getName());
+
+ ComponentOffsetSettingsDefinition.DEF.setValue(settings, 0x123);
+ assertEquals(
+ "bob *16 " + formatAttributes("space(register),mask(0x123456789abcdef0),offset(0x123)"),
+ dbDt.getName());
+
+ OffsetShiftSettingsDefinition.DEF.setValue(settings, 16);
+ assertEquals(
+ "bob *16 " + formatAttributes(
+ "space(register),mask(0x123456789abcdef0),shift(16),offset(0x123)"),
+ dbDt.getName());
+
+ PointerTypeSettingsDefinition.DEF.setType(settings, PointerType.IMAGE_BASE_RELATIVE);
+ assertEquals(
+ "bob *16 " + formatAttributes(
+ "image-base-relative,space(register),mask(0x123456789abcdef0),shift(16),offset(0x123)"),
+ dbDt.getName());
+
+ st.setName("bill");
+ assertEquals(
+ "bill *16 " + formatAttributes(
+ "image-base-relative,space(register),mask(0x123456789abcdef0),shift(16),offset(0x123)"),
+ dbDt.getName());
+
+ PointerTypeSettingsDefinition.DEF.clear(settings);
+ assertEquals(
+ "bill *16 " + formatAttributes(
+ "space(register),mask(0x123456789abcdef0),shift(16),offset(0x123)"),
+ dbDt.getName());
+
+ ComponentOffsetSettingsDefinition.DEF.clear(settings);
+ assertEquals(
+ "bill *16 " + formatAttributes("space(register),mask(0x123456789abcdef0),shift(16)"),
+ dbDt.getName());
+
+ // NOTE: Changing address space setting will not alter pointer size
+
+ AddressSpaceSettingsDefinition.DEF.clear(settings);
+ assertEquals(
+ "bill *16 " + formatAttributes("mask(0x123456789abcdef0),shift(16)"),
+ dbDt.getName());
+
+ OffsetShiftSettingsDefinition.DEF.clear(settings);
+ assertEquals(
+ "bill *16 " + formatAttributes("mask(0x123456789abcdef0)"),
+ dbDt.getName());
+
+ }
+
+ @Test
+ public void testPointerTypedefEquivalence() throws Exception {
+
+ DataType st = dtm.resolve(new StructureDataType("foo", 10), null);
+
+ TypeDef dt = new PointerTypedef(null, st, -1, dtm,
+ program.getAddressFactory().getRegisterSpace());
+ assertTrue(dt.isAutoNamed());
+ assertFalse(dt.hasLanguageDependantLength());
+ assertEquals(2, dt.getLength());
+ assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
+ TypeDef dbDt = (TypeDef) dtm.resolve(dt, null);
+ assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
+ assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
+
+ dt = (TypeDef) dt.copy(dtm);
+ assertTrue(dbDt == dtm.resolve(dt, null)); // should resolve to same instance
+
+ dt = (TypeDef) dt.copy(dtm);
+ PointerTypeSettingsDefinition.DEF.setType(dt.getDefaultSettings(), PointerType.IMAGE_BASE_RELATIVE);
+ TypeDef dbDt2 = (TypeDef) dtm.resolve(dt, null); // should resolve to new instance
+ assertTrue(dbDt != dbDt2);
+ assertEquals("foo *16 " + formatAttributes("image-base-relative,space(register)"),
+ dbDt2.getName());
+
+ PointerTypeSettingsDefinition.DEF.clear(dbDt2.getDefaultSettings());
+ assertEquals("foo *16 " + formatAttributes("space(register)") + DataType.CONFLICT_SUFFIX,
+ dbDt2.getName());
+
+ }
+
+ @Test
+ public void testPointerTypedefEquivalence2() throws Exception {
+
+ DataType st = dtm.resolve(new StructureDataType("foo", 10), null);
+
+ TypeDef dt = new PointerTypedef(null, st, -1, dtm,
+ program.getAddressFactory().getRegisterSpace());
+ assertTrue(dt.isAutoNamed());
+ assertFalse(dt.hasLanguageDependantLength());
+ assertEquals(2, dt.getLength());
+ assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
+ TypeDef dbDt = (TypeDef) dtm.resolve(dt, null);
+ assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
+ assertTrue(dt.isEquivalent(dbDt));
+ assertEquals(dt.getName(), dbDt.getName());
+
+ TypeDef dt2 = new PointerTypedef("john", st, -1, dtm,
+ program.getAddressFactory().getRegisterSpace());
+ assertFalse(dt2.isAutoNamed());
+ assertFalse(dt2.hasLanguageDependantLength());
+ assertEquals(2, dt.getLength());
+ assertEquals("john", dt2.getName());
+ TypeDef dbDt2 = (TypeDef) dtm.resolve(dt2, null);
+ assertTrue(dbDt != dbDt2);
+ assertFalse(dbDt.isEquivalent(dbDt2));
+ assertFalse(dbDt2.isEquivalent(dbDt));
+ assertTrue(dbDt2 instanceof DatabaseObject); // transforms to TypedefDB
+ assertTrue(dt2.isEquivalent(dbDt2));
+ assertEquals(dt2.getName(), dbDt2.getName());
+
+ }
+
+ private static String formatAttributes(String attrs) {
+ StringBuilder buf = new StringBuilder(DataType.TYPEDEF_ATTRIBUTE_PREFIX);
+ buf.append(attrs);
+ buf.append(DataType.TYPEDEF_ATTRIBUTE_SUFFIX);
+ return buf.toString();
+ }
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/database/AbstractMTFModel.java b/Ghidra/Features/Base/src/test/java/ghidra/program/database/AbstractMTFModel.java
index d5fb7ca90c..52d07c1b86 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/program/database/AbstractMTFModel.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/program/database/AbstractMTFModel.java
@@ -17,6 +17,7 @@ package ghidra.program.database;
import java.io.IOException;
+import db.*;
import db.buffers.BufferFile;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
@@ -28,6 +29,7 @@ import ghidra.program.model.listing.ProgramChangeSet;
import ghidra.test.TestEnv;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
/**
@@ -105,7 +107,7 @@ public abstract class AbstractMTFModel {
return privateChangeSet;
}
- public ProgramChangeSet getResultChangeSet() {
+ public ProgramChangeSet getLatestChangeSet() {
return latestChangeSet;
}
@@ -113,7 +115,7 @@ public abstract class AbstractMTFModel {
return env;
}
- protected void disableAutoAnalysis(Program p) {
+ protected static void disableAutoAnalysis(Program p) {
// Disable all analysis
AutoAnalysisManager analysisMgr = AutoAnalysisManager.getAnalysisManager(p);
AbstractGenericTest.setInstanceField("isEnabled", analysisMgr, Boolean.FALSE);
@@ -169,4 +171,25 @@ public abstract class AbstractMTFModel {
throws Exception;
public abstract void initialize(String programName, ProgramModifierListener l) throws Exception;
+
+ /**
+ * Clone a program to a new instance. The new instance will be assigned an empty change-set.
+ * @param prog program to be cloned
+ * @param consumer new program consumer
+ * @return new program instance
+ * @throws IOException if a file IO error occurs
+ */
+ public static ProgramDB cloneProgram(ProgramDB prog, Object consumer) throws IOException {
+ try {
+ DBHandle newDbh = DBTestUtils.cloneDbHandle(prog.getDBHandle());
+ ProgramDB newProg =
+ new ProgramDB(newDbh, DBConstants.UPDATE, TaskMonitor.DUMMY, consumer);
+ newProg.setChangeSet(new ProgramDBChangeSet(newProg.getAddressMap(), 20));
+ disableAutoAnalysis(newProg);
+ return newProg;
+ }
+ catch (CancelledException | VersionException e) {
+ throw new RuntimeException(e); // unexpected
+ }
+ }
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/database/MergeTestFacilitator.java b/Ghidra/Features/Base/src/test/java/ghidra/program/database/MergeTestFacilitator.java
index 574d072473..66bcf0ef1a 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/program/database/MergeTestFacilitator.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/program/database/MergeTestFacilitator.java
@@ -90,7 +90,7 @@ public class MergeTestFacilitator {
* Get the change set for Result program.
*/
public ProgramChangeSet getResultChangeSet() {
- return model.getResultChangeSet();
+ return model.getLatestChangeSet();
}
public void dispose() {
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/database/RealProgramMTFModel.java b/Ghidra/Features/Base/src/test/java/ghidra/program/database/RealProgramMTFModel.java
index 369b3b7496..814c28517e 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/program/database/RealProgramMTFModel.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/program/database/RealProgramMTFModel.java
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
- * REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,11 +29,7 @@ import ghidra.util.exception.AssertException;
// TODO rename--this is no longer using real programs
public class RealProgramMTFModel extends AbstractMTFModel {
- /**
- * We install our test ID generator to ensure that all datatypes we create will share the
- * same ID across all versions of the programs we create. If we do not do this, then they will
- * be different, which breaks many tests.
- */
+ // Use simple ID generation
private TestUniversalIdGenerator universalIdGenerator = new TestUniversalIdGenerator();
RealProgramMTFModel(TestEnv env) {
@@ -46,12 +41,15 @@ public class RealProgramMTFModel extends AbstractMTFModel {
cleanup();
MergeProgramGenerator programGenerator = createProgramGenerator(programName);
- generatePrograms(programName, programGenerator);
+ originalProgram = programGenerator.generateProgram(programName);
- disableAutoAnalysis();
+ latestProgram = cloneProgram(originalProgram, this);
+ modifier.modifyLatest(latestProgram);
- makeIncomingChanges(modifier);
- makeLocalChanges(modifier);
+ resultProgram = cloneProgram(latestProgram, this);
+
+ privateProgram = cloneProgram(originalProgram, this);
+ modifier.modifyPrivate(privateProgram);
recordChanges();
clearChanges();
@@ -63,36 +61,21 @@ public class RealProgramMTFModel extends AbstractMTFModel {
cleanup();
MergeProgramGenerator programGenerator = createProgramGenerator(programName);
- generatePrograms(programName, programGenerator);
+ originalProgram = programGenerator.generateProgram(programName);
+ modifier.modifyOriginal(originalProgram);
- disableAutoAnalysis();
+ privateProgram = cloneProgram(originalProgram, this);
+ modifier.modifyPrivate(privateProgram);
- createCustomStartingProgram(modifier);
- clearChanges();
+ latestProgram = cloneProgram(originalProgram, this);
+ modifier.modifyLatest(latestProgram);
- makeIncomingChanges(modifier);
- makeLocalChanges(modifier);
+ resultProgram = cloneProgram(latestProgram, this);
recordChanges();
clearChanges();
}
- /**
- * Tests that use this method are creating a new 'original' program, rather than using
- * a pre-fabricated one from a program builder.
- */
- private void createCustomStartingProgram(OriginalProgramModifierListener modifier)
- throws Exception {
- universalIdGenerator.checkpoint();
- modifier.modifyOriginal(originalProgram);
- universalIdGenerator.restore();
- modifier.modifyOriginal(privateProgram);
- universalIdGenerator.restore();
- modifier.modifyOriginal(latestProgram);
- universalIdGenerator.restore();
- modifier.modifyOriginal(resultProgram);
- }
-
private MergeProgramGenerator createProgramGenerator(String programName) {
if (programName.toLowerCase().contains("notepad")) {
return new MergeProgramGenerator_Notepads(this);
@@ -117,35 +100,6 @@ public class RealProgramMTFModel extends AbstractMTFModel {
throw new UnsupportedOperationException();
}
- private void disableAutoAnalysis() {
- disableAutoAnalysis(privateProgram);
- disableAutoAnalysis(resultProgram);
- disableAutoAnalysis(latestProgram);
- }
-
- private void makeLocalChanges(ProgramModifierListener modifier) throws Exception {
- modifier.modifyPrivate(privateProgram);
- }
-
- private void makeIncomingChanges(ProgramModifierListener modifier) throws Exception {
- universalIdGenerator.checkpoint();
- modifier.modifyLatest(latestProgram);
- universalIdGenerator.restore();
- modifier.modifyLatest(resultProgram);
- }
-
- private void generatePrograms(String programName, MergeProgramGenerator programGenerator)
- throws Exception {
- universalIdGenerator.checkpoint();
- privateProgram = programGenerator.generateProgram(programName);
- universalIdGenerator.restore();
- originalProgram = programGenerator.generateProgram(programName);
- universalIdGenerator.restore();
- resultProgram = programGenerator.generateProgram(programName);
- universalIdGenerator.restore();
- latestProgram = programGenerator.generateProgram(programName);
- }
-
private void recordChanges() {
// ...keep track of the changes we've made
latestChangeSet = latestProgram.getChanges();
diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java
index c4adf5df18..777e511f05 100644
--- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java
+++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java
@@ -581,8 +581,8 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
int addressSize = address.getSize();
if (addressSize == 64 && getIboIf64bit) {
- ImageBaseOffset32DataType ibo32 =
- new ImageBaseOffset32DataType(currentProgram.getDataTypeManager());
+ IBO32DataType ibo32 =
+ new IBO32DataType(currentProgram.getDataTypeManager());
int length = ibo32.getLength();
DumbMemBufferImpl compMemBuffer =
new DumbMemBufferImpl(currentProgram.getMemory(), address);
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHCatchHandlerModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHCatchHandlerModel.java
index c24a6eb193..20e61a8770 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHCatchHandlerModel.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHCatchHandlerModel.java
@@ -15,7 +15,7 @@
*/
package ghidra.app.cmd.data.exceptionhandling;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
+import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
import ghidra.app.cmd.data.*;
import ghidra.app.util.datatype.microsoft.DataValidationOptions;
@@ -116,7 +116,7 @@ public class EHCatchHandlerModel extends AbstractCreateDataTypeModel {
/* comps[1] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
struct.add(compDt, "dispType", null);
}
else {
@@ -136,7 +136,7 @@ public class EHCatchHandlerModel extends AbstractCreateDataTypeModel {
/* comps[3] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
struct.add(compDt, "dispOfHandler", null);
}
else {
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHESTypeListModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHESTypeListModel.java
index c6163ef40f..469e160a43 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHESTypeListModel.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHESTypeListModel.java
@@ -15,7 +15,7 @@
*/
package ghidra.app.cmd.data.exceptionhandling;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
+import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
import ghidra.app.cmd.data.EHDataTypeUtilities;
@@ -101,7 +101,7 @@ public class EHESTypeListModel extends AbstractCreateDataTypeModel {
/* comps[1] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
struct.add(compDt, "dispTypeArray", null);
}
else {
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHFunctionInfoModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHFunctionInfoModel.java
index c662368fd4..f47e48a333 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHFunctionInfoModel.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHFunctionInfoModel.java
@@ -15,7 +15,7 @@
*/
package ghidra.app.cmd.data.exceptionhandling;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
+import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
import ghidra.app.cmd.data.EHDataTypeUtilities;
@@ -150,7 +150,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
DataTypeManager dataTypeManager = getProgram().getDataTypeManager();
int intSize = new IntegerDataType(dataTypeManager).getLength();
int uintSize = new UnsignedIntegerDataType(dataTypeManager).getLength();
- int ibo32Size = new ImageBaseOffset32DataType(dataTypeManager).getLength();
+ int ibo32Size = new IBO32DataType(dataTypeManager).getLength();
int defaultPointerSize = getDefaultPointerSize();
int size20;
int additional21;
@@ -316,7 +316,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
/* comps[2] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
struct.add(compDt, "dispUnwindMap", null);
}
else {
@@ -330,7 +330,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
/* comps[4] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
struct.add(compDt, "dispTryBlockMap", null);
}
else {
@@ -344,7 +344,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
/* comps[6] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
struct.add(compDt, "dispIPToStateMap", null);
}
else {
@@ -359,7 +359,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
if (isV2 || isV3) {
if (isRelative) { /* comps[8] */
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
struct.add(compDt, "dispESTypeList", null);
}
else { /* comps[7] */
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHIPToStateModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHIPToStateModel.java
index 4214c92949..46cfcd9b63 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHIPToStateModel.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHIPToStateModel.java
@@ -15,7 +15,7 @@
*/
package ghidra.app.cmd.data.exceptionhandling;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
+import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
import ghidra.app.cmd.data.EHDataTypeUtilities;
@@ -102,7 +102,7 @@ public class EHIPToStateModel extends AbstractCreateDataTypeModel {
/* comps[0] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
}
else {
DataType dwordDt = new TypedefDataType(new CategoryPath("/WinDef.h"), "DWORD",
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHTryBlockModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHTryBlockModel.java
index a0c94043c7..a23deb0640 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHTryBlockModel.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHTryBlockModel.java
@@ -15,7 +15,7 @@
*/
package ghidra.app.cmd.data.exceptionhandling;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
+import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
import ghidra.app.cmd.data.EHDataTypeUtilities;
@@ -114,7 +114,7 @@ public class EHTryBlockModel extends AbstractCreateDataTypeModel {
/* comps[4] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
struct.add(compDt, "dispHandlerArray", null);
}
else {
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHUnwindModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHUnwindModel.java
index be386b881a..b09153e91c 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHUnwindModel.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/exceptionhandling/EHUnwindModel.java
@@ -15,7 +15,7 @@
*/
package ghidra.app.cmd.data.exceptionhandling;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
+import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
import ghidra.app.cmd.data.EHDataTypeUtilities;
@@ -106,7 +106,7 @@ public class EHUnwindModel extends AbstractCreateDataTypeModel {
/* comps[1] */
if (isRelative) {
- compDt = new ImageBaseOffset32DataType(dataTypeManager);
+ compDt = new IBO32DataType(dataTypeManager);
}
else {
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti1Model.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti1Model.java
index 4dfea16da2..ee5261e991 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti1Model.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti1Model.java
@@ -232,7 +232,7 @@ public class Rtti1Model extends AbstractCreateRttiDataModel {
boolean is64Bit = MSDataTypeUtils.is64Bit(program);
Structure rtti1Struct = (Structure) DataTypeUtils.getBaseDataType(rtti1Dt);
DataType rtti3RefDt =
- is64Bit ? new ImageBaseOffset32DataType(dataTypeManager) : new PointerDataType(rtti3Dt);
+ is64Bit ? new IBO32DataType(dataTypeManager) : new PointerDataType(rtti3Dt);
rtti1Struct.replace(CLASS_HIERARCHY_POINTER_ORDINAL, rtti3RefDt, rtti3RefDt.getLength(),
"pClassHierarchyDescriptor", "ref to ClassHierarchyDescriptor (RTTI 3) for class");
}
@@ -248,9 +248,9 @@ public class Rtti1Model extends AbstractCreateRttiDataModel {
boolean is64Bit = MSDataTypeUtils.is64Bit(program);
DataType rtti0Dt = TypeDescriptorModel.getDataType(program);
DataType rtti0RefDt =
- is64Bit ? new ImageBaseOffset32DataType(dataTypeManager) : new PointerDataType(rtti0Dt);
+ is64Bit ? new IBO32DataType(dataTypeManager) : new PointerDataType(rtti0Dt);
DataType rtti3RefDt =
- is64Bit ? new ImageBaseOffset32DataType(dataTypeManager) : new PointerDataType();
+ is64Bit ? new IBO32DataType(dataTypeManager) : new PointerDataType();
CategoryPath categoryPath = new CategoryPath(CATEGORY_PATH);
StructureDataType struct =
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti2Model.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti2Model.java
index 88efe8b986..aa20822dea 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti2Model.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti2Model.java
@@ -15,7 +15,7 @@
*/
package ghidra.app.cmd.data.rtti;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getReferencedAddress;
+import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
import java.util.ArrayList;
import java.util.List;
@@ -145,11 +145,8 @@ public class Rtti2Model extends AbstractCreateRttiDataModel {
DataTypeManager dataTypeManager = program.getDataTypeManager();
- if (MSDataTypeUtils.is64Bit(program)) {
- return new ImageBaseOffset32DataType(dataTypeManager);
- }
-
- return new PointerDataType(rtti1Dt, dataTypeManager);
+ return MSDataTypeUtils.is64Bit(program) ? IBO32DataType.createIBO32PointerTypedef(rtti1Dt)
+ : new PointerDataType(rtti1Dt, dataTypeManager);
}
/**
@@ -162,11 +159,8 @@ public class Rtti2Model extends AbstractCreateRttiDataModel {
DataTypeManager dataTypeManager = program.getDataTypeManager();
- if (MSDataTypeUtils.is64Bit(program)) {
- return new ImageBaseOffset32DataType(dataTypeManager);
- }
-
- return new PointerDataType(dataTypeManager);
+ return MSDataTypeUtils.is64Bit(program) ? IBO32DataType.dataType
+ : new PointerDataType(dataTypeManager);
}
/**
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti3Model.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti3Model.java
index 19b1372bab..be9b4f8415 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti3Model.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/Rtti3Model.java
@@ -15,9 +15,6 @@
*/
package ghidra.app.cmd.data.rtti;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getReferencedAddress;
-
import java.util.List;
import ghidra.app.cmd.data.EHDataTypeUtilities;
@@ -147,8 +144,8 @@ public class Rtti3Model extends AbstractCreateRttiDataModel {
boolean is64Bit = MSDataTypeUtils.is64Bit(program);
Structure rtti3Struct = (Structure) DataTypeUtils.getBaseDataType(rtti3Dt);
DataType individualRtti2EntryDt = Rtti2Model.getIndividualEntryDataType(program, rtti1Dt);
- DataType rtti2RefDt = is64Bit ? new ImageBaseOffset32DataType(dataTypeManager)
- : new PointerDataType(individualRtti2EntryDt);
+ DataType rtti2RefDt = is64Bit ? IBO32DataType.createIBO32PointerTypedef(individualRtti2EntryDt)
+ : new PointerDataType(individualRtti2EntryDt, dataTypeManager);
rtti3Struct.replace(BASE_ARRAY_PTR_ORDINAL, rtti2RefDt, rtti2RefDt.getLength(),
"pBaseClassArray", "ref to BaseClassArray (RTTI 2)");
}
@@ -165,7 +162,7 @@ public class Rtti3Model extends AbstractCreateRttiDataModel {
CategoryPath categoryPath = new CategoryPath(CATEGORY_PATH);
StructureDataType struct =
- getAlignedPack4Structure(dataTypeManager, categoryPath, STRUCTURE_NAME);
+ MSDataTypeUtils.getAlignedPack4Structure(dataTypeManager, categoryPath, STRUCTURE_NAME);
// Add the components.
DWordDataType dWordDataType = new DWordDataType(dataTypeManager);
@@ -174,8 +171,10 @@ public class Rtti3Model extends AbstractCreateRttiDataModel {
struct.add(dWordDataType, "numBaseClasses", "number of base classes (i.e. rtti1Count)");
DataType rtti2Dt = Rtti2Model.getSimpleIndividualEntryDataType(program);
+ // FIXME! I don't think we should be making a pointer-to-pointer
DataType rtti2RefDt =
- is64Bit ? new ImageBaseOffset32DataType(dataTypeManager) : new PointerDataType(rtti2Dt);
+ is64Bit ? IBO32DataType.createIBO32PointerTypedef(rtti2Dt)
+ : new PointerDataType(rtti2Dt, dataTypeManager);
struct.add(rtti2RefDt, "pBaseClassArray", "ref to BaseClassArray (RTTI 2)");
return new TypedefDataType(categoryPath, DATA_TYPE_NAME, struct, dataTypeManager);
@@ -264,7 +263,7 @@ public class Rtti3Model extends AbstractCreateRttiDataModel {
Memory memory = program.getMemory();
Address rtti2CompAddress = rtti3Address.add(BASE_ARRAY_PTR_OFFSET);
- Address pointedToAddress = getReferencedAddress(program, rtti2CompAddress);
+ Address pointedToAddress = MSDataTypeUtils.getReferencedAddress(program, rtti2CompAddress);
if (pointedToAddress == null || !memory.contains(pointedToAddress)) {
return null;
}
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/AbstractRttiTest.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/AbstractRttiTest.java
index 85fa51c2f5..9457988424 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/AbstractRttiTest.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/AbstractRttiTest.java
@@ -15,9 +15,8 @@
*/
package ghidra.app.cmd.data.rtti;
-import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAbsoluteAddress;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
+import static org.junit.Assert.*;
import ghidra.app.cmd.data.AbstractCreateDataTypeModelTest;
import ghidra.app.cmd.data.TypeDescriptorModel;
@@ -591,10 +590,10 @@ class AbstractRttiTest extends AbstractCreateDataTypeModelTest {
}
protected void checkRtti2Data(ProgramDB program, long address, int numEntries) {
+ DataType rtti1Dt = Rtti1Model.getDataType(program);
DataType expectedDataType =
- MSDataTypeUtils.is64Bit(program) ? new ImageBaseOffset32DataType()
- : new PointerDataType(Rtti1Model.getDataType(program),
- program.getDataTypeManager());
+ MSDataTypeUtils.is64Bit(program) ? IBO32DataType.createIBO32PointerTypedef(rtti1Dt)
+ : new PointerDataType(rtti1Dt, program.getDataTypeManager());
checkArrayData(program, address, expectedDataType, numEntries);
}
diff --git a/Ghidra/Framework/DB/src/main/java/db/DBHandle.java b/Ghidra/Framework/DB/src/main/java/db/DBHandle.java
index 3647bce50a..319e9479b1 100644
--- a/Ghidra/Framework/DB/src/main/java/db/DBHandle.java
+++ b/Ghidra/Framework/DB/src/main/java/db/DBHandle.java
@@ -679,11 +679,16 @@ public class DBHandle {
* @param outFile buffer file open for writing
* @param newDatabaseId database ID to be forced for new database or null to generate
* new database ID
+ * @param associateWithNewFile if true the outFile will be associated with this DBHandle as the
+ * current source file, if false no change will be made to this DBHandle's state and the outFile
+ * will be written and set as read-only. The caller is responsbile for disposing the outFile if
+ * this parameter is false.
* @param monitor progress monitor
* @throws IOException if IO error occurs
* @throws CancelledException if monitor cancels operation
*/
- protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId, TaskMonitor monitor)
+ protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId,
+ boolean associateWithNewFile, TaskMonitor monitor)
throws IOException, CancelledException {
if (txStarted) {
@@ -704,7 +709,7 @@ public class DBHandle {
endTransaction(txId, true); // saved file may be corrupt on IOException
}
- bufferMgr.saveAs(outFile, true, monitor);
+ bufferMgr.saveAs(outFile, associateWithNewFile, monitor);
}
/**
diff --git a/Ghidra/Framework/DB/src/test/java/db/DBTestUtils.java b/Ghidra/Framework/DB/src/test/java/db/DBTestUtils.java
index eedec3b7db..28b828273e 100644
--- a/Ghidra/Framework/DB/src/test/java/db/DBTestUtils.java
+++ b/Ghidra/Framework/DB/src/test/java/db/DBTestUtils.java
@@ -23,8 +23,9 @@ import java.util.Random;
import org.junit.Assert;
-import db.buffers.BufferFileManager;
-import db.buffers.DummyBufferFileMgr;
+import db.buffers.*;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
/**
*
@@ -803,6 +804,30 @@ public class DBTestUtils {
static BufferFileManager getBufferFileManager(File dir, String dbName) {
return new DummyBufferFileMgr(dir, dbName, false, false);
}
+
+ /**
+ * Clone a DBHandle backed by a new temporary source buffer file.
+ * The specified dbh will remain associated with its original source buffer file.
+ * @param dbh DBHandle to clone
+ * @return new DBhandle
+ * @throws IOException if a file IO error occurs
+ */
+ public static DBHandle cloneDbHandle(DBHandle dbh) throws IOException {
+
+ try {
+ File tmpFile = File.createTempFile("tmp", ".db");
+ tmpFile.delete();
+
+ LocalBufferFile bf = new LocalBufferFile(tmpFile, dbh.getBufferSize());
+ dbh.saveAs(bf, dbh.getDatabaseId(), false, TaskMonitor.DUMMY);
+ tmpFile.deleteOnExit();
+
+ return new DBHandle(bf);
+ }
+ catch (CancelledException e) {
+ throw new IOException(e); // unexpected
+ }
+ }
}
class DuplicateKeyException extends Exception {
diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/FloatingPointPrecisionSettingsDefinition.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/FloatingPointPrecisionSettingsDefinition.java
index 00bd9597e9..7acb3ff028 100644
--- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/FloatingPointPrecisionSettingsDefinition.java
+++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/FloatingPointPrecisionSettingsDefinition.java
@@ -92,6 +92,11 @@ public class FloatingPointPrecisionSettingsDefinition implements EnumSettingsDef
return PRECISION_DIGITS;
}
+ @Override
+ public String getStorageKey() {
+ return PRECISION_DIGITS;
+ }
+
@Override
public String getDescription() {
return "Selects the number of digits of precision to display";
diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/FormatSettingsDefinition.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/FormatSettingsDefinition.java
index c1b934d1e3..6709d5a589 100644
--- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/FormatSettingsDefinition.java
+++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/FormatSettingsDefinition.java
@@ -114,6 +114,11 @@ public class FormatSettingsDefinition implements EnumSettingsDefinition {
return "Format";
}
+ @Override
+ public String getStorageKey() {
+ return FORMAT;
+ }
+
@Override
public String getDescription() {
return "Selects the display format";
diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/IntegerSignednessFormattingModeSettingsDefinition.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/IntegerSignednessFormattingModeSettingsDefinition.java
index ace9083fdb..26d2529fb2 100644
--- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/IntegerSignednessFormattingModeSettingsDefinition.java
+++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/IntegerSignednessFormattingModeSettingsDefinition.java
@@ -113,6 +113,11 @@ public class IntegerSignednessFormattingModeSettingsDefinition implements EnumSe
return "Signedness Mode";
}
+ @Override
+ public String getStorageKey() {
+ return SIGN_FORMAT;
+ }
+
@Override
public String getDescription() {
return "Selects the display mode for signed values";
diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/JavaEnumSettingsDefinition.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/JavaEnumSettingsDefinition.java
index d4347b0124..6dcf822ed1 100644
--- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/JavaEnumSettingsDefinition.java
+++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/JavaEnumSettingsDefinition.java
@@ -80,7 +80,7 @@ public class JavaEnumSettingsDefinition> implements EnumSettin
* @return Enum<T> value, or the specified defaultValueOveride if not present.
*/
public T getEnumValue(Settings settings, T defaultValueOverride) {
- Long lvalue = settings.getLong(getSettingName());
+ Long lvalue = settings.getLong(settingName);
if (lvalue == null) {
return defaultValueOverride;
}
@@ -126,38 +126,34 @@ public class JavaEnumSettingsDefinition> implements EnumSettin
return -1;
}
- /**
- * The name of this setting as it is stored in a {@link Settings} object.
- *
- * @return String name.
- */
- public String getSettingName() {
- return settingName;
- }
-
@Override
public boolean hasValue(Settings setting) {
- return setting.getValue(getSettingName()) != null;
+ return setting.getValue(settingName) != null;
}
@Override
- public String getName() {
+ public final String getName() {
return name;
}
@Override
- public String getDescription() {
+ public final String getStorageKey() {
+ return settingName;
+ }
+
+ @Override
+ public final String getDescription() {
return description;
}
@Override
public void clear(Settings settings) {
- settings.clearSetting(getSettingName());
+ settings.clearSetting(settingName);
}
@Override
public void copySetting(Settings srcSettings, Settings destSettings) {
- Long l = srcSettings.getLong(getSettingName());
+ Long l = srcSettings.getLong(settingName);
if (l == null) {
clear(destSettings);
}
@@ -168,7 +164,7 @@ public class JavaEnumSettingsDefinition> implements EnumSettin
@Override
public int getChoice(Settings settings) {
- Long lvalue = settings.getLong(getSettingName());
+ Long lvalue = settings.getLong(settingName);
int value = (lvalue != null) ? (int) (long) lvalue : defaultValue.ordinal();
return Math.min(Math.max(value, 0), values.length - 1);
@@ -181,7 +177,7 @@ public class JavaEnumSettingsDefinition> implements EnumSettin
@Override
public void setChoice(Settings settings, int value) {
- settings.setLong(getSettingName(), value);
+ settings.setLong(settingName, value);
}
@Override
diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/Settings.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/Settings.java
index 03740c3783..fe4e2c53d6 100644
--- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/Settings.java
+++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/Settings.java
@@ -22,6 +22,14 @@ package ghidra.docking.settings;
*/
public interface Settings {
+ /**
+ * Determine if a settings change corresponding to the specified
+ * settingsDefinition is permitted.
+ * @param settingsDefinition settings definition
+ * @return true if change permitted else false
+ */
+ boolean isChangeAllowed(SettingsDefinition settingsDefinition);
+
/**
* Gets the Long value associated with the given name
* @param name the key used to retrieve a value
diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsDefinition.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsDefinition.java
index 01c78d0723..0f2b45ec86 100644
--- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsDefinition.java
+++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsDefinition.java
@@ -16,6 +16,7 @@
package ghidra.docking.settings;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.function.Predicate;
/**
@@ -26,8 +27,7 @@ public interface SettingsDefinition {
/**
* Create a new list of {@link SettingsDefinition}s by concat'ing a base list with
- * a var-arg'ish additional list of setting defs.
- *
+ * a var-arg'ish additional list of setting defs. Any additional duplicates are discarded.
* @param settings List of settings defs.
* @param additional More settings defs to add
* @return new array with all the settings defs joined together.
@@ -40,11 +40,14 @@ public interface SettingsDefinition {
if (settings == null) {
return additional;
}
-
- SettingsDefinition[] result = new SettingsDefinition[settings.length + additional.length];
- System.arraycopy(settings, 0, result, 0, settings.length);
- System.arraycopy(additional, 0, result, settings.length, additional.length);
- return result;
+ ArrayList list = new ArrayList<>();
+ list.addAll(Arrays.asList(settings));
+ for (SettingsDefinition def : additional) {
+ if (!list.contains(def)) {
+ list.add(def);
+ }
+ }
+ return list.toArray(new SettingsDefinition[list.size()]);
}
/**
@@ -81,11 +84,17 @@ public interface SettingsDefinition {
public String getValueString(Settings settings);
/**
- * Returns the name of this SettingsDefinition
+ * Returns the display name of this SettingsDefinition
* @return display name for setting
*/
public String getName();
+ /**
+ * Get the {@link Settings} key which is used when storing a key/value entry.
+ * @return settings storage key
+ */
+ String getStorageKey();
+
/**
* Returns a description of this settings definition
* @return setting description
diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsImpl.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsImpl.java
index 228c26418a..98c077d538 100644
--- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsImpl.java
+++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsImpl.java
@@ -65,31 +65,19 @@ public class SettingsImpl implements Settings, Serializable {
}
/**
- * Check for immutable settings and log error of modification not permitted
- * @param type setting type or null
- * @param name setting name or null
- * @return true if change permitted
+ * Construct a new SettingsImpl object. If settings object is specified this
+ * settings will copy all name/value pairs and underlying defaults.
+ * @param settings the settings object to copy
*/
- private boolean checkSetting(String type, String name) {
- if (immutable) {
- String typeStr = "";
- if (type != null) {
- typeStr = type + " ";
+ public SettingsImpl(Settings settings) {
+ this();
+ if (settings != null) {
+ String[] names = settings.getNames();
+ for (int i = 0; i < names.length; i++) {
+ map.put(names[i], settings.getValue(names[i]));
}
- String nameStr = ": " + name;
- if (name == null) {
- nameStr = "s";
- }
- Msg.warn(SettingsImpl.class,
- "Ignored invalid attempt to modify immutable " + typeStr + "component setting" +
- nameStr);
- return false;
+ defaultSettings = settings.getDefaultSettings();
}
- if (allowedSettingPredicate != null && !allowedSettingPredicate.apply(name)) {
- Msg.warn(this, "Ignored disallowed setting '" + name + "'");
- return false;
- }
- return true;
}
/**
@@ -113,20 +101,45 @@ public class SettingsImpl implements Settings, Serializable {
this.changeSourceObj = changeSourceObj;
}
- /**
- * Construct a new SettingsImpl object. If settings object is specified this
- * settings will copy all name/value pairs and underlying defaults.
- * @param settings the settings object to copy
- */
- public SettingsImpl(Settings settings) {
- this();
- if (settings != null) {
- String[] names = settings.getNames();
- for (int i = 0; i < names.length; i++) {
- map.put(names[i], settings.getValue(names[i]));
- }
- defaultSettings = settings.getDefaultSettings();
+ @Override
+ public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
+ if (immutable) {
+ return false;
}
+ if (allowedSettingPredicate != null &&
+ !allowedSettingPredicate.apply(settingsDefinition.getStorageKey())) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Check for immutable settings and log error of modification not permitted
+ * @param type setting type or null
+ * @param name setting name or null
+ * @return true if change permitted
+ */
+ private boolean checkSetting(String type, String name) {
+ if (immutable) {
+ String typeStr = "";
+ if (type != null) {
+ typeStr = type + " ";
+ }
+ String nameStr = ": " + name;
+ if (name == null) {
+ nameStr = "s";
+ }
+ Msg.warn(SettingsImpl.class,
+ "Ignored invalid attempt to modify immutable " + typeStr + "component setting" +
+ nameStr);
+ return false;
+ }
+ if (name != null && allowedSettingPredicate != null &&
+ !allowedSettingPredicate.apply(name)) {
+ Msg.warn(this, "Ignored disallowed setting '" + name + "'");
+ return false;
+ }
+ return true;
}
@Override
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDBHandle.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDBHandle.java
index 49ea1afae6..e5af28139a 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDBHandle.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDBHandle.java
@@ -82,9 +82,10 @@ public class PackedDBHandle extends DBHandle {
}
@Override
- protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId, TaskMonitor monitor)
+ protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId,
+ boolean associateWithNewFile, TaskMonitor monitor)
throws IOException, CancelledException {
- super.saveAs(outFile, newDatabaseId, monitor);
+ super.saveAs(outFile, newDatabaseId, associateWithNewFile, monitor);
if (pdb != null) {
pdb.dispose();
pdb = null;
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDatabase.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDatabase.java
index c36c663248..7c52469008 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDatabase.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/db/PackedDatabase.java
@@ -179,7 +179,7 @@ public class PackedDatabase extends Database {
LocalManagedBufferFile bfile = new LocalManagedBufferFile(dbHandle.getBufferSize(),
bfMgr, FolderItem.DEFAULT_CHECKOUT_ID);
- dbHandle.saveAs(bfile, newDatabaseId, monitor);
+ dbHandle.saveAs(bfile, newDatabaseId, true, monitor);
packDatabase(monitor);
addInstance(this);
success = true;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoData.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoData.java
index bd837d1457..6ee5a8174b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoData.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoData.java
@@ -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 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);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java
index 4208d0118f..0e2b4c88e0 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java
@@ -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
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerTypedefInspector.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerTypedefInspector.java
index c38023c790..a605019334 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerTypedefInspector.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerTypedefInspector.java
@@ -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) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java
index 8f74f0547e..20cde8ca57 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java
@@ -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();
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SettingsDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SettingsDBAdapterV1.java
index 3f3326aa5d..6a9cfae3fc 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SettingsDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SettingsDBAdapterV1.java
@@ -55,8 +55,8 @@ class SettingsDBAdapterV1 extends SettingsDBAdapter {
private Table settingsTable;
private Table settingsNameTable;
- private HashMap nameIndexMap = new HashMap<>();
- private HashMap nameStringMap = new HashMap<>();
+ private HashMap nameIndexMap;
+ private HashMap nameStringMap;
SettingsDBAdapterV1(String tableName, DBHandle handle, boolean create)
throws VersionException, IOException {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java
index 4f419875b8..c1ca9ab810 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java
@@ -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;
+ }
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapter.java
index 9dd75a5a81..a2746aa88a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapter.java
@@ -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;
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV0.java
index 2c1dbffb0e..6eaa2a2d3c 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV0.java
@@ -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);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV1.java
index eda97c81c4..d89c386594 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV1.java
@@ -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;
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV2.java
new file mode 100644
index 0000000000..39226fa23d
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV2.java
@@ -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;
+ }
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java
index 3fa67ebacd..4d09c023f1 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java
@@ -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
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractImageBaseOffsetDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractImageBaseOffsetDataType.java
deleted file mode 100644
index 22d0306068..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractImageBaseOffsetDataType.java
+++ /dev/null
@@ -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;
- }
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java
similarity index 86%
rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefDataType.java
rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java
index 4f121ff6e5..a86bedc28a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java
@@ -25,14 +25,10 @@ import ghidra.util.UniversalID;
import ghidra.util.UniversalIdGenerator;
/**
- * AbstractPointerTypedefDataType provides an abstract implementation for
- * a Pointer-Typedef BuiltIn datatype.
- *
- * 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.
+ * AbstractPointerTypedefDataType 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);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharsetSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharsetSettingsDefinition.java
index 42892bd606..2381d25487 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharsetSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharsetSettingsDefinition.java
@@ -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";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ComponentOffsetSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ComponentOffsetSettingsDefinition.java
index 60d80d5c49..563fbf5b56 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ComponentOffsetSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ComponentOffsetSettingsDefinition.java
@@ -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;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java
index 883e292c25..0e6f8b35a3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java
@@ -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;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java
index 144eb8cfa9..b3deabd11a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java
@@ -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
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeMnemonicSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeMnemonicSettingsDefinition.java
index 3f77587c19..0b57bfd833 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeMnemonicSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeMnemonicSettingsDefinition.java
@@ -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";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EndianSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EndianSettingsDefinition.java
index c655139e4a..6939ea0bab 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EndianSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EndianSettingsDefinition.java
@@ -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";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IBO32DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IBO32DataType.java
index 517b41e39a..2528afd4e1 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IBO32DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IBO32DataType.java
@@ -15,27 +15,43 @@
*/
package ghidra.program.model.data;
+import ghidra.docking.settings.Settings;
+import ghidra.util.classfinder.ClassTranslator;
+
/**
* IBO32DataType 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}.
+ *
+ * This class replaces the use of the old ImageBaseOffset32DataType
+ * 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);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IBO64DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IBO64DataType.java
index cc78d5641d..894cb3c7a6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IBO64DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IBO64DataType.java
@@ -15,27 +15,43 @@
*/
package ghidra.program.model.data;
+import ghidra.docking.settings.Settings;
+import ghidra.util.classfinder.ClassTranslator;
+
/**
* IBO64DataType 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}.
+ *
+ * This class replaces the use of the old ImageBaseOffset64DataType
+ * 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);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ImageBaseOffset32DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ImageBaseOffset32DataType.java
deleted file mode 100644
index 8505ae9422..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ImageBaseOffset32DataType.java
+++ /dev/null
@@ -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);
- }
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ImageBaseOffset64DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ImageBaseOffset64DataType.java
deleted file mode 100644
index a8e69fdb45..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ImageBaseOffset64DataType.java
+++ /dev/null
@@ -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);
- }
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MutabilitySettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MutabilitySettingsDefinition.java
index 7ab887e13d..c7cf3a30bd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MutabilitySettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MutabilitySettingsDefinition.java
@@ -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";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PaddingSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PaddingSettingsDefinition.java
index d37bf58d24..a8cf53d6fd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PaddingSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PaddingSettingsDefinition.java
@@ -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";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java
index 8d2810c556..b102e2fea7 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java
@@ -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();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerType.java
index b56932da4e..391e67e033 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerType.java
@@ -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
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypeSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypeSettingsDefinition.java
index c47a5a2700..5b74e32447 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypeSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypeSettingsDefinition.java
@@ -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" };
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedef.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedef.java
index 7ecc1596e7..2a417ef12a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedef.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedef.java
@@ -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;
/**
* PointerTypedef 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}.
+ *
+ * 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;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedefBuilder.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedefBuilder.java
index 0057a40d94..f5c45e23c6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedefBuilder.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedefBuilder.java
@@ -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;
/**
* PointerTypedefBuilder 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;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramBasedDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramBasedDataTypeManager.java
index c9ef0e0286..1fc1eda8f3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramBasedDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramBasedDataTypeManager.java
@@ -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
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TerminatedSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TerminatedSettingsDefinition.java
index 1228652316..c74dfbb86b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TerminatedSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TerminatedSettingsDefinition.java
@@ -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";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDef.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDef.java
index cb9419a6a3..c0492db5bf 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDef.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDef.java
@@ -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;
}
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDefSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDefSettingsDefinition.java
index 95f05bebe9..456393b106 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDefSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDefSettingsDefinition.java
@@ -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.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java
index 3a495f0550..840fd731d7 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java
@@ -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();
}
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataStub.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataStub.java
index 0131532cdd..237039f40b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataStub.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataStub.java
@@ -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();
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/SettingsBuilder.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/SettingsBuilder.java
index 39b02d70b9..8a61f66d3b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/SettingsBuilder.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/SettingsBuilder.java
@@ -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}.
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java
index f5687c7a1c..93b977a761 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java
@@ -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();
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java
index 5dbb81a14d..142c21800c 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java
@@ -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