mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge branch 'GP-2308_1633_ghidra1_FunctionDefinitionCallingConventions'
(Closes #4537, Closes #4898, Closes #3723, Closes #3267)
This commit is contained in:
commit
2cdaebf0c3
273 changed files with 8249 additions and 3415 deletions
|
@ -23,16 +23,13 @@ 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.data.*;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
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.
|
||||
|
@ -43,12 +40,19 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB
|
|||
/**
|
||||
* DB_VERSION should be incremented any time a change is made to the overall
|
||||
* database schema associated with any of the managers.
|
||||
* 18-Sep-2008 - version 1 - added fields for synchronizing program data types with project archives.
|
||||
* 18-Sep-2008 - version 1 - Added fields for synchronizing program data types with project archives.
|
||||
* 03-Dec-2009 - version 2 - Added source archive updating (consolidating windows.gdt, clib.gdt, ntddk.gdt)
|
||||
* 14-Nov-2019 - version 3 - Corrected fixed length indexing implementation causing change
|
||||
* in index table low-level storage for newly created tables.
|
||||
* 20-Apr-2023 - version 4 - Added architecture support and string-based function calling
|
||||
* convention specification.
|
||||
*
|
||||
* NOTE: In reality version is based entirely on the underlying {@link StandAloneDataTypeManager}
|
||||
* implementation and its ability to detect and manage versioning concerns. Due to the need to
|
||||
* always support opening in a read-only fashion we are unable to impose a forced upgrade
|
||||
* requirement.
|
||||
*/
|
||||
static final int DB_VERSION = 3;
|
||||
static final int DB_VERSION = 4;
|
||||
|
||||
/**
|
||||
* UPGRADE_REQUIRED_BEFORE_VERSION should be changed to DB_VERSION any time the
|
||||
|
@ -493,7 +497,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 +510,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* <B>NOTE:</B> 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<Long> deletedIds, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
long[] ids = new long[deletedIds.size()];
|
||||
Iterator<Long> it = deletedIds.iterator();
|
||||
int i = 0;
|
||||
while (it.hasNext()) {
|
||||
ids[i++] = it.next().longValue();
|
||||
}
|
||||
// dataTypeArchive.getCodeManager().clearData(ids, monitor);
|
||||
// TODO
|
||||
protected void deleteDataTypeIDs(LinkedList<Long> 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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -47,6 +47,7 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
protected DataType baseDataType;
|
||||
|
||||
protected int level = 0;
|
||||
|
||||
protected ProgramDataTypeManager dataMgr;
|
||||
|
||||
private Boolean hasMutabilitySetting;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> 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<String> getCallingConventionNames() throws IOException;
|
||||
|
||||
}
|
|
@ -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<String> conventionAdded) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getCallingConventionName(byte id) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void invalidateCache() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<String> getCallingConventionNames() throws IOException {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String, Byte> callingConventionNameToIDMap;
|
||||
private Map<Byte, String> 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<Byte> 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<Range<Byte>> it = freeKeySet.asRanges().iterator();
|
||||
if (!it.hasNext()) {
|
||||
return -1;
|
||||
}
|
||||
Range<Byte> 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<String> 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<String> getCallingConventionNames() throws IOException {
|
||||
populateCache();
|
||||
return callingConventionNameToIDMap.keySet();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -518,9 +518,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType {
|
|||
|
||||
@Override
|
||||
public SourceArchive getSourceArchive() {
|
||||
if (dataMgr == null) {
|
||||
return null;
|
||||
}
|
||||
return dataMgr.getSourceArchive(getSourceArchiveID());
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<DBRecord> 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<DBRecord> 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
|
||||
*/
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<UniversalID, SourceArchive> windowsMap;
|
||||
private Map<UniversalID, SourceArchive> defaultMap;
|
||||
|
||||
private Map<UniversalID, SourceArchive> 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<UniversalID, SourceArchive>();
|
||||
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<UniversalID, SourceArchive>();
|
||||
|
||||
// create defaultMap
|
||||
defaultMap = new HashMap<UniversalID, SourceArchive>();
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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--) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<FunctionDB> cache;
|
||||
private FunctionAdapter adapter;
|
||||
private ThunkFunctionAdapter thunkAdapter;
|
||||
private CallingConventionDBAdapter callingConventionAdapter;
|
||||
private Map<String, Byte> callingConventionNameToIDMap = new HashMap<>();
|
||||
private Map<Byte, String> 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<String> getCallingConventionNames() {
|
||||
CompilerSpec compilerSpec = program.getCompilerSpec();
|
||||
PrototypeModel[] namedCallingConventions = compilerSpec.getCallingConventions();
|
||||
List<String> 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<String> 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<PrototypeModel> 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 {
|
||||
|
||||
|
|
|
@ -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<SymbolDB> 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.
|
||||
* <p>
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -60,4 +60,9 @@ public class VariableStorageDBAdapterNoTable extends VariableStorageDBAdapter {
|
|||
int getRecordCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
void deleteTable() {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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<Varnode> 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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<String> 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;
|
||||
|
|
|
@ -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 \<bitfield_packing> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \<data_organization> 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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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<Composite> getAllComposites();
|
||||
|
||||
/**
|
||||
* Returns an iterator over all function definition data types in this manager
|
||||
* @return the iterator
|
||||
*/
|
||||
public Iterator<FunctionDefinition> 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<String> 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.
|
||||
* <p>
|
||||
* 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<String> 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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -73,4 +73,8 @@ public class DataTypeManagerChangeListenerAdapter implements DataTypeManagerChan
|
|||
public void sourceArchiveChanged(DataTypeManager dataTypeManager, SourceArchive dataTypeSource) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* <B>NOTE:</B> 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.
|
||||
* <p>
|
||||
* <B>NOTE:</B> 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.
|
||||
* <p>
|
||||
* <B>NOTE:</B> 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 {
|
||||
|
|
|
@ -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.
|
||||
* <br>
|
||||
* 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.
|
||||
* <br>
|
||||
* 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
|
||||
*
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -21,6 +21,10 @@ import ghidra.program.model.lang.CompilerSpec;
|
|||
* <code>GenericCallingConvention</code> 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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue