diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java
index 6648157c64..ddce23a38b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java
@@ -23,7 +23,6 @@ import ghidra.framework.Application;
import ghidra.framework.data.DomainObjectAdapterDB;
import ghidra.framework.model.*;
import ghidra.framework.options.Options;
-import ghidra.program.database.data.ProjectDataTypeManager;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.listing.DataTypeArchive;
@@ -32,7 +31,6 @@ import ghidra.program.util.*;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
-import ghidra.util.task.TaskMonitorAdapter;
/**
* Database implementation for Data Type Archive.
@@ -493,7 +491,7 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB
// }
try {
- dataTypeManager = new ProjectDataTypeManager(dbh, openMode, this, lock, monitor);
+ dataTypeManager = new ProjectDataTypeManager(this, dbh, openMode, this, lock, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
@@ -506,7 +504,6 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB
private void initManagers(int openMode, TaskMonitor monitor)
throws IOException, CancelledException {
monitor.checkCanceled();
- dataTypeManager.setDataTypeArchive(this);
dataTypeManager.archiveReady(openMode, monitor);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
index 80cfeb8140..17d754799e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
@@ -36,7 +36,6 @@ import ghidra.program.database.code.InstructionDB;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.database.external.ExternalManagerDB;
import ghidra.program.database.function.FunctionManagerDB;
-import ghidra.program.database.map.AddressMap;
import ghidra.program.database.map.AddressMapDB;
import ghidra.program.database.mem.MemoryMapDB;
import ghidra.program.database.module.TreeManager;
@@ -745,13 +744,13 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
/**
* Returns this programs address map.
- * NOTE: This method has been dropped from the Program interface to help
- * discourage the use of the program's address map since bad assumptions
+ * NOTE: This method should be dropped from the {@link Program} interface to help
+ * discourage the its use external to this implementation since bad assumptions
* are frequently made about address keys which may not be ordered or sequential
* across an entire address space.
*/
@Override
- public AddressMap getAddressMap() {
+ public AddressMapDB getAddressMap() {
return addrMap;
}
@@ -1678,7 +1677,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
monitor.checkCanceled();
try {
- managers[SYMBOL_MGR] = new SymbolManager(dbh, addrMap, openMode, lock, monitor);
+ managers[SYMBOL_MGR] = new SymbolManager(dbh, addrMap, openMode, this, lock, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
@@ -2069,6 +2068,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
contextMgr.initializeDefaultValues(language, compilerSpec);
}
+ // Update datatype manager data organization
+ getDataTypeManager().languageChanged(monitor);
+
// Force function manager to reconcile calling conventions
managers[FUNCTION_MGR].setProgram(this);
managers[FUNCTION_MGR].programReady(UPDATE, getStoredVersion(), monitor);
@@ -2443,6 +2445,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
lock.acquire();
try {
((ProgramCompilerSpec) compilerSpec).installExtensions();
+ getFunctionManager().invalidateCache(true);
+ getDataTypeManager().invalidateCache();
}
finally {
lock.release();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProjectDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java
similarity index 76%
rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProjectDataTypeManager.java
rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java
index 41b4f5b6fd..abace47dc5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProjectDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java
@@ -13,17 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.program.database.data;
+package ghidra.program.database;
import java.io.IOException;
-import java.util.Iterator;
import java.util.LinkedList;
+import javax.help.UnsupportedOperationException;
+
import db.*;
import db.util.ErrorHandler;
import ghidra.framework.model.DomainFile;
-import ghidra.program.database.DataTypeArchiveDB;
+import ghidra.framework.store.LockException;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.util.DataTypeArchiveChangeManager;
import ghidra.util.InvalidNameException;
import ghidra.util.Lock;
@@ -35,13 +38,23 @@ import ghidra.util.task.TaskMonitor;
* Class for managing data types in a project archive
* NOTE: default data organization is used.
*/
-public class ProjectDataTypeManager extends DataTypeManagerDB
+public class ProjectDataTypeManager extends StandAloneDataTypeManager
implements ProjectArchiveBasedDataTypeManager {
- private DataTypeArchiveDB dataTypeArchive;
+ private final DataTypeArchiveDB dataTypeArchive;
/**
- * Constructor
+ * Constructor for a data-type manager using a specified DBHandle.
+ *
+ * NOTE: If archive has an assigned architecture, issues may arise due to a revised or
+ * missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
+ * prevent the archive from being opened. Such a warning condition will ne logged and may
+ * result in missing or stale information for existing datatypes which have architecture related
+ * data. In some case it may be appropriate to
+ * {@link FileDataTypeManager#getWarning() check for warnings} on the returned archive
+ * object prior to its use.
+ *
+ * @param dataTypeArchive associated archive
* @param handle open database handle
* @param openMode the program open mode
* @param errHandler the database I/O error handler
@@ -51,17 +64,12 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
* @throws VersionException if the database does not match the expected version.
* @throws IOException if a database I/O error occurs.
*/
- public ProjectDataTypeManager(DBHandle handle, int openMode, ErrorHandler errHandler, Lock lock,
+ ProjectDataTypeManager(DataTypeArchiveDB dataTypeArchive, DBHandle handle, int openMode,
+ ErrorHandler errHandler, Lock lock,
TaskMonitor monitor) throws CancelledException, VersionException, IOException {
- super(handle, null, openMode, errHandler, lock, monitor);
- }
-
- /**
- * Set the associated Archive
- * @param dtArchive associated archive
- */
- public void setDataTypeArchive(DataTypeArchiveDB dtArchive) {
- this.dataTypeArchive = dtArchive;
+ super(handle, openMode, errHandler, lock, monitor);
+ this.dataTypeArchive = dataTypeArchive;
+ reportWarning();
}
@Override
@@ -69,11 +77,6 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
return dataTypeArchive.getDomainFile().getName();
}
- @Override
- public Pointer getPointer(DataType dt) {
- return PointerDataType.getPointer(dt, dataTypeArchive.getDefaultPointerSize());
- }
-
@Override
public void setName(String name) throws InvalidNameException {
if (name == null || name.length() == 0) {
@@ -84,6 +87,23 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
categoryRenamed(CategoryPath.ROOT, null);
}
+ @Override
+ public void clearProgramArchitecture(TaskMonitor monitor)
+ throws CancelledException, IOException, LockException {
+ dataTypeArchive.checkExclusiveAccess();
+ super.clearProgramArchitecture(monitor);
+ }
+
+ @Override
+ public void setProgramArchitecture(Language language, CompilerSpecID compilerSpecId,
+ LanguageUpdateOption updateOption, TaskMonitor monitor)
+ throws CompilerSpecNotFoundException, LanguageNotFoundException, IOException,
+ LockException, UnsupportedOperationException, IncompatibleLanguageException,
+ CancelledException {
+ dataTypeArchive.checkExclusiveAccess();
+ super.setProgramArchitecture(language, compilerSpecId, updateOption, monitor);
+ }
+
////////////////////
@Override
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
@@ -169,21 +189,12 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
///////////////////
@Override
protected void replaceDataTypeIDs(long oldDataTypeID, long newDataTypeID) {
-// dataTypeArchive.getCodeManager().replace(oldID, newID, monitor);
- // TODO
+ // do nothing
}
@Override
- protected void deleteDataTypeIDs(LinkedList deletedIds, TaskMonitor monitor)
- throws CancelledException {
- long[] ids = new long[deletedIds.size()];
- Iterator it = deletedIds.iterator();
- int i = 0;
- while (it.hasNext()) {
- ids[i++] = it.next().longValue();
- }
-// dataTypeArchive.getCodeManager().clearData(ids, monitor);
- // TODO
+ protected void deleteDataTypeIDs(LinkedList deletedIds, TaskMonitor monitor) {
+ // do nothing
}
@Override
@@ -191,6 +202,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
return dataTypeArchive.openTransaction(description);
}
+ @SuppressWarnings("sync-override")
@Override
public int startTransaction(String description) {
return dataTypeArchive.startTransaction(description);
@@ -201,6 +213,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
dataTypeArchive.flushEvents();
}
+ @SuppressWarnings("sync-override")
@Override
public void endTransaction(int transactionID, boolean commit) {
dataTypeArchive.endTransaction(transactionID, commit);
@@ -231,7 +244,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
public void archiveReady(int openMode, TaskMonitor monitor)
throws IOException, CancelledException {
if (openMode == DBConstants.UPGRADE) {
- doSourceArchiveUpdates(null, monitor);
+ doSourceArchiveUpdates(monitor);
migrateOldFlexArrayComponentsIfRequired(monitor);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java
index 01372bef38..cab9d93887 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java
@@ -721,7 +721,7 @@ public class SpecExtension {
PrototypeModel currentModel = function.getCallingConvention();
if (currentModel != null && currentModel.getName().equals(modelName)) {
try {
- function.setCallingConvention("unknown");
+ function.setCallingConvention(Function.UNKNOWN_CALLING_CONVENTION_STRING);
}
catch (InvalidInputException e) {
// shouldn't reach here
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java
index 2dfe56cdec..d1c446d444 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java
@@ -47,6 +47,7 @@ class DataDB extends CodeUnitDB implements Data {
protected DataType baseDataType;
protected int level = 0;
+
protected ProgramDataTypeManager dataMgr;
private Boolean hasMutabilitySetting;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapter.java
index ba42612d9e..af5ed4b49e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapter.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -33,13 +34,25 @@ abstract class ArrayDBAdapter {
static final int ARRAY_ELEMENT_LENGTH_COL = ArrayDBAdapterV1.V1_ARRAY_ELEMENT_LENGTH_COL;
static final int ARRAY_CAT_COL = ArrayDBAdapterV1.V1_ARRAY_CAT_COL;
- static ArrayDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ /**
+ * Gets an adapter for working with the {@link ArrayDB} database table.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
+ * @return adapter instance
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is a problem accessing the database.
+ * @throws CancelledException task cancelled
+ */
+ static ArrayDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new ArrayDBAdapterV1(handle, true);
+ return new ArrayDBAdapterV1(handle, tablePrefix, true);
}
try {
- return new ArrayDBAdapterV1(handle, false);
+ return new ArrayDBAdapterV1(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -47,33 +60,36 @@ abstract class ArrayDBAdapter {
}
ArrayDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
}
- static ArrayDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
+ private static ArrayDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
return new ArrayDBAdapterV0(handle);
}
- static ArrayDBAdapter upgrade(DBHandle handle, ArrayDBAdapter oldAdapter)
- throws VersionException, IOException {
+ private static ArrayDBAdapter upgrade(DBHandle handle, ArrayDBAdapter oldAdapter,
+ String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
ArrayDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new ArrayDBAdapterV1(tmpHandle, true);
+ tmpAdapter = new ArrayDBAdapterV1(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- ArrayDBAdapterV1 newAdapter = new ArrayDBAdapterV1(handle, true);
+ ArrayDBAdapterV1 newAdapter = new ArrayDBAdapterV1(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV0.java
index 8e6c3e10e5..3ef1f94bc5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV0.java
@@ -24,13 +24,14 @@ import ghidra.util.exception.VersionException;
*
*/
class ArrayDBAdapterV0 extends ArrayDBAdapter {
+
+ private static final int VERSION = 0;
+
private static final String ARRAY_TABLE_NAME = "Arrays";
private static final int V0_ARRAY_DT_ID_COL = 0;
private static final int V0_ARRAY_DIM_COL = 1;
private static final int V0_ARRAY_ELEMENT_LENGTH_COL = 2; // applies to sizable dynamic types only
- private Table table;
-
// DO NOT REMOVE - this documents the schema used in version 0.
// public static final Schema SCHEMA = new Schema(0, "Array ID",
// new Class[] {LongField.class, IntField.class,
@@ -38,9 +39,13 @@ class ArrayDBAdapterV0 extends ArrayDBAdapter {
// new String[] {"Data Type ID", "Dimension",
// "Length"});
+ private Table table;
+
/**
- * Constructor
- *
+ * Gets a version 0 read-only adapter for the {@link ArrayDB} database table.
+ * @param handle handle to the database containing the table.
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
*/
public ArrayDBAdapterV0(DBHandle handle) throws VersionException {
@@ -48,9 +53,8 @@ class ArrayDBAdapterV0 extends ArrayDBAdapter {
if (table == null) {
throw new VersionException("Missing Table: " + ARRAY_TABLE_NAME);
}
- else if (table.getSchema().getVersion() != 0) {
- throw new VersionException("Expected version 0 for table " + ARRAY_TABLE_NAME +
- " but got " + table.getSchema().getVersion());
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException();
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV1.java
index c1ec6c3779..938f736c9c 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV1.java
@@ -25,40 +25,49 @@ import ghidra.util.exception.VersionException;
* To change the template for this generated type comment go to
* {@literal Window>Preferences>Java>Code Generation>Code and Comments}
*
- *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class ArrayDBAdapterV1 extends ArrayDBAdapter {
+
static final int VERSION = 1;
+
static final String ARRAY_TABLE_NAME = "Arrays";
static final int V1_ARRAY_DT_ID_COL = 0;
static final int V1_ARRAY_DIM_COL = 1;
static final int V1_ARRAY_ELEMENT_LENGTH_COL = 2; // applies to sizable dynamic types only
static final int V1_ARRAY_CAT_COL = 3;
- private Table table;
-
public static final Schema V1_SCHEMA =
new Schema(VERSION, "Array ID",
new Field[] { LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE,
LongField.INSTANCE },
new String[] { "Data Type ID", "Dimension", "Length", "Cat ID" });
- /**
- * Constructor
- *
- */
- public ArrayDBAdapterV1(DBHandle handle, boolean create) throws VersionException, IOException {
+ private Table table;
+ /**
+ * Gets a version 1 adapter for the {@link ArrayDB} database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create create table if true else acquire for read-only or update use
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
+ * @throws IOException an IO error occured during table creation
+ */
+ public ArrayDBAdapterV1(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + ARRAY_TABLE_NAME;
if (create) {
- table = handle.createTable(ARRAY_TABLE_NAME, V1_SCHEMA, new int[] { V1_ARRAY_CAT_COL });
+ table = handle.createTable(tableName, V1_SCHEMA, new int[] { V1_ARRAY_CAT_COL });
}
else {
- table = handle.getTable(ARRAY_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + ARRAY_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- else if (table.getSchema().getVersion() != VERSION) {
- throw new VersionException(VersionException.NEWER_VERSION, false);
+ int version = table.getSchema().getVersion();
+ if (version != VERSION) {
+ throw new VersionException(version < VERSION);
}
}
}
@@ -67,11 +76,7 @@ class ArrayDBAdapterV1 extends ArrayDBAdapter {
public DBRecord createRecord(long dataTypeID, int numberOfElements, int length, long catID)
throws IOException {
- long tableKey = table.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.ARRAY, tableKey);
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.ARRAY, table.getKey());
DBRecord record = V1_SCHEMA.createRecord(key);
record.setLongValue(V1_ARRAY_DT_ID_COL, dataTypeID);
@@ -105,7 +110,7 @@ class ArrayDBAdapterV1 extends ArrayDBAdapter {
@Override
void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(ARRAY_TABLE_NAME);
+ handle.deleteTable(table.getName());
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapter.java
index 809a6f4097..b146cf8e80 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapter.java
@@ -19,7 +19,6 @@ import java.io.IOException;
import db.*;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
/**
* Database adapter for managing built-in data types.
@@ -35,14 +34,14 @@ public abstract class BuiltinDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
- * @param monitor the monitor to use for displaying status or for canceling.
+ * @param tablePrefix prefix to be used with default table name
* @return the adapter for accessing the table of built-in data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there was a problem accessing the database
*/
- static BuiltinDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
+ static BuiltinDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
- return new BuiltinDBAdapterV0(handle, openMode == DBConstants.CREATE);
+ return new BuiltinDBAdapterV0(handle, tablePrefix, openMode == DBConstants.CREATE);
}
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapterV0.java
index 9075a5c7f8..c6525617f0 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapterV0.java
@@ -24,38 +24,44 @@ import ghidra.util.exception.VersionException;
* Version 0 implementation of the adapter for accessing the built-ins table.
*/
class BuiltinDBAdapterV0 extends BuiltinDBAdapter {
+
+ private static final int VERSION = 0;
+
static final String BUILT_IN_TABLE_NAME = "Built-in datatypes";
static final int V0_BUILT_IN_NAME_COL = 0;
static final int V0_BUILT_IN_CLASSNAME_COL = 1;
static final int V0_BUILT_IN_CAT_COL = 2;
+
static final Schema V0_SCHEMA = new Schema(0, "Data Type ID",
new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE },
new String[] { "Name", "Class Name", "Category ID" });
+
private Table table;
/**
* Gets a version 0 adapter for the Built-Ins database table.
* @param handle handle to the database containing the table.
- * @param create true if this constructor should create the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create create table if true else acquire for read-only or update use
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if there is trouble accessing the database.
*/
- public BuiltinDBAdapterV0(DBHandle handle, boolean create)
+ public BuiltinDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
+ String tableName = tablePrefix + BUILT_IN_TABLE_NAME;
if (create) {
- table = handle.createTable(BUILT_IN_TABLE_NAME, V0_SCHEMA,
+ table = handle.createTable(tableName, V0_SCHEMA,
new int[] { V0_BUILT_IN_CAT_COL });
}
else {
- table = handle.getTable(BUILT_IN_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + BUILT_IN_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- else if (table.getSchema().getVersion() != 0) {
- throw new VersionException("Expected version 0 for table " + BUILT_IN_TABLE_NAME +
- " but got " + table.getSchema().getVersion());
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapter.java
new file mode 100644
index 0000000000..8001512af3
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapter.java
@@ -0,0 +1,119 @@
+/* ###
+ * 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.Set;
+import java.util.function.Consumer;
+
+import db.*;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.VersionException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * Adapter to access the Function Calling Conventions tables.
+ */
+abstract class CallingConventionDBAdapter {
+
+ static final byte UNKNOWN_CALLING_CONVENTION_ID = (byte) 0;
+ static final byte DEFAULT_CALLING_CONVENTION_ID = (byte) 1;
+ static final byte FIRST_CALLING_CONVENTION_ID = (byte) 2;
+
+ static final String CALLING_CONVENTION_TABLE_NAME = "Calling Conventions";
+
+ static final Schema CALLING_CONVENTION_SCHEMA =
+ CallingConventionDBAdapterV0.V0_CALLING_CONVENTION_SCHEMA;
+ // Calling Convention Columns
+ static final int CALLING_CONVENTION_NAME_COL =
+ CallingConventionDBAdapterV0.V0_CALLING_CONVENTION_NAME_COL;
+
+ /**
+ * Gets an adapter for working with the calling convention database table.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
+ * @return adapter instance
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is a problem accessing the database.
+ * @throws CancelledException if task is cancelled
+ */
+ static CallingConventionDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
+ if (openMode == DBConstants.CREATE) {
+ return new CallingConventionDBAdapterV0(handle, tablePrefix, true);
+ }
+ try {
+ return new CallingConventionDBAdapterV0(handle, tablePrefix, false);
+ }
+ catch (VersionException e) {
+ if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
+ throw e;
+ }
+ CallingConventionDBAdapter adapter = findReadOnlyAdapter(handle);
+ if (openMode == DBConstants.UPGRADE) {
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
+ }
+ return adapter;
+ }
+ }
+
+ private static CallingConventionDBAdapter findReadOnlyAdapter(DBHandle handle) {
+ return new CallingConventionDBAdapterNoTable();
+ }
+
+ private static CallingConventionDBAdapter upgrade(DBHandle handle,
+ CallingConventionDBAdapter oldAdapter, String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException {
+ return new CallingConventionDBAdapterV0(handle, tablePrefix, true);
+ }
+
+ /**
+ * Get (and assign if needed thus requiring open transaction) the ID associated with the
+ * specified calling convention name. If name is a new convention and the number of stored
+ * convention names exceeds 127 the returned ID will correspond to the unknown calling
+ * convention.
+ * @param name calling convention name or null if unknown
+ * @param conventionAdded callback when new calling convention is added
+ * @return calling convention ID
+ * @throws IOException if an IO error occurs
+ */
+ abstract byte getCallingConventionId(String name, Consumer conventionAdded)
+ throws IOException;
+
+ /**
+ * Get calling convention name which corresponds to the specified id.
+ * @param id calling convention storage ID
+ * @return calling convention name or null if unknown call convention
+ * @throws IOException if IO error occurs
+ */
+ abstract String getCallingConventionName(byte id) throws IOException;
+
+ /**
+ * Clear calling convention cached lookup maps
+ */
+ abstract void invalidateCache();
+
+ /**
+ * Get all stored calling convention names. The "default" and "unknown"
+ * names are excluded from this set.
+ * @return set of all stored calling convention names
+ * @throws IOException if an IO error occurs
+ */
+ abstract Set getCallingConventionNames() throws IOException;
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterNoTable.java
new file mode 100644
index 0000000000..d09de20140
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterNoTable.java
@@ -0,0 +1,56 @@
+/* ###
+ * 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.Set;
+import java.util.function.Consumer;
+
+import javax.help.UnsupportedOperationException;
+
+/**
+ * Adapter when no Calling Convention table exists.
+ */
+class CallingConventionDBAdapterNoTable extends CallingConventionDBAdapter {
+
+ /**
+ * Gets a no-table adapter for the calling convention database table.
+ */
+ CallingConventionDBAdapterNoTable() {
+ // no table - do nothing
+ }
+
+ @Override
+ byte getCallingConventionId(String name, Consumer conventionAdded) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ String getCallingConventionName(byte id) throws IOException {
+ return null;
+ }
+
+ @Override
+ void invalidateCache() {
+ // do nothing
+ }
+
+ @Override
+ Set getCallingConventionNames() throws IOException {
+ return Set.of();
+ }
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterV0.java
new file mode 100644
index 0000000000..8815377062
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterV0.java
@@ -0,0 +1,187 @@
+/* ###
+ * 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.*;
+import java.util.function.Consumer;
+
+import com.google.common.collect.Range;
+import com.google.common.collect.TreeRangeSet;
+
+import db.*;
+import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.listing.Function;
+import ghidra.util.Msg;
+import ghidra.util.exception.VersionException;
+
+/**
+ * Version 0 implementation for the calling conventions tables adapter.
+ *
+ */
+class CallingConventionDBAdapterV0 extends CallingConventionDBAdapter {
+
+ private static final int VERSION = 0;
+
+ // Calling Convention Columns
+ // Key field is the Calling convention ID, which is a Byte field.
+ static final int V0_CALLING_CONVENTION_NAME_COL = 0;
+
+ static final Schema V0_CALLING_CONVENTION_SCHEMA = new Schema(0, ByteField.INSTANCE, "ID",
+ new Field[] { StringField.INSTANCE }, new String[] { "Name" });
+
+ private Table callingConventionTable;
+
+ private Map callingConventionNameToIDMap;
+ private Map callingConventionIDToNameMap;
+
+ // There is currently no method for removing an allocated calling convention name/ID,
+ // therefor we can assume key consumption will be sequential until the ability
+ // to delete is added. Use of freeKeySet can be eliminated if delete ability never added.
+ private TreeRangeSet freeKeySet; // closed-ranges only
+
+ /**
+ * Gets a version 0 adapter for the calling convention database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @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 an IO error occurs
+ */
+ CallingConventionDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + CALLING_CONVENTION_TABLE_NAME;
+ if (create) {
+ // No additional indexed fields.
+ callingConventionTable = handle.createTable(tableName,
+ V0_CALLING_CONVENTION_SCHEMA, new int[] {});
+ }
+ else {
+ callingConventionTable = handle.getTable(tableName);
+ if (callingConventionTable == null) {
+ throw new VersionException(true);
+ }
+ if (callingConventionTable.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
+ }
+ }
+ }
+
+ /**
+ * Remove next available free key value from freeKeySet.
+ * @return the next available key. A negative value indicates that all allowed IDs have
+ * been used.
+ */
+ private byte removeFirstAvailableKey() {
+ Iterator> it = freeKeySet.asRanges().iterator();
+ if (!it.hasNext()) {
+ return -1;
+ }
+ Range r = it.next();
+ it.remove();
+ byte nextId = r.lowerEndpoint();
+ byte lastId = r.upperEndpoint();
+ if (nextId != lastId) {
+ freeKeySet.add(Range.closed((byte) (nextId + 1), lastId));
+ }
+ return nextId;
+ }
+
+ @Override
+ void invalidateCache() {
+ callingConventionNameToIDMap = null;
+ callingConventionIDToNameMap = null;
+ freeKeySet = null;
+ }
+
+ private void populateCache() throws IOException {
+ if (callingConventionNameToIDMap != null) {
+ return;
+ }
+ callingConventionNameToIDMap = new HashMap<>();
+ callingConventionIDToNameMap = new HashMap<>();
+
+ freeKeySet = TreeRangeSet.create();
+ int nextKey = FIRST_CALLING_CONVENTION_ID;
+ RecordIterator iterator = callingConventionTable.iterator();
+ while (iterator.hasNext()) {
+ DBRecord rec = iterator.next();
+
+ byte id = (byte) rec.getKey();
+ String name = rec.getString(V0_CALLING_CONVENTION_NAME_COL);
+ callingConventionIDToNameMap.put(id, name);
+ callingConventionNameToIDMap.put(name, id);
+
+ if (nextKey != id) {
+ freeKeySet.add(Range.closed((byte) nextKey, (byte) (id - 1)));
+ }
+ nextKey = id + 1;
+ }
+ if (nextKey <= Byte.MAX_VALUE) {
+ freeKeySet.add(Range.closed((byte) nextKey, Byte.MAX_VALUE));
+ }
+ }
+
+ @Override
+ byte getCallingConventionId(String name, Consumer conventionAdded) throws IOException {
+ if (name == null || name.equals(CompilerSpec.CALLING_CONVENTION_unknown)) {
+ return UNKNOWN_CALLING_CONVENTION_ID;
+ }
+ else if (name.equals(CompilerSpec.CALLING_CONVENTION_default)) {
+ return DEFAULT_CALLING_CONVENTION_ID;
+ }
+ populateCache();
+ Byte id = callingConventionNameToIDMap.get(name);
+ if (id != null) {
+ return id;
+ }
+
+ byte newId = removeFirstAvailableKey();
+ if (newId < 0) {
+ Msg.error(this, "Unable to assign calling convention `" + name +
+ "` - allocation capacity exceeded");
+ return UNKNOWN_CALLING_CONVENTION_ID;
+ }
+
+ DBRecord record = V0_CALLING_CONVENTION_SCHEMA.createRecord(new ByteField(newId));
+ record.setString(V0_CALLING_CONVENTION_NAME_COL, name);
+ callingConventionTable.putRecord(record);
+
+ callingConventionIDToNameMap.put(newId, name);
+ callingConventionNameToIDMap.put(name, newId);
+ conventionAdded.accept(name);
+ return newId;
+ }
+
+ @Override
+ String getCallingConventionName(byte id) throws IOException {
+ if (id == DEFAULT_CALLING_CONVENTION_ID) {
+ return Function.DEFAULT_CALLING_CONVENTION_STRING;
+ }
+ else if (id == UNKNOWN_CALLING_CONVENTION_ID) {
+ return null;
+ }
+ populateCache();
+ return callingConventionIDToNameMap.get(id);
+ }
+
+ @Override
+ Set getCallingConventionNames() throws IOException {
+ populateCache();
+ return callingConventionNameToIDMap.keySet();
+ }
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapter.java
index 1cf7867ef7..3f0783ac78 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapter.java
@@ -18,16 +18,25 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.program.model.data.Category;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
abstract class CategoryDBAdapter {
static final int CATEGORY_NAME_COL = CategoryDBAdapterV0.V0_CATEGORY_NAME_COL;
static final int CATEGORY_PARENT_COL = CategoryDBAdapterV0.V0_CATEGORY_PARENT_COL;
- static CategoryDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
+ /**
+ * Gets an adapter for working with the {@link Category} database table.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @return adapter instance
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is a problem accessing the database.
+ */
+ static CategoryDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
- return new CategoryDBAdapterV0(handle, openMode);
+ return new CategoryDBAdapterV0(handle, tablePrefix, openMode == DBConstants.CREATE);
}
/**
@@ -81,7 +90,16 @@ abstract class CategoryDBAdapter {
*/
abstract DBRecord getRootRecord() throws IOException;
+ /**
+ * Update record in database
+ * @param record category record
+ * @throws IOException if IO error occurs
+ */
abstract void putRecord(DBRecord record) throws IOException;
+ /**
+ * Get the total number of category records
+ * @return category record count
+ */
abstract int getRecordCount();
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapterV0.java
index 62f260be8c..6c45bab1bb 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapterV0.java
@@ -21,9 +21,13 @@ import db.*;
import ghidra.util.exception.VersionException;
class CategoryDBAdapterV0 extends CategoryDBAdapter {
+
+ private static final int VERSION = 0;
+
static final String CATEGORY_TABLE_NAME = "Categories";
static final int V0_CATEGORY_NAME_COL = 0;
static final int V0_CATEGORY_PARENT_COL = 1;
+
static final Schema V0_SCHEMA =
new Schema(0, "Category ID", new Field[] { StringField.INSTANCE, LongField.INSTANCE },
new String[] { "Name", "Parent ID" });
@@ -31,34 +35,38 @@ class CategoryDBAdapterV0 extends CategoryDBAdapter {
private Table table;
/**
- * Constructor
- *
+ * Gets a version 0 adapter for the Category database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @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 an IO error occurs
*/
- public CategoryDBAdapterV0(DBHandle handle, int openMode) throws VersionException, IOException {
-
- if (openMode == DBConstants.CREATE) {
- table = handle.createTable(CATEGORY_TABLE_NAME, V0_SCHEMA,
- new int[] { V0_CATEGORY_PARENT_COL });
+ CategoryDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + CATEGORY_TABLE_NAME;
+ if (create) {
+ table = handle.createTable(tableName, V0_SCHEMA, new int[] { V0_CATEGORY_PARENT_COL });
}
else {
- table = handle.getTable(CATEGORY_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + CATEGORY_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- else if (table.getSchema().getVersion() != 0) {
- throw new VersionException("Expected version 0 for table " + CATEGORY_TABLE_NAME +
- " but got " + table.getSchema().getVersion());
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
@Override
- public DBRecord getRecord(long categoryID) throws IOException {
+ DBRecord getRecord(long categoryID) throws IOException {
return table.getRecord(categoryID);
}
@Override
- public Field[] getRecordIdsWithParent(long categoryID) throws IOException {
+ Field[] getRecordIdsWithParent(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), V0_CATEGORY_PARENT_COL);
}
@@ -76,7 +84,7 @@ class CategoryDBAdapterV0 extends CategoryDBAdapter {
}
@Override
- public DBRecord createCategory(String name, long parentID) throws IOException {
+ DBRecord createCategory(String name, long parentID) throws IOException {
long key = table.getKey();
if (key == 0) {
key = 1;
@@ -90,12 +98,12 @@ class CategoryDBAdapterV0 extends CategoryDBAdapter {
}
@Override
- public boolean removeCategory(long categoryID) throws IOException {
+ boolean removeCategory(long categoryID) throws IOException {
return table.deleteRecord(categoryID);
}
@Override
- public DBRecord getRootRecord() throws IOException {
+ DBRecord getRootRecord() throws IOException {
Field[] keys = table.findRecords(new LongField(-1), V0_CATEGORY_PARENT_COL);
if (keys.length != 1) {
throw new IOException("Found " + keys.length + " entries for root category");
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java
index 021e0c8114..f70793ad9d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java
@@ -19,7 +19,6 @@ import java.io.IOException;
import db.*;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
/**
* Adapter to access the Component database table.
@@ -43,14 +42,14 @@ abstract class ComponentDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
- * @param monitor the monitor to use for displaying status or for canceling.
+ * @param tablePrefix prefix to be used with default table name
* @return the adapter for accessing the table of component data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is a problem accessing the database.
*/
- static ComponentDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
+ static ComponentDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
- return new ComponentDBAdapterV0(handle, openMode == DBConstants.CREATE);
+ return new ComponentDBAdapterV0(handle, tablePrefix, openMode == DBConstants.CREATE);
}
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java
index 69f8f3a1aa..614ccfa3aa 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java
@@ -40,48 +40,41 @@ class ComponentDBAdapterV0 extends ComponentDBAdapter {
StringField.INSTANCE, StringField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE },
new String[] { "Parent", "Offset", "Data Type ID", "Field Name", "Comment",
"Component Size", "Ordinal" });
+
private Table componentTable;
/**
* Gets a version 0 adapter for the Component database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @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 an IO error occurs
*/
- public ComponentDBAdapterV0(DBHandle handle, boolean create)
+ ComponentDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + COMPONENT_TABLE_NAME;
if (create) {
- componentTable = handle.createTable(COMPONENT_TABLE_NAME, V0_COMPONENT_SCHEMA,
+ componentTable = handle.createTable(tableName, V0_COMPONENT_SCHEMA,
new int[] { V0_COMPONENT_PARENT_ID_COL });
}
else {
- componentTable = handle.getTable(COMPONENT_TABLE_NAME);
+ componentTable = handle.getTable(tableName);
if (componentTable == null) {
- throw new VersionException("Missing Table: " + COMPONENT_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- int version = componentTable.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + COMPONENT_TABLE_NAME +
- " but got " + componentTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (componentTable.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
@Override
- public DBRecord createRecord(long dataTypeID, long parentID, int length, int ordinal, int offset,
+ DBRecord createRecord(long dataTypeID, long parentID, int length, int ordinal, int offset,
String name, String comment) throws IOException {
-
- long tableKey = componentTable.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.COMPONENT, tableKey);
+ long key =
+ DataTypeManagerDB.createKey(DataTypeManagerDB.COMPONENT, componentTable.getKey());
DBRecord record = ComponentDBAdapter.COMPONENT_SCHEMA.createRecord(key);
record.setLongValue(ComponentDBAdapter.COMPONENT_PARENT_ID_COL, parentID);
record.setLongValue(ComponentDBAdapter.COMPONENT_OFFSET_COL, offset);
@@ -95,22 +88,22 @@ class ComponentDBAdapterV0 extends ComponentDBAdapter {
}
@Override
- public DBRecord getRecord(long componentID) throws IOException {
+ DBRecord getRecord(long componentID) throws IOException {
return componentTable.getRecord(componentID);
}
@Override
- public void updateRecord(DBRecord record) throws IOException {
+ void updateRecord(DBRecord record) throws IOException {
componentTable.putRecord(record);
}
@Override
- public boolean removeRecord(long componentID) throws IOException {
+ boolean removeRecord(long componentID) throws IOException {
return componentTable.deleteRecord(componentID);
}
@Override
- public Field[] getComponentIdsInComposite(long compositeID) throws IOException {
+ Field[] getComponentIdsInComposite(long compositeID) throws IOException {
return componentTable.findRecords(new LongField(compositeID),
ComponentDBAdapter.COMPONENT_PARENT_ID_COL);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java
index 291dc5120e..c27e3fe2ee 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java
@@ -60,8 +60,8 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
protected abstract void initialize();
/**
- * Get the preferred length for a new component. For Unions and internally
- * aligned structures the preferred component length for a fixed-length dataType
+ * Get the preferred length for a new component. For Unions and packed
+ * structures the preferred component length for a fixed-length dataType
* will be the length of that dataType. Otherwise the length returned will be no
* larger than the specified length.
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapter.java
index 2541cdbc82..5ac775aebd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapter.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.program.database.util.DBRecordAdapter;
import ghidra.program.model.data.CompositeInternal;
import ghidra.util.UniversalID;
import ghidra.util.exception.CancelledException;
@@ -27,7 +28,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Adapter to access the Composite database table.
*/
-abstract class CompositeDBAdapter {
+abstract class CompositeDBAdapter implements DBRecordAdapter {
static final String COMPOSITE_TABLE_NAME = "Composite Data Types";
static final Schema COMPOSITE_SCHEMA = CompositeDBAdapterV5V6.V5V6_COMPOSITE_SCHEMA;
@@ -73,24 +74,25 @@ abstract class CompositeDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of composite data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
* @throws CancelledException task cancelled
*/
- static CompositeDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException, CancelledException {
+ static CompositeDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
try {
- return new CompositeDBAdapterV5V6(handle, openMode);
+ return new CompositeDBAdapterV5V6(handle, openMode, tablePrefix);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
throw e;
}
- CompositeDBAdapter adapter = findReadOnlyAdapter(handle);
+ CompositeDBAdapter adapter = findReadOnlyAdapter(handle, tablePrefix);
if (openMode == DBConstants.UPGRADE) {
- return upgrade(handle, adapter, monitor);
+ return upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -99,14 +101,15 @@ abstract class CompositeDBAdapter {
/**
* Tries to get a read only adapter for the database whose handle is passed to this method.
* @param handle handle to prior version of the database.
+ * @param tablePrefix prefix to be used with default table name
* @return the read only Composite data type table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
* @throws IOException if IO error occurs
*/
- static CompositeDBAdapter findReadOnlyAdapter(DBHandle handle)
+ private static CompositeDBAdapter findReadOnlyAdapter(DBHandle handle, String tablePrefix)
throws VersionException, IOException {
try {
- return new CompositeDBAdapterV5V6(handle, DBConstants.READ_ONLY);
+ return new CompositeDBAdapterV5V6(handle, DBConstants.READ_ONLY, tablePrefix);
}
catch (VersionException e) {
// ignore
@@ -130,6 +133,7 @@ abstract class CompositeDBAdapter {
* Upgrades the Composite data type table from the oldAdapter's version to the current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
* @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
@@ -137,14 +141,15 @@ abstract class CompositeDBAdapter {
* @throws IOException if the database can't be read or written.
* @throws CancelledException user cancelled upgrade
*/
- static CompositeDBAdapter upgrade(DBHandle handle, CompositeDBAdapter oldAdapter,
- TaskMonitor monitor) throws VersionException, IOException, CancelledException {
+ private static CompositeDBAdapter upgrade(DBHandle handle, CompositeDBAdapter oldAdapter,
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
CompositeDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new CompositeDBAdapterV5V6(tmpHandle, DBConstants.CREATE);
+ tmpAdapter = new CompositeDBAdapterV5V6(tmpHandle, DBConstants.CREATE, tablePrefix);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
monitor.checkCanceled();
@@ -152,7 +157,8 @@ abstract class CompositeDBAdapter {
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
- CompositeDBAdapter newAdapter = new CompositeDBAdapterV5V6(handle, DBConstants.CREATE);
+ CompositeDBAdapter newAdapter =
+ new CompositeDBAdapterV5V6(handle, DBConstants.CREATE, tablePrefix);
if (oldAdapter.getVersion() < FLEX_ARRAY_ELIMINATION_SCHEMA_VERSION) {
newAdapter.flexArrayMigrationRequired = true;
}
@@ -211,7 +217,7 @@ abstract class CompositeDBAdapter {
* @return the composite data type record iterator.
* @throws IOException if the database can't be accessed.
*/
- abstract RecordIterator getRecords() throws IOException;
+ public abstract RecordIterator getRecords() throws IOException;
/**
* Updates the composite data type table with the provided record.
@@ -269,6 +275,6 @@ abstract class CompositeDBAdapter {
* Get the number of composite records
* @return total number of composite records
*/
- abstract int getRecordCount();
+ public abstract int getRecordCount();
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV0.java
index 3ed7feb480..646f3eb7c9 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV0.java
@@ -35,11 +35,12 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
static final int V0_COMPOSITE_LENGTH_COL = 4;
static final int V0_COMPOSITE_NUM_COMPONENTS_COL = 5;
- static final Schema V0_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
- new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
- LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE },
- new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
- "Number Of Components" });
+// DO NOT REMOVE - this documents the schema used in version 0.
+// static final Schema V0_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
+// new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
+// LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE },
+// new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
+// "Number Of Components" });
private Table compositeTable;
@@ -49,20 +50,14 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public CompositeDBAdapterV0(DBHandle handle) throws VersionException {
+ CompositeDBAdapterV0(DBHandle handle) throws VersionException {
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
if (compositeTable == null) {
throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
}
- int version = compositeTable.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + COMPOSITE_TABLE_NAME +
- " but got " + compositeTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (compositeTable.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
@@ -71,12 +66,12 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- int getRecordCount() {
+ public int getRecordCount() {
return compositeTable.getRecordCount();
}
@Override
- public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
+ DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
long lastChangeTime, int packValue, int minAlignment) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
@@ -84,7 +79,7 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public DBRecord getRecord(long dataTypeID) throws IOException {
+ DBRecord getRecord(long dataTypeID) throws IOException {
return translateRecord(compositeTable.getRecord(dataTypeID));
}
@@ -94,18 +89,18 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long compositeID) throws IOException {
+ boolean removeRecord(long compositeID) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
" of " + COMPOSITE_TABLE_NAME + " table.");
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return compositeTable.findRecords(new LongField(categoryID),
CompositeDBAdapter.COMPOSITE_CAT_COL);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV1.java
index 71a367b6f2..4a01f3628e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV1.java
@@ -38,6 +38,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
static final int V1_COMPOSITE_SOURCE_SYNC_TIME_COL = 8;
static final int V1_COMPOSITE_LAST_CHANGE_TIME_COL = 9;
+// DO NOT REMOVE - this documents the schema used in version 1.
// static final Schema V1_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
// new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
// LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, LongField.INSTANCE,
@@ -54,7 +55,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public CompositeDBAdapterV1(DBHandle handle) throws VersionException {
+ CompositeDBAdapterV1(DBHandle handle) throws VersionException {
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
if (compositeTable == null) {
@@ -62,12 +63,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
int version = compositeTable.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + COMPOSITE_TABLE_NAME +
- " but got " + compositeTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
@@ -76,12 +72,12 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- int getRecordCount() {
+ public int getRecordCount() {
return compositeTable.getRecordCount();
}
@Override
- public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
+ DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
long lastChangeTime, int packValue, int minAlignment) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
@@ -89,7 +85,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public DBRecord getRecord(long dataTypeID) throws IOException {
+ DBRecord getRecord(long dataTypeID) throws IOException {
return translateRecord(compositeTable.getRecord(dataTypeID));
}
@@ -99,12 +95,12 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long compositeID) throws IOException {
+ boolean removeRecord(long compositeID) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
" of " + COMPOSITE_TABLE_NAME + " table.");
}
@@ -115,7 +111,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return compositeTable.findRecords(new LongField(categoryID),
CompositeDBAdapter.COMPOSITE_CAT_COL);
}
@@ -126,9 +122,6 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
V1_COMPOSITE_SOURCE_ARCHIVE_ID_COL);
}
- /* (non-Javadoc)
- * @see db.RecordTranslator#translateRecord(db.Record)
- */
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV2V4.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV2V4.java
index afc02c2a11..881dbb2bc9 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV2V4.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV2V4.java
@@ -51,14 +51,15 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
static final int V2V4_COMPOSITE_PACK_COL = 10; // renamed from Internal Alignment
static final int V2V4_COMPOSITE_MIN_ALIGN_COL = 11; // renamed from External Alignment
- static final Schema V2V4_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
- new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
- LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, LongField.INSTANCE,
- LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE,
- IntField.INSTANCE },
- new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
- "Number Of Components", "Source Archive ID", "Source Data Type ID", "Source Sync Time",
- "Last Change Time", "Pack", "MinAlign" });
+// DO NOT REMOVE - this documents the schema used in versions 2 thru 4.
+// static final Schema V2V4_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
+// new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
+// LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, LongField.INSTANCE,
+// LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE,
+// IntField.INSTANCE },
+// new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
+// "Number Of Components", "Source Archive ID", "Source Data Type ID", "Source Sync Time",
+// "Last Change Time", "Pack", "MinAlign" });
private Table compositeTable;
@@ -68,7 +69,7 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public CompositeDBAdapterV2V4(DBHandle handle) throws VersionException {
+ CompositeDBAdapterV2V4(DBHandle handle) throws VersionException {
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
if (compositeTable == null) {
throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
@@ -90,12 +91,12 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
}
@Override
- int getRecordCount() {
+ public int getRecordCount() {
return compositeTable.getRecordCount();
}
@Override
- public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
+ DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
long lastChangeTime, int packValue, int minAlignment) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
@@ -103,7 +104,7 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
}
@Override
- public DBRecord getRecord(long dataTypeID) throws IOException {
+ DBRecord getRecord(long dataTypeID) throws IOException {
return translateRecord(compositeTable.getRecord(dataTypeID));
}
@@ -113,12 +114,12 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long compositeID) throws IOException {
+ boolean removeRecord(long compositeID) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
" of " + COMPOSITE_TABLE_NAME + " table.");
}
@@ -129,7 +130,7 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return compositeTable.findRecords(new LongField(categoryID),
CompositeDBAdapter.COMPOSITE_CAT_COL);
}
@@ -140,9 +141,6 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
V2V4_COMPOSITE_SOURCE_ARCHIVE_ID_COL);
}
- /* (non-Javadoc)
- * @see db.RecordTranslator#translateRecord(db.Record)
- */
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV5V6.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV5V6.java
index d2b3b3e914..cb22520b8d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV5V6.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV5V6.java
@@ -32,6 +32,8 @@ import ghidra.util.exception.VersionException;
* Version 6 did not change the schema but corresponds to the elimination
* of Structure flex-arrays which are supported in read-only mode under
* the older version 5 adapter version.
+ *
+ * NOTE: Use of tablePrefix introduced with adapter V6.
*/
class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
@@ -66,33 +68,30 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
/**
* Gets an adapter for the Composite database table.
* @param handle handle to the database containing the table.
- * @param openMode
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if IO error occurs
*/
- public CompositeDBAdapterV5V6(DBHandle handle, int openMode)
+ CompositeDBAdapterV5V6(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
+ String tableName = tablePrefix + COMPOSITE_TABLE_NAME;
if (openMode == DBConstants.CREATE) {
- compositeTable = handle.createTable(COMPOSITE_TABLE_NAME, V5V6_COMPOSITE_SCHEMA,
+ compositeTable = handle.createTable(tableName, V5V6_COMPOSITE_SCHEMA,
new int[] { V5V6_COMPOSITE_CAT_COL, V5V6_COMPOSITE_UNIVERSAL_DT_ID_COL });
}
else {
- compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
+ compositeTable = handle.getTable(tableName);
if (compositeTable == null) {
- throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
int version = compositeTable.getSchema().getVersion();
- if (version == V5_VERSION && openMode == DBConstants.READ_ONLY) {
- return; // StructureDB handles read-only flex-array migration
- }
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + COMPOSITE_TABLE_NAME +
- " but got " + version;
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
+ if (version == V5_VERSION && openMode == DBConstants.READ_ONLY) {
+ return; // StructureDB handles read-only flex-array migration
}
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
}
@@ -102,12 +101,12 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
}
@Override
- int getRecordCount() {
+ public int getRecordCount() {
return compositeTable.getRecordCount();
}
@Override
- public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
+ DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
long lastChangeTime, int packValue, int minAlignment) throws IOException {
if (compositeTable.getSchema().getVersion() == V5_VERSION) {
@@ -141,7 +140,7 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
}
@Override
- public DBRecord getRecord(long dataTypeID) throws IOException {
+ DBRecord getRecord(long dataTypeID) throws IOException {
return compositeTable.getRecord(dataTypeID);
}
@@ -151,7 +150,7 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
if (compositeTable.getSchema().getVersion() == V5_VERSION) {
throw new UnsupportedOperationException();
}
@@ -163,7 +162,7 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
}
@Override
- public boolean removeRecord(long compositeID) throws IOException {
+ boolean removeRecord(long compositeID) throws IOException {
if (compositeTable.getSchema().getVersion() == V5_VERSION) {
throw new UnsupportedOperationException();
}
@@ -172,11 +171,11 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
@Override
void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(COMPOSITE_TABLE_NAME);
+ handle.deleteTable(compositeTable.getName());
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return compositeTable.findRecords(new LongField(categoryID),
CompositeDBAdapter.COMPOSITE_CAT_COL);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformer.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformer.java
index b7800805aa..c214cc2ae8 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformer.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformer.java
@@ -37,6 +37,7 @@ import ghidra.framework.ApplicationConfiguration;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.Enum;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.util.*;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.*;
@@ -63,8 +64,27 @@ public class DataTypeArchiveTransformer implements GhidraLaunchable {
FileDataTypeManager newFileArchive = null;
try {
monitor.initialize(100);
+
oldFileArchive = FileDataTypeManager.openFileArchive(oldFile, false);
+ ArchiveWarning warning = oldFileArchive.getWarning();
+ if (warning == ArchiveWarning.LANGUAGE_UPGRADE_REQURED) {
+ throw new IOException("Archive requires language upgrade: " + oldFile);
+ }
+ if (warning != ArchiveWarning.NONE) {
+ throw new IOException("Archive language error occured: " + oldFile,
+ oldFileArchive.getWarningDetail());
+ }
+
newFileArchive = FileDataTypeManager.openFileArchive(newFile, true);
+ warning = newFileArchive.getWarning();
+ if (warning == ArchiveWarning.LANGUAGE_UPGRADE_REQURED) {
+ throw new IOException("Archive requires language upgrade: " + newFile);
+ }
+ if (warning != ArchiveWarning.NONE) {
+ throw new IOException("Archive language error occured: " + newFile,
+ newFileArchive.getWarningDetail());
+ }
+
UniversalID oldUniversalID = oldFileArchive.getUniversalID();
UniversalID newUniversalID = newFileArchive.getUniversalID();
Msg.info(DataTypeArchiveTransformer.class, "Old file ID = " + oldUniversalID);
@@ -739,12 +759,10 @@ public class DataTypeArchiveTransformer implements GhidraLaunchable {
FileDataTypeManager destinationFileArchive =
FileDataTypeManager.openFileArchive(destinationFile, false);
- if (destinationFileArchive != null) {
- UniversalID destinationUniversalID = destinationFileArchive.getUniversalID();
- destinationFileArchive.close();
- Msg.info(DataTypeArchiveTransformer.class,
- "Resulting file ID = " + destinationUniversalID.getValue());
- }
+ UniversalID destinationUniversalID = destinationFileArchive.getUniversalID();
+ destinationFileArchive.close();
+ Msg.info(DataTypeArchiveTransformer.class,
+ "Resulting file ID = " + destinationUniversalID.getValue());
}
static File myOldFile = null;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java
index 2235dbfa24..412334180f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java
@@ -305,10 +305,10 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
return false;
}
DataType myParent = getParent();
- boolean aligned =
+ boolean isPacked =
(myParent instanceof Composite) ? ((Composite) myParent).isPackingEnabled() : false;
- // Components don't need to have matching offset when they are aligned
- if ((!aligned && (offset != dtc.getOffset())) ||
+ // Components don't need to have matching offset when structure has packing enabled
+ if ((!isPacked && (offset != dtc.getOffset())) ||
!SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) ||
!SystemUtilities.isEqual(getComment(), dtc.getComment())) {
return false;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java
index 930c028bcf..7996a6a226 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java
@@ -518,9 +518,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType {
@Override
public SourceArchive getSourceArchive() {
- if (dataMgr == null) {
- return null;
- }
return dataMgr.getSourceArchive(getSourceArchiveID());
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeIDConverter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeIDConverter.java
index 63a8026254..9cf7192734 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeIDConverter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeIDConverter.java
@@ -23,6 +23,7 @@ import ghidra.GhidraLaunchable;
import ghidra.framework.Application;
import ghidra.framework.ApplicationConfiguration;
import ghidra.program.model.data.*;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.util.NumericUtilities;
import ghidra.util.UniversalID;
import ghidra.util.datastruct.LongLongHashtable;
@@ -90,6 +91,10 @@ public class DataTypeIDConverter implements GhidraLaunchable {
FileDataTypeManager oldFileArchive = null;
try {
oldFileArchive = FileDataTypeManager.openFileArchive(inFile, false);
+ if (oldFileArchive.getWarning() != ArchiveWarning.NONE) {
+ System.out.println("Archive ID Conversion aborted");
+ return;
+ }
UniversalID oldFileUID = oldFileArchive.getUniversalID();
long newID = idMap.get(oldFileUID.getValue());
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
index e7fa3194f8..45aeb46c00 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
@@ -19,24 +19,30 @@ import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javax.help.UnsupportedOperationException;
+
import db.*;
import db.util.ErrorHandler;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
import ghidra.docking.settings.*;
+import ghidra.framework.Application;
import ghidra.framework.store.db.PackedDBHandle;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.graph.*;
import ghidra.graph.algo.GraphNavigator;
import ghidra.program.database.*;
import ghidra.program.database.map.AddressMap;
+import ghidra.program.database.symbol.VariableStorageManager;
+import ghidra.program.database.util.DBRecordAdapter;
import ghidra.program.model.data.*;
import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult;
import ghidra.program.model.data.Enum;
-import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.lang.*;
import ghidra.util.*;
import ghidra.util.classfinder.ClassTranslator;
import ghidra.util.datastruct.FixedSizeHashMap;
@@ -89,9 +95,15 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
// Data map keys
private static final String DTM_DB_VERSION_KEY = "DB Version";
+ private static final String DTM_GHIDRA_VERSION_KEY = "GHIDRA Version";
private static final String SETTINGS_TABLE_NAME = "Default Settings";
+ public static final byte UNKNOWN_CALLING_CONVENTION_ID =
+ CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID;
+ public static final byte DEFAULT_CALLING_CONVENTION_ID =
+ CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID;
+
private BuiltinDBAdapter builtinAdapter;
private ComponentDBAdapter componentAdapter;
private CompositeDBAdapter compositeAdapter;
@@ -107,7 +119,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private ParentChildAdapter parentChildAdapter;
protected SourceArchiveAdapter sourceArchiveAdapter;
+ private CallingConventionDBAdapter callingConventionAdapter;
+ private TreeSet knownCallingConventions;
+ private TreeSet definedCallingConventions;
+
protected DBHandle dbHandle;
+ private int mode; // open mode (see DBConstants)
+ protected final String tablePrefix;
protected final ErrorHandler errHandler;
private DataTypeConflictHandler currentHandler;
@@ -143,8 +161,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
protected AddressMap addrMap;
- protected DataOrganization dataOrganization;
-
+ private DataOrganization dataOrganization;
+ private ProgramArchitecture programArchitecture;
+ private VariableStorageManager variableStorageMgr;
+
protected final Lock lock;
private static class ResolvePair implements Comparable {
@@ -186,13 +206,15 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
/**
* Construct a new temporary data-type manager. Note that this manager does not
- * support the save or saveAs operation.
+ * support the save or saveAs operation. No Language is associated with instance.
+ *
* @param dataOrganization applicable data organization
*/
protected DataTypeManagerDB(DataOrganization dataOrganization) {
this.lock = new Lock("DataTypeManagerDB");
this.errHandler = new DbErrorHandler();
this.dataOrganization = dataOrganization;
+ this.tablePrefix = "";
try {
dbHandle = new DBHandle();
@@ -224,10 +246,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* @throws IOException a low-level IO error. This exception may also be thrown
* when a version error occurs (cause is VersionException).
*/
- protected DataTypeManagerDB(ResourceFile packedDBfile, int openMode) throws IOException {
+ protected DataTypeManagerDB(ResourceFile packedDBfile, int openMode)
+ throws IOException {
this.errHandler = new DbErrorHandler();
- lock = new Lock("DataTypeManagerDB");
+ this.lock = new Lock("DataTypeManagerDB");
+ this.tablePrefix = "";
File file = packedDBfile.getFile(false);
if (file == null && openMode != DBConstants.READ_ONLY) {
@@ -267,14 +291,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
boolean initSuccess = false;
try {
- // TODO: In the future it may be neccessary to store additional properties
- // within the archive to failitate use of a language specified data organization.
- // It will likely be neccessary to have a different CREATE constructor which accepts
- // a DataOrganization
-
- dataOrganization = DataOrganizationImpl.getDefaultOrganization();
-
- initPackedDatabase(packedDBfile, openMode);
+ initPackedDatabase(packedDBfile, openMode); // performs upgrade if needed
if (openMode == DBConstants.CREATE) {
// preserve UniversalID if it has been established
@@ -329,8 +346,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
*
* @param handle database handle
* @param addrMap address map (may be null)
- * @param openMode open mode CREATE, READ_ONLY or UPDATE (see
- * {@link DBConstants}).
+ * @param openMode open mode CREATE, READ_ONLY or UPDATE (see {@link DBConstants}).
+ * @param tablePrefix DB table prefix to be applied to all associated table names. This
+ * need only be specified when using multiple instances with the same
+ * DB handle (null or empty string for no-prefix).
* @param errHandler the error handler
* @param lock database lock
* @param monitor the current task monitor
@@ -340,9 +359,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* This exception will never be thrown in READ_ONLY mode.
*/
protected DataTypeManagerDB(DBHandle handle, AddressMap addrMap, int openMode,
- ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
+ String tablePrefix, ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
throws CancelledException, IOException, VersionException {
-
+ this.tablePrefix = tablePrefix != null ? tablePrefix : "";
this.dbHandle = handle;
this.addrMap = addrMap;
this.errHandler = errHandler;
@@ -352,10 +371,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private void init(int openMode, TaskMonitor monitor)
throws CancelledException, IOException, VersionException {
+ this.mode = openMode;
updateID();
initializeAdapters(openMode, monitor);
if (checkForSourceArchiveUpdatesNeeded(openMode, monitor)) {
- doSourceArchiveUpdates(null, monitor);
+ doSourceArchiveUpdates(monitor);
}
dtCache = new DBObjectCache<>(10);
sourceArchiveDBCache = new DBObjectCache<>(10);
@@ -371,97 +391,110 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
throws CancelledException, IOException, VersionException {
//
- // IMPORTANT! All adapter version must retain read-only capability to permit
+ // IMPORTANT! All adapter versions must retain read-only capability to permit
// opening older archives without requiring an upgrade. Failure to do so may
// present severe usability issues when the ability to open for update is not
// possible.
//
- checkAndUpdateManagerVersion(openMode);
+ checkManagerVersion(openMode);
VersionException versionExc = null;
try {
- builtinAdapter = BuiltinDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ callingConventionAdapter =
+ CallingConventionDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- categoryAdapter = CategoryDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ builtinAdapter = BuiltinDBAdapter.getAdapter(dbHandle, openMode, tablePrefix);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- arrayAdapter = ArrayDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ categoryAdapter = CategoryDBAdapter.getAdapter(dbHandle, openMode, tablePrefix);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- typedefAdapter = TypedefDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ arrayAdapter = ArrayDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- compositeAdapter = CompositeDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ typedefAdapter = TypedefDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- componentAdapter = ComponentDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ compositeAdapter =
+ CompositeDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
+ }
+ catch (VersionException e) {
+ versionExc = e.combine(versionExc);
+ }
+ try {
+ componentAdapter = ComponentDBAdapter.getAdapter(dbHandle, openMode, tablePrefix);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
functionDefAdapter =
- FunctionDefinitionDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ FunctionDefinitionDBAdapter.getAdapter(dbHandle, openMode, tablePrefix,
+ callingConventionAdapter, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- paramAdapter = FunctionParameterAdapter.getAdapter(dbHandle, openMode, monitor);
+ paramAdapter =
+ FunctionParameterAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- settingsAdapter = SettingsDBAdapter.getAdapter(SETTINGS_TABLE_NAME, dbHandle, openMode,
+ settingsAdapter =
+ SettingsDBAdapter.getAdapter(tablePrefix + SETTINGS_TABLE_NAME, dbHandle, openMode,
null, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- pointerAdapter = PointerDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ pointerAdapter = PointerDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- enumAdapter = EnumDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ enumAdapter = EnumDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- enumValueAdapter = EnumValueDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ enumValueAdapter =
+ EnumValueDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- parentChildAdapter = ParentChildAdapter.getAdapter(dbHandle, openMode, monitor);
+ parentChildAdapter = ParentChildAdapter.getAdapter(dbHandle, openMode, tablePrefix);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- sourceArchiveAdapter = SourceArchiveAdapter.getAdapter(dbHandle, openMode, monitor);
+ sourceArchiveAdapter =
+ SourceArchiveAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
@@ -477,6 +510,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (versionExc != null) {
throw versionExc;
}
+
+ updateManagerAndAppVersion(openMode);
}
/**
@@ -539,20 +574,16 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
/**
* Check data map for overall manager version for compatibility.
- * If not open read-only the map will be immediately updated to latest version.
* @throws VersionException if database is a newer unsupported version
* @throws IOException if an IO error occurs
*/
- private void checkAndUpdateManagerVersion(int openMode) throws IOException, VersionException {
+ private void checkManagerVersion(int openMode) throws IOException, VersionException {
if (openMode == DBConstants.CREATE) {
- DBStringMapAdapter dataMap = getDataMap(true);
- dataMap.put(DTM_DB_VERSION_KEY, Integer.toString(DB_VERSION));
return;
}
// Check data map for overall manager version for compatibility.
- // If not open read-only the map will be immediately updated to latest version.
DBStringMapAdapter dataMap = getDataMap(openMode == DBConstants.UPGRADE);
if (dataMap != null) {
// verify that we are compatible with stored data
@@ -560,14 +591,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (dbVersion > DB_VERSION) {
throw new VersionException(false);
}
- if (dbVersion < DB_VERSION) {
- if (openMode == DBConstants.UPGRADE) {
- // Upgrade mode required to advance overall DB version
- dataMap.put(DTM_DB_VERSION_KEY, Integer.toString(DB_VERSION));
- }
- else if (openMode == DBConstants.UPDATE) {
- throw new VersionException(true);
- }
+ if (dbVersion < DB_VERSION && openMode == DBConstants.UPDATE) {
+ // Force upgrade if open for update
+ throw new VersionException(true);
}
}
else if (openMode == DBConstants.UPDATE) {
@@ -576,6 +602,14 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
+ private void updateManagerAndAppVersion(int openMode) throws IOException {
+ if (openMode == DBConstants.CREATE || openMode == DBConstants.UPGRADE) {
+ DBStringMapAdapter dataMap = getDataMap(true);
+ dataMap.put(DTM_DB_VERSION_KEY, Integer.toString(DB_VERSION));
+ dataMap.put(DTM_GHIDRA_VERSION_KEY, Application.getApplicationVersion());
+ }
+ }
+
/**
* Get the manager string data map.
* @param createIfNeeded if true map will be created if it does not exist
@@ -736,6 +770,132 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
+ /**
+ * Set the architecture-specific details associated with this datatype manager.
+ * The data organization will be obtained from the compiler spec specified by
+ * the program architecture. Fixup of all composites will be performed, if store is
+ * true, to reflect any changes in the data organization.
+ * The caller is resposible for ensuring that this setting is done consistent
+ * with the {@link #addrMap} setting used during construction if applicable.
+ * @param programArchitecture program architecture details (may be null) in which case
+ * default data organization will be used.
+ * @param variableStorageMgr variable storage manager (within same database) or null
+ * to disable variable storage support. Ignored if programArchitecture is null;
+ * @param store if true database update will occur and datatypes will be updated if
+ * any change to the data organization is detected (a stored copy may be used to
+ * detect this condition). This should never be passed as true if opened read-only.
+ * @param monitor task monitor
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if processing cancelled - data types may not properly reflect
+ * updated compiler specification
+ * @throws UnsupportedOperationException if language was previously set
+ */
+ protected void setProgramArchitecture(ProgramArchitecture programArchitecture,
+ VariableStorageManager variableStorageMgr, boolean store, TaskMonitor monitor)
+ throws IOException, CancelledException {
+
+ this.programArchitecture = programArchitecture;
+ this.variableStorageMgr = programArchitecture != null ? variableStorageMgr : null;
+
+ dataOrganization = programArchitecture != null
+ ? programArchitecture.getCompilerSpec().getDataOrganization()
+ : DataOrganizationImpl.getDefaultOrganization();
+
+ if (mode == DBConstants.CREATE) {
+ saveDataOrganization();
+ }
+ else if (store) {
+ compilerSpecChanged(monitor);
+ updateLastChangeTime();
+ }
+ }
+
+ /**
+ * Perform updates related to a compiler spec change, including:
+ *
+ * - data organization changes which may impact datatype components and packing
+ *
+ * NOTE: this manager must be open for update.
+ * @param monitor task monitor
+ * @throws ReadOnlyException if this manager has not been open for update
+ * @throws IOException if an IO error occurs while performing updates
+ * @throws CancelledException if processing cancelled - data types may not properly reflect
+ * updated compiler specification
+ */
+ private void compilerSpecChanged(TaskMonitor monitor) throws IOException, CancelledException {
+
+ if (mode == DBConstants.READ_ONLY) {
+ throw new ReadOnlyException();
+ }
+
+ DataOrganization oldDataOrganization = readDataOrganization();
+
+ try {
+ saveDataOrganization();
+
+ if (oldDataOrganization != null &&
+ !oldDataOrganization.equals(dataOrganization)) {
+ Msg.info(this,
+ "Fixing datatypes to reflect data organization change: " + getPath());
+ doCompositeFixup(monitor);
+ }
+
+ // FUTURE: may need to handle calling convention and data organization change impact
+ // on function definitions
+
+ }
+ finally {
+ invalidateCache();
+ }
+ }
+
+ private void saveDataOrganization() throws IOException {
+ if (dataOrganization == null) {
+ return;
+ }
+ DataOrganizationImpl.save(dataOrganization, getDataMap(true), "dataOrg.");
+ }
+
+ private DataOrganization readDataOrganization() throws IOException {
+ DBStringMapAdapter dataMap = getDataMap(false);
+ if (dataMap == null) {
+ return null;
+ }
+ return DataOrganizationImpl.restore(dataMap, "dataOrg.");
+ }
+
+ @Override
+ public ProgramArchitecture getProgramArchitecture() {
+ return programArchitecture;
+ }
+
+ protected static String getProgramArchitectureSummary(LanguageID languageId,
+ int languageVersion, CompilerSpecID compilerSpecId) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(languageId.getIdAsString());
+ buf.append(" / ");
+ buf.append(compilerSpecId.getIdAsString());
+ return buf.toString();
+ }
+
+ @Override
+ public String getProgramArchitectureSummary() {
+ if (programArchitecture != null) {
+ return getProgramArchitectureSummary(programArchitecture.getLanguage().getLanguageID(),
+ programArchitecture.getLanguage().getVersion(),
+ programArchitecture.getCompilerSpec().getCompilerSpecID());
+ }
+ return null;
+ }
+
+ /**
+ * Get the variable storage manager if it has been established.
+ * @return variable storage manager or null if no associated architecture.
+ */
+ protected VariableStorageManager getVariableStorageManager() {
+ return variableStorageMgr;
+ }
+
/**
* Determine if transaction is active. With proper lock established
* this method may be useful for determining if a lazy record update
@@ -1130,7 +1290,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
int storageSize = bitFieldDataType.getStorageSize();
int storageSizeBits = 8 * storageSize;
if ((bitOffset + bitSize) > storageSizeBits) {
- // should get recomputed during packing when used within aligned structure
+ // should get recomputed during packing when used within structure with packing enabled
int effectiveBitSize = Math.min(bitSize, baseLengthBits);
bitOffset = getDataOrganization().isBigEndian() ? baseLengthBits - effectiveBitSize : 0;
storageSize = baseLength;
@@ -1574,11 +1734,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (sourceArchive == null) {
return null;
}
- if (getSourceArchive(sourceArchive.getSourceArchiveID()) != null) {
- // already have it
- return getSourceArchive(sourceArchive.getSourceArchiveID());
- }
+ lock.acquire();
try {
+ SourceArchive existingArchive = getSourceArchive(sourceArchive.getSourceArchiveID());
+ if (existingArchive != null) {
+ return existingArchive; // already have it
+ }
DBRecord record = sourceArchiveAdapter.createRecord(sourceArchive);
SourceArchive newSourceArchive = getSourceArchiveDB(record);
invalidateSourceArchiveCache();
@@ -1587,8 +1748,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
catch (IOException e) {
dbError(e);
- return null;
}
+ finally {
+ lock.release();
+ }
+ return null;
}
@Override
@@ -1602,15 +1766,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
throw new IllegalArgumentException("Attempted to delete the local archive!");
}
disassociateAllDataTypes(sourceArchiveID);
- try {
- sourceArchiveAdapter.deleteRecord(sourceArchiveID);
- }
- catch (IOException e) {
- dbError(e);
- }
- sourceArchiveChanged(sourceArchiveID);
+ sourceArchiveAdapter.deleteRecord(sourceArchiveID);
+ sourceArchiveChanged(sourceArchiveID); // must occur before invalidateSourceArchiveCache
invalidateSourceArchiveCache();
}
+ catch (IOException e) {
+ dbError(e);
+ }
finally {
lock.release();
}
@@ -1747,6 +1909,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
+ /**
+ * Replace all datatype uses external to the datatype manager if applicable.
+ * @param oldID old datatype ID
+ * @param newID new datatype ID
+ */
abstract protected void replaceDataTypeIDs(long oldID, long newID);
/**
@@ -2167,6 +2334,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
idsToDelete.add(Long.valueOf(id));
}
+ /**
+ * Delete all datatype uses external to the datatype manager if applicable.
+ * @param deletedIds old datatype IDs which were deleted
+ * @param monitor task monitor
+ * @throws CancelledException if operation cancelled
+ */
abstract protected void deleteDataTypeIDs(LinkedList deletedIds, TaskMonitor monitor)
throws CancelledException;
@@ -2442,26 +2615,36 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private DataType getDataType(long dataTypeID, DBRecord record) {
int tableId = getTableID(dataTypeID);
+ DataType dt = null;
switch (tableId) {
case BUILT_IN:
- return getBuiltInDataType(dataTypeID, record);
+ dt = getBuiltInDataType(dataTypeID, record);
+ break;
case COMPOSITE:
- return getCompositeDataType(dataTypeID, record);
+ dt = getCompositeDataType(dataTypeID, record);
+ break;
case ARRAY:
- return getArrayDataType(dataTypeID, record);
+ dt = getArrayDataType(dataTypeID, record);
+ break;
case POINTER:
- return getPointerDataType(dataTypeID, record);
+ dt = getPointerDataType(dataTypeID, record);
+ break;
case TYPEDEF:
- return getTypedefDataType(dataTypeID, record);
+ dt = getTypedefDataType(dataTypeID, record);
+ break;
case FUNCTION_DEF:
- return getFunctionDefDataType(dataTypeID, record);
+ dt = getFunctionDefDataType(dataTypeID, record);
+ break;
case ENUM:
- return getEnumDataType(dataTypeID, record);
+ dt = getEnumDataType(dataTypeID, record);
+ break;
case BITFIELD:
- return BitFieldDBDataType.getBitFieldDataType(dataTypeID, this);
+ dt = BitFieldDBDataType.getBitFieldDataType(dataTypeID, this);
+ break;
default:
return null;
}
+ return dt;
}
private DataType getBuiltInDataType(long dataTypeID, DBRecord record) {
@@ -2938,7 +3121,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return arrayDB;
}
- private void updateLastChangeTime() {
+ protected void updateLastChangeTime() {
SourceArchive mySourceArchive = getSourceArchive(getUniversalID());
if (mySourceArchive == null) {
return;
@@ -3105,10 +3288,14 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
try {
creatingDataType++;
+ byte callingConventionId =
+ callingConventionAdapter.getCallingConventionId(funDef.getCallingConventionName(),
+ cc -> callingConventionNameAdded(cc));
DBRecord record =
functionDefAdapter.createRecord(name, funDef.getComment(), cat.getID(),
- DEFAULT_DATATYPE_ID, funDef.hasVarArgs(), funDef.getGenericCallingConvention(),
- sourceArchiveIdValue, universalIdValue, funDef.getLastChangeTime());
+ DEFAULT_DATATYPE_ID, funDef.hasNoReturn(), funDef.hasVarArgs(),
+ callingConventionId, sourceArchiveIdValue, universalIdValue,
+ funDef.getLastChangeTime());
FunctionDefinitionDB funDefDb =
new FunctionDefinitionDB(this, dtCache, functionDefAdapter, paramAdapter, record);
@@ -3127,13 +3314,16 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
creatingDataType--;
}
}
-
- class StructureIterator implements Iterator {
+
+ class DataTypeIterator implements Iterator {
private RecordIterator it;
- private StructureDB nextStruct;
+ private T nextDataType;
+ private Predicate predicate;
- StructureIterator() throws IOException {
- it = compositeAdapter.getRecords();
+ DataTypeIterator(DBRecordAdapter adapter, Predicate predicate)
+ throws IOException {
+ it = adapter.getRecords();
+ this.predicate = predicate;
}
@Override
@@ -3143,29 +3333,30 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public boolean hasNext() {
- if (nextStruct == null) {
- getNextStruct();
+ if (nextDataType == null) {
+ getNextDataType();
}
- return nextStruct != null;
+ return nextDataType != null;
}
@Override
- public StructureDB next() {
+ public T next() {
if (hasNext()) {
- StructureDB s = nextStruct;
- nextStruct = null;
- return s;
+ T dt = nextDataType;
+ nextDataType = null;
+ return dt;
}
return null;
}
- private void getNextStruct() {
+ @SuppressWarnings("unchecked")
+ private void getNextDataType() {
try {
while (it.hasNext()) {
DBRecord rec = it.next();
DataType dt = getDataType(rec.getKey(), rec);
- if (dt instanceof Structure) {
- nextStruct = (StructureDB) dt;
+ if (predicate.test(dt)) {
+ nextDataType = (T) dt;
return;
}
}
@@ -3176,50 +3367,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
- class CompositeIterator implements Iterator {
- private RecordIterator it;
- private CompositeDB nextComposite;
-
- CompositeIterator() throws IOException {
- it = compositeAdapter.getRecords();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException("Remove not supported");
- }
-
- @Override
- public boolean hasNext() {
- if (nextComposite == null) {
- getNextComposite();
- }
- return nextComposite != null;
- }
-
- @Override
- public CompositeDB next() {
- if (hasNext()) {
- CompositeDB c = nextComposite;
- nextComposite = null;
- return c;
- }
- return null;
- }
-
- private void getNextComposite() {
- try {
- if (it.hasNext()) {
- DBRecord rec = it.next();
- nextComposite = (CompositeDB) getDataType(rec.getKey(), rec);
- }
- }
- catch (IOException e) {
- Msg.error(this, "Unexpected exception iterating composites", e);
- }
- }
- }
-
private class NameComparator implements Comparator {
/**
* Compares its two arguments for order. Returns a negative integer, zero, or a
@@ -3321,10 +3468,23 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
+ @Override
+ public Iterator getAllFunctionDefinitions() {
+ try {
+ return new DataTypeIterator(functionDefAdapter, dt -> true);
+ }
+ catch (IOException e) {
+ dbError(e);
+ }
+ List emptyList = List.of();
+ return emptyList.iterator();
+ }
+
@Override
public Iterator getAllStructures() {
try {
- return new StructureIterator();
+ return new DataTypeIterator(compositeAdapter,
+ dt -> (dt instanceof Structure));
}
catch (IOException e) {
dbError(e);
@@ -3335,7 +3495,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public Iterator getAllComposites() {
try {
- return new CompositeIterator();
+ return new DataTypeIterator(compositeAdapter, dt -> true);
}
catch (IOException e) {
dbError(e);
@@ -3359,6 +3519,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
public void invalidateCache() {
lock.acquire();
try {
+ callingConventionAdapter.invalidateCache();
+ knownCallingConventions = null;
+ definedCallingConventions = null;
dtCache.invalidate();
sourceArchiveDBCache.invalidate();
invalidateSourceArchiveCache();
@@ -3540,12 +3703,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
@Override
- public Pointer getPointer(DataType dt) {
+ public final Pointer getPointer(DataType dt) {
return new PointerDataType(dt, this);
}
@Override
- public Pointer getPointer(DataType dt, int size) {
+ public final Pointer getPointer(DataType dt, int size) {
return new PointerDataType(dt, size, this);
}
@@ -3576,7 +3739,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (dt instanceof Enum) {
enumValueMap = null;
}
- if (creatingDataType == 0) {
+ if (!isAutoChange && creatingDataType == 0) {
+ // auto-changes should not be synced
updateLastChangeTime();
setDirtyFlag(dt);
}
@@ -3762,13 +3926,192 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
@Override
- public DataOrganization getDataOrganization() {
+ public AddressMap getAddressMap() {
+ return addrMap;
+ }
+
+ @Override
+ public final DataOrganization getDataOrganization() {
if (dataOrganization == null) {
dataOrganization = DataOrganizationImpl.getDefaultOrganization();
}
return dataOrganization;
}
+ /**
+ * Get calling convention name corresponding to existing specified id.
+ * @param id calling convention ID
+ * @return calling convention name if found else unknown
+ */
+ public String getCallingConventionName(byte id) {
+ lock.acquire();
+ try {
+ String callingConvention = callingConventionAdapter.getCallingConventionName(id);
+ return callingConvention != null ? callingConvention
+ : CompilerSpec.CALLING_CONVENTION_unknown;
+ }
+ catch (IOException e) {
+ dbError(e);
+ }
+ finally {
+ lock.release();
+ }
+ return null;
+ }
+
+ /**
+ * Get (and assign if needed thus requiring open transaction) the ID associated with the
+ * specified calling convention name. If name is a new convention and the number of stored
+ * convention names exceeds 127 the returned ID will correspond to the unknown calling
+ * convention.
+ * @param name calling convention name
+ * @param restrictive if true an error will be thrown if name is not defined by
+ * {@link GenericCallingConvention} or the associated compiler specification if
+ * datatype manager has an associated program architecture.
+ * @return calling convention ID
+ * @throws IOException if database IO error occurs
+ * @throws InvalidInputException if restrictive is true and name is not defined by
+ * {@link GenericCallingConvention} or the associated compiler specification if
+ * datatype manager has an associated program architecture.
+ */
+ public byte getCallingConventionID(String name, boolean restrictive)
+ throws InvalidInputException, IOException {
+
+ if (name == null || CompilerSpec.CALLING_CONVENTION_unknown.equals(name)) {
+ return UNKNOWN_CALLING_CONVENTION_ID;
+ }
+ if (CompilerSpec.CALLING_CONVENTION_default.equals(name)) {
+ return DEFAULT_CALLING_CONVENTION_ID;
+ }
+
+ lock.acquire();
+ try {
+ // If restrictive only permit a name which is known
+ if (restrictive &&
+ GenericCallingConvention
+ .getGenericCallingConvention(name) == GenericCallingConvention.unknown &&
+ !getKnownCallingConventionNames().contains(name) &&
+ getCallingConvention(name) == null) {
+
+ throw new InvalidInputException("Invalid calling convention name: " + name);
+ }
+
+ return callingConventionAdapter.getCallingConventionId(name,
+ cc -> callingConventionNameAdded(cc));
+ }
+ catch (IOException e) {
+ dbError(e);
+ }
+ finally {
+ lock.release();
+ }
+ return UNKNOWN_CALLING_CONVENTION_ID;
+ }
+
+ private void callingConventionNameAdded(String name) {
+ getKnownCallingConventionSet().add(name);
+ }
+
+ private Set getDefinedCallingConventionSet() {
+ if (definedCallingConventions == null) {
+ definedCallingConventions = buildDefinedCallingConventionSet();
+ }
+ return definedCallingConventions;
+ }
+
+ private TreeSet buildDefinedCallingConventionSet() {
+
+ // Include all calling conventions defined by associated architecure compiler spec
+ TreeSet nameSet = new TreeSet<>();
+ ProgramArchitecture arch = getProgramArchitecture();
+ if (arch != null) {
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ PrototypeModel[] namedCallingConventions = compilerSpec.getCallingConventions();
+ for (PrototypeModel model : namedCallingConventions) {
+ nameSet.add(model.getName());
+ }
+ }
+
+ // Include all generic calling convention names without cspec
+ else {
+ for (GenericCallingConvention conv : GenericCallingConvention.values()) {
+ if (conv == GenericCallingConvention.unknown) {
+ continue; // added below
+ }
+ nameSet.add(conv.getDeclarationName());
+ }
+ }
+
+ return nameSet;
+ }
+
+ @Override
+ public Collection getDefinedCallingConventionNames() {
+ lock.acquire();
+ try {
+ return new ArrayList<>(getDefinedCallingConventionSet());
+ }
+ finally {
+ lock.release();
+ }
+ }
+
+ private Set getKnownCallingConventionSet() {
+ if (knownCallingConventions == null) {
+ knownCallingConventions = buildKnownCallingConventionSet();
+ }
+ return knownCallingConventions;
+ }
+
+ private TreeSet buildKnownCallingConventionSet() {
+ TreeSet nameSet = new TreeSet<>();
+ try {
+ // Include defined call convention names
+ nameSet.addAll(getDefinedCallingConventionSet());
+
+ // Include all calling convention names previously added to DB
+ for (String name : callingConventionAdapter.getCallingConventionNames()) {
+ nameSet.add(name);
+ }
+ }
+ catch (IOException e) {
+ dbError(e);
+ }
+
+ return nameSet;
+ }
+
+ @Override
+ public Collection getKnownCallingConventionNames() {
+ lock.acquire();
+ try {
+ return new ArrayList<>(getKnownCallingConventionSet());
+ }
+ finally {
+ lock.release();
+ }
+ }
+
+ @Override
+ public PrototypeModel getDefaultCallingConvention() {
+ ProgramArchitecture arch = getProgramArchitecture();
+ if (arch != null) {
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ return compilerSpec.getDefaultCallingConvention();
+ }
+ return null;
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention(String name) {
+ ProgramArchitecture arch = getProgramArchitecture();
+ if (arch != null) {
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ return compilerSpec.getCallingConvention(name);
+ }
+ return null;
+ }
+
private boolean checkForSourceArchiveUpdatesNeeded(int openMode, TaskMonitor monitor)
throws IOException, CancelledException {
if (openMode == DBConstants.CREATE || openMode == DBConstants.READ_ONLY) {
@@ -3816,16 +4159,15 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
/**
* This method is only invoked during an upgrade.
*
- * @param compilerSpec compiler spec
* @param monitor task monitor
* @throws CancelledException if task cancelled
*/
- protected void doSourceArchiveUpdates(CompilerSpec compilerSpec, TaskMonitor monitor)
+ protected void doSourceArchiveUpdates(TaskMonitor monitor)
throws CancelledException {
SourceArchiveUpgradeMap upgradeMap = new SourceArchiveUpgradeMap();
for (SourceArchive sourceArchive : getSourceArchives()) {
SourceArchive mappedSourceArchive =
- upgradeMap.getMappedSourceArchive(sourceArchive, compilerSpec);
+ upgradeMap.getMappedSourceArchive(sourceArchive);
if (mappedSourceArchive != null) {
replaceSourceArchive(sourceArchive, mappedSourceArchive);
}
@@ -3854,36 +4196,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* that this program be open with exclusive access before invoking this method to avoid
* excessive merge conflicts with other users.
* @param monitor task monitor
- * @throws CancelledException if operation is cancelled
+ * @throws CancelledException if processing cancelled - data types may not properly reflect
+ * updated compiler specification
*/
public void fixupComposites(TaskMonitor monitor) throws CancelledException {
lock.acquire();
try {
-
- // NOTE: Any composite could be indirectly affected by a component size change
- // based upon type relationships
-
- // NOTE: Composites brought in from archive may have incorrect component size
- // if not aligned and should not be used to guage a primitive size change
-
- // Unfortunately parent table does not track use of primitives so a brute
- // force search is required. Since all composites must be checked, this
- // is combined with the composite graph generation to get ordered list
- // of composites for subsequent size change operation.
-
- List orderedComposites = getAllCompositesInPostDependencyOrder(monitor);
-
- monitor.setProgress(0);
- monitor.setMaximum(orderedComposites.size());
- monitor.setMessage("Updating Datatype Sizes...");
-
- int count = 0;
- for (CompositeDB c : orderedComposites) {
- monitor.checkCanceled();
- c.fixupComponents();
- monitor.setProgress(++count);
- }
-
+ doCompositeFixup(monitor);
}
catch (IOException e) {
dbError(e);
@@ -3892,6 +4211,34 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
lock.release();
}
}
+
+ private void doCompositeFixup(TaskMonitor monitor) throws CancelledException, IOException {
+
+ // NOTE: Any composite could be indirectly affected by a component size change
+ // based upon type relationships. In addition, an architecture change could
+ // alter the size and alignment of any datatype.
+
+ // NOTE: Composites brought in from archive may have incorrect component size
+ // if packing disabled and should not be used to guage a primitive size change
+
+ // Unfortunately parent table does not track use of primitives so a brute
+ // force search is required. Since all composites must be checked, this
+ // is combined with the composite graph generation to get ordered list
+ // of composites for subsequent size change operation.
+
+ List orderedComposites = getAllCompositesInPostDependencyOrder(monitor);
+
+ monitor.setProgress(0);
+ monitor.setMaximum(orderedComposites.size());
+ monitor.setMessage("Updating Datatype Sizes...");
+
+ int count = 0;
+ for (CompositeDB c : orderedComposites) {
+ monitor.checkCanceled();
+ c.fixupComponents();
+ monitor.setProgress(++count);
+ }
+ }
/**
* Get composite base type which corresponds to a specified datatype.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapter.java
index 1644fa4a7c..8a5e73d441 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapter.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import db.*;
import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -45,26 +46,26 @@ abstract class EnumDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of enumeration data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task cancelled
*/
- static EnumDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static EnumDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new EnumDBAdapterV1(handle, true);
+ return new EnumDBAdapterV1(handle, tablePrefix, true);
}
try {
- return new EnumDBAdapterV1(handle, false);
+ return new EnumDBAdapterV1(handle, tablePrefix, false);
}
catch (VersionException e) {
-// if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
-// throw e;
-// }
EnumDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -76,7 +77,7 @@ abstract class EnumDBAdapter {
* @return the read only Enumeration data type table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static EnumDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
+ private static EnumDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
try {
return new EnumDBAdapterV0(handle);
}
@@ -93,28 +94,35 @@ abstract class EnumDBAdapter {
* Upgrades the Enumeration data type table from the oldAdapter's version to the current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task cancelled
*/
- static EnumDBAdapter upgrade(DBHandle handle, EnumDBAdapter oldAdapter)
- throws VersionException, IOException {
+ private static EnumDBAdapter upgrade(DBHandle handle, EnumDBAdapter oldAdapter,
+ String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
EnumDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new EnumDBAdapterV1(tmpHandle, true);
+ tmpAdapter = new EnumDBAdapterV1(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
- EnumDBAdapterV1 newAdapter = new EnumDBAdapterV1(handle, true);
+ EnumDBAdapterV1 newAdapter = new EnumDBAdapterV1(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec, false);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV0.java
index 733b9a9708..3bcd715bfd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV0.java
@@ -28,6 +28,7 @@ import ghidra.util.exception.VersionException;
* Version 0 implementation for accessing the Enumeration database table.
*/
class EnumDBAdapterV0 extends EnumDBAdapter implements RecordTranslator {
+
static final int VERSION = 0;
// Enum Columns
@@ -36,10 +37,11 @@ class EnumDBAdapterV0 extends EnumDBAdapter implements RecordTranslator {
static final int V0_ENUM_CAT_COL = 2;
static final int V0_ENUM_SIZE_COL = 3;
- static final Schema V0_ENUM_SCHEMA = new Schema(
- VERSION, "Enum ID", new Field[] { StringField.INSTANCE, StringField.INSTANCE,
- LongField.INSTANCE, ByteField.INSTANCE },
- new String[] { "Name", "Comment", "Category ID", "Size" });
+// DO NOT REMOVE - this documents the schema used in version 0.
+// static final Schema V0_ENUM_SCHEMA = new Schema(
+// VERSION, "Enum ID", new Field[] { StringField.INSTANCE, StringField.INSTANCE,
+// LongField.INSTANCE, ByteField.INSTANCE },
+// new String[] { "Name", "Comment", "Category ID", "Size" });
private Table enumTable;
@@ -53,16 +55,11 @@ class EnumDBAdapterV0 extends EnumDBAdapter implements RecordTranslator {
enumTable = handle.getTable(ENUM_TABLE_NAME);
if (enumTable == null) {
- throw new VersionException("Missing Table: " + ENUM_TABLE_NAME);
+ throw new VersionException(true);
}
int version = enumTable.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + ENUM_TABLE_NAME +
- " but got " + enumTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(false);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV1.java
index aa37beae15..06b3e7ce1b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV1.java
@@ -24,6 +24,8 @@ import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for accessing the Enumeration database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class EnumDBAdapterV1 extends EnumDBAdapter {
static final int VERSION = 1;
@@ -50,29 +52,27 @@ class EnumDBAdapterV1 extends EnumDBAdapter {
/**
* Gets a version 1 adapter for the Enumeration database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @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 an IO error occured during table creation
*/
- public EnumDBAdapterV1(DBHandle handle, boolean create) throws VersionException, IOException {
-
+ public EnumDBAdapterV1(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + ENUM_TABLE_NAME;
if (create) {
- enumTable = handle.createTable(ENUM_TABLE_NAME, V1_ENUM_SCHEMA,
+ enumTable = handle.createTable(tableName, V1_ENUM_SCHEMA,
new int[] { V1_ENUM_CAT_COL, V1_ENUM_UNIVERSAL_DT_ID_COL });
}
else {
- enumTable = handle.getTable(ENUM_TABLE_NAME);
+ enumTable = handle.getTable(tableName);
if (enumTable == null) {
- throw new VersionException("Missing Table: " + ENUM_TABLE_NAME);
+ throw new VersionException(true);
}
int version = enumTable.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + ENUM_TABLE_NAME +
- " but got " + enumTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
}
@@ -121,7 +121,7 @@ class EnumDBAdapterV1 extends EnumDBAdapter {
@Override
protected void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(ENUM_TABLE_NAME);
+ handle.deleteTable(enumTable.getName());
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java
index bb0adfeba2..1b0d8403d6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java
@@ -24,6 +24,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -46,18 +47,20 @@ abstract class EnumValueDBAdapter implements RecordTranslator {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of enumeration data type values.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
- static EnumValueDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static EnumValueDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new EnumValueDBAdapterV1(handle, true);
+ return new EnumValueDBAdapterV1(handle, tablePrefix, true);
}
try {
- return new EnumValueDBAdapterV1(handle, false);
+ return new EnumValueDBAdapterV1(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -65,13 +68,13 @@ abstract class EnumValueDBAdapter implements RecordTranslator {
}
EnumValueDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
}
- static EnumValueDBAdapter findReadOnlyAdapter(DBHandle handle) {
+ private static EnumValueDBAdapter findReadOnlyAdapter(DBHandle handle) {
try {
return new EnumValueDBAdapterV0(handle);
}
@@ -85,28 +88,34 @@ abstract class EnumValueDBAdapter implements RecordTranslator {
* version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static EnumValueDBAdapter upgrade(DBHandle handle, EnumValueDBAdapter oldAdapter)
- throws VersionException, IOException {
+ private static EnumValueDBAdapter upgrade(DBHandle handle, EnumValueDBAdapter oldAdapter,
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
EnumValueDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new EnumValueDBAdapterV1(tmpHandle, true);
+ tmpAdapter = new EnumValueDBAdapterV1(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- EnumValueDBAdapter newAdapter = new EnumValueDBAdapterV1(handle, true);
+ EnumValueDBAdapter newAdapter = new EnumValueDBAdapterV1(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
@@ -149,9 +158,7 @@ abstract class EnumValueDBAdapter implements RecordTranslator {
* @param handle the handle used to delete the table
* @throws IOException if there was a problem accessing the database
*/
- void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(ENUM_VALUE_TABLE_NAME);
- }
+ abstract void deleteTable(DBHandle handle) throws IOException;
/**
* Remove the record for the given enum Value ID.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java
index a07ff31f4e..8afa4fb1df 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java
@@ -32,33 +32,33 @@ class EnumValueDBAdapterNoTable extends EnumValueDBAdapter {
* Gets a pre-table version of the adapter for the enumeration data type values database table.
* @param handle handle to the database which doesn't contain the table.
*/
- public EnumValueDBAdapterNoTable(DBHandle handle) {
+ EnumValueDBAdapterNoTable(DBHandle handle) {
// no table needed
}
@Override
- public void createRecord(long enumID, String name, long value, String comment)
+ void createRecord(long enumID, String name, long value, String comment)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public DBRecord getRecord(long valueID) throws IOException {
+ DBRecord getRecord(long valueID) throws IOException {
return null;
}
@Override
- public void updateRecord(DBRecord record) throws IOException {
+ void updateRecord(DBRecord record) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public void removeRecord(long valueID) throws IOException {
+ void removeRecord(long valueID) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public Field[] getValueIdsInEnum(long enumID) throws IOException {
+ Field[] getValueIdsInEnum(long enumID) throws IOException {
return Field.EMPTY_ARRAY;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java
index 87dfa5fd83..68226355e4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java
@@ -39,7 +39,7 @@ class EnumValueDBAdapterV0 extends EnumValueDBAdapter {
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public EnumValueDBAdapterV0(DBHandle handle) throws VersionException {
+ EnumValueDBAdapterV0(DBHandle handle) throws VersionException {
table = handle.getTable(ENUM_VALUE_TABLE_NAME);
if (table == null) {
@@ -55,31 +55,35 @@ class EnumValueDBAdapterV0 extends EnumValueDBAdapter {
}
@Override
- public void createRecord(long enumID, String name, long value, String comment)
+ void createRecord(long enumID, String name, long value, String comment)
throws IOException {
throw new UnsupportedOperationException("Cannot update Version 0");
}
@Override
- public DBRecord getRecord(long valueID) throws IOException {
+ DBRecord getRecord(long valueID) throws IOException {
return translateRecord(table.getRecord(valueID));
}
@Override
- public void removeRecord(long valueID) throws IOException {
+ void removeRecord(long valueID) throws IOException {
throw new UnsupportedOperationException("Cannot remove Version 0");
}
@Override
- public void updateRecord(DBRecord record) throws IOException {
+ void updateRecord(DBRecord record) throws IOException {
throw new UnsupportedOperationException("Cannot update Version 0");
}
@Override
- public Field[] getValueIdsInEnum(long enumID) throws IOException {
+ Field[] getValueIdsInEnum(long enumID) throws IOException {
return table.findRecords(new LongField(enumID), ENUMVAL_ID_COL);
}
+ void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(ENUM_VALUE_TABLE_NAME);
+ }
+
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV1.java
index 1b3b922767..33522350c3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV1.java
@@ -22,6 +22,8 @@ import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for the enumeration tables adapter.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
@@ -36,36 +38,32 @@ class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
/**
* Gets a version 1 adapter for the Enumeration Data Type Values database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @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 EnumValueDBAdapterV1(DBHandle handle, boolean create)
+ EnumValueDBAdapterV1(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + ENUM_VALUE_TABLE_NAME;
if (create) {
- table = handle.createTable(ENUM_VALUE_TABLE_NAME, SCHEMA, new int[] { ENUMVAL_ID_COL });
+ table = handle.createTable(tableName, SCHEMA, new int[] { ENUMVAL_ID_COL });
}
else {
- table = handle.getTable(ENUM_VALUE_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
throw new VersionException(true);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + ENUM_VALUE_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);
+ throw new VersionException(version < VERSION);
}
}
}
@Override
- public void createRecord(long enumID, String name, long value, String comment)
+ void createRecord(long enumID, String name, long value, String comment)
throws IOException {
DBRecord record = SCHEMA.createRecord(table.getKey());
record.setLongValue(ENUMVAL_ID_COL, enumID);
@@ -76,22 +74,22 @@ class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
}
@Override
- public DBRecord getRecord(long valueID) throws IOException {
+ DBRecord getRecord(long valueID) throws IOException {
return table.getRecord(valueID);
}
@Override
- public void removeRecord(long valueID) throws IOException {
+ void removeRecord(long valueID) throws IOException {
table.deleteRecord(valueID);
}
@Override
- public void updateRecord(DBRecord record) throws IOException {
+ void updateRecord(DBRecord record) throws IOException {
table.putRecord(record);
}
@Override
- public Field[] getValueIdsInEnum(long enumID) throws IOException {
+ Field[] getValueIdsInEnum(long enumID) throws IOException {
return table.findRecords(new LongField(enumID), ENUMVAL_ID_COL);
}
@@ -100,6 +98,10 @@ class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
return table.iterator();
}
+ void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(table.getName());
+ }
+
@Override
public DBRecord translateRecord(DBRecord r) {
return r;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java
index b0fdce3a9b..9c1ccb91d2 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java
@@ -24,12 +24,14 @@ import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsImpl;
import ghidra.program.database.DBObjectCache;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.symbol.SourceType;
-import ghidra.util.Msg;
import ghidra.util.UniversalID;
+import ghidra.util.exception.AssertException;
+import ghidra.util.exception.InvalidInputException;
class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
@@ -108,13 +110,17 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
try {
checkIsValid();
StringBuffer buf = new StringBuffer();
+ if (includeCallingConvention && hasNoReturn()) {
+ buf.append(NORETURN_DISPLAY_STRING);
+ buf.append(" ");
+ }
DataType returnType = getReturnType();
buf.append((returnType != null ? returnType.getDisplayName() : "void"));
buf.append(" ");
if (includeCallingConvention) {
- GenericCallingConvention genericCallingConvention = getGenericCallingConvention();
- if (genericCallingConvention != GenericCallingConvention.unknown) {
- buf.append(genericCallingConvention.name());
+ String callingConvention = getCallingConventionName();
+ if (!Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConvention)) {
+ buf.append(callingConvention);
buf.append(" ");
}
}
@@ -188,7 +194,6 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
lock.acquire();
try {
checkDeleted();
-
setArguments(functionDefinition.getArguments());
try {
setReturnType(functionDefinition.getReturnType());
@@ -197,7 +202,16 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
setReturnType(DEFAULT);
}
setVarArgs(functionDefinition.hasVarArgs());
- setGenericCallingConvention(functionDefinition.getGenericCallingConvention());
+ setNoReturn(functionDefinition.hasNoReturn());
+ try {
+ setCallingConvention(functionDefinition.getCallingConventionName(), false);
+ }
+ catch (InvalidInputException e) {
+ // will not happen
+ }
+ }
+ catch (IOException e) {
+ dataMgr.dbError(e);
}
finally {
lock.release();
@@ -394,8 +408,9 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
(comment != null && comment.equals(myComment))) &&
(DataTypeUtilities.isSameOrEquivalentDataType(getReturnType(),
signature.getReturnType())) &&
- (getGenericCallingConvention() == signature.getGenericCallingConvention()) &&
- (hasVarArgs() == signature.hasVarArgs())) {
+ getCallingConventionName().equals(signature.getCallingConventionName()) &&
+ (hasVarArgs() == signature.hasVarArgs()) &&
+ (hasNoReturn() == signature.hasNoReturn())) {
ParameterDefinition[] args = signature.getArguments();
ParameterDefinition[] thisArgs = this.getArguments();
if (args.length == thisArgs.length) {
@@ -517,6 +532,22 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
}
}
+ @Override
+ public boolean hasNoReturn() {
+ lock.acquire();
+ try {
+ checkIsValid();
+ if (record == null) {
+ return false;
+ }
+ byte flags = record.getByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL);
+ return ((flags & FunctionDefinitionDBAdapter.FUNCTION_DEF_NORETURN_FLAG) != 0);
+ }
+ finally {
+ lock.release();
+ }
+ }
+
@Override
public void setVarArgs(boolean hasVarArgs) {
lock.acquire();
@@ -544,20 +575,17 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
}
@Override
- public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention) {
+ public void setNoReturn(boolean hasNoReturn) {
lock.acquire();
try {
checkDeleted();
- int ordinal = genericCallingConvention.ordinal();
- if (ordinal < 0 ||
- ordinal > FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_MASK) {
- Msg.error(this, "GenericCallingConvention ordinal unsupported: " + ordinal);
- return;
- }
byte flags = record.getByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL);
- flags &=
- ~(FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_MASK << FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_SHIFT);
- flags |= ordinal << FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_SHIFT;
+ if (hasNoReturn) {
+ flags |= FunctionDefinitionDBAdapter.FUNCTION_DEF_NORETURN_FLAG;
+ }
+ else {
+ flags &= ~FunctionDefinitionDBAdapter.FUNCTION_DEF_NORETURN_FLAG;
+ }
record.setByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL, flags);
try {
funDefAdapter.updateRecord(record, true);
@@ -573,18 +601,70 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
}
@Override
- public GenericCallingConvention getGenericCallingConvention() {
+ public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention) {
+ lock.acquire();
+ try {
+ checkDeleted();
+ setCallingConvention(genericCallingConvention.name(), false);
+ }
+ catch (IOException e) {
+ dataMgr.dbError(e);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertException(e);
+ }
+ finally {
+ lock.release();
+ }
+ }
+
+ @Override
+ public void setCallingConvention(String conventionName) throws InvalidInputException {
+ lock.acquire();
+ try {
+ checkDeleted();
+ setCallingConvention(conventionName, true);
+ }
+ catch (IOException e) {
+ dataMgr.dbError(e);
+ }
+ finally {
+ lock.release();
+ }
+ }
+
+ private void setCallingConvention(String conventionName, boolean restrictive)
+ throws InvalidInputException, IOException {
+ byte id = dataMgr.getCallingConventionID(conventionName, restrictive);
+ record.setByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_CALLCONV_COL, id);
+ funDefAdapter.updateRecord(record, true);
+ dataMgr.dataTypeChanged(this, false);
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention() {
+ ProgramArchitecture arch = dataMgr.getProgramArchitecture();
+ if (arch == null) {
+ return null;
+ }
+ String callingConvention = getCallingConventionName();
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ return compilerSpec.getCallingConvention(callingConvention);
+ }
+
+ @Override
+ public String getCallingConventionName() {
lock.acquire();
try {
checkIsValid();
if (record == null) {
- return GenericCallingConvention.unknown;
+ return Function.UNKNOWN_CALLING_CONVENTION_STRING;
}
- byte flags = record.getByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL);
- int ordinal =
- (flags >> FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_SHIFT) &
- FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_MASK;
- return GenericCallingConvention.get(ordinal);
+ byte id = record.getByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_CALLCONV_COL);
+ if (funDefAdapter.usesGenericCallingConventionId()) {
+ return FunctionDefinitionDBAdapter.getGenericCallingConventionName(id);
+ }
+ return dataMgr.getCallingConventionName(id);
}
finally {
lock.release();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapter.java
index cefe1f96bb..d840224fac 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapter.java
@@ -18,68 +18,81 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.program.database.util.DBRecordAdapter;
import ghidra.program.model.data.GenericCallingConvention;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
/**
* Adapter to access the Function Signature Definition database table.
*/
-abstract class FunctionDefinitionDBAdapter {
+abstract class FunctionDefinitionDBAdapter implements DBRecordAdapter {
static final String FUNCTION_DEF_TABLE_NAME = "Function Definitions";
- static final Schema FUN_DEF_SCHEMA = FunctionDefinitionDBAdapterV1.V1_FUN_DEF_SCHEMA;
+ static final Schema FUN_DEF_SCHEMA = FunctionDefinitionDBAdapterV2.V2_FUN_DEF_SCHEMA;
- static final int FUNCTION_DEF_NAME_COL = FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_NAME_COL;
+ static final int FUNCTION_DEF_NAME_COL = FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_NAME_COL;
static final int FUNCTION_DEF_COMMENT_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_COMMENT_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_COMMENT_COL;
static final int FUNCTION_DEF_CAT_ID_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_CAT_ID_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_CAT_ID_COL;
static final int FUNCTION_DEF_RETURN_ID_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_RETURN_ID_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_RETURN_ID_COL;
static final int FUNCTION_DEF_FLAGS_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_FLAGS_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_FLAGS_COL;
+ static final int FUNCTION_DEF_CALLCONV_COL =
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_CALLCONV_COL;
static final int FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL;
static final int FUNCTION_DEF_SOURCE_DT_ID_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_UNIVERSAL_DT_ID_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL;
static final int FUNCTION_DEF_SOURCE_SYNC_TIME_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_SOURCE_SYNC_TIME_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_SOURCE_SYNC_TIME_COL;
static final int FUNCTION_DEF_LAST_CHANGE_TIME_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_LAST_CHANGE_TIME_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_LAST_CHANGE_TIME_COL;
static final byte FUNCTION_DEF_VARARG_FLAG = (byte) 0x1; // Bit 0 is flag for "has vararg".
-
- // Flags Bits 1..4 used for generic calling convention ID
- static final int GENERIC_CALLING_CONVENTION_FLAG_MASK = 0xf;
- static final int GENERIC_CALLING_CONVENTION_FLAG_SHIFT = 1;
+ static final byte FUNCTION_DEF_NORETURN_FLAG = (byte) 0x2; // Bit 1 is flag for "has noreturn" (added with V2).
/**
* Gets an adapter for working with the function definition data type database table. The adapter is based
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @param callConvAdapter calling convention table adapter suitable to add new conventions
+ * (e.g., this adapter being used during upgrade operation). Only used when openMode is
+ * {@link DBConstants#UPGRADE} when adding new calling conventions must be permitted.
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of function definition data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
static FunctionDefinitionDBAdapter getAdapter(DBHandle handle, int openMode,
- TaskMonitor monitor) throws VersionException, IOException {
+ String tablePrefix, CallingConventionDBAdapter callConvAdapter, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
+
if (openMode == DBConstants.CREATE) {
- return new FunctionDefinitionDBAdapterV1(handle, true);
+ return new FunctionDefinitionDBAdapterV2(handle, tablePrefix, true);
}
try {
- return new FunctionDefinitionDBAdapterV1(handle, false);
+ return new FunctionDefinitionDBAdapterV2(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
throw e;
}
- FunctionDefinitionDBAdapter adapter = findReadOnlyAdapter(handle);
+ FunctionDefinitionDBAdapter adapter;
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = findReadOnlyAdapter(handle, tablePrefix, callConvAdapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
+ }
+ else {
+ adapter = findReadOnlyAdapter(handle, tablePrefix, null);
}
return adapter;
}
@@ -88,18 +101,27 @@ abstract class FunctionDefinitionDBAdapter {
/**
* Tries to get a read only adapter for the database whose handle is passed to this method.
* @param handle handle to prior version of the database.
+ * @param tablePrefix prefix to be used with default table name
+ * @param callConvAdapter calling convention table adapter suitable to add new conventions
+ * (e.g., this adapter being used during upgrade operation). Should be null if not performing
+ * an upgrade.
* @return the read only Function Definition data type table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static FunctionDefinitionDBAdapter findReadOnlyAdapter(DBHandle handle)
+ private static FunctionDefinitionDBAdapter findReadOnlyAdapter(DBHandle handle,
+ String tablePrefix, CallingConventionDBAdapter callConvAdapter)
throws VersionException {
+ try {
+ return new FunctionDefinitionDBAdapterV1(handle, tablePrefix, callConvAdapter);
+ }
+ catch (VersionException e) {
+ // ignore
+ }
try {
return new FunctionDefinitionDBAdapterV0(handle);
}
catch (VersionException e) {
- if (!e.isUpgradable()) {
- throw e;
- }
+ // ignore
}
return new FunctionDefinitionDBAdapterNoTable(handle);
@@ -109,29 +131,35 @@ abstract class FunctionDefinitionDBAdapter {
* Upgrades the Function Definition data type table from the oldAdapter's version to the current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static FunctionDefinitionDBAdapter upgrade(DBHandle handle,
- FunctionDefinitionDBAdapter oldAdapter) throws VersionException, IOException {
+ private static FunctionDefinitionDBAdapter upgrade(DBHandle handle,
+ FunctionDefinitionDBAdapter oldAdapter, String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
FunctionDefinitionDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new FunctionDefinitionDBAdapterV1(tmpHandle, true);
+ tmpAdapter = new FunctionDefinitionDBAdapterV2(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
- FunctionDefinitionDBAdapterV1 newAdapter =
- new FunctionDefinitionDBAdapterV1(handle, true);
+ FunctionDefinitionDBAdapter newAdapter =
+ new FunctionDefinitionDBAdapterV2(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec, false);
}
@@ -150,7 +178,8 @@ abstract class FunctionDefinitionDBAdapter {
* @param categoryID the ID for the category that contains this data type.
* @param returnDtID the ID of the data type that is returned by this function definition.
* @param hasVarArgs true if this function definition has a variable length argument list.
- * @param genericCallingConvention generic calling convention
+ * @param hasNoReturn true if this function definition has noreturn enabled
+ * @param callingConventionID calling convention ID
* @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.
* @param lastChangeTime the time this data type was last changed.
@@ -158,8 +187,8 @@ abstract class FunctionDefinitionDBAdapter {
* @throws IOException if the database can't be accessed.
*/
abstract DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
- boolean hasVarArgs, GenericCallingConvention genericCallingConvention,
- long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException;
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException;
/**
* Gets a function signature definition data type record from the database based on its ID.
@@ -174,7 +203,7 @@ abstract class FunctionDefinitionDBAdapter {
* @return the function definition data type record iterator.
* @throws IOException if the database can't be accessed.
*/
- abstract RecordIterator getRecords() throws IOException;
+ public abstract RecordIterator getRecords() throws IOException;
/**
* Removes the function definition data type record with the specified ID.
@@ -227,4 +256,27 @@ abstract class FunctionDefinitionDBAdapter {
abstract DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID)
throws IOException;
+ /**
+ * Determine if the calling convention ID within record reflects a Generic Calling Convention
+ * ordinal (i.e., true if V1 adapter in use for read-only mode).
+ * See {@link #getGenericCallingConventionName(int)} for Generic Calling Convention name lookup.
+ * @return true if calling convention ID within record reflects a Generic Calling Convention
+ * ordinal.
+ */
+ boolean usesGenericCallingConventionId() {
+ return false;
+ }
+
+ /**
+ * Get old GenericCallingConvention name for specified ordinal value.
+ * @param ordinal old GenericCallingConvention ordinal
+ * @return old GenericCallingConvention name
+ */
+ static String getGenericCallingConventionName(int ordinal) {
+ GenericCallingConvention genericCallingConvention = GenericCallingConvention.get(ordinal);
+ return genericCallingConvention != GenericCallingConvention.unknown
+ ? genericCallingConvention.getDeclarationName()
+ : CompilerSpec.CALLING_CONVENTION_unknown;
+ }
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterNoTable.java
index cd149d79c1..38721f487b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterNoTable.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterNoTable.java
@@ -19,7 +19,6 @@ import java.io.IOException;
import db.*;
import ghidra.program.database.util.EmptyRecordIterator;
-import ghidra.program.model.data.GenericCallingConvention;
import ghidra.util.UniversalID;
/**
@@ -37,15 +36,19 @@ class FunctionDefinitionDBAdapterNoTable extends FunctionDefinitionDBAdapter {
}
@Override
- public DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
- boolean hasVarArgs, GenericCallingConvention genericCallingConvention,
- long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
- throw new UnsupportedOperationException(
- "Not allowed to update version prior to existence of Function Definition Data Types table.");
+ DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
- public DBRecord getRecord(long functionDefID) throws IOException {
+ public int getRecordCount() {
+ return 0;
+ }
+
+ @Override
+ DBRecord getRecord(long functionDefID) throws IOException {
return null;
}
@@ -55,22 +58,22 @@ class FunctionDefinitionDBAdapterNoTable extends FunctionDefinitionDBAdapter {
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long functionDefID) throws IOException {
+ boolean removeRecord(long functionDefID) throws IOException {
return false;
}
@Override
- protected void deleteTable(DBHandle handle) {
+ void deleteTable(DBHandle handle) {
// do nothing
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return Field.EMPTY_ARRAY;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV0.java
index 5697a0069b..34ee8aec09 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV0.java
@@ -18,7 +18,8 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
-import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.util.UniversalID;
import ghidra.util.UniversalIdGenerator;
import ghidra.util.exception.VersionException;
@@ -28,12 +29,15 @@ import ghidra.util.exception.VersionException;
*/
class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
implements RecordTranslator {
+
static final int VERSION = 0;
+
static final int V0_FUNCTION_DEF_NAME_COL = 0;
static final int V0_FUNCTION_DEF_COMMENT_COL = 1;
static final int V0_FUNCTION_DEF_CAT_ID_COL = 2;
static final int V0_FUNCTION_DEF_RETURN_ID_COL = 3;
static final int V0_FUNCTION_DEF_FLAGS_COL = 4;
+
// DO NOT REMOVE WHAT'S BELOW - this documents the schema used in version 0.
// static final Schema V0_FUN_DEF_SCHEMA = new Schema(VERSION, "Data Type ID",
// new Class[] {StringField.class, StringField.class,
@@ -51,33 +55,31 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public FunctionDefinitionDBAdapterV0(DBHandle handle) throws VersionException {
+ FunctionDefinitionDBAdapterV0(DBHandle handle) throws VersionException {
table = handle.getTable(FUNCTION_DEF_TABLE_NAME);
if (table == null) {
- throw new VersionException("Missing Table: " + FUNCTION_DEF_TABLE_NAME);
+ throw new VersionException(true);
}
- int version = table.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + FUNCTION_DEF_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);
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
@Override
- public DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
- boolean hasVarArgs, GenericCallingConvention genericCallingConvention,
- long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
- throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
- " of " + FUNCTION_DEF_TABLE_NAME + " table.");
+ public int getRecordCount() {
+ return table.getRecordCount();
}
@Override
- public DBRecord getRecord(long functionDefID) throws IOException {
+ DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ DBRecord getRecord(long functionDefID) throws IOException {
return translateRecord(table.getRecord(functionDefID));
}
@@ -87,22 +89,22 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long functionDefID) throws IOException {
- return table.deleteRecord(functionDefID);
+ boolean removeRecord(long functionDefID) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
- protected void deleteTable(DBHandle handle) throws IOException {
+ void deleteTable(DBHandle handle) throws IOException {
handle.deleteTable(FUNCTION_DEF_TABLE_NAME);
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), V0_FUNCTION_DEF_CAT_ID_COL);
}
@@ -111,6 +113,11 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
return Field.EMPTY_ARRAY;
}
+ @Override
+ DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
+ return null;
+ }
+
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
@@ -123,6 +130,8 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
rec.setLongValue(FUNCTION_DEF_RETURN_ID_COL,
oldRec.getLongValue(V0_FUNCTION_DEF_RETURN_ID_COL));
rec.setByteValue(FUNCTION_DEF_FLAGS_COL, oldRec.getByteValue(V0_FUNCTION_DEF_FLAGS_COL));
+ rec.setByteValue(FUNCTION_DEF_CALLCONV_COL,
+ DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID);
rec.setLongValue(FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL, DataTypeManager.LOCAL_ARCHIVE_KEY);
rec.setLongValue(FUNCTION_DEF_SOURCE_DT_ID_COL, UniversalIdGenerator.nextID().getValue());
rec.setLongValue(FUNCTION_DEF_SOURCE_SYNC_TIME_COL, DataType.NO_SOURCE_SYNC_TIME);
@@ -130,9 +139,4 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
return rec;
}
- @Override
- DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
- return null;
- }
-
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV1.java
index b3fa3de5ba..3c89118faa 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV1.java
@@ -16,19 +16,24 @@
package ghidra.program.database.data;
import java.io.IOException;
-import java.util.Date;
import db.*;
-import ghidra.program.model.data.GenericCallingConvention;
-import ghidra.util.Msg;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.util.UniversalID;
+import ghidra.util.UniversalIdGenerator;
import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for accessing the Function Signature Definition database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
-class FunctionDefinitionDBAdapterV1 extends FunctionDefinitionDBAdapter {
+class FunctionDefinitionDBAdapterV1 extends FunctionDefinitionDBAdapter
+ implements RecordTranslator {
+
static final int VERSION = 1;
+
static final int V1_FUNCTION_DEF_NAME_COL = 0;
static final int V1_FUNCTION_DEF_COMMENT_COL = 1;
static final int V1_FUNCTION_DEF_CAT_ID_COL = 2;
@@ -38,116 +43,91 @@ class FunctionDefinitionDBAdapterV1 extends FunctionDefinitionDBAdapter {
static final int V1_FUNCTION_DEF_UNIVERSAL_DT_ID_COL = 6;
static final int V1_FUNCTION_DEF_SOURCE_SYNC_TIME_COL = 7;
static final int V1_FUNCTION_DEF_LAST_CHANGE_TIME_COL = 8;
- static final Schema V1_FUN_DEF_SCHEMA = new Schema(VERSION, "Data Type ID",
- new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
- LongField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
- LongField.INSTANCE, LongField.INSTANCE },
- new String[] { "Name", "Comment", "Category ID", "Return Type ID", "Flags",
- "Source Archive ID", "Source 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_FUN_DEF_SCHEMA = new Schema(VERSION, "Data Type ID",
+// new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
+// LongField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
+// LongField.INSTANCE, LongField.INSTANCE },
+// new String[] { "Name", "Comment", "Category ID", "Return Type ID", "Flags",
+// "Source Archive ID", "Source Data Type ID", "Source Sync Time", "Last Change Time" });
+
+ // Flags Bits 1..4 used for generic calling convention ID
+ private static final int GENERIC_CALLING_CONVENTION_FLAG_MASK = 0xf;
+ private static final int GENERIC_CALLING_CONVENTION_FLAG_SHIFT = 1;
private Table table;
+ private CallingConventionDBAdapter callConvAdapter; // must be null if not performing upgrade
/**
- * Gets a version 1 adapter for the Function Definition database table.
+ * Gets a version 1 read-only adapter for the Function Definition database table.
* @param handle handle to the database containing the table.
- * @param create true if this constructor should create the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param callConvAdapter calling convention table adapter suitable to add new conventions
+ * (e.g., this adapter being used during upgrade operation). Should be null if not performing
+ * an upgrade in which case calling convention IDs will reflect generic convention ordinals.
+ *
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public FunctionDefinitionDBAdapterV1(DBHandle handle, boolean create)
- throws VersionException, IOException {
-
- if (create) {
- table = handle.createTable(FUNCTION_DEF_TABLE_NAME, V1_FUN_DEF_SCHEMA,
- new int[] { V1_FUNCTION_DEF_CAT_ID_COL, V1_FUNCTION_DEF_UNIVERSAL_DT_ID_COL });
+ public FunctionDefinitionDBAdapterV1(DBHandle handle, String tablePrefix,
+ CallingConventionDBAdapter callConvAdapter) throws VersionException {
+ this.callConvAdapter = callConvAdapter;
+ String tableName = tablePrefix + FUNCTION_DEF_TABLE_NAME;
+ table = handle.getTable(tableName);
+ if (table == null) {
+ throw new VersionException(true);
}
- else {
- table = handle.getTable(FUNCTION_DEF_TABLE_NAME);
- if (table == null) {
- throw new VersionException("Missing Table: " + FUNCTION_DEF_TABLE_NAME);
- }
- int version = table.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " +
- FUNCTION_DEF_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) {
+ throw new VersionException(version < VERSION);
}
}
@Override
- public DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
- boolean hasVarArgs, GenericCallingConvention genericCallingConvention,
- long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
- byte flags = (byte) 0;
- if (hasVarArgs) {
- flags |= FunctionDefinitionDBAdapter.FUNCTION_DEF_VARARG_FLAG;
- }
- if (genericCallingConvention != null) {
- int ordinal = genericCallingConvention.ordinal();
- if (ordinal < 0 ||
- ordinal > FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_MASK) {
- Msg.error(this, "GenericCallingConvention ordinal unsupported: " + ordinal);
- }
- else {
- flags |=
- ordinal << FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_SHIFT;
- }
- }
- long tableKey = table.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.FUNCTION_DEF, tableKey);
- DBRecord record = V1_FUN_DEF_SCHEMA.createRecord(key);
-
- record.setString(V1_FUNCTION_DEF_NAME_COL, name);
- record.setString(V1_FUNCTION_DEF_COMMENT_COL, comments);
- record.setLongValue(V1_FUNCTION_DEF_CAT_ID_COL, categoryID);
- record.setLongValue(V1_FUNCTION_DEF_RETURN_ID_COL, returnDtID);
- record.setByteValue(V1_FUNCTION_DEF_FLAGS_COL, flags);
- record.setLongValue(V1_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
- record.setLongValue(V1_FUNCTION_DEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
- record.setLongValue(V1_FUNCTION_DEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
- record.setLongValue(V1_FUNCTION_DEF_LAST_CHANGE_TIME_COL, lastChangeTime);
- table.putRecord(record);
- return record;
+ boolean usesGenericCallingConventionId() {
+ return callConvAdapter == null;
}
@Override
- public DBRecord getRecord(long functionDefID) throws IOException {
- return table.getRecord(functionDefID);
+ public int getRecordCount() {
+ return table.getRecordCount();
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
- if (setLastChangeTime) {
- record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_LAST_CHANGE_TIME_COL,
- (new Date()).getTime());
- }
- table.putRecord(record);
+ DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ DBRecord getRecord(long functionDefID) throws IOException {
+ return translateRecord(table.getRecord(functionDefID));
+ }
+
+ @Override
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
public RecordIterator getRecords() throws IOException {
- return table.iterator();
+ return new TranslatedRecordIterator(table.iterator(), this);
}
@Override
- public boolean removeRecord(long functionDefID) throws IOException {
- return table.deleteRecord(functionDefID);
+ boolean removeRecord(long functionDefID) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
- protected void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(FUNCTION_DEF_TABLE_NAME);
+ void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(table.getName());
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), V1_FUNCTION_DEF_CAT_ID_COL);
}
@@ -169,4 +149,48 @@ class FunctionDefinitionDBAdapterV1 extends FunctionDefinitionDBAdapter {
}
return null;
}
+
+ @Override
+ public DBRecord translateRecord(DBRecord oldRec) {
+ if (oldRec == null) {
+ return null;
+ }
+ DBRecord rec = FunctionDefinitionDBAdapter.FUN_DEF_SCHEMA.createRecord(oldRec.getKey());
+ rec.setString(FUNCTION_DEF_NAME_COL, oldRec.getString(V1_FUNCTION_DEF_NAME_COL));
+ rec.setString(FUNCTION_DEF_COMMENT_COL, oldRec.getString(V1_FUNCTION_DEF_COMMENT_COL));
+ rec.setLongValue(FUNCTION_DEF_CAT_ID_COL, oldRec.getLongValue(V1_FUNCTION_DEF_CAT_ID_COL));
+ rec.setLongValue(FUNCTION_DEF_RETURN_ID_COL, oldRec.getLongValue(V1_FUNCTION_DEF_RETURN_ID_COL));
+
+ byte flags = oldRec.getByteValue(V1_FUNCTION_DEF_FLAGS_COL);
+ int mask = GENERIC_CALLING_CONVENTION_FLAG_MASK << GENERIC_CALLING_CONVENTION_FLAG_SHIFT;
+ int genericCallConvId = (flags & mask) >> GENERIC_CALLING_CONVENTION_FLAG_SHIFT;
+ flags &= (byte) (~mask); // clear old flag bits used for calling convention
+
+ byte callingConventionId = DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID;
+ try {
+ if (callConvAdapter == null) {
+ // Must use old generic calling convention ordinal as ID
+ callingConventionId = (byte) genericCallConvId;
+ }
+ else {
+ // It is expected that an open transaction exists during upgrade use
+ // and that all records are upgraded prior to general use
+ String callingConvention = getGenericCallingConventionName(genericCallConvId);
+ callingConventionId = callConvAdapter.getCallingConventionId(callingConvention,
+ cc -> {
+ /* ignore */ });
+ }
+ }
+ catch (IOException e) {
+ // ignore - use unknown convention ID
+ }
+
+ rec.setByteValue(FUNCTION_DEF_FLAGS_COL, flags);
+ rec.setByteValue(FUNCTION_DEF_CALLCONV_COL, callingConventionId);
+ rec.setLongValue(FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL, DataTypeManager.LOCAL_ARCHIVE_KEY);
+ rec.setLongValue(FUNCTION_DEF_SOURCE_DT_ID_COL, UniversalIdGenerator.nextID().getValue());
+ rec.setLongValue(FUNCTION_DEF_SOURCE_SYNC_TIME_COL, DataType.NO_SOURCE_SYNC_TIME);
+ rec.setLongValue(FUNCTION_DEF_LAST_CHANGE_TIME_COL, DataType.NO_LAST_CHANGE_TIME);
+ return rec;
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV2.java
new file mode 100644
index 0000000000..e57118173b
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV2.java
@@ -0,0 +1,164 @@
+/* ###
+ * 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 Function Signature Definition database table.
+ */
+class FunctionDefinitionDBAdapterV2 extends FunctionDefinitionDBAdapter {
+
+ static final int VERSION = 2;
+ static final int V2_FUNCTION_DEF_NAME_COL = 0;
+ static final int V2_FUNCTION_DEF_COMMENT_COL = 1;
+ static final int V2_FUNCTION_DEF_CAT_ID_COL = 2;
+ static final int V2_FUNCTION_DEF_RETURN_ID_COL = 3;
+ static final int V2_FUNCTION_DEF_FLAGS_COL = 4;
+ static final int V2_FUNCTION_DEF_CALLCONV_COL = 5;
+ static final int V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL = 6;
+ static final int V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL = 7;
+ static final int V2_FUNCTION_DEF_SOURCE_SYNC_TIME_COL = 8;
+ static final int V2_FUNCTION_DEF_LAST_CHANGE_TIME_COL = 9;
+ static final Schema V2_FUN_DEF_SCHEMA = new Schema(VERSION, "Data Type ID",
+ new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
+ LongField.INSTANCE, ByteField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE,
+ LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
+ new String[] { "Name", "Comment", "Category ID", "Return Type ID", "Flags", "Call Conv ID",
+ "Source Archive ID", "Source Data Type ID", "Source Sync Time", "Last Change Time" });
+
+ private Table table;
+
+ /**
+ * Gets a version 2 adapter for the Function Definition database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @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 an IO error occurs
+ */
+ public FunctionDefinitionDBAdapterV2(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + FUNCTION_DEF_TABLE_NAME;
+ if (create) {
+ table = handle.createTable(tableName, V2_FUN_DEF_SCHEMA,
+ new int[] { V2_FUNCTION_DEF_CAT_ID_COL, V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL });
+ }
+ else {
+ table = handle.getTable(tableName);
+ if (table == null) {
+ throw new VersionException(true);
+ }
+ int version = table.getSchema().getVersion();
+ if (version != VERSION) {
+ throw new VersionException(version < VERSION);
+ }
+ }
+ }
+
+ @Override
+ public int getRecordCount() {
+ return table.getRecordCount();
+ }
+
+ @Override
+ DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException {
+ byte flags = (byte) 0;
+ if (hasVarArgs) {
+ flags |= FUNCTION_DEF_VARARG_FLAG;
+ }
+ if (hasNoReturn) {
+ flags |= FUNCTION_DEF_NORETURN_FLAG;
+ }
+ long tableKey = table.getKey();
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.FUNCTION_DEF, tableKey);
+ DBRecord record = V2_FUN_DEF_SCHEMA.createRecord(key);
+
+ record.setString(V2_FUNCTION_DEF_NAME_COL, name);
+ record.setString(V2_FUNCTION_DEF_COMMENT_COL, comments);
+ record.setLongValue(V2_FUNCTION_DEF_CAT_ID_COL, categoryID);
+ record.setLongValue(V2_FUNCTION_DEF_RETURN_ID_COL, returnDtID);
+ record.setByteValue(V2_FUNCTION_DEF_FLAGS_COL, flags);
+ record.setByteValue(V2_FUNCTION_DEF_CALLCONV_COL, callingConventionID);
+ record.setLongValue(V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
+ record.setLongValue(V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
+ record.setLongValue(V2_FUNCTION_DEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
+ record.setLongValue(V2_FUNCTION_DEF_LAST_CHANGE_TIME_COL, lastChangeTime);
+ table.putRecord(record);
+ return record;
+ }
+
+ @Override
+ DBRecord getRecord(long functionDefID) throws IOException {
+ return table.getRecord(functionDefID);
+ }
+
+ @Override
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ if (setLastChangeTime) {
+ record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_LAST_CHANGE_TIME_COL,
+ (new Date()).getTime());
+ }
+ table.putRecord(record);
+ }
+
+ @Override
+ public RecordIterator getRecords() throws IOException {
+ return table.iterator();
+ }
+
+ @Override
+ boolean removeRecord(long functionDefID) throws IOException {
+ return table.deleteRecord(functionDefID);
+ }
+
+ @Override
+ void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(table.getName());
+ }
+
+ @Override
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ return table.findRecords(new LongField(categoryID), V2_FUNCTION_DEF_CAT_ID_COL);
+ }
+
+ @Override
+ Field[] getRecordIdsForSourceArchive(long archiveID) throws IOException {
+ return table.findRecords(new LongField(archiveID), V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL);
+ }
+
+ @Override
+ DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
+ Field[] keys = table.findRecords(new LongField(datatypeID.getValue()),
+ V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL);
+
+ for (int i = 0; i < keys.length; i++) {
+ DBRecord record = table.getRecord(keys[i]);
+ if (record.getLongValue(V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
+ return record;
+ }
+ }
+ return null;
+ }
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapter.java
index ef141fc156..6dc3b77bdd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapter.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -39,22 +40,24 @@ abstract class FunctionParameterAdapter {
FunctionParameterAdapterV1.V1_PARAMETER_DT_LENGTH_COL;
/**
- * Gets an adapter for working with the function definition parameters database table. The adapter is based
- * on the version of the database associated with the specified database handle and the openMode.
+ * Gets an adapter for working with the function definition parameters database table.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of function definition parameters.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
- static FunctionParameterAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static FunctionParameterAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new FunctionParameterAdapterV1(handle, true);
+ return new FunctionParameterAdapterV1(handle, tablePrefix, true);
}
try {
- return new FunctionParameterAdapterV1(handle, false);
+ return new FunctionParameterAdapterV1(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -62,7 +65,7 @@ abstract class FunctionParameterAdapter {
}
FunctionParameterAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -74,7 +77,8 @@ abstract class FunctionParameterAdapter {
* @return the read only Function Definition Parameters table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static FunctionParameterAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
+ private static FunctionParameterAdapter findReadOnlyAdapter(DBHandle handle)
+ throws VersionException {
try {
return new FunctionParameterAdapterV0(handle);
}
@@ -91,28 +95,35 @@ abstract class FunctionParameterAdapter {
* current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static FunctionParameterAdapter upgrade(DBHandle handle, FunctionParameterAdapter oldAdapter)
- throws VersionException, IOException {
+ private static FunctionParameterAdapter upgrade(DBHandle handle,
+ FunctionParameterAdapter oldAdapter, String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
FunctionParameterAdapter tmpAdapter = null;
try {
- tmpAdapter = new FunctionParameterAdapterV1(tmpHandle, true);
+ tmpAdapter = new FunctionParameterAdapterV1(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- FunctionParameterAdapterV1 newAdapter = new FunctionParameterAdapterV1(handle, true);
+ FunctionParameterAdapterV1 newAdapter =
+ new FunctionParameterAdapterV1(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV0.java
index b23f18271c..fb0b4dfaee 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV0.java
@@ -26,6 +26,7 @@ import ghidra.util.exception.VersionException;
class FunctionParameterAdapterV0 extends FunctionParameterAdapter implements RecordTranslator {
static final int VERSION = 0;
+
// Parameter Table Columns
static final int V0_PARAMETER_PARENT_ID_COL = 0;
static final int V0_PARAMETER_DT_ID_COL = 1;
@@ -52,34 +53,15 @@ class FunctionParameterAdapterV0 extends FunctionParameterAdapter implements Rec
if (parameterTable == null) {
throw new VersionException(true);
}
- int version = parameterTable.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + PARAMETER_TABLE_NAME +
- " but got " + parameterTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (parameterTable.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
@Override
public DBRecord createRecord(long dataTypeID, long parentID, int ordinal, String name,
String comment, int dtLength) throws IOException {
-
- long tableKey = parameterTable.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.PARAMETER, tableKey);
- DBRecord record = V0_PARAMETER_SCHEMA.createRecord(key);
- record.setLongValue(V0_PARAMETER_PARENT_ID_COL, parentID);
- record.setLongValue(V0_PARAMETER_DT_ID_COL, dataTypeID);
- record.setString(V0_PARAMETER_NAME_COL, name);
- record.setString(V0_PARAMETER_COMMENT_COL, comment);
- record.setIntValue(V0_PARAMETER_ORDINAL_COL, ordinal);
- parameterTable.putRecord(record);
- return record;
+ throw new UnsupportedOperationException();
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV1.java
index f67a7ea810..3a063a4550 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV1.java
@@ -22,6 +22,8 @@ import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for accessing the Function Definition Parameters database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class FunctionParameterAdapterV1 extends FunctionParameterAdapter {
static final int VERSION = 1;
@@ -45,30 +47,27 @@ class FunctionParameterAdapterV1 extends FunctionParameterAdapter {
/**
* Gets a version 1 adapter for the Function Definition Parameter database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @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 an IO error occurs
*/
- public FunctionParameterAdapterV1(DBHandle handle, boolean create)
+ public FunctionParameterAdapterV1(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + PARAMETER_TABLE_NAME;
if (create) {
- table = handle.createTable(PARAMETER_TABLE_NAME, V1_PARAMETER_SCHEMA,
+ table = handle.createTable(tableName, V1_PARAMETER_SCHEMA,
new int[] { V1_PARAMETER_PARENT_ID_COL });
}
else {
- table = handle.getTable(PARAMETER_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
throw new VersionException(true);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + PARAMETER_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);
+ throw new VersionException(version < VERSION);
}
}
}
@@ -76,12 +75,7 @@ class FunctionParameterAdapterV1 extends FunctionParameterAdapter {
@Override
public DBRecord createRecord(long dataTypeID, long parentID, int ordinal, String name,
String comment, int dtLength) throws IOException {
-
- long tableKey = table.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.PARAMETER, tableKey);
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.PARAMETER, table.getKey());
DBRecord record = V1_PARAMETER_SCHEMA.createRecord(key);
record.setLongValue(V1_PARAMETER_PARENT_ID_COL, parentID);
record.setLongValue(V1_PARAMETER_DT_ID_COL, dataTypeID);
@@ -115,7 +109,7 @@ class FunctionParameterAdapterV1 extends FunctionParameterAdapter {
@Override
protected void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(PARAMETER_TABLE_NAME);
+ handle.deleteTable(table.getName());
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildAdapter.java
index 6b2b8daabb..4a7b69a1a4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildAdapter.java
@@ -21,7 +21,6 @@ import java.util.Set;
import db.DBConstants;
import db.DBHandle;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
/**
*
@@ -31,16 +30,25 @@ import ghidra.util.task.TaskMonitor;
*
*/
abstract class ParentChildAdapter {
- static final String TABLE_NAME = "DT_PARENT_CHILD";
+ static final String PARENT_CHILD_TABLE_NAME = "DT_PARENT_CHILD";
- static ParentChildAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
+ /**
+ * Gets an adapter for working with the function definition parameters database table.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @return the adapter for accessing the table of function definition parameters.
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is trouble accessing the database.
+ */
+ static ParentChildAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
if (openMode == DBConstants.CREATE) {
- return new ParentChildDBAdapterV0(handle, true);
+ return new ParentChildDBAdapterV0(handle, tablePrefix, true);
}
try {
- return new ParentChildDBAdapterV0(handle, false);
+ return new ParentChildDBAdapterV0(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -48,20 +56,20 @@ abstract class ParentChildAdapter {
}
ParentChildAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix);
}
return adapter;
}
}
- static ParentChildAdapter findReadOnlyAdapter(DBHandle handle) {
+ private static ParentChildAdapter findReadOnlyAdapter(DBHandle handle) {
return new ParentChildDBAdapterNoTable(handle);
}
- static ParentChildAdapter upgrade(DBHandle handle, ParentChildAdapter oldAdapter)
- throws VersionException, IOException {
+ private static ParentChildAdapter upgrade(DBHandle handle, ParentChildAdapter oldAdapter,
+ String tablePrefix) throws VersionException, IOException {
- ParentChildDBAdapterV0 adapter = new ParentChildDBAdapterV0(handle, true);
+ ParentChildDBAdapterV0 adapter = new ParentChildDBAdapterV0(handle, tablePrefix, true);
adapter.setNeedsInitializing();
return adapter;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildDBAdapterV0.java
index d2278d3f40..e9f4a22984 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildDBAdapterV0.java
@@ -22,6 +22,11 @@ import java.util.Set;
import db.*;
import ghidra.util.exception.VersionException;
+/**
+ * Version 0 implementation for accessing the datatype parent/child database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
+ */
class ParentChildDBAdapterV0 extends ParentChildAdapter {
private static final int VERSION = 0;
@@ -35,19 +40,28 @@ class ParentChildDBAdapterV0 extends ParentChildAdapter {
private Table table;
private boolean needsInitializing = false;
- ParentChildDBAdapterV0(DBHandle handle, boolean create) throws VersionException, IOException {
-
+ /**
+ * Gets a version 1 adapter for the datatype parent/child database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @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 an IO error occurs
+ */
+ ParentChildDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + PARENT_CHILD_TABLE_NAME;
if (create) {
- table = handle.createTable(TABLE_NAME, V0_SCHEMA, new int[] { PARENT_COL, CHILD_COL });
+ table = handle.createTable(tableName, V0_SCHEMA, new int[] { PARENT_COL, CHILD_COL });
}
else {
- table = handle.getTable(TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
throw new VersionException(true);
}
- if (table.getSchema().getVersion() != 0) {
- throw new VersionException("Expected version 0 for table " + TABLE_NAME +
- " but got " + table.getSchema().getVersion());
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapter.java
index 3d45173f83..95e3f9bfdc 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapter.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -36,14 +37,26 @@ abstract class PointerDBAdapter implements RecordTranslator {
static final int PTR_CATEGORY_COL = 1;
static final int PTR_LENGTH_COL = 2;
- static PointerDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ /**
+ * Gets an adapter for working with the enumeration data type values database table. The adapter is based
+ * on the version of the database associated with the specified database handle and the openMode.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor the monitor to use for displaying status or for canceling.
+ * @return the adapter for accessing the table of enumeration data type values.
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
+ */
+ static PointerDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new PointerDBAdapterV2(handle, true);
+ return new PointerDBAdapterV2(handle, tablePrefix, true);
}
try {
- return new PointerDBAdapterV2(handle, false);
+ return new PointerDBAdapterV2(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -51,7 +64,7 @@ abstract class PointerDBAdapter implements RecordTranslator {
}
PointerDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter, monitor);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -67,22 +80,25 @@ abstract class PointerDBAdapter implements RecordTranslator {
}
static PointerDBAdapter upgrade(DBHandle handle, PointerDBAdapter oldAdapter,
- TaskMonitor monitor) throws VersionException, IOException {
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
PointerDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new PointerDBAdapterV2(tmpHandle, true);
+ tmpAdapter = new PointerDBAdapterV2(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- PointerDBAdapter newAdapter = new PointerDBAdapterV2(handle, true);
+ PointerDBAdapter newAdapter = new PointerDBAdapterV2(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapterV2.java
index 3890b5e22a..ec5a2a82b4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapterV2.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapterV2.java
@@ -20,36 +20,46 @@ import java.io.IOException;
import db.*;
import ghidra.util.exception.VersionException;
+/**
+ * Version 2 implementation for accessing the PointerDB database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
+ */
class PointerDBAdapterV2 extends PointerDBAdapter {
final static int VERSION = 2;
private Table table;
- PointerDBAdapterV2(DBHandle handle, boolean create) throws VersionException, IOException {
-
+ /**
+ * Gets a version 2 adapter for the PointerDB database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @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
+ */
+ PointerDBAdapterV2(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + POINTER_TABLE_NAME;
if (create) {
- table = handle.createTable(POINTER_TABLE_NAME, SCHEMA, new int[] { PTR_CATEGORY_COL });
+ table = handle.createTable(tableName, SCHEMA, new int[] { PTR_CATEGORY_COL });
}
else {
- table = handle.getTable(POINTER_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + POINTER_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- else if (table.getSchema().getVersion() != VERSION) {
- int version = table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(true);
- }
- throw new VersionException(VersionException.NEWER_VERSION, false);
+ int version = table.getSchema().getVersion();
+ if (version != VERSION) {
+ throw new VersionException(version < VERSION);
}
}
}
@Override
DBRecord createRecord(long dataTypeID, long categoryID, int length) throws IOException {
- long tableKey = table.getKey();
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.POINTER, tableKey);
-
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.POINTER, table.getKey());
DBRecord record = SCHEMA.createRecord(key);
record.setLongValue(PTR_DT_ID_COL, dataTypeID);
record.setLongValue(PTR_CATEGORY_COL, categoryID);
@@ -85,7 +95,7 @@ class PointerDBAdapterV2 extends PointerDBAdapter {
@Override
void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(POINTER_TABLE_NAME);
+ handle.deleteTable(table.getName());
}
@Override
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 20cde8ca57..d004105cd5 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
@@ -50,6 +50,9 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
* @param handle open database handle
* @param addrMap the address map (instance settings not supported if null)
* @param openMode the program open mode (see {@link DBConstants})
+ * @param tablePrefix DB table prefix to be applied to all associated table names. This
+ * need only be specified when using multiple instances with the same
+ * DB handle (null or empty string for no-prefix).
* @param errHandler the database io error handler
* @param lock the program synchronization lock
* @param monitor the progress monitor
@@ -57,18 +60,18 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
* @throws VersionException if the database does not match the expected version.
* @throws IOException if a database IO error occurs.
*/
- public ProgramBasedDataTypeManagerDB(DBHandle handle, AddressMap addrMap, int openMode,
- ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
+ protected ProgramBasedDataTypeManagerDB(DBHandle handle, AddressMap addrMap, int openMode,
+ String tablePrefix, ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
throws CancelledException, VersionException, IOException {
- super(handle, addrMap, openMode, errHandler, lock, monitor);
+ super(handle, addrMap, openMode, tablePrefix, errHandler, lock, monitor);
}
protected void initializeOtherAdapters(int openMode, TaskMonitor monitor)
throws CancelledException, IOException, VersionException {
if (addrMap != null) {
instanceSettingsAdapter =
- SettingsDBAdapter.getAdapter(INSTANCE_SETTINGS_TABLE_NAME, dbHandle, openMode,
- addrMap, monitor);
+ SettingsDBAdapter.getAdapter(tablePrefix + INSTANCE_SETTINGS_TABLE_NAME, dbHandle,
+ openMode, addrMap, monitor);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java
index 2db4e3c414..2f73ce80fd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java
@@ -31,8 +31,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ChangeManager;
import ghidra.util.*;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.exception.VersionException;
+import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
@@ -61,7 +60,7 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB
public ProgramDataTypeManager(DBHandle handle, AddressMap addrMap, int openMode,
ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
throws CancelledException, VersionException, IOException {
- super(handle, addrMap, openMode, errHandler, lock, monitor);
+ super(handle, addrMap, openMode, null, errHandler, lock, monitor);
upgrade = (openMode == DBConstants.UPGRADE);
}
@@ -79,8 +78,16 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB
@Override
public void setProgram(ProgramDB p) {
this.program = p;
- dataOrganization = p.getCompilerSpec().getDataOrganization();
- removeOldFileNameList();
+ try {
+ setProgramArchitecture(p, p.getSymbolTable().getVariableStorageManager(), false,
+ TaskMonitor.DUMMY);
+ }
+ catch (CancelledException e) {
+ throw new AssertException(e); // unexpected - no IO performed
+ }
+ catch (IOException e) {
+ errHandler.dbError(e);
+ }
if (upgrade) {
removeOldFileNameList();
}
@@ -102,11 +109,22 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB
public void programReady(int openMode, int currentRevision, TaskMonitor monitor)
throws IOException, CancelledException {
if (openMode == DBConstants.UPGRADE) {
- doSourceArchiveUpdates(program.getCompilerSpec(), monitor);
+ doSourceArchiveUpdates(monitor);
migrateOldFlexArrayComponentsIfRequired(monitor);
}
}
+ /**
+ * Update program-architecture information following a language upgrade/change
+ * @param monitor task monitor
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if task monitor cancelled
+ */
+ public void languageChanged(TaskMonitor monitor) throws IOException, CancelledException {
+ setProgramArchitecture(program, program.getSymbolTable().getVariableStorageManager(), true,
+ monitor);
+ }
+
@Override
public String getName() {
return program.getName();
@@ -296,12 +314,4 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB
return ArchiveType.PROGRAM;
}
- @Override
- public DataOrganization getDataOrganization() {
- if (dataOrganization == null) {
- dataOrganization = program.getCompilerSpec().getDataOrganization();
- }
- return dataOrganization;
- }
-
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapter.java
index debb9cae8c..645ada0f5f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapter.java
@@ -22,6 +22,7 @@ import java.util.List;
import db.*;
import ghidra.program.model.data.SourceArchive;
import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -32,8 +33,10 @@ import ghidra.util.task.TaskMonitor;
*/
abstract class SourceArchiveAdapter {
- static final String TABLE_NAME = "Data Type Archive IDs";
+ static final String SOURCE_ARCHIVE_TABLE_NAME = "Data Type Archive IDs";
+
static final Schema SCHEMA = SourceArchiveAdapterV0.V0_SCHEMA;
+
// Data Type Archive ID Columns
static final int ARCHIVE_ID_DOMAIN_FILE_ID_COL =
SourceArchiveAdapterV0.V0_ARCHIVE_ID_DOMAIN_FILE_ID_COL;
@@ -52,18 +55,20 @@ abstract class SourceArchiveAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of data type archive ID entries.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
- static SourceArchiveAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static SourceArchiveAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new SourceArchiveAdapterV0(handle, true);
+ return new SourceArchiveAdapterV0(handle, tablePrefix, true);
}
try {
- return new SourceArchiveAdapterV0(handle, false);
+ return new SourceArchiveAdapterV0(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -71,7 +76,7 @@ abstract class SourceArchiveAdapter {
}
SourceArchiveAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -83,7 +88,8 @@ abstract class SourceArchiveAdapter {
* @return the read only Data Type Archive ID table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static SourceArchiveAdapter findReadOnlyAdapter(DBHandle handle) {
+ private static SourceArchiveAdapter findReadOnlyAdapter(DBHandle handle)
+ throws VersionException {
return new SourceArchiveAdapterNoTable(handle);
}
@@ -95,24 +101,28 @@ abstract class SourceArchiveAdapter {
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static SourceArchiveAdapter upgrade(DBHandle handle, SourceArchiveAdapter oldAdapter)
- throws VersionException, IOException {
+ private static SourceArchiveAdapter upgrade(DBHandle handle, SourceArchiveAdapter oldAdapter,
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
SourceArchiveAdapter tmpAdapter = null;
try {
- tmpAdapter = new SourceArchiveAdapterV0(tmpHandle, true);
+ tmpAdapter = new SourceArchiveAdapterV0(tmpHandle, tablePrefix, true);
Iterator it = oldAdapter.getRecords().iterator();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- SourceArchiveAdapter newAdapter = new SourceArchiveAdapterV0(handle, true);
+ SourceArchiveAdapter newAdapter = new SourceArchiveAdapterV0(handle, tablePrefix, true);
it = tmpAdapter.getRecords().iterator();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
@@ -125,22 +135,33 @@ abstract class SourceArchiveAdapter {
}
}
+ /**
+ * Delete table from database
+ * @param handle database handle
+ * @throws IOException if IO error occurs
+ */
abstract void deleteTable(DBHandle handle) throws IOException;
/**
* Creates a new source archive record using the information from the given source archive.
* @param sourceArchive the source archive from which to get the archive information.
+ * @return new archive record which corresponds to specified sourceArchive
+ * @throws IOException if IO error occurs
*/
abstract DBRecord createRecord(SourceArchive sourceArchive) throws IOException;
/**
* Returns a list containing all records in the archive table
- * @return
+ * @return list of all archive records
+ * @throws IOException if IO error occurs
*/
abstract List getRecords() throws IOException;
/**
* Returns the record for the given key (sourceArchiveID)
+ * @param key ID of data type archive record
+ * @return archive record or null if not found
+ * @throws IOException if IO error occurs
*/
abstract DBRecord getRecord(long key) throws IOException;
@@ -153,7 +174,7 @@ abstract class SourceArchiveAdapter {
/**
* Remove the record for the given data type archive ID.
- * @param dataTypeArchiveID ID of data type archive record to delete
+ * @param key ID of data type archive record to delete
* @return true if the record was deleted
* @throws IOException if there was a problem accessing the database
*/
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapterV0.java
index f1dd2e7951..906fb60ad3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapterV0.java
@@ -26,6 +26,8 @@ import ghidra.util.exception.VersionException;
/**
* Version 0 implementation for accessing the Data Type Archive ID database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
static final int VERSION = 0;
@@ -45,38 +47,33 @@ class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
/**
* Gets a version 1 adapter for the Data Type Archive ID table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @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 an IO errr occurs
*/
- public SourceArchiveAdapterV0(DBHandle handle, boolean create)
+ public SourceArchiveAdapterV0(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + SOURCE_ARCHIVE_TABLE_NAME;
if (create) {
- table = handle.createTable(TABLE_NAME, V0_SCHEMA);
-
+ table = handle.createTable(tableName, V0_SCHEMA);
createRecordForLocalManager();
}
else {
- table = handle.getTable(TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
throw new VersionException(true);
}
- int version = table.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + 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);
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
/**
- *
- * @throws IOException
+ * Create standard entry which corresponds to local datatype manager
+ * @throws IOException if an IO error occurs
*/
private void createRecordForLocalManager() throws IOException {
DBRecord record = V0_SCHEMA.createRecord(DataTypeManager.LOCAL_ARCHIVE_KEY);
@@ -129,6 +126,7 @@ class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
@Override
protected void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(table.getName());
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveUpgradeMap.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveUpgradeMap.java
index 3b59b71c03..745a69d886 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveUpgradeMap.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveUpgradeMap.java
@@ -19,7 +19,6 @@ import java.util.HashMap;
import java.util.Map;
import ghidra.program.model.data.*;
-import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.CompilerSpecID;
import ghidra.util.UniversalID;
@@ -31,8 +30,8 @@ public class SourceArchiveUpgradeMap {
new long[] { OLD_CLIB_ARCHIVE_ID, OLD_NTDDK_ARCHIVE_ID, OLD_WINDOWS_ARCHIVE_ID };
private CompilerSpecID WINDOWS_CSPEC_ID = new CompilerSpecID("windows");
- private Map windowsMap;
- private Map defaultMap;
+
+ private Map oldArchiveRemappings;
public SourceArchiveUpgradeMap() {
@@ -47,34 +46,25 @@ public class SourceArchiveUpgradeMap {
SourceArchive newDefaultClibArchive =
new SourceArchiveImpl(NEW_DEFAULT_CLIB_ARCHIVE_ID, NEW_DEFAULT_CLIB_ARCHIVE_NAME);
- // create mapping for WINDOWS
- windowsMap = new HashMap();
- windowsMap.put(new UniversalID(OLD_CLIB_ARCHIVE_ID), newWindowsArchive);
- windowsMap.put(new UniversalID(OLD_WINDOWS_ARCHIVE_ID), newWindowsArchive);
- windowsMap.put(new UniversalID(OLD_NTDDK_ARCHIVE_ID), newWindowsArchive);
+ oldArchiveRemappings = new HashMap();
- // create defaultMap
- defaultMap = new HashMap();
- defaultMap.put(new UniversalID(OLD_CLIB_ARCHIVE_ID), newDefaultClibArchive);
+ // create mappings for old Windows archives
+ oldArchiveRemappings.put(new UniversalID(OLD_CLIB_ARCHIVE_ID), newWindowsArchive);
+ oldArchiveRemappings.put(new UniversalID(OLD_WINDOWS_ARCHIVE_ID), newWindowsArchive);
+ oldArchiveRemappings.put(new UniversalID(OLD_NTDDK_ARCHIVE_ID), newWindowsArchive);
+
+ // create mappings for old default archives
+ oldArchiveRemappings.put(new UniversalID(OLD_CLIB_ARCHIVE_ID), newDefaultClibArchive);
+
+ // create mappings for old removed archives
SourceArchive removedSourceArchive = new SourceArchiveImpl();
- defaultMap.put(new UniversalID(OLD_WINDOWS_ARCHIVE_ID), removedSourceArchive);
- defaultMap.put(new UniversalID(OLD_NTDDK_ARCHIVE_ID), removedSourceArchive);
+ oldArchiveRemappings.put(new UniversalID(OLD_WINDOWS_ARCHIVE_ID), removedSourceArchive);
+ oldArchiveRemappings.put(new UniversalID(OLD_NTDDK_ARCHIVE_ID), removedSourceArchive);
}
- public SourceArchive getMappedSourceArchive(SourceArchive sourceArchive,
- CompilerSpec compiler) {
- if (compiler != null) {
- CompilerSpecID compilerSpecID = compiler.getCompilerSpecID();
- if (WINDOWS_CSPEC_ID.equals(compilerSpecID)) {
- SourceArchive replacementSourceArchive =
- windowsMap.get(sourceArchive.getSourceArchiveID());
- if (replacementSourceArchive != null) {
- return replacementSourceArchive;
- }
- }
- }
- return defaultMap.get(sourceArchive.getSourceArchiveID());
+ public SourceArchive getMappedSourceArchive(SourceArchive sourceArchive) {
+ return oldArchiveRemappings.get(sourceArchive.getSourceArchiveID());
}
public static boolean isReplacedSourceArchive(long id) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java
index 6fbbece0c1..19987ba5ac 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java
@@ -376,7 +376,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
componentName, comment);
}
- // handle aligned bitfield insertion
+ // handle aligned bitfield insertion (packing enabled)
BitFieldDataType bitFieldDt = new BitFieldDBDataType(baseDataType, bitSize, 0);
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
}
@@ -1860,7 +1860,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
@Override
protected void fixupComponents() throws IOException {
boolean isPacked = isPackingEnabled();
- boolean didChange = false;
+ boolean forceRepack = false;
+ boolean changed = false;
boolean warn = false;
int n = components.size();
for (int i = 0; i < n; i++) {
@@ -1870,7 +1871,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
continue; // length can't change
}
if (dt instanceof BitFieldDataType) {
- // TODO: could get messy
+ // Always repack if bitfields present and packing enabled
+ forceRepack |= isPacked;
continue;
}
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength();
@@ -1881,18 +1883,18 @@ class StructureDB extends CompositeDB implements StructureInternal {
if (dtcLen != length) {
if (isPacked) {
dtc.setLength(length, true);
- didChange = true;
+ changed = true;
}
else if (length < dtcLen) {
dtc.setLength(length, true);
shiftOffsets(i + 1, dtcLen - length, 0); // updates structure record and last modified time
- didChange = true;
+ changed = true;
}
else if (length > dtcLen) {
int consumed = consumeBytesAfter(i, length - dtcLen); // updates component record
if (consumed > 0) {
shiftOffsets(i + 1, -consumed, 0); // updates structure record and last modified time
- didChange = true;
+ changed = true;
}
}
if (dtc.getLength() != length) {
@@ -1900,11 +1902,14 @@ class StructureDB extends CompositeDB implements StructureInternal {
}
}
}
- if (didChange) {
+ if (changed || forceRepack) {
// Do not notify parents - must be invoked in composite dependency order
- repack(false, false);
- compositeAdapter.updateRecord(record, true);
- dataMgr.dataTypeChanged(this, false);
+ // Treat as an auto-change as a result of data organization change
+ changed |= repack(true, false);
+ }
+ if (changed) {
+ compositeAdapter.updateRecord(record, false); // force record update
+ dataMgr.dataTypeChanged(this, true);
}
if (warn) {
Msg.warn(this, "Failed to resize one or more structure components: " + getPathName());
@@ -2238,10 +2243,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
checkAncestry(replacementDt);
}
catch (Exception e) {
- // TODO: should we use Undefined1 instead to avoid cases where DEFAULT datatype can
- // not be used (bitfield, aligned structure, etc.)
- // TODO: failing silently is rather hidden
- replacementDt = DataType.DEFAULT;
+ // TODO: should we flag bad replacement
+ replacementDt = isPackingEnabled() ? Undefined1DataType.dataType : DataType.DEFAULT;
}
boolean changed = false;
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 a2746aa88a..f8a07fd032 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
@@ -19,6 +19,7 @@ import java.io.IOException;
import db.*;
import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -51,15 +52,18 @@ abstract class TypedefDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of Typedef data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
- static TypedefDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static TypedefDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
try {
- return new TypedefDBAdapterV2(handle, openMode == DBConstants.CREATE);
+ return new TypedefDBAdapterV2(handle, tablePrefix, openMode == DBConstants.CREATE);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -67,7 +71,7 @@ abstract class TypedefDBAdapter {
}
TypedefDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -79,7 +83,7 @@ abstract class TypedefDBAdapter {
* @return the read only Typedef table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static TypedefDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
+ private static TypedefDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
try {
return new TypedefDBAdapterV1(handle);
}
@@ -93,28 +97,34 @@ abstract class TypedefDBAdapter {
* Upgrades the Typedef data type table from the oldAdapter's version to the current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static TypedefDBAdapter upgrade(DBHandle handle, TypedefDBAdapter oldAdapter)
- throws VersionException, IOException {
+ private static TypedefDBAdapter upgrade(DBHandle handle, TypedefDBAdapter oldAdapter,
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
TypedefDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new TypedefDBAdapterV2(tmpHandle, true);
+ tmpAdapter = new TypedefDBAdapterV2(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
- TypedefDBAdapter newAdapter = new TypedefDBAdapterV2(handle, true);
+ TypedefDBAdapter newAdapter = new TypedefDBAdapterV2(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec, false);
}
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 6eaa2a2d3c..3bbac383f5 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
@@ -28,15 +28,19 @@ import ghidra.util.exception.VersionException;
* Version 0 implementation for accessing the Typedef database table.
*/
class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
+
static final int VERSION = 0;
+
private static final int V0_TYPEDEF_DT_ID_COL = 0;
private static final int V0_TYPEDEF_NAME_COL = 1;
private static final int V0_TYPEDEF_CAT_COL = 2;
+
// DO NOT REMOVE WHAT'S BELOW - this documents the schema used in version 0.
// static final Schema V0_SCHEMA = new Schema(VERSION, "Typedef ID",
// new Class[] {LongField.class, StringField.class,
// LongField.class},
// new String[] {"Data Type ID", "Name", "Category ID"});
+
private Table table;
/**
@@ -51,14 +55,8 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
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);
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
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 d89c386594..dde15e7e51 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
@@ -25,7 +25,9 @@ import ghidra.util.exception.VersionException;
* Version 1 implementation for accessing the Typedef database table.
*/
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;
static final int V1_TYPEDEF_CAT_COL = 2;
@@ -40,6 +42,7 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter implements RecordTranslator {
// 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;
/**
@@ -56,12 +59,7 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter implements RecordTranslator {
}
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);
+ throw new VersionException(version < VERSION);
}
}
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
index 39226fa23d..d67dd66eb5 100644
--- 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
@@ -24,9 +24,13 @@ import ghidra.util.exception.VersionException;
/**
* Version 2 implementation for accessing the Typedef database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
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;
@@ -35,61 +39,53 @@ class TypedefDBAdapterV2 extends TypedefDBAdapter {
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 tablePrefix prefix to be used with default table name
* @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)
+ public TypedefDBAdapterV2(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + TYPEDEF_TABLE_NAME;
if (create) {
- table = handle.createTable(TYPEDEF_TABLE_NAME, V2_SCHEMA,
+ table = handle.createTable(tableName, V2_SCHEMA,
new int[] { V2_TYPEDEF_CAT_COL, V2_TYPEDEF_UNIVERSAL_DT_ID_COL });
}
else {
- table = handle.getTable(TYPEDEF_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
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);
+ throw new VersionException(version < VERSION);
}
}
}
@Override
void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(TYPEDEF_TABLE_NAME);
+ handle.deleteTable(table.getName());
}
@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);
-
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, table.getKey());
DBRecord record = V2_SCHEMA.createRecord(key);
record.setLongValue(V2_TYPEDEF_DT_ID_COL, dataTypeID);
record.setShortValue(V2_TYPEDEF_FLAGS_COL, flags);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java
index dd8869a237..3072a52070 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java
@@ -497,12 +497,10 @@ class UnionDB extends CompositeDB implements UnionInternal {
}
}
if (changed) {
- // NOTE: since we do not retain our external alignment we have no way of knowing if
- // it has changed, so we must assume it has if we are an aligned union
- // Do not notify parents
- if (!repack(false, false)) {
- dataMgr.dataTypeChanged(this, false);
- }
+ // Do not notify parents - must be invoked in composite dependency order
+ // Treat as an auto-change as a result of data organization change
+ repack(true, false);
+ dataMgr.dataTypeChanged(this, true);
}
}
@@ -562,8 +560,8 @@ class UnionDB extends CompositeDB implements UnionInternal {
DataType baseDataType = bitfieldDt.getBaseDataType();
baseDataType = resolve(baseDataType);
- // Both aligned and non-packed bitfields use same adjustment
- // non-packed must force bitfield placement at byte offset 0
+ // Both packed and non-packed bitfields use same adjustment
+ // Non-packed must force bitfield placement at byte offset 0
int bitSize = bitfieldDt.getDeclaredBitSize();
int effectiveBitSize =
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
@@ -795,9 +793,8 @@ class UnionDB extends CompositeDB implements UnionInternal {
checkAncestry(replacementDt);
}
catch (Exception e) {
- // TODO: should we use Undefined instead since we do not support
- // DEFAULT in Unions
- replacementDt = DataType.DEFAULT;
+ // TODO: should we flag bad replacement
+ replacementDt = Undefined1DataType.dataType;
}
boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapter.java
deleted file mode 100644
index 0c7bcc1e45..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapter.java
+++ /dev/null
@@ -1,79 +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.database.function;
-
-import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
-
-import java.io.IOException;
-
-import db.*;
-
-/**
- * Adapter to access the Function Calling Conventions tables.
- */
-abstract class CallingConventionDBAdapter {
- static final byte UNKNOWN_CALLING_CONVENTION_ID = (byte) 0;
- static final byte DEFAULT_CALLING_CONVENTION_ID = (byte) 1;
-
- static final Schema CALLING_CONVENTION_SCHEMA =
- CallingConventionDBAdapterV0.V0_CALLING_CONVENTION_SCHEMA;
- // Calling Convention Columns
- static final int CALLING_CONVENTION_NAME_COL =
- CallingConventionDBAdapterV0.V0_CALLING_CONVENTION_NAME_COL;
-
- static CallingConventionDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
- if (openMode == DBConstants.CREATE) {
- return new CallingConventionDBAdapterV0(handle, true);
- }
- try {
- return new CallingConventionDBAdapterV0(handle, false);
- }
- catch (VersionException e) {
- if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
- throw e;
- }
- CallingConventionDBAdapter adapter = findReadOnlyAdapter(handle);
- if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
- }
- return adapter;
- }
- }
-
- static CallingConventionDBAdapter findReadOnlyAdapter(DBHandle handle) throws IOException {
- try {
- return new CallingConventionDBAdapterV0(handle, false);
- }
- catch (VersionException e) {
- }
-
- return new CallingConventionDBAdapterNoTable();
- }
-
- static CallingConventionDBAdapter upgrade(DBHandle handle, CallingConventionDBAdapter oldAdapter)
- throws VersionException, IOException {
- return new CallingConventionDBAdapterV0(handle, true);
- }
-
- abstract DBRecord createCallingConventionRecord(String name) throws IOException;
-
- abstract DBRecord getCallingConventionRecord(byte callingConventionID) throws IOException;
-
- abstract DBRecord getCallingConventionRecord(String name) throws IOException;
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterNoTable.java
deleted file mode 100644
index ac7033ef0e..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterNoTable.java
+++ /dev/null
@@ -1,59 +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.database.function;
-
-import java.io.IOException;
-
-import db.DBRecord;
-
-/**
- * Adapter needed for a read-only version of Program that is not going
- * to be upgraded, and there is no Calling Convention table in the Program.
- *
- */
-class CallingConventionDBAdapterNoTable extends CallingConventionDBAdapter {
-
- /**
- *
- */
- public CallingConventionDBAdapterNoTable() {
- }
-
- /* (non-Javadoc)
- * @see ghidra.program.database.function.CallingConventionDBAdapter#createCallingConventionRecord(java.lang.String)
- */
- @Override
- public DBRecord createCallingConventionRecord(String name) throws IOException {
- return null;
- }
-
- /* (non-Javadoc)
- * @see ghidra.program.database.function.CallingConventionDBAdapter#getCallingConventionRecord(byte)
- */
- @Override
- public DBRecord getCallingConventionRecord(byte callingConventionID) throws IOException {
- return null;
- }
-
- /* (non-Javadoc)
- * @see ghidra.program.database.function.CallingConventionDBAdapter#getCallingConventionRecord(java.lang.String)
- */
- @Override
- public DBRecord getCallingConventionRecord(String name) throws IOException {
- return null;
- }
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterV0.java
deleted file mode 100644
index 8e9f9e2942..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterV0.java
+++ /dev/null
@@ -1,109 +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.database.function;
-
-import java.io.IOException;
-
-import db.*;
-import ghidra.util.exception.VersionException;
-
-/**
- * Version 0 implementation for the calling conventions tables adapter.
- *
- */
-class CallingConventionDBAdapterV0 extends CallingConventionDBAdapter {
-
- static final String CALLING_CONVENTION_TABLE_NAME = "Calling Conventions";
-
- // Calling Convention Columns
- // Key field is the Calling convention ID, which is a Byte field.
- static final int V0_CALLING_CONVENTION_NAME_COL = 0;
-
- static final Schema V0_CALLING_CONVENTION_SCHEMA = new Schema(0, ByteField.INSTANCE, "ID",
- new Field[] { StringField.INSTANCE }, new String[] { "Name" });
-
- private Table callingConventionTable;
-
- /**
- * Constructor
- *
- */
- public CallingConventionDBAdapterV0(DBHandle handle, boolean create)
- throws VersionException, IOException {
-
- if (create) {
- // No additional indexed fields.
- callingConventionTable = handle.createTable(CALLING_CONVENTION_TABLE_NAME,
- V0_CALLING_CONVENTION_SCHEMA, new int[] {});
- }
- else {
- callingConventionTable = handle.getTable(CALLING_CONVENTION_TABLE_NAME);
- if (callingConventionTable == null) {
- throw new VersionException(true);
- }
- if (callingConventionTable.getSchema().getVersion() != 0) {
- throw new VersionException(VersionException.NEWER_VERSION, false);
- }
- }
- }
-
- @Override
- public DBRecord createCallingConventionRecord(String name) throws IOException {
- byte key = getFirstAvailableKey();
- DBRecord record = V0_CALLING_CONVENTION_SCHEMA.createRecord(new ByteField(key));
- record.setString(V0_CALLING_CONVENTION_NAME_COL, name);
- callingConventionTable.putRecord(record);
- return record;
- }
-
- /**
- * Get the first unused key value. Remember 0 is reserved for unknown and 1 for default.
- * @return the first available key. This is a number for 2 to 255.
- * @throws IOException if there are no more available keys.
- */
- private byte getFirstAvailableKey() throws IOException {
- byte key = 2;
- for (; key < 256; key++) {
- DBRecord record = getCallingConventionRecord(key);
- if (record == null) {
- return key;
- }
- }
- if (key >= 256) {
- throw new IOException("No more keys available for calling conventions.");
- }
- return key;
- }
-
- @Override
- public DBRecord getCallingConventionRecord(byte callingConventionID) throws IOException {
- return callingConventionTable.getRecord(new ByteField(callingConventionID));
- }
-
- @Override
- public DBRecord getCallingConventionRecord(String name) throws IOException {
- RecordIterator iterator = callingConventionTable.iterator();
- while (iterator.hasNext()) {
- DBRecord record = iterator.next();
- String callingConventionName = record.getString(V0_CALLING_CONVENTION_NAME_COL);
- if (callingConventionName.equals(name)) {
- return record;
- }
- }
- return null;
- }
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapterV3.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapterV3.java
index 0d64b65a70..f45946f00b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapterV3.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapterV3.java
@@ -15,15 +15,15 @@
*/
package ghidra.program.database.function;
+import java.io.IOException;
+
+import db.*;
+import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.database.map.AddressMap;
import ghidra.program.model.listing.Function;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.VersionException;
-import java.io.IOException;
-
-import db.*;
-
class FunctionAdapterV3 extends FunctionAdapter {
//
@@ -116,7 +116,7 @@ class FunctionAdapterV3 extends FunctionAdapter {
rec.setByteValue(FUNCTION_FLAGS_COL, getSignatureSourceFlagBits(SourceType.DEFAULT));
rec.setLongValue(RETURN_DATA_TYPE_ID_COL, returnDataTypeId);
rec.setByteValue(CALLING_CONVENTION_ID_COL,
- CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID);
+ DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID);
rec.setIntValue(STACK_PURGE_COL, Function.UNKNOWN_STACK_DEPTH_CHANGE);
table.putRecord(rec);
return rec;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
index fa60100546..5cf78369dc 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
@@ -229,11 +229,6 @@ public class FunctionDB extends DatabaseObject implements Function {
return super.hashCode();
}
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Object#toString()
- */
@Override
public String toString() {
return getName(true);
@@ -826,7 +821,7 @@ public class FunctionDB extends DatabaseObject implements Function {
PrototypeModel callingConvention = getCallingConvention();
if (callingConvention == null) {
- callingConvention = getDefaultCallingConvention();
+ callingConvention = manager.getDefaultCallingConvention();
}
if (callingConvention == null) {
return;
@@ -1310,6 +1305,7 @@ public class FunctionDB extends DatabaseObject implements Function {
source);
}
+
/**
* Increment updateInProgressCount indicating that an update operation is in progress and
* that any attempted refresh should be deferred. The updateRefreshReqd flag will be set
@@ -2517,11 +2513,6 @@ public class FunctionDB extends DatabaseObject implements Function {
}
}
- /*
- * (non-Javadoc)
- *
- * @see ghidra.program.model.listing.Function#getCallingConvention()
- */
@Override
public PrototypeModel getCallingConvention() {
String name = getCallingConventionName();
@@ -2535,11 +2526,6 @@ public class FunctionDB extends DatabaseObject implements Function {
return functionMgr.getCallingConvention(name);
}
- /*
- * (non-Javadoc)
- *
- * @see ghidra.program.model.listing.Function#getCallingConventionName()
- */
@Override
public String getCallingConventionName() {
manager.lock.acquire();
@@ -2551,14 +2537,13 @@ public class FunctionDB extends DatabaseObject implements Function {
return thunkedFunction.getCallingConventionName();
}
byte callingConventionID = rec.getByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL);
- if (callingConventionID == CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID) {
+ if (callingConventionID == DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID) {
return Function.UNKNOWN_CALLING_CONVENTION_STRING;
}
- if (callingConventionID == CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID) {
+ if (callingConventionID == DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID) {
return Function.DEFAULT_CALLING_CONVENTION_STRING;
}
- String name = manager.getCallingConventionName(callingConventionID);
- return name != null ? name : UNKNOWN_CALLING_CONVENTION_STRING;
+ return program.getDataTypeManager().getCallingConventionName(callingConventionID);
}
finally {
manager.lock.release();
@@ -2569,36 +2554,16 @@ public class FunctionDB extends DatabaseObject implements Function {
if (thunkedFunction != null) {
return thunkedFunction.getRealCallingConventionName();
}
- String name = null;
byte callingConventionID = rec.getByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL);
- if (callingConventionID != CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID &&
- callingConventionID != CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID) {
- name = manager.getCallingConventionName(callingConventionID);
+ String name = program.getDataTypeManager().getCallingConventionName(callingConventionID);
+ if (UNKNOWN_CALLING_CONVENTION_STRING.equals(name) ||
+ DEFAULT_CALLING_CONVENTION_STRING.equals(name)) {
+ name = null;
}
// null returned for unknown or default calling convention
return name;
}
- private PrototypeModel getDefaultCallingConvention() {
- CompilerSpec compilerSpec = getProgram().getCompilerSpec();
- if (compilerSpec != null) {
- return compilerSpec.getDefaultCallingConvention();
- }
- return null;
- }
-
- @Override
- public String getDefaultCallingConventionName() {
- PrototypeModel defaultPrototype = getDefaultCallingConvention();
- if (defaultPrototype != null) {
- String defaultPrototypeName = defaultPrototype.getName();
- if (defaultPrototypeName != null) {
- return defaultPrototypeName;
- }
- }
- return Function.DEFAULT_CALLING_CONVENTION_STRING;
- }
-
@Override
public void setCallingConvention(String name) throws InvalidInputException {
manager.lock.acquire();
@@ -2610,36 +2575,38 @@ public class FunctionDB extends DatabaseObject implements Function {
return;
}
- byte newCallingConventionID = manager.getCallingConventionID(name);
+ byte newCallingConventionID =
+ program.getDataTypeManager().getCallingConventionID(name, true);
byte oldCallingConventionID =
rec.getByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL);
- if (oldCallingConventionID != newCallingConventionID) {
+ if (oldCallingConventionID == newCallingConventionID) {
+ return; // no change
+ }
+ loadVariables();
+
+ rec.setByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL, newCallingConventionID);
+ manager.getFunctionAdapter().updateFunctionRecord(rec);
+
+ boolean hasCustomStorage = hasCustomVariableStorage();
+ if (!hasCustomStorage) {
+ // remove 'this' param if switching to __thiscall with dynamic storage
+ removeExplicitThisParameter();
+ }
+
+ frame.setInvalid();
+
+ if (!hasCustomStorage) {
+ createClassStructIfNeeded(); // TODO: How should thunks within Class namespace be handled?
loadVariables();
-
- rec.setByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL, newCallingConventionID);
- manager.getFunctionAdapter().updateFunctionRecord(rec);
-
- boolean hasCustomStorage = hasCustomVariableStorage();
- if (!hasCustomStorage) {
- // remove 'this' param if switching to __thiscall with dynamic storage
- removeExplicitThisParameter();
- }
-
- frame.setInvalid();
-
- if (!hasCustomStorage) {
- createClassStructIfNeeded(); // TODO: How should thunks within Class namespace be handled?
- loadVariables();
- removeExplicitThisParameter();
- updateParametersAndReturn(); // assign dynamic storage
- manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS);
- manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_RETURN);
- }
- else {
- manager.functionChanged(this, 0); // change did not affect parameters
- }
+ removeExplicitThisParameter();
+ updateParametersAndReturn(); // assign dynamic storage
+ manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS);
+ manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_RETURN);
+ }
+ else {
+ manager.functionChanged(this, 0); // change did not affect parameters
}
}
catch (IOException e) {
@@ -2654,7 +2621,7 @@ public class FunctionDB extends DatabaseObject implements Function {
void createClassStructIfNeeded() {
PrototypeModel callingConvention = getCallingConvention();
if (callingConvention == null ||
- callingConvention.getGenericCallingConvention() != GenericCallingConvention.thiscall) {
+ !CompilerSpec.CALLING_CONVENTION_thiscall.equals(callingConvention.getName())) {
return;
}
Namespace parent = getParentNamespace();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java
index 24053a6151..72eb40c7a4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java
@@ -26,6 +26,7 @@ import generic.FilteredIterator;
import ghidra.program.database.DBObjectCache;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.code.CodeManager;
+import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.database.external.ExternalLocationDB;
import ghidra.program.database.map.AddressMap;
import ghidra.program.database.symbol.*;
@@ -60,12 +61,10 @@ public class FunctionManagerDB implements FunctionManager {
private DBObjectCache cache;
private FunctionAdapter adapter;
private ThunkFunctionAdapter thunkAdapter;
- private CallingConventionDBAdapter callingConventionAdapter;
- private Map callingConventionNameToIDMap = new HashMap<>();
- private Map callingConventionIDToNameMap = new HashMap<>();
private NamespaceManager namespaceMgr;
private SymbolManager symbolMgr;
private CodeManager codeMgr;
+ private DataTypeManagerDB dtMgr;
private FunctionTagManagerDB functionTagManager;
private Namespace globalNamespace;
@@ -125,8 +124,6 @@ public class FunctionManagerDB implements FunctionManager {
}
adapter = FunctionAdapter.getAdapter(dbHandle, openMode, addrMap, monitor);
thunkAdapter = ThunkFunctionAdapter.getAdapter(dbHandle, openMode, addrMap, monitor);
- callingConventionAdapter =
- CallingConventionDBAdapter.getAdapter(dbHandle, openMode, monitor);
}
@Override
@@ -138,136 +135,21 @@ public class FunctionManagerDB implements FunctionManager {
return adapter;
}
- /**
- * Get calling convention name corresponding to existing ID. If id is no longer valid,
- * null will be returned.
- * @param id
- * @return
- */
- String getCallingConventionName(byte id) {
- if (id == CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID) {
- return Function.DEFAULT_CALLING_CONVENTION_STRING;
- }
- else if (id == CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID) {
- return null;
- }
- String name = callingConventionIDToNameMap.get(id);
- if (name != null) {
- return name;
- }
- try {
- DBRecord record = callingConventionAdapter.getCallingConventionRecord(id);
- if (record == null) {
- return null;
- }
-
- name = record.getString(CallingConventionDBAdapter.CALLING_CONVENTION_NAME_COL);
- CompilerSpec compilerSpec = program.getCompilerSpec();
- PrototypeModel callingConvention = compilerSpec.getCallingConvention(name);
- if (callingConvention != null) {
- callingConventionIDToNameMap.put(id, name);
- callingConventionNameToIDMap.put(name, id);
- return name;
- }
- }
- catch (IOException e) {
- dbError(e);
- }
- return null;
- }
-
- /**
- * Get (and assign if needed) the ID associated with the specified calling convention name.
- * @param name calling convention name
- * @return calling convention ID
- * @throws IOException
- * @throws InvalidInputException
- */
- byte getCallingConventionID(String name) throws InvalidInputException, IOException {
- if (name == null || name.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
- return CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID;
- }
- else if (name.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
- return CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID;
- }
- Byte id = callingConventionNameToIDMap.get(name);
- if (id != null) {
- return id;
- }
- CompilerSpec compilerSpec = program.getCompilerSpec();
- PrototypeModel callingConvention = compilerSpec.getCallingConvention(name);
- if (callingConvention == null) {
- throw new InvalidInputException("Invalid calling convention name: " + name);
- }
- DBRecord record = callingConventionAdapter.getCallingConventionRecord(name);
- if (record == null) {
- record = callingConventionAdapter.createCallingConventionRecord(name);
- }
- byte newId = record.getKeyField().getByteValue();
- callingConventionIDToNameMap.put(newId, name);
- callingConventionNameToIDMap.put(name, newId);
- return newId;
- }
-
@Override
- public List getCallingConventionNames() {
- CompilerSpec compilerSpec = program.getCompilerSpec();
- PrototypeModel[] namedCallingConventions = compilerSpec.getCallingConventions();
- List names = new ArrayList<>(namedCallingConventions.length + 2);
- names.add(Function.UNKNOWN_CALLING_CONVENTION_STRING);
- names.add(Function.DEFAULT_CALLING_CONVENTION_STRING);
- for (PrototypeModel model : namedCallingConventions) {
- names.add(model.getName());
- }
- return names;
+ public Collection getCallingConventionNames() {
+ return dtMgr.getDefinedCallingConventionNames();
}
@Override
public PrototypeModel getDefaultCallingConvention() {
CompilerSpec compilerSpec = program.getCompilerSpec();
- if (compilerSpec == null) {
- return null;
- }
return compilerSpec.getDefaultCallingConvention();
}
@Override
public PrototypeModel getCallingConvention(String name) {
CompilerSpec compilerSpec = program.getCompilerSpec();
- if (compilerSpec == null) {
- return null;
- }
- if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
- return null;
- }
- if (Function.DEFAULT_CALLING_CONVENTION_STRING.equals(name)) {
- return getDefaultCallingConvention();
- }
- PrototypeModel[] models = compilerSpec.getCallingConventions();
- for (PrototypeModel model : models) {
- String modelName = model.getName();
- if (modelName != null && modelName.equals(name)) {
- return model;
- }
- }
- return null;
- }
-
- @Override
- public PrototypeModel[] getCallingConventions() {
- CompilerSpec compilerSpec = program.getCompilerSpec();
- if (compilerSpec == null) {
- return new PrototypeModel[0];
- }
- ArrayList namedList = new ArrayList<>();
- PrototypeModel[] models = compilerSpec.getCallingConventions();
- for (PrototypeModel model : models) {
- String name = model.getName();
- if (name != null && name.length() > 0) {
- namedList.add(model);
- }
- }
- return namedList.toArray(new PrototypeModel[namedList.size()]);
+ return compilerSpec.getCallingConvention(name);
}
/**
@@ -751,7 +633,8 @@ public class FunctionManagerDB implements FunctionManager {
this.program = program;
namespaceMgr = program.getNamespaceManager();
codeMgr = program.getCodeManager();
- symbolMgr = (SymbolManager) program.getSymbolTable();
+ dtMgr = program.getDataTypeManager();
+ symbolMgr = program.getSymbolTable();
globalNamespace = program.getGlobalNamespace();
functionTagManager.setProgram(program);
}
@@ -935,8 +818,6 @@ public class FunctionManagerDB implements FunctionManager {
callFixupMap = null;
lastFuncID = -1;
cache.invalidate();
- callingConventionIDToNameMap.clear();
- callingConventionNameToIDMap.clear();
}
finally {
lock.release();
@@ -1037,9 +918,8 @@ public class FunctionManagerDB implements FunctionManager {
}
/**
- * Construct a function iterator over all functions residing in memory starting from the specified
- * entry point address.
- * @param start starting address for iteration
+ * Construct a function iterator over all functions residing in specified address set.
+ * @param addrSet address set over which to iterate
* @param forward if true iterate forward from start, otherwise iterate in reverse
*/
FunctionIteratorDB(AddressSetView addrSet, boolean forward) {
@@ -1096,9 +976,6 @@ public class FunctionManagerDB implements FunctionManager {
return list.iterator();
}
- /**
- * Set the new body for the function.
- */
void setFunctionBody(FunctionDB function, AddressSetView newBody)
throws OverlappingFunctionException {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java
index 5fa6301a53..61aa942f18 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java
@@ -24,6 +24,7 @@ import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import db.*;
+import db.util.ErrorHandler;
import ghidra.program.database.*;
import ghidra.program.database.code.CodeManager;
import ghidra.program.database.external.ExternalManagerDB;
@@ -63,6 +64,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
private LabelHistoryAdapter historyAdapter;
private DBObjectCache cache;
+ private ErrorHandler errHandler;
private ProgramDB program;
private ReferenceDBManager refManager;
private NamespaceManager namespaceMgr;
@@ -81,22 +83,26 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* @param handle the database handler
* @param addrMap the address map.
* @param openMode the open mode.
+ * @param errHandler database error handler
* @param lock the program synchronization lock
* @param monitor the progress monitor used when upgrading.
* @throws CancelledException if the user cancels the upgrade.
* @throws IOException if a database io error occurs.
* @throws VersionException if the database version doesn't match the current version.
*/
- public SymbolManager(DBHandle handle, AddressMap addrMap, int openMode, Lock lock,
- TaskMonitor monitor) throws CancelledException, IOException, VersionException {
+ public SymbolManager(DBHandle handle, AddressMap addrMap, int openMode, ErrorHandler errHandler,
+ Lock lock, TaskMonitor monitor)
+ throws CancelledException, IOException, VersionException {
this.addrMap = addrMap;
+ this.errHandler = errHandler;
this.lock = lock;
dynamicSymbolAddressMap = new AddressMapImpl((byte) 0x40, addrMap.getAddressFactory());
initializeAdapters(handle, openMode, monitor);
cache = new DBObjectCache<>(100);
- variableStorageMgr = new VariableStorageManagerDB(handle, addrMap, openMode, lock, monitor);
+ variableStorageMgr =
+ new VariableStorageManagerDB(handle, addrMap, openMode, errHandler, lock, monitor);
if (openMode == DBConstants.UPGRADE &&
OldVariableStorageManagerDB.isOldVariableStorageManagerUpgradeRequired(handle)) {
@@ -140,7 +146,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
this.program = program;
refManager = program.getReferenceManager();
namespaceMgr = program.getNamespaceManager();
- variableStorageMgr.setProgram(program);
+ variableStorageMgr.setProgramArchitecture(program);
}
@Override
@@ -177,6 +183,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
}
+ /**
+ * Get the variable storage manager used by this symbol table
+ * @return varable storage manager
+ */
+ public VariableStorageManager getVariableStorageManager() {
+ return variableStorageMgr;
+ }
+
/**
* Check for and upgrade old namespace symbol addresses which included a namespace ID.
*
@@ -1579,7 +1593,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
void dbError(IOException e) {
- program.dbError(e);
+ errHandler.dbError(e);
}
void validateSource(String name, Address address, SymbolType symbolType, SourceType source) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapter.java
index 273eaa1943..f6a179343b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapter.java
@@ -39,6 +39,7 @@ abstract class VariableStorageDBAdapter {
* @param openMode the openmode
* @param addrMap the address map
* @param monitor the progress monitor.
+ * @return variable storage table adapter
* @throws VersionException if the database table does not match the adapter.
* @throws CancelledException if the user cancels an upgrade.
* @throws IOException if a database io error occurs.
@@ -95,4 +96,6 @@ abstract class VariableStorageDBAdapter {
abstract int getRecordCount();
+ abstract void deleteTable() throws IOException;
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterNoTable.java
index 3440fdbd6f..451f8f1876 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterNoTable.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterNoTable.java
@@ -60,4 +60,9 @@ public class VariableStorageDBAdapterNoTable extends VariableStorageDBAdapter {
int getRecordCount() {
return 0;
}
+
+ @Override
+ void deleteTable() {
+ // do nothing
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterV2.java
index 0314bdac08..0980897408 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterV2.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterV2.java
@@ -26,10 +26,11 @@ public class VariableStorageDBAdapterV2 extends VariableStorageDBAdapter {
private static final int TABLE_VERSION = 2;
private Table variableStorageTable;
+ private DBHandle handle;
VariableStorageDBAdapterV2(DBHandle handle, boolean create)
throws VersionException, IOException {
-
+ this.handle = handle;
if (create) {
variableStorageTable = handle.createTable(VARIABLE_STORAGE_TABLE_NAME,
VARIABLE_STORAGE_SCHEMA, new int[] { HASH_COL });
@@ -49,6 +50,11 @@ public class VariableStorageDBAdapterV2 extends VariableStorageDBAdapter {
}
}
+ @Override
+ void deleteTable() throws IOException {
+ handle.deleteTable(VARIABLE_STORAGE_TABLE_NAME);
+ }
+
@Override
long getNextStorageID() {
long nextKey = variableStorageTable.getMaxKey() + 1;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManager.java
new file mode 100644
index 0000000000..bad8835c3f
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManager.java
@@ -0,0 +1,34 @@
+/* ###
+ * 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.symbol;
+
+import java.io.IOException;
+
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.VariableStorage;
+
+public interface VariableStorageManager {
+
+ /**
+ * Get a variable address for the given storage specification.
+ * @param storage variable storage specification
+ * @param create if true a new variable address will be allocated if needed
+ * @return variable address which corresponds to the storage specification or null if not found
+ * and create is false.
+ * @throws IOException if an IO error occurs
+ */
+ Address getVariableStorageAddress(VariableStorage storage, boolean create) throws IOException;
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManagerDB.java
index e0a07e9d76..f116150b68 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManagerDB.java
@@ -19,10 +19,13 @@ import java.io.IOException;
import java.util.List;
import db.*;
-import ghidra.program.database.*;
+import db.util.ErrorHandler;
+import ghidra.program.database.DBObjectCache;
+import ghidra.program.database.DatabaseObject;
import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.lang.ProgramArchitecture;
import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.util.LanguageTranslator;
@@ -32,11 +35,11 @@ import ghidra.util.datastruct.WeakValueHashMap;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
-public class VariableStorageManagerDB {
+public class VariableStorageManagerDB implements VariableStorageManager {
- private ProgramDB program;
- private AddressMap addrMap;
+ private ProgramArchitecture arch;
private Lock lock;
+ private ErrorHandler errorHandler;
private VariableStorageDBAdapter adapter;
@@ -47,45 +50,55 @@ public class VariableStorageManagerDB {
/**
* Construct a new variable manager.
* @param handle the database handle.
- * @param addrMap the address map
+ * @param addrMap the address map (required for legacy adpter use only)
* @param openMode the open mode
+ * @param errorHandler database error handler
* @param lock the program synchronization lock
* @param monitor the task monitor.
* @throws IOException if a database error occurs.
* @throws VersionException if the table version is different from this adapter.
- * @throws IOException
+ * @throws IOException if an IO error occurs
* @throws CancelledException if the user cancels the upgrade.
*/
- public VariableStorageManagerDB(DBHandle handle, AddressMap addrMap, int openMode, Lock lock,
- TaskMonitor monitor) throws VersionException, IOException, CancelledException {
-
- this.addrMap = addrMap;
+ public VariableStorageManagerDB(DBHandle handle, AddressMap addrMap, int openMode,
+ ErrorHandler errorHandler, Lock lock, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
+ this.errorHandler = errorHandler;
this.lock = lock;
-
adapter = VariableStorageDBAdapter.getAdapter(handle, openMode, addrMap, monitor);
}
+ /**
+ * Set program architecture.
+ * @param arch program architecture
+ */
+ public void setProgramArchitecture(ProgramArchitecture arch) {
+ this.arch = arch;
+ }
+
+ /**
+ * Delete the DB table which correspnds to this variable storage implementation
+ * @param dbHandle database handle
+ * @throws IOException if an IO error occurs
+ */
+ public static void delete(DBHandle dbHandle) throws IOException {
+ dbHandle.deleteTable(VariableStorageDBAdapter.VARIABLE_STORAGE_TABLE_NAME);
+ }
+
+ /**
+ * Determine if the variable storage manager table already exists
+ * @param dbHandle database handle
+ * @return true if storage table exists
+ */
+ public static boolean exists(DBHandle dbHandle) {
+ return dbHandle.getTable(VariableStorageDBAdapter.VARIABLE_STORAGE_TABLE_NAME) != null;
+ }
+
void invalidateCache(boolean all) {
cache.invalidate();
cacheMap.clear();
}
- void setProgram(ProgramDB program) {
- this.program = program;
- }
-
-// private void cacheNamespaceStorage(long namespaceID) throws IOException {
-// variableAddrLookupCache.clear();
-// storageLookupCache.clear();
-// lastNamespaceCacheID = namespaceID;
-// Record[] records = adapter.getRecordsForNamespace(namespaceID);
-// for (Record rec : records) {
-// MyVariableStorage varStore = new MyVariableStorage(rec);
-// variableAddrLookupCache.put(varStore.getVariableAddress(), varStore);
-// storageLookupCache.put(varStore.getVariableStorage(), varStore);
-// }
-// }
-
private MyVariableStorage getMyVariableStorage(Address variableAddr) throws IOException {
if (!variableAddr.isVariableAddress()) {
throw new IllegalArgumentException("Address is not a VariableAddress: " + variableAddr);
@@ -103,6 +116,14 @@ public class VariableStorageManagerDB {
return varStore;
}
+ /**
+ * Get the list of varnodes associated with the specified variable storage address.
+ * NOTE: The program architecture and error handler must be set appropriately prior to
+ * invocation of this method (see {@link #setProgramArchitecture(ProgramArchitecture, ErrorHandler)}.
+ * @param variableAddr variable storage address
+ * @return storage varnode list or null if address unknown
+ * @throws IOException if a database IO error occurs
+ */
List getStorageVarnodes(Address variableAddr) throws IOException {
if (!variableAddr.isVariableAddress()) {
throw new IllegalArgumentException();
@@ -112,7 +133,7 @@ public class VariableStorageManagerDB {
return null;
}
try {
- return VariableStorage.getVarnodes(program.getAddressFactory(),
+ return VariableStorage.getVarnodes(arch.getAddressFactory(),
rec.getString(VariableStorageDBAdapter.STORAGE_COL));
}
catch (InvalidInputException e) {
@@ -121,6 +142,14 @@ public class VariableStorageManagerDB {
return null;
}
+ /**
+ * Get the variable storage object associated with the specified variable storage address.
+ * NOTE: The program architecture and error handler must be set appropriately prior to
+ * invocation of this method (see {@link #setProgramArchitecture(ProgramArchitecture, ErrorHandler)}.
+ * @param variableAddr variable storage address
+ * @return variable storage object or null if address unknown
+ * @throws IOException if a database IO error occurs
+ */
VariableStorage getVariableStorage(Address variableAddr) throws IOException {
MyVariableStorage myStorage = getMyVariableStorage(variableAddr);
if (myStorage != null) {
@@ -129,6 +158,17 @@ public class VariableStorageManagerDB {
return null;
}
+ /**
+ * Get a variable address for the given storage specification.
+ * NOTE: The program architecture and error handler must be set appropriately prior to
+ * invocation of this method (see {@link #setProgramArchitecture(ProgramArchitecture, ErrorHandler)}.
+ * @param storage variable storage specification
+ * @param create if true a new variable address will be allocated if needed
+ * @return variable address which corresponds to the storage specification or null if not found
+ * and create is false.
+ * @throws IOException if an IO error occurs
+ */
+ @Override
public Address getVariableStorageAddress(VariableStorage storage, boolean create)
throws IOException {
long hash = storage.getLongHash();
@@ -215,7 +255,7 @@ public class VariableStorageManagerDB {
super(cache, record.getKey());
this.record = record;
try {
- storage = VariableStorage.deserialize(program,
+ storage = VariableStorage.deserialize(arch,
record.getString(VariableStorageDBAdapter.STORAGE_COL));
}
catch (InvalidInputException e) {
@@ -250,7 +290,7 @@ public class VariableStorageManagerDB {
}
record = rec;
try {
- storage = VariableStorage.deserialize(program,
+ storage = VariableStorage.deserialize(arch,
record.getString(VariableStorageDBAdapter.STORAGE_COL));
}
catch (InvalidInputException e) {
@@ -260,7 +300,7 @@ public class VariableStorageManagerDB {
}
}
catch (IOException e) {
- program.dbError(e);
+ errorHandler.dbError(e);
}
finally {
lock.release();
@@ -272,10 +312,13 @@ public class VariableStorageManagerDB {
/**
* Perform language translation.
+ * Following the invocation of this method it is important to ensure that the program
+ * architecure is adjusted if neccessary.
* Update variable storage specifications to reflect address space and register mappings
- * @param translator
- * @param monitor
- * @throws CancelledException
+ * @param translator language translator to be used for mapping storage varnodes to new
+ * architecture.
+ * @param monitor task monitor
+ * @throws CancelledException if task is cancelled
*/
public void setLanguage(LanguageTranslator translator, TaskMonitor monitor)
throws CancelledException {
@@ -308,7 +351,7 @@ public class VariableStorageManagerDB {
}
}
catch (IOException e) {
- program.dbError(e);
+ errorHandler.dbError(e);
}
finally {
invalidateCache(true);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/DBRecordAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/DBRecordAdapter.java
index 8b939d0536..d07edefa77 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/DBRecordAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/DBRecordAdapter.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,8 +15,6 @@
*/
package ghidra.program.database.util;
-import ghidra.program.model.address.Address;
-
import java.io.IOException;
import db.RecordIterator;
@@ -29,11 +26,15 @@ import db.RecordIterator;
public interface DBRecordAdapter {
/**
- * Get a record iterator.
- * @param start start of iterator
- * @param end end of iterator
- * @param colIndex index column
+ * Get a record iterator for all records.
+ * @return record iterator
* @throws IOException if there was a problem accessing the database
*/
- public RecordIterator getRecords(Address start, Address end, int colIndex) throws IOException;
+ public RecordIterator getRecords() throws IOException;
+
+ /**
+ * Get the number of records in table
+ * @return total record count
+ */
+ public int getRecordCount();
}
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 4d09c023f1..2aa7b34763 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
@@ -36,7 +36,6 @@ public abstract class AbstractDataType implements DataType {
protected String name;
protected CategoryPath categoryPath;
protected final DataTypeManager dataMgr;
- private DataOrganization dataOrganization;
protected AbstractDataType(CategoryPath path, String name, DataTypeManager dataTypeManager) {
if (path == null) {
@@ -75,16 +74,8 @@ public abstract class AbstractDataType implements DataType {
@Override
public final DataOrganization getDataOrganization() {
- if (dataOrganization != null) {
- return dataOrganization;
- }
- if (dataMgr != null) {
- dataOrganization = dataMgr.getDataOrganization();
- }
- if (dataOrganization == null) {
- dataOrganization = DataOrganizationImpl.getDefaultOrganization();
- }
- return dataOrganization;
+ return dataMgr != null ? dataMgr.getDataOrganization()
+ : DataOrganizationImpl.getDefaultOrganization();
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java
index 0e5d906ed6..3e17923920 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java
@@ -56,18 +56,14 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
private static SettingsDefinition[] SETTINGS_DEFS =
{ FormatSettingsDefinition.DEF_HEX, PADDING, ENDIAN, MNEMONIC };
- private final boolean signed;
-
/**
* Constructor
*
* @param name a unique signed/unsigned data-type name (also used as the mnemonic)
- * @param signed true if signed, false if unsigned
* @param dtm data-type manager whose data organization should be used
*/
- public AbstractIntegerDataType(String name, boolean signed, DataTypeManager dtm) {
+ public AbstractIntegerDataType(String name, DataTypeManager dtm) {
super(null, name, dtm);
- this.signed = signed;
}
/**
@@ -86,11 +82,10 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
}
/**
+ * Determine if this type is signed.
* @return true if this is a signed integer data-type
*/
- public boolean isSigned() {
- return signed;
- }
+ public abstract boolean isSigned();
@Override
public String getDefaultLabelPrefix() {
@@ -134,6 +129,7 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
if (size <= 0) {
return null;
}
+ boolean signed = isSigned();
DataOrganization dataOrganization = getDataOrganization();
if (size == dataOrganization.getCharSize()) {
return signed ? C_SIGNED_CHAR : C_UNSIGNED_CHAR;
@@ -311,7 +307,7 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
boolean negative = bigInt.signum() < 0;
- if (negative && (!signed || (format != FormatSettingsDefinition.DECIMAL))) {
+ if (negative && (!isSigned() || (format != FormatSettingsDefinition.DECIMAL))) {
// force use of unsigned value
bigInt = bigInt.add(BigInteger.valueOf(2).pow(bitLength));
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractSignedIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractSignedIntegerDataType.java
new file mode 100644
index 0000000000..67231bd75e
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractSignedIntegerDataType.java
@@ -0,0 +1,37 @@
+/* ###
+ * 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;
+
+/**
+ * Base type for unsigned integer data types.
+ */
+public abstract class AbstractSignedIntegerDataType extends AbstractIntegerDataType {
+
+ /**
+ * Constructor
+ *
+ * @param name a signed data-type name (also used as the mnemonic)
+ * @param dtm data-type manager whose data organization should be used
+ */
+ protected AbstractSignedIntegerDataType(String name, DataTypeManager dtm) {
+ super(name, dtm);
+ }
+
+ @Override
+ public final boolean isSigned() {
+ return true;
+ }
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractUnsignedIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractUnsignedIntegerDataType.java
new file mode 100644
index 0000000000..2c03452ea5
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractUnsignedIntegerDataType.java
@@ -0,0 +1,37 @@
+/* ###
+ * 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;
+
+/**
+ * Base type for unsigned integer data types.
+ */
+public abstract class AbstractUnsignedIntegerDataType extends AbstractIntegerDataType {
+
+ /**
+ * Constructor
+ *
+ * @param name a unsigned data-type name (also used as the mnemonic)
+ * @param dtm data-type manager whose data organization should be used
+ */
+ protected AbstractUnsignedIntegerDataType(String name, DataTypeManager dtm) {
+ super(name, dtm);
+ }
+
+ @Override
+ public final boolean isSigned() {
+ return false;
+ }
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AddressSpaceSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AddressSpaceSettingsDefinition.java
index b6177add8b..2f9093c63f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AddressSpaceSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AddressSpaceSettingsDefinition.java
@@ -21,8 +21,8 @@ import org.apache.commons.lang3.StringUtils;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.StringSettingsDefinition;
-import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.lang.ProgramArchitecture;
public class AddressSpaceSettingsDefinition
implements StringSettingsDefinition, TypeDefSettingsDefinition {
@@ -118,12 +118,14 @@ public class AddressSpaceSettingsDefinition
@Override
public boolean addPreferredValues(Object settingsOwner, Set set) {
- if (settingsOwner instanceof ProgramBasedDataTypeManager) {
- ProgramBasedDataTypeManager dtm = (ProgramBasedDataTypeManager) settingsOwner;
- AddressFactory addressFactory = dtm.getProgram().getAddressFactory();
- for (AddressSpace space : addressFactory.getAllAddressSpaces()) {
- if (space.isLoadedMemorySpace()) {
- set.add(space.getName());
+ if (settingsOwner instanceof DataTypeManager) {
+ DataTypeManager dtm = (DataTypeManager) settingsOwner;
+ ProgramArchitecture arch = dtm.getProgramArchitecture();
+ if (arch != null) {
+ for (AddressSpace space : arch.getAddressFactory().getAllAddressSpaces()) {
+ if (space.isLoadedMemorySpace()) {
+ set.add(space.getName());
+ }
}
}
return true;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java
index 1419616ff4..ff7ae47c9b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java
@@ -20,6 +20,7 @@ import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
+import ghidra.program.database.DBStringMapAdapter;
import ghidra.program.model.pcode.Encoder;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
@@ -27,9 +28,13 @@ import ghidra.xml.XmlPullParser;
public class BitFieldPackingImpl implements BitFieldPacking {
- private boolean useMSConvention = false;
- private boolean typeAlignmentEnabled = true;
- private int zeroLengthBoundary = 0;
+ public static final boolean DEFAULT_USE_MS_CONVENTION = false;
+ public static final boolean DEFAULT_TYPE_ALIGNMENT_ENABLED = true;
+ public static final int DEFAULT_ZERO_LENGTH_BOUNDARY = 0;
+
+ private boolean useMSConvention = DEFAULT_USE_MS_CONVENTION;
+ private boolean typeAlignmentEnabled = DEFAULT_TYPE_ALIGNMENT_ENABLED;
+ private int zeroLengthBoundary = DEFAULT_ZERO_LENGTH_BOUNDARY;
@Override
public boolean useMSConvention() {
@@ -76,26 +81,81 @@ public class BitFieldPackingImpl implements BitFieldPacking {
}
/**
- * Write configuration to a stream as a \ element
- * @param encoder is the stream encoder
- * @throws IOException for errors writing to the underlying stream
+ * Save the specified bitfield packing options to the specified DB data map.
+ * @param bitfieldPacking bitfield packing options
+ * @param dataMap DB data map
+ * @param keyPrefix key prefix for all map entries
+ * @throws IOException if an IO error occurs
+ */
+ static void save(BitFieldPacking bitfieldPacking, DBStringMapAdapter dataMap,
+ String keyPrefix) throws IOException {
+
+ boolean useMSConvention = bitfieldPacking.useMSConvention();
+ if (useMSConvention != DEFAULT_USE_MS_CONVENTION) {
+ dataMap.put(keyPrefix + "use_MS_convention", Boolean.toString(useMSConvention));
+ }
+
+ boolean typeAlignmentEnabled = bitfieldPacking.isTypeAlignmentEnabled();
+ if (typeAlignmentEnabled != DEFAULT_TYPE_ALIGNMENT_ENABLED) {
+ dataMap.put(keyPrefix + "type_alignment_enabled",
+ Boolean.toString(typeAlignmentEnabled));
+ }
+
+ int zeroLengthBoundary = bitfieldPacking.getZeroLengthBoundary();
+ if (zeroLengthBoundary != DEFAULT_ZERO_LENGTH_BOUNDARY) {
+ dataMap.put(keyPrefix + "zero_length_boundary", Integer.toString(zeroLengthBoundary));
+ }
+ }
+
+ /**
+ * Restore a data organization from the specified DB data map.
+ * @param dataMap DB data map
+ * @param keyPrefix key prefix for all map entries
+ * @return data organization
+ * @throws IOException if an IO error occurs
+ */
+ static BitFieldPackingImpl restore(DBStringMapAdapter dataMap, String keyPrefix)
+ throws IOException {
+
+ BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl();
+
+ bitFieldPacking.useMSConvention =
+ dataMap.getBoolean(keyPrefix + ELEM_USE_MS_CONVENTION.name(),
+ bitFieldPacking.useMSConvention);
+
+ bitFieldPacking.typeAlignmentEnabled = dataMap.getBoolean(
+ keyPrefix + ELEM_TYPE_ALIGNMENT_ENABLED.name(), bitFieldPacking.typeAlignmentEnabled);
+
+ bitFieldPacking.zeroLengthBoundary =
+ dataMap.getInt(keyPrefix + ELEM_ZERO_LENGTH_BOUNDARY.name(),
+ bitFieldPacking.zeroLengthBoundary);
+
+ return bitFieldPacking;
+ }
+
+ /**
+ * Output the details of this bitfield packing to a encoded document formatter.
+ * @param encoder the output document encoder.
+ * @throws IOException if an IO error occurs while encoding/writing output
*/
public void encode(Encoder encoder) throws IOException {
- if (!useMSConvention && typeAlignmentEnabled && zeroLengthBoundary == 0) {
+ if (useMSConvention == DEFAULT_USE_MS_CONVENTION &&
+ typeAlignmentEnabled == DEFAULT_TYPE_ALIGNMENT_ENABLED &&
+ zeroLengthBoundary == DEFAULT_ZERO_LENGTH_BOUNDARY) {
return; // All defaults
}
encoder.openElement(ELEM_BITFIELD_PACKING);
- if (useMSConvention) {
+ if (useMSConvention != DEFAULT_USE_MS_CONVENTION) {
encoder.openElement(ELEM_USE_MS_CONVENTION);
encoder.writeBool(ATTRIB_VALUE, true);
encoder.closeElement(ELEM_USE_MS_CONVENTION);
}
- if (!typeAlignmentEnabled) {
+ if (typeAlignmentEnabled != DEFAULT_TYPE_ALIGNMENT_ENABLED) {
encoder.openElement(ELEM_TYPE_ALIGNMENT_ENABLED);
encoder.writeBool(ATTRIB_VALUE, false);
encoder.closeElement(ELEM_TYPE_ALIGNMENT_ENABLED);
}
- if (zeroLengthBoundary != 0) {
+ if (zeroLengthBoundary != DEFAULT_ZERO_LENGTH_BOUNDARY) {
encoder.openElement(ELEM_ZERO_LENGTH_BOUNDARY);
encoder.writeSignedInteger(ATTRIB_VALUE, zeroLengthBoundary);
encoder.closeElement(ELEM_ZERO_LENGTH_BOUNDARY);
@@ -115,13 +175,13 @@ public class BitFieldPackingImpl implements BitFieldPacking {
String name = subel.getName();
String value = subel.getAttribute("value");
- if (name.equals("use_MS_convention")) {
+ if (name.equals(ELEM_USE_MS_CONVENTION.name())) {
useMSConvention = SpecXmlUtils.decodeBoolean(value);
}
- else if (name.equals("type_alignment_enabled")) {
+ else if (name.equals(ELEM_TYPE_ALIGNMENT_ENABLED.name())) {
typeAlignmentEnabled = SpecXmlUtils.decodeBoolean(value);
}
- else if (name.equals("zero_length_boundary")) {
+ else if (name.equals(ELEM_ZERO_LENGTH_BOUNDARY.name())) {
zeroLengthBoundary = SpecXmlUtils.decodeInt(value);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java
index ca300be5ef..48ba33918a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java
@@ -26,7 +26,7 @@ import ghidra.program.model.mem.MemoryAccessException;
/**
* Provides a definition of an Ascii byte in a program.
*/
-public class BooleanDataType extends AbstractIntegerDataType {
+public class BooleanDataType extends AbstractUnsignedIntegerDataType {
private static SettingsDefinition[] SETTINGS_DEFS = {};
@@ -40,7 +40,7 @@ public class BooleanDataType extends AbstractIntegerDataType {
}
public BooleanDataType(DataTypeManager dtm) {
- super("bool", false, dtm);
+ super("bool", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java
index 8f4588dad9..094939e06a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java
@@ -15,24 +15,29 @@
*/
package ghidra.program.model.data;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import javax.help.UnsupportedOperationException;
import javax.swing.event.ChangeListener;
import ghidra.framework.ShutdownHookRegistry;
import ghidra.framework.ShutdownPriority;
+import ghidra.program.database.symbol.VariableStorageManager;
+import ghidra.program.model.lang.ProgramArchitecture;
import ghidra.util.*;
import ghidra.util.classfinder.ClassFilter;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.AssertException;
+import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Data type manager for built in types that do not live anywhere except
* in memory.
*/
-public class BuiltInDataTypeManager extends StandAloneDataTypeManager {
+public final class BuiltInDataTypeManager extends StandAloneDataTypeManager {
// TODO: There appear to be many public methods in DataTypeManagerDB which could potentially modify the
// underlying database - these methods should probably be overridden
@@ -64,6 +69,17 @@ public class BuiltInDataTypeManager extends StandAloneDataTypeManager {
initialize();
}
+ protected final void setProgramArchitecture(ProgramArchitecture programArchitecture,
+ VariableStorageManager variableStorageMgr, boolean force, TaskMonitor monitor)
+ throws IOException, CancelledException {
+ throw new UnsupportedOperationException("program architecture change not permitted");
+ }
+
+ @Override
+ protected final boolean isArchitectureChangeAllowed() {
+ return false;
+ }
+
@Override
public synchronized int startTransaction(String description) {
if (manager != null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ByteDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ByteDataType.java
index de99b576dc..95213aa4f8 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ByteDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ByteDataType.java
@@ -20,9 +20,7 @@ import ghidra.program.model.lang.DecompilerLanguage;
/**
* Provides a definition of a Byte within a program.
*/
-public class ByteDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class ByteDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined ByteDataType instance.*/
public final static ByteDataType dataType = new ByteDataType();
@@ -32,7 +30,7 @@ public class ByteDataType extends AbstractIntegerDataType {
}
public ByteDataType(DataTypeManager dtm) {
- super("byte", false, dtm);
+ super("byte", dtm);
}
@Override
@@ -52,8 +50,9 @@ public class ByteDataType extends AbstractIntegerDataType {
@Override
public String getDecompilerDisplayName(DecompilerLanguage language) {
- if (language == DecompilerLanguage.JAVA_LANGUAGE)
+ if (language == DecompilerLanguage.JAVA_LANGUAGE) {
return "ubyte";
+ }
return name;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharDataType.java
index 38afef95e6..18be5b3488 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharDataType.java
@@ -26,7 +26,6 @@ import ghidra.util.classfinder.ClassTranslator;
* determined by the data organization of the associated data type manager.
*/
public class CharDataType extends AbstractIntegerDataType implements DataTypeWithCharset {
- private final static long serialVersionUID = 1;
static {
ClassTranslator.put("ghidra.program.model.data.AsciiDataType",
@@ -54,12 +53,13 @@ public class CharDataType extends AbstractIntegerDataType implements DataTypeWit
this("char", dtm);
}
- protected CharDataType(String name, boolean signed, DataTypeManager dtm) {
- super(name, signed, dtm);
+ protected CharDataType(String name, DataTypeManager dtm) {
+ super(name, dtm);
}
- private CharDataType(String name, DataTypeManager dtm) {
- super(name, isSignedChar(dtm), dtm);
+ @Override
+ public boolean isSigned() {
+ return getDataOrganization().isSignedChar();
}
@Override
@@ -76,12 +76,6 @@ public class CharDataType extends AbstractIntegerDataType implements DataTypeWit
return getLength() != 1;
}
- private static boolean isSignedChar(DataTypeManager dtm) {
- DataOrganization dataOrganization =
- dtm != null ? dtm.getDataOrganization() : DataOrganizationImpl.getDefaultOrganization();
- return dataOrganization.isSignedChar();
- }
-
/**
* Returns the C style data-type declaration for this data-type. Null is returned if no
* appropriate declaration exists.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DWordDataType.java
index e404ccfd44..1108770383 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DWordDataType.java
@@ -18,7 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a definition of a Double Word within a program.
*/
-public class DWordDataType extends AbstractIntegerDataType {
+public class DWordDataType extends AbstractUnsignedIntegerDataType {
private static final long serialVersionUID = 1L;
@@ -30,7 +30,7 @@ public class DWordDataType extends AbstractIntegerDataType {
}
public DWordDataType(DataTypeManager dtm) {
- super("dword", false, dtm);
+ super("dword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java
index fea8581459..c15d05ba0b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java
@@ -164,15 +164,6 @@ public interface DataOrganization {
*/
int getAlignment(DataType dataType);
-// /**
-// * Determines the offset where the specified data type should be placed to be properly aligned.
-// * @param minimumOffset the minimum allowable offset where the data type can be placed.
-// * @param dataType the data type
-// * @param dtSize the data type's size
-// * @return the aligned offset for the data type
-// */
-// int getAlignmentOffset(int minimumOffset, DataType dataType, int dtSize);
-
/**
* Determine if this DataOrganization is equivalent to another specific instance
* @param obj is the other instance
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java
index fa33af396c..b16292b30d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java
@@ -21,6 +21,7 @@ import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
import java.util.*;
+import ghidra.program.database.DBStringMapAdapter;
import ghidra.program.model.lang.Language;
import ghidra.program.model.pcode.Encoder;
import ghidra.util.exception.NoValueException;
@@ -34,26 +35,48 @@ import ghidra.xml.XmlPullParser;
*/
public class DataOrganizationImpl implements DataOrganization {
+ // NOTE: it is important that defaults match Decompiler defaults
+ public static final int DEFAULT_MACHINE_ALIGNMENT = 8;
+ public static final int DEFAULT_DEFAULT_ALIGNMENT = 1;
+ public static final int DEFAULT_DEFAULT_POINTER_ALIGNMENT = 4;
+ public static final int DEFAULT_POINTER_SHIFT = 0;
+ public static final int DEFAULT_POINTER_SIZE = 4;
+ public static final int DEFAULT_CHAR_SIZE = 1;
+ public static final boolean DEFAULT_CHAR_IS_SIGNED = true;
+ public static final int DEFAULT_WIDE_CHAR_SIZE = 2;
+ public static final int DEFAULT_SHORT_SIZE = 2;
+ public static final int DEFAULT_INT_SIZE = 4;
+ public static final int DEFAULT_LONG_SIZE = 4;
+ public static final int DEFAULT_LONG_LONG_SIZE = 8;
+ public static final int DEFAULT_FLOAT_SIZE = 4;
+ public static final int DEFAULT_DOUBLE_SIZE = 8;
+ public static final int DEFAULT_LONG_DOUBLE_SIZE = 8;
+
+ // DBStringMapAdapter save/restore keys
+ private static final String BIG_ENDIAN_NAME = "big_endian";
+ private static final String SIGNED_CHAR_TYPE_NAME = "signed_char_type";
+
private int absoluteMaxAlignment = NO_MAXIMUM_ALIGNMENT;
- private int machineAlignment = 8;
- private int defaultAlignment = 1;
- private int defaultPointerAlignment = 4;
+ private int machineAlignment = DEFAULT_MACHINE_ALIGNMENT;
+ private int defaultAlignment = DEFAULT_DEFAULT_ALIGNMENT;
+ private int defaultPointerAlignment = DEFAULT_DEFAULT_POINTER_ALIGNMENT;
// Default sizes for primitive data types.
- private int pointerShift = 0;
- private int pointerSize = 4;
- private int charSize = 1;
- private int wideCharSize = 2;
- private int shortSize = 2;
- private int integerSize = 4;
- private int longSize = 4;
- private int longLongSize = 8;
- private int floatSize = 4;
- private int doubleSize = 8;
- private int longDoubleSize = 8;
+ private int pointerShift = DEFAULT_POINTER_SHIFT;
+ private int pointerSize = DEFAULT_POINTER_SIZE;
+ private int charSize = DEFAULT_CHAR_SIZE;
+ private boolean isSignedChar = DEFAULT_CHAR_IS_SIGNED;
+ private int wideCharSize = DEFAULT_WIDE_CHAR_SIZE;
+ private int shortSize = DEFAULT_SHORT_SIZE;
+ private int integerSize = DEFAULT_INT_SIZE;
+ private int longSize = DEFAULT_LONG_SIZE;
+ private int longLongSize = DEFAULT_LONG_LONG_SIZE;
+ private int floatSize = DEFAULT_FLOAT_SIZE;
+ private int doubleSize = DEFAULT_DOUBLE_SIZE;
+ private int longDoubleSize = DEFAULT_LONG_DOUBLE_SIZE;
+ // Endianess explicitly set and not supported by saveXml/restore
private boolean bigEndian = false;
- private boolean isSignedChar = true;
private BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl();
@@ -86,7 +109,9 @@ public class DataOrganizationImpl implements DataOrganization {
dataOrganization.setSizeAlignment(4, 4);
dataOrganization.setSizeAlignment(8, 4);
if (language != null) {
+ // NOTE: Ensure that saveXml always saves pointer size
dataOrganization.setPointerSize(language.getDefaultSpace().getPointerSize());
+ // NOTE: Endianess is not handled by saveXml/restore
dataOrganization.setBigEndian(language.isBigEndian());
}
return dataOrganization;
@@ -556,84 +581,300 @@ public class DataOrganizationImpl implements DataOrganization {
return (value2 != 0) ? getGreatestCommonDenominator(value2, value1 % value2) : value1;
}
+ /**
+ * Save the specified data organization to the specified DB data map.
+ * All existing map entries starting with keyPrefix will be removed prior
+ * to ading the new map entries.
+ * @param dataOrg data organization
+ * @param dataMap DB data map
+ * @param keyPrefix key prefix for all map entries
+ * @throws IOException if an IO error occurs
+ */
+ public static void save(DataOrganization dataOrg, DBStringMapAdapter dataMap, String keyPrefix)
+ throws IOException {
+
+ for (String key : dataMap.keySet()) {
+ if (key.startsWith(keyPrefix)) {
+ dataMap.delete(key);
+ }
+ }
+
+ if (dataOrg.isBigEndian()) { // default is little-endian
+ dataMap.put(keyPrefix + BIG_ENDIAN_NAME, Boolean.TRUE.toString());
+ }
+
+ int absoluteMaxAlignment = dataOrg.getAbsoluteMaxAlignment();
+ if (absoluteMaxAlignment != NO_MAXIMUM_ALIGNMENT) {
+ dataMap.put(keyPrefix + ELEM_ABSOLUTE_MAX_ALIGNMENT.name(),
+ Integer.toString(absoluteMaxAlignment));
+ }
+
+ int machineAlignment = dataOrg.getMachineAlignment();
+ if (machineAlignment != DEFAULT_MACHINE_ALIGNMENT) {
+ dataMap.put(keyPrefix + ELEM_MACHINE_ALIGNMENT.name(),
+ Integer.toString(machineAlignment));
+ }
+
+ int defaultAlignment = dataOrg.getDefaultAlignment();
+ if (defaultAlignment != DEFAULT_DEFAULT_ALIGNMENT) {
+ dataMap.put(keyPrefix + ELEM_DEFAULT_ALIGNMENT.name(),
+ Integer.toString(defaultAlignment));
+ }
+
+ int defaultPointerAlignment = dataOrg.getDefaultPointerAlignment();
+ if (defaultPointerAlignment != DEFAULT_DEFAULT_POINTER_ALIGNMENT) {
+ dataMap.put(keyPrefix + ELEM_DEFAULT_POINTER_ALIGNMENT.name(),
+ Integer.toString(defaultPointerAlignment));
+ }
+
+ int pointerSize = dataOrg.getPointerSize();
+ if (pointerSize != DEFAULT_POINTER_SIZE) {
+ dataMap.put(keyPrefix + ELEM_POINTER_SIZE.name(), Integer.toString(pointerSize));
+ }
+
+ int pointerShift = dataOrg.getPointerShift();
+ if (pointerShift != DEFAULT_POINTER_SHIFT) {
+ dataMap.put(keyPrefix + ELEM_POINTER_SHIFT.name(), Integer.toString(pointerShift));
+ }
+
+ boolean isSignedChar = dataOrg.isSignedChar();
+ if (!isSignedChar) {
+ // NOTE: This differs from XML element name
+ dataMap.put(keyPrefix + SIGNED_CHAR_TYPE_NAME, Boolean.toString(isSignedChar));
+ }
+
+ int charSize = dataOrg.getCharSize();
+ if (charSize != DEFAULT_CHAR_SIZE) {
+ dataMap.put(keyPrefix + ELEM_CHAR_SIZE.name(), Integer.toString(charSize));
+ }
+
+ int wideCharSize = dataOrg.getWideCharSize();
+ if (wideCharSize != DEFAULT_WIDE_CHAR_SIZE) {
+ dataMap.put(keyPrefix + ELEM_WCHAR_SIZE.name(), Integer.toString(wideCharSize));
+ }
+
+ int shortSize = dataOrg.getShortSize();
+ if (shortSize != DEFAULT_SHORT_SIZE) {
+ dataMap.put(keyPrefix + ELEM_SHORT_SIZE.name(), Integer.toString(shortSize));
+ }
+
+ int integerSize = dataOrg.getIntegerSize();
+ if (integerSize != DEFAULT_INT_SIZE) {
+ dataMap.put(keyPrefix + ELEM_INTEGER_SIZE.name(), Integer.toString(integerSize));
+ }
+
+ int longSize = dataOrg.getLongSize();
+ if (longSize != DEFAULT_LONG_SIZE) {
+ dataMap.put(keyPrefix + ELEM_LONG_SIZE.name(), Integer.toString(longSize));
+ }
+
+ int longLongSize = dataOrg.getLongLongSize();
+ if (longLongSize != DEFAULT_LONG_LONG_SIZE) {
+ dataMap.put(keyPrefix + ELEM_LONG_LONG_SIZE.name(), Integer.toString(longLongSize));
+ }
+
+ int floatSize = dataOrg.getFloatSize();
+ if (floatSize != DEFAULT_FLOAT_SIZE) {
+ dataMap.put(keyPrefix + ELEM_FLOAT_SIZE.name(), Integer.toString(floatSize));
+ }
+
+ int doubleSize = dataOrg.getDoubleSize();
+ if (doubleSize != DEFAULT_DOUBLE_SIZE) {
+ dataMap.put(keyPrefix + ELEM_DOUBLE_SIZE.name(), Integer.toString(doubleSize));
+ }
+
+ int longDoubleSize = dataOrg.getLongDoubleSize();
+ if (longDoubleSize != DEFAULT_LONG_DOUBLE_SIZE) {
+ dataMap.put(keyPrefix + ELEM_LONG_DOUBLE_SIZE.name(), Integer.toString(longDoubleSize));
+ }
+
+ for (int size : dataOrg.getSizes()) {
+ try {
+ String key = keyPrefix + ELEM_SIZE_ALIGNMENT_MAP.name() + "." + size;
+ dataMap.put(key, Integer.toString(dataOrg.getSizeAlignment(size)));
+ }
+ catch (NoValueException e) {
+ // skip entry
+ }
+ }
+
+ BitFieldPackingImpl.save(dataOrg.getBitFieldPacking(), dataMap,
+ keyPrefix + ELEM_BITFIELD_PACKING.name() + ".");
+ }
+
+ /**
+ * Restore a data organization from the specified DB data map.
+ * @param dataMap DB data map
+ * @param keyPrefix key prefix for all map entries
+ * @return data organization
+ * @throws IOException if an IO error occurs
+ */
+ public static DataOrganizationImpl restore(DBStringMapAdapter dataMap, String keyPrefix)
+ throws IOException {
+
+ DataOrganizationImpl dataOrg = new DataOrganizationImpl();
+
+ dataOrg.bigEndian = dataMap.getBoolean(BIG_ENDIAN_NAME, false);
+
+ dataOrg.absoluteMaxAlignment =
+ dataMap.getInt(keyPrefix + ELEM_ABSOLUTE_MAX_ALIGNMENT.name(),
+ dataOrg.absoluteMaxAlignment);
+
+ dataOrg.machineAlignment =
+ dataMap.getInt(keyPrefix + ELEM_MACHINE_ALIGNMENT.name(), dataOrg.machineAlignment);
+
+ dataOrg.defaultAlignment =
+ dataMap.getInt(keyPrefix + ELEM_DEFAULT_ALIGNMENT.name(), dataOrg.defaultAlignment);
+
+ dataOrg.defaultPointerAlignment =
+ dataMap.getInt(keyPrefix + ELEM_DEFAULT_POINTER_ALIGNMENT.name(),
+ dataOrg.defaultPointerAlignment);
+
+ dataOrg.pointerSize =
+ dataMap.getInt(keyPrefix + ELEM_POINTER_SIZE.name(), dataOrg.pointerSize);
+
+ dataOrg.pointerShift =
+ dataMap.getInt(keyPrefix + ELEM_POINTER_SHIFT.name(), dataOrg.pointerShift);
+
+ dataOrg.isSignedChar =
+ dataMap.getBoolean(keyPrefix + SIGNED_CHAR_TYPE_NAME, dataOrg.isSignedChar);
+
+ dataOrg.charSize = dataMap.getInt(keyPrefix + ELEM_CHAR_SIZE.name(), dataOrg.charSize);
+
+ dataOrg.wideCharSize =
+ dataMap.getInt(keyPrefix + ELEM_WCHAR_SIZE.name(), dataOrg.wideCharSize);
+
+ dataOrg.shortSize = dataMap.getInt(keyPrefix + ELEM_SHORT_SIZE.name(), dataOrg.shortSize);
+
+ dataOrg.integerSize =
+ dataMap.getInt(keyPrefix + ELEM_INTEGER_SIZE.name(), dataOrg.integerSize);
+
+ dataOrg.longSize = dataMap.getInt(keyPrefix + ELEM_LONG_SIZE.name(), dataOrg.longSize);
+
+ dataOrg.longLongSize =
+ dataMap.getInt(keyPrefix + ELEM_LONG_LONG_SIZE.name(), dataOrg.longLongSize);
+
+ dataOrg.floatSize = dataMap.getInt(keyPrefix + ELEM_FLOAT_SIZE.name(), dataOrg.floatSize);
+
+ dataOrg.doubleSize =
+ dataMap.getInt(keyPrefix + ELEM_DOUBLE_SIZE.name(), dataOrg.doubleSize);
+
+ dataOrg.longDoubleSize =
+ dataMap.getInt(keyPrefix + ELEM_LONG_DOUBLE_SIZE.name(), dataOrg.longDoubleSize);
+
+ boolean firstEntry = true;
+ String alignmentMapKeyPrefix = keyPrefix + ELEM_SIZE_ALIGNMENT_MAP.name() + ".";
+ for (String key : dataMap.keySet()) {
+ if (!key.startsWith(alignmentMapKeyPrefix)) {
+ continue;
+ }
+ try {
+ int size = Integer.valueOf(key.substring(alignmentMapKeyPrefix.length()));
+ int alignment = Integer.valueOf(dataMap.get(key));
+ if (firstEntry) {
+ dataOrg.sizeAlignmentMap.clear();
+ firstEntry = false;
+ }
+ dataOrg.sizeAlignmentMap.put(size, alignment);
+ }
+ catch (NumberFormatException e) {
+ // ignore
+ }
+ }
+
+ dataOrg.bitFieldPacking =
+ BitFieldPackingImpl.restore(dataMap, keyPrefix + ELEM_BITFIELD_PACKING.name() + ".");
+
+ return dataOrg;
+ }
+
+ /**
+ * Output the details of this data organization to a encoded document formatter.
+ * @param encoder the output document encoder.
+ * @throws IOException if an IO error occurs while encoding/writing output
+ */
public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_DATA_ORGANIZATION);
+
+ // NOTE: endianess intentionally omitted from output
+
if (absoluteMaxAlignment != NO_MAXIMUM_ALIGNMENT) {
encoder.openElement(ELEM_ABSOLUTE_MAX_ALIGNMENT);
encoder.writeSignedInteger(ATTRIB_VALUE, absoluteMaxAlignment);
encoder.closeElement(ELEM_ABSOLUTE_MAX_ALIGNMENT);
}
- if (machineAlignment != 8) {
+ if (machineAlignment != DEFAULT_MACHINE_ALIGNMENT) {
encoder.openElement(ELEM_MACHINE_ALIGNMENT);
encoder.writeSignedInteger(ATTRIB_VALUE, machineAlignment);
encoder.closeElement(ELEM_MACHINE_ALIGNMENT);
}
- if (defaultAlignment != 1) {
+ if (defaultAlignment != DEFAULT_DEFAULT_ALIGNMENT) {
encoder.openElement(ELEM_DEFAULT_ALIGNMENT);
encoder.writeSignedInteger(ATTRIB_VALUE, defaultAlignment);
encoder.closeElement(ELEM_DEFAULT_ALIGNMENT);
}
- if (defaultPointerAlignment != 4) {
+ if (defaultPointerAlignment != DEFAULT_DEFAULT_POINTER_ALIGNMENT) {
encoder.openElement(ELEM_DEFAULT_POINTER_ALIGNMENT);
encoder.writeSignedInteger(ATTRIB_VALUE, defaultPointerAlignment);
encoder.closeElement(ELEM_DEFAULT_POINTER_ALIGNMENT);
}
- if (pointerSize != 0) {
- encoder.openElement(ELEM_POINTER_SIZE);
- encoder.writeSignedInteger(ATTRIB_VALUE, pointerSize);
- encoder.closeElement(ELEM_POINTER_SIZE);
- }
- if (pointerShift != 0) {
+
+ // Always output pointer size
+ encoder.openElement(ELEM_POINTER_SIZE);
+ encoder.writeSignedInteger(ATTRIB_VALUE, pointerSize);
+ encoder.closeElement(ELEM_POINTER_SIZE);
+
+ if (pointerShift != DEFAULT_POINTER_SHIFT) {
encoder.openElement(ELEM_POINTER_SHIFT);
encoder.writeSignedInteger(ATTRIB_VALUE, pointerShift);
encoder.closeElement(ELEM_POINTER_SHIFT);
}
- if (!isSignedChar) {
+ if (isSignedChar != DEFAULT_CHAR_IS_SIGNED) {
encoder.openElement(ELEM_CHAR_TYPE);
- encoder.writeBool(ATTRIB_SIGNED, false);
+ encoder.writeBool(ATTRIB_SIGNED, isSignedChar);
encoder.closeElement(ELEM_CHAR_TYPE);
}
- if (charSize != 1) {
+ if (charSize != DEFAULT_CHAR_SIZE) {
encoder.openElement(ELEM_CHAR_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, charSize);
encoder.closeElement(ELEM_CHAR_SIZE);
}
- if (wideCharSize != 2) {
+ if (wideCharSize != DEFAULT_WIDE_CHAR_SIZE) {
encoder.openElement(ELEM_WCHAR_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, wideCharSize);
encoder.closeElement(ELEM_WCHAR_SIZE);
}
- if (shortSize != 2) {
+ if (shortSize != DEFAULT_SHORT_SIZE) {
encoder.openElement(ELEM_SHORT_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, shortSize);
encoder.closeElement(ELEM_SHORT_SIZE);
}
- if (integerSize != 4) {
+ if (integerSize != DEFAULT_INT_SIZE) {
encoder.openElement(ELEM_INTEGER_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, integerSize);
encoder.closeElement(ELEM_INTEGER_SIZE);
}
- if (longSize != 4) {
+ if (longSize != DEFAULT_LONG_SIZE) {
encoder.openElement(ELEM_LONG_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, longSize);
encoder.closeElement(ELEM_LONG_SIZE);
}
- if (longLongSize != 8) {
+ if (longLongSize != DEFAULT_LONG_LONG_SIZE) {
encoder.openElement(ELEM_LONG_LONG_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, longLongSize);
encoder.closeElement(ELEM_LONG_LONG_SIZE);
}
- if (floatSize != 4) {
+ if (floatSize != DEFAULT_FLOAT_SIZE) {
encoder.openElement(ELEM_FLOAT_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, floatSize);
encoder.closeElement(ELEM_FLOAT_SIZE);
}
- if (doubleSize != 8) {
+ if (doubleSize != DEFAULT_DOUBLE_SIZE) {
encoder.openElement(ELEM_DOUBLE_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, doubleSize);
encoder.closeElement(ELEM_DOUBLE_SIZE);
}
- if (longDoubleSize != 8) {
+ if (longDoubleSize != DEFAULT_LONG_DOUBLE_SIZE) {
encoder.openElement(ELEM_LONG_DOUBLE_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, longDoubleSize);
encoder.closeElement(ELEM_LONG_DOUBLE_SIZE);
@@ -654,33 +895,39 @@ public class DataOrganizationImpl implements DataOrganization {
}
/**
- * Restore settings from an XML stream. This expects to see a \ tag.
- * The XML is designed to override existing default settings. So this object needs to
- * be pre-populated with defaults, typically via getDefaultOrganization().
+ * Restore settings from an XML stream. This expects to see parser positioned on the
+ * <data_organization> start tag. The XML is designed to override existing language-specific
+ * default settings which are pre-populated with {@link #getDefaultOrganization(Language)}. This
+ * will will ensure that the endianess setting is properly established since it is not included
+ * in the XML.
* @param parser is the XML stream
*/
public void restoreXml(XmlPullParser parser) {
+
+ // NOTE: endianess intentionally omitted from XML.
+
parser.start();
while (parser.peek().isStart()) {
String name = parser.peek().getName();
- if (name.equals("char_type")) {
+ if (name.equals(ELEM_CHAR_TYPE.name())) {
XmlElement subel = parser.start();
- String boolStr = subel.getAttribute("signed");
- isSignedChar = SpecXmlUtils.decodeBoolean(boolStr);
+ String boolStr = subel.getAttribute(ATTRIB_SIGNED.name());
+ isSignedChar = SpecXmlUtils.decodeBoolean(boolStr, isSignedChar);
parser.end(subel);
continue;
}
- else if (name.equals("bitfield_packing")) {
+ else if (name.equals(ELEM_BITFIELD_PACKING.name())) {
bitFieldPacking.restoreXml(parser);
continue;
}
- else if (name.equals("size_alignment_map")) {
+ else if (name.equals(ELEM_SIZE_ALIGNMENT_MAP.name())) {
XmlElement subel = parser.start();
while (parser.peek().isStart()) {
XmlElement subsubel = parser.start();
- int size = SpecXmlUtils.decodeInt(subsubel.getAttribute("size"));
- int alignment = SpecXmlUtils.decodeInt(subsubel.getAttribute("alignment"));
+ int size = SpecXmlUtils.decodeInt(subsubel.getAttribute(ATTRIB_SIZE.name()));
+ int alignment =
+ SpecXmlUtils.decodeInt(subsubel.getAttribute(ATTRIB_ALIGNMENT.name()));
sizeAlignmentMap.put(size, alignment);
parser.end(subsubel);
}
@@ -689,51 +936,51 @@ public class DataOrganizationImpl implements DataOrganization {
}
XmlElement subel = parser.start();
- String value = subel.getAttribute("value");
+ String value = subel.getAttribute(ATTRIB_VALUE.name());
- if (name.equals("absolute_max_alignment")) {
+ if (name.equals(ELEM_ABSOLUTE_MAX_ALIGNMENT.name())) {
absoluteMaxAlignment = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("machine_alignment")) {
+ else if (name.equals(ELEM_MACHINE_ALIGNMENT.name())) {
machineAlignment = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("default_alignment")) {
+ else if (name.equals(ELEM_DEFAULT_ALIGNMENT.name())) {
defaultAlignment = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("default_pointer_alignment")) {
+ else if (name.equals(ELEM_DEFAULT_POINTER_ALIGNMENT.name())) {
defaultPointerAlignment = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("pointer_size")) {
+ else if (name.equals(ELEM_POINTER_SIZE.name())) {
pointerSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("pointer_shift")) {
+ else if (name.equals(ELEM_POINTER_SHIFT.name())) {
pointerShift = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("char_size")) {
+ else if (name.equals(ELEM_CHAR_SIZE.name())) {
charSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("wchar_size")) {
+ else if (name.equals(ELEM_WCHAR_SIZE.name())) {
wideCharSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("short_size")) {
+ else if (name.equals(ELEM_SHORT_SIZE.name())) {
shortSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("integer_size")) {
+ else if (name.equals(ELEM_INTEGER_SIZE.name())) {
integerSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("long_size")) {
+ else if (name.equals(ELEM_LONG_SIZE.name())) {
longSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("long_long_size")) {
+ else if (name.equals(ELEM_LONG_LONG_SIZE.name())) {
longLongSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("float_size")) {
+ else if (name.equals(ELEM_FLOAT_SIZE.name())) {
floatSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("double_size")) {
+ else if (name.equals(ELEM_DOUBLE_SIZE.name())) {
doubleSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("long_double_size")) {
+ else if (name.equals(ELEM_LONG_DOUBLE_SIZE.name())) {
longDoubleSize = SpecXmlUtils.decodeInt(value);
}
parser.end(subel);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeArchiveIdDumper.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeArchiveIdDumper.java
index 9738ee9cb3..e077d58298 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeArchiveIdDumper.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeArchiveIdDumper.java
@@ -39,6 +39,7 @@ public class DataTypeArchiveIdDumper implements GhidraLaunchable {
FileWriter writer = new FileWriter(outputFile);
FileDataTypeManager archive = FileDataTypeManager.openFileArchive(archiveFile, false);
+ archive.reportWarning();
UniversalID universalID2 = archive.getUniversalID();
writer.write("FILE_ID: " + Long.toHexString(universalID2.getValue()));
writer.write("\n");
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 8fc90407c0..3d806e962c 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
@@ -18,6 +18,11 @@ package ghidra.program.model.data;
import java.util.*;
import db.Transaction;
+import ghidra.program.database.SpecExtension;
+import ghidra.program.database.map.AddressMap;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
import ghidra.util.exception.CancelledException;
@@ -59,6 +64,21 @@ public interface DataTypeManager {
*/
public UniversalID getUniversalID();
+ /**
+ * Get the optional program architecture details associated with this archive
+ * @return program architecture details or null if none
+ */
+ public ProgramArchitecture getProgramArchitecture();
+
+ /**
+ * Get the program architecture information which has been associated with this
+ * datatype manager. If {@link #getProgramArchitecture()} returns null this method
+ * may still return information if the program architecture was set on an archive but unable
+ * to properly instantiate.
+ * @return program architecture summary if it has been set
+ */
+ public String getProgramArchitectureSummary();
+
/**
* Returns true if the given category path exists in this datatype manager
* @param path the path
@@ -138,6 +158,12 @@ public interface DataTypeManager {
*/
public Iterator getAllComposites();
+ /**
+ * Returns an iterator over all function definition data types in this manager
+ * @return the iterator
+ */
+ public Iterator getAllFunctionDefinitions();
+
/**
* Begin searching at the root category for all data types with the
* given name. Places all the data types in this data type manager
@@ -522,6 +548,13 @@ public interface DataTypeManager {
*/
public DataOrganization getDataOrganization();
+ /**
+ * Returns the associated AddressMap used by this datatype manager.
+ * @return the AddressMap used by this datatype manager or null if
+ * one has not be established.
+ */
+ public AddressMap getAddressMap();
+
/**
* Returns a list of source archives not including the builtin or the program's archive.
* @return a list of source archives not including the builtin or the program's archive.
@@ -568,4 +601,49 @@ public interface DataTypeManager {
* @return true if BuiltIn Settings are permitted
*/
public boolean allowsDefaultComponentSettings();
+
+ /**
+ * Get the ordered list of known calling convention names. The reserved names
+ * "unknown" and "default" are not included. The returned collection will include all names
+ * ever used or resolved by associated {@link Function} and {@link FunctionDefinition} objects,
+ * even if not currently defined by the associated {@link CompilerSpec} or {@link Program}
+ * {@link SpecExtension}. To get only those calling conventions formally defined, the method
+ * {@link CompilerSpec#getCallingConventions()} should be used.
+ *
+ * @return all known calling convention names.
+ */
+ public Collection getKnownCallingConventionNames();
+
+ /**
+ * Get the ordered list of defined calling convention names. The reserved names
+ * "unknown" and "default" are not included. The returned collection may not include all names
+ * referenced by various functions and function-definitions. This set is generally limited to
+ * those defined by the associated compiler specification. If this instance does not have an
+ * assigned architecture the {@link GenericCallingConvention} names will be returned.
+ *
+ * For a set of all known names (including those that are not defined by compiler spec)
+ * see {@link #getKnownCallingConventionNames()}.
+ *
+ * @return the set of defined calling convention names.
+ */
+ public Collection getDefinedCallingConventionNames();
+
+ /**
+ * Get the default calling convention's prototype model in this datatype manager if known.
+ *
+ * @return the default calling convention prototype model or null.
+ */
+ public PrototypeModel getDefaultCallingConvention();
+
+ /**
+ * Get the prototype model of the calling convention with the specified name from the
+ * associated compiler specification. If an architecture has not been established this method
+ * will return null. If {@link Function#DEFAULT_CALLING_CONVENTION_STRING}
+ * is specified {@link #getDefaultCallingConvention()} will be returned.
+ *
+ * @param name the calling convention name
+ * @return the named function calling convention prototype model or null.
+ */
+ public PrototypeModel getCallingConvention(String name);
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListener.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListener.java
index 400955df3f..c1791265f4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListener.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListener.java
@@ -123,4 +123,11 @@ public interface DataTypeManagerChangeListener {
*/
public void sourceArchiveAdded(final DataTypeManager dataTypeManager,
final SourceArchive sourceArchive);
+
+ /**
+ * Notification that the program architecture associated with the specified
+ * dataTypeManager has changed.
+ * @param dataTypeManager data type manager referring to the given source information.
+ */
+ public void programArchitectureChanged(DataTypeManager dataTypeManager);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerAdapter.java
index 82be93f86d..d55f93374d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerAdapter.java
@@ -73,4 +73,8 @@ public class DataTypeManagerChangeListenerAdapter implements DataTypeManagerChan
public void sourceArchiveChanged(DataTypeManager dataTypeManager, SourceArchive dataTypeSource) {
}
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ }
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerHandler.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerHandler.java
index db82316e47..f5765860f9 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerHandler.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerHandler.java
@@ -15,18 +15,20 @@
*/
package ghidra.program.model.data;
-import ghidra.util.datastruct.WeakDataStructureFactory;
-import ghidra.util.datastruct.WeakSet;
-
import java.io.IOException;
import java.io.ObjectInputStream;
import javax.swing.SwingUtilities;
+import ghidra.util.datastruct.WeakDataStructureFactory;
+import ghidra.util.datastruct.WeakSet;
+
/**
*
- * Default implementation for a category change listener that sends out the
- * events to its own list of category change listeners.
+ * Default implementation for a {@link DataTypeManagerChangeListener} that sends out the
+ * events to its own list of listeners.
+ *
+ * NOTE: all listener notifications must be asynchronous within a different thread.
*
*/
public class DataTypeManagerChangeListenerHandler implements DataTypeManagerChangeListener {
@@ -51,158 +53,122 @@ public class DataTypeManagerChangeListenerHandler implements DataTypeManagerChan
}
@Override
- public void categoryAdded(final DataTypeManager dtm, final CategoryPath path) {
+ public void categoryAdded(DataTypeManager dtm, CategoryPath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.categoryAdded(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.categoryAdded(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void categoryMoved(final DataTypeManager dtm, final CategoryPath oldPath,
- final CategoryPath newPath) {
+ public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath,
+ CategoryPath newPath) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.categoryMoved(dtm, oldPath, newPath);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.categoryMoved(dtm, oldPath, newPath);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void categoryRemoved(final DataTypeManager dtm, final CategoryPath path) {
+ public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.categoryRemoved(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.categoryRemoved(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void categoryRenamed(final DataTypeManager dtm, final CategoryPath oldPath,
- final CategoryPath newPath) {
+ public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath,
+ CategoryPath newPath) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.categoryRenamed(dtm, oldPath, newPath);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.categoryRenamed(dtm, oldPath, newPath);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeAdded(final DataTypeManager dtm, final DataTypePath path) {
+ public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeAdded(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeAdded(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeChanged(final DataTypeManager dtm, final DataTypePath path) {
+ public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeChanged(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeChanged(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeMoved(final DataTypeManager dtm, final DataTypePath oldPath,
- final DataTypePath newPath) {
+ public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeMoved(dtm, oldPath, newPath);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeMoved(dtm, oldPath, newPath);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeRemoved(final DataTypeManager dtm, final DataTypePath path) {
+ public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeRemoved(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeRemoved(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeRenamed(final DataTypeManager dtm, final DataTypePath oldPath,
- final DataTypePath newPath) {
+ public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeRenamed(dtm, oldPath, newPath);
- listener.favoritesChanged(dtm, oldPath, false);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeRenamed(dtm, oldPath, newPath);
+ listener.favoritesChanged(dtm, oldPath, false);
}
- };
- invokeRunnable(r);
+ });
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
@@ -220,73 +186,67 @@ public class DataTypeManagerChangeListenerHandler implements DataTypeManagerChan
}
@Override
- public void dataTypeReplaced(final DataTypeManager dtm, final DataTypePath oldPath,
- final DataTypePath newPath, final DataType newDataType) {
+ public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath, DataType newDataType) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeReplaced(dtm, oldPath, newPath, newDataType);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeReplaced(dtm, oldPath, newPath, newDataType);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void favoritesChanged(final DataTypeManager dtm, final DataTypePath path,
- final boolean isFavorite) {
+ public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.favoritesChanged(dtm, path, isFavorite);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.favoritesChanged(dtm, path, isFavorite);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void sourceArchiveChanged(final DataTypeManager dataTypeManager,
- final SourceArchive dataTypeSource) {
+ public void sourceArchiveChanged(DataTypeManager dataTypeManager,
+ SourceArchive dataTypeSource) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.sourceArchiveChanged(dataTypeManager, dataTypeSource);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.sourceArchiveChanged(dataTypeManager, dataTypeSource);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void sourceArchiveAdded(final DataTypeManager dataTypeManager,
- final SourceArchive dataTypeSource) {
+ public void sourceArchiveAdded(DataTypeManager dataTypeManager,
+ SourceArchive dataTypeSource) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.sourceArchiveAdded(dataTypeManager, dataTypeSource);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.sourceArchiveAdded(dataTypeManager, dataTypeSource);
}
- };
- invokeRunnable(r);
+ });
+ }
+
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ if (listenerList.isEmpty()) {
+ return;
+ }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.programArchitectureChanged(dataTypeManager);
+ }
+ });
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
index 6a1fed94d9..1a9323c165 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
@@ -22,6 +22,8 @@ import db.DBConstants;
import generic.jar.ResourceFile;
import ghidra.framework.store.db.PackedDBHandle;
import ghidra.framework.store.db.PackedDatabase;
+import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.lang.Language;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
import ghidra.util.exception.*;
@@ -48,15 +50,21 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
/**
* Construct a new DataTypeFileManager using the default data organization.
+ *
+ * NOTE: it may be appropriate to {@link #getWarning() check for warnings} after
+ * opening an existing archive file prior to use. While an archive will remain useable
+ * with a warning condition, architecture-specific data may not be available or up-to-date.
+ *
* @param packedDbfile file to load or create based upon openMode
* @param openMode one of the DBConstants: CREATE, UPDATE, READ_ONLY, UPGRADE
- * @throws IOException
+ * @throws IOException if an IO error occurs
*/
private FileDataTypeManager(ResourceFile packedDbfile, int openMode) throws IOException {
super(validateFilename(packedDbfile), openMode);
file = packedDbfile;
name = getRootName(file.getName());
packedDB = ((PackedDBHandle) dbHandle).getPackedDatabase();
+ reportWarning();
}
private static ResourceFile validateFilename(ResourceFile packedDbfile) {
@@ -70,18 +78,27 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
* Create a new data-type file archive using the default data organization
* @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
* @return data-type manager backed by specified packedDbFile
- * @throws IOException
+ * @throws IOException if an IO error occurs
*/
public static FileDataTypeManager createFileArchive(File packedDbfile) throws IOException {
return new FileDataTypeManager(new ResourceFile(packedDbfile), DBConstants.CREATE);
}
/**
- * Open an existing data-type file archive using the default data organization
+ * Open an existing data-type file archive using the default data organization.
+ *
+ * NOTE: If archive has an assigned architecture, issues may arise due to a revised or
+ * missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
+ * prevent the archive from being opened. Such a warning condition will ne logged and may
+ * result in missing or stale information for existing datatypes which have architecture related
+ * data. In some case it may be appropriate to
+ * {@link FileDataTypeManager#getWarning() check for warnings} on the returned archive
+ * object prior to its use.
+ *
* @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
* @param openForUpdate if true archive will be open for update
* @return data-type manager backed by specified packedDbFile
- * @throws IOException
+ * @throws IOException if an IO error occurs
*/
public static FileDataTypeManager openFileArchive(File packedDbfile, boolean openForUpdate)
throws IOException {
@@ -89,11 +106,20 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
}
/**
- * Open an existing data-type file archive using the default data organization
+ * Open an existing data-type file archive using the default data organization.
+ *
+ * NOTE: If archive has an assigned architecture, issues may arise due to a revised or
+ * missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
+ * prevent the archive from being opened. Such a warning condition will ne logged and may
+ * result in missing or stale information for existing datatypes which have architecture related
+ * data. In some case it may be appropriate to
+ * {@link FileDataTypeManager#getWarning() check for warnings} on the returned archive
+ * object prior to its use.
+ *
* @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
* @param openForUpdate if true archive will be open for update
* @return data-type manager backed by specified packedDbFile
- * @throws IOException
+ * @throws IOException if an IO error occurs
*/
public static FileDataTypeManager openFileArchive(ResourceFile packedDbfile,
boolean openForUpdate) throws IOException {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java
index c1c90571c2..7ce46edeca 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java
@@ -16,7 +16,9 @@
package ghidra.program.model.data;
import ghidra.program.model.listing.FunctionSignature;
+import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.SourceType;
+import ghidra.util.exception.InvalidInputException;
/**
* Defines a function signature for things like function pointers.
@@ -49,12 +51,44 @@ public interface FunctionDefinition extends DataType, FunctionSignature {
*/
public void setVarArgs(boolean hasVarArgs);
+ /**
+ * Set whether or not this function has a return.
+ *
+ * @param hasNoReturn true if this function does not return.
+ */
+ public void setNoReturn(boolean hasNoReturn);
+
/**
* Set the generic calling convention associated with this function definition.
+ *
+ * The total number of unique calling convention names used within a given {@link Program}
+ * or {@link DataTypeManager} may be limited (e.g., 127). When this limit is exceeded an error
+ * will be logged and this setting ignored.
+ *
* @param genericCallingConvention generic calling convention
+ * @deprecated Use of {@link GenericCallingConvention} is deprecated since arbitrary calling
+ * convention names are now supported. {@link #setCallingConvention(String)} should be used.
*/
public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention);
+ /**
+ * Set the calling convention associated with this function definition.
+ *
+ * The total number of unique calling convention names used within a given {@link Program}
+ * or {@link DataTypeManager} may be limited (e.g., 127). When this limit is exceeded an error
+ * will be logged and this setting ignored.
+ *
+ * @param conventionName calling convention name or null. This name is restricted to those
+ * defined by {@link GenericCallingConvention}, the associated compiler specification.
+ * The prototype model declaration name form (e.g., "__stdcall") should be specified as it
+ * appears in a compiler specification (*.cspec). The special "unknown" and "default" names
+ * are also allowed.
+ * @throws InvalidInputException if specified conventionName is not defined by
+ * {@link GenericCallingConvention} or the associated compiler specification if
+ * datatype manager has an associated program architecture.
+ */
+ public void setCallingConvention(String conventionName) throws InvalidInputException;
+
/**
* Replace the given argument with another data type
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinitionDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinitionDataType.java
index 4e518c3108..7a407f70f3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinitionDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinitionDataType.java
@@ -19,11 +19,12 @@ import java.util.ArrayList;
import ghidra.docking.settings.Settings;
import ghidra.program.database.data.DataTypeUtilities;
-import ghidra.program.model.lang.PrototypeModel;
+import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.UniversalID;
+import ghidra.util.exception.InvalidInputException;
/**
* Definition of a function for things like function pointers.
@@ -34,7 +35,8 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
private ParameterDefinition[] params;
private String comment;
private boolean hasVarArgs;
- private GenericCallingConvention genericCallingConvention = GenericCallingConvention.unknown;
+ private boolean hasNoReturn;
+ private String callingConventionName = CompilerSpec.CALLING_CONVENTION_unknown;
public FunctionDefinitionDataType(String name) {
this(CategoryPath.ROOT, name, null, null);
@@ -108,15 +110,9 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
params = paramList.toArray(new ParameterDefinition[paramList.size()]);
hasVarArgs = function.hasVarArgs();
+ hasNoReturn = function.hasNoReturn();
- PrototypeModel prototypeModel = function.getCallingConvention();
-
- if (prototypeModel == null) {
- genericCallingConvention = GenericCallingConvention.unknown;
- }
- else {
- genericCallingConvention = prototypeModel.getGenericCallingConvention();
- }
+ callingConventionName = function.getCallingConventionName();
}
private ParameterDefinition getParameterDefinition(Parameter param, boolean useFormalType,
@@ -140,7 +136,8 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
setReturnType(rtnType.clone(getDataTypeManager()));
setArguments(sig.getArguments());
hasVarArgs = sig.hasVarArgs();
- genericCallingConvention = sig.getGenericCallingConvention();
+ hasNoReturn = sig.hasNoReturn();
+ callingConventionName = sig.getCallingConventionName();
}
@Override
@@ -169,14 +166,58 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
}
@Override
- public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention) {
- this.genericCallingConvention = genericCallingConvention;
+ public void setNoReturn(boolean hasNoReturn) {
+ this.hasNoReturn = hasNoReturn;
}
@Override
- public GenericCallingConvention getGenericCallingConvention() {
- return genericCallingConvention != null ? genericCallingConvention
- : GenericCallingConvention.unknown;
+ public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention) {
+ this.callingConventionName = genericCallingConvention.getDeclarationName();
+ }
+
+ @Override
+ public void setCallingConvention(String conventionName) throws InvalidInputException {
+
+ if (conventionName == null ||
+ CompilerSpec.CALLING_CONVENTION_unknown.equals(conventionName)) {
+ this.callingConventionName = CompilerSpec.CALLING_CONVENTION_unknown;
+ return;
+ }
+ if (CompilerSpec.CALLING_CONVENTION_default.equals(conventionName)) {
+ this.callingConventionName = CompilerSpec.CALLING_CONVENTION_default;
+ return;
+ }
+
+ if (GenericCallingConvention
+ .getGenericCallingConvention(conventionName) != GenericCallingConvention.unknown) {
+ ProgramArchitecture arch = dataMgr != null ? dataMgr.getProgramArchitecture() : null;
+ if (arch != null) {
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ PrototypeModel callingConvention =
+ compilerSpec.getCallingConvention(conventionName);
+ if (callingConvention == null) {
+ throw new InvalidInputException(
+ "Invalid calling convention name: " + conventionName);
+ }
+ }
+ }
+
+ this.callingConventionName = conventionName;
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention() {
+ ProgramArchitecture arch = dataMgr != null ? dataMgr.getProgramArchitecture() : null;
+ if (arch == null) {
+ return null;
+ }
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ return compilerSpec.getCallingConvention(callingConventionName);
+ }
+
+ @Override
+ public String getCallingConventionName() {
+ return callingConventionName;
}
@Override
@@ -227,11 +268,15 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
@Override
public String getPrototypeString(boolean includeCallingConvention) {
StringBuffer buf = new StringBuffer();
+ if (includeCallingConvention && hasNoReturn) {
+ buf.append(NORETURN_DISPLAY_STRING);
+ buf.append(" ");
+ }
buf.append((returnType != null ? returnType.getDisplayName() : "void"));
buf.append(" ");
if (includeCallingConvention &&
- genericCallingConvention != GenericCallingConvention.unknown) {
- buf.append(genericCallingConvention.name());
+ !Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConventionName)) {
+ buf.append(callingConventionName);
buf.append(" ");
}
buf.append(name);
@@ -279,6 +324,11 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
return hasVarArgs;
}
+ @Override
+ public boolean hasNoReturn() {
+ return hasNoReturn;
+ }
+
/**
* Compare the comment of the given function signature to my comment.
*
@@ -316,7 +366,8 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
(DataTypeUtilities.isSameOrEquivalentDataType(signature.getReturnType(),
this.returnType)) &&
(hasVarArgs == signature.hasVarArgs()) &&
- (genericCallingConvention == signature.getGenericCallingConvention())) {
+ (hasNoReturn == signature.hasNoReturn()) &&
+ callingConventionName.equals(signature.getCallingConventionName())) {
ParameterDefinition[] args = signature.getArguments();
if (args.length == this.params.length) {
for (int i = 0; i < args.length; i++) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/GenericCallingConvention.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/GenericCallingConvention.java
index cdd9ab0248..cecd440ecb 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/GenericCallingConvention.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/GenericCallingConvention.java
@@ -21,6 +21,10 @@ import ghidra.program.model.lang.CompilerSpec;
* GenericCallingConvention
identifies the generic calling convention
* associated with a specific function definition. This can be used to help identify
* the appropriate compiler-specific function prototype (i.e., calling convention).
+ *
+ * @deprecated Calling convention name strings should be used instead of this class.
+ * {@link CompilerSpec} provides constants for those included in this enumeration and other
+ * setter/getter methods exist for using the string form.
*/
public enum GenericCallingConvention {
@@ -76,14 +80,11 @@ public enum GenericCallingConvention {
/**
* Returns the GenericCallingConvention corresponding to the specified
- * type string or unknown. Case and underscore prefix is ignored.
- * @param callingConvention calling convention name
- * @return GenericCallingConvention
+ * type string or unknown if name is not defined.
+ * @param callingConvention calling convention declaration name (e.g., "__stdcall")
+ * @return GenericCallingConvention or {@link #unknown} if not found.
*/
public static GenericCallingConvention getGenericCallingConvention(String callingConvention) {
- while (callingConvention.startsWith("_")) {
- callingConvention = callingConvention.substring(1);
- }
for (GenericCallingConvention value : GenericCallingConvention.values()) {
if (value.name().equalsIgnoreCase(callingConvention)) {
return value;
@@ -92,28 +93,6 @@ public enum GenericCallingConvention {
return unknown;
}
- /**
- * Returns the GenericCallingConvention which is likely to correspond with the
- * specified prototype name.
- * @param callingConvention compiler specific calling convention name
- * @return GenericCallingConvention
- */
- public static GenericCallingConvention guessFromName(String callingConvention) {
- if (callingConvention == null) {
- return unknown;
- }
- callingConvention = callingConvention.toLowerCase();
- for (GenericCallingConvention value : GenericCallingConvention.values()) {
- if (value == unknown) {
- continue;
- }
- if (callingConvention.contains(value.name())) {
- return value;
- }
- }
- return unknown;
- }
-
/**
* Returns the GenericCallingConvention corresponding to the specified
* ordinal.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer16DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer16DataType.java
index 132959c615..f37e2d1f90 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer16DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer16DataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* A fixed size 16 byte signed integer (commonly referred to in C as int128_t)
*/
-public class Integer16DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer16DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer16DataType instance.*/
public final static Integer16DataType dataType = new Integer16DataType();
@@ -30,7 +28,7 @@ public class Integer16DataType extends AbstractIntegerDataType {
}
public Integer16DataType(DataTypeManager dtm) {
- super("int16", true, dtm);
+ super("int16", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer3DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer3DataType.java
index 36b682d5b2..cab694606d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer3DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer3DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class Integer3DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer3DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer3DataType instance.*/
public final static Integer3DataType dataType = new Integer3DataType();
@@ -27,7 +25,7 @@ public class Integer3DataType extends AbstractIntegerDataType {
}
public Integer3DataType(DataTypeManager dtm) {
- super("int3", true, dtm);
+ super("int3", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer5DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer5DataType.java
index 8be233505a..6cec0672ea 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer5DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer5DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class Integer5DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer5DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer5DataType instance.*/
public final static Integer5DataType dataType = new Integer5DataType();
@@ -27,7 +25,7 @@ public class Integer5DataType extends AbstractIntegerDataType {
}
public Integer5DataType(DataTypeManager dtm) {
- super("int5", true, dtm);
+ super("int5", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer6DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer6DataType.java
index fe4733b0af..9761bed8b5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer6DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer6DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class Integer6DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer6DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer6DataType instance.*/
public final static Integer6DataType dataType = new Integer6DataType();
@@ -27,7 +25,7 @@ public class Integer6DataType extends AbstractIntegerDataType {
}
public Integer6DataType(DataTypeManager dtm) {
- super("int6", true, dtm);
+ super("int6", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer7DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer7DataType.java
index 135a74f0c5..eacb1dd002 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer7DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer7DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class Integer7DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer7DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer7DataType instance.*/
public final static Integer7DataType dataType = new Integer7DataType();
@@ -27,7 +25,7 @@ public class Integer7DataType extends AbstractIntegerDataType {
}
public Integer7DataType(DataTypeManager dtm) {
- super("int7", true, dtm);
+ super("int7", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IntegerDataType.java
index 61f713916c..10e0019cf6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IntegerDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IntegerDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for an signed Integer dataType
*/
-public class IntegerDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class IntegerDataType extends AbstractSignedIntegerDataType {
/** A statically defined IntegerDataType instance.*/
public final static IntegerDataType dataType = new IntegerDataType();
@@ -30,7 +28,7 @@ public class IntegerDataType extends AbstractIntegerDataType {
}
public IntegerDataType(DataTypeManager dtm) {
- super("int", true, dtm);
+ super("int", dtm);
}
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDataType.java
index 5c310a809e..48796e6b94 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for a Signed Long Integer dataType
*/
-public class LongDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class LongDataType extends AbstractSignedIntegerDataType {
/** A statically defined LongDataType instance.*/
public final static LongDataType dataType = new LongDataType();
@@ -30,29 +28,19 @@ public class LongDataType extends AbstractIntegerDataType {
}
public LongDataType(DataTypeManager dtm) {
- super("long", true, dtm);
+ super("long", dtm);
}
- /**
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getLongSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Signed Long Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongLongDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongLongDataType.java
index 0c8b95dce4..a913b56067 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongLongDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongLongDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for an Signed LongLong Integer dataType
*/
-public class LongLongDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class LongLongDataType extends AbstractSignedIntegerDataType {
/** A statically defined LongLongDataType instance.*/
public final static LongLongDataType dataType = new LongLongDataType();
@@ -30,29 +28,19 @@ public class LongLongDataType extends AbstractIntegerDataType {
}
public LongLongDataType(DataTypeManager dtm) {
- super("longlong", true, dtm);
+ super("longlong", dtm);
}
- /**
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getLongLongSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Signed Long Long Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramArchitectureTranslator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramArchitectureTranslator.java
new file mode 100644
index 0000000000..67a42c6043
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramArchitectureTranslator.java
@@ -0,0 +1,69 @@
+/* ###
+ * 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.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
+import ghidra.program.util.DefaultLanguageService;
+import ghidra.program.util.LanguageTranslatorAdapter;
+
+public class ProgramArchitectureTranslator extends LanguageTranslatorAdapter {
+
+ private CompilerSpec oldCompilerSpec;
+ private CompilerSpec newCompilerSpec;
+
+ public ProgramArchitectureTranslator(Language oldLanguage, CompilerSpecID oldCompilerSpecId,
+ Language newLanguage, CompilerSpecID newCompilerSpecId)
+ throws CompilerSpecNotFoundException, IncompatibleLanguageException {
+ super(oldLanguage, newLanguage);
+ if (!oldLanguage.getProcessor().equals(newLanguage.getProcessor())) {
+ throw new IncompatibleLanguageException("Architecture processors differ: " +
+ oldLanguage.getProcessor() + " vs " + newLanguage.getProcessor());
+ }
+ this.oldCompilerSpec = oldLanguage.getCompilerSpecByID(oldCompilerSpecId);
+ this.newCompilerSpec = newLanguage.getCompilerSpecByID(newCompilerSpecId);
+ validateDefaultSpaceMap();
+ }
+
+ public ProgramArchitectureTranslator(LanguageID oldLanguageId, int oldLanguageVersion,
+ CompilerSpecID oldCompilerSpecId, Language newLanguage,
+ CompilerSpecID newCompilerSpecId)
+ throws LanguageNotFoundException, CompilerSpecNotFoundException,
+ IncompatibleLanguageException {
+ this(getLanguage(oldLanguageId, oldLanguageVersion), oldCompilerSpecId, newLanguage,
+ newCompilerSpecId);
+ }
+
+ private static Language getLanguage(LanguageID languageId, int languageVersion)
+ throws LanguageNotFoundException {
+ Language language = DefaultLanguageService.getLanguageService().getLanguage(languageId);
+ if (languageVersion > 0 && language.getVersion() != languageVersion) {
+ throw new LanguageNotFoundException(
+ "Language not found for '" + languageId + "' version " + languageVersion + ".x");
+ }
+ return language;
+ }
+
+ public CompilerSpec getOldCompilerSpec() {
+ return oldCompilerSpec;
+ }
+
+ public CompilerSpec getNewCompilerSpec() {
+ return newCompilerSpec;
+ }
+
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/QWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/QWordDataType.java
index de85f83a9a..6de4d09765 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/QWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/QWordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a definition of a Quad Word within a program.
*/
-public class QWordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class QWordDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined QWordDataType instance.*/
public final static QWordDataType dataType = new QWordDataType();
@@ -30,7 +28,7 @@ public class QWordDataType extends AbstractIntegerDataType {
}
public QWordDataType(DataTypeManager dtm) {
- super("qword", false, dtm);
+ super("qword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ShortDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ShortDataType.java
index dd1ac9e3e4..83ce54f9ba 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ShortDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ShortDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for a Short Integer dataType
*/
-public class ShortDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class ShortDataType extends AbstractSignedIntegerDataType {
/** A statically defined ShortDataType instance.*/
public final static ShortDataType dataType = new ShortDataType();
@@ -30,29 +28,19 @@ public class ShortDataType extends AbstractIntegerDataType {
}
public ShortDataType(DataTypeManager dtm) {
- super("short", true, dtm);
+ super("short", dtm);
}
- /**
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getShortSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Signed Short Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedByteDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedByteDataType.java
index 50b96dd33b..f41f444b13 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedByteDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedByteDataType.java
@@ -20,9 +20,7 @@ import ghidra.program.model.lang.DecompilerLanguage;
/**
* Provides a definition of a Signed Byte within a program.
*/
-public class SignedByteDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class SignedByteDataType extends AbstractSignedIntegerDataType {
/** A statically defined SignedByteDataType instance.*/
public final static SignedByteDataType dataType = new SignedByteDataType();
@@ -32,7 +30,7 @@ public class SignedByteDataType extends AbstractIntegerDataType {
}
public SignedByteDataType(DataTypeManager dtm) {
- super("sbyte", true, dtm);
+ super("sbyte", dtm);
}
@Override
@@ -52,8 +50,9 @@ public class SignedByteDataType extends AbstractIntegerDataType {
@Override
public String getDecompilerDisplayName(DecompilerLanguage language) {
- if (language == DecompilerLanguage.JAVA_LANGUAGE)
+ if (language == DecompilerLanguage.JAVA_LANGUAGE) {
return "byte";
+ }
return name;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedCharDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedCharDataType.java
index e79ef3bcf3..2ef633df67 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedCharDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedCharDataType.java
@@ -22,7 +22,6 @@ package ghidra.program.model.data;
* associated data type manager.
*/
public class SignedCharDataType extends CharDataType {
- private final static long serialVersionUID = 1;
public static final SignedCharDataType dataType = new SignedCharDataType();
@@ -34,7 +33,12 @@ public class SignedCharDataType extends CharDataType {
}
public SignedCharDataType(DataTypeManager dtm) {
- super("schar", true, dtm);
+ super("schar", dtm);
+ }
+
+ @Override
+ public boolean isSigned() {
+ return true;
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedDWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedDWordDataType.java
index b1e5e1a3de..fbcf50ebd2 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedDWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedDWordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a definition of a Signed Double Word within a program.
*/
-public class SignedDWordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class SignedDWordDataType extends AbstractSignedIntegerDataType {
/** A statically defined SignedDWordDataType instance.*/
public final static SignedDWordDataType dataType = new SignedDWordDataType();
@@ -30,7 +28,7 @@ public class SignedDWordDataType extends AbstractIntegerDataType {
}
public SignedDWordDataType(DataTypeManager dtm) {
- super("sdword", true, dtm);
+ super("sdword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedQWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedQWordDataType.java
index 1a2800f0f8..c81df3d093 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedQWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedQWordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a definition of a Signed Quad Word within a program.
*/
-public class SignedQWordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class SignedQWordDataType extends AbstractSignedIntegerDataType {
/** A statically defined SignedQWordDataType instance.*/
public final static SignedQWordDataType dataType = new SignedQWordDataType();
@@ -30,7 +28,7 @@ public class SignedQWordDataType extends AbstractIntegerDataType {
}
public SignedQWordDataType(DataTypeManager dtm) {
- super("sqword", true, dtm);
+ super("sqword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedWordDataType.java
index 7e909ce939..ed6dad3ef0 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedWordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a basic implementation of a signed word datatype
*/
-public class SignedWordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class SignedWordDataType extends AbstractSignedIntegerDataType {
/** A statically defined SignedWordDataType instance.*/
public final static SignedWordDataType dataType = new SignedWordDataType();
@@ -30,7 +28,7 @@ public class SignedWordDataType extends AbstractIntegerDataType {
}
public SignedWordDataType(DataTypeManager dtm) {
- super("sword", true, dtm);
+ super("sword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java
index 9ee458c209..e25c6d4b99 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java
@@ -15,26 +15,100 @@
*/
package ghidra.program.model.data;
+import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
-import db.Transaction;
-import db.DBConstants;
+import javax.help.UnsupportedOperationException;
+
+import com.google.common.collect.ImmutableList;
+
+import db.*;
+import db.util.ErrorHandler;
import generic.jar.ResourceFile;
+import ghidra.framework.store.LockException;
+import ghidra.program.database.DBStringMapAdapter;
+import ghidra.program.database.ProgramAddressFactory;
import ghidra.program.database.data.DataTypeManagerDB;
-import ghidra.util.InvalidNameException;
+import ghidra.program.database.symbol.VariableStorageManager;
+import ghidra.program.database.symbol.VariableStorageManagerDB;
+import ghidra.program.model.address.AddressFactory;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
+import ghidra.program.util.DefaultLanguageService;
+import ghidra.program.util.LanguageTranslator;
+import ghidra.util.*;
+import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
* Basic implementation of the DataTypeManger interface
*/
-public class StandAloneDataTypeManager extends DataTypeManagerDB {
+public class StandAloneDataTypeManager extends DataTypeManagerDB implements Closeable {
+
+ private static final String LANGUAGE_VERSION = "Language Version"; // major version only
+ private static final String LANGUAGE_ID = "Language ID";
+ private static final String COMPILER_SPEC_ID = "Compiler Spec ID";
- protected String name;
private int transactionCount;
private Long transaction;
private boolean commitTransaction;
+ private LanguageTranslator languageUpgradeTranslator;
+ private String programArchitectureSummary; // summary of expected program architecture
+
+ protected String name;
+
+ public static enum ArchiveWarning {
+ /**
+ * {@link #NONE} indicates a normal archive condition
+ */
+ NONE,
+
+ /**
+ * {@link #UPGRADED_LANGUAGE_VERSION} indicates an archive which has been open for update
+ * was upgraded to a newer language version. This is expected when the {@link Language}
+ * required by the associated {@link ProgramArchitecture} has a major version change
+ * which involves significant {@link Register} changes. Sharing an upgraded archive
+ * may impact others who do not have access to the updated {@link Language} module.
+ */
+ UPGRADED_LANGUAGE_VERSION,
+
+ // programArchitectureSummary must be set for the warnings below
+
+ /**
+ * {@link #LANGUAGE_NOT_FOUND} indicates the {@link Language} or its appropriate version,
+ * required by the associated {@link ProgramArchitecture}, was not found or encountered
+ * a problem being loaded. The {@link FileDataTypeManager#getWarningDetail()} may provide
+ * additional insight to the underlying cause.
+ */
+ LANGUAGE_NOT_FOUND,
+
+ /**
+ * {@link #COMPILER_SPEC_NOT_FOUND} indicates the {@link CompilerSpec},
+ * required by the associated {@link ProgramArchitecture}, was not found or encountered
+ * a problem being loaded. The {@link FileDataTypeManager#getWarningDetail()} may provide
+ * additional insight to the underlying cause. This condition can only occur if the
+ * required {@link Language} was found.
+ */
+ COMPILER_SPEC_NOT_FOUND,
+
+ /**
+ * {@link #LANGUAGE_UPGRADE_REQURED} indicates an archive which has been open read-only
+ * requires an upgraded to a newer language version. This is expected when the
+ * {@link Language} required by the associated {@link ProgramArchitecture} has a major
+ * version change within the current installation. Major version changes for a
+ * {@link Language} rarely occur but are required when significant {@link Register}
+ * or addressing changes have been made. Upgrading a shared archive may impact others
+ * who do not have access to the updated {@link Language} module and should be
+ * coordinated with others who may be affected.
+ */
+ LANGUAGE_UPGRADE_REQURED,
+ }
+
+ private ArchiveWarning warning;
+ private Exception warningDetail;
+
/**
* Constructor for new temporary data-type manager using the default DataOrganization.
* Note that this manager does not support the save or saveAs operation.
@@ -59,6 +133,12 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
/**
* Constructor for a data-type manager backed by a packed database file.
* When opening for UPDATE an automatic upgrade will be performed if required.
+ *
+ * NOTE: {@link #reportWarning()} should be invoked immediately after
+ * instantiating a {@link StandAloneDataTypeManager} for an existing database after
+ * {@link #getName()} and {@link #getPath()} can be invoked safely. In addition, it
+ * may be appropriate to use {@link #getWarning() check for warnings} prior to use.
+ *
* @param packedDbfile packed datatype archive file (i.e., *.gdt resource).
* @param openMode open mode CREATE, READ_ONLY or UPDATE (see {@link DBConstants})
* @throws IOException a low-level IO error. This exception may also be thrown
@@ -69,6 +149,579 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
super(packedDbfile, openMode);
}
+ /**
+ * Constructor for a data-type manager using a specified DBHandle.
+ *
+ * NOTE: {@link #reportWarning()} should be invoked immediately after
+ * instantiating a {@link StandAloneDataTypeManager} for an existing database after
+ * {@link #getName()} and {@link #getPath()} can be invoked safely. In addition, it
+ * may be appropriate to use {@link #getWarning() check for warnings} prior to use.
+ *
+ * @param handle open database handle
+ * @param openMode the program open mode
+ * @param errHandler the database I/O error handler
+ * @param lock the program synchronization lock
+ * @param monitor the progress monitor
+ * @throws CancelledException if the user cancels an upgrade
+ * @throws VersionException if the database does not match the expected version.
+ * @throws IOException if a database I/O error occurs.
+ */
+ protected StandAloneDataTypeManager(DBHandle handle, int openMode, ErrorHandler errHandler,
+ Lock lock, TaskMonitor monitor)
+ throws CancelledException, VersionException, IOException {
+ super(handle, null, openMode, null, errHandler, lock, monitor);
+ }
+
+ /**
+ * Get the {@link ArchiveWarning} which may have occured immediately following
+ * instatiation of this {@link StandAloneDataTypeManager}. {@link ArchiveWarning#NONE}
+ * will be returned if not warning condition.
+ * @return warning type.
+ */
+ public ArchiveWarning getWarning() {
+ return warning;
+ }
+
+ /**
+ * Get the detail exception associated with {@link ArchiveWarning#LANGUAGE_NOT_FOUND} or
+ * {@link ArchiveWarning#COMPILER_SPEC_NOT_FOUND} warning (see {@link #getWarning()})
+ * immediately following instatiation of this {@link StandAloneDataTypeManager}.
+ * @return warning detail exception or null
+ */
+ public Exception getWarningDetail() {
+ return warningDetail;
+ }
+
+ /**
+ * Due to the supression of error and warning conditions during instantiation this method should
+ * be invoked at the end of instatiation when {@link #getName()} and {@link #getPath()} are
+ * ready to be invoked safely. Logging will be performed via {@link Msg}.
+ */
+ protected void reportWarning() {
+ String msg;
+ switch (warning) {
+ case NONE:
+ break;
+ case LANGUAGE_NOT_FOUND:
+ msg = "Language not found for Archive '" + getName() + "': " +
+ warningDetail.getMessage();
+ Msg.error(this, msg);
+ break;
+ case COMPILER_SPEC_NOT_FOUND:
+ msg = "Compiler specification not found for Archive '" + getName() + "': " +
+ warningDetail.getMessage();
+ Msg.error(this, msg);
+ break;
+ case LANGUAGE_UPGRADE_REQURED:
+ msg = "Language upgrade required for Archive '" + getName() + "': " +
+ programArchitectureSummary;
+ Msg.warn(this, msg);
+ break;
+ case UPGRADED_LANGUAGE_VERSION:
+ ProgramArchitecture arch = getProgramArchitecture();
+ LanguageDescription languageDescription =
+ arch.getLanguage().getLanguageDescription();
+ msg =
+ "Upgraded program-architecture for Archive: '" + getName() +
+ "'\n Language: " +
+ languageDescription.getLanguageID() + " Version " +
+ languageDescription.getVersion() + ".x" +
+ ", CompilerSpec: " + arch.getCompilerSpec().getCompilerSpecID();
+ Msg.info(this, msg);
+ }
+
+ }
+
+ @Override
+ protected void initializeOtherAdapters(int openMode, TaskMonitor monitor)
+ throws CancelledException, IOException, VersionException {
+
+ warning = ArchiveWarning.NONE;
+ if (openMode == DBConstants.CREATE) {
+ return; // optional program architecture is set after initialization is complete
+ }
+
+ // Check for optional program architecture data (LanguageID, etc.)
+ // The DB data map is also used by the base implementation to store the data organization
+ DBStringMapAdapter dataMap = getDataMap(false);
+ if (dataMap == null) {
+ return;
+ }
+
+ String languageIdStr = dataMap.get(LANGUAGE_ID);
+ if (languageIdStr == null) {
+ return; // assume architecture info is missing
+ }
+ LanguageID languageId = new LanguageID(languageIdStr);
+ CompilerSpecID compilerSpecId = new CompilerSpecID(dataMap.get(COMPILER_SPEC_ID));
+ int languageVersion = 1;
+ try {
+ languageVersion = Integer.parseInt(dataMap.get(LANGUAGE_VERSION));
+ }
+ catch (Exception e) {
+ // Ignore
+ }
+
+ VariableStorageManagerDB variableStorageMgr = null;
+ if (VariableStorageManagerDB.exists(dbHandle)) {
+ variableStorageMgr =
+ new VariableStorageManagerDB(dbHandle, null, openMode, errHandler, lock, monitor);
+ }
+
+ programArchitectureSummary =
+ getProgramArchitectureSummary(languageId, languageVersion, compilerSpecId);
+
+ Language language = null;
+ LanguageVersionException languageVersionExc = null;
+ try {
+ language = DefaultLanguageService.getLanguageService().getLanguage(languageId);
+ languageVersionExc =
+ LanguageVersionException.check(language, languageVersion, -1); // don't care about minor version
+ }
+ catch (LanguageNotFoundException e) {
+ warning = ArchiveWarning.LANGUAGE_NOT_FOUND;
+ warningDetail = e;
+ try {
+ languageVersionExc =
+ LanguageVersionException.checkForLanguageChange(e, languageId, languageVersion);
+ }
+ catch (LanguageNotFoundException e2) {
+ // Missing language or language translation
+ warningDetail = e2;
+ return; // allow archive to open without error
+ }
+ }
+
+ if (languageVersionExc != null && !languageVersionExc.isUpgradable()) {
+ // Inability to translate language treated like language-not-found
+ warning = ArchiveWarning.LANGUAGE_NOT_FOUND;
+ warningDetail = languageVersionExc;
+ }
+ else if (languageVersionExc != null) {
+ warning = ArchiveWarning.LANGUAGE_UPGRADE_REQURED;
+ languageUpgradeTranslator = languageVersionExc.getLanguageTranslator();
+
+ // language upgrade required
+ if (openMode == DBConstants.READ_ONLY) {
+ // read-only mode - do not set program architecture - upgrade flag has been set
+ return;
+ }
+
+ if (openMode == DBConstants.UPDATE) {
+ throw languageVersionExc;
+ }
+
+ // else UPGRADE mode falls-through
+ language = languageUpgradeTranslator.getNewLanguage();
+ compilerSpecId = languageUpgradeTranslator.getNewCompilerSpecID(compilerSpecId);
+ }
+
+ assert (language != null);
+
+ CompilerSpec compilerSpec;
+ try {
+ compilerSpec = language.getCompilerSpecByID(compilerSpecId);
+ }
+ catch (CompilerSpecNotFoundException e) {
+ warning = ArchiveWarning.COMPILER_SPEC_NOT_FOUND;
+ warningDetail = e;
+ return; // allow archive to open without error
+ }
+
+ if (warning == ArchiveWarning.LANGUAGE_UPGRADE_REQURED) {
+
+ if (variableStorageMgr != null) {
+ variableStorageMgr.setLanguage(languageUpgradeTranslator, monitor);
+ }
+
+ // update data map with language upgrade info
+ dataMap.put(LANGUAGE_ID, language.getLanguageID().getIdAsString());
+ dataMap.put(LANGUAGE_VERSION, Integer.toString(language.getVersion()));
+ dataMap.put(COMPILER_SPEC_ID, compilerSpecId.getIdAsString());
+
+ warning = ArchiveWarning.UPGRADED_LANGUAGE_VERSION;
+ }
+
+ programArchitectureSummary = null; // not needed
+
+ final Language lang = language;
+ final CompilerSpec cspec = compilerSpec;
+ final AddressFactory addrFactory = new ProgramAddressFactory(lang, cspec);
+
+ super.setProgramArchitecture(new ProgramArchitecture() {
+
+ @Override
+ public Language getLanguage() {
+ return lang;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return cspec;
+ }
+
+ @Override
+ public AddressFactory getAddressFactory() {
+ return addrFactory;
+ }
+ }, variableStorageMgr, false, monitor);
+
+ if (variableStorageMgr != null) {
+ variableStorageMgr.setProgramArchitecture(getProgramArchitecture());
+ }
+
+ }
+
+ /**
+ * Get the program architecture information which has been associated with this
+ * datatype manager. If {@link #getProgramArchitecture()} returns null this method
+ * may still return information if the program architecture was set on an archive
+ * and either {@link #isProgramArchitectureMissing()} or
+ * {@link #isProgramArchitectureUpgradeRequired()} returns true.
+ * @return program architecture summary if it has been set
+ */
+ @Override
+ public String getProgramArchitectureSummary() {
+ if (programArchitectureSummary != null) {
+ return programArchitectureSummary;
+ }
+ return super.getProgramArchitectureSummary();
+ }
+
+ /**
+ * Delete all program architecture related data in response to an
+ * architecture change when all related data should be removed.
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if task cancelled
+ */
+ private void deleteAllProgramArchitectureData(TaskMonitor monitor)
+ throws IOException, CancelledException {
+
+ clearCustomStorageUse(monitor);
+
+ DBStringMapAdapter dataMap = getDataMap(false);
+ if (dataMap != null) {
+ dataMap.delete(LANGUAGE_ID);
+ dataMap.delete(LANGUAGE_VERSION);
+ dataMap.delete(COMPILER_SPEC_ID);
+ }
+
+ VariableStorageManagerDB.delete(dbHandle);
+
+ warning = ArchiveWarning.NONE;
+ programArchitectureSummary = null;
+ }
+
+ private VariableStorageManagerDB createProgramArchitectureData(
+ ProgramArchitecture programArchitecture, VariableStorageManagerDB variableStorageMgr)
+ throws IOException {
+ Language newLanguage = programArchitecture.getLanguage();
+ LanguageID newLanguageId = newLanguage.getLanguageID();
+ CompilerSpec newCompilerSpec = programArchitecture.getCompilerSpec();
+ CompilerSpecID newCmpilerSpecID = newCompilerSpec.getCompilerSpecID();
+
+ DBStringMapAdapter dataMap = getDataMap(true);
+ dataMap.put(LANGUAGE_ID, newLanguageId.getIdAsString());
+ dataMap.put(COMPILER_SPEC_ID, newCmpilerSpecID.getIdAsString());
+ dataMap.put(LANGUAGE_VERSION, Integer.toString(newLanguage.getVersion())); // major version only
+
+ if (variableStorageMgr == null) { // TODO: may re-use if translation performed
+ try {
+ variableStorageMgr = new VariableStorageManagerDB(dbHandle, null,
+ DBConstants.CREATE, errHandler, lock, TaskMonitor.DUMMY);
+ variableStorageMgr.setProgramArchitecture(programArchitecture);
+ }
+ catch (VersionException | CancelledException e) {
+ throw new AssertException(e); // unexpected
+ }
+ }
+
+ variableStorageMgr.setProgramArchitecture(programArchitecture);
+
+ warning = ArchiveWarning.NONE;
+ programArchitectureSummary = null;
+
+ return variableStorageMgr;
+ }
+
+ /**
+ * Indicates that an program architecture upgrade is required in order
+ * to constitute associated data. If true, the associated archive
+ * must be open for update to allow the upgrade to complete, or a new
+ * program architecture may be set/cleared if such an operation is supported.
+ * @return true if a program architecture upgrade is required, else false
+ */
+ public boolean isProgramArchitectureUpgradeRequired() {
+ return warning == ArchiveWarning.LANGUAGE_UPGRADE_REQURED;
+ }
+
+ /**
+ * Indicates that a failure occured establishing the program architecture
+ * for the associated archive.
+ * @return true if a failure occured establishing the program architecture
+ */
+ public boolean isProgramArchitectureMissing() {
+ return warning == ArchiveWarning.LANGUAGE_NOT_FOUND ||
+ warning == ArchiveWarning.COMPILER_SPEC_NOT_FOUND;
+ }
+
+
+ /**
+ * Clear the program architecture setting and all architecture-specific data from this archive.
+ * Archive will revert to using the default {@link DataOrganization}.
+ * Archive must be open for update for this method to be used.
+ * @param monitor task monitor
+ * @throws CancelledException if task cancelled. If thrown, this data type manager is no longer
+ * stable and should be closed without saving.
+ * @throws IOException if IO error occurs
+ * @throws LockException failure if exclusive access is required
+ * @throws UnsupportedOperationException if architecture change is not permitted by
+ * implementation (e.g., {@link BuiltInDataTypeManager}).
+ */
+ public void clearProgramArchitecture(TaskMonitor monitor)
+ throws CancelledException, IOException, LockException {
+ lock.acquire();
+ try {
+
+ if (!isArchitectureChangeAllowed()) {
+ throw new UnsupportedOperationException(
+ "Program-architecture change not permitted");
+ }
+
+ if (!dbHandle.canUpdate()) {
+ throw new ReadOnlyException("Read-only Archive: " + getName());
+ }
+
+ if (getProgramArchitecture() == null && !isProgramArchitectureMissing()) {
+ return;
+ }
+
+ Msg.info(this, "Removing program-architecture for Archive: " + getName());
+
+ int txId = startTransaction("Remove Program Architecture");
+ try {
+ if (!isArchitectureChangeAllowed()) {
+ throw new UnsupportedOperationException(
+ "Program-architecture change not permitted");
+ }
+ deleteAllProgramArchitectureData(monitor);
+
+ super.setProgramArchitecture((ProgramArchitecture) null, null, true, monitor);
+ }
+ finally {
+ // TODO: ensure state is restored if transaction rollback/cancel occurs
+ endTransaction(txId, !monitor.isCancelled());
+ }
+
+ defaultListener.programArchitectureChanged(this);
+ }
+ finally {
+ invalidateCache();
+ lock.release();
+ }
+ }
+
+ public static enum LanguageUpdateOption {
+ /**
+ * All existing storage data should be cleared
+ */
+ CLEAR,
+ /**
+ * An attempt should be made to translate from old-to-new language.
+ * This has limitations (i.e., similar architecture) and may result in
+ * poor register mappings.
+ */
+ TRANSLATE,
+ /**
+ * Variable storage data will be retained as-is but may not de-serialize
+ * properly when used.
+ */
+ UNCHANGED // TODO: Need to test to see if this option is safe and useable
+ }
+
+ /**
+ * Establish the program architecture for this datatype manager. The current setting can be
+ * determined from {@link #getProgramArchitecture()}. Archive must be open for update for
+ * this method to be used.
+ * @param language language
+ * @param compilerSpecId compiler specification ID defined by the language.
+ * @param updateOption indicates how variable storage data should be transitioned. If {@link #isProgramArchitectureMissing()}
+ * is true and {@link LanguageUpdateOption#TRANSLATE} specified, the translator will be based on whatever language version can
+ * be found. In this situation it may be best to force a {@link LanguageUpdateOption#CLEAR}.
+ * @param monitor task monitor (cancel not permitted to avoid corrupt state)
+ * @throws CompilerSpecNotFoundException if invalid compilerSpecId specified for language
+ * @throws LanguageNotFoundException if current language is not found (if required for data transition)
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if task cancelled. If thrown, this data type manager is no longer
+ * stable and should be closed without saving.
+ * @throws LockException failure if exclusive access is required
+ * @throws UnsupportedOperationException if architecture change is not permitted
+ * @throws IncompatibleLanguageException if translation requested but not possible due to incompatible language architectures
+ */
+ public void setProgramArchitecture(Language language, CompilerSpecID compilerSpecId,
+ LanguageUpdateOption updateOption, TaskMonitor monitor)
+ throws CompilerSpecNotFoundException, LanguageNotFoundException, IOException,
+ CancelledException, LockException, UnsupportedOperationException,
+ IncompatibleLanguageException {
+
+ lock.acquire();
+ try {
+
+ if (!isArchitectureChangeAllowed()) {
+ throw new UnsupportedOperationException(
+ "Program-architecture change not permitted");
+ }
+
+ if (!dbHandle.canUpdate()) {
+ throw new ReadOnlyException("Read-only Archive: " + getName());
+ }
+
+ Msg.info(this,
+ "Updating program-architecture for Archive: " + getName() + "\n Language: " +
+ language.getLanguageID() + " version " + language.getVersion() + ".x" +
+ ", CompilerSpec: " + compilerSpecId);
+
+ CompilerSpec compilerSpec = language.getCompilerSpecByID(compilerSpecId);
+
+ // This type of datatype manager only uses VariableStorageManagerDB
+ VariableStorageManagerDB variableStorageMgr =
+ (VariableStorageManagerDB) getVariableStorageManager();
+
+ int txId = startTransaction("Set Program Architecture");
+ try {
+ ProgramArchitectureTranslator translator = null;
+
+ ProgramArchitecture oldArch = getProgramArchitecture();
+ if (oldArch != null || isProgramArchitectureMissing()) {
+
+ if (updateOption == LanguageUpdateOption.CLEAR) {
+ deleteAllProgramArchitectureData(monitor);
+ variableStorageMgr = null;
+ }
+ else if (isProgramArchitectureMissing()) {
+
+ assert (variableStorageMgr == null);
+
+ if (updateOption == LanguageUpdateOption.TRANSLATE) {
+ // Go out on a limb and use any version of old language if available
+ DBStringMapAdapter dataMap = getDataMap(false);
+ LanguageID oldLanguageId =
+ new LanguageID(getDataMap(false).get(LANGUAGE_ID));
+ CompilerSpecID oldCompilerSpecId =
+ new CompilerSpecID(dataMap.get(COMPILER_SPEC_ID));
+ translator = new ProgramArchitectureTranslator(oldLanguageId, -1,
+ oldCompilerSpecId, language, compilerSpecId);
+ }
+
+ if (VariableStorageManagerDB.exists(dbHandle)) {
+ try {
+ variableStorageMgr = new VariableStorageManagerDB(dbHandle, null,
+ DBConstants.UPDATE, errHandler, lock, monitor);
+ }
+ catch (VersionException e) {
+ throw new IOException(
+ "Unexpected version error for VariableStorageManagerDB");
+ }
+ }
+ }
+ else if (updateOption == LanguageUpdateOption.TRANSLATE) {
+ translator = new ProgramArchitectureTranslator(oldArch.getLanguage(),
+ oldArch.getCompilerSpec().getCompilerSpecID(), language,
+ compilerSpecId);
+ }
+
+ if (translator != null && variableStorageMgr != null) {
+ variableStorageMgr.setLanguage(translator, monitor);
+ }
+ }
+
+ ProgramArchitecture programArchitecture = new ProgramArchitecture() {
+
+ @Override
+ public Language getLanguage() {
+ return language;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return compilerSpec;
+ }
+
+ @Override
+ public AddressFactory getAddressFactory() {
+ return language.getAddressFactory();
+ }
+ };
+
+ variableStorageMgr =
+ createProgramArchitectureData(programArchitecture, variableStorageMgr);
+
+ super.setProgramArchitecture(programArchitecture, variableStorageMgr, true,
+ monitor);
+ }
+ finally {
+ // TODO: ensure state is restored if transaction rollback/cancel occurs
+ endTransaction(txId, !monitor.isCancelled());
+ }
+
+ defaultListener.programArchitectureChanged(this);
+ }
+ finally {
+ invalidateCache();
+ lock.release();
+ }
+ }
+
+ /**
+ * Set the architecture-specific details associated with a new datatype manager.
+ * This method is intended to be used during instantiation of derived implementations.
+ * @param programArchitecture program architecture details (required)
+ * @param variableStorageMgr variable storage manager. Must be null.
+ * @param store if true database update will occur and datatypes will be updated if
+ * any change to the data organization is detected (a stored copy may be used to
+ * detect this condition). This should never be passed as true if opened read-only.
+ * If true and no variable storage is specified it will be created.
+ * @param monitor task monitor
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if task cancelled
+ * @throws UnsupportedOperationException if language was previously set
+ */
+ @Override
+ protected void setProgramArchitecture(ProgramArchitecture programArchitecture,
+ VariableStorageManager variableStorageMgr, boolean store, TaskMonitor monitor)
+ throws IOException, CancelledException {
+
+ // TODO: Determine if cancelling can leave in bad state
+
+ if (programArchitecture == null) {
+ throw new IllegalArgumentException("ProgramArchitecture must be specified");
+ }
+ if (variableStorageMgr != null) {
+ throw new IllegalArgumentException("VariableStorageManager may not be specified");
+ }
+
+ if (getProgramArchitecture() != null || isProgramArchitectureUpgradeRequired() ||
+ isProgramArchitectureMissing()) {
+ throw new UnsupportedOperationException(
+ "Program-architecture change not permitted with this method");
+ }
+
+ if (store) {
+ variableStorageMgr = createProgramArchitectureData(programArchitecture, null);
+ }
+
+ // super handles possible change to data organization and update if store is true
+ super.setProgramArchitecture(programArchitecture, variableStorageMgr, store, monitor);
+ }
+
+ /**
+ * Determine if a program architecture change is permitted
+ * @return true if change allowed else false if disallowed
+ */
+ protected boolean isArchitectureChangeAllowed() {
+ return true;
+ }
+
@Override
public String getName() {
return name;
@@ -83,12 +736,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
defaultListener.categoryRenamed(this, CategoryPath.ROOT, CategoryPath.ROOT);
}
-
- @Override
- public final DataOrganization getDataOrganization() {
- return super.getDataOrganization();
- }
-
+
@Override
public Transaction openTransaction(String description) throws IllegalStateException {
return new Transaction() {
@@ -173,8 +821,13 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
return null;
}
+ /**
+ * Get the path name associated with the storage of this stand alone
+ * datatype manager.
+ * @return path name or null if not applicable
+ */
@Override
- protected String getPath() {
+ public String getPath() {
return null;
}
@@ -182,4 +835,30 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
public ArchiveType getType() {
return ArchiveType.TEST;
}
+
+ /**
+ * Update custom storage for function definitions to be unassigned.
+ * @param monitor task monitor
+ * @throws CancelledException if task cancelled
+ */
+ private void clearCustomStorageUse(TaskMonitor monitor) throws CancelledException {
+
+ // Get copy of all function defs to avoid concurrent modification of underlaying table
+ ImmutableList defs = ImmutableList.copyOf(getAllFunctionDefinitions());
+
+ monitor.initialize(defs.size());
+ monitor.setMessage("Clear custom storage use...");
+
+// for (FunctionDefinition def : ImmutableList.copyOf(getAllFunctionDefinitions())) {
+ monitor.checkCanceled();
+// monitor.incrementProgress(1);
+//
+// // TODO: update function definition
+// if (def.hasCustomStorage()) {
+//
+//
+// }
+// }
+
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedCharDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedCharDataType.java
index cc088cf221..1b9f27d0ad 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedCharDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedCharDataType.java
@@ -34,7 +34,12 @@ public class UnsignedCharDataType extends CharDataType {
}
public UnsignedCharDataType(DataTypeManager dtm) {
- super("uchar", false, dtm);
+ super("uchar", dtm);
+ }
+
+ @Override
+ public boolean isSigned() {
+ return false;
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger16DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger16DataType.java
index 883f75815d..09bb37dc20 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger16DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger16DataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* A fixed size 16 byte unsigned integer (commonly referred to in C as uint128_t)
*/
-public class UnsignedInteger16DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger16DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger16DataType instance.*/
public final static UnsignedInteger16DataType dataType = new UnsignedInteger16DataType();
@@ -30,7 +28,7 @@ public class UnsignedInteger16DataType extends AbstractIntegerDataType {
}
public UnsignedInteger16DataType(DataTypeManager dtm) {
- super("uint16", false, dtm);
+ super("uint16", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger3DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger3DataType.java
index e9ac687917..eb1ee6c391 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger3DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger3DataType.java
@@ -17,9 +17,7 @@ package ghidra.program.model.data;
import ghidra.util.classfinder.ClassTranslator;
-public class UnsignedInteger3DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger3DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger3DataType instance.*/
public final static UnsignedInteger3DataType dataType = new UnsignedInteger3DataType();
@@ -34,7 +32,7 @@ public class UnsignedInteger3DataType extends AbstractIntegerDataType {
}
public UnsignedInteger3DataType(DataTypeManager dtm) {
- super("uint3", false, dtm);
+ super("uint3", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger5DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger5DataType.java
index 6acdeb20e9..c0001cc35d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger5DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger5DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class UnsignedInteger5DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger5DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger5DataType instance.*/
public final static UnsignedInteger5DataType dataType = new UnsignedInteger5DataType();
@@ -27,7 +25,7 @@ public class UnsignedInteger5DataType extends AbstractIntegerDataType {
}
public UnsignedInteger5DataType(DataTypeManager dtm) {
- super("uint5", false, dtm);
+ super("uint5", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger6DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger6DataType.java
index e98562d40f..e952b0e144 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger6DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger6DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class UnsignedInteger6DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger6DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger6DataType instance.*/
public final static UnsignedInteger6DataType dataType = new UnsignedInteger6DataType();
@@ -27,7 +25,7 @@ public class UnsignedInteger6DataType extends AbstractIntegerDataType {
}
public UnsignedInteger6DataType(DataTypeManager dtm) {
- super("uint6", false, dtm);
+ super("uint6", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger7DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger7DataType.java
index 381c790f14..b69b0d2123 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger7DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger7DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class UnsignedInteger7DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger7DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger7DataType instance.*/
public final static UnsignedInteger7DataType dataType = new UnsignedInteger7DataType();
@@ -27,7 +25,7 @@ public class UnsignedInteger7DataType extends AbstractIntegerDataType {
}
public UnsignedInteger7DataType(DataTypeManager dtm) {
- super("uint7", false, dtm);
+ super("uint7", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedIntegerDataType.java
index 76ca393b36..e3445d53f8 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedIntegerDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedIntegerDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for an unsigned Integer dataType
*/
-public class UnsignedIntegerDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class UnsignedIntegerDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedIntegerDataType instance.*/
public final static UnsignedIntegerDataType dataType = new UnsignedIntegerDataType();
@@ -30,30 +28,19 @@ public class UnsignedIntegerDataType extends AbstractIntegerDataType {
}
public UnsignedIntegerDataType(DataTypeManager dtm) {
- super("uint", false, dtm);
+ super("uint", dtm);
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getIntegerSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Unsigned Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongDataType.java
index 4fb6e2aa87..f4e662f2c9 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for a Signed Long Integer dataType
*/
-public class UnsignedLongDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class UnsignedLongDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedLongDataType instance.*/
public final static UnsignedLongDataType dataType = new UnsignedLongDataType();
@@ -30,30 +28,19 @@ public class UnsignedLongDataType extends AbstractIntegerDataType {
}
public UnsignedLongDataType(DataTypeManager dtm) {
- super("ulong", false, dtm);
+ super("ulong", dtm);
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getLongSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Unsigned Long Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongLongDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongLongDataType.java
index c46bb4a33c..b6f653ea90 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongLongDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongLongDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for an Signed LongLong Integer dataType
*/
-public class UnsignedLongLongDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class UnsignedLongLongDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedLongLongDataType instance.*/
public final static UnsignedLongLongDataType dataType = new UnsignedLongLongDataType();
@@ -30,30 +28,19 @@ public class UnsignedLongLongDataType extends AbstractIntegerDataType {
}
public UnsignedLongLongDataType(DataTypeManager dtm) {
- super("ulonglong", false, dtm);
+ super("ulonglong", dtm);
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getLongLongSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Unsigned Long Long Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedShortDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedShortDataType.java
index 57d40651f0..a1bfd44203 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedShortDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedShortDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for a Short Integer dataType
*/
-public class UnsignedShortDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class UnsignedShortDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedShortDataType instance.*/
public final static UnsignedShortDataType dataType = new UnsignedShortDataType();
@@ -30,30 +28,19 @@ public class UnsignedShortDataType extends AbstractIntegerDataType {
}
public UnsignedShortDataType(DataTypeManager dtm) {
- super("ushort", false, dtm);
+ super("ushort", dtm);
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getShortSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Unsigned Short Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WordDataType.java
index f33ed19a70..9ffea46759 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a basic implementation of a word datatype
*/
-public class WordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class WordDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined WordDataType instance.*/
public final static WordDataType dataType = new WordDataType();
@@ -30,7 +28,7 @@ public class WordDataType extends AbstractIntegerDataType {
}
public WordDataType(DataTypeManager dtm) {
- super("word", false, dtm);
+ super("word", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java
index 78487bfba8..09e34cc9b4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java
@@ -32,9 +32,9 @@ import generic.jar.ResourceFile;
import generic.stl.Pair;
import ghidra.app.plugin.processors.sleigh.*;
import ghidra.program.model.address.*;
-import ghidra.program.model.data.*;
-import ghidra.program.model.listing.DefaultProgramContext;
-import ghidra.program.model.listing.Parameter;
+import ghidra.program.model.data.DataOrganization;
+import ghidra.program.model.data.DataOrganizationImpl;
+import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.*;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
@@ -312,6 +312,12 @@ public class BasicCompilerSpec implements CompilerSpec {
@Override
public PrototypeModel getCallingConvention(String name) {
+ if (name == null || Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
+ return null;
+ }
+ if (Function.DEFAULT_CALLING_CONVENTION_STRING.equals(name)) {
+ return getDefaultCallingConvention();
+ }
return callingConventionMap.get(name);
}
@@ -1077,12 +1083,14 @@ public class BasicCompilerSpec implements CompilerSpec {
}
@Override
- public PrototypeModel matchConvention(GenericCallingConvention genericCallingConvention) {
- if (genericCallingConvention == GenericCallingConvention.unknown) {
+ public PrototypeModel matchConvention(String conventionName) {
+ if (conventionName == null ||
+ CALLING_CONVENTION_unknown.equals(conventionName) ||
+ CALLING_CONVENTION_default.equals(conventionName)) {
return defaultModel;
}
for (PrototypeModel model : models) {
- if (model.getGenericCallingConvention() == genericCallingConvention) {
+ if (model.getName().equals(conventionName)) {
return model;
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java
index f208ee8c33..061f6057a4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java
@@ -21,7 +21,6 @@ import java.util.Set;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.DataOrganization;
-import ghidra.program.model.data.GenericCallingConvention;
import ghidra.program.model.listing.DefaultProgramContext;
import ghidra.program.model.listing.Parameter;
import ghidra.program.model.pcode.Encoder;
@@ -40,6 +39,9 @@ import ghidra.program.model.pcode.Encoder;
*/
public interface CompilerSpec {
+ public static final String CALLING_CONVENTION_unknown = "unknown";
+ public static final String CALLING_CONVENTION_default = "default";
+
public final static String CALLING_CONVENTION_cdecl = "__cdecl";
public final static String CALLING_CONVENTION_pascal = "__pascal";
public final static String CALLING_CONVENTION_thiscall = "__thiscall";
@@ -174,15 +176,16 @@ public interface CompilerSpec {
public PcodeInjectLibrary getPcodeInjectLibrary();
/**
- * Get the PrototypeModel corresponding to the given generic calling convention
- * @param genericCallingConvention is the given generic calling convention
+ * Get the PrototypeModel which corresponds to the given calling convention name.
+ * If no match is found the default prototype model is returned.
+ * @param conventionName calling convention name.
* @return the matching model or the defaultModel if nothing matches
*/
- public PrototypeModel matchConvention(GenericCallingConvention genericCallingConvention);
+ public PrototypeModel matchConvention(String conventionName);
/**
* Find the best guess at a calling convention model from this compiler spec
- * given an ordered list of (potential) parameters.
+ * given an ordered list of (potential) parameters with storage assignments.
* @param params is the ordered list of parameters
* @return prototype model corresponding to the specified function signature
*/
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpecID.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpecID.java
index 421c6f9d81..53b1b21202 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpecID.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpecID.java
@@ -18,17 +18,20 @@ package ghidra.program.model.lang;
/**
* Represents an opinion's compiler (gcc, borlandcpp, etc).
*/
-public class CompilerSpecID implements Comparable {
+public final class CompilerSpecID implements Comparable {
+
+ public static final String DEFAULT_ID = "default";
private final String id;
/**
* Creates a new compiler spec ID.
*
- * @param id The compiler ID (gcc, borlandcpp, etc).
+ * @param id The compiler ID (gcc, borlandcpp, etc) as defined in the appropriate
+ * {@link LanguageDescription}. If null the value of "default" will be assumed.
*/
public CompilerSpecID(String id) {
- this.id = id;
+ this.id = id != null ? id : DEFAULT_ID;
}
/**
@@ -38,12 +41,6 @@ public class CompilerSpecID implements Comparable {
* @throws IllegalArgumentException if the compiler spec ID is null or empty.
*/
public String getIdAsString() {
- if (id == null) {
- throw new IllegalArgumentException("id == null not allowed");
- }
- if ("".equals(id)) {
- throw new IllegalArgumentException("empty id not allowed");
- }
return id;
}
@@ -51,7 +48,7 @@ public class CompilerSpecID implements Comparable {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + id.hashCode();
return result;
}
@@ -67,15 +64,7 @@ public class CompilerSpecID implements Comparable {
return false;
}
final CompilerSpecID other = (CompilerSpecID) obj;
- if (id == null) {
- if (other.id != null) {
- return false;
- }
- }
- else if (!id.equals(other.id)) {
- return false;
- }
- return true;
+ return id.equals(other.id);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java
index a74ad79b44..2496c4b6c6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java
@@ -16,7 +16,8 @@
package ghidra.program.model.lang;
import ghidra.program.model.address.Address;
-import ghidra.program.model.listing.*;
+import ghidra.program.model.listing.AutoParameterType;
+import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.pcode.Varnode;
import ghidra.util.exception.InvalidInputException;
@@ -56,7 +57,8 @@ public class DynamicVariableStorage extends VariableStorage {
* @param size varnode size
* @throws InvalidInputException
*/
- public DynamicVariableStorage(Program program, AutoParameterType autoParamType, Address address,
+ public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType,
+ Address address,
int size) throws InvalidInputException {
super(program, address, size);
this.autoParamType = autoParamType;
@@ -69,7 +71,8 @@ public class DynamicVariableStorage extends VariableStorage {
* @param varnodes one or more ordered storage varnodes
* @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public DynamicVariableStorage(Program program, AutoParameterType autoParamType, Varnode... varnodes)
+ public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType,
+ Varnode... varnodes)
throws InvalidInputException {
super(program, varnodes);
this.autoParamType = autoParamType;
@@ -84,7 +87,8 @@ public class DynamicVariableStorage extends VariableStorage {
* @param size varnode size
* @throws InvalidInputException
*/
- public DynamicVariableStorage(Program program, boolean forcedIndirect, Address address, int size)
+ public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect,
+ Address address, int size)
throws InvalidInputException {
super(program, address, size);
this.forcedIndirect = forcedIndirect;
@@ -98,7 +102,8 @@ public class DynamicVariableStorage extends VariableStorage {
* @param varnodes one or more ordered storage varnodes
* @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public DynamicVariableStorage(Program program, boolean forcedIndirect, Varnode... varnodes)
+ public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect,
+ Varnode... varnodes)
throws InvalidInputException {
super(program, varnodes);
this.forcedIndirect = forcedIndirect;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/LanguageCompilerSpecPair.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/LanguageCompilerSpecPair.java
index 408a60c535..b561b3cb26 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/LanguageCompilerSpecPair.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/LanguageCompilerSpecPair.java
@@ -70,6 +70,22 @@ public final class LanguageCompilerSpecPair implements Comparable languageMinorVersion) {
// Minor version change - translator not needed (languageUpgradeTranslator is null)
- return new LanguageVersionException();
+ String fromVer = languageVersion + "." + languageMinorVersion;
+ String toVer = languageVersion + "." + language.getMinorVersion();
+ return new LanguageVersionException("Minor language change " + fromVer + " -> " + toVer,
+ true);
}
else if (language.getMinorVersion() != languageMinorVersion ||
language.getVersion() != languageVersion) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ProgramArchitecture.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ProgramArchitecture.java
new file mode 100644
index 0000000000..e38ebb7139
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ProgramArchitecture.java
@@ -0,0 +1,57 @@
+/* ###
+ * 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.lang;
+
+import ghidra.program.model.address.AddressFactory;
+import ghidra.program.model.address.OverlayAddressSpace;
+import ghidra.program.model.listing.Program;
+
+/**
+ * ProgramArchitecture
which identifies program architecture details required to
+ * utilize language/compiler-specific memory and variable storage specifications.
+ */
+public interface ProgramArchitecture {
+
+ /**
+ * Get the processor language
+ * @return processor language
+ */
+ Language getLanguage();
+
+ /**
+ * Get the address factory for this architecture. In the case of a {@link Program} this should
+ * be the extended address factory that includes the stack space and any defined overlay
+ * spaces (i.e., {@link OverlayAddressSpace}).
+ * @return address factory
+ */
+ AddressFactory getAddressFactory();
+
+ /**
+ * Get the compiler specification
+ * @return compiler specification
+ */
+ CompilerSpec getCompilerSpec();
+
+ /**
+ * Get the language/compiler spec ID pair associated with this program architecture.
+ * @return language/compiler spec ID pair
+ */
+ public default LanguageCompilerSpecPair getLanguageCompilerSpecPair() {
+ return new LanguageCompilerSpecPair(getLanguage().getLanguageID(),
+ getCompilerSpec().getCompilerSpecID());
+ }
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java
index 52a7dd2c34..b67b21b472 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java
@@ -55,7 +55,6 @@ public class PrototypeModel {
private AddressSet localRange; // Range on the stack considered for local storage
private AddressSet paramRange; // Range on the stack considered for parameter storage
private InputListType inputListType = InputListType.STANDARD;
- private GenericCallingConvention genericCallingConvention;
private boolean hasThis; // Convention has a this (auto-parameter)
private boolean isConstruct; // Convention is used for object construction
private boolean hasUponEntry; // Does this have an uponentry injection
@@ -88,7 +87,6 @@ public class PrototypeModel {
paramRange = new AddressSet(model.paramRange);
hasThis = model.hasThis || name.equals(CompilerSpec.CALLING_CONVENTION_thiscall);
isConstruct = model.isConstruct;
- genericCallingConvention = GenericCallingConvention.getGenericCallingConvention(name);
hasUponEntry = model.hasUponEntry;
hasUponReturn = model.hasUponReturn;
}
@@ -107,21 +105,12 @@ public class PrototypeModel {
compatModel = null;
localRange = null;
paramRange = null;
- genericCallingConvention = GenericCallingConvention.unknown;
hasThis = false;
isConstruct = false;
hasUponEntry = false;
hasUponReturn = false;
}
- /**
- * Get the generic calling convention enum associated with this
- * @return the enum
- */
- public GenericCallingConvention getGenericCallingConvention() {
- return genericCallingConvention;
- }
-
/**
* @return list of registers unaffected by called functions
*/
@@ -439,10 +428,6 @@ public class PrototypeModel {
encoder.writeString(ATTRIB_EXTRAPOP, "unknown");
}
encoder.writeSignedInteger(ATTRIB_STACKSHIFT, stackshift);
- GenericCallingConvention nameType = GenericCallingConvention.guessFromName(name);
- if (nameType != genericCallingConvention) {
- encoder.writeString(ATTRIB_TYPE, genericCallingConvention.getDeclarationName());
- }
if (hasThis) {
encoder.writeBool(ATTRIB_HASTHIS, true);
}
@@ -602,13 +587,6 @@ public class PrototypeModel {
extrapop = SpecXmlUtils.decodeInt(extpopStr);
}
stackshift = SpecXmlUtils.decodeInt(protoElement.getAttribute("stackshift"));
- String type = protoElement.getAttribute("type");
- if (type != null) {
- genericCallingConvention = GenericCallingConvention.getGenericCallingConvention(type);
- }
- else {
- genericCallingConvention = GenericCallingConvention.guessFromName(name);
- }
hasThis = false;
isConstruct = false;
String thisString = protoElement.getAttribute("hasthis");
@@ -742,9 +720,6 @@ public class PrototypeModel {
if (extrapop != obj.extrapop || stackshift != obj.stackshift) {
return false;
}
- if (genericCallingConvention != obj.genericCallingConvention) {
- return false;
- }
if (hasThis != obj.hasThis || isConstruct != obj.isConstruct) {
return false;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java
index a8f48cccf8..cae228ceda 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java
@@ -24,6 +24,7 @@ import java.util.*;
import ghidra.app.plugin.processors.sleigh.SleighException;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Parameter;
+import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.pcode.Encoder;
import ghidra.xml.*;
@@ -101,7 +102,11 @@ public class PrototypeModelMerged extends PrototypeModel {
for (int i = 0; i < modellist.length; ++i) {
ScoreProtoModel scoremodel = new ScoreProtoModel(true, modellist[i], params.length);
for (Parameter p : params) {
- scoremodel.addParameter(p.getMinAddress(), p.getLength());
+ VariableStorage storage = p.getVariableStorage();
+ if (storage.isUnassignedStorage() || storage.isBadStorage()) {
+ continue;
+ }
+ scoremodel.addParameter(storage.getMinAddress(), p.getLength());
}
scoremodel.doScore();
int score = scoremodel.getScore();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.java
index 96b8d793bd..9de3080709 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.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,10 +15,10 @@
*/
package ghidra.program.model.listing;
-import ghidra.program.model.data.DataTypeManagerDomainObject;
-
import java.util.Date;
+import ghidra.program.model.data.DataTypeManagerDomainObject;
+
/**
* This interface represents the main entry point into an object which
* stores all information relating to a single data type archive.
@@ -37,6 +36,13 @@ public interface DataTypeArchive extends DataTypeManagerDomainObject {
/** A date from January 1, 1970 */
public static final Date JANUARY_1_1970 = new Date(0);
+ /**
+ * Determine if this archive has exclusive-write access which may be neccessary for some
+ * operations.
+ * @return true if archive has exclusive-write access
+ */
+ public boolean hasExclusiveAccess();
+
/**
* Gets the default pointer size as it may be stored within the data type archive.
* @return default pointer size.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java
index eb3dbb09ad..a4437ef4c2 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java
@@ -22,6 +22,8 @@ import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.DataTypeManager;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.DuplicateNameException;
@@ -42,8 +44,10 @@ public interface Function extends Namespace {
public static final String DEFAULT_LOCAL_RESERVED_PREFIX = "local_res";
public static final String DEFAULT_LOCAL_TEMP_PREFIX = "temp_";
public static final int DEFAULT_LOCAL_PREFIX_LEN = DEFAULT_LOCAL_PREFIX.length();
- public static final String UNKNOWN_CALLING_CONVENTION_STRING = "unknown";
- public static final String DEFAULT_CALLING_CONVENTION_STRING = "default";
+ public static final String UNKNOWN_CALLING_CONVENTION_STRING =
+ CompilerSpec.CALLING_CONVENTION_unknown;
+ public static final String DEFAULT_CALLING_CONVENTION_STRING =
+ CompilerSpec.CALLING_CONVENTION_default;
public static final String INLINE = "inline";
public static final String NORETURN = "noreturn";
public static final String THUNK = "thunk";
@@ -177,7 +181,7 @@ public interface Function extends Namespace {
/**
* Set the function's return type.
* @param type the dataType that will define this functions return type.
- * @param source TODO
+ * @param source signature source
* @throws InvalidInputException if data type is not a fixed length.
*/
public void setReturnType(DataType type, SourceType source) throws InvalidInputException;
@@ -399,11 +403,13 @@ public interface Function extends Namespace {
Variable... params) throws DuplicateNameException, InvalidInputException;
/**
- * Replace all current parameters with the given list of parameters and optionally change the calling convention
- * and function return.
+ * Replace all current parameters with the given list of parameters and optionally change the
+ * calling convention and function return.
* The {@link VariableUtilities#checkVariableConflict(Function, Variable, VariableStorage, boolean)}
* method may be used to check and remove conflicting variables which already exist in the function.
- * @param callingConvention updated calling convention name or null if no change is required
+ * @param callingConvention updated calling convention name or null if no change is required.
+ * Only {@link DataTypeManager#getKnownCallingConventionNames() known calling convention names}
+ * may be specified which will always include those defined by the associated {@link CompilerSpec}.
* @param returnValue return variable or null if no change required
* @param updateType function update type
* @param force if true any conflicting local parameters will be removed
@@ -422,11 +428,13 @@ public interface Function extends Namespace {
throws DuplicateNameException, InvalidInputException;
/**
- * Replace all current parameters with the given list of parameters and optionally change the calling convention
- * and function return.
+ * Replace all current parameters with the given list of parameters and optionally change the
+ * calling convention and function return.
* The {@link VariableUtilities#checkVariableConflict(Function, Variable, VariableStorage, boolean)}
* method may be used to check and remove conflicting variables which already exist in the function.
- * @param callingConvention updated calling convention name or null if no change is required
+ * @param callingConvention updated calling convention name or null if no change is required.
+ * Only {@link DataTypeManager#getKnownCallingConventionNames() known calling convention names}
+ * may be specified which will always include those defined by the associated {@link CompilerSpec}.
* @param returnVar return variable or null if no change required
* @param updateType function update type
* @param force if true any conflicting local parameters will be removed
@@ -614,6 +622,14 @@ public interface Function extends Namespace {
*/
public PrototypeModel getCallingConvention();
+ /**
+ * Determine if this signature has an unknown or unrecognized calling convention name.
+ * @return true if calling convention is unknown or unrecognized name, else false.
+ */
+ public default boolean hasUnknownCallingConventionName() {
+ return getCallingConvention() == null;
+ }
+
/**
* Gets the calling convention's name for this function.
*
@@ -626,22 +642,19 @@ public interface Function extends Namespace {
public String getCallingConventionName();
/**
- * Gets the name of the default calling convention.
- *
Note: The name in the PrototypeModel of the default calling convention may be null.
- *
- * @return the name of the default calling convention.
- */
- public String getDefaultCallingConventionName();
-
- /**
- * Sets the calling convention for this function to the named calling convention.
- * @param name the name of the calling convention. "unknown" and "default" are reserved names
- * that can also be used here.
- *
Null or Function.UNKNOWN_CALLING_CONVENTION_STRING sets this function to not have a
- * calling convention (i.e. unknown).
- *
Function.DEFAULT_CALLING_CONVENTION_STRING sets this function to use the default calling
- * convention. (i.e. default)
- * @throws InvalidInputException if the specified name is not a recognized calling convention name.
+ * Sets the calling convention for this function to the named calling convention. Only
+ * {@link DataTypeManager#getKnownCallingConventionNames() known calling convention names}
+ * may be specified which will always include those defined by the associated
+ * {@link CompilerSpec}.
+ * @param name the name of the calling convention. Only
+ * {@link DataTypeManager#getKnownCallingConventionNames() known calling convention names}
+ * may be specified which will always include those defined by the associated
+ * {@link CompilerSpec}. In addition the reserved names
+ * {@link Function#UNKNOWN_CALLING_CONVENTION_STRING "unknown"} and
+ * {@link Function#DEFAULT_CALLING_CONVENTION_STRING "default"} may also be
+ * used here.
+ * @throws InvalidInputException if the specified name is not a recognized calling
+ * convention name.
*/
public void setCallingConvention(String name) throws InvalidInputException;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionManager.java
index be598d8661..5194a53efe 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionManager.java
@@ -15,13 +15,14 @@
*/
package ghidra.program.model.listing;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import ghidra.program.database.ManagerDB;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SourceType;
@@ -41,13 +42,18 @@ public interface FunctionManager extends ManagerDB {
public Program getProgram();
/**
- * Gets the names associated with each of the current calling conventions associated with this
- * program. Within the exception of "unknown", all of these calling convention names should have
- * a PrototypeModel.
+ * Get the ordered list of defined calling convention names. The reserved names
+ * "unknown" and "default" are not included. The returned collection may not include all names
+ * referenced by various functions and function-definitions. This set is limited to those
+ * defined by the associated compiler specification.
+ * See {@link DataTypeManager#getDefinedCallingConventionNames}.
+ *
+ * For a set of all known names (including those that are not defined by compiler spec)
+ * see {@link DataTypeManager#getKnownCallingConventionNames()}.
*
* @return the calling convention names.
*/
- public List getCallingConventionNames();
+ public Collection getCallingConventionNames();
/**
* Gets the default calling convention's prototype model in this program.
@@ -63,13 +69,6 @@ public interface FunctionManager extends ManagerDB {
*/
public PrototypeModel getCallingConvention(String name);
- /**
- * Gets all the calling convention prototype models in this program that have names.
- *
- * @return the function calling convention prototype models.
- */
- public PrototypeModel[] getCallingConventions();
-
/**
* Create a function with the given body at entry point within the global namespace.
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionSignature.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionSignature.java
index cef0ffe7ce..8ae21a15db 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionSignature.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionSignature.java
@@ -15,7 +15,9 @@
*/
package ghidra.program.model.listing;
-import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.ParameterDefinition;
+import ghidra.program.model.lang.PrototypeModel;
/**
* Interface describing all the things about a function that are portable
@@ -23,6 +25,7 @@ import ghidra.program.model.data.*;
*/
public interface FunctionSignature {
+ public static final String NORETURN_DISPLAY_STRING = "noreturn";
public static final String VAR_ARGS_DISPLAY_STRING = "...";
public static final String VOID_PARAM_DISPLAY_STRING = "void";
@@ -32,43 +35,73 @@ public interface FunctionSignature {
public String getName();
/**
- * Return a string representation of the function signature without the
+ * Get string representation of the function signature without the
* calling convention specified.
+ * @return function signature string
*/
public String getPrototypeString();
/**
- * Return a string representation of the function signature
+ * Get string representation of the function signature
* @param includeCallingConvention if true prototype will include call convention
- * declaration if known.
+ * declaration if known as well as noreturn
indicator if applicable.
+ * @return function signature string
*/
public String getPrototypeString(boolean includeCallingConvention);
/**
- * Return an array of parameters for the function
+ * Get function signature parameter arguments
+ * @return an array of parameters for the function
*/
public ParameterDefinition[] getArguments();
/**
- * Return the return data type
+ * Get function signature return type
+ * @return the return data type
*/
public DataType getReturnType();
/**
- * Return the comment string
+ * Get descriptive comment for signature
+ * @return the comment string
*/
public String getComment();
/**
- * Returns true if this function signature has a variable argument list (VarArgs).
+ * @return true if this function signature has a variable argument list (VarArgs).
*/
public boolean hasVarArgs();
/**
- * Returns the generic calling convention associated with this function definition.
- * The "unknown" convention should be returned instead of null.
+ * @return true if this function signature corresponds to a non-returning function.
*/
- public GenericCallingConvention getGenericCallingConvention();
+ public boolean hasNoReturn();
+
+ /**
+ * Gets the calling convention prototype model for this function if associated with a
+ * compiler specificfation. This method will always return null if signature is not
+ * associated with a specific program architecture.
+ *
+ * @return the prototype model of the function's current calling convention or null.
+ */
+ public PrototypeModel getCallingConvention();
+
+ /**
+ * Returns the calling convention name associated with this function definition.
+ * Reserved names may also be returned: {@link Function#UNKNOWN_CALLING_CONVENTION_STRING},
+ * {@link Function#DEFAULT_CALLING_CONVENTION_STRING}.
+ * The "unknown" convention must be returned instead of null.
+ * @return calling convention name
+ */
+ public String getCallingConventionName();
+
+ /**
+ * Determine if this signature has an unknown or unrecognized calling convention name.
+ * @return true if calling convention is unknown or unrecognized name, else false.
+ */
+ public default boolean hasUnknownCallingConventionName() {
+ return getCallingConvention() == null;
+ }
/**
* Returns true if the given signature is equivalent to this signature. The
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java
index 948d01fcbd..2a2f5984a2 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java
@@ -46,7 +46,7 @@ import ghidra.util.task.TaskMonitor;
* For example, the createCodeUnit() method of listing will fail if memory is
* undefined at the address where the codeUnit is to be created.
*/
-public interface Program extends DataTypeManagerDomainObject {
+public interface Program extends DataTypeManagerDomainObject, ProgramArchitecture {
public static final String ANALYSIS_PROPERTIES = "Analyzers";
public static final String DISASSEMBLER_PROPERTIES = "Disassembler";
@@ -83,8 +83,10 @@ public interface Program extends DataTypeManagerDomainObject {
/**
* Get the internal program address map
* @return internal address map
+ * @deprecated Method intended for internal ProgramDB use and is not intended for general use.
+ * This method may be removed from this interface in a future release.
*/
- // FIXME!! Should not expose on interface - anything using this should use ProgramDB or avoid using map!
+ @Deprecated(forRemoval = true)
public AddressMap getAddressMap();
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java
index db51390974..f314185b5a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java
@@ -20,8 +20,7 @@ import java.util.List;
import generic.algorithms.CRC64;
import ghidra.program.model.address.*;
-import ghidra.program.model.lang.Register;
-import ghidra.program.model.lang.UnknownRegister;
+import ghidra.program.model.lang.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.util.LanguageTranslator;
import ghidra.util.exception.InvalidInputException;
@@ -58,7 +57,7 @@ public class VariableStorage implements Comparable {
public static final VariableStorage VOID_STORAGE = new VariableStorage();
protected final Varnode[] varnodes;
- protected final Program program;
+ protected final ProgramArchitecture programArch;
private List registers;
private int size;
@@ -69,42 +68,45 @@ public class VariableStorage implements Comparable {
* Construct an empty variable storage for reserved usage (i.e., BAD_STORAGE, UNMAPPED_STORAGE)
*/
protected VariableStorage() {
- this.program = null;
+ this.programArch = null;
this.varnodes = null;
}
/**
* Construct variable storage
- * @param program
+ * @param programArch program architecture details
* @param varnodes one or more ordered storage varnodes
* @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public VariableStorage(Program program, Varnode... varnodes) throws InvalidInputException {
- this.program = program;
+ public VariableStorage(ProgramArchitecture programArch, Varnode... varnodes)
+ throws InvalidInputException {
+ this.programArch = programArch;
this.varnodes = varnodes.clone();
checkVarnodes();
}
/**
* Construct register variable storage
- * @param program
+ * @param programArch program architecture details
* @param registers one or more ordered registers
* @throws InvalidInputException if specified registers violate storage restrictions
*/
- public VariableStorage(Program program, Register... registers) throws InvalidInputException {
- this(program, getVarnodeList(registers));
+ public VariableStorage(ProgramArchitecture programArch, Register... registers)
+ throws InvalidInputException {
+ this(programArch, getVarnodeList(registers));
}
/**
* Construct stack variable storage
- * @param program
+ * @param programArch program architecture details
* @param stackOffset stack offset
* @param size stack element size
* @throws InvalidInputException if specified registers violate storage restrictions
*/
- public VariableStorage(Program program, int stackOffset, int size) throws InvalidInputException {
- this(program, new Varnode(program.getAddressFactory().getStackSpace().getAddress(
- stackOffset), size));
+ public VariableStorage(ProgramArchitecture programArch, int stackOffset, int size)
+ throws InvalidInputException {
+ this(programArch, new Varnode(
+ programArch.getAddressFactory().getStackSpace().getAddress(stackOffset), size));
}
private static Varnode[] getVarnodeList(Register[] registers) {
@@ -117,34 +119,37 @@ public class VariableStorage implements Comparable {
/**
* Construct variable storage
- * @param program
+ * @param programArch program architecture details
* @param varnodes one or more ordered storage varnodes
* @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public VariableStorage(Program program, List varnodes) throws InvalidInputException {
- this.program = program;
+ public VariableStorage(ProgramArchitecture programArch, List varnodes)
+ throws InvalidInputException {
+ this.programArch = programArch;
this.varnodes = varnodes.toArray(new Varnode[varnodes.size()]);
checkVarnodes();
}
/**
* Construct variable storage
- * @param program
- * @param address
- * @param size
- * @throws InvalidInputException
+ * @param programArch program architecture details
+ * @param address varnode address
+ * @param size varnode size
+ * @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public VariableStorage(Program program, Address address, int size) throws InvalidInputException {
- this(program, new Varnode(address, size));
+ public VariableStorage(ProgramArchitecture programArch, Address address, int size)
+ throws InvalidInputException {
+ this(programArch, new Varnode(address, size));
}
/**
* Construct variable storage
- * @param program
+ * @param programArch program architecture details
* @param serialization storage serialization string
- * @throws InvalidInputException
+ * @return deserialized variable storage. {@link #BAD_STORAGE} may be returned on failure.
+ * @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public static VariableStorage deserialize(Program program, String serialization)
+ public static VariableStorage deserialize(ProgramArchitecture programArch, String serialization)
throws InvalidInputException {
if (serialization == null || UNASSIGNED.equals(serialization)) {
return UNASSIGNED_STORAGE;
@@ -155,18 +160,18 @@ public class VariableStorage implements Comparable {
if (BAD.equals(serialization)) {
return BAD_STORAGE;
}
- List varnodes = getVarnodes(program.getAddressFactory(), serialization);
+ List varnodes = getVarnodes(programArch.getAddressFactory(), serialization);
if (varnodes == null) {
return BAD_STORAGE;
}
- return new VariableStorage(program, varnodes);
+ return new VariableStorage(programArch, varnodes);
}
/**
* @return program for which this storage is associated
*/
- public Program getProgram() {
- return program;
+ public ProgramArchitecture getProgramArchitecture() {
+ return programArch;
}
/**
@@ -181,7 +186,7 @@ public class VariableStorage implements Comparable {
throw new IllegalArgumentException("A minimum of one varnode must be specified");
}
- AddressFactory addrFactory = program.getAddressFactory();
+ AddressFactory addrFactory = programArch.getAddressFactory();
size = 0;
for (int i = 0; i < varnodes.length; i++) {
Varnode varnode = varnodes[i];
@@ -212,7 +217,8 @@ public class VariableStorage implements Comparable {
}
if (!storageAddr.isStackAddress()) {
- Register reg = program.getRegister(storageAddr, varnode.getSize());
+ Register reg =
+ programArch.getLanguage().getRegister(storageAddr, varnode.getSize());
if (reg != null && !(reg instanceof UnknownRegister)) {
isRegister = true;
if (registers == null) {
@@ -255,12 +261,12 @@ public class VariableStorage implements Comparable {
/**
* Attempt to clone variable storage for use in a different program.
* Dynamic storage characteristics will not be preserved.
- * @param newProgram target program
+ * @param newProgramArch target program architecture details
* @return cloned storage
- * @throws InvalidInputException
+ * @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public VariableStorage clone(Program newProgram) throws InvalidInputException {
- if (program == null || newProgram == program) {
+ public VariableStorage clone(ProgramArchitecture newProgramArch) throws InvalidInputException {
+ if (programArch == null || newProgramArch == programArch) {
if (getClass().equals(VariableStorage.class)) {
return this; // only reuse if simple VariableStorage instance
}
@@ -270,14 +276,14 @@ public class VariableStorage implements Comparable {
if (isBadStorage()) {
return BAD_STORAGE;
}
- return new VariableStorage(newProgram, varnodes);
+ return new VariableStorage(newProgramArch, varnodes);
}
- if (!newProgram.getLanguage().equals(program.getLanguage())) {
+ if (!newProgramArch.getLanguage().equals(programArch.getLanguage())) {
throw new IllegalArgumentException(
"Variable storage incompatible with program language: " +
- newProgram.getLanguage().toString());
+ newProgramArch.getLanguage().toString());
}
- AddressFactory newAddressFactory = newProgram.getAddressFactory();
+ AddressFactory newAddressFactory = newProgramArch.getAddressFactory();
Varnode[] v = getVarnodes();
Varnode[] newVarnodes = new Varnode[v.length];
for (int i = 0; i < v.length; i++) {
@@ -291,7 +297,7 @@ public class VariableStorage implements Comparable {
newVarnodes[i] =
new Varnode(newSpace.getAddress(v[i].getOffset()), v[i].getSize());
}
- return new VariableStorage(newProgram, newVarnodes);
+ return new VariableStorage(newProgramArch, newVarnodes);
}
@Override
@@ -322,9 +328,9 @@ public class VariableStorage implements Comparable {
builder.append(varnode.getSize());
}
- private String getAddressString(Address address, int size) {
+ private String getAddressString(Address address, int sz) {
if (address.isRegisterAddress() || address.isMemoryAddress()) {
- Register register = program.getRegister(address, size);
+ Register register = programArch.getLanguage().getRegister(address, sz);
if (register != null) {
return register.toString();
}
@@ -610,7 +616,7 @@ public class VariableStorage implements Comparable {
/**
* Determine if this variable storage intersects the specified variable storage
- * @param variableStorage
+ * @param variableStorage other variable storage
* @return true if any intersection exists between this storage and the specified
* variable storage
*/
@@ -666,8 +672,8 @@ public class VariableStorage implements Comparable {
/**
* Determine if the specified address is contained within this storage
- * @param address
- * @return
+ * @param address address
+ * @return true if this storage varnode(s) contain specified address
*/
public boolean contains(Address address) {
if (varnodes == null) {
@@ -751,7 +757,7 @@ public class VariableStorage implements Comparable {
/**
* Generate VariableStorage serialization string
- * @param varnodes
+ * @param varnodes one or more storage varnodes
* @return storage serialization string useful for subsequent reconstruction
* of a VariableStorage object
*/
@@ -773,9 +779,10 @@ public class VariableStorage implements Comparable {
/**
* Parse a storage serialization string to produce an array or varnodes
- * @param addrFactory
- * @param serialization
+ * @param addrFactory address factory
+ * @param serialization serialized variable storage string (see {@link #getSerializationString()}).
* @return array of varnodes or null if invalid
+ * @throws InvalidInputException if specified registers violate storage restrictions
*/
public static List getVarnodes(AddressFactory addrFactory, String serialization)
throws InvalidInputException {
@@ -866,7 +873,7 @@ public class VariableStorage implements Comparable {
translator.getOldLanguage().getAddressFactory().getRegisterSpace().getAddress(
offset);
String newOffsetStr =
- translateRegisterVarnodeOffset(oldRegAddr, size, translator, space);
+ translateRegisterVarnodeOffset(oldRegAddr, size, translator);
if (newOffsetStr != null) {
// if mapping failed - leave it unchanged
offsetStr = newOffsetStr;
@@ -896,15 +903,15 @@ public class VariableStorage implements Comparable {
}
/**
- * Translate register varnode address offsetStr
- * @param translator
- * @param space
- * @param offsetStr
- * @param sizeStr
- * @return translated offsetStr or null if BAD translation
+ * Translate old register storage defined by oldRegAddr and varnodeSize using the
+ * specified translator.
+ * @param oldRegAddr old register address
+ * @param varnodeSize varnode size
+ * @param translator language translator
+ * @return new register offset within same space as oldRegAddr or null if translation failed.
*/
private static String translateRegisterVarnodeOffset(Address oldRegAddr, int varnodeSize,
- LanguageTranslator translator, AddressSpace newRegisterSpace) {
+ LanguageTranslator translator) {
// Handle register movement within register space only
// Assumes all translators will map register space properly
// If old or new register not found no adjustment is made
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java
index 066e7871fd..9196b23385 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java
@@ -243,7 +243,7 @@ public class VariableUtilities {
}
if (dtLen < storageSize && storage.isRegisterStorage()) {
// TODO: this could be expanded to handle other storage
- return new VariableStorage(storage.getProgram(),
+ return new VariableStorage(storage.getProgramArchitecture(),
shrinkRegister(storage.getRegister(), storageSize - dtLen));
}
throw new InvalidInputException(
@@ -721,7 +721,7 @@ public class VariableUtilities {
@Deprecated
public static ParameterImpl getThisParameter(Function function, PrototypeModel convention) {
if (convention != null &&
- convention.getGenericCallingConvention() == GenericCallingConvention.thiscall) {
+ CompilerSpec.CALLING_CONVENTION_thiscall.equals(convention.getName())) {
DataType dt = findOrCreateClassStruct(function);
if (dt == null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java
index 64393e2dd4..31b80daffb 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java
@@ -36,7 +36,6 @@ public class FunctionPrototype {
private LocalSymbolMap localsyms; // Prototype backed by symbol map
private String modelname; // Name of prototype model
- private GenericCallingConvention gconv; // Generic name for the model
private String injectname; // Name of pcode inject associated with this prototype
private DataType returntype; // Output parameter
private VariableStorage returnstorage; // Where the output value is stored
@@ -64,7 +63,6 @@ public class FunctionPrototype {
public FunctionPrototype(LocalSymbolMap ls, Function func) {
localsyms = ls;
modelname = null;
- gconv = null;
injectname = null;
returntype = null;
returnstorage = null;
@@ -90,10 +88,9 @@ public class FunctionPrototype {
*/
public FunctionPrototype(FunctionSignature proto, CompilerSpec cspec,
boolean voidimpliesdotdotdot) {
- modelname = proto.getGenericCallingConvention().getDeclarationName();
- PrototypeModel model = cspec.matchConvention(proto.getGenericCallingConvention());
+ modelname = proto.getName();
+ PrototypeModel model = cspec.matchConvention(modelname);
localsyms = null;
- gconv = proto.getGenericCallingConvention();
injectname = null;
returntype = proto.getReturnType();
returnstorage = null;
@@ -103,7 +100,7 @@ public class FunctionPrototype {
outputlock = true;
dotdotdot = proto.hasVarArgs();
isinline = false;
- noreturn = false;
+ noreturn = proto.hasNoReturn();
custom = false;
extrapop = model.getExtrapop();
hasThis = model.hasThisPointer();
@@ -135,8 +132,7 @@ public class FunctionPrototype {
protoModel = f.getProgram().getCompilerSpec().getDefaultCallingConvention();
}
hasThis = protoModel.hasThisPointer();
- modellock =
- ((modelname != null) && (modelname != Function.UNKNOWN_CALLING_CONVENTION_STRING));
+ modellock = !f.hasUnknownCallingConventionName();
injectname = f.getCallFixup();
voidinputlock = false;
Parameter returnparam = f.getReturn();
@@ -310,13 +306,6 @@ public class FunctionPrototype {
return modelname;
}
- /**
- * @return generic calling convention
- */
- public GenericCallingConvention getGenericCallingConvention() {
- return gconv;
- }
-
/**
* Encode this function prototype to a stream.
* @param encoder is the stream encoder
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunctionDBUtil.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunctionDBUtil.java
index b7145c7b09..c85958659e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunctionDBUtil.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunctionDBUtil.java
@@ -696,10 +696,11 @@ public class HighFunctionDBUtil {
ParameterDefinition[] params = sig.getArguments();
FunctionDefinitionDataType fsig = new FunctionDefinitionDataType("tmpname"); // Empty datatype, will get renamed later
- fsig.setGenericCallingConvention(sig.getGenericCallingConvention());
+ fsig.setCallingConvention(sig.getCallingConventionName());
fsig.setArguments(params);
fsig.setReturnType(sig.getReturnType());
fsig.setVarArgs(sig.hasVarArgs());
+ fsig.setNoReturn(sig.hasNoReturn());
DataTypeSymbol datsym = new DataTypeSymbol(fsig, "prt", AUTO_CAT);
Program program = function.getProgram();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java
index 94255200a2..904ffaf698 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java
@@ -501,8 +501,8 @@ public class HighSymbol {
AutoParameterType autoType =
isThis ? AutoParameterType.THIS : AutoParameterType.RETURN_STORAGE_PTR;
try {
- VariableStorage newStorage = new DynamicVariableStorage(storage.getProgram(),
- autoType, storage.getFirstVarnode());
+ VariableStorage newStorage = new DynamicVariableStorage(
+ storage.getProgramArchitecture(), autoType, storage.getFirstVarnode());
entryList[0] = new MappedEntry(this, newStorage, entry.getPCAdress());
}
catch (InvalidInputException e) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java
index 0fa2f22c38..2e03b03a56 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java
@@ -20,7 +20,6 @@ import java.util.*;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataOrganization;
-import ghidra.program.model.data.GenericCallingConvention;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Encoder;
@@ -55,7 +54,7 @@ public abstract class LanguageTranslatorAdapter implements LanguageTranslator {
* @param oldLanguage
* @param newLanguage
*/
- private LanguageTranslatorAdapter(Language oldLanguage, Language newLanguage) {
+ protected LanguageTranslatorAdapter(Language oldLanguage, Language newLanguage) {
this.oldLanguage = oldLanguage;
this.newLanguage = newLanguage;
oldLanguageID = oldLanguage.getLanguageID();
@@ -483,7 +482,7 @@ public abstract class LanguageTranslatorAdapter implements LanguageTranslator {
* @param newLanguage
* @return default translator or null if reasonable mappings can not be determined.
*/
- static LanguageTranslator getDefaultLanguageTranslator(Language oldLanguage,
+ public static LanguageTranslator getDefaultLanguageTranslator(Language oldLanguage,
Language newLanguage) {
DefaultLanguageTranslator translator =
@@ -626,7 +625,7 @@ class TemporaryCompilerSpec implements CompilerSpec {
}
@Override
- public PrototypeModel matchConvention(GenericCallingConvention genericCallingConvention) {
+ public PrototypeModel matchConvention(String callingConvention) {
throw new UnsupportedOperationException("Language for upgrade use only (matchConvention)");
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java
index e861d8a285..5bedbfd670 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java
@@ -21,13 +21,13 @@ import java.util.NoSuchElementException;
import org.junit.*;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.util.task.TaskMonitor;
/**
* Tests for Enum data types.
*/
-public class EnumTest extends AbstractGTest {
+public class EnumTest extends AbstractGenericTest {
private DataTypeManager dataMgr;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FileDataTypeManagerTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FileDataTypeManagerTest.java
index f5adb2f71e..5db5c46761 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FileDataTypeManagerTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FileDataTypeManagerTest.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
import org.junit.*;
import generic.test.AbstractGenericTest;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
public class FileDataTypeManagerTest extends AbstractGenericTest {
@@ -68,6 +69,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
dtMgr = null;
dtMgr = FileDataTypeManager.openFileArchive(testArchiveFile, false);
+ assertEquals(ArchiveWarning.NONE, dtMgr.getWarning());
assertFalse(dtMgr.isUpdatable());
ArrayList list = new ArrayList<>();
@@ -94,7 +96,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
dtMgr = null;
}
catch (IOException e) {
- Assert.fail("Unexpected Exception");
+ failWithException("Unexpected exception", e);
}
finally {
if (dtMgr != null) {
@@ -113,6 +115,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
FileDataTypeManager dtMgr = null;
try {
dtMgr = FileDataTypeManager.openFileArchive(testArchiveFile, true);
+ assertEquals(ArchiveWarning.NONE, dtMgr.getWarning());
assertTrue("Archive not updateable, i=" + i, dtMgr.isUpdatable());
int txId = dtMgr.startTransaction("Add Type");
@@ -143,6 +146,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
try {
dtMgr = FileDataTypeManager.openFileArchive(testArchiveFile, false);
+ assertEquals(ArchiveWarning.NONE, dtMgr.getWarning());
assertFalse(dtMgr.isUpdatable());
ArrayList list = new ArrayList<>();
diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FunctionDefinitionDataTypeTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FunctionDefinitionDataTypeTest.java
index 795d55324b..ee01baebde 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FunctionDefinitionDataTypeTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FunctionDefinitionDataTypeTest.java
@@ -19,9 +19,9 @@ import static org.junit.Assert.*;
import org.junit.*;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
-public class FunctionDefinitionDataTypeTest extends AbstractGTest {
+public class FunctionDefinitionDataTypeTest extends AbstractGenericTest {
private StandAloneDataTypeManager dtm;
private FunctionDefinition functionDt;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/BitFieldDBDataTypeTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/BitFieldDBDataTypeTest.java
index c5d3f621ec..0aa7334fb6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/BitFieldDBDataTypeTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/BitFieldDBDataTypeTest.java
@@ -15,15 +15,15 @@
*/
package ghidra.program.database.data;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.program.model.data.*;
-public class BitFieldDBDataTypeTest extends AbstractGTest {
+public class BitFieldDBDataTypeTest extends AbstractGenericTest {
private DataTypeManagerDB dataMgr;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java
index 2f8fc607d4..e9b0b581a7 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java
@@ -23,13 +23,13 @@ import org.junit.*;
import com.google.common.collect.Sets;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.program.model.data.*;
import ghidra.util.InvalidNameException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
-public class StructureDBTest extends AbstractGTest {
+public class StructureDBTest extends AbstractGenericTest {
private StructureDB struct;
private DataTypeManagerDB dataMgr;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java
index 6a0f1d6566..6152b93453 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java
@@ -21,14 +21,14 @@ import org.junit.*;
import com.google.common.collect.Sets;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.program.model.data.*;
import ghidra.util.task.TaskMonitor;
/**
*
*/
-public class UnionDBTest extends AbstractGTest {
+public class UnionDBTest extends AbstractGenericTest {
private DataTypeManager dataMgr;
private UnionDB union;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java
index e7b4344ea2..8f3f8094bc 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java
@@ -383,12 +383,7 @@ public class FunctionTestDouble implements Function {
@Override
public String getCallingConventionName() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getDefaultCallingConventionName() {
- throw new UnsupportedOperationException();
+ return Function.UNKNOWN_CALLING_CONVENTION_STRING;
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java
index 530aa56f84..d388eff5dd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java
@@ -53,11 +53,6 @@ public class StubFunctionManager implements FunctionManager {
throw new UnsupportedOperationException();
}
- @Override
- public PrototypeModel[] getCallingConventions() {
- throw new UnsupportedOperationException();
- }
-
@Override
public Function createFunction(String name, Address entryPoint, AddressSetView body,
SourceType source) throws InvalidInputException, OverlappingFunctionException {
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/TestDoubleFunctionSignature.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/TestDoubleFunctionSignature.java
index 165b47a3b5..bac52f7e74 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/TestDoubleFunctionSignature.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/TestDoubleFunctionSignature.java
@@ -15,7 +15,10 @@
*/
package ghidra.program.model;
-import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.ParameterDefinition;
+import ghidra.program.model.lang.PrototypeModel;
+import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
/**
@@ -65,10 +68,20 @@ public class TestDoubleFunctionSignature implements FunctionSignature {
}
@Override
- public GenericCallingConvention getGenericCallingConvention() {
+ public boolean hasNoReturn() {
throw new UnsupportedOperationException();
}
+ @Override
+ public PrototypeModel getCallingConvention() {
+ return null;
+ }
+
+ @Override
+ public String getCallingConventionName() {
+ return Function.UNKNOWN_CALLING_CONVENTION_STRING;
+ }
+
@Override
public String getPrototypeString() {
return funtionSignature;
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 643944123a..e6dedcd54c 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
@@ -18,6 +18,9 @@ package ghidra.program.model.data;
import java.util.*;
import db.Transaction;
+import ghidra.program.database.map.AddressMap;
+import ghidra.program.model.lang.ProgramArchitecture;
+import ghidra.program.model.lang.PrototypeModel;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@@ -39,6 +42,26 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
return id;
}
+ @Override
+ public AddressMap getAddressMap() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ProgramArchitecture getProgramArchitecture() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProgramArchitectureSummary() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DataOrganization getDataOrganization() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public boolean containsCategory(CategoryPath path) {
throw new UnsupportedOperationException();
@@ -85,6 +108,11 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
throw new UnsupportedOperationException();
}
+ @Override
+ public Iterator getAllFunctionDefinitions() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void findDataTypes(String name, List list) {
throw new UnsupportedOperationException();
@@ -322,11 +350,6 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
throw new UnsupportedOperationException();
}
- @Override
- public DataOrganization getDataOrganization() {
- throw new UnsupportedOperationException();
- }
-
@Override
public List getSourceArchives() {
throw new UnsupportedOperationException();
@@ -356,4 +379,24 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
public boolean allowsDefaultComponentSettings() {
return false;
}
+
+ @Override
+ public Collection getKnownCallingConventionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Collection getDefinedCallingConventionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PrototypeModel getDefaultCallingConvention() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention(String name) {
+ 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 d07ddef22e..b68306cc03 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
@@ -18,6 +18,9 @@ package ghidra.program.model.data;
import java.util.*;
import db.Transaction;
+import ghidra.program.database.map.AddressMap;
+import ghidra.program.model.lang.ProgramArchitecture;
+import ghidra.program.model.lang.PrototypeModel;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
import ghidra.util.exception.CancelledException;
@@ -88,6 +91,12 @@ public class TestDummyDataTypeManager implements DataTypeManager {
return null;
}
+ @Override
+ public Iterator getAllFunctionDefinitions() {
+ // stub
+ return null;
+ }
+
@Override
public void findDataTypes(String name, List list) {
// stub
@@ -371,6 +380,23 @@ public class TestDummyDataTypeManager implements DataTypeManager {
return false;
}
+ @Override
+ public AddressMap getAddressMap() {
+ // stub
+ return null;
+ }
+
+ @Override
+ public ProgramArchitecture getProgramArchitecture() {
+ // stub
+ return null;
+ }
+
+ @Override
+ public String getProgramArchitectureSummary() {
+ return null;
+ }
+
@Override
public DataOrganization getDataOrganization() {
// stub
@@ -413,4 +439,24 @@ public class TestDummyDataTypeManager implements DataTypeManager {
return false;
}
+ @Override
+ public Collection getKnownCallingConventionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Collection getDefinedCallingConventionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PrototypeModel getDefaultCallingConvention() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention(String name) {
+ throw new UnsupportedOperationException();
+ }
+
}
diff --git a/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs b/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs
index 421644f47e..a33d0cac6a 100644
--- a/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs
+++ b/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs
@@ -9,7 +9,7 @@
processorspec="AARCH64.pspec"
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:LE:64:v8A">
- Generic ARM v8.5-A LE instructions, LE data, missing some 8.5 vector
+ Generic ARM64 v8.5-A LE instructions, LE data, missing some 8.5 vector
@@ -25,7 +25,7 @@
processorspec="AARCH64.pspec"
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:BE:64:v8A">
- Generic ARM v8.5-A LE instructions, BE data, missing some 8.5 vector
+ Generic ARM64 v8.5-A LE instructions, BE data, missing some 8.5 vector
@@ -39,7 +39,7 @@
processorspec="AARCH64.pspec"
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:LE:32:ilp32">
- Generic ARM v8.5-A LE instructions, LE data, ilp32
+ Generic ARM64 v8.5-A LE instructions, LE data, ilp32
@@ -55,7 +55,7 @@
processorspec="AARCH64.pspec"
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:BE:32:ilp32">
- Generic ARM v8.5-A LE instructions, BE data, ilp32
+ Generic ARM64 v8.5-A LE instructions, BE data, ilp32
diff --git a/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java b/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java
index f7480d2538..942527c795 100644
--- a/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java
+++ b/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java
@@ -23,10 +23,12 @@ import ghidra.file.formats.android.dex.format.*;
import ghidra.file.formats.android.dex.util.DexUtil;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.ConstantPool;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
+import ghidra.util.exception.InvalidInputException;
/**
* Map Ghidra's generic ConstantPool interface onto the Dex specific constant pool
@@ -121,8 +123,14 @@ public class ConstantPoolDex extends ConstantPool {
String defName = res.token + '_' + Integer.toHexString(methodID);
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(defName, dtManager);
res.type = new PointerDataType(funcDef);
- funcDef.setGenericCallingConvention(
- isStatic ? GenericCallingConvention.stdcall : GenericCallingConvention.thiscall);
+ try {
+ funcDef.setCallingConvention(
+ isStatic ? CompilerSpec.CALLING_CONVENTION_stdcall
+ : CompilerSpec.CALLING_CONVENTION_thiscall);
+ }
+ catch (InvalidInputException e) {
+ // unexpected
+ }
int prototypeIndex = methodIDItem.getProtoIndex() & 0xffff;
PrototypesIDItem prototype = dexHeader.getPrototypes().get(prototypeIndex);
diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java
index 9ec1451e6b..4e06fb49ee 100644
--- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java
+++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java
@@ -21,8 +21,11 @@ import java.util.List;
import ghidra.javaclass.format.*;
import ghidra.javaclass.format.constantpool.*;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.ConstantPool;
import ghidra.program.model.listing.Program;
+import ghidra.util.exception.AssertException;
+import ghidra.util.exception.InvalidInputException;
public class ConstantPoolJava extends ConstantPool {
@@ -103,20 +106,30 @@ public class ConstantPoolJava extends ConstantPool {
new ParameterDefinitionImpl("", params.get(i), null);
paramDefs[i] = currentParam;
}
- funcDef.setGenericCallingConvention(GenericCallingConvention.stdcall);
+ try {
+ funcDef.setCallingConvention(CompilerSpec.CALLING_CONVENTION_stdcall);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertException(e); // unexpected
+ }
}
//invokeinterface, invokespecial, and invokevirtual do have a this pointer
else {
paramDefs = new ParameterDefinitionImpl[params.size() + 1];
ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef",
- new Pointer32DataType(DataType.VOID), null);
+ new Pointer32DataType(VoidDataType.dataType), null);
paramDefs[0] = thisParam;
for (int i = 1, max = params.size(); i <= max; ++i) {
ParameterDefinitionImpl currentParam =
new ParameterDefinitionImpl("", params.get(i - 1), null);
paramDefs[i] = currentParam;
}
- funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall);
+ try {
+ funcDef.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertException(e); // unexpected
+ }
}
funcDef.setArguments(paramDefs);
res.type = new PointerDataType(funcDef);
@@ -282,7 +295,7 @@ public class ConstantPoolJava extends ConstantPool {
break;
case CPOOL_MULTIANEWARRAY:
res.tag = ConstantPool.CLASS_REFERENCE;
- res.type = new PointerDataType(DataType.VOID);
+ res.type = new PointerDataType(VoidDataType.dataType);
int nameIndex = ((ConstantPoolClassInfo) poolRef).getNameIndex();
ConstantPoolUtf8Info utf8Info = (ConstantPoolUtf8Info) constantPool[nameIndex];
String classNameWithSemicolon = utf8Info.getString();
diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LanguageProviderPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LanguageProviderPluginScreenShots.java
index f17d1c14c1..64af927171 100644
--- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LanguageProviderPluginScreenShots.java
+++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LanguageProviderPluginScreenShots.java
@@ -37,7 +37,8 @@ public class LanguageProviderPluginScreenShots extends GhidraScreenShotGenerator
@Test
public void testLanguages() {
- final SetLanguageDialog dialog = new SetLanguageDialog(tool, program);
+ final SetLanguageDialog dialog = new SetLanguageDialog(tool, program,
+ "Set Language: " + program.getDomainFile().getName());
Object newLanguagePanel = getInstanceField("selectLangPanel", dialog);
final GTableFilterPanel> filterPanel =
(GTableFilterPanel>) getInstanceField("tableFilterPanel", newLanguagePanel);