diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/SymPcodeExecutor.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/SymPcodeExecutor.java
index b6585a3794..9b3f916907 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/SymPcodeExecutor.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/SymPcodeExecutor.java
@@ -264,9 +264,9 @@ class SymPcodeExecutor extends PcodeExecutor {
// TODO: Does the decompiler communicate the inferred calling convention?
try {
PrototypeModel convention = program.getCompilerSpec().findBestCallingConvention(params);
- sig.setGenericCallingConvention(convention.getGenericCallingConvention());
+ sig.setCallingConvention(convention.getName());
}
- catch (SleighException e) {
+ catch (SleighException | InvalidInputException e) {
// Whatever, just leave sig at "unknown"
}
return sig;
@@ -352,7 +352,7 @@ class SymPcodeExecutor extends PcodeExecutor {
throw new PcodeExecutionException("Cannot get stack change for indirect call: " + op);
}
PrototypeModel convention =
- program.getCompilerSpec().matchConvention(sig.getGenericCallingConvention());
+ program.getCompilerSpec().matchConvention(sig.getCallingConventionName());
if (convention == null) {
warnings.add(new UnspecifiedConventionStackUnwindWarning(null));
convention = program.getCompilerSpec().getDefaultCallingConvention();
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
index fc96d2e0c2..c2bd9b7db7 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
@@ -24,7 +24,9 @@ import db.DBHandle;
import ghidra.framework.model.DomainFile;
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.*;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceManager;
import ghidra.trace.model.data.TraceBasedDataTypeManager;
@@ -38,15 +40,36 @@ import ghidra.util.task.TaskMonitor;
public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
implements TraceBasedDataTypeManager, DBTraceManager {
- protected final ReadWriteLock lock;
+ protected final ReadWriteLock lock; // TODO: This lock object is not used
protected final DBTrace trace;
+ private static final String INSTANCE_TABLE_PREFIX = null; // placeholder only
+
public DBTraceDataTypeManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
TaskMonitor monitor, DBTrace trace)
throws CancelledException, VersionException, IOException {
- super(dbh, null, openMode.toInteger(), trace, trace.getLock(), monitor);
+ super(dbh, null, openMode.toInteger(), INSTANCE_TABLE_PREFIX, trace, trace.getLock(),
+ monitor);
this.lock = lock; // TODO: nothing uses this local lock - not sure what its purpose is
this.trace = trace;
+
+ setProgramArchitecture(new ProgramArchitecture() {
+
+ @Override
+ public Language getLanguage() {
+ return trace.getBaseLanguage();
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return trace.getBaseCompilerSpec();
+ }
+
+ @Override
+ public AddressFactory getAddressFactory() {
+ return trace.getBaseAddressFactory();
+ }
+ }, null, false, monitor);
}
@Override
@@ -233,12 +256,4 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
*/
return ArchiveType.PROGRAM;
}
-
- @Override
- public DataOrganization getDataOrganization() {
- if (dataOrganization == null) {
- dataOrganization = trace.getBaseCompilerSpec().getDataOrganization();
- }
- return dataOrganization;
- }
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java
index 6b4ed7fd84..8381a53d49 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java
@@ -15,11 +15,11 @@
*/
package ghidra.trace.database.program;
-import static ghidra.lifecycle.Unfinished.TODO;
+import static ghidra.lifecycle.Unfinished.*;
import java.io.IOException;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import generic.NestedIterator;
import ghidra.program.database.ProgramDB;
@@ -64,7 +64,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
}
@Override
- public List getCallingConventionNames() {
+ public Collection getCallingConventionNames() {
return functions.getCallingConventionNames();
}
@@ -78,11 +78,6 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
return functions.getCallingConvention(name);
}
- @Override
- public PrototypeModel[] getCallingConventions() {
- return functions.getCallingConventions();
- }
-
@Override
public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body,
SourceType source) throws InvalidInputException, OverlappingFunctionException {
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java
index 0da88f305d..b3678a2333 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java
@@ -22,6 +22,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import db.DBRecord;
+import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
@@ -33,6 +34,7 @@ import ghidra.program.model.symbol.*;
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec;
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
import ghidra.trace.database.bookmark.DBTraceBookmarkType;
+import ghidra.trace.database.data.DBTraceDataTypeManager;
import ghidra.trace.database.listing.DBTraceCommentAdapter;
import ghidra.trace.database.listing.DBTraceData;
import ghidra.trace.database.program.DBTraceProgramView;
@@ -122,7 +124,7 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
@DBAnnotatedField(column = FIXUP_COLUMN_NAME)
protected String callFixup;
@DBAnnotatedField(column = CALLING_CONVENTION_COLUMN_NAME)
- protected byte callingConventionID = DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_ID;
+ protected byte callingConventionID = DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID;
// TODO: Pack into flags if more bits needed
@DBAnnotatedField(column = SIGNATURE_SOURCE_COLUMN_NAME)
protected SourceType signatureSource = SourceType.ANALYSIS; // Assumed default, 0-ordinal
@@ -484,7 +486,8 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
}
protected boolean hasExplicitCallingConvention() {
- return callingConventionID != -1 && callingConventionID != -2;
+ return callingConventionID != DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID &&
+ callingConventionID != DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID;
}
@Override
@@ -1734,16 +1737,14 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
if (cs == null) {
return null;
}
- if (DBTraceSymbolManager.UNKNOWN_CALLING_CONVENTION_ID == callingConventionID) {
+ DBTraceDataTypeManager dtm = manager.dataTypeManager;
+ if (callingConventionID == DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID) {
return null;
}
- if (DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_ID == callingConventionID) {
+ if (callingConventionID == DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID) {
return cs.getDefaultCallingConvention();
}
- String ccName = manager.callingConventionMap.getKey(callingConventionID);
- if (ccName == null) {
- return null;
- }
+ String ccName = dtm.getCallingConventionName(callingConventionID);
return cs.getCallingConvention(ccName);
}
}
@@ -1751,28 +1752,8 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
@Override
public String getCallingConventionName() {
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
- if (DBTraceSymbolManager.UNKNOWN_CALLING_CONVENTION_ID == callingConventionID) {
- return null;
- }
- if (DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_ID == callingConventionID) {
- return DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_NAME;
- }
- return manager.callingConventionMap.getKey(callingConventionID);
- }
- }
-
- @Override
- public String getDefaultCallingConventionName() {
- try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
- PrototypeModel cc = manager.functions.getDefaultCallingConvention();
- if (cc == null) {
- return DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_NAME;
- }
- String ccName = cc.getName();
- if (ccName == null) { // Really?
- return DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_NAME;
- }
- return ccName;
+ DBTraceDataTypeManager dtm = manager.dataTypeManager;
+ return dtm.getCallingConventionName(callingConventionID);
}
}
@@ -1783,12 +1764,16 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
thunked.setCallingConvention(name);
return;
}
- if (Objects.equals(getCallingConventionName(), name)) {
- return;
+
+ DBTraceDataTypeManager dtm = manager.dataTypeManager;
+ byte id = dtm.getCallingConventionID(name, true);
+ if (id == callingConventionID) {
+ return; // no change
}
+
doLoadVariables();
- this.callingConventionID = manager.findOrRecordCallingConvention(name);
+ callingConventionID = id;
update(CALLING_CONVENTION_COLUMN);
boolean hasCustomStorage = hasCustomVariableStorage();
@@ -1813,11 +1798,14 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), this));
}
}
+ catch (IOException e) {
+ manager.dbError(e);
+ }
}
protected void createClassStructIfNeeded() {
PrototypeModel cc = getCallingConvention();
- if (cc == null || cc.getGenericCallingConvention() != GenericCallingConvention.thiscall) {
+ if (cc == null || !CompilerSpec.CALLING_CONVENTION_thiscall.equals(cc.getName())) {
return;
}
Namespace parentNS = getParentNamespace();
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolView.java
index bbdd19f432..7bda22e323 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolView.java
@@ -15,8 +15,7 @@
*/
package ghidra.trace.database.symbol;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.database.symbol.OverlappingNamespaceException;
@@ -165,54 +164,19 @@ public class DBTraceFunctionSymbolView
}
}
- public static List getCallingConventionNames(CompilerSpec cs) {
- PrototypeModel[] namedCCs = cs.getCallingConventions();
- List names = new ArrayList<>(2 + namedCCs.length);
- names.add(Function.UNKNOWN_CALLING_CONVENTION_STRING);
- names.add(Function.DEFAULT_CALLING_CONVENTION_STRING);
- for (PrototypeModel model : namedCCs) {
- names.add(model.getName());
- }
- return names;
- }
-
@Override
- public List getCallingConventionNames() {
- // TODO: Allow for user-selected compiler spec(s)
- return getCallingConventionNames(manager.trace.getBaseCompilerSpec());
+ public Collection getCallingConventionNames() {
+ return manager.dataTypeManager.getDefinedCallingConventionNames();
}
@Override
public PrototypeModel getDefaultCallingConvention() {
- CompilerSpec cs = manager.trace.getBaseCompilerSpec();
- if (cs == null) {
- return null;
- }
- return cs.getDefaultCallingConvention();
+ return manager.dataTypeManager.getDefaultCallingConvention();
}
@Override
public PrototypeModel getCallingConvention(String name) {
- CompilerSpec cs = manager.trace.getBaseCompilerSpec();
- if (cs == null) {
- return null;
- }
- if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
- return null;
- }
- if (Function.DEFAULT_CALLING_CONVENTION_STRING.equals(name)) {
- return cs.getDefaultCallingConvention();
- }
- return cs.getCallingConvention(name);
- }
-
- @Override
- public PrototypeModel[] getCallingConventions() {
- CompilerSpec cs = manager.trace.getBaseCompilerSpec();
- if (cs == null) {
- return EMPTY_MODEL_LIST;
- }
- return cs.getCallingConventions();
+ return manager.dataTypeManager.getCallingConvention(name);
}
// TODO: Move this into a FunctionUtilities class?
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java
index d3cd85d3b4..ff43266523 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java
@@ -20,9 +20,6 @@ import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
-import org.apache.commons.collections4.BidiMap;
-import org.apache.commons.collections4.bidimap.DualHashBidiMap;
-
import db.*;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
@@ -60,11 +57,6 @@ import ghidra.util.task.TaskMonitor;
* TODO: See if CALL-type references produce dynamic labels or functions.
*/
public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager {
- protected static final byte DEFAULT_CALLING_CONVENTION_ID = -1;
- protected static final byte UNKNOWN_CALLING_CONVENTION_ID = -2;
-
- protected static final String DEFAULT_CALLING_CONVENTION_NAME = "default";
- protected static final String UNKNOWN_CALLING_CONVENTION_NAME = "unknown";
private static final long TYPE_MASK = 0xFF;
private static final int TYPE_SHIFT = 64 - 8;
@@ -101,32 +93,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
}
}
- @DBAnnotatedObjectInfo(version = 0)
- public static class DBTraceCallingConventionEntry extends DBAnnotatedObject {
- static final String TABLE_NAME = "CallingConventions";
-
- static final String NAME_COLUMN_NAME = "Name";
-
- @DBAnnotatedColumn(NAME_COLUMN_NAME)
- static DBObjectColumn NAME_COLUMN;
-
- @DBAnnotatedField(column = NAME_COLUMN_NAME)
- String name;
-
- public DBTraceCallingConventionEntry(DBCachedObjectStore> store, DBRecord record) {
- super(store, record);
- }
-
- public void setName(String name) {
- this.name = name;
- update(NAME_COLUMN);
- }
-
- public String getName() {
- return name;
- }
- }
-
@DBAnnotatedObjectInfo(version = 0)
public static class DBTraceFunctionTag extends DBAnnotatedObject implements FunctionTag {
@@ -435,9 +401,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
protected final DBTraceAddressSnapRangePropertyMap idMap;
- protected final DBCachedObjectStore callingConventionStore;
- protected final BidiMap callingConventionMap = new DualHashBidiMap<>();
-
protected final DBCachedObjectStore tagStore;
protected final DBCachedObjectIndex tagsByName;
@@ -494,11 +457,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
baseLanguage, trace, threadManager, DBTraceSymbolIDEntry.class,
DBTraceSymbolIDEntry::new);
- callingConventionStore =
- factory.getOrCreateCachedStore(DBTraceCallingConventionEntry.TABLE_NAME,
- DBTraceCallingConventionEntry.class, DBTraceCallingConventionEntry::new, true);
- loadCallingConventions();
-
tagStore = factory.getOrCreateCachedStore(DBTraceFunctionTag.TABLE_NAME,
DBTraceFunctionTag.class, (s, r) -> new DBTraceFunctionTag(this, s, r), true);
tagsByName = tagStore.getIndex(String.class, DBTraceFunctionTag.NAME_COLUMN);
@@ -570,9 +528,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
if (ptrSize != dataTypeManager.getDataOrganization().getPointerSize()) {
return dataTypeManager.getPointer(formal, ptrSize);
}
- else {
- return dataTypeManager.getPointer(formal);
- }
+ return dataTypeManager.getPointer(formal);
}
protected > T putInMap(T view) {
@@ -608,25 +564,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
return (symbolID >> KEY_SHIFT) & KEY_MASK;
}
- protected void loadCallingConventions() {
- // NOTE: Should already own write lock
- for (DBTraceCallingConventionEntry ent : callingConventionStore.asMap().values()) {
- // NOTE: No need to check. Only called on new or invalidate.
- callingConventionMap.put(ent.name, (byte) ent.getKey());
- }
- }
-
- protected byte doRecordCallingConvention(String name) {
- DBTraceCallingConventionEntry ent = callingConventionStore.create();
- ent.setName(name);
- return (byte) ent.getKey();
- }
-
- protected byte findOrRecordCallingConvention(String name) {
- // NOTE: Must already have write lock
- return callingConventionMap.computeIfAbsent(name, this::doRecordCallingConvention);
- }
-
protected int findOrRecordVariableStorage(VariableStorage storage) {
DBTraceVariableStorageEntry entry = storageByStorage.getOne(storage);
if (entry == null) {
@@ -645,9 +582,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
public void invalidateCache(boolean all) {
try (LockHold hold = LockHold.lock(lock.writeLock())) {
idMap.invalidateCache(all);
- callingConventionStore.invalidateCache();
- callingConventionMap.clear();
- loadCallingConventions();
for (AbstractDBTraceSymbolSingleTypeView> view : symbolViews.values()) {
view.invalidateCache();
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbolView.java
index 8137ea34d2..5fd3000820 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbolView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbolView.java
@@ -15,7 +15,7 @@
*/
package ghidra.trace.model.symbol;
-import java.util.List;
+import java.util.Collection;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.Address;
@@ -37,11 +37,30 @@ public interface TraceFunctionSymbolView extends TraceSymbolWithLocationView getCallingConventionNames();
+ /**
+ * Get the ordered unmodifiable set of defined calling convention names. The reserved names
+ * "unknown" and "default" are not included. The returned collection may not include all names
+ * referenced by various functions and function-definitions. This set is limited to
+ * those defined by the associated compiler specification.
+ *
+ * @return the set of defined calling convention names.
+ */
+ Collection getCallingConventionNames();
+ /**
+ * Get the default calling convention's prototype model.
+ *
+ * @return the default calling convention prototype model.
+ */
PrototypeModel getDefaultCallingConvention();
+ /**
+ * Get the prototype model of the calling convention with the specified name from the
+ * associated compiler specification. 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 if not defined.
+ */
PrototypeModel getCallingConvention(String name);
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManagerTest.java
index 5a12f6b8e6..7e1255b2e1 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManagerTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManagerTest.java
@@ -19,8 +19,8 @@ import static ghidra.lifecycle.Unfinished.*;
import static org.junit.Assert.*;
import java.io.IOException;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import org.junit.*;
@@ -423,25 +423,12 @@ public class DBTraceProgramViewFunctionManagerTest extends AbstractGhidraHeadles
assertEquals(defaultModel, protoModel);
}
- @Test
- public void testGetCallingConventions() throws Exception {
- PrototypeModel[] protoModels = functionManager.getCallingConventions();
- assertTrue(protoModels.length >= 1);
- }
-
@Test
public void testGetCallingConventionNames() throws Exception {
-
- List names = functionManager.getCallingConventionNames();
+ Collection names = functionManager.getCallingConventionNames();
assertTrue(names.size() >= 1);
-
for (String name : names) {
- if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
- assertNull(functionManager.getCallingConvention(name));
- }
- else {
- assertNotNull(functionManager.getCallingConvention(name));
- }
+ assertNotNull(functionManager.getCallingConvention(name));
}
}
diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest
index 59208a051b..4ceb05162e 100644
--- a/Ghidra/Features/Base/certification.manifest
+++ b/Ghidra/Features/Base/certification.manifest
@@ -30,8 +30,9 @@ data/parserprofiles/MacOSX_10.9.prf||GHIDRA||||END|
data/parserprofiles/MacOSX_Cocoa.prf||GHIDRA||||END|
data/parserprofiles/VisualStudio12_32.prf||GHIDRA||||END|
data/parserprofiles/VisualStudio12_64.prf||GHIDRA||||END|
-data/parserprofiles/VisualStudio9.prf||GHIDRA||reviewed||END|
-data/parserprofiles/clib.prf||GHIDRA||reviewed||END|
+data/parserprofiles/VisualStudio22_64.prf||GHIDRA||||END|
+data/parserprofiles/VisualStudio9.prf||GHIDRA||||END|
+data/parserprofiles/clib.prf||GHIDRA||||END|
data/parserprofiles/generic_clib_32.prf||GHIDRA||||END|
data/parserprofiles/generic_clib_64.prf||GHIDRA||||END|
data/parserprofiles/linux_32.prf||GHIDRA||||END|
diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf
index d6d7265a87..929ce4271e 100644
--- a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf
@@ -207,7 +207,6 @@ zlib.h
-DTARGET_API_MAC_OSX
-DTARGET_COCOA
-DHANDLE="unsigned long"
--D_WCHAR_T
-D_Complex
-Drestrict
-D__restrict
diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf
index d084caa7ba..ef2649046e 100644
--- a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf
@@ -323,7 +323,6 @@ zlib.h
-D_MAC_
-DTARGET_API_MAC_OSX
-DHANDLE="unsigned long"
--D_WCHAR_T
-D_Complex
-Drestrict
-D__restrict
diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf
index ad295be77e..8daa8f9d32 100644
--- a/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf
@@ -28,7 +28,6 @@ Cocoa\Cocoa.h
-D_MAC_
-DTARGET_API_MAC_OSX=1
-DHANDLE="unsigned long"
--D_WCHAR_T
-D_Complex
-Drestrict
-D__restrict
diff --git a/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_32.prf b/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_32.prf
index b65e318471..2dd5df02d2 100644
--- a/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_32.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_32.prf
@@ -172,12 +172,8 @@ wpcapi.h
wscapi.h
wsdapi.h
wspiapi.h
-
rpcproxy.h
--I/VC/VS12/src
--I/VC/VS12/include
--I/VC/SDK/v7.1A/Include
-D_M_IX86=300
-D_MSC_VER=1200
-D_INTEGRAL_MAX_BITS=32
@@ -191,7 +187,6 @@ rpcproxy.h
-DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
--D_WCHAR_T_DEFINED
-DCONST=const
-D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE
@@ -205,3 +200,14 @@ rpcproxy.h
-D_ThrowInfo=ThrowInfo
-v0
-D__inner_checkReturn=""
+
+/data/HeaderFiles/VC/VS12/src
+/data/HeaderFiles/VC/VS12/include
+/data/HeaderFiles/VC/SDK/v7.1A/Include
+
+x86:LE:32:default
+
+windows
+
+
+
diff --git a/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_64.prf b/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_64.prf
index aa7101f648..b30064ecc3 100644
--- a/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_64.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_64.prf
@@ -172,12 +172,8 @@ wpcapi.h
wscapi.h
wsdapi.h
wspiapi.h
-
rpcproxy.h
--I/VC/VS12/src
--I/VC/VS12/include
--I/VC/SDK/v7.1A/Include
-D_M_IX86=300
-D_MSC_VER=1200
-D_INTEGRAL_MAX_BITS=64
@@ -193,7 +189,6 @@ rpcproxy.h
-DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
--D_WCHAR_T_DEFINED
-DCONST=const
-D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE
@@ -208,3 +203,11 @@ rpcproxy.h
-D__unaligned=""
-v0
-D__inner_checkReturn=""
+
+/data/HeaderFiles/VC/VS12/include
+/data/HeaderFiles/VC/VS12/src
+/data/HeaderFiles/VC/SDK/v7.1A/Include
+
+
+
+
diff --git a/Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf b/Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf
new file mode 100644
index 0000000000..88d953a047
--- /dev/null
+++ b/Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf
@@ -0,0 +1,341 @@
+# Core necessary files
+winapifamily.h
+winpackagefamily.h
+sdkddkver.h
+sal.h
+no_sal2.h
+corecrt.h
+wtypes.h
+winnt.h
+winternl.h
+#ntdef.h
+# Common headers
+dos.h
+errno.h
+malloc.h
+signal.h
+stdalign.h
+stddef.h
+stdio.h
+stdlib.h
+assert.h
+crtdbg.h
+ctype.h
+conio.h
+direct.h
+fcntl.h
+float.h
+fpieee.h
+inttypes.h
+io.h
+locale.h
+complex.h
+math.h
+mbctype.h
+mbstring.h
+memory.h
+minmax.h
+new.h
+process.h
+search.h
+share.h
+winbase.h
+winuser.h
+Windows.h
+# Security and identity (https://docs.microsoft.com/en-us/windows/win32/api/_security/)
+accctrl.h
+aclapi.h
+aclui.h
+advapi32.h
+adtgen.h
+authz.h
+azroles.h
+bcrypt.h
+casetup.h
+ccgplugins.h
+celib.h
+ntlsa.h
+sspi.h
+ntsecapi.h
+ntsecpkg.h
+schannel.h
+certadm.h
+certbcli.h
+certcli.h
+certenroll.h
+certexit.h
+certif.h
+certmod.h
+certpol.h
+certpoleng.h
+certsrv.h
+certview.h
+credssp.h
+cryptdlg.h
+cryptuiapi.h
+cryptxml.h
+diagnosticdataquery.h
+diagnosticdataquerytypes.h
+dpapi.h
+dssec.h
+iads.h
+identitycommon.h
+identityprovider.h
+identitystore.h
+keycredmgr.h
+lmaccess.h
+lsalookup.h
+mmcobj.h
+mscat.h
+mssip.h
+namedpipeapi.h
+ncrypt.h
+ncryptprotect.h
+npapi.h
+processthreadsapi.h
+sas.h
+scesvc.h
+sddl.h
+securityappcontainer.h
+securitybaseapi.h
+slpublic.h
+subauth.h
+tokenbinding.h
+tpmvscmgr.h
+wincred.h
+wincrypt.h
+winnetwk.h
+winreg.h
+winsafer.h
+winscard.h
+winsvc.h
+wintrust.h
+winwlx.h
+xenroll.h
+# Windows sockets
+af_irda.h
+in6addr.h
+mstcpip.h
+ws2def.h
+winsock.h
+winsock2.h
+nsemail.h
+nspapi.h
+socketapi.h
+# Nothing includes this; is it necessary?
+#sporder.h
+transportsettingcommon.h
+ws2atm.h
+ws2spi.h
+mswsock.h
+ws2tcpip.h
+wsipv6ok.h
+wsnwlink.h
+wsrm.h
+mswsockdef.h
+# Remote Procedure Call (RPC)
+midles.h
+midlbase.h
+rpc.h
+rpcndr.h
+rpcasync.h
+rpcdcep.h
+rpcnsi.h
+rpcproxy.h
+rpcssl.h
+# COM
+accctrl.h
+callobj.h
+combaseapi.h
+comcat.h
+ctxtcall.h
+dmerror.h
+docobj.h
+eventsys.h
+guiddef.h
+iaccess.h
+hstring.h
+imessagedispatcher.h
+messagedispatcherapi.h
+objbase.h
+objidlbase.h
+objidl.h
+ocidl.h
+ole.h
+ole2.h
+oledlg.h
+oleidl.h
+roapi.h
+rpcdce.h
+servprov.h
+shobjidl.h
+txlogpub.h
+unknwnbase.h
+unknwn.h
+urlmon.h
+vbinterf.h
+winddi.h
+winerror.h
+wtypesbase.h
+# COM+
+comadmin.h
+mtxdm.h
+# More
+inspectable.h
+# Windows Internet
+proofofpossessioncookieinfo.h
+wininet.h
+winineti.h
+# Windows HTTP Services
+winhttp.h
+# Compression
+compressapi.h
+# TraceLogging
+#traceloggingactivity.h
+#traceloggingprovider.h
+# Windows Error Reporting
+errorrep.h
+werapi.h
+# Windows and MEssages
+olectl.h
+windef.h
+windowsx.h
+# Shell
+appmgmt.h
+appnotify.h
+cpl.h
+credentialprovider.h
+dimm.h
+imagetranscode.h
+inputpanelconfiguration.h
+intsafe.h
+intshcut.h
+mobsync.h
+objectarray.h
+pathcch.h
+profinfo.h
+propkeydef.h
+scrnsave.h
+shappmgr.h
+shdeprecated.h
+shidfact.h
+shimgdata.h
+shlwapi.h
+shtypes.h
+storageprovider.h
+syncmgr.h
+thumbcache.h
+thumbnailstreamcache.h
+tlogstg.h
+userenv.h
+# Windows Controls
+commctrl.h
+commoncontrols.h
+dpa_dsa.h
+prsht.h
+richedit.h
+richole.h
+shlobj_core.h
+shlobj.h
+#textserv.h // C++
+tom.h
+uxtheme.h
+# Menus and other resources
+resourceindexer.h
+strsafe.h
+verrsrc.h
+winver.h
+# Windows Accessibility Features
+oleacc.h
+uiautomationcore.h
+uiautomationclient.h
+uiautomationcoreapi.h
+# Internationalization
+datetimeapi.h
+elscore.h
+gb18030.h
+imepad.h
+imm.h
+immdev.h
+msime.h
+msimeapi.h
+muiload.h
+spellcheck.h
+spellcheckprovider.h
+stringapiset.h
+usp10.h
+winnls.h
+# HTTP Server API
+#http.h // included by something else
+# IP Helper
+ifdef.h
+inaddr.h
+ip2string.h
+ipexport.h
+iphlpapi.h
+icmpapi.h
+iprtrmib.h
+iptypes.h
+netioapi.h
+nldef.h
+tcpestats.h
+ws2ipdef.h
+# Network Management
+atacct.h
+lmalert.h
+lmapibuf.h
+lmat.h
+lmaudit.h
+lmconfig.h
+lmerrlog.h
+lmjoin.h
+lmmsg.h
+lmremutl.h
+lmserver.h
+lmsvc.h
+lmuse.h
+lmwksta.h
+
+-D_MSC_VER=1924
+-D_INTEGRAL_MAX_BITS=64
+-DWINVER=0x0a00
+-D_WIN32_WINNT=0x0a00
+-D_AMD64_
+-D_M_AMD64
+-D_M_X64
+-D_WIN64
+-D_WIN32
+-D_USE_ATTRIBUTES_FOR_SAL
+-D_CRTBLD
+-D_OPENMP_NOFORCE_MANIFEST
+-DSTRSAFE_LIB
+-DSTRSAFE_LIB_IMPL
+-DLPSKBINFO=LPARAM
+-DCONST=const
+-D_CRT_SECURE_NO_WARNINGS
+-D_CRT_NONSTDC_NO_DEPRECATE
+-D_CRT_NONSTDC_NO_WARNINGS
+-D_CRT_OBSOLETE_NO_DEPRECATE
+-D_ALLOW_KEYWORD_MACROS
+-D_ASSERT_OK
+-DSTRSAFE_NO_DEPRECATE
+-D__possibly_notnullterminated
+"-Dtype_info=\"void *\"",
+-D_ThrowInfo=ThrowInfo
+-D__unaligned=
+-v0
+-D__inner_checkReturn=
+-DWINAPI_PARTITION_APP=1
+-DWINAPI_PARTITION_SYSTEM=1
+-DWINAPI_PARTITION_GAMES=1
+-DSECURITY_WIN32
+
+/data/HeaderFiles/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include
+/data/HeaderFiles/VC/VS22/10.0.19041.0/shared
+/data/HeaderFiles/VC/VS22/10.0.19041.0/ucrt
+/data/HeaderFiles/VC/VS22/10.0.19041.0/um
+/data/HeaderFiles/VC/VS22/10.0.19041.0/winrt
+
+x86:LE:64:default
+
+windows
diff --git a/Ghidra/Features/Base/data/parserprofiles/VisualStudio9.prf b/Ghidra/Features/Base/data/parserprofiles/VisualStudio9.prf
index 3a4b3376b8..d96adeb393 100644
--- a/Ghidra/Features/Base/data/parserprofiles/VisualStudio9.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/VisualStudio9.prf
@@ -58,13 +58,10 @@ yvals.h
CommDlg.h
WinUser.h
WinNls.h
-C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src\internal.h
+internal.h
strsafe.h
penwin.h
--IC:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Include
--IC:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include
--IC:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
-D_M_IX86=500
-D_MSC_VER=9090
-D_MSC_EXTENSIONS
@@ -85,5 +82,11 @@ penwin.h
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
-D_PHNDLR=void *
--D_WCHAR_T_DEFINED
-DCONST=const
+
+C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Include
+C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include
+C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
+
+x86:LE:64:default
+
diff --git a/Ghidra/Features/Base/data/parserprofiles/clib.prf b/Ghidra/Features/Base/data/parserprofiles/clib.prf
index 6cbd35baac..04fa31722d 100644
--- a/Ghidra/Features/Base/data/parserprofiles/clib.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/clib.prf
@@ -78,13 +78,17 @@ wchar.h
wctype.h
wordexp.h
--IU:\linux_include\include
--IU:\linux_include\include\sys
--IU:\linux_include\i386-redhat-linux\4.1.2\include
-D_X86_
-D__STDC__
-D__WORDSIZE=32
-D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE
-D_Complex
--D_WCHAR_T
+
+U:\linux_include\include
+U:\linux_include\include\sys
+U:\linux_include\i386-redhat-linux\4.1.2\include
+
+x86:LE:32:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf b/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf
index 3d331f0ffd..188be92604 100644
--- a/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf
@@ -219,11 +219,6 @@ arpa/nameser_compat.h
arpa/telnet.h
arpa/tftp.h
--I/linux/include
--I/linux/include/sys
--I/linux/gcc/include
--I/linux/x86_64-redhat-linux5E/include
--I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_
-D__STDC__
-D_GNU_SOURCE
@@ -231,10 +226,19 @@ arpa/tftp.h
-D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE
-D_Complex
--D_WCHAR_T
-D__NO_STRING_INLINES
-D__NO_LONG_DOUBLE_MATH
-D__signed__
-D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t
+
+/data/HeaderFiles/linux/include
+/data/HeaderFiles/linux/include/sys
+/data/HeaderFiles/linux/gcc/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
+
+x86:LE:32:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf b/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf
index 0c76e8d1aa..af46b60039 100644
--- a/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf
@@ -219,11 +219,6 @@ arpa/nameser_compat.h
arpa/telnet.h
arpa/tftp.h
--I/linux/include
--I/linux/include/sys
--I/linux/gcc/include
--I/linux/x86_64-redhat-linux5E/include
--I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_
-D__STDC__
-D_GNU_SOURCE
@@ -231,10 +226,19 @@ arpa/tftp.h
-D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE
-D_Complex
--D_WCHAR_T
-D__NO_STRING_INLINES
-D__signed__
-D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1
-D__need_sigset_t
-Daligned_u64=uint64_t
+
+/data/HeaderFiles/linux/include
+/data/HeaderFiles/linux/include/sys
+/data/HeaderFiles/linux/gcc/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
+
+x86:LE:64:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/linux_32.prf b/Ghidra/Features/Base/data/parserprofiles/linux_32.prf
index 5235499a8a..2c8fe49cf8 100644
--- a/Ghidra/Features/Base/data/parserprofiles/linux_32.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/linux_32.prf
@@ -515,11 +515,6 @@ mechglue.h
auth_gss.h
auth_gssapi.h
--I/linux/include
--I/linux/include/sys
--I/linux/gcc/include
--I/linux/x86_64-redhat-linux5E/include
--I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_
-D__STDC__
-D_POSIX_C_SOURCE
@@ -528,10 +523,19 @@ auth_gssapi.h
-D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE
-D_Complex
--D_WCHAR_T
-D__NO_STRING_INLINES
-D__NO_LONG_DOUBLE_MATH
-D__signed__
-D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t
+
+/data/HeaderFiles/linux/include
+/data/HeaderFiles/linux/include/sys
+/data/HeaderFiles/linux/gcc/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
+
+x86:LE:32:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/linux_64.prf b/Ghidra/Features/Base/data/parserprofiles/linux_64.prf
index f3c783c33b..2d714aef72 100644
--- a/Ghidra/Features/Base/data/parserprofiles/linux_64.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/linux_64.prf
@@ -515,11 +515,6 @@ mechglue.h
auth_gss.h
auth_gssapi.h
--I/linux/include
--I/linux/include/sys
--I/linux/gcc/include
--I/linux/x86_64-redhat-linux5E/include
--I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_
-D__STDC__
-D_POSIX_C_SOURCE
@@ -528,9 +523,18 @@ auth_gssapi.h
-D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE
-D_Complex
--D_WCHAR_T
-D__NO_STRING_INLINES
-D__signed__
-D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t
+
+/data/HeaderFiles/linux/include
+/data/HeaderFiles/linux/include/sys
+/data/HeaderFiles/linux/gcc/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
+
+x86:LE:64:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/vs12Local.prf b/Ghidra/Features/Base/data/parserprofiles/vs12Local.prf
index 7427750503..cdf7b4b8bd 100644
--- a/Ghidra/Features/Base/data/parserprofiles/vs12Local.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/vs12Local.prf
@@ -222,9 +222,6 @@ wscapi.h
wsdapi.h
wspiapi.h
--I/VisualStudio/VS12/include
--I/VisualStudio/Windows/v7.0a/Include
--I/VisualStudio/VS12/src
-D_M_IX86
-D_MSC_VER=9090
-D_INTEGRAL_MAX_BITS=32
@@ -239,7 +236,6 @@ wspiapi.h
-DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
--D_WCHAR_T_DEFINED
-DCONST=const
-D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE
@@ -250,3 +246,12 @@ wspiapi.h
-D__possibly_notnullterminated
-Dtype_info="void *"
-v0
+
+/data/HeaderFiles/VC/VS12/include
+/data/HeaderFiles/VC/Windows/v7.0a/Include
+/data/HeaderFiles/VC/VS12/src
+
+x86:LE:32:default
+
+windows
+
diff --git a/Ghidra/Features/Base/data/pcodetest/EmuTesting.gdt b/Ghidra/Features/Base/data/pcodetest/EmuTesting.gdt
index bcc5b355a1..c7657a7215 100644
Binary files a/Ghidra/Features/Base/data/pcodetest/EmuTesting.gdt and b/Ghidra/Features/Base/data/pcodetest/EmuTesting.gdt differ
diff --git a/Ghidra/Features/Base/data/typeinfo/generic/generic_clib.gdt b/Ghidra/Features/Base/data/typeinfo/generic/generic_clib.gdt
index b5399bdd0c..16a28c3c27 100644
Binary files a/Ghidra/Features/Base/data/typeinfo/generic/generic_clib.gdt and b/Ghidra/Features/Base/data/typeinfo/generic/generic_clib.gdt differ
diff --git a/Ghidra/Features/Base/data/typeinfo/generic/generic_clib_64.gdt b/Ghidra/Features/Base/data/typeinfo/generic/generic_clib_64.gdt
index 18cfbb8c9c..e89f7ba5af 100644
Binary files a/Ghidra/Features/Base/data/typeinfo/generic/generic_clib_64.gdt and b/Ghidra/Features/Base/data/typeinfo/generic/generic_clib_64.gdt differ
diff --git a/Ghidra/Features/Base/data/typeinfo/mac_10.9/mac_osx.gdt b/Ghidra/Features/Base/data/typeinfo/mac_10.9/mac_osx.gdt
index 8a73fe1325..cdb34ed6b2 100644
Binary files a/Ghidra/Features/Base/data/typeinfo/mac_10.9/mac_osx.gdt and b/Ghidra/Features/Base/data/typeinfo/mac_10.9/mac_osx.gdt differ
diff --git a/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_32.gdt b/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_32.gdt
index c34d8e0b13..2b77f5cca9 100644
Binary files a/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_32.gdt and b/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_32.gdt differ
diff --git a/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_64.gdt b/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_64.gdt
index 5ed3b70894..be58ee9d23 100644
Binary files a/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_64.gdt and b/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_64.gdt differ
diff --git a/Ghidra/Features/Base/ghidra_scripts/CompareGDTs.java b/Ghidra/Features/Base/ghidra_scripts/CompareGDTs.java
index 34ce0a23ff..55a2fb4e56 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CompareGDTs.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CompareGDTs.java
@@ -26,6 +26,7 @@ import java.util.Iterator;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.data.*;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.util.UniversalID;
public class CompareGDTs extends GhidraScript {
@@ -54,13 +55,28 @@ public class CompareGDTs extends GhidraScript {
return;
}
}
+
+ firstArchive = openDataTypeArchive(firstFile, false);
+ if (firstArchive.getWarning() != ArchiveWarning.NONE) {
+ popup(
+ "An architecture language error occured while opening archive (see log for details)\n" +
+ firstFile.getPath());
+ return;
+ }
+
+ secondArchive = openDataTypeArchive(secondFile, false);
+ if (secondArchive.getWarning() != ArchiveWarning.NONE) {
+ popup(
+ "An architecture language error occured while opening archive (see log for details)\n" +
+ secondFile.getPath());
+ return;
+ }
+
matchByName = askYesNo("Match Data Types By Path Name?",
"Do you want to match data types by their path names (rather than by Universal ID)?");
checkPointers = askYesNo("Check Pointers?", "Do you want to check Pointers?");
checkArrays = askYesNo("Check Arrays?", "Do you want to check Arrays?");
- firstArchive = FileDataTypeManager.openFileArchive(firstFile, false);
- secondArchive = FileDataTypeManager.openFileArchive(secondFile, false);
printWriter = new PrintWriter(outputFile);
try {
compareDataTypes();
diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
index d84e1341c5..894068140e 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
@@ -31,6 +31,7 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
@@ -55,14 +56,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
}
- private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
+ private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
+ String[] filenames, String includePaths[], String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
DataTypeManager openTypes[] = null;
- parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args);
+ parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
}
- private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
+ private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
+ String[] filenames, String[] includePaths, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
@@ -71,9 +74,9 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
- String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
+ CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
- Msg.info(this, messages);
+ Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save();
dtMgr.close();
@@ -276,14 +279,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"wscapi.h",
"wsdapi.h",
"wspiapi.h",
-
"rpcproxy.h",
};
+ String includePaths[] = {
+ headerFilePath+"/VC/VS12/src",
+ headerFilePath+"/VC/VS12/include",
+ headerFilePath+"/VC/SDK/v7.1A/Include",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/VC/VS12/src",
- "-I"+headerFilePath+"/VC/VS12/include",
- "-I"+headerFilePath+"/VC/SDK/v7.1A/Include",
"-D_M_IX86=300",
"-D_MSC_VER=1200",
"-D_INTEGRAL_MAX_BITS=32",
@@ -294,8 +299,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D_USE_ATTRIBUTES_FOR_SAL",
"-D_CRTBLD",
"-D_OPENMP_NOFORCE_MANIFEST",
- "-DSTRSAFE_LIB",
- "-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM",
"-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS",
@@ -312,7 +315,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D__inner_checkReturn=",
};
- parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, includePaths, args);
}
@@ -494,14 +497,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"wscapi.h",
"wsdapi.h",
"wspiapi.h",
-
"rpcproxy.h",
};
+ String includePaths[] = {
+ headerFilePath+"/VC/VS12/src",
+ headerFilePath+"/VC/VS12/include",
+ headerFilePath+"/VC/SDK/v7.1A/Include",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/VC/VS12/src",
- "-I"+headerFilePath+"/VC/VS12/include",
- "-I"+headerFilePath+"/VC/SDK/v7.1A/Include",
"-D_MSC_VER=1200",
"-D_INTEGRAL_MAX_BITS=64",
"-DWINVER=0x0900",
@@ -513,8 +518,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D_USE_ATTRIBUTES_FOR_SAL",
"-D_CRTBLD",
"-D_OPENMP_NOFORCE_MANIFEST",
- "-DSTRSAFE_LIB",
- "-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM",
"-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS",
@@ -532,7 +535,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D__inner_checkReturn=",
};
- parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, includePaths, args);
}
@@ -761,12 +764,15 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"arpa/tftp.h",
};
+ String includePaths[] = {
+ headerFilePath+"/linux/include",
+ headerFilePath+"/linux/include/sys",
+ headerFilePath+"/linux/gcc/include",
+ headerFilePath+"/linux/x86_64-redhat-linux5E/include",
+ headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/linux/include",
- "-I"+headerFilePath+"/linux/include/sys",
- "-I"+headerFilePath+"/linux/gcc/include",
- "-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include",
- "-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
"-D_X86_",
"-D__STDC__",
"-D_GNU_SOURCE",
@@ -782,7 +788,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-Daligned_u64=uint64_t",
};
- parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, includePaths, args);
}
@@ -1011,12 +1017,15 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"arpa/tftp.h",
};
+ String includePaths[] = {
+ headerFilePath+"/linux/include",
+ headerFilePath+"/linux/include/sys",
+ headerFilePath+"/linux/gcc/include",
+ headerFilePath+"/linux/x86_64-redhat-linux5E/include",
+ headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/linux/include",
- "-I"+headerFilePath+"/linux/include/sys",
- "-I"+headerFilePath+"/linux/gcc/include",
- "-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include",
- "-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
"-D_X86_",
"-D__STDC__",
"-D_GNU_SOURCE",
@@ -1032,6 +1041,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-Daligned_u64=uint64_t",
};
- parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, includePaths, args);
}
}
diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
index 3b9397a386..bab606bb29 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
@@ -31,6 +31,7 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
@@ -52,14 +53,16 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
parseGDT_WinVS22();
}
- private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
+ private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
+ String[] filenames, String includePaths[], String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
DataTypeManager openTypes[] = null;
- parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args);
+ parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
}
- private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
+ private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
+ String[] filenames, String[] includePaths, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
@@ -68,9 +71,9 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
- String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
+ CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
- Msg.info(this, messages);
+ Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save();
dtMgr.close();
@@ -79,7 +82,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
/**
* Turn string into a file, delete old archive if it exists
*
- * @param dataTypeFile
+ * @param dataTypeFile name of archive file
*
* @return file
*/
@@ -112,12 +115,15 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"dsound.h",
};
+ String includeFiles[] = {
+ headerFilePath+"/VC/VS22/10.0.190141.0",
+ headerFilePath+"/VC/VS22/10.0.19041.0/um",
+ headerFilePath+"/VC/VS22/10.0.19041.0/shared",
+ headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
+ headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/VC/VS22/10.0.190141.0",
- "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um",
- "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared",
- "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
- "-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include",
"-D_AMD64_",
"-D_M_AMD64",
"-D_M_X64",
@@ -126,7 +132,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-v0",
};
- parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, includeFiles, args);
}
public void parseGDT_WinVS22() throws Exception {
@@ -167,7 +173,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"complex.h",
"math.h",
"mbctype.h",
- "mbstring.hs",
+ "mbstring.h",
"memory.h",
"minmax.h",
"new.h",
@@ -216,7 +222,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"dssec.h",
"iads.h",
"identitycommon.h",
- "identityproviders.h",
+ "identityprovider.h",
"identitystore.h",
"keycredmgr.h",
"lmaccess.h",
@@ -237,7 +243,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"slpublic.h",
"subauth.h",
"tokenbinding.h",
- "tpmsvcmgr.h",
+ "tpmvscmgr.h",
"wincred.h",
"wincrypt.h",
"winnetwk.h",
@@ -267,7 +273,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"mswsock.h",
"ws2tcpip.h",
"wsipv6ok.h",
- "wslwlink.h",
+ "wsnwlink.h",
"wsrm.h",
"mswsockdef.h",
@@ -375,7 +381,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"thumbcache.h",
"thumbnailstreamcache.h",
"tlogstg.h",
- "usereng.h",
+ "userenv.h",
"# Windows Controls",
"commctrl.h",
@@ -452,12 +458,15 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"lmwksta.h"
};
+ String includeFiles[] = {
+ headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
+ headerFilePath+"/VC/VS22/10.0.19041.0/shared",
+ headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
+ headerFilePath+"/VC/VS22/10.0.19041.0/um",
+ headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
- "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared",
- "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
- "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um",
- "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
"-D_MSC_VER=1924",
"-D_INTEGRAL_MAX_BITS=64",
"-DWINVER=0x0a00",
@@ -473,7 +482,6 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-DSTRSAFE_LIB",
"-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM",
- "-D_WCHAR_T_DEFINED",
"-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS",
"-D_CRT_NONSTDC_NO_DEPRECATE",
@@ -494,6 +502,6 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-DSECURITY_WIN32",
};
- parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, includeFiles, args);
}
}
diff --git a/Ghidra/Features/Base/ghidra_scripts/FixupCompositeDataTypesScript.java b/Ghidra/Features/Base/ghidra_scripts/FixupCompositeDataTypesScript.java
index f060066835..a69867fcc7 100644
--- a/Ghidra/Features/Base/ghidra_scripts/FixupCompositeDataTypesScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/FixupCompositeDataTypesScript.java
@@ -29,6 +29,7 @@ import ghidra.app.script.GhidraScript;
import ghidra.app.services.DataTypeManagerService;
import ghidra.framework.model.DomainFile;
import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.database.ProjectDataTypeManager;
import ghidra.program.database.data.*;
import ghidra.program.model.data.BuiltInDataTypeManager;
import ghidra.program.model.data.DataTypeManager;
diff --git a/Ghidra/Features/Base/ghidra_scripts/SynchronizeGDTCategoryPaths.java b/Ghidra/Features/Base/ghidra_scripts/SynchronizeGDTCategoryPaths.java
index 368a87344f..4df0b93831 100644
--- a/Ghidra/Features/Base/ghidra_scripts/SynchronizeGDTCategoryPaths.java
+++ b/Ghidra/Features/Base/ghidra_scripts/SynchronizeGDTCategoryPaths.java
@@ -24,43 +24,59 @@ import java.io.File;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.data.Category;
import ghidra.program.model.data.FileDataTypeManager;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
public class SynchronizeGDTCategoryPaths extends GhidraScript {
- private File firstFile;
- private File secondFile;
- private FileDataTypeManager firstArchive;
- private FileDataTypeManager secondArchive;
-
@Override
protected void run() throws Exception {
- firstFile = askFile("Select First GDT File", "Select 1st");
- secondFile = askFile("Select Second GDT File", "Select 2nd");
- try {
- firstArchive = FileDataTypeManager.openFileArchive(firstFile, false);
- secondArchive = FileDataTypeManager.openFileArchive(secondFile, true);
-
- int transactionID = secondArchive.startTransaction("Synchronize Category Path Names");
- Category firstCategory = firstArchive.getRootCategory();
- Category secondCategory = secondArchive.getRootCategory();
-
- synchronizeCategory(firstCategory, secondCategory);
- secondArchive.endTransaction(transactionID, true);
- }
- finally {
- if (firstArchive != null) {
- firstArchive.close();
+ File firstFile = askFile("Select First GDT File", "Select 1st");
+ try (FileDataTypeManager firstArchive =
+ FileDataTypeManager.openFileArchive(firstFile, false)) {
+ if (hasWarning(firstArchive, firstFile)) {
+ return;
}
- secondArchive.save();
- if (secondArchive != null) {
- secondArchive.close();
+
+ File secondFile = askFile("Select Second GDT File", "Select 2nd");
+ try (FileDataTypeManager secondArchive =
+ FileDataTypeManager.openFileArchive(secondFile, true)) {
+ if (hasWarning(secondArchive, secondFile)) {
+ return;
+ }
+
+ int transactionID =
+ secondArchive.startTransaction("Synchronize Category Path Names");
+ try {
+ Category firstCategory = firstArchive.getRootCategory();
+ Category secondCategory = secondArchive.getRootCategory();
+ synchronizeCategory(firstCategory, secondCategory);
+ }
+ finally {
+ secondArchive.endTransaction(transactionID, true);
+ }
}
}
}
+ private boolean hasWarning(FileDataTypeManager archive, File file) {
+ ArchiveWarning warning = archive.getWarning();
+ if (warning == ArchiveWarning.NONE) {
+ return false;
+ }
+ if (warning == ArchiveWarning.UPGRADED_LANGUAGE_VERSION) {
+ return !askYesNo("Archive Upgrade Confirmation",
+ "A language upgrade has been performed on archive " + file.getName() +
+ "\nIs it OK to proceed?");
+ }
+ popup(
+ "An architecture language error occured while opening archive (see log for details)\n" +
+ file.getPath());
+ return true;
+ }
+
private void synchronizeCategory(Category firstCategory, Category secondCategory) {
Category[] firstCategories = firstCategory.getCategories();
for (Category categoryA : firstCategories) {
diff --git a/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml b/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml
index 4c44167d9b..32dd85d8a1 100644
--- a/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml
+++ b/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml
@@ -123,18 +123,27 @@
-
-
-
-
-
-
-
+ sortgroup="e"
+ text="Ghidra Functionality"
+ target = "help/topics/Intro/GhidraFunctionality.htm">
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -220,16 +229,6 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
index 6ac79334c8..4b328fccd8 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
@@ -353,6 +353,14 @@
editing, since they support sharing and version control and therefore allow more than one
user to modify them at a time. Only one user at a time can have a file archive opened for
editing.
+
+
+
You can assign a specific "Architecture"
+ to a Data Type Archive while it is open for editing. This is recommended when an archive is targeting
+ a specific processor and compiler specification (see Setting
+ Data Type Archive Architecture).
+
+
@@ -406,6 +414,51 @@
Archive.
+
+ Setting Data Type Archive Architecture
+
+
+ By default, data type archives are not assigned an architecture and adopt a default
+ Data Organization which determines primitive data type sizing (e.g., int, long, pointer, etc.)
+ as well as alignment and packing behavior. While data types copied between archives or a program
+ with disimilar Data Organizations will generally resolve correctly, unexpected results
+ may sometimes arise (e.g., bit-field packing within structures). In addition, this situation
+ frequently causes some confusion when viewing and editing data types where the Data
+ Organization differs from the intended target architecture.
+
+ With either a file or project data type archive open for editing, a specific architecture
+ may be assigned to the archive. This is done by selecting the open archive node from the
+ data type tree, right-click on it and select the Set Architecture... action.
+ This will popup a processor/compiler-specification selection dialog from which a selection
+ may be made and the OK button clicked. A final confirmation dialog will be displayed
+ before completing the change from which the Set Architecture or Cancel button
+ must be clicked to confirm or cancel the change. If confirmed, any architecture transition
+ will resolve all data types to the new data organization. Details related to custom variable
+ storage for Function Definitions (not yet implemented) will be preserved if possible but
+ may be discarded.
+
+ At present, the user will be forced to save any unsaved archive changes prior to completing
+ an architecture setting change to allow for a fallback if neccessary.
+
+
+
+ Clearing Data Type Archive Architecture
+
+
+
+ With either a file or project data type archive open for editing, a currently assigned architecture
+ may be cleared for a selected archive. This is done by selecting the open archive node from the
+ data type tree, right-click on it and select the Clear Architecture action.
+ A final confirmation dialog will be displayed
+ before completing the change from which the Clear Architecture or Cancel button
+ must be clicked to confirm or cancel the change. If confirmed, the archive will revert a default
+ Data Organization and any custom variable storage for Function Definitions
+ (not yet implemented) will be discarded.
+
+
At present, the user will be forced to save any unsaved changes prior to clearing the
+ architecture setting to allow for a fallback if neccessary.
+
+
Closing a Data Type Archive
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionSignatureCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionSignatureCmd.java
index 2eee3110d0..1a87d98c0d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionSignatureCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionSignatureCmd.java
@@ -140,6 +140,7 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
func.updateFunction(conventionName, returnParam, params,
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, false, source);
func.setVarArgs(signature.hasVarArgs());
+ func.setNoReturn(signature.hasNoReturn());
}
catch (DuplicateNameException e) {
// should not happen unless caused by a concurrent operation
@@ -212,29 +213,21 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
}
private String getCallingConvention(Function function, CompilerSpec compilerSpec) {
- PrototypeModel preferredModel = null;
- if (signature.getGenericCallingConvention() != GenericCallingConvention.unknown) {
- preferredModel = compilerSpec.matchConvention(signature.getGenericCallingConvention());
+
+ // Ignore signature's calling convention if unknown/not-defined
+ String callingConvention = signature.getCallingConventionName();
+ if (compilerSpec.getCallingConvention(callingConvention) == null) {
+ callingConvention = null;
}
- PrototypeModel convention = function.getCallingConvention();
- if (convention == null || !preserveCallingConvention) {
- convention = preferredModel;
-// NOTE: This has been disable since it can cause imported signature information to be
-// ignored and overwritten by subsequent analysis
-// if (convention == null && compilerSpec.getCallingConventions().length > 1) {
-// // use default source for signature if convention is really unknown so that we
-// // know dynamic storage assignment is unreliable
-// source = SourceType.DEFAULT;
-// }
+ // Continue using function's current calling convention if valid and either
+ // reservation was requested or signature's convention is unknown/not-defined.
+ PrototypeModel currentConvention = function.getCallingConvention();
+ if (currentConvention != null && (callingConvention == null || preserveCallingConvention)) {
+ callingConvention = function.getCallingConventionName();
}
- // Calling convention is permitted to change
- String conventionName = function.getCallingConventionName();
- if (!preserveCallingConvention && convention != null) {
- conventionName = convention.getName();
- }
- return conventionName;
+ return callingConvention;
}
private static void updateStackPurgeSize(Function function, Program program) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
index 3877a2d317..4fdb96a65c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
@@ -1473,6 +1473,7 @@ public class DataTypeMergeManager implements MergeResolver {
ParameterDefinition[] sourceVars = sourceFunctionDefDt.getArguments();
ParameterDefinition[] destVars = new ParameterDefinition[sourceVars.length];
boolean sourceHasVarArgs = sourceFunctionDefDt.hasVarArgs();
+ boolean sourceHasNoReturn = sourceFunctionDefDt.hasNoReturn();
DataType resolvedRDT = DataType.DEFAULT;
if (sourceReturnType != null) {
@@ -1492,6 +1493,7 @@ public class DataTypeMergeManager implements MergeResolver {
}
destDt.setArguments(destVars);
destDt.setVarArgs(sourceHasVarArgs);
+ destDt.setNoReturn(sourceHasNoReturn);
destDt.setLastChangeTime(oldLastChangeTime);
destDt.setLastChangeTimeInSourceArchive(oldLastChangeTimeInSourceArchive);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypePanel.java
index f18266061d..1e8e8d1b46 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypePanel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypePanel.java
@@ -29,6 +29,7 @@ import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
+import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
import ghidra.util.StringUtilities;
import ghidra.util.UniversalID;
@@ -348,7 +349,14 @@ class DataTypePanel extends JPanel {
ParameterDefinition[] vars = fd.getArguments();
DataType returnType = fd.getReturnType();
+ if (fd.hasNoReturn()) {
+ insertString(FunctionSignature.NORETURN_DISPLAY_STRING + " ", contentAttrSet);
+ }
insertString(returnType.getDisplayName(), contentAttrSet);
+ String callingConventionName = fd.getCallingConventionName();
+ if (!Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConventionName)) {
+ insertString(callingConventionName + " ", contentAttrSet);
+ }
insertString(" " + fd.getDisplayName(), nameAttrSet);
insertString(" (", contentAttrSet);
boolean hasVarArgs = fd.hasVarArgs();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java
index fbdde9a48f..e165d9c492 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java
@@ -15,7 +15,13 @@
*/
package ghidra.app.plugin.core.compositeeditor;
+import java.io.IOException;
+
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.ProgramArchitecture;
+import ghidra.util.exception.AssertException;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
@@ -23,10 +29,10 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
* The data type manager for original composite data type being edited.
* This is where the edited datatype will be written back to.
*/
- private DataTypeManager originalDTM;
- private Composite originalComposite;
- private Composite viewComposite;
- private int transactionID;
+ private final DataTypeManager originalDTM;
+ private final Composite originalComposite;
+ private final Composite viewComposite;
+ private final int transactionID;
/**
* Creates a data type manager that the structure editor will use
@@ -39,16 +45,42 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
this.originalComposite = originalComposite;
transactionID = startTransaction("");
originalDTM = originalComposite.getDataTypeManager();
- universalID = originalDTM.getUniversalID(); // mimic original DTM
+
+ ProgramArchitecture arch = originalDTM.getProgramArchitecture();
+ if (arch != null) {
+ try {
+ setProgramArchitecture(arch, null, true, TaskMonitor.DUMMY);
+ }
+ catch (CancelledException e) {
+ throw new AssertException(e); // unexpected
+ }
+ catch (IOException e) {
+ errHandler.dbError(e);
+ }
+ }
+
viewComposite = (Composite) super.resolve(originalComposite, null);
}
-
+
+ @Override
+ protected final boolean isArchitectureChangeAllowed() {
+ return false;
+ }
+
@Override
public void close() {
endTransaction(transactionID, true);
super.close();
}
+ /**
+ * Get the {@link DataTypeManager} associated with the original composite datatype being edited.
+ * @return original datatype manager
+ */
+ public DataTypeManager getOriginalDataTypeManager() {
+ return originalDTM;
+ }
+
@Override
public ArchiveType getType() {
return originalDTM.getType();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java
index b0cb27cd17..83acb51fb7 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java
@@ -1344,4 +1344,8 @@ abstract class CompositeViewerModel extends AbstractTableModel
return originalCompositeId;
}
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ // don't care
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserPlugin.java
index c02e2a4559..bf55b2c8a1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserPlugin.java
@@ -15,19 +15,13 @@
*/
package ghidra.app.plugin.core.cparser;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.PrintStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
import javax.swing.SwingUtilities;
-import org.apache.commons.io.DirectoryWalker.CancelException;
-
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.MenuData;
@@ -38,21 +32,17 @@ import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.services.DataTypeManagerService;
-import ghidra.app.util.cparser.C.CParser;
-import ghidra.app.util.cparser.CPP.PreProcessor;
+import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.framework.Application;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.database.data.ProgramDataTypeManager;
-import ghidra.program.model.data.BuiltInDataTypeManager;
-import ghidra.program.model.data.DataTypeManager;
-import ghidra.program.model.data.FileDataTypeManager;
+import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
-import ghidra.util.HTMLUtilities;
-import ghidra.util.HelpLocation;
-import ghidra.util.Msg;
+import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@@ -66,22 +56,20 @@ import ghidra.util.task.TaskMonitor;
)
//@formatter:on
public class CParserPlugin extends ProgramPlugin {
- final static String PARSE_ACTION_NAME = "Import C DataTypes";
+ public final static String PARSE_ACTION_NAME = "Import C DataTypes";
final static String USER_PROFILES_DIR =
Application.getUserSettingsDirectory().getAbsolutePath() + File.separatorChar +
"parserprofiles";
+
private ParseDialog parseDialog;
private File userProfileDir;
- private String parserMessages;
- private String cppMessages;
+ private CParseResults results;
final static String DESCRIPTION =
"Parse C and C Header files, extracting data definitions and function signatures.";
- private static final String PARSER_DEBUG_OUTFILE = "CParserPlugin.out";
-
public CParserPlugin(PluginTool plugintool) {
super(plugintool);
createActions();
@@ -155,26 +143,37 @@ public class CParserPlugin extends ProgramPlugin {
if (parseDialog == null) {
parseDialog = new ParseDialog(this);
}
- else {
- parseDialog.toFront();
- }
+ parseDialog.setupForDisplay();
tool.showDialog(parseDialog);
}
/*
* Parse into a saved data type data base file
*/
- protected void parse(String[] filenames, String options, String dataFilename) {
- CParserTask parseTask = new CParserTask(this, filenames, options, dataFilename);
+ protected void parse(String[] filenames, String includePaths[], String options,
+ String languageIDString, String compilerSpecID, String dataFilename) {
+
+ CParserTask parseTask = new CParserTask(this, dataFilename)
+ .setFileNames(filenames)
+ .setIncludePaths(includePaths)
+ .setOptions(options)
+ .setLanguageID(languageIDString)
+ .setCompilerID(compilerSpecID);
+
this.getTool().execute(parseTask, 500);
}
+
/*
* Parse C-source into a data type manager
*/
- protected void parse(String[] filenames, String options, DataTypeManager dtMgr,
+ protected void parse(String[] filenames, String includePaths[], String options,
+ String languageIDString, String compilerSpecID, DataTypeManager dtMgr,
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException {
+
+ results = null;
+
String[] args = parseOptions(options);
DataTypeManager openDTmanagers[] = null;
@@ -184,100 +183,22 @@ public class CParserPlugin extends ProgramPlugin {
return; // parse canceled
}
- cppMessages = "";
- PreProcessor cpp = new PreProcessor();
-
- cpp.setArgs(args);
-
- PrintStream os = System.out;
- String homeDir = System.getProperty("user.home");
- String fName = homeDir + File.separator + "CParserPlugin.out";
try {
- os = new PrintStream(new FileOutputStream(fName));
- }
- catch (FileNotFoundException e2) {
- Msg.error(this, "Unexpected Exception: " + e2.getMessage(), e2);
- }
-
- PrintStream old = System.out;
- System.setOut(os);
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- cpp.setOutputStream(bos);
- cpp.setMonitor(monitor);
-
- try {
- for (String filename : filenames) {
- if (monitor.isCancelled()) {
- break;
- }
- // any file beginning with a "#" is assumed to be a comment
- if (filename.trim().startsWith("#")) {
- continue;
- }
- File file = new File(filename);
-
- if (file.isDirectory()) {
- // process each header file in the directory
- String[] children = file.list();
- if (children == null) {
- continue;
- }
- for (String element : children) {
- File child = new File(file.getAbsolutePath() + "/" + element);
- if (child.getName().endsWith(".h")) {
- parseFile(child.getAbsolutePath(), monitor, cpp);
- }
- }
- }
- else {
- parseFile(filename, monitor, cpp);
- }
- }
- }
- catch (RuntimeException re) {
- os.close();
- throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
- }
-
- // process all the defines and add any that are integer values into
- // the Equates table
- cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
-
- System.out.println(bos.toString());
-
- System.setOut(old);
- os.close();
-
- if (!monitor.isCancelled()) {
- monitor.setMessage("Parsing C");
-
- CParser cParser = new CParser(dtMgr, true, openDTmanagers);
- cParser.setParseFileName(PARSER_DEBUG_OUTFILE);
- ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
- try {
- parserMessages = "";
- cParser.setParseFileName(fName);
- cParser.setMonitor(monitor);
- cParser.parse(bis);
- }
- finally {
- parserMessages = cParser.getParseMessages();
- }
-
+ results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
+ args, dtMgr, languageIDString, compilerSpecID, monitor);
+
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager);
-
+
SwingUtilities.invokeLater(() -> {
// CParserTask will show any errors
- if (!cParser.didParseSucceed()) {
+ if (!results.successful()) {
return;
}
if (isProgramDtMgr) {
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
"C-Parse of Header Files Complete",
"Successfully parsed header file(s) to Program.",
- getFormattedParseMessage(
- "Check the Manage Data Types window for added data types."),
+ getFormattedParseMessage("Check the Manage Data Types window for added data types."),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
else {
@@ -286,20 +207,22 @@ public class CParserPlugin extends ProgramPlugin {
archiveName = ((FileDataTypeManager) dtMgr).getFilename();
}
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
- "C-Parse of Header Files Complete. ",
+ "C-Parse of Header Files Complete",
"Successfully parsed header file(s) to Archive File: " + archiveName,
- getFormattedParseMessage(null), MultiLineMessageDialog.INFORMATION_MESSAGE);
+ getFormattedParseMessage(null),
+ MultiLineMessageDialog.INFORMATION_MESSAGE);
}
});
}
-
+ catch (IOException e) {
+ // ignore
+ }
}
/**
* Get open data type managers.
* User can Use Open managers, Select not to use, or Cancel
*
- * @param openDTmanagers open mgrs, null if don't use
* @return array of open data type managers
*
* @throws CancelledException if user cancels
@@ -335,7 +258,7 @@ public class CParserPlugin extends ProgramPlugin {
"" + "The new archive will become dependent on these archives
" +
"for any datatypes already defined in them (only unique
" +
"data types will be added to the new archive).",
- "Use Open Archives?", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE);
+ "Use Open Archives", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE);
if (result == OptionDialog.CANCEL_OPTION) {
throw new CancelledException("User Cancelled");
}
@@ -346,62 +269,40 @@ public class CParserPlugin extends ProgramPlugin {
return openDTmanagers;
}
+
+ public CParseResults getParseResults() {
+ return results;
+ }
+
+ public String getParseMessage() {
+ return (results != null ? results.cParseMessages() : "");
+ }
- public String getFormattedParseMessage(String errMsg) {
+ protected String getFormattedParseMessage(String errMsg) {
String message = "";
if (errMsg != null) {
message += errMsg + "\n\n";
}
- String msg = getParseMessage();
+ String msg = (results == null ? null : results.cParseMessages());
if (msg != null && msg.length() != 0) {
message += "CParser Messages:\n" + msg + "\n\n";
}
- msg = getPreProcessorMessage();
+ msg = (results == null ? null : results.cppParseMessages());
if (msg != null && msg.length() != 0) {
- message += "PreProcessor Messages:\n" + getPreProcessorMessage();
+ message += "PreProcessor Messages:\n" + msg;
}
return message;
}
- /**
- * Get any parse messages produced by parsing good, or informational
- *
- * @return messages from parser
- */
- public String getParseMessage() {
- return parserMessages;
- }
-
- public String getPreProcessorMessage() {
- return cppMessages;
- }
-
- private void parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
- throws ghidra.app.util.cparser.CPP.ParseException {
- monitor.setMessage("PreProcessing " + filename);
- try {
- Msg.info(this, "parse " + filename);
- cpp.parse(filename);
- }
- catch (Throwable e) {
- Msg.error(this, "Parsing file :" + filename);
- Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
-
- throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
- }
- finally {
- cppMessages += cpp.getParseMessages();
- }
- }
-
/*
* Parse into the current programs data type manager
*/
- protected void parse(String[] filenames, String options) {
+ protected void parse(String[] filenames, String[] includePaths, String options,
+ String languageIDString, String compilerIDString) {
if (currentProgram == null) {
Msg.showInfo(getClass(), parseDialog.getComponent(), "No Open Program",
"A program must be open to \"Parse to Program\"");
@@ -413,8 +314,14 @@ public class CParserPlugin extends ProgramPlugin {
if (result == OptionDialog.CANCEL_OPTION) {
return;
}
+
CParserTask parseTask =
- new CParserTask(this, filenames, options, currentProgram.getDataTypeManager());
+ new CParserTask(this, currentProgram.getDataTypeManager())
+ .setFileNames(filenames)
+ .setIncludePaths(includePaths)
+ .setOptions(options)
+ .setLanguageID(languageIDString)
+ .setCompilerID(compilerIDString);
tool.execute(parseTask);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
index c5a2f720e6..68ae94864a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
@@ -20,44 +20,97 @@ import java.io.File;
import javax.swing.SwingUtilities;
import docking.widgets.dialogs.MultiLineMessageDialog;
-import ghidra.program.model.data.DataTypeManager;
-import ghidra.program.model.data.FileDataTypeManager;
+import ghidra.program.model.data.*;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateFileException;
import ghidra.util.task.Task;
import ghidra.util.task.TaskMonitor;
/**
- * This is called by the dialog box.
+ * Background task to parse files for cparser plugin
*
*
*/
class CParserTask extends Task {
- private String[] filenames;
- private String options;
+
private CParserPlugin plugin;
private String dataFileName;
+
+ private String[] filenames;
+ private String[] includePaths;
+
+ private String options;
+
+ private String languageString;
+ private String compilerString;
+
private DataTypeManager dtMgr;
- CParserTask(CParserPlugin plugin, String[] filenames, String options, String dataFileName) {
+
+ /**
+ * Create task to parse to a dataFile
+ *
+ * @param plugin CParserPlugin that will do the work
+ * @param dataFileName name of the file to parse to
+ */
+ CParserTask(CParserPlugin plugin, String dataFileName) {
super("Parsing C Files", true, false, false);
this.plugin = plugin;
- this.filenames = filenames;
- this.options = options;
this.dataFileName = dataFileName;
}
- public CParserTask(CParserPlugin plugin, String[] filenames, String options,
- DataTypeManager dataTypeManager) {
+ /**
+ * Create task to parse to a dataTypeManager
+ *
+ * @param plugin
+ * @param dataTypeManager
+ */
+ public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) {
super("Parsing C Files", true, false, false);
this.plugin = plugin;
- this.filenames = filenames;
- this.options = options;
this.dtMgr = dataTypeManager;
}
+ /**
+ * Create task to parse to a ProgramDataTypeManager
+ *
+ * @param plugin
+ * @param dataTypeManager
+ */
+ public CParserTask(CParserPlugin plugin, ProgramBasedDataTypeManager dataTypeManager) {
+ super("Parsing C Files", true, false, false);
+
+ this.plugin = plugin;
+ this.dtMgr = dataTypeManager;
+ }
+
+ public CParserTask setLanguageID(String languageID) {
+ this.languageString = languageID;
+ return this;
+ }
+
+ public CParserTask setCompilerID(String compilerID) {
+ this.compilerString = compilerID;
+ return this;
+ }
+
+ public CParserTask setIncludePaths(String includePaths[]) {
+ this.includePaths = includePaths.clone();
+ return this;
+ }
+
+ public CParserTask setFileNames(String names[]) {
+ this.filenames = names.clone();
+ return this;
+ }
+
+ public CParserTask setOptions(String options) {
+ this.options = options;
+ return this;
+ }
+
private String getFirstMessageLine(final String errMsg) {
int indexOf = errMsg.indexOf('\n');
String msg = errMsg;
@@ -77,8 +130,9 @@ class CParserTask extends Task {
fileDtMgr = dtMgr;
}
- plugin.parse(filenames, options, dtMgr, monitor);
+ plugin.parse(filenames, includePaths, options, languageString, compilerString, dtMgr, monitor);
if (dataFileName != null) {
+ // TODO: does not consider existing datatypes
if (dtMgr.getDataTypeCount(true) != 0) {
try {
((FileDataTypeManager) dtMgr).save();
@@ -102,6 +156,10 @@ class CParserTask extends Task {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
+ // no results, was canceled
+ if (plugin.getParseResults() == null) {
+ return;
+ }
MultiLineMessageDialog.showModalMessageDialog(
plugin.getDialog().getComponent(), "Parse Errors",
"File was not created due to parse errors: " +
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
index 70d64ef2fc..3b13c69e75 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
@@ -15,31 +15,44 @@
*/
package ghidra.app.plugin.core.cparser;
-import java.awt.BorderLayout;
-import java.awt.Dimension;
+import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.*;
import java.util.*;
+import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.TableModel;
+import org.apache.commons.lang3.ObjectUtils;
+
import docking.*;
import docking.action.*;
import docking.widgets.OptionDialog;
+import docking.widgets.button.BrowseButton;
import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.dialogs.InputDialog;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.filechooser.GhidraFileChooserMode;
+import docking.widgets.label.GLabel;
import docking.widgets.pathmanager.PathnameTablePanel;
+import docking.widgets.table.GTableCellRenderer;
+import docking.widgets.table.GTableCellRenderingData;
import generic.jar.ResourceFile;
+import generic.theme.GThemeDefaults.Colors.Tables;
+import ghidra.app.plugin.core.processors.SetLanguageDialog;
+import ghidra.app.util.Option;
+import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.exporter.Exporter;
import ghidra.framework.Application;
import ghidra.framework.options.SaveState;
import ghidra.framework.preferences.Preferences;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.program.model.data.FileDataTypeManager;
+import ghidra.program.model.lang.CompilerSpecID;
+import ghidra.program.model.lang.LanguageID;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.filechooser.ExtensionFileFilter;
@@ -75,6 +88,13 @@ class ParseDialog extends ReusableDialogComponentProvider {
private PathnameTablePanel pathPanel;
private JTextArea parseOptionsField;
+
+ protected JComponent languagePanel;
+ protected JTextField languageTextField;
+ protected JButton languageButton;
+ protected String languageIDString = null;
+ protected String compilerIDString = null;
+
private GhidraComboBox comboBox;
private DefaultComboBoxModel comboModel;
private DockingAction saveAction;
@@ -86,44 +106,75 @@ class ParseDialog extends ReusableDialogComponentProvider {
private TableModelListener tableListener;
private ItemListener comboItemListener;
private TableModel tableModel;
+
+ private PathnameTablePanel includePathPanel;
+ private TableModel parsePathTableModel;
+ private TableModelListener parsePathTableListener;
+
private ArrayList itemList;
private ComboBoxItemComparator comparator;
private ResourceFile parentUserFile;
private boolean saveAsInProgress;
+ private boolean initialBuild = true;
+
+ private boolean userDefined = false;
+ private String currentProfileName = null;
ParseDialog(CParserPlugin plugin) {
super("Parse C Source", false, true, true, false);
this.plugin = plugin;
- itemList = new ArrayList<>();
- comparator = new ComboBoxItemComparator();
- addWorkPanel(buildMainPanel());
- addDismissButton();
- createActions();
- setActionsEnabled();
}
+ public void setupForDisplay() {
+ if (initialBuild) {
+ itemList = new ArrayList<>();
+ comparator = new ComboBoxItemComparator();
+ addWorkPanel(buildMainPanel());
+ addDismissButton();
+ createActions();
+ setActionsEnabled();
+
+ // setup based on save state
+ if (currentProfileName != null) {
+ for (int i = 0; i < itemList.size(); i++) {
+ ComboBoxItem item = itemList.get(i);
+ if (userDefined == item.isUserDefined && currentProfileName.equals(item.file.getName())) {
+ comboBox.setSelectedIndex(i);
+ break;
+ }
+ }
+ }
+ } else {
+ toFront();
+ }
+ }
+
void writeState(SaveState saveState) {
- ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
- saveState.putString(CURRENT_PROFILE, item.file.getName());
- saveState.putBoolean(USER_DEFINED, item.isUserDefined);
+ // Get the current state if the dialog has been displayed
+ if (!initialBuild) {
+ ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+
+ currentProfileName = item.file.getName();
+ userDefined = item.isUserDefined;
+
+ }
+ saveState.putString(CURRENT_PROFILE, currentProfileName);
+ saveState.putBoolean(USER_DEFINED, userDefined);
}
void readState(SaveState saveState) {
- String name = saveState.getString(CURRENT_PROFILE, null);
- if (name != null) {
- boolean userDefined = saveState.getBoolean(USER_DEFINED, true);
- for (int i = 0; i < itemList.size(); i++) {
- ComboBoxItem item = itemList.get(i);
- if (userDefined == item.isUserDefined && name.equals(item.file.getName())) {
- comboBox.setSelectedIndex(i);
- break;
- }
- }
+ currentProfileName = saveState.getString(CURRENT_PROFILE, null);
+ if (currentProfileName != null) {
+ userDefined = saveState.getBoolean(USER_DEFINED, true);
}
}
void closeProfile() {
+ // dialog not built yet
+ if (initialBuild) {
+ return;
+ }
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
if (item.isChanged) {
processItemChanged(item);
@@ -136,6 +187,8 @@ class ParseDialog extends ReusableDialogComponentProvider {
}
protected JPanel buildMainPanel() {
+ initialBuild = true;
+
mainPanel = new JPanel(new BorderLayout(10, 5));
comboModel = new DefaultComboBoxModel<>();
@@ -164,14 +217,64 @@ class ParseDialog extends ReusableDialogComponentProvider {
pathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY,
GhidraFileChooserMode.FILES_AND_DIRECTORIES, true,
new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
+
+ // Set default render to display red if file would not we found
+ // Using include paths
+ pathPanel.getTable().setDefaultRenderer(String.class, new GTableCellRenderer() {
+ @Override
+ public Component getTableCellRendererComponent(GTableCellRenderingData data) {
+ JLabel label = (JLabel) super.getTableCellRendererComponent(data);
+ Object value = data.getValue();
+
+ String pathName = (String) value;
+ pathName = (pathName == null ? "" : pathName.trim());
+
+ if (pathName.length() == 0 || pathName.startsWith("#")) {
+ return label;
+ }
+
+ boolean fileExists = true;
+ File file = new File(pathName);
+ fileExists = file.exists();
+
+ // file not found directly, see if one of the include paths will find the file
+ if (!fileExists) {
+ fileExists = doesFileExist(pathName, fileExists);
+ }
+
+ label.setText(pathName.toString());
+ if (!fileExists) {
+ label.setForeground(data.isSelected() ? Tables.FG_ERROR_SELECTED
+ : Tables.FG_ERROR_UNSELECTED);
+ }
+
+ return label;
+ }
+ });
+
tableListener = e -> {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
- item.isChanged = true;
+ item.isChanged = !initialBuild;
setActionsEnabled();
};
tableModel = pathPanel.getTable().getModel();
tableModel.addTableModelListener(tableListener);
+
+ includePathPanel = new PathnameTablePanel(null, true, false);
+ includePathPanel.setBorder(BorderFactory.createTitledBorder("Include paths"));
+ includePathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY,
+ GhidraFileChooserMode.FILES_AND_DIRECTORIES, true,
+ new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
+
+ parsePathTableListener = e -> {
+ ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+ item.isChanged = !initialBuild;
+ setActionsEnabled();
+ pathPanel.getTable().repaint();
+ };
+ parsePathTableModel = includePathPanel.getTable().getModel();
+ parsePathTableModel.addTableModelListener(parsePathTableListener);
JPanel optionsPanel = new JPanel(new BorderLayout());
optionsPanel.setBorder(BorderFactory.createTitledBorder("Parse Options"));
@@ -182,7 +285,13 @@ class ParseDialog extends ReusableDialogComponentProvider {
JScrollPane pane = new JScrollPane(parseOptionsField);
pane.getViewport().setPreferredSize(new Dimension(300, 200));
optionsPanel.add(pane, BorderLayout.CENTER);
-
+
+ JPanel archPanel = new JPanel(new BorderLayout());
+ archPanel.setBorder(BorderFactory.createTitledBorder("Program Architecture:"));
+ archPanel.add(new GLabel(" ", SwingConstants.RIGHT));
+ languagePanel = buildLanguagePanel();
+ archPanel.add(languagePanel);
+
// create Parse Button
parseButton = new JButton("Parse to Program");
@@ -195,23 +304,103 @@ class ParseDialog extends ReusableDialogComponentProvider {
parseToFileButton.setToolTipText("Parse files and output to archive file");
addButton(parseToFileButton);
- pathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
- JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pathPanel, optionsPanel);
- splitPane.setResizeWeight(0.50);
+
mainPanel.add(comboPanel, BorderLayout.NORTH);
- mainPanel.add(splitPane, BorderLayout.CENTER);
+
+ includePathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
+ JSplitPane optionsPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, includePathPanel, optionsPanel);
+ optionsPane.setResizeWeight(0.50);
+
+ pathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
+ JSplitPane outerPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pathPanel, optionsPane);
+ outerPane.setResizeWeight(0.50);
+
+ mainPanel.add(outerPane, BorderLayout.CENTER);
+
+ mainPanel.add(archPanel, BorderLayout.SOUTH);
setHelpLocation(new HelpLocation(plugin.getName(), "Parse_C_Source"));
loadProfile();
+ initialBuild = false;
return mainPanel;
}
+ private boolean doesFileExist(String pathName, boolean fileExists) {
+ String[] includePaths = includePathPanel.getPaths();
+ for (String path : includePaths) {
+ File file = CParserUtils.getFile(path, pathName);
+ if (file == null) {
+ continue;
+ }
+ fileExists = file.exists();
+ if (fileExists) {
+ break;
+ }
+ }
+ return fileExists;
+ }
+
+ private JComponent buildLanguagePanel() {
+ languageTextField = new JTextField();
+ languageTextField.setEditable(false);
+ languageTextField.setFocusable(false);
+
+ languageButton = new BrowseButton();
+ languageButton.addActionListener(e -> {
+ SetLanguageDialog dialog = new SetLanguageDialog(plugin.getTool(), languageIDString, compilerIDString,
+ "Select Program Architecture for File DataType Archive");
+ LanguageID languageId = dialog.getLanguageDescriptionID();
+ CompilerSpecID compilerSpecId = dialog.getCompilerSpecDescriptionID();
+ if ((languageId == null) || (compilerSpecId == null)) {
+ return;
+ }
+
+ String newLanguageIDString = languageId.getIdAsString();
+ String newCompilerIDString = compilerSpecId.getIdAsString();
+
+ if (!Objects.equals(newLanguageIDString, languageIDString) ||
+ !Objects.equals(newCompilerIDString, compilerIDString)) {
+ itemChanged();
+ }
+
+ languageIDString = newLanguageIDString;
+ compilerIDString = newCompilerIDString;
+
+ updateArchitectureDescription();
+ });
+
+ updateArchitectureDescription();
+
+ languageButton.setName("Set Processor Architecture");
+ Font font = languageButton.getFont();
+ languageButton.setFont(font.deriveFont(Font.BOLD));
+
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(languageTextField, BorderLayout.CENTER);
+ panel.add(languageButton, BorderLayout.EAST);
+ return panel;
+ }
+
+ private void updateArchitectureDescription() {
+ String newProgramArchitectureSummary = "64/32 (primarily for backward compatibility)";
+
+ if (languageIDString != null) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(languageIDString);
+ buf.append(" / ");
+ buf.append(compilerIDString != null ? compilerIDString : "none");
+ newProgramArchitectureSummary = buf.toString();
+ }
+
+ languageTextField.setText(newProgramArchitectureSummary);
+ }
+
private void selectionChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.DESELECTED) {
ComboBoxItem item = (ComboBoxItem) e.getItem();
- if (item.isChanged && !saveAsInProgress) {
+ if (item.isChanged && !saveAsInProgress && !initialBuild) {
if (item.isUserDefined) {
if (OptionDialog.showOptionDialog(rootPanel, "Save Changes to Profile?",
"Profile " + item.file.getName() +
@@ -256,53 +445,6 @@ class ParseDialog extends ReusableDialogComponentProvider {
}
}
- private void loadProfile() {
- if (docListener != null) {
- parseOptionsField.getDocument().removeDocumentListener(docListener);
- }
- tableModel.removeTableModelListener(tableListener);
- ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
-
- StringBuffer sb = new StringBuffer();
- ArrayList pathList = new ArrayList<>();
- try {
- BufferedReader br =
- new BufferedReader(new InputStreamReader(item.file.getInputStream()));
- String line = null;
- while ((line = br.readLine()) != null) {
- line = line.trim();
- if (line.startsWith("-") || (line.length() == 0 && sb.length() > 0)) {
- // this is a compiler directive
- sb.append(line + "\n");
- }
- else if (line.length() > 0) {
- File f = new File(line);
- pathList.add(f.getPath());
- }
- }
- String[] paths = new String[pathList.size()];
- paths = pathList.toArray(paths);
- pathPanel.setPaths(paths);
- parseOptionsField.setText(sb.toString());
-
- br.close();
- }
- catch (FileNotFoundException e) {
- Msg.showInfo(getClass(), getComponent(), "File Not Found",
- "Could not find file\n" + item.file.getAbsolutePath());
- }
- catch (IOException e) {
- Msg.showError(this, getComponent(), "Error Loading Profile",
- "Exception occurred while reading file\n" + item.file.getAbsolutePath() + ": " + e);
- }
- finally {
- // add a document listener to the options field
- addDocumentListener();
- tableModel.addTableModelListener(tableListener);
- setActionsEnabled();
- }
- }
-
private void addDocumentListener() {
if (docListener == null) {
docListener = new DocumentListener() {
@@ -327,6 +469,9 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void itemChanged() {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+ if (item == null) {
+ return;
+ }
item.isChanged = true;
setActionsEnabled();
}
@@ -466,6 +611,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
}
file.delete();
}
+ saveAsInProgress = true;
ComboBoxItem newItem = new ComboBoxItem(file, true);
if (itemList.contains(newItem)) {
itemList.remove(newItem);
@@ -476,7 +622,6 @@ class ParseDialog extends ReusableDialogComponentProvider {
index = -index - 1;
}
itemList.add(index, newItem);
- saveAsInProgress = true;
writeProfile(newItem.file);
newItem.isChanged = false;
item.isChanged = false;
@@ -491,6 +636,97 @@ class ParseDialog extends ReusableDialogComponentProvider {
}
}
+ private void loadProfile() {
+ if (docListener != null) {
+ parseOptionsField.getDocument().removeDocumentListener(docListener);
+ }
+ tableModel.removeTableModelListener(tableListener);
+ parsePathTableModel.removeTableModelListener(parsePathTableListener);
+ ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+ item.isChanged = false;
+
+ StringBuffer sb = new StringBuffer();
+ ArrayList pathList = new ArrayList<>();
+ ArrayList includeList = new ArrayList<>();
+ String langString = null;
+ String compileString = null;
+ try {
+ BufferedReader br =
+ new BufferedReader(new InputStreamReader(item.file.getInputStream()));
+ String line = null;
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
+ line = line.trim();
+
+ pathList.add(line);
+ }
+
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
+ line = line.trim();
+
+ sb.append(line + "\n");
+ }
+
+ // get paths
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
+ line = line.trim();
+
+ includeList.add(line);
+ }
+
+ // get language
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.length() > 0) {
+ langString = (line.length() == 0 ? null : line);
+ break;
+ }
+ }
+
+ // get compiler spec
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.length() > 0) {
+ compileString = (line.length() == 0 ? null : line);
+ break;
+ }
+ }
+
+
+ String[] paths = new String[pathList.size()];
+ paths = pathList.toArray(paths);
+ pathPanel.setPaths(paths);
+
+ String[] incpaths = new String[includeList.size()];
+ incpaths = includeList.toArray(incpaths);
+ includePathPanel.setPaths(incpaths);
+
+ parseOptionsField.setText(sb.toString());
+
+ languageIDString = langString;
+
+ compilerIDString = compileString;
+
+ updateArchitectureDescription();
+
+ br.close();
+ }
+ catch (FileNotFoundException e) {
+ Msg.showInfo(getClass(), getComponent(), "File Not Found",
+ "Could not find file\n" + item.file.getAbsolutePath());
+ }
+ catch (IOException e) {
+ Msg.showError(this, getComponent(), "Error Loading Profile",
+ "Exception occurred while reading file\n" + item.file.getAbsolutePath() + ": " + e);
+ }
+ finally {
+ // add a document listener to the options field
+ addDocumentListener();
+ tableModel.addTableModelListener(tableListener);
+ parsePathTableModel.addTableModelListener(parsePathTableListener);
+ setActionsEnabled();
+ }
+ }
+
private void writeProfile(ResourceFile outputFile) {
// write the pathnames
try {
@@ -498,7 +734,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
new BufferedWriter(new OutputStreamWriter(outputFile.getOutputStream()));
String[] paths = pathPanel.getPaths();
for (String path : paths) {
- writer.write(path);
+ writer.write(path.trim());
writer.newLine();
}
writer.newLine();
@@ -510,6 +746,30 @@ class ParseDialog extends ReusableDialogComponentProvider {
writer.write(tok);
writer.newLine();
}
+ writer.newLine();
+
+ // Write paths
+ String [] includePaths = includePathPanel.getPaths();
+ for (String path : includePaths) {
+ writer.write(path.trim());
+ writer.newLine();
+ }
+ writer.newLine();
+
+ // Write Language ID Spec
+ if (languageIDString != null) {
+ writer.write(languageIDString);
+ }
+ writer.newLine();
+ writer.newLine();
+
+ // Write Compiler ID Spec
+ if (compilerIDString != null) {
+ writer.write(compilerIDString);
+ }
+ writer.newLine();
+ writer.newLine();
+
writer.close();
}
catch (IOException e) {
@@ -537,6 +797,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void doParse(boolean parseToFile) {
clearStatusText();
String options = getParseOptions();
+ String[] includePaths = includePathPanel.getPaths();
String[] paths = pathPanel.getPaths();
if (paths.length == 0) {
@@ -547,15 +808,21 @@ class ParseDialog extends ReusableDialogComponentProvider {
paths = expandPaths(paths);
pathPanel.setPaths(paths);
+
+ if (languageIDString == null || compilerIDString == null ) {
+ Msg.showWarn(getClass(), rootPanel, "Program Architecture not Specified",
+ "A Program Architecture must be specified in order to parse to a file.");
+ return;
+ }
if (parseToFile) {
File file = getSaveFile();
if (file != null) {
- plugin.parse(paths, options, file.getAbsolutePath());
+ plugin.parse(paths, includePaths, options, languageIDString, compilerIDString, file.getAbsolutePath());
}
}
else {
- plugin.parse(paths, options);
+ plugin.parse(paths, includePaths, options, languageIDString, compilerIDString);
}
}
@@ -605,7 +872,12 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void addToComboModel(ResourceFile parent, boolean isUserDefined) {
ResourceFile[] children = parent.listFiles();
- for (ResourceFile resourceFile : children) {
+ List sorted = Arrays.asList(children);
+ // sort each set of files, system will go first
+ // User local files second
+ // new files at the end
+ Collections.sort(sorted);
+ for (ResourceFile resourceFile : sorted) {
if (resourceFile.getName().startsWith(".")) {
continue;
}
@@ -687,7 +959,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
return parseOptionsField.getText();
}
- private class ComboBoxItem {
+ class ComboBoxItem {
private ResourceFile file;
private boolean isUserDefined;
private boolean isChanged;
@@ -745,4 +1017,55 @@ class ParseDialog extends ReusableDialogComponentProvider {
return 1;
}
}
+
+ //==================================================================================================
+ // Methods for Testing
+ //==================================================================================================
+
+
+ GhidraComboBox getParseComboBox() {
+ return comboBox;
+ }
+
+ PathnameTablePanel getSourceFiles() {
+ return this.pathPanel;
+ }
+
+ PathnameTablePanel getIncludePaths() {
+ return this.includePathPanel;
+ }
+
+ JTextArea getParseOptionsTextField() {
+ return this.parseOptionsField;
+ }
+
+ JButton getLanguageButton() {
+ return this.languageButton;
+ }
+
+ JTextField getLanguageText() {
+ return this.languageTextField;
+ }
+
+ JButton getParseButton() {
+ return this.parseButton;
+ }
+
+ JButton getParseToFileButton() {
+ return this.parseToFileButton;
+ }
+
+ ArrayList getProfiles() {
+ return this.itemList;
+ }
+
+ ComboBoxItem getCurrentItem() {
+ ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+
+ return item;
+ }
+
+ ResourceFile getUserProfileParent() {
+ return parentUserFile;
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java
index 6a5ea1464f..7c20d83b60 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java
@@ -180,6 +180,10 @@ public class DataTypesProvider extends ComponentProviderAdapter {
addLocalAction(new LockArchiveAction(plugin)); // Archive
addLocalAction(new UnlockArchiveAction(plugin)); // Archive
+ // Arch group
+ addLocalAction(new SetArchiveArchitectureAction(plugin)); // Archive
+ addLocalAction(new ClearArchiveArchitectureAction(plugin)); // Archive
+
// Repository group : version control actions
addVersionControlActions(); // Archive
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ClearArchiveArchitectureAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ClearArchiveArchitectureAction.java
new file mode 100644
index 0000000000..f88e1aea76
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ClearArchiveArchitectureAction.java
@@ -0,0 +1,187 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.plugin.core.datamgr.actions;
+
+import java.io.IOException;
+
+import javax.swing.tree.TreePath;
+
+import docking.ActionContext;
+import docking.action.DockingAction;
+import docking.action.MenuData;
+import docking.widgets.OptionDialog;
+import docking.widgets.tree.GTree;
+import docking.widgets.tree.GTreeNode;
+import generic.theme.GThemeDefaults.Colors.Messages;
+import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
+import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
+import ghidra.app.plugin.core.datamgr.archive.*;
+import ghidra.app.plugin.core.datamgr.tree.*;
+import ghidra.framework.model.DomainFile;
+import ghidra.framework.store.LockException;
+import ghidra.program.model.data.StandAloneDataTypeManager;
+import ghidra.util.Msg;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.*;
+
+public class ClearArchiveArchitectureAction extends DockingAction {
+
+ private final DataTypeManagerPlugin plugin;
+
+ public ClearArchiveArchitectureAction(DataTypeManagerPlugin plugin) {
+ super("Clear Archive Architecture", plugin.getName());
+ this.plugin = plugin;
+
+ setPopupMenuData(new MenuData(new String[] { "Clear Architecture" }, null, "SetArch"));
+
+ setDescription(
+ "Clear program-architecture associated with a data type archive (existing custom storage details will be discarded)");
+
+ setEnabled(true);
+ }
+
+ @Override
+ public boolean isEnabledForContext(ActionContext context) {
+ if (!(context instanceof DataTypesActionContext)) {
+ return false;
+ }
+
+ Object contextObject = context.getContextObject();
+ GTree gtree = (GTree) contextObject;
+ TreePath[] selectionPaths = gtree.getSelectionPaths();
+
+ if (selectionPaths.length != 1) {
+ return false;
+ }
+ GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent();
+ if (!(node instanceof FileArchiveNode) && !(node instanceof ProjectArchiveNode)) {
+ return false;
+ }
+ ArchiveNode archiveNode = (ArchiveNode) node;
+ StandAloneDataTypeManager dtm =
+ (StandAloneDataTypeManager) archiveNode.getArchive().getDataTypeManager();
+
+ return dtm.getProgramArchitectureSummary() != null && dtm.isUpdatable();
+ }
+
+ @Override
+ public void actionPerformed(ActionContext context) {
+ GTree gtree = (GTree) context.getContextObject();
+ TreePath[] selectionPaths = gtree.getSelectionPaths();
+ if (selectionPaths.length != 1) {
+ return;
+ }
+ GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent();
+ if (!(node instanceof FileArchiveNode) && !(node instanceof ProjectArchiveNode)) {
+ return;
+ }
+
+ if (node instanceof ProjectArchiveNode) {
+ ProjectArchiveNode paNode = (ProjectArchiveNode) node;
+ ProjectArchive pa = (ProjectArchive) paNode.getArchive();
+ if (!pa.hasExclusiveAccess()) {
+ Msg.showError(this, null, "Clear Program Architecture Failed",
+ "Clearing program-architecture on Project Archive requires exclusive checkout.");
+ return;
+ }
+ }
+
+ ArchiveNode archiveNode = (ArchiveNode) node;
+ StandAloneDataTypeManager dtm =
+ (StandAloneDataTypeManager) archiveNode.getArchive().getDataTypeManager();
+
+ if (dtm.isChanged()) {
+ if (OptionDialog.OPTION_ONE != OptionDialog.showOptionDialogWithCancelAsDefaultButton(
+ null, "Save Archive Changes",
+ "Archive has unsaved changes which must be saved before continuing." +
+ "\nThis is required to allow for a reversion to the previous saved state.",
+ "Save")) {
+ return;
+ }
+ try {
+ archiveNode.getArchive().save();
+ }
+ catch (IOException e) {
+ Msg.showError(this, null, "Save Archive Failed",
+ "Failed to save changes for Archive: " + dtm.getName() + "\n" + e.getMessage());
+ return;
+ }
+ }
+
+ // TODO: Update message indicating that custom storage specification will not be
+ // retained/permitted (once supported)
+ String msg = "Clear program-architecture for Archive?
" + dtm.getPath() +
+ "
Archive will revert to using default data organization.";
+ int response = OptionDialog.showOptionDialogWithCancelAsDefaultButton(null,
+ "Confirm Clearing Archive Architecture", msg, "Clear Architecture",
+ OptionDialog.WARNING_MESSAGE);
+ if (response != OptionDialog.OPTION_ONE) {
+ return;
+ }
+
+ new TaskLauncher(new ClearProgramArchitectureTask(archiveNode.getArchive(), dtm));
+ }
+
+ private class ClearProgramArchitectureTask extends Task {
+
+ private final Archive archive;
+ private final StandAloneDataTypeManager dtm;
+
+ public ClearProgramArchitectureTask(Archive archive, StandAloneDataTypeManager dtm) {
+ super("Clearing Program-Architecture for Archive", true, false, true, false);
+ this.archive = archive;
+ this.dtm = dtm;
+ }
+
+ @Override
+ public void run(TaskMonitor monitor) throws CancelledException {
+ boolean success = false;
+ try {
+ dtm.clearProgramArchitecture(monitor);
+ success = true;
+ }
+ catch (CancelledException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ Msg.showError(this, null, "Archive Update Failed",
+ "Failed to clear program-architecture for Archive: " + dtm.getName() + "\n" +
+ e.getMessage());
+ }
+ finally {
+ if (!success) {
+ if (archive instanceof FileArchive) {
+ try {
+ ((FileArchive) archive).releaseWriteLock();
+ ((FileArchive) archive).acquireWriteLock();
+ }
+ catch (LockException | IOException e) {
+ archive.close();
+ }
+ }
+ else { // if (archive instanceof ProjectArchive) {
+ archive.close();
+ DomainFile df = ((ProjectArchive) archive).getDomainFile();
+ plugin.openArchive(df);
+ }
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java
index bf0fba6450..708eb47577 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java
@@ -37,8 +37,7 @@ public class DeleteArchiveAction extends DockingAction {
public DeleteArchiveAction(DataTypeManagerPlugin plugin) {
super("Delete Archive", plugin.getName());
-// ACTIONS - auto generated
- setPopupMenuData(new MenuData(new String[] { "Delete Archive" }, null, "Edit"));
+ setPopupMenuData(new MenuData(new String[] { "Delete Archive" }, null, "File"));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_DELETE, 0));
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SetArchiveArchitectureAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SetArchiveArchitectureAction.java
new file mode 100644
index 0000000000..0520cf2ad0
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SetArchiveArchitectureAction.java
@@ -0,0 +1,259 @@
+/* ###
+ * 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.app.plugin.core.datamgr.actions;
+
+import java.io.IOException;
+
+import javax.swing.tree.TreePath;
+
+import docking.ActionContext;
+import docking.action.DockingAction;
+import docking.action.MenuData;
+import docking.widgets.OptionDialog;
+import docking.widgets.tree.GTree;
+import docking.widgets.tree.GTreeNode;
+import generic.theme.GThemeDefaults.Colors.Messages;
+import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
+import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
+import ghidra.app.plugin.core.datamgr.archive.*;
+import ghidra.app.plugin.core.datamgr.tree.*;
+import ghidra.app.plugin.core.processors.SetLanguageDialog;
+import ghidra.framework.model.DomainFile;
+import ghidra.framework.store.LockException;
+import ghidra.program.model.data.StandAloneDataTypeManager;
+import ghidra.program.model.data.StandAloneDataTypeManager.LanguageUpdateOption;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
+import ghidra.program.util.DefaultLanguageService;
+import ghidra.util.Msg;
+import ghidra.util.Swing;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.*;
+
+public class SetArchiveArchitectureAction extends DockingAction {
+
+ private final DataTypeManagerPlugin plugin;
+
+ public SetArchiveArchitectureAction(DataTypeManagerPlugin plugin) {
+ super("Set Archive Architecture", plugin.getName());
+ this.plugin = plugin;
+
+ setPopupMenuData(new MenuData(new String[] { "Set Architecture..." }, null, "SetArch"));
+
+ setDescription("Set program-architecture associated with a data type archive");
+
+ setEnabled(true);
+ }
+
+ private TreePath getSelectionPath(ActionContext context) {
+ Object contextObject = context.getContextObject();
+ GTree gtree = (GTree) contextObject;
+ TreePath[] selectionPaths = gtree.getSelectionPaths();
+ if (selectionPaths.length != 1) {
+ return null;
+ }
+ return selectionPaths[0];
+ }
+
+ @Override
+ public boolean isEnabledForContext(ActionContext context) {
+ if (!(context instanceof DataTypesActionContext)) {
+ return false;
+ }
+ TreePath selectionPath = getSelectionPath(context);
+ if (selectionPath == null) {
+ return false;
+ }
+ GTreeNode node = (GTreeNode) selectionPath.getLastPathComponent();
+ if (!(node instanceof FileArchiveNode) && !(node instanceof ProjectArchiveNode)) {
+ return false;
+ }
+ ArchiveNode archiveNode = (ArchiveNode) node;
+ StandAloneDataTypeManager dtm =
+ (StandAloneDataTypeManager) archiveNode.getArchive().getDataTypeManager();
+ return dtm.isUpdatable();
+ }
+
+ @Override
+ public void actionPerformed(ActionContext context) {
+ TreePath selectionPath = getSelectionPath(context);
+ if (selectionPath == null) {
+ return;
+ }
+ GTreeNode node = (GTreeNode) selectionPath.getLastPathComponent();
+ if (!(node instanceof FileArchiveNode) && !(node instanceof ProjectArchiveNode)) {
+ return;
+ }
+
+ if (node instanceof ProjectArchiveNode) {
+ ProjectArchiveNode paNode = (ProjectArchiveNode) node;
+ ProjectArchive pa = (ProjectArchive) paNode.getArchive();
+ if (!pa.hasExclusiveAccess()) {
+ Msg.showError(this, null, "Set Program Architecture Failed",
+ "Setting program-architecture on Project Archive requires exclusive checkout.");
+ return;
+ }
+ }
+
+ ArchiveNode archiveNode = (ArchiveNode) node;
+ StandAloneDataTypeManager dtm =
+ (StandAloneDataTypeManager) archiveNode.getArchive().getDataTypeManager();
+
+ if (dtm.isChanged()) {
+ if (OptionDialog.OPTION_ONE != OptionDialog.showOptionDialogWithCancelAsDefaultButton(
+ null, "Save Archive Changes",
+ "Archive has unsaved changes which must be saved before continuing." +
+ "\nThis is required to allow for a reversion to the previous saved state.",
+ "Save")) {
+ return;
+ }
+ try {
+ archiveNode.getArchive().save();
+ }
+ catch (IOException e) {
+ Msg.showError(this, null, "Save Archive Failed",
+ "Failed to save changes for Archive: " + dtm.getName() + "\n" + e.getMessage());
+ return;
+ }
+ }
+
+ SetLanguageDialog dialog = new SetLanguageDialog(plugin.getTool(),
+ dtm.getProgramArchitecture(),
+ "Select Program Architecture for Archive: " + dtm.getName());
+ LanguageID languageId = dialog.getLanguageDescriptionID();
+ CompilerSpecID compilerSpecId = dialog.getCompilerSpecDescriptionID();
+ if ((languageId == null) || (compilerSpecId == null)) {
+ return;
+ }
+ try {
+ Language language = DefaultLanguageService.getLanguageService().getLanguage(languageId);
+
+ StringBuilder buf = new StringBuilder();
+ buf.append(languageId.getIdAsString());
+ buf.append(" / ");
+ buf.append(compilerSpecId.getIdAsString());
+ String newProgramArchitectureSummary = buf.toString();
+
+ String programArchitectureSummary = dtm.getProgramArchitectureSummary();
+ String msg =
+ "Set program-architecture for Archive?
" + dtm.getPath() + "";
+ if (programArchitectureSummary != null) {
+ msg +=
+ "\nChange Language/Compiler\n from: " +
+ programArchitectureSummary + "\n to: ";
+ }
+ else {
+ msg += "\n\nLanguage/Compiler: ";
+ }
+ msg += "";
+ msg += newProgramArchitectureSummary;
+ msg += "";
+ int response = OptionDialog.showOptionDialogWithCancelAsDefaultButton(null,
+ "Confirm Archive Architecture Change", msg, "Set Architecture",
+ OptionDialog.WARNING_MESSAGE);
+ if (response != OptionDialog.OPTION_ONE) {
+ return;
+ }
+
+ new TaskLauncher(new SetProgramArchitectureTask(archiveNode.getArchive(), dtm, language,
+ compilerSpecId));
+ }
+ catch (LanguageNotFoundException e) {
+ Msg.showError(this, null, "Archive Update Failed",
+ "Failed to set program-architecture for Archive: " + dtm.getName() + "\n" +
+ e.getMessage());
+ }
+ }
+
+ private class SetProgramArchitectureTask extends Task {
+
+ private final Archive archive;
+ private final StandAloneDataTypeManager dtm;
+ private final Language language;
+ private final CompilerSpecID compilerSpecId;
+
+ public SetProgramArchitectureTask(Archive archive, StandAloneDataTypeManager dtm,
+ Language language, CompilerSpecID compilerSpecId) {
+ super("Updating Program-Architecture for Archive", true, false, true, false);
+ this.archive = archive;
+ this.dtm = dtm;
+ this.language = language;
+ this.compilerSpecId = compilerSpecId;
+ }
+
+ @Override
+ public void run(TaskMonitor monitor) throws CancelledException {
+
+ boolean success = false;
+ try {
+ try {
+ dtm.setProgramArchitecture(language, compilerSpecId,
+ LanguageUpdateOption.TRANSLATE, monitor);
+ success = true;
+ }
+ catch (IncompatibleLanguageException e) {
+ int resp = OptionDialog.showOptionDialog(null, "Archive Architecture Change",
+ "Unable to translate storage for specified architecture change.
" + dtm.getPath() +
+ "
Would you like to Clear custom storage information or Cancel change?",
+ "Clear");
+ if (resp == OptionDialog.CANCEL_OPTION) {
+ success = true; // keep archive open
+ return;
+ }
+ LanguageUpdateOption updateOption = LanguageUpdateOption.CLEAR;
+ if (resp == OptionDialog.OPTION_TWO) {
+ updateOption = LanguageUpdateOption.UNCHANGED;
+ }
+ dtm.setProgramArchitecture(language, compilerSpecId, updateOption, monitor);
+ success = true;
+ }
+ }
+ catch (CancelledException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ Msg.showError(this, null, "Archive Update Failed",
+ "Failed to set program-architecture for Archive: " + dtm.getName() + "\n" +
+ e.getMessage());
+ }
+ finally {
+ if (!success) {
+ Swing.runNow(() -> {
+ /* flush event queue before closing archive */ });
+ if (archive instanceof FileArchive) {
+ try {
+ ((FileArchive) archive).releaseWriteLock();
+ ((FileArchive) archive).acquireWriteLock();
+ }
+ catch (LockException | IOException e) {
+ archive.close();
+ }
+ }
+ else { // if (archive instanceof ProjectArchive) {
+ archive.close();
+ DomainFile df = ((ProjectArchive) archive).getDomainFile();
+ plugin.openArchive(df);
+ }
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java
index b45d8b0031..590fad3050 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java
@@ -96,17 +96,21 @@ public class ArchiveUtils {
return true;
}
catch (ReadOnlyException e) {
- Msg.showError(log, null, "Unable to Lock File for Writing", e.getMessage());
+ Msg.showError(log, null, "Unable to Lock Archive for Writing", e.getMessage());
}
catch (LockException exc) {
- Msg.showError(log, null, "Unable to Lock File for Writing",
+ Msg.showError(log, null, "Unable to Lock Archive for Writing",
"Unable to obtain lock for archive: " + archive.getName() + "\n" +
exc.getMessage());
}
catch (IOException ioe) {
- Msg.showError(log, null, "Unable to Lock File for Writing",
- "Problem attempting to lock archive: " + archive.getName() + "\n" +
- ioe.getMessage());
+ Throwable cause = ioe.getCause();
+ if (cause == null) {
+ cause = ioe;
+ }
+ Msg.showError(log, null, "Unable to Lock Archive for Writing",
+ "Problem attempting to open archive for update: " + archive.getName() + "\n" +
+ cause.getMessage());
}
return false;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeIndexer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeIndexer.java
index 3fce3c2984..b89dce170c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeIndexer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeIndexer.java
@@ -219,5 +219,10 @@ public class DataTypeIndexer {
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
markStale();
}
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ markStale();
+ }
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java
index 4bb5abd0ff..c2d36b183c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java
@@ -437,12 +437,13 @@ public class DataTypeManagerHandler {
return openArchive(new ResourceFile(file), acquireWriteLock, isUserAction);
}
- public Archive openArchive(ResourceFile file, boolean acquireWriteLock, boolean isUserAction)
+ public FileArchive openArchive(ResourceFile file, boolean acquireWriteLock,
+ boolean isUserAction)
throws IOException, DuplicateIdException {
file = file.getCanonicalFile();
- Archive archive = getArchiveForFile(file);
+ FileArchive archive = getArchiveForFile(file);
if (archive == null) {
archive = new FileArchive(this, file, acquireWriteLock);
Archive existingArchive =
@@ -451,11 +452,10 @@ public class DataTypeManagerHandler {
archive.close();
throw new DuplicateIdException(archive.getName(), existingArchive.getName());
}
-
addArchivePath(file);
addArchive(archive);
}
- if (isUserAction && (archive instanceof FileArchive)) {
+ if (isUserAction) {
userOpenedFileArchiveNames.add(getSaveableArchive(file.getAbsolutePath()));
}
return archive;
@@ -524,7 +524,7 @@ public class DataTypeManagerHandler {
return null;
}
- private Archive getArchiveForFile(ResourceFile file) {
+ private FileArchive getArchiveForFile(ResourceFile file) {
for (Archive archive : openArchives) {
if (archive instanceof FileArchive) {
FileArchive fileArchive = (FileArchive) archive;
@@ -1230,6 +1230,13 @@ public class DataTypeManagerHandler {
listener.sourceArchiveChanged(dataTypeManager, dataTypeSource);
}
}
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.programArchitectureChanged(dataTypeManager);
+ }
+ }
}
/**
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DomainFileArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DomainFileArchive.java
index 28fd51880d..2660379a8a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DomainFileArchive.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DomainFileArchive.java
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
- * REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,4 +23,6 @@ public interface DomainFileArchive extends Archive {
public abstract DomainFile getDomainFile();
public abstract DomainObject getDomainObject();
+
+ public abstract boolean hasExclusiveAccess();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java
index f30fef276a..3e4e2e851a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java
@@ -146,7 +146,7 @@ public class FileArchive implements Archive {
}
@Override
- public DataTypeManager getDataTypeManager() {
+ public FileDataTypeManager getDataTypeManager() {
return fileDataTypeManager;
}
@@ -295,6 +295,11 @@ public class FileArchive implements Archive {
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
setChanged(true);
}
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ setChanged(true);
+ }
}
@Override
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java
index 830a3eb9f7..bbfbd94ee4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java
@@ -93,6 +93,11 @@ public class ProgramArchive implements DomainFileArchive {
// Can't directly close the program archive. Instead you must close the Program.
}
+ @Override
+ public boolean hasExclusiveAccess() {
+ return program.hasExclusiveAccess();
+ }
+
@Override
public boolean isChanged() {
return false;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java
index d7f8940c5e..4558918945 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java
@@ -87,6 +87,10 @@ public class ProjectArchive implements DomainFileArchive {
return Objects.equals(originalDomainFile.getFileID(), other.originalDomainFile.getFileID());
}
+ public boolean hasExclusiveAccess() {
+ return dataTypeArchive.hasExclusiveAccess();
+ }
+
@Override
public boolean isModifiable() {
DomainFile domainFile = getDomainObject().getDomainFile();
@@ -213,5 +217,10 @@ public class ProjectArchive implements DomainFileArchive {
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
fireStateChanged();
}
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager dtm) {
+ fireStateChanged();
+ }
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
index d05f007a9d..29c8a52a48 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
@@ -15,8 +15,7 @@
*/
package ghidra.app.plugin.core.datamgr.editor;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import docking.ComponentProvider;
import docking.actions.DockingToolActions;
@@ -28,11 +27,9 @@ import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
-import ghidra.program.model.listing.FunctionSignature;
-import ghidra.program.model.listing.Program;
+import ghidra.program.model.listing.*;
import ghidra.util.*;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.exception.DuplicateNameException;
+import ghidra.util.exception.*;
/**
* Manages program and archive data type editors.
@@ -541,27 +538,53 @@ public class DataTypeEditorManager
* Use of this editor requires the presence of the tool-based datatype manager service.
*/
private class DTMEditFunctionSignatureDialog extends AbstractEditFunctionSignatureDialog {
- private final FunctionDefinition functionDefinition;
+ private final FunctionDefinition functionDefinition; // may be null
private final FunctionSignature oldSignature;
private final Category category;
+ /**
+ * Construct function signature editor model
+ * @param pluginTool plugin tool
+ * @param title Dialog title
+ * @param category datatype category
+ * @param functionDefinition function definition to be modified (null for new definition)
+ */
DTMEditFunctionSignatureDialog(PluginTool pluginTool, String title, Category category,
FunctionDefinition functionDefinition) {
- super(pluginTool, title, false, false, false);
+ super(pluginTool, title, false, true, false);
this.functionDefinition = functionDefinition;
this.category = category;
this.oldSignature = buildSignature();
+ if (isAdhocCallingConventionPermitted()) {
+ callingConventionComboBox.setEditable(true);
+ }
+ }
+
+ /**
+ * Determine if an adhoc calling convention entry is permitted (i.e., text entry)
+ * @return true if calling convention name may be edited with text entry, else false
+ */
+ private boolean isAdhocCallingConventionPermitted() {
+ // DataTypeManager dtm = functionDefinition.getDataTypeManager();
+ // return dtm == null || dtm.getProgramArchitecture() == null;
+ // TODO: not sure we should allow unrestricted entries which could lead to using misspelled names
+ return false;
}
private FunctionSignature buildSignature() {
if (functionDefinition != null) {
if (category.getDataTypeManager() != functionDefinition.getDataTypeManager()) {
throw new IllegalArgumentException(
- "functionDefinition and category must have same Datatypemanager");
+ "FunctionDefinition and Category must have same DataTypeManager");
}
return functionDefinition;
}
- return new FunctionDefinitionDataType("newFunction");
+ return new FunctionDefinitionDataType("newFunction", category.getDataTypeManager());
+ }
+
+ @Override
+ protected boolean hasNoReturn() {
+ return functionDefinition != null ? functionDefinition.hasNoReturn() : false;
}
@Override
@@ -586,17 +609,21 @@ public class DataTypeEditorManager
@Override
protected String getCallingConventionName() {
- return getFunctionSignature().getGenericCallingConvention().toString();
+ return getFunctionSignature().getCallingConventionName();
}
@Override
protected List getCallingConventionNames() {
- GenericCallingConvention[] values = GenericCallingConvention.values();
- List choices = new ArrayList<>();
- for (GenericCallingConvention value : values) {
- choices.add(value.toString());
+ // can't rely on functionDefinition which may be null for new definition
+ DataTypeManager dtMgr = getDataTypeManager();
+ if (dtMgr instanceof CompositeViewerDataTypeManager) {
+ dtMgr = ((CompositeViewerDataTypeManager)dtMgr).getOriginalDataTypeManager();
}
- return choices;
+ ArrayList list = new ArrayList<>();
+ list.add(Function.UNKNOWN_CALLING_CONVENTION_STRING);
+ list.add(Function.DEFAULT_CALLING_CONVENTION_STRING);
+ list.addAll(dtMgr.getDefinedCallingConventionNames());
+ return list;
}
@Override
@@ -620,36 +647,53 @@ public class DataTypeEditorManager
return false;
}
- GenericCallingConvention callingConvention =
- GenericCallingConvention.getGenericCallingConvention(getCallingConvention());
- newDefinition.setGenericCallingConvention(callingConvention);
+ String callingConvention = getCallingConvention();
+ boolean hasNoReturn = hasNoReturnSelected();
+ try {
+ newDefinition.setCallingConvention(callingConvention);
+ newDefinition.setNoReturn(hasNoReturn);
- DataTypeManager manager = getDataTypeManager();
- SourceArchive sourceArchive = manager.getLocalSourceArchive();
- if (functionDefinition == null) {
- newDefinition.setSourceArchive(sourceArchive);
- newDefinition.setCategoryPath(category.getCategoryPath());
- int id = manager.startTransaction("Create Function Definition");
- manager.addDataType(newDefinition, DataTypeConflictHandler.REPLACE_HANDLER);
- manager.endTransaction(id, true);
- }
- else {
- int id = manager.startTransaction("Edit Function Definition");
- try {
- if (!functionDefinition.getName().equals(newDefinition.getName())) {
- functionDefinition.setName(newDefinition.getName());
+ DataTypeManager manager = getDataTypeManager();
+ SourceArchive sourceArchive = manager.getLocalSourceArchive();
+ if (functionDefinition == null) {
+ newDefinition.setSourceArchive(sourceArchive);
+ newDefinition.setCategoryPath(category.getCategoryPath());
+ int id = manager.startTransaction("Create Function Definition");
+ try {
+ manager.addDataType(newDefinition, DataTypeConflictHandler.REPLACE_HANDLER);
+ }
+ finally {
+ manager.endTransaction(id, true);
}
- functionDefinition.setArguments(newDefinition.getArguments());
- functionDefinition.setGenericCallingConvention(
- newDefinition.getGenericCallingConvention());
- functionDefinition.setReturnType(newDefinition.getReturnType());
- functionDefinition.setVarArgs(newDefinition.hasVarArgs());
}
- catch (InvalidNameException | DuplicateNameException e) {
- // not sure why we are squashing this? ...assuming this can't happen
- Msg.error(this, "Unexpected Exception", e);
+ else {
+ int id = manager.startTransaction("Edit Function Definition");
+ try {
+ if (!functionDefinition.getName().equals(newDefinition.getName())) {
+ functionDefinition.setName(newDefinition.getName());
+ }
+ functionDefinition.setArguments(newDefinition.getArguments());
+ if (!Objects.equals(callingConvention,
+ functionDefinition.getCallingConventionName())) {
+ functionDefinition.setCallingConvention(callingConvention);
+ }
+ functionDefinition.setReturnType(newDefinition.getReturnType());
+ functionDefinition.setVarArgs(newDefinition.hasVarArgs());
+ functionDefinition.setNoReturn(hasNoReturn);
+ }
+ catch (InvalidNameException | DuplicateNameException e) {
+ // not sure why we are squashing this? ...assuming this can't happen
+ Msg.error(this, "Unexpected Exception", e);
+ }
+ finally {
+ manager.endTransaction(id, true);
+ }
}
- manager.endTransaction(id, true);
+ }
+ catch (InvalidInputException e) {
+ setStatusText("Unknown calling convention specified: " + callingConvention,
+ MessageType.ERROR);
+ return false;
}
return true;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java
index e2bca8e965..56bb376442 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java
@@ -21,12 +21,17 @@ import javax.swing.Icon;
import docking.widgets.tree.GTree;
import docking.widgets.tree.GTreeNode;
+import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.plugin.core.datamgr.archive.Archive;
import ghidra.program.model.data.*;
+import ghidra.util.HTMLUtilities;
import ghidra.util.task.SwingUpdateManager;
public class ArchiveNode extends CategoryNode {
+ protected static final String DEFAULT_DATA_ORG_DESCRIPTION =
+ "[Using Default Data Organization]";
+
protected Archive archive;
protected ArchiveNodeCategoryChangeListener listener;
private DataTypeManager dataTypeManager; // may be null
@@ -45,6 +50,43 @@ public class ArchiveNode extends CategoryNode {
this.archive = archive;
}
+ protected String buildTooltip(String path) {
+ DataTypeManager dtm = archive.getDataTypeManager();
+ if (dtm == null) {
+ return null;
+ }
+ StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
+ buf.append(HTMLUtilities.escapeHTML(path));
+ buf.append(HTMLUtilities.BR);
+ String programArchSummary = dtm.getProgramArchitectureSummary();
+ if (programArchSummary != null) {
+ buf.append(HTMLUtilities.HTML_SPACE);
+ buf.append(HTMLUtilities.HTML_SPACE);
+ buf.append(HTMLUtilities.escapeHTML(programArchSummary));
+ addArchiveWarnings(dtm, buf);
+ }
+ else {
+ buf.append(DEFAULT_DATA_ORG_DESCRIPTION);
+ }
+ return buf.toString();
+ }
+
+ private void addArchiveWarnings(DataTypeManager dtm, StringBuilder buf) {
+ if (dtm instanceof StandAloneDataTypeManager archiveDtm) {
+ if (archiveDtm.isProgramArchitectureMissing()) {
+ buf.append(HTMLUtilities.BR);
+ buf.append(
+ "** Missing Language/Compiler Specification **");
+ }
+ else if (archiveDtm.isProgramArchitectureUpgradeRequired()) {
+ buf.append(HTMLUtilities.BR);
+ buf.append("** Language Upgrade Required **");
+ }
+ }
+ }
+
protected void archiveStateChanged() {
nodeChanged();
}
@@ -172,11 +214,11 @@ public class ArchiveNode extends CategoryNode {
return -1; // All ArchiveNodes are before any other types of nodes
}
- @Override
/**
* The hashcode must not be based on the name since it can change based upon the underlying
* archive. This must be consistent with the equals method implementation.
*/
+ @Override
public int hashCode() {
return getArchive().hashCode();
}
@@ -424,5 +466,13 @@ public class ArchiveNode extends CategoryNode {
public void sourceArchiveChanged(DataTypeManager manager, SourceArchive sourceArchive) {
nodeChangedUpdater.update();
}
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager manager) {
+ // need to force all cached datatype tooltips to be cleared
+ // due to change in data organization
+ unloadChildren();
+ nodeChangedUpdater.update();
+ }
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BuiltInArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BuiltInArchiveNode.java
index 67a9926a58..56379b9302 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BuiltInArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BuiltInArchiveNode.java
@@ -18,6 +18,7 @@ package ghidra.app.plugin.core.datamgr.tree;
import javax.swing.Icon;
import ghidra.app.plugin.core.datamgr.archive.BuiltInArchive;
+import ghidra.util.HTMLUtilities;
import resources.MultiIcon;
public class BuiltInArchiveNode extends ArchiveNode {
@@ -35,7 +36,13 @@ public class BuiltInArchiveNode extends ArchiveNode {
@Override
public String getToolTip() {
- return "Built In Data Types";
+ StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
+ buf.append("Built In Data Types");
+ buf.append(HTMLUtilities.BR);
+ buf.append(HTMLUtilities.HTML_SPACE);
+ buf.append(HTMLUtilities.HTML_SPACE);
+ buf.append(DEFAULT_DATA_ORG_DESCRIPTION);
+ return buf.toString();
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java
index f8b0cdbcc9..251f9d3c85 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java
@@ -22,11 +22,10 @@ import ghidra.app.plugin.core.datamgr.archive.DomainFileArchive;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.listing.Program;
-import ghidra.util.HTMLUtilities;
import resources.MultiIcon;
import resources.icons.TranslateIcon;
-public class DomainFileArchiveNode extends ArchiveNode {
+public abstract class DomainFileArchiveNode extends ArchiveNode {
//@formatter:off
private static Icon CHECKED_OUT_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out");
@@ -98,13 +97,7 @@ public class DomainFileArchiveNode extends ArchiveNode {
}
@Override
- public String getToolTip() {
- DomainFile file = ((DomainFileArchive) archive).getDomainFile();
- if (file != null) {
- return "" + HTMLUtilities.escapeHTML(file.getPathname());
- }
- return "[Unsaved New Domain File Archive]";
- }
+ public abstract String getToolTip();
@Override
public boolean canDelete() {
@@ -120,7 +113,7 @@ public class DomainFileArchiveNode extends ArchiveNode {
multiIcon.addIcon(baseIcon);
if (isReadOnly) {
- multiIcon.addIcon(new TranslateIcon(READ_ONLY_ICON, 6, 6));
+ multiIcon.addIcon(new TranslateIcon(READ_ONLY_ICON, 14, 3));
}
else if (isHijacked) {
multiIcon.addIcon(new TranslateIcon(HIJACKED_ICON, 8, -4));
@@ -137,6 +130,8 @@ public class DomainFileArchiveNode extends ArchiveNode {
}
}
+ // TODO: add program architecture state
+
return multiIcon;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java
index 95eabc7514..bae0a4393e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java
@@ -20,7 +20,6 @@ import javax.swing.Icon;
import generic.jar.ResourceFile;
import generic.theme.GIcon;
import ghidra.app.plugin.core.datamgr.archive.FileArchive;
-import ghidra.util.HTMLUtilities;
import resources.MultiIcon;
import resources.icons.TranslateIcon;
@@ -46,16 +45,16 @@ public class FileArchiveNode extends ArchiveNode {
if (hasWriteLock) {
multiIcon.addIcon(new TranslateIcon(CHECKED_OUT_EXCLUSIVE_ICON, 8, -4));
}
+
+ // TODO: add program architecture state
+
return multiIcon;
}
@Override
public String getToolTip() {
ResourceFile file = fileArchive.getFile();
- if (file != null) {
- return "" + HTMLUtilities.escapeHTML(file.getAbsolutePath());
- }
- return "[Unsaved New Archive]";
+ return buildTooltip(file != null ? file.getAbsolutePath() : "[Unsaved New Archive]");
}
public boolean hasWriteLock() {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProgramArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProgramArchiveNode.java
index 57198b7a0a..61f27055f1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProgramArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProgramArchiveNode.java
@@ -17,6 +17,7 @@ package ghidra.app.plugin.core.datamgr.tree;
import ghidra.app.plugin.core.datamgr.archive.ProgramArchive;
import ghidra.framework.model.DomainFile;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.util.HTMLUtilities;
public class ProgramArchiveNode extends DomainFileArchiveNode {
@@ -27,10 +28,19 @@ public class ProgramArchiveNode extends DomainFileArchiveNode {
@Override
public String getToolTip() {
+ DataTypeManager dtm = archive.getDataTypeManager();
DomainFile file = ((ProgramArchive) archive).getDomainFile();
+ StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
if (file != null) {
- return "" + HTMLUtilities.escapeHTML(file.getPathname());
+ buf.append(HTMLUtilities.escapeHTML(file.toString()));
}
- return "[Unsaved New Program Archive]";
+ else {
+ buf.append("[Unsaved New Program Archive]");
+ }
+ buf.append(HTMLUtilities.BR);
+ buf.append(HTMLUtilities.HTML_SPACE);
+ buf.append(HTMLUtilities.HTML_SPACE);
+ buf.append(HTMLUtilities.escapeHTML(dtm.getProgramArchitectureSummary()));
+ return buf.toString();
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProjectArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProjectArchiveNode.java
index 8763a3cf14..ae0671ac33 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProjectArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProjectArchiveNode.java
@@ -17,7 +17,6 @@ package ghidra.app.plugin.core.datamgr.tree;
import ghidra.app.plugin.core.datamgr.archive.ProjectArchive;
import ghidra.framework.model.DomainFile;
-import ghidra.util.HTMLUtilities;
public class ProjectArchiveNode extends DomainFileArchiveNode {
@@ -35,10 +34,7 @@ public class ProjectArchiveNode extends DomainFileArchiveNode {
@Override
public String getToolTip() {
DomainFile file = ((ProjectArchive) archive).getDomainFile();
- if (file != null) {
- return "" + HTMLUtilities.escapeHTML(file.getPathname());
- }
- return "[Unsaved New Project Archive]";
+ return buildTooltip(file != null ? file.getPathname() : "[Unsaved New Project Archive]");
}
public boolean hasWriteLock() {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeCopyMoveTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeCopyMoveTask.java
index 5f11b43d9d..83442e6dfa 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeCopyMoveTask.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeCopyMoveTask.java
@@ -361,6 +361,7 @@ public class DataTypeTreeCopyMoveTask extends Task {
DataTypeManager dtm = toCategory.getDataTypeManager();
DataTypeManager nodeDtm = dataType.getDataTypeManager();
boolean sameManager = (dtm == nodeDtm);
+
DataType newDt = !sameManager ? dataType.clone(nodeDtm) : dataType.copy(nodeDtm);
if (!sameManager && toCategory.isRoot()) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeUtils.java
index bbe5b44b3c..dd4a6b9e3f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeUtils.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeUtils.java
@@ -24,7 +24,6 @@ import javax.swing.Icon;
import generic.theme.GColor;
import generic.theme.GIcon;
import ghidra.app.services.DataTypeQueryService;
-import ghidra.program.database.data.ProjectDataTypeManager;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.util.Msg;
@@ -438,8 +437,9 @@ public class DataTypeUtils {
msg = "The archive file is not modifiable!\nYou must open the archive for editing\n" +
"before performing this operation.\n" + dtm.getName();
}
- else if (dtm instanceof ProjectDataTypeManager) {
- ProjectDataTypeManager projectDtm = (ProjectDataTypeManager) dtm;
+ else if (dtm instanceof ProjectArchiveBasedDataTypeManager) {
+ ProjectArchiveBasedDataTypeManager projectDtm =
+ (ProjectArchiveBasedDataTypeManager) dtm;
if (!projectDtm.isUpdatable() && !projectDtm.getDomainFile().canCheckout()) {
msg = "The project archive is not modifiable!\n" + dtm.getName();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AbstractEditFunctionSignatureDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AbstractEditFunctionSignatureDialog.java
index 63d18b1332..ee199456ee 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AbstractEditFunctionSignatureDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AbstractEditFunctionSignatureDialog.java
@@ -18,6 +18,7 @@ package ghidra.app.plugin.core.function;
import java.awt.Component;
import java.awt.event.ItemEvent;
import java.util.List;
+import java.util.Objects;
import javax.swing.*;
@@ -32,6 +33,7 @@ import ghidra.app.util.parser.FunctionSignatureParser;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FunctionDefinitionDataType;
+import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
import ghidra.util.exception.CancelledException;
@@ -110,7 +112,7 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
protected abstract String getPrototypeString();
/**
- * @return initial calling convention name
+ * @return initial calling convention name or null for unknown
*/
protected abstract String getCallingConventionName();
@@ -282,17 +284,33 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
}
private void setCallingConventionChoices() {
+ String callingConventionName = getCallingConventionName();
callingConventionComboBox.removeAllItems();
for (String element : getCallingConventionNames()) {
+ if (element.equals(callingConventionName)) {
+ callingConventionName = null;
+ }
callingConventionComboBox.addItem(element);
}
+ if (callingConventionName != null) {
+ callingConventionComboBox.addItem(callingConventionName);
+ }
}
/**
- * @return current calling convention selection from dialog
+ * @return current calling convention selection from dialog. Null will be returned
+ * if unknown is selected.
*/
- protected String getCallingConvention() {
- return (String) callingConventionComboBox.getSelectedItem();
+ protected final String getCallingConvention() {
+ String callingConvention = (String) callingConventionComboBox.getSelectedItem();
+ if (callingConvention != null) {
+ callingConvention = callingConvention.trim();
+ }
+ if (callingConvention.length() == 0 ||
+ Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConvention)) {
+ callingConvention = null;
+ }
+ return callingConvention;
}
/**
@@ -379,7 +397,6 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
FunctionSignatureParser parser = new FunctionSignatureParser(
getDataTypeManager(), tool.getService(DataTypeManagerService.class));
try {
- // FIXME: Parser returns FunctionDefinition which only supports GenericCallingConventions
return parser.parse(getFunctionSignature(), getSignature());
}
catch (ParseException e) {
@@ -402,22 +419,7 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
*/
protected final boolean isCallingConventionChanged() {
String current = getCallingConventionName();
- if (current == null && this.getCallingConvention() == null) {
- return false;
- }
- if (current == null && this.getCallingConvention().equals("default")) {
- return false;
- }
- if (current == null && this.getCallingConvention().equals("unknown")) {
- return false;
- }
- if (current == null) {
- return true;
- }
- if (current.equals(getCallingConvention())) {
- return false;
- }
- return true;
+ return !Objects.equals(current, getCallingConvention());
}
@Override
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialog.java
index 270b9440a7..ab6e9894d2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialog.java
@@ -15,6 +15,7 @@
*/
package ghidra.app.plugin.core.function;
+import java.util.ArrayList;
import java.util.List;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
@@ -77,7 +78,11 @@ public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDi
@Override
protected List getCallingConventionNames() {
- return function.getProgram().getFunctionManager().getCallingConventionNames();
+ List list = new ArrayList<>();
+ list.add(Function.UNKNOWN_CALLING_CONVENTION_STRING);
+ list.add(Function.DEFAULT_CALLING_CONVENTION_STRING);
+ list.addAll(function.getProgram().getFunctionManager().getCallingConventionNames());
+ return list;
}
@Override
@@ -182,12 +187,6 @@ public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDi
public boolean applyTo(DomainObject obj) {
try {
String conventionName = getCallingConvention();
- if ("unknown".equals(conventionName)) {
- conventionName = null;
- }
- else if ("default".equals(conventionName)) {
- conventionName = function.getDefaultCallingConventionName();
- }
function.setCallingConvention(conventionName);
return true;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java
index 0010138747..45fdd7468b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java
@@ -124,15 +124,24 @@ public class FunctionEditorModel {
return false;
}
- public List getCallingConventionNames() {
- return functionManager.getCallingConventionNames();
+ List getCallingConventionNames() {
+ Collection names =
+ function.getProgram().getFunctionManager().getCallingConventionNames();
+ List list = new ArrayList<>(names);
+ if (callingConventionName != null && !names.contains(callingConventionName)) {
+ list.add(callingConventionName);
+ Collections.sort(list);
+ }
+ list.add(0, Function.DEFAULT_CALLING_CONVENTION_STRING);
+ list.add(0, Function.UNKNOWN_CALLING_CONVENTION_STRING);
+ return list;
}
- public String[] getCallFixupNames() {
+ String[] getCallFixupNames() {
return program.getCompilerSpec().getPcodeInjectLibrary().getCallFixupNames();
}
- public void setName(String name) {
+ void setName(String name) {
if (this.name.equals(name)) {
return;
}
@@ -147,20 +156,20 @@ public class FunctionEditorModel {
notifyDataChanged();
}
- public String getCallingConventionName() {
+ String getCallingConventionName() {
return callingConventionName;
}
- public void setHasVarArgs(boolean b) {
+ void setHasVarArgs(boolean b) {
hasVarArgs = b;
notifyDataChanged();
}
- public String getName() {
+ String getName() {
return name;
}
- public void dispose() {
+ void dispose() {
listener = new ModelChangeListener() {
@Override
public void tableRowsChanged() {
@@ -316,7 +325,7 @@ public class FunctionEditorModel {
return true;
}
- public boolean hasValidName() {
+ boolean hasValidName() {
if (name.length() == 0) {
statusText = "Missing function name";
return false;
@@ -381,11 +390,11 @@ public class FunctionEditorModel {
return true;
}
- public boolean isValid() {
+ boolean isValid() {
return isValid;
}
- public String getFunctionSignatureTextFromModel() {
+ String getFunctionSignatureTextFromModel() {
StringBuilder buf = new StringBuilder();
buf.append(returnInfo.getFormalDataType().getName()).append(" ");
buf.append(getNameString());
@@ -420,7 +429,7 @@ public class FunctionEditorModel {
return buf.toString();
}
- public String getNameString() {
+ String getNameString() {
return name.length() == 0 ? "?" : name;
}
@@ -428,15 +437,15 @@ public class FunctionEditorModel {
return param.getName();
}
- public boolean hasVarArgs() {
+ boolean hasVarArgs() {
return hasVarArgs;
}
- public DataType getReturnType() {
+ DataType getReturnType() {
return returnInfo.getDataType();
}
- public DataType getFormalReturnType() {
+ DataType getFormalReturnType() {
return returnInfo.getFormalDataType();
}
@@ -444,14 +453,14 @@ public class FunctionEditorModel {
return setParameterFormalDataType(returnInfo, formalReturnType);
}
- public String getStatusText() {
+ String getStatusText() {
if (isInParsingMode) {
return PARSING_MODE_STATUS_TEXT;
}
return statusText;
}
- public void setIsInLine(boolean isInLine) {
+ void setIsInLine(boolean isInLine) {
if (isInLine == this.isInLine) {
return;
}
@@ -462,12 +471,12 @@ public class FunctionEditorModel {
notifyDataChanged();
}
- public void setNoReturn(boolean isNoReturn) {
+ void setNoReturn(boolean isNoReturn) {
this.isNoReturn = isNoReturn;
notifyDataChanged();
}
- public boolean isInlineAllowed() {
+ boolean isInlineAllowed() {
return !getAffectiveFunction().isExternal();
}
@@ -481,19 +490,19 @@ public class FunctionEditorModel {
return function.isThunk() ? function.getThunkedFunction(true) : function;
}
- public boolean isInLine() {
+ boolean isInLine() {
return isInLine;
}
- public boolean isNoReturn() {
+ boolean isNoReturn() {
return isNoReturn;
}
- public String getCallFixupName() {
+ String getCallFixupName() {
return callFixupName;
}
- public void setCallFixupName(String callFixupName) {
+ void setCallFixupName(String callFixupName) {
if (callFixupName.equals(this.callFixupName)) {
return;
}
@@ -555,11 +564,11 @@ public class FunctionEditorModel {
}
}
- public int[] getSelectedParameterRows() {
+ int[] getSelectedParameterRows() {
return selectedFunctionRows;
}
- public void addParameter() {
+ void addParameter() {
if (listener != null) {
listener.tableRowsChanged();
}
@@ -700,7 +709,7 @@ public class FunctionEditorModel {
notifyDataChanged();
}
- public void moveSelectedParameterUp() {
+ void moveSelectedParameterUp() {
if (!canMoveParameterUp()) {
throw new AssertException("Attempted to move parameters up when not allowed.");
}
@@ -716,7 +725,7 @@ public class FunctionEditorModel {
notifyDataChanged();
}
- public void moveSelectedParameterDown() {
+ void moveSelectedParameterDown() {
if (!canMoveParameterDown()) {
throw new AssertException("Attempted to move parameters down when not allowed.");
}
@@ -736,7 +745,7 @@ public class FunctionEditorModel {
return parameters;
}
- public boolean canRemoveParameters() {
+ boolean canRemoveParameters() {
if (selectedFunctionRows.length == 0) {
return false;
}
@@ -748,7 +757,7 @@ public class FunctionEditorModel {
return true;
}
- public boolean canMoveParameterUp() {
+ boolean canMoveParameterUp() {
// remember first row (return type) and auto-params cannot be moved.
int minRowToMoveUp = 2 + autoParamCount;
if (parameters.size() > 0 && parameters.get(0).getName().equals("this")) {
@@ -757,7 +766,7 @@ public class FunctionEditorModel {
return selectedFunctionRows.length == 1 && selectedFunctionRows[0] >= minRowToMoveUp;
}
- public boolean canMoveParameterDown() {
+ boolean canMoveParameterDown() {
if (selectedFunctionRows.length != 1) {
return false;
}
@@ -770,12 +779,12 @@ public class FunctionEditorModel {
return selectedRow >= minRowToMoveDown && selectedRow < parameters.size();
}
- public void setParameterName(ParamInfo param, String newName) {
+ void setParameterName(ParamInfo param, String newName) {
param.setName(newName);
notifyDataChanged();
}
- public boolean setParameterFormalDataType(ParamInfo param, DataType formalDataType) {
+ boolean setParameterFormalDataType(ParamInfo param, DataType formalDataType) {
boolean isReturn = (param.getOrdinal() == Parameter.RETURN_ORIDINAL);
try {
formalDataType = VariableUtilities.checkDataType(formalDataType, isReturn, 0, program);
@@ -839,11 +848,11 @@ public class FunctionEditorModel {
}
}
- public VariableStorage getReturnStorage() {
+ VariableStorage getReturnStorage() {
return returnInfo.getStorage();
}
- public Function getFunction() {
+ Function getFunction() {
return function;
}
@@ -940,7 +949,7 @@ public class FunctionEditorModel {
return allowCustomStorage;
}
- public boolean apply() {
+ boolean apply() {
if (!modelChanged) {
return true;
}
@@ -1085,16 +1094,10 @@ public class FunctionEditorModel {
}
public void setFunctionData(FunctionDefinitionDataType functionDefinition) {
+
name = functionDefinition.getName();
- GenericCallingConvention genericCallingConvention =
- functionDefinition.getGenericCallingConvention();
- if (genericCallingConvention != null &&
- genericCallingConvention != GenericCallingConvention.unknown) {
- PrototypeModel matchConvention =
- function.getProgram().getCompilerSpec().matchConvention(genericCallingConvention);
- setCallingConventionName(matchConvention.getName());
- }
+ setCallingConventionName(functionDefinition.getCallingConventionName());
if (!isSameSize(returnInfo.getFormalDataType(), functionDefinition.getReturnType())) {
returnInfo.setStorage(VariableStorage.UNASSIGNED_STORAGE);
@@ -1110,6 +1113,7 @@ public class FunctionEditorModel {
parameters.add(new ParamInfo(this, paramDefinition));
}
hasVarArgs = functionDefinition.hasVarArgs();
+
fixupOrdinals();
if (allowCustomStorage) {
@@ -1162,11 +1166,11 @@ public class FunctionEditorModel {
return null;
}
- public boolean isInParsingMode() {
+ boolean isInParsingMode() {
return isInParsingMode;
}
- public void setSignatureFieldText(String text) {
+ void setSignatureFieldText(String text) {
signatureFieldText = text;
boolean signatureTextFieldInSync =
signatureFieldText.equals(getFunctionSignatureTextFromModel());
@@ -1177,24 +1181,32 @@ public class FunctionEditorModel {
}
}
- public void resetSignatureTextField() {
+ void resetSignatureTextField() {
setSignatureFieldText(getFunctionSignatureTextFromModel());
}
- public boolean hasChanges() {
+ boolean hasChanges() {
return !Objects.equals(getFunctionSignatureTextFromModel(), signatureFieldText);
}
- public void parseSignatureFieldText() throws ParseException, CancelledException {
+ void parseSignatureFieldText() throws ParseException, CancelledException {
FunctionSignatureParser parser =
new FunctionSignatureParser(program.getDataTypeManager(), dataTypeManagerService);
FunctionDefinitionDataType f = parser.parse(getFunctionSignature(), signatureFieldText);
+ // Preserve calling convention and noreturn flag from current model
+ f.setNoReturn(isNoReturn);
+ try {
+ f.setCallingConvention(callingConventionName);
+ }
+ catch (InvalidInputException e) {
+ // ignore
+ }
setFunctionData(f);
isInParsingMode = false;
}
- public int getFunctionNameStartPosition() {
+ int getFunctionNameStartPosition() {
return returnInfo.getFormalDataType().getName().length() + 1;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/LanguageProviderPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/LanguageProviderPlugin.java
index 7bac625749..81a4413070 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/LanguageProviderPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/LanguageProviderPlugin.java
@@ -221,7 +221,8 @@ public final class LanguageProviderPlugin extends Plugin implements ApplicationL
Program program = (Program) dobj;
monitor.setMessage("Identify Language...");
- SetLanguageDialog dialog = new SetLanguageDialog(tool, program);
+ SetLanguageDialog dialog = new SetLanguageDialog(tool, program,
+ "Set Language: " + program.getDomainFile().getName());
LanguageID langDescID = dialog.getLanguageDescriptionID();
CompilerSpecID compilerSpecDescID = dialog.getCompilerSpecDescriptionID();
if ((langDescID == null) || (compilerSpecDescID == null)) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/SetLanguageDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/SetLanguageDialog.java
index 0913d263a8..b7e1bd355c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/SetLanguageDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/SetLanguageDialog.java
@@ -22,59 +22,81 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.plugin.importer.LcsSelectionListener;
import ghidra.plugin.importer.NewLanguagePanel;
import ghidra.program.model.lang.*;
-import ghidra.program.model.listing.Program;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.HelpLocation;
+import ghidra.util.Msg;
public class SetLanguageDialog extends DialogComponentProvider {
private NewLanguagePanel selectLangPanel;
- private LanguageService langService;
private PluginTool tool;
- private Program currProgram;
+ private LanguageCompilerSpecPair currentLCSPair;
- private LanguageID dialogLanguageDescID;
- private CompilerSpecID dialogCompilerSpecDescID;
+ private LanguageID dialogLanguageID;
+ private CompilerSpecID dialogCompilerSpecID;
LcsSelectionListener listener = e -> {
LanguageID langID = null;
CompilerSpecID compilerSpecID = null;
- if (e.selection != null) {
+ if (e != null && e.selection != null) {
langID = e.selection.languageID;
compilerSpecID = e.selection.compilerSpecID;
}
- if ((langID != null) && (langID.equals(currProgram.getLanguageID()))) {
- if ((compilerSpecID != null) &&
- (compilerSpecID.equals(currProgram.getCompilerSpec().getCompilerSpecID()))) {
- //selectLangPanel.setNotificationText("Please select a different Language or Compiler Spec.");
+ if ((currentLCSPair != null) && (langID != null) &&
+ (langID.equals(currentLCSPair.getLanguageID()))) {
+ if (compilerSpecID != null &&
+ compilerSpecID.equals(currentLCSPair.getCompilerSpecID())) {
setStatusText("Please select a different Language or Compiler Spec.");
setOkEnabled(false);
}
else {
- //selectLangPanel.setNotificationText(null);
setStatusText(null);
setOkEnabled(true);
}
return;
}
- //selectLangPanel.setNotificationText("Setting the language from '" + currProgram.getLanguageName() + "' to '" + langDesc.getName() + "'...");
- //selectLangPanel.setNotificationText(null);
setStatusText(null);
setOkEnabled(langID != null);
};
- public SetLanguageDialog(PluginTool tool, Program program) {
- super(getTitle(program), true, true, true, false);
- currProgram = program;
- this.tool = tool;
+ /**
+ * Construct set Language/Compiler-Spec dialog
+ * @param tool parent tool
+ * @param programArch current program architecture or null
+ * @param title dialog title
+ */
+ public SetLanguageDialog(PluginTool tool, ProgramArchitecture programArch, String title) {
+ this(tool, programArch != null ? programArch.getLanguageCompilerSpecPair() : null, title);
+ }
- langService = DefaultLanguageService.getLanguageService();
+ /**
+ * Construct set Language/Compiler-Spec dialog
+ * @param tool parent tool
+ * @param languageId initial language ID or null
+ * @param compilerSpecId initial Compiler-Spec ID or null
+ * @param title dialog title
+ */
+ public SetLanguageDialog(PluginTool tool, String languageId, String compilerSpecId,
+ String title) {
+ this(tool, getLanguageCompilerSpecPair(languageId, compilerSpecId), title);
+ }
+
+ /**
+ * Construct set Language/Compiler-Spec dialog
+ * @param tool parent tool
+ * @param lcsPair language/compiler-spec ID pair or null
+ * @param title dialog title
+ */
+ public SetLanguageDialog(PluginTool tool, LanguageCompilerSpecPair lcsPair, String title) {
+ super(title, true, true, true, false);
+ currentLCSPair = lcsPair;
+ this.tool = tool;
selectLangPanel = new NewLanguagePanel();
- LanguageCompilerSpecPair lcsPair = new LanguageCompilerSpecPair(currProgram.getLanguageID(),
- currProgram.getCompilerSpec().getCompilerSpecID());
- selectLangPanel.setSelectedLcsPair(lcsPair);
+ if (lcsPair != null) {
+ selectLangPanel.setSelectedLcsPair(lcsPair);
+ }
selectLangPanel.addSelectionListener(listener);
@@ -83,35 +105,57 @@ public class SetLanguageDialog extends DialogComponentProvider {
addWorkPanel(selectLangPanel);
addOKButton();
addCancelButton();
- //getComponent().setPreferredSize(new Dimension(450, 430));
+
setOkEnabled(false);
setHelpLocation(new HelpLocation("LanguageProviderPlugin", "set language"));
selectLangPanel.setShowRecommendedCheckbox(false);
+
+ listener.valueChanged(null); // kick to establish initial button enablement
}
- private static String getTitle(Program program) {
- return "Set Language: " + program.getDomainFile().getName();
+ private static LanguageCompilerSpecPair getLanguageCompilerSpecPair(String languageIdStr,
+ String compilerSpecIdStr) {
+ if (languageIdStr == null) {
+ return null;
+ }
+ LanguageService languageService = DefaultLanguageService.getLanguageService();
+ try {
+ LanguageID languageId = new LanguageID(languageIdStr);
+ LanguageDescription descr = languageService.getLanguageDescription(languageId);
+ CompilerSpecID compilerSpecId = new CompilerSpecID(compilerSpecIdStr);
+ try {
+ descr.getCompilerSpecDescriptionByID(compilerSpecId);
+ }
+ catch (CompilerSpecNotFoundException e) {
+ Msg.warn(SetLanguageDialog.class, e.getMessage());
+ }
+ return new LanguageCompilerSpecPair(languageId, compilerSpecId);
+ }
+ catch (LanguageNotFoundException e) {
+ Msg.warn(SetLanguageDialog.class, e.getMessage());
+ return null;
+ }
}
- LanguageID getLanguageDescriptionID() {
+ public LanguageID getLanguageDescriptionID() {
tool.showDialog(this);
- return dialogLanguageDescID;
+ return dialogLanguageID;
}
- CompilerSpecID getCompilerSpecDescriptionID() {
- return dialogCompilerSpecDescID;
+ public CompilerSpecID getCompilerSpecDescriptionID() {
+ return dialogCompilerSpecID;
}
@Override
protected void okCallback() {
LanguageCompilerSpecPair selectedLcsPair = selectLangPanel.getSelectedLcsPair();
if (selectedLcsPair == null) {
- dialogLanguageDescID = null;
- dialogCompilerSpecDescID = null;
+ dialogLanguageID = null;
+ dialogCompilerSpecID = null;
}
else {
- dialogLanguageDescID = selectedLcsPair.languageID;
- dialogCompilerSpecDescID = selectedLcsPair.compilerSpecID;
+ dialogLanguageID = selectedLcsPair.languageID;
+ dialogCompilerSpecID = selectedLcsPair.compilerSpecID;
}
close();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java
index a9a33ca3ad..83ecf27cbe 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java
@@ -16,6 +16,8 @@
package ghidra.app.util;
import ghidra.program.model.data.*;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.FunctionSignature;
import ghidra.util.InvalidNameException;
public class DataTypeNamingUtil {
@@ -42,12 +44,16 @@ public class DataTypeNamingUtil {
StringBuilder sb = new StringBuilder(ANONYMOUS_FUNCTION_DEF_PREFIX);
- GenericCallingConvention convention = functionDefinition.getGenericCallingConvention();
- if (convention != null && convention != GenericCallingConvention.unknown) {
- sb.append(convention.getDeclarationName());
+ if (functionDefinition.hasNoReturn()) {
+ sb.append("_").append(FunctionSignature.NORETURN_DISPLAY_STRING);
}
- sb.append("_");
+ String convention = functionDefinition.getCallingConventionName();
+ if (convention != null && !Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(convention)) {
+ sb.append("_").append(convention);
+ }
+
+ sb.append("_");
sb.append(mangleDTName(returnType.getName()));
for (ParameterDefinition p : parameters) {
sb.append("_").append(mangleDTName(p.getDataType().getName()));
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/ToolTipUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/ToolTipUtils.java
index efd670063a..9edf8b22e7 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/ToolTipUtils.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/ToolTipUtils.java
@@ -289,12 +289,20 @@ public class ToolTipUtils {
}
buffy.append(friendlyEncodeHTML(function.getReturnType().getName()));
buffy.append(HTML_SPACE);
- PrototypeModel callingConvention = function.getCallingConvention();
- if (isNonDefaultCallingConvention(callingConvention)) {
- buffy.append(friendlyEncodeHTML(callingConvention.getName()));
+
+ String callingConvention = function.getCallingConventionName();
+ if (callingConvention.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
+ callingConvention = function.getCallingConvention().getName();
+ }
+ if (!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
+ String ccHtml = friendlyEncodeHTML(callingConvention);
+ if (function.hasUnknownCallingConventionName()) {
+ ccHtml = colorString(Color.RED, ccHtml);
+ }
+ buffy.append(ccHtml);
buffy.append(HTML_SPACE);
}
-
+
String functionName = StringUtilities.trimMiddle(function.getName(), LINE_LENGTH);
buffy.append(colorString(FunctionColors.NAME, friendlyEncodeHTML(functionName)));
buffy.append(HTML_SPACE).append("(");
@@ -304,14 +312,6 @@ public class ToolTipUtils {
return buffy.toString();
}
- private static boolean isNonDefaultCallingConvention(PrototypeModel callingConvention) {
- if (callingConvention == null) {
- return false;
- }
-
- return !Function.DEFAULT_CALLING_CONVENTION_STRING.equals(callingConvention.getName());
- }
-
private static void buildParameterPreview(Function function, StringBuilder buffy) {
int rawTextLength = 0;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporter.java
index 73b55ff6d0..81b0d4bf1f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporter.java
@@ -16,13 +16,11 @@
package ghidra.app.util.bin.format.dwarf4.next;
import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.DW_TAG_base_type;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.DW_TAG_subrange_type;
-
-import java.util.*;
-import java.util.stream.Collectors;
+import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
@@ -35,7 +33,9 @@ import ghidra.program.database.DatabaseObject;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.util.Msg;
+import ghidra.util.exception.InvalidInputException;
/**
* Creates Ghidra {@link DataType}s using information from DWARF debug entries. The caller
@@ -301,6 +301,7 @@ public class DWARFDataTypeImporter {
FunctionDefinitionDataType funcDef =
new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager);
funcDef.setReturnType(returnType.dataType);
+ funcDef.setNoReturn(diea.getBool(DW_AT_noreturn, false));
funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()]));
if (!diea.getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) {
@@ -308,7 +309,12 @@ public class DWARFDataTypeImporter {
}
if (foundThisParam) {
- funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall);
+ try {
+ funcDef.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
+ }
+ catch (InvalidInputException e) {
+ Msg.error(this, "Unexpected calling convention error", e);
+ }
}
if (dni.isAnon() && mangleAnonFuncNames) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java
index 81dda81a50..b2437cf07c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java
@@ -15,22 +15,22 @@
*/
package ghidra.app.util.bin.format.dwarf4.next;
+import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.io.IOException;
-
import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFEncoding;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
+import ghidra.app.util.bin.format.dwarf4.encoding.*;
import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
import ghidra.app.util.bin.format.dwarf4.next.DWARFDataTypeImporter.DWARFDataType;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import utility.function.Dummy;
@@ -726,13 +726,19 @@ public class DWARFDataTypeManager {
FunctionDefinitionDataType funcDef =
new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager);
funcDef.setReturnType(returnDataType);
+ funcDef.setNoReturn(diea.getBool(DWARFAttribute.DW_AT_noreturn, false));
funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()]));
if (!diea.getHeadFragment().getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) {
funcDef.setVarArgs(true);
}
if (foundThisParam) {
- funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall);
+ try {
+ funcDef.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
+ }
+ catch (InvalidInputException e) {
+ Msg.error(this, "Unexpected calling convention error", e);
+ }
}
return funcDef;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
index 62a054a6c1..0f9f1a5ffb 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
@@ -388,7 +388,8 @@ public class DWARFFunctionImporter {
Parameter curparam = buildParameter(gfunc, i, dfunc.params.get(i), diea);
params.add(curparam);
if (i == 0 && checkThisParameter(dfunc.params.get(0), diea)) {
- convention = compilerSpec.matchConvention(GenericCallingConvention.thiscall);
+ convention =
+ compilerSpec.matchConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java
index ff8dffb1f1..c28865e49c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java
@@ -17,27 +17,52 @@ package ghidra.app.util.cparser.C;
import java.io.*;
import java.util.Arrays;
-import java.util.Iterator;
+
+import javax.help.UnsupportedOperationException;
import generic.theme.GThemeDefaults.Colors;
import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.framework.plugintool.ServiceProvider;
-import ghidra.program.database.ProgramDB;
+import ghidra.framework.store.LockException;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.model.listing.Program;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
public class CParserUtils {
-
+
private CParserUtils() {
// utils class
}
+
+ public record CParseResults(PreProcessor preProcessor, String cppParseMessages, String cParseMessages, boolean successful) {
+ public String getFormattedParseMessage(String errMsg) {
+ String message = "";
+
+ if (errMsg != null) {
+ message += errMsg + "\n\n";
+ }
+
+ String msg = cppParseMessages;
+ if (msg != null && msg.length() != 0) {
+ message += "CParser Messages:\n" + msg + "\n\n";
+ }
+
+ msg = cppParseMessages;
+ if (msg != null && msg.length() != 0) {
+ message += "PreProcessor Messages:\n" + msg;
+ }
+
+ return message;
+ }
+ }
/**
* Parse the given function signature text. Any exceptions will be handled herein
@@ -88,7 +113,7 @@ public class CParserUtils {
* [0]= part before function name
* [1]= function name
* [2]= parameter body after function name
- * @param signature
+ * @param signature function signature string to split
* @return parts array or null if split failed
*/
private static String[] splitFunctionSignature(String signature) {
@@ -136,7 +161,7 @@ public class CParserUtils {
/**
* Get a temporary name of a specified length (tttt....)
- * @param length
+ * @param length of temporary string
* @return temporary name string
*/
private static String getTempName(int length) {
@@ -158,6 +183,7 @@ public class CParserUtils {
* parsing exceptions. This allows clients to perform exception handling that
* better matches their workflow.
* @return the data type that is created as a result of parsing; null if there was a problem
+ * @throws ParseException for catastrophic errors in C parsing
*/
public static FunctionDefinitionDataType parseSignature(DataTypeManagerService service,
Program program, String signatureText, boolean handleExceptions) throws ParseException {
@@ -237,8 +263,6 @@ public class CParserUtils {
*
* @param dataFileName name of data type archive file (include the .gdt extension)
*
- * @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
- *
* @param monitor used to cancel or provide results
*
* @return the data types in the ghidra .gdt archive file
@@ -250,15 +274,48 @@ public class CParserUtils {
*/
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
- PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
+ TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
- File file = new File(dataFileName);
- FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
- parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, cpp, monitor);
+ return parseHeaderFiles(openDTMgrs, filenames, null, args, dataFileName, monitor);
+ }
+
+ /**
+ * Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
+ * with in the provided dataFileName.
+ *
+ * Note: Using another open archive while parsing will cause:
+ * - a dependence on the other archive
+ * - any missing data types while parsing are supplied if present from an openDTMgr
+ * - after parsing all data types parsed with an equivalent data type in any openDTMgr
+ * replaced by the data type from the openDTMgr
+ *
+ * NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
+ *
+ * @param openDTMgrs array of datatypes managers to use for undefined data types
+ *
+ * @param filenames names of files in order to parse, could include strings with
+ * "#" at start, which are ignored as comments
+ * @param includePaths paths to include files, instead of using "-I" in args
+ * @param args arguments for parsing, "-D=", ( "-I" use includePaths parm instead)
+ *
+ * @param dataFileName name of data type archive file (include the .gdt extension)
+ *
+ * @param monitor used to cancel or provide results
+ *
+ * @return the data types in the ghidra .gdt archive file
+ *
+ * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
+ * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
+ * @throws IOException if there io are errors saving the archive
+ *
+ */
+
+ public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
+ TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
+ ghidra.app.util.cparser.CPP.ParseException, IOException {
- dtMgr.save();
- return dtMgr;
+ return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dataFileName, null, null, monitor);
}
@@ -280,6 +337,7 @@ public class CParserUtils {
*
* @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments
+ * @param includePaths path to include files, could also be in args with "-I"
* @param args arguments for parsing, "-D=", "-I"
*
* @param dataFileName name of data type archive file (include the .gdt extension)
@@ -287,8 +345,6 @@ public class CParserUtils {
* @param languageId language identication to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing
*
- * @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
- *
* @param monitor used to cancel or provide results
*
* @return the data types in the ghidra .gdt archive file
@@ -298,14 +354,17 @@ public class CParserUtils {
* @throws IOException if there io are errors saving the archive
*
*/
- public static DataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
- String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
+ public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
+ String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
File file = new File(dataFileName);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
- String messages = parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, languageId, compileSpecId, cpp, monitor);
+ CParseResults results;
+ results = parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, languageId, compileSpecId, monitor);
+
+ String messages = results.getFormattedParseMessage(null);
Msg.info(CParserUtils.class, messages);
dtMgr.save();
@@ -331,15 +390,13 @@ public class CParserUtils {
*
* @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments
- * @param args arguments for parsing, "-D=", "-I"
+ * @param args arguments for parsing, "-D=", ( "-I" use includePaths parm instead)
*
* @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
*
* @param languageId language identication to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing
*
- * @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
- *
* @param monitor used to cancel or provide results
*
* @return a formatted string of any output from pre processor parsing or C parsing
@@ -349,39 +406,84 @@ public class CParserUtils {
* @throws IOException if there io are errors saving the archive
*
*/
- public static String parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
- String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
+ public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
+ String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
+ ghidra.app.util.cparser.CPP.ParseException, IOException {
+
+ return parseHeaderFiles(openDTMgrs, filenames, null, args, existingDTMgr, languageId, compileSpecId, monitor);
+ }
+
+ /**
+ * Parse a set of C Header files and associated parsing arguments, data types are added to the provided
+ * DTMgr.
+ *
+ * Note: Using another open archive while parsing will cause:
+ * - a dependence on the other archive
+ * - any missing data types while parsing are supplied if present from an openDTMgr
+ * - after parsing all data types parsed with an equivalent data type in any openDTMgr
+ * replaced by the data type from the openDTMgr
+ *
+ * NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
+ *
+ * NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
+ * @param openDTMgrs array of datatypes managers to use for undefined data types
+ *
+ * @param filenames names of files in order to parse, could include strings with
+ * "#" at start, which are ignored as comments
+ * @param includePaths paths to include files, instead of using "-I" in args
+ * @param args arguments for parsing, "-D=", ( "-I" use includePaths parm instead)
+ *
+ * @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
+ *
+ * @param languageId language identication to use for data type organization definitions (int, long, ptr size)
+ * @param compileSpecId compiler specification to use for parsing
+ *
+ * @param monitor used to cancel or provide results
+ *
+ * @return a formatted string of any output from pre processor parsing or C parsing
+ *
+ * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
+ * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
+ * @throws IOException if there io are errors saving the archive
+ *
+ */
+ public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], DataTypeManager existingDTMgr,
+ String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
Language language = DefaultLanguageService.getLanguageService().getLanguage(new LanguageID(languageId));
CompilerSpec compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compileSpecId));
-
- String dtmgrName = existingDTMgr.getName();
- if (existingDTMgr instanceof FileDataTypeManager) {
- dtmgrName = ((FileDataTypeManager) existingDTMgr).getPath();
- }
-
- ProgramDB program = new ProgramDB(dtmgrName, language, compilerSpec, CParserUtils.class);
- try {
- DataTypeManager programDtm = program.getDataTypeManager();
- String messages = parseHeaderFiles(openDTMgrs, filenames, args, programDtm, cpp, monitor);
-
- int txId = existingDTMgr.startTransaction("Add Types");
- try {
- Iterator allDataTypes = programDtm.getAllDataTypes();
- while (allDataTypes.hasNext()) {
- existingDTMgr.resolve(allDataTypes.next(), null);
- }
- }
- finally {
- existingDTMgr.endTransaction(txId, true);
- }
- return messages;
- }
- finally {
- program.release(CParserUtils.class);
+ if (existingDTMgr instanceof StandAloneDataTypeManager) {
+ try {
+ ((StandAloneDataTypeManager) existingDTMgr).setProgramArchitecture(language, compilerSpec.getCompilerSpecID(),
+ StandAloneDataTypeManager.LanguageUpdateOption.UNCHANGED, monitor);
+ }
+ catch (CompilerSpecNotFoundException e) {
+ e.printStackTrace();
+ }
+ catch (LanguageNotFoundException e) {
+ e.printStackTrace();
+ }
+ catch (CancelledException e) {
+ // ignore
+ }
+ catch (LockException e) {
+ e.printStackTrace();
+ }
+ catch (UnsupportedOperationException e) {
+ e.printStackTrace();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ catch (IncompatibleLanguageException e) {
+ // Shouldn't happen, unless already had a language
+ e.printStackTrace();
+ }
}
+
+ return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, existingDTMgr, monitor);
}
/**
@@ -405,12 +507,11 @@ public class CParserUtils {
*
* @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments
- * @param args arguments for parsing, "-D=", "-I"
+ * @param includePaths paths to include files, instead of using "-I" in args
+ * @param args arguments for parsing, "-D=", ( "-I" use includePaths parm instead)
*
* @param dtMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
*
- * @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
- *
* @param monitor used to cancel or provide results
*
* @return a formatted string of any output from pre processor parsing or C parsing
@@ -418,22 +519,31 @@ public class CParserUtils {
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
*/
- public static String parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames,
- String args[], DataTypeManager dtMgr, PreProcessor cpp, TaskMonitor monitor)
+ public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames, String[] includePaths,
+ String args[], DataTypeManager dtMgr, TaskMonitor monitor)
throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException {
String cppMessages = "";
- if (cpp == null) {
- cpp = new PreProcessor();
- }
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ PreProcessor cpp = new PreProcessor();
+
cpp.setArgs(args);
+ cpp.addIncludePaths(includePaths);
PrintStream os = System.out;
- String fName = dtMgr.getName().replace(".gdt","")+"_CParser.out";
+
+ String fName = dtMgr.getName();
+
+ // make a path to tmpdir with name of data type manager
+ String path = System.getProperty("java.io.tmpdir") + File.pathSeparator + fName;
+ // if file data type manager, use path to .gdt file
+ if (dtMgr instanceof FileDataTypeManager) {
+ path = ((FileDataTypeManager) dtMgr).getPath();
+ }
+ path = path + "_CParser.out";
+
try {
- os = new PrintStream(new FileOutputStream(fName));
+ os = new PrintStream(new FileOutputStream(path));
} catch (FileNotFoundException e2) {
Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2);
}
@@ -442,8 +552,10 @@ public class CParserUtils {
System.setOut(os);
cpp.setMonitor(monitor);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setOutputStream(bos);
+ boolean parseSucceeded = false;
try {
for (String filename : filenames) {
if (monitor.isCancelled()) {
@@ -469,9 +581,9 @@ public class CParserUtils {
parseFile(filename, monitor, cpp);
}
}
- } catch (RuntimeException re) {
+ parseSucceeded = true;
+ } catch (Throwable e) {
Msg.info(cpp, cpp.getParseMessages());
- throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
} finally {
System.out.println(bos);
os.flush();
@@ -481,12 +593,16 @@ public class CParserUtils {
}
cppMessages = cpp.getParseMessages();
+ if (!parseSucceeded) {
+ return new CParseResults(cpp, "", cppMessages, false);
+ }
// process all the defines and add any that are integer values into
// the Equates table
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
String parserMessages = "";
+ boolean cparseSucceeded = false;
if (!monitor.isCancelled()) {
monitor.setMessage("Parsing C");
@@ -497,12 +613,15 @@ public class CParserUtils {
cParser.setParseFileName(fName);
cParser.setMonitor(monitor);
cParser.parse(bis);
+ cparseSucceeded = cParser.didParseSucceed();
+ } catch (RuntimeException re) {
+ Msg.info(cpp, cpp.getParseMessages());
} finally {
parserMessages = cParser.getParseMessages();
}
}
- return getFormattedParseMessage(parserMessages, cppMessages, null);
+ return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded);
}
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
@@ -522,26 +641,6 @@ public class CParserUtils {
return cpp.getParseMessages();
}
- private static String getFormattedParseMessage(String parseMessage, String cppMessage, String errMsg) {
- String message = "";
-
- if (errMsg != null) {
- message += errMsg + "\n\n";
- }
-
- String msg = parseMessage;
- if (msg != null && msg.length() != 0) {
- message += "CParser Messages:\n" + msg + "\n\n";
- }
-
- msg = cppMessage;
- if (msg != null && msg.length() != 0) {
- message += "PreProcessor Messages:\n" + msg;
- }
-
- return message;
- }
-
private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) {
if (service == null) {
@@ -680,4 +779,54 @@ public class CParserUtils {
errorIndex + "
" + successFailureBuffer;
}
+
+ public static File getFile(String parent, String filename) {
+ File file = findFile(parent, filename);
+ if (file != null) {
+ return file;
+ }
+ // filename lower
+ file = findFile(parent, filename.toLowerCase());
+ if (file != null) {
+ return file;
+ }
+ // parent and filename lower
+ file = findFile(parent.toLowerCase(), filename.toLowerCase());
+ if (file != null) {
+ return file;
+ }
+ // parent and filename upper
+ file = findFile(parent.toUpperCase(), filename.toUpperCase());
+ return file;
+ }
+
+ private static File findFile(String parent, String filename) {
+ File iFile = null;
+
+ iFile = new File(parent + File.separator + filename);
+ if (iFile.exists())
+ return iFile;
+
+ // try just in this directory
+ File sameiFile = new File(parent + File.separator
+ + (new File(filename)).getName());
+ if (sameiFile.exists())
+ return sameiFile;
+
+ // try all files in this directory doing to-lower on both input file and output file
+ // if match return it
+ File folder = new File(parent);
+ if (folder.isDirectory()) {
+ File[] listOfFiles = folder.listFiles();
+
+ if (listOfFiles != null) {
+ for (File file : listOfFiles) {
+ if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) {
+ return file;
+ }
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/FunctionDataTypeHTMLRepresentation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/FunctionDataTypeHTMLRepresentation.java
index c927613963..3050086820 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/FunctionDataTypeHTMLRepresentation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/FunctionDataTypeHTMLRepresentation.java
@@ -21,10 +21,12 @@ import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
+import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.util.ToolTipUtils;
import ghidra.app.util.html.diff.DataTypeDiff;
import ghidra.app.util.html.diff.DataTypeDiffBuilder;
import ghidra.program.model.data.*;
+import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
import ghidra.util.HTMLUtilities;
import ghidra.util.StringUtilities;
@@ -113,14 +115,26 @@ public class FunctionDataTypeHTMLRepresentation extends HTMLDataTypeRepresentati
}
private TextLine buildReturnType(FunctionDefinition functionDefinition) {
+
DataType returnDataType = functionDefinition.getReturnType();
- GenericCallingConvention genericCallingConvention =
- functionDefinition.getGenericCallingConvention();
- String modifier = genericCallingConvention != GenericCallingConvention.unknown
- ? (" " + genericCallingConvention.getDeclarationName())
- : "";
- return new TextLine(
- HTMLUtilities.friendlyEncodeHTML(returnDataType.getDisplayName()) + modifier);
+ String rtHtml = friendlyEncodeHTML(returnDataType.getDisplayName());
+
+ String noReturnHtml = "";
+ if (functionDefinition.hasNoReturn()) {
+ noReturnHtml = FunctionSignature.NORETURN_DISPLAY_STRING + HTML_SPACE;
+ }
+
+ String ccHtml = "";
+ String callingConvention = functionDefinition.getCallingConventionName();
+ if (!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
+ ccHtml = friendlyEncodeHTML(callingConvention);
+ if (functionDefinition.hasUnknownCallingConventionName()) {
+ ccHtml = colorString(Messages.ERROR, ccHtml);
+ }
+ ccHtml = HTML_SPACE + ccHtml;
+ }
+
+ return new TextLine(noReturnHtml + rtHtml + ccHtml);
}
// display name to name pairs
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureFieldFactory.java
index 77bda1c845..7c71990b49 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureFieldFactory.java
@@ -123,12 +123,11 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
if (callingConvention.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
callingConvention = function.getCallingConvention().getName();
}
- if (callingConvention != null &&
- !callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
+ if (!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
as = new AttributedString(callingConvention + " ", FunctionColors.RETURN_TYPE,
getMetrics());
textElements
- .add(new FunctionCallingConventionFieldElement(as, elementIndex, 0, startCol));
+ .add(new FunctionCallingConventionFieldElement(as, elementIndex, 0, startCol));
startCol += as.length();
elementIndex++;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/LanguageSortedTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/LanguageSortedTableModel.java
index a8957c9c72..8db1e6c6ef 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/LanguageSortedTableModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/LanguageSortedTableModel.java
@@ -129,6 +129,14 @@ public class LanguageSortedTableModel extends AbstractSortedTableModel
+ * NOTE: If archive has an assigned architecture, issues may arise due to a revised or
+ * missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
+ * prevent the archive from being opened. Such a warning condition will be 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 archiveFile the archive file to open
* @param readOnly should file be opened read only
* @return the data type manager
@@ -2494,8 +2505,7 @@ public class FlatProgramAPI {
*/
public final FileDataTypeManager openDataTypeArchive(File archiveFile, boolean readOnly)
throws Exception {
- FileDataTypeManager dtfm = FileDataTypeManager.openFileArchive(archiveFile, !readOnly);
- return dtfm;
+ return FileDataTypeManager.openFileArchive(archiveFile, !readOnly);
}
/**
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java
index cd86c27bff..23b353b7e1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java
@@ -20,7 +20,6 @@ import java.util.*;
import generic.theme.GThemeDefaults.Colors.Palette;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
-import ghidra.program.model.data.GenericCallingConvention;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.*;
@@ -64,7 +63,7 @@ public class FunctionUtility {
Program sourceProgram = sourceFunction.getProgram();
Program destinationProgram = destinationFunction.getProgram();
- boolean sameLanguage = isSameLanguage(destinationProgram, sourceProgram);
+ boolean sameLanguage = isSameLanguageAndCompilerSpec(destinationProgram, sourceProgram);
String callingConventionName =
determineCallingConventionName(destinationFunction, sourceFunction, sameLanguage);
@@ -274,7 +273,7 @@ public class FunctionUtility {
* @param program2 the second program
* @return true if the two programs have the same processor language and compiler spec.
*/
- public static boolean isSameLanguage(Program program1, Program program2) {
+ public static boolean isSameLanguageAndCompilerSpec(Program program1, Program program2) {
Language language1 = program1.getLanguage();
Language language2 = program2.getLanguage();
if (language1.getLanguageID() != language2.getLanguageID()) {
@@ -289,17 +288,9 @@ public class FunctionUtility {
}
private static String determineCallingConventionName(Function destinationFunction,
- Function sourceFunction, boolean sameLanguage) {
- String sourceCallingConventionName = sourceFunction.getCallingConventionName();
- if (sameLanguage) {
- return sourceCallingConventionName; // Same language, so set to source.
- }
- GenericCallingConvention guessedCallingConvention =
- GenericCallingConvention.guessFromName(sourceCallingConventionName);
- if (guessedCallingConvention == GenericCallingConvention.thiscall) {
- return GenericCallingConvention.thiscall.name(); // this call
- }
- return destinationFunction.getCallingConventionName(); // leave destination unchanged.
+ Function sourceFunction, boolean sameLanguageAndCompilerSpec) {
+ return sameLanguageAndCompilerSpec ? sourceFunction.getCallingConventionName()
+ : destinationFunction.getCallingConventionName();
}
private static boolean determineCustomStorageUse(Function destinationFunction,
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java
index 8b8545200c..f26e95e0d4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java
@@ -44,6 +44,7 @@ import ghidra.program.database.ProgramDB;
import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Function.FunctionUpdateType;
@@ -971,6 +972,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
ResourceFile emuTestingArchive = Application.getModuleDataFile("pcodetest/EmuTesting.gdt");
archiveDtMgr = FileDataTypeManager.openFileArchive(emuTestingArchive, false);
+ assertEquals(ArchiveWarning.NONE, archiveDtMgr.getWarning());
DataType dt = archiveDtMgr.getDataType(CategoryPath.ROOT, TEST_INFO_STRUCT_NAME);
if (dt == null || !(dt instanceof Structure)) {
fail(TEST_INFO_STRUCT_NAME +
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/UndefinedFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/util/UndefinedFunction.java
index 08cffc06c7..6e65f5b5ad 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/UndefinedFunction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/UndefinedFunction.java
@@ -218,6 +218,11 @@ public class UndefinedFunction implements Function {
return p.getCompilerSpec().getDefaultCallingConvention();
}
+ @Override
+ public boolean hasUnknownCallingConventionName() {
+ return true;
+ }
+
@Override
public String getCallingConventionName() {
return Function.UNKNOWN_CALLING_CONVENTION_STRING;
@@ -233,11 +238,6 @@ public class UndefinedFunction implements Function {
return new String[0];
}
- @Override
- public String getDefaultCallingConventionName() {
- return p.getCompilerSpec().getDefaultCallingConvention().getName();
- }
-
@Override
public Address getEntryPoint() {
return entry;
diff --git a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
index 5e6775e301..c6e6d59c74 100644
--- a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
+++ b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
@@ -622,11 +622,12 @@ public class CParser {
* @param dec Declaration
* @param funcDT function data type to qualify
*/
- private void applyFunctionQualifiers(Declaration dec, FunctionDefinitionDataType funcDT) {
+ private void applyFunctionQualifiers(Declaration dec, FunctionDefinition funcDT) {
List qualifierList = dec.getQualifiers();
if (qualifierList.contains(NORETURN) ) {
- // TODO: set no return on function
+ funcDT.setNoReturn(true);
}
+ // TODO: switch to setting calling convention by string identifier
for (Integer qualifier : qualifierList) {
switch (qualifier) {
case CDECL:
@@ -1772,18 +1773,18 @@ Declaration TypeQualifier(Declaration dec) : {}
|
|
|
- ( DeclSpec() )
+ ( DeclSpec(dec) )
)
{
return dec;
}
}
-void AttributeSpec() : {}
+void AttributeSpec(Declaration dec) : {}
{
- ( ("(") SubIdent() (")") ) |
+ ( ("(") SubIdent(dec) (")") ) |
AsmStatement() |
- ( "[" "[" AttributeList() "]" "]" ) |
+ ( "[" "[" AttributeList(dec) "]" "]" ) |
AlignmentSpecifier()
}
@@ -1793,48 +1794,59 @@ void AlignmentSpecifier() : { Declaration dt = new Declaration(); }
< ALIGNAS > "(" ( TypeQualifier(dt) | AssignmentExpression() ) ")"
}
-void AttributeList() : { }
+void AttributeList(Declaration dec) : { }
{
- AttributeToken() [ ("," AttributeToken())+ ]
+ AttributeToken(dec) [ ("," AttributeToken(dec))+ ]
}
-void AttributeToken() : { Declaration dt = new Declaration(); }
+void AttributeToken(Declaration dec) : { }
{
- ( < IDENTIFIER > | TypeQualifier(dt) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dt) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ]
+ ( < IDENTIFIER > | TypeQualifier(dec) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dec) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ]
}
-void AttributeSpecList() : {}
+void AttributeSpecList(Declaration dec) : {}
{
- ( AttributeSpec() )+
+ ( AttributeSpec(dec) )+
}
-void SubIdent() : { Declaration dt = new Declaration(); }
+void SubIdent(Declaration dec) : {
+ Token id = null;
+ Declaration dt = new Declaration();
+}
{
- ( ( "(" [SubIdent()] ")" ) |
- ( | TypeQualifier(dt)) [ ( "(" [SubIdent()] ")") | ("=" SubIdent()) ]
+ ( ( "(" [SubIdent(dec)] ")" ) |
+ (id= | TypeQualifier(dec)) [ ( "(" [SubIdent(dt)] ")") | ("=" SubIdent(dt)) ]
[ ","
- SubIdent()
+ SubIdent(dt)
] |
Constant() [ ","
- SubIdent()
+ SubIdent(dt)
]
)
+ {
+ if (id != null && "noreturn".equals(id.image.replace("_", ""))) {
+ dec.addQualifier(NORETURN);
+ if (dec.getDataType() instanceof FunctionDefinition) {
+ applyFunctionQualifiers(dec, (FunctionDefinition) dec.getDataType());
+ }
+ }
+ }
}
-void DeclSpec() : {
+void DeclSpec(Declaration dec) : {
}
{
- ( ( | ) "(" DeclSpecifier() ")" ) |
- AttributeSpecList()
+ ( ( | ) "(" DeclSpecifier(dec) ")" ) |
+ AttributeSpecList(dec)
}
-void DeclSpecifier() : {
+void DeclSpecifier(Declaration dec) : {
+ Token id = null;
}
{
- "(" DeclSpecifier() ")" |
- ()+ [ "("
- DeclConstant() ( DeclConstant() )*
- ")" ]
+ "(" DeclSpecifier(dec) ")" |
+ (id= { if (id != null && "noreturn".equals(id.image)) dec.addQualifier(NORETURN); } )+
+ [ "(" DeclConstant() ( DeclConstant() )* ")" ]
}
void DeclConstant() : {}
@@ -1970,6 +1982,7 @@ DataType StructOrUnionSpecifier() : {
Token parent;
Token sname;
Composite comp;
+ Declaration dec = new Declaration();
}
{
{
@@ -1982,7 +1995,7 @@ DataType StructOrUnionSpecifier() : {
LOOKAHEAD(3)
[ t= [ ":" parent=]
{ comp=defineNamedComposite(t, null, comp); } // no parent yet, since there are no guts
- ] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList() ]
+ ] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList(dec) ]
|
sname=
)
@@ -1997,10 +2010,13 @@ DataType StructOrUnionSpecifier() : {
}
}
-Composite StructOrUnion() : {Composite comp;}
+Composite StructOrUnion() : {
+ Composite comp;
+ Declaration dec = new Declaration();
+}
{
(
- ( DeclSpec() | PragmaSpec() )*
+ ( DeclSpec(dec) | PragmaSpec() )*
{
comp = new StructureDataType(getCurrentCategoryPath(), ANONYMOUS_STRUCT_PREFIX + cnt++, 0, dtMgr);
@@ -2014,7 +2030,7 @@ Composite StructOrUnion() : {Composite comp;}
}
|
- ( DeclSpec() )* {
+ ( DeclSpec(dec) )* {
comp = new UnionDataType(getCurrentCategoryPath(), ANONYMOUS_UNION_PREFIX + cnt++, dtMgr);
// Always set the packing, because by default structures should be aligned
@@ -2067,6 +2083,7 @@ void InitDeclarator(Declaration dt) : { Declaration dec; }
void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
Declaration dt = null;
+ Declaration dec = new Declaration();
}
{
LineDef() |
@@ -2077,7 +2094,7 @@ void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
[
StructDeclaratorList(dt, comp, compositeHandler) { dt= null; }
]
- [ AttributeSpecList() ]
+ [ AttributeSpecList(dec) ]
";"
)
{
@@ -2173,12 +2190,13 @@ DataType EnumSpecifier() : {
Token t= null;
DataType dt;
ArrayList list;
+ Declaration dec = new Declaration();
}
{
(
LOOKAHEAD(3)
- [AttributeSpecList()] [ t= ] "{" list= EnumeratorList() "}"
+ [AttributeSpecList(dec)] [ t= ] "{" list= EnumeratorList() "}"
{
String enumName= (t != null ? t.image : ("enum_" + cnt++));
EnumDataType enuum= new EnumDataType(getCurrentCategoryPath(), enumName, 4, dtMgr);
@@ -2247,7 +2265,7 @@ Declaration Declarator(Declaration dt, DataType container) : {
}
{
(
- [ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList() ]
+ [ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList(dec) ]
)
{
return dec;
diff --git a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj
index 7ca754faf2..8d837647b4 100644
--- a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj
+++ b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj
@@ -1172,6 +1172,16 @@ public class PreProcessor {
public void addIncludePath(String path) {
pathList.addElement(path);
}
+
+ public void addIncludePaths(String[] paths) {
+ if (paths == null || paths.length < 1) {
+ return;
+ }
+
+ for (String path : paths) {
+ addIncludePath(path);
+ }
+ }
public int getNumericType(String val) {
try {
@@ -1246,7 +1256,7 @@ public class PreProcessor {
outputStream = new PrintStream(fos);
}
- public void parse(String filename) throws ParseException {
+ public boolean parse(String filename) throws ParseException {
if (verboseLevel == 1) {
addParseMessage(null,
"PreProcessor: Reading from file " + filename + " . . .");
@@ -1269,7 +1279,7 @@ public class PreProcessor {
}
if (fis == null) {
addParseMessage(null, "PreProcessor: File " + filename + " not found.");
- return;
+ return false;
}
fileStack.push(filename);
alreadyDone = new HashMap();
@@ -1290,6 +1300,7 @@ public class PreProcessor {
addParseMessage(filename, "PreProcessor Token Error: " + e.getMessage());
throw e;
}
+ return true;
}
PreProcessor(PreProcessor parent) {
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge2Test.java
index ecaad2678d..c2fc0500db 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge2Test.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge2Test.java
@@ -45,17 +45,12 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeEditedInMy() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
// Make no changes to Latest.
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -99,9 +94,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeEditedInBoth() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -126,9 +119,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -171,9 +161,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedChanged() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -197,9 +185,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -235,9 +220,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedChanged2() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -263,9 +246,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -309,9 +289,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedChanged3() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -340,9 +318,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -383,9 +358,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedChanged4() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -411,9 +384,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -458,9 +428,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedInBoth() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -487,9 +455,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -532,9 +497,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testRenamedChanged() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -556,9 +519,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -602,9 +562,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// in Latest move data type; in MY change the name;
// should be a conflict
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -628,9 +586,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -666,9 +621,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testRenamedChangedMoved() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -699,9 +652,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -739,9 +689,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testRenamedChangedMovedNoConflict() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -772,9 +720,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -813,9 +758,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testRenamedChangedMovedNoConflict2() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -835,9 +778,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -889,9 +829,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// edit DLL_Table in latest; edit DLL_Table in private
// only DLL_Table should be in conflict; not the ones where it is used.
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -919,9 +857,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -963,9 +898,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// edit DLL_Table in latest; edit DLL_Table in private
// only DLL_Table should be in conflict; not the ones where it is used.
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -993,9 +926,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -1037,9 +967,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// edit ArrayStruct in latest; edit ArrayStruct in private
// only ArrayStruct should be in conflict; not the ones where it is used.
mtf.initialize("notepad", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -1067,9 +995,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -1337,9 +1262,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDeletedInLatest() throws Exception {
mtf.initialize("notepad2", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -1356,9 +1279,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -1429,9 +1349,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testAddedFuncSig() throws Exception {
mtf.initialize("notepad2", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
@@ -1448,9 +1366,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
@@ -1496,9 +1411,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testEditFuncSig() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1517,9 +1430,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1562,9 +1472,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testEditFuncSig2() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1585,9 +1493,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1629,9 +1534,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testEditFuncSig3() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1642,6 +1545,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
try {
fd.setVarArgs(true);
+ fd.setNoReturn(true);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
dtm.remove(foo, TaskMonitor.DUMMY);
commit = true;
@@ -1651,9 +1555,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1689,16 +1590,15 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals(DataType.DEFAULT, vars[0].getDataType());
assertEquals("this is a comment", vars[0].getComment());
assertEquals(DataType.DEFAULT, vars[1].getDataType());
- assertEquals(false, fd.hasVarArgs());
+ assertFalse(fd.hasVarArgs());
+ assertFalse(fd.hasNoReturn());
}
@Test
public void testEditFuncSig4() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1709,6 +1609,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
try {
fd.setVarArgs(true);
+ fd.setNoReturn(true);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
dtm.remove(foo, TaskMonitor.DUMMY);
commit = true;
@@ -1718,9 +1619,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1759,16 +1657,15 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
checkDataType(new CharDataType(), vars[1].getDataType());
checkDataType(new Undefined4DataType(), vars[2].getDataType());
checkDataType(new Undefined4DataType(), vars[3].getDataType());
- assertEquals(true, fd.hasVarArgs());
+ assertTrue(fd.hasVarArgs());
+ assertTrue(fd.hasNoReturn());
}
@Test
public void testEditFuncSig5() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1788,9 +1685,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1808,6 +1702,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
"this is another comment");
fd.setArguments(newVars);
fd.setVarArgs(true);
+ fd.setNoReturn(true);
commit = true;
}
finally {
@@ -1831,6 +1726,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals("Bar", vars[4].getName());
assertEquals("this is another comment", vars[4].getComment());
assertTrue(fd.hasVarArgs());
+ assertTrue(fd.hasNoReturn());
}
private void checkDataType(DataType expectedDataType, DataType actualDataType) {
@@ -1842,9 +1738,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testAddConflictFuncSig1() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() {
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
- */
+
@Override
public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1866,9 +1760,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
}
}
- /* (non-Javadoc)
- * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
- */
@Override
public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false;
@@ -1902,7 +1793,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals("format", vars[0].getName());
assertEquals(null, vars[0].getComment());
checkDataType(new WordDataType(), fd1.getReturnType());
- assertEquals(false, fd1.hasVarArgs());
+ assertFalse(fd1.hasVarArgs());
FunctionDefinition fd2 =
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "printf.conflict");
@@ -1913,7 +1804,80 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals("format", vars2[0].getName());
assertEquals(null, vars2[0].getComment());
checkDataType(new WordDataType(), fd2.getReturnType());
- assertEquals(true, fd2.hasVarArgs());
+ assertTrue(fd2.hasVarArgs());
+ }
+
+ @Test
+ public void testAddConflictFuncSig2() throws Exception {
+
+ mtf.initialize("notepad3", new ProgramModifierListener() {
+
+ @Override
+ public void modifyLatest(ProgramDB program) throws Exception {
+ boolean commit = false;
+ DataTypeManager dtm = program.getDataTypeManager();
+ int transactionID = program.startTransaction("test");
+ try {
+ FunctionDefinition fd =
+ new FunctionDefinitionDataType(new CategoryPath("/MISC"), "exit");
+ fd.setReturnType(VoidDataType.dataType);
+ fd.setNoReturn(false);
+ fd.setArguments(
+ new ParameterDefinition[] { new ParameterDefinitionImpl("rc",
+ IntegerDataType.dataType, null) });
+ dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER);
+ commit = true;
+ }
+ finally {
+ program.endTransaction(transactionID, commit);
+ }
+ }
+
+ @Override
+ public void modifyPrivate(ProgramDB program) throws Exception {
+ boolean commit = false;
+ DataTypeManager dtm = program.getDataTypeManager();
+ int transactionID = program.startTransaction("test");
+ try {
+ FunctionDefinition fd =
+ new FunctionDefinitionDataType(new CategoryPath("/MISC"), "exit");
+ fd.setReturnType(VoidDataType.dataType);
+ fd.setNoReturn(true);
+ fd.setArguments(
+ new ParameterDefinition[] { new ParameterDefinitionImpl("rc",
+ IntegerDataType.dataType, null) });
+ dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER);
+ commit = true;
+ }
+ finally {
+ program.endTransaction(transactionID, commit);
+ }
+ }
+ });
+ executeMerge(DataTypeMergeManager.OPTION_MY);
+ DataTypeManager dtm = resultProgram.getDataTypeManager();
+
+ FunctionDefinition fd1 =
+ (FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "exit");
+ assertNotNull(fd1);
+ ParameterDefinition[] vars = fd1.getArguments();
+ assertEquals(1, vars.length);
+ checkDataType(IntegerDataType.dataType, vars[0].getDataType());
+ assertEquals("rc", vars[0].getName());
+ assertEquals(null, vars[0].getComment());
+ checkDataType(VoidDataType.dataType, fd1.getReturnType());
+ assertFalse(fd1.hasNoReturn());
+
+ FunctionDefinition fd2 =
+ (FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "exit.conflict");
+ assertNotNull(fd2);
+ ParameterDefinition[] vars2 = fd2.getArguments();
+ assertEquals(1, vars2.length);
+ checkDataType(IntegerDataType.dataType, vars2[0].getDataType());
+ assertEquals("rc", vars2[0].getName());
+ assertEquals(null, vars2[0].getComment());
+ checkDataType(VoidDataType.dataType, fd2.getReturnType());
+ assertTrue(fd2.hasNoReturn());
}
}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogParsingAndPromptsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogParsingAndPromptsTest.java
new file mode 100644
index 0000000000..19a2c2916c
--- /dev/null
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogParsingAndPromptsTest.java
@@ -0,0 +1,613 @@
+/* ###
+ * 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.app.plugin.core.cparser;
+
+import static org.junit.Assert.*;
+
+import java.awt.Window;
+import java.io.File;
+import java.util.ArrayList;
+
+import javax.swing.JTextArea;
+
+import org.junit.*;
+
+import docking.action.DockingActionIf;
+import docking.widgets.combobox.GhidraComboBox;
+import docking.widgets.dialogs.InputDialog;
+import docking.widgets.filechooser.GhidraFileChooser;
+import docking.widgets.pathmanager.PathnameTablePanel;
+import generic.jar.ResourceFile;
+import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
+import ghidra.app.plugin.core.cparser.ParseDialog.ComboBoxItem;
+import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
+import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
+import ghidra.app.plugin.core.processors.SetLanguageDialog;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.plugin.importer.NewLanguagePanel;
+import ghidra.program.model.data.*;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.Program;
+import ghidra.test.*;
+import utilities.util.FileUtilities;
+
+public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegrationTest {
+
+ private static final String TITLE = "CParser Results Summary";
+
+ private TestEnv env;
+ private PluginTool tool;
+
+ private Program program;
+ private CParserPlugin plugin;
+
+ private DockingActionIf cparserAction;
+
+ private DataTypeManagerPlugin dtmPlugin;
+
+
+ @Before
+ public void setUp() throws Exception {
+ program = getNotepad();
+
+ env = new TestEnv();
+ }
+
+ private Program getNotepad() throws Exception {
+ ClassicSampleX86ProgramBuilder builder =
+ new ClassicSampleX86ProgramBuilder("notepad", false, this);
+ return builder.getProgram();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ env.dispose();
+ }
+
+ private void initTool(Program prog) throws Exception {
+ if (prog != null) {
+ tool = env.showTool(prog);
+ } else {
+ tool = env.showTool();
+ }
+
+ tool.addPlugin(CodeBrowserPlugin.class.getName());
+ tool.addPlugin(GoToAddressLabelPlugin.class.getName());
+ tool.addPlugin(CParserPlugin.class.getName());
+ tool.addPlugin(DataTypeManagerPlugin.class.getName());
+ plugin = getPlugin(tool, CParserPlugin.class);
+
+ cparserAction = getAction(plugin, CParserPlugin.PARSE_ACTION_NAME);
+ dtmPlugin = getPlugin(tool, DataTypeManagerPlugin.class);
+ }
+
+ @Test
+ public void testImportToProgramNoneOpen() throws Exception {
+ initTool(null);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("No Open Program"), "OK", false);
+
+ }
+
+ @Test
+ public void testImportToProgramNoArch() throws Exception {
+ program = getNotepad();
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "MacOSX_10.5.prf");
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ String langText = parseDialog.getLanguageText().getText();
+ assertEquals("64/32 (primarily for backward compatibility)", langText);
+
+ pressButtonByText(waitForDialogComponent("Program Architecture not Specified"), "OK", false);
+ }
+
+ @Test
+ public void testImportToProgramConfirm() throws Exception {
+ program = getNotepad();
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Cancel", false);
+ }
+
+ @Test
+ public void testImportToProgram() throws Exception {
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ // write out a dummy header file to read
+ File dummyHeader = this.createTempFile("dummy.h");
+
+ FileUtilities.deleteDir(dummyHeader);
+
+ String files[] = {dummyHeader.getPath()};
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ // dummy file empty, error
+ pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
+
+ // dummy file full, OK
+ FileUtilities.writeStringToFile(dummyHeader,
+ "typedef int wchar_t;\n" +
+ "struct mystruct {\n" +
+ " wchar_t defined_wchar_t;\n" +
+ "};\n");
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ waitForBusyTool(tool);
+
+ pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
+
+ DataType dataType = program.getDataTypeManager().getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
+
+ assertNotNull("mystruct parsed into program", dataType);
+ }
+
+ @Test
+ public void testImportToProgramWithIncludePaths() throws Exception {
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ // write out a dummy header file to read
+ File dummyHeader = this.createTempFile("dummy.h");
+
+ FileUtilities.deleteDir(dummyHeader);
+
+ String files[] = {dummyHeader.getName()};
+
+ this.setFiles(parseDialog, files);
+
+ String includePath[] = {dummyHeader.getParent()};
+
+ this.setIncludePaths(parseDialog, includePath);
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ // dummy file empty, error
+ pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
+
+ // dummy file full, OK
+ FileUtilities.writeStringToFile(dummyHeader,
+ "typedef int wchar_t;\n" +
+ "struct mystruct {\n" +
+ " wchar_t defined_wchar_t;\n" +
+ "};\n");
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ waitForBusyTool(tool);
+
+ pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
+
+ DataType dataType = program.getDataTypeManager().getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
+
+ assertNotNull("mystruct parsed into program", dataType);
+ }
+
+ @Test
+ public void testImportToProgramOpenArchives() throws Exception {
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ // open an archive
+ dtmPlugin.openDataTypeArchive("windows_vs12_64");
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Don't Use Open Archives", false);
+ }
+
+ // switch between two
+ // change, test ask save if change
+ @Test
+ public void testSetLanguage() throws Exception {
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ //
+ // test switch to new profile after changes, NO to save changes
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_64.prf");
+ }, false);
+
+ pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "No", false);
+
+
+ assertEquals("VisualStudio12_64.prf",parseDialog.getCurrentItem().getName());
+
+ //
+ // test forced save as new profile, doesn't exist
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+ }, false);
+
+ // make sure profile is gone
+ ResourceFile userProfileParent = parseDialog.getUserProfileParent();
+ File f = new File(userProfileParent.getAbsolutePath(),"MyTestProfile.prf");
+ f.delete();
+
+ pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "Yes", false);
+
+ InputDialog dialog = waitForDialogComponent(InputDialog.class);
+
+ dialog.setValue("MyTestProfile");
+ pressButtonByText(dialog, "OK");
+ waitForSwing();
+
+ assertEquals("MyTestProfile.prf",parseDialog.getCurrentItem().getName());
+
+ // test save as forced to an existing profile
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_64.prf");
+ }, false);
+
+ setLanguage(parseDialog, "x86:LE:64:default", "gcc");
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+ }, false);
+
+ pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "Yes", false);
+
+ dialog = waitForDialogComponent(InputDialog.class);
+
+ dialog.setValue("MyTestProfile");
+ pressButtonByText(dialog, "OK");
+ waitForSwing();
+
+ pressButtonByText(waitForDialogComponent("Overwrite Existing File?"), "Yes", false);
+
+ waitForSwing();
+
+ assertEquals("MyTestProfile.prf",parseDialog.getCurrentItem().getName());
+
+ // test save the current USER profile when switching
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "MyTestProfile.prf");
+ }, false);
+
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+ }, false);
+
+ pressButtonByText(waitForDialogComponent("Save Changes to Profile?"), "Yes", false);
+
+ assertEquals("VisualStudio12_32.prf",parseDialog.getCurrentItem().getName());
+
+ }
+
+ private void setLanguage(ParseDialog parseDialog, String langID, String compID) {
+ runSwing(() -> {
+ pressButton(parseDialog.getLanguageButton());
+ }, false);
+
+ SetLanguageDialog dlg = waitForDialogComponent(SetLanguageDialog.class);
+ assertNotNull(dlg);
+ NewLanguagePanel languagePanel =
+ (NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
+ assertNotNull(languagePanel);
+
+ waitForSwing();
+
+ runSwing(() -> {
+ NewLanguagePanel selectLangPanel =
+ (NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
+ selectLangPanel.setSelectedLcsPair(
+ new LanguageCompilerSpecPair(new LanguageID(langID), new CompilerSpecID(compID)));
+ }, true);
+
+ waitForSwing();
+
+ pressButtonByText(dlg, "OK");
+ }
+
+ // test parse to file, choose file
+ @Test
+ public void testImportToFile() throws Exception {
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ final File tmpDir = createTempDirectory("GDT");
+ FileUtilities.checkedMkdir(tmpDir);
+
+ // open an archive
+ // write out a dummy header file to read
+ File dummyHeader = this.createTempFile("dummy.h");
+
+ FileUtilities.deleteDir(dummyHeader);
+
+ String files[] = {dummyHeader.getName()};
+
+ this.setFiles(parseDialog, files);
+
+ String includePath[] = {dummyHeader.getParent()};
+
+ this.setIncludePaths(parseDialog, includePath);
+
+ pressButtonByText(parseDialog, "Parse to File...", false);
+
+ final GhidraFileChooser fileChooser = waitForDialogComponent(GhidraFileChooser.class);
+
+ runSwing(() -> fileChooser.setSelectedFile(new File(tmpDir, "dummy")));
+
+ waitForUpdateOnChooser(fileChooser);
+
+ pressButtonByName(fileChooser.getComponent(), "OK");
+
+ // dummy file empty, error
+ pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
+
+ // dummy file full, OK
+ FileUtilities.writeStringToFile(dummyHeader,
+ "typedef int wchar_t;\n" +
+ "struct mystruct {\n" +
+ " wchar_t defined_wchar_t;\n" +
+ "};\n");
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to File...", false);
+
+ final GhidraFileChooser existsChooser = waitForDialogComponent(GhidraFileChooser.class);
+
+ final File GDTarchiveFile = new File(tmpDir, "dummy.gdt");
+
+ runSwing(() -> existsChooser.setSelectedFile(GDTarchiveFile), true);
+
+ waitForUpdateOnChooser(existsChooser);
+
+ pressButtonByName(existsChooser.getComponent(), "OK");
+
+ pressButtonByText(waitForDialogComponent("Overwrite Existing File?"), "Yes", false);
+
+ pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
+
+ waitForBusyTool(tool);
+
+ // open the file archive
+ FileDataTypeManager fileArchive = FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
+ try {
+ DataType dataType =
+ fileArchive.getDataType("/" + dummyHeader.getName() + "/" + "mystruct");
+ assertNotNull("mystruct parsed into program", dataType);
+ }
+ finally {
+ fileArchive.close();
+ }
+ }
+
+ // test parse to file, choose file
+ @Test
+ public void testImportToFileUseArchive() throws Exception {
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ // open an archive
+ dtmPlugin.openDataTypeArchive("windows_vs12_64");
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ final File tmpDir = createTempDirectory("GDT");
+ FileUtilities.checkedMkdir(tmpDir);
+
+ // open an archive
+ // write out a dummy header file to read
+ File dummyHeader = this.createTempFile("dummy.h");
+
+ FileUtilities.deleteDir(dummyHeader);
+
+ String files[] = {dummyHeader.getName()};
+
+ String includePath[] = {dummyHeader.getParent()};
+
+ this.setIncludePaths(parseDialog, includePath);
+
+ // dummy file full, OK
+ FileUtilities.writeStringToFile(dummyHeader,
+ "typedef int wchar_t;\n" +
+ "struct mystruct {\n" +
+ " wchar_t defined_wchar_t;\n" +
+ " wint_t defined_from_windows;\n" +
+ "};\n");
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to File...", false);
+
+ final GhidraFileChooser existsChooser = waitForDialogComponent(GhidraFileChooser.class);
+
+ final File GDTarchiveFile = new File(tmpDir, "dummy.gdt");
+
+ runSwing(() -> existsChooser.setSelectedFile(GDTarchiveFile), true);
+
+ waitForUpdateOnChooser(existsChooser);
+
+ pressButtonByName(existsChooser.getComponent(), "OK");
+
+ pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Use Open Archives", false);
+
+ waitForBusyTool(tool);
+
+ pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
+
+ // open the file archive
+ FileDataTypeManager fileArchive = FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
+ try {
+ DataType dataType =
+ fileArchive.getDataType("/" + dummyHeader.getName() + "/" + "mystruct");
+
+ assertNotNull("mystruct parsed into program", dataType);
+
+ Structure struct = (Structure) dataType;
+
+ DataTypeComponent component = struct.getComponent(1);
+ assertEquals(component.getDataType().getName(), "wint_t");
+ }
+ finally {
+ fileArchive.close();
+ }
+ }
+
+
+ private void startSetLanguage(LanguageID languageID, CompilerSpecID compilerSpecID) throws Exception {
+ if (languageID == null) {
+ throw new RuntimeException("languageID == null not allowed");
+ }
+ if (compilerSpecID == null) {
+ throw new RuntimeException("compilerSpecID == null not allowed");
+ }
+
+ SetLanguageDialog dlg = waitForDialogComponent(SetLanguageDialog.class);
+ assertNotNull(dlg);
+ NewLanguagePanel languagePanel =
+ (NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
+ assertNotNull(languagePanel);
+
+ waitForSwing();
+
+ runSwing(() -> {
+ NewLanguagePanel selectLangPanel =
+ (NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
+ selectLangPanel.setSelectedLcsPair(
+ new LanguageCompilerSpecPair(languageID, compilerSpecID));
+ }, true);
+
+ waitForSwing();
+
+ pressButtonByText(dlg, "OK");
+ }
+
+ private void assertResultDialog() {
+ Window aboutDialog = waitForWindow(TITLE);
+ assertNotNull(aboutDialog);
+ pressButtonByText(aboutDialog, "OK");
+ }
+
+ private ParseDialog showParseDialog() {
+
+ //ActionContext actionContext = cbPlugin.getProvider().getActionContext(null);
+ performAction(cparserAction, false);
+ ParseDialog parseDialog = waitForDialogComponent(ParseDialog.class);
+ assertNotNull(parseDialog);
+ return parseDialog;
+ }
+
+ private void setOption(ParseDialog dialog, String options) {
+ runSwing(() -> {
+ JTextArea parseOptionsTextField = dialog.getParseOptionsTextField();
+ parseOptionsTextField.setText(options);
+ });
+ }
+
+ private void setIncludePaths(ParseDialog dialog, String paths[]) {
+ runSwing(() -> {
+ PathnameTablePanel incPaths = dialog.getIncludePaths();
+ incPaths.setPaths(paths);
+ });
+ }
+
+ private void setFiles(ParseDialog dialog, String files[]) {
+ runSwing(() -> {
+ PathnameTablePanel sourceFiles = dialog.getSourceFiles();
+ sourceFiles.setPaths(files);
+ });
+ }
+
+ private void setSelectedParseProfile(ParseDialog dialog, String profileName) {
+ runSwing(() -> {
+ GhidraComboBox parseComboBox = dialog.getParseComboBox();
+ ArrayList profiles = dialog.getProfiles();
+ int index = 0;
+ for (ComboBoxItem comboBoxItem : profiles) {
+ if (profileName.equals(comboBoxItem.getName())) {
+ parseComboBox.setSelectedIndex(index);
+ break;
+ }
+ index++;
+ }
+ });
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogTest.java
index f2d0ff3844..e3d14c13e5 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogTest.java
@@ -352,17 +352,21 @@ public class ParseDialogTest extends AbstractGhidraHeadedIntegrationTest {
BufferedReader br = new BufferedReader(new InputStreamReader(profileFile.getInputStream()));
String line = null;
- while ((line = br.readLine()) != null) {
+
+ // read paths
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
line = line.trim();
- if (line.startsWith("-") || (line.length() == 0 && buffy.length() > 0)) {
- // this is a compiler directive
- buffy.append(line + "\n");
- }
- else if (line.length() > 0) {
- File f = new File(line);
- pathList.add(f.getPath());
- }
+
+ pathList.add(line);
}
+
+ // read options
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
+ line = line.trim();
+
+ buffy.append(line + "\n");
+ }
+
paths = pathList;
defaultPrfOptions = buffy.toString();
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/AbstractCreateArchiveTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/AbstractCreateArchiveTest.java
index 35eb92c428..0c31124a99 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/AbstractCreateArchiveTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/AbstractCreateArchiveTest.java
@@ -37,10 +37,13 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.data.*;
+import ghidra.program.model.data.StandAloneDataTypeManager.LanguageUpdateOption;
+import ghidra.program.model.lang.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.InvalidNameException;
import ghidra.util.Msg;
+import ghidra.util.task.TaskMonitor;
public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedIntegrationTest {
@@ -93,6 +96,45 @@ public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedInte
waitForTree();
}
+ protected DataType resolveDataType(StandAloneDataTypeManager archiveDtm, DataType dt)
+ throws Exception {
+ int id = archiveDtm.startTransaction("resolve datatype");
+ try {
+ return archiveDtm.resolve(dt, null);
+ }
+ finally {
+ archiveDtm.endTransaction(id, true);
+ waitForTree();
+ }
+ }
+
+ protected void setArchitecture(StandAloneDataTypeManager archiveDtm, String languageId,
+ String compilerSpecId) throws Exception {
+ LanguageService languageService = getLanguageService();
+ Language language = languageService.getLanguage(new LanguageID(languageId));
+
+ int id = archiveDtm.startTransaction("set architecture");
+ try {
+ archiveDtm.setProgramArchitecture(language, new CompilerSpecID(compilerSpecId),
+ LanguageUpdateOption.CLEAR, TaskMonitor.DUMMY);
+ }
+ finally {
+ archiveDtm.endTransaction(id, true);
+ }
+ waitForTree();
+ }
+
+ protected void removeArchitecture(StandAloneDataTypeManager archiveDtm) throws Exception {
+ int id = archiveDtm.startTransaction("remove architecture");
+ try {
+ archiveDtm.clearProgramArchitecture(TaskMonitor.DUMMY);
+ }
+ finally {
+ archiveDtm.endTransaction(id, true);
+ }
+ waitForTree();
+ }
+
protected void createNewArchive(String archiveName, boolean deleteExisting) throws Exception {
File archiveFile = new File(getTestDirectoryPath(), archiveName);
if (deleteExisting && archiveFile.exists()) {
@@ -190,10 +232,12 @@ public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedInte
@After
public void tearDown() throws Exception {
- SwingUtilities.invokeLater(() -> {
- ProgramManager pm = tool.getService(ProgramManager.class);
- pm.closeProgram();
- });
+ if (tool != null) {
+ SwingUtilities.invokeLater(() -> {
+ ProgramManager pm = tool.getService(ProgramManager.class);
+ pm.closeProgram();
+ });
+ }
waitForPostedSwingRunnables();
// this handles the save changes dialog and potential analysis dialogs
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/CreateArchive1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/CreateArchive1Test.java
index cfef7d4fe3..fcfe469f5b 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/CreateArchive1Test.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/CreateArchive1Test.java
@@ -32,7 +32,9 @@ import ghidra.app.plugin.core.datamgr.archive.Archive;
import ghidra.app.plugin.core.datamgr.archive.FileArchive;
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
import ghidra.framework.GenericRunInfo;
-import ghidra.program.model.data.FileDataTypeManager;
+import ghidra.program.database.ProgramBuilder;
+import ghidra.program.model.data.*;
+import ghidra.program.model.lang.ProgramArchitecture;
import ghidra.util.Msg;
public class CreateArchive1Test extends AbstractCreateArchiveTest {
@@ -62,6 +64,10 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
createNewArchive(string + FileDataTypeManager.SUFFIX, true);
ArchiveNode archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
+ StandAloneDataTypeManager dtm =
+ (StandAloneDataTypeManager) archiveNode.getCategory().getDataTypeManager();
+ assertNull(dtm.getProgramArchitecture());
+
createCategory(archiveNode.getCategory(), "bob");
waitForTree();
@@ -79,6 +85,9 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
DataTypeTestUtils.performAction(action, tree);
waitForTree();
+ archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
+ assertNull(archiveNode);
+
archiveNode =
DataTypeTestUtils.openArchive(getTestDirectoryPath(), "MyArchive.gdt", false, plugin);
assertNotNull(archiveNode.getChild("bob"));
@@ -88,6 +97,65 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
f.deleteOnExit();
}
+ @Test
+ public void testCreateAndPopulateWithArchitecture() throws Exception {
+
+ String string = "MyArchive";
+ createNewArchive(string + FileDataTypeManager.SUFFIX, true);
+
+ ArchiveNode archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
+ StandAloneDataTypeManager dtm =
+ (StandAloneDataTypeManager) archiveNode.getCategory().getDataTypeManager();
+ assertNull(dtm.getProgramArchitecture());
+ setArchitecture(dtm, ProgramBuilder._TOY64_LE, "default");
+
+ assertEquals(8, dtm.getPointer(DataType.DEFAULT).getLength());
+
+ createCategory(archiveNode.getCategory(), "bob");
+ waitForTree();
+
+ DataType dt =
+ resolveDataType(dtm, new StructureDataType(new CategoryPath("/bob"), "MyStruct", 0));
+ dt = resolveDataType(dtm, new PointerDataType(dt));
+ assertEquals(8, dtm.getPointer(DataType.DEFAULT).getLength());
+ DataTypePath dataTypePath = dt.getDataTypePath();
+
+ tree.setSelectedNode(archiveNode);
+ waitForTree();
+
+ createCategory(archiveNode.getCategory(), "joe");
+ waitForTree();
+
+ DockingActionIf action = getAction(plugin, "Save");
+ DataTypeTestUtils.performAction(action, tree);
+ waitForTree();
+
+ action = getAction(plugin, "Close Archive");
+ DataTypeTestUtils.performAction(action, tree);
+ waitForTree();
+
+ archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
+ assertNull(archiveNode);
+
+ archiveNode =
+ DataTypeTestUtils.openArchive(getTestDirectoryPath(), "MyArchive.gdt", false, plugin);
+ assertNotNull(archiveNode.getChild("bob"));
+ assertNotNull(archiveNode.getChild("joe"));
+
+ dtm = (StandAloneDataTypeManager) archiveNode.getCategory().getDataTypeManager();
+ ProgramArchitecture arch = dtm.getProgramArchitecture();
+ assertNotNull("Expected architecture to be set", arch);
+ assertEquals(ProgramBuilder._TOY64_LE, arch.getLanguage().getLanguageID().toString());
+ assertEquals("default", arch.getCompilerSpec().getCompilerSpecID().toString());
+
+ dt = dtm.getDataType(dataTypePath);
+ assertNotNull(dt);
+ assertEquals(8, dtm.getPointer(DataType.DEFAULT).getLength());
+
+ File f = new File(getTestDirectoryPath(), "MyArchive.gdt.bak");
+ f.deleteOnExit();
+ }
+
@Test
public void testCreateArchiveNameCollision1() throws Exception {
// create archive
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeArchiveIDTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeArchiveIDTest.java
index d8176ec876..31f0436ce3 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeArchiveIDTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeArchiveIDTest.java
@@ -27,6 +27,7 @@ import generic.jar.ResourceFile;
import generic.test.AbstractGenericTest;
import ghidra.framework.Application;
import ghidra.program.model.data.*;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
public class DataTypeArchiveIDTest extends AbstractGenericTest {
@@ -68,6 +69,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
notFound.remove(path);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
+ assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try {
assertEquals("Archive UniversalID mismatch: " + path, oldID,
dtm.getUniversalID().toString());
@@ -101,6 +103,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckWindowsVS12_32() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(WIN_VS12_32_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
+ assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try {
DataType dt = dtm.getDataType("/winsock.h/fd_set");
assertNotNull(dt);
@@ -117,6 +120,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckWindowsVS12_64() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(WIN_VS12_64_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
+ assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try {
DataType dt = dtm.getDataType("/winsock.h/fd_set");
assertNotNull(dt);
@@ -132,6 +136,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckGenericCLib32() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(GENERIC_CLIB_32_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
+ assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try {
DataType dt = dtm.getDataType("/select.h/fd_set");
assertNotNull(dt);
@@ -147,6 +152,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckGenericCLib64() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(GENERIC_CLIB_64_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
+ assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try {
DataType dt = dtm.getDataType("/select.h/fd_set");
assertNotNull(dt);
@@ -162,6 +168,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckMacOS10_9() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(MAC_OS_10_9_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
+ assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try {
DataType dt = dtm.getDataType("/_fd_def.h/fd_set");
assertNotNull(dt);
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialogTest.java
index 526b1edd86..f9f6fda857 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialogTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialogTest.java
@@ -25,6 +25,7 @@ import ghidra.program.database.ProgramDB;
import ghidra.program.model.FunctionTestDouble;
import ghidra.program.model.TestDoubleFunctionSignature;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.test.*;
@@ -118,11 +119,9 @@ public class EditFunctionSignatureDialogTest extends AbstractGhidraHeadedIntegra
//==================================================================================================
private class LocalFunctionStub extends FunctionTestDouble {
- private DataType returnType;
public LocalFunctionStub(String name, String signature) {
super("Name", new LocalFunctionSignatureTestDouble(name, signature));
- this.returnType = returnType;
}
@Override
@@ -132,7 +131,7 @@ public class EditFunctionSignatureDialogTest extends AbstractGhidraHeadedIntegra
@Override
public String getCallingConventionName() {
- return GenericCallingConvention.stdcall.toString();
+ return CompilerSpec.CALLING_CONVENTION_stdcall;
}
@Override
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/datatype/DataTypeSelectionDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/datatype/DataTypeSelectionDialogTest.java
index a8102ca6a6..66923c69a8 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/datatype/DataTypeSelectionDialogTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/datatype/DataTypeSelectionDialogTest.java
@@ -1113,6 +1113,11 @@ public class DataTypeSelectionDialogTest extends AbstractGhidraHeadedIntegration
SourceArchive sourceArchive) {
// don't care for now
}
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ // don't care for now
+ }
}
private class CustomDataType extends StructureDataType {
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/CategoryTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/CategoryTest.java
index b1e40c20fd..09b223ad9d 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/CategoryTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/CategoryTest.java
@@ -908,5 +908,10 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
SourceArchive dataTypeSource) {
// don't care
}
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ // don't care
+ }
}
}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/InstanceSettingsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/InstanceSettingsTest.java
new file mode 100644
index 0000000000..6dd937cccf
--- /dev/null
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/InstanceSettingsTest.java
@@ -0,0 +1,265 @@
+/* ###
+ * 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 static org.junit.Assert.*;
+
+import org.junit.*;
+
+import ghidra.docking.settings.FormatSettingsDefinition;
+import ghidra.docking.settings.Settings;
+import ghidra.program.database.ProgramBuilder;
+import ghidra.program.database.ProgramDB;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataUtilities.ClearDataMode;
+import ghidra.program.model.listing.Data;
+import ghidra.program.model.listing.Listing;
+import ghidra.program.model.mem.Memory;
+import ghidra.test.AbstractGhidraHeadedIntegrationTest;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ *
+ * Test setting default and instance settings on Data.
+ *
+ *
+ */
+public class InstanceSettingsTest extends AbstractGhidraHeadedIntegrationTest {
+
+ // Suitable settings allowed for StringDataType data
+ private static String LONG_SETTING_NAME = "mutability";
+ private static String STRING_SETTING_NAME = "charset";
+
+ private ProgramDB program;
+ private ProgramDataTypeManager dataMgr;
+ private Listing listing;
+ private AddressSpace space;
+ private int transactionID;
+
+ public InstanceSettingsTest() {
+ super();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
+ space = program.getAddressFactory().getDefaultAddressSpace();
+ dataMgr = program.getDataTypeManager();
+ listing = program.getListing();
+ transactionID = program.startTransaction("Test");
+ addBlock();
+
+ for (int i = 0; i < 40; i++) {
+ DataUtilities.createData(program, addr(i), StringDataType.dataType, 1, false,
+ ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (program.getCurrentTransactionInfo() != null) {
+ program.endTransaction(transactionID, true);
+ }
+ program.release(this);
+ }
+
+ @Test
+ public void testInstanceSettings() throws Exception {
+
+ Data data = DataUtilities.createData(program, addr(10), ByteDataType.dataType, 1, false,
+ ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
+
+ DataType dt = data.getDataType();
+ Settings defaultSettings = dt.getDefaultSettings();
+ FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.CHAR);
+ EndianSettingsDefinition.DEF.setBigEndian(defaultSettings, false);
+ PaddingSettingsDefinition.DEF.setPadded(defaultSettings, true);
+
+ assertEquals(FormatSettingsDefinition.CHAR, data.getLong("format").longValue());
+ FormatSettingsDefinition.DEF.setChoice(data, FormatSettingsDefinition.DECIMAL);
+ assertEquals(FormatSettingsDefinition.DECIMAL, data.getLong("format").longValue());
+
+ assertEquals(EndianSettingsDefinition.LITTLE, data.getLong("endian").longValue());
+ EndianSettingsDefinition.DEF.setChoice(data, EndianSettingsDefinition.BIG);
+ assertEquals(EndianSettingsDefinition.BIG, data.getLong("endian").longValue());
+
+ assertEquals(PaddingSettingsDefinition.PADDED_VALUE, data.getLong("padded").longValue());
+ PaddingSettingsDefinition.DEF.setChoice(data, PaddingSettingsDefinition.UNPADDED_VALUE);
+ assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE, data.getLong("padded").longValue());
+
+ FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.HEX);
+ EndianSettingsDefinition.DEF.clear(defaultSettings);
+ PaddingSettingsDefinition.DEF.clear(defaultSettings);
+
+ assertEquals(FormatSettingsDefinition.DECIMAL, data.getLong("format").longValue());
+ assertEquals(EndianSettingsDefinition.BIG, data.getLong("endian").longValue());
+ assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE, data.getLong("padded").longValue());
+ }
+
+ @Test
+ public void testGetInstanceNames() throws Exception {
+ Data data = listing.getDataAt(addr(10));
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
+
+ String[] names = data.getNames();
+ assertEquals(2, names.length);
+ }
+
+ @Test
+ public void testClearInstanceSettings() throws Exception {
+ Data data = listing.getDataAt(addr(10));
+
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
+
+ data.clearSetting(STRING_SETTING_NAME);
+ assertNull(data.getString(STRING_SETTING_NAME));
+ }
+
+ @Test
+ public void testClearAllInstanceSettings() throws Exception {
+ Data data = listing.getDataAt(addr(10));
+
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
+
+ data.clearAllSettings();
+ assertNull(data.getString(STRING_SETTING_NAME));
+ assertNull(data.getLong(LONG_SETTING_NAME));
+ }
+
+ @Test
+ public void testIsEmptyInstanceSettings() throws Exception {
+ Data data = listing.getDataAt(addr(10));
+
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
+
+ assertTrue(!data.isEmpty());
+ data.clearAllSettings();
+
+ assertTrue(data.isEmpty());
+ }
+
+ @Test
+ public void testGetNames() throws Exception {
+
+ Data data = listing.getDataAt(addr(10));
+
+ data.setString(STRING_SETTING_NAME, "red");
+ data.setLong(LONG_SETTING_NAME, 10);
+
+ String[] names = data.getNames();
+ assertEquals(2, names.length);
+ }
+
+ private Data getDataAt(long offset) {
+ Data data = listing.getDataAt(addr(offset));
+ assertNotNull("expected data at address 0x" + Long.toHexString(offset));
+ return data;
+ }
+
+ @Test
+ public void testMoveSettings() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+ Data d = getDataAt(i);
+ dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
+ dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
+ }
+ dataMgr.moveAddressRange(addr(0), addr(20), 10, TaskMonitor.DUMMY);
+ int j = 0;
+ for (int i = 20; i < 30; i++, j++) {
+ Data d = getDataAt(i);
+
+ String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
+ assertEquals("red" + j, s);
+
+ Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
+ assertEquals(j, lvalue.longValue());
+ }
+ }
+
+ @Test
+ public void testMoveSettings2() {
+
+ for (int i = 0; i < 10; i++) {
+ Data d = getDataAt(i);
+ dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
+ dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
+ }
+ try {
+ dataMgr.moveAddressRange(addr(0), addr(5), 10, TaskMonitor.DUMMY);
+ }
+ catch (CancelledException e) {
+ Assert.fail("Unexpected cancelled exception");
+ }
+
+ int j = 0;
+ for (int i = 5; i < 15; i++, j++) {
+ Data d = getDataAt(i);
+
+ String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
+ assertEquals("red" + j, s);
+
+ Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
+ assertEquals(j, lvalue.longValue());
+ }
+ }
+
+ @Test
+ public void testMoveSettings3() {
+
+ int j = 20;
+ for (int i = 20; i < 30; i++, j++) {
+ Data d = getDataAt(i);
+ dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
+ dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
+ }
+ j = 20;
+ try {
+ dataMgr.moveAddressRange(addr(20), addr(5), 10, TaskMonitor.DUMMY);
+ }
+ catch (CancelledException e) {
+ Assert.fail("Unexpected cancelled exception");
+ }
+ for (int i = 5; i < 15; i++, j++) {
+ Data d = getDataAt(i);
+
+ String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
+ assertEquals("red" + j, s);
+
+ Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
+ assertEquals(j, lvalue.longValue());
+ }
+
+ }
+
+ private Address addr(long l) {
+ return space.getAddress(l);
+ }
+
+ private void addBlock() throws Exception {
+
+ Memory memory = program.getMemory();
+ memory.createInitializedBlock("test", addr(0), 100, (byte) 0,
+ TaskMonitor.DUMMY, false);
+ }
+}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java
index bd3aa5e7b0..39dc6c95d7 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java
@@ -42,8 +42,8 @@ import ghidra.util.task.TaskMonitor;
*/
public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
private ProgramDB program;
- private ProgramBasedDataTypeManager dataMgr;
private Listing listing;
+ private ProgramBasedDataTypeManager dataMgr;
private AddressSpace space;
private int transactionID;
@@ -62,11 +62,12 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
+ listing = program.getListing();
space = program.getAddressFactory().getDefaultAddressSpace();
dataMgr = program.getDataTypeManager();
- listing = program.getListing();
transactionID = program.startTransaction("Test");
addBlock();
+
// pointer-typedef has the largest
// System.out.println("Defined string settings:");
// for (SettingsDefinition def : StringDataType.dataType.getSettingsDefinitions()) {
@@ -164,8 +165,8 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testIsEmpty() throws Exception {
- Data data = listing.getDataAt(addr(10));
- Settings defaultSettings = data.getDataType().getDefaultSettings();
+ DataType dt = dataMgr.resolve(StringDataType.dataType, null);
+ Settings defaultSettings = dt.getDefaultSettings();
defaultSettings.setString(STRING_SETTING_NAME, "red");
defaultSettings.setLong(LONG_SETTING_NAME, 10);
@@ -390,7 +391,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testDefaultSettingsOnTypedef() throws Exception {
- DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
+ DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
SettingsDefinition[] settingsDefinitions = byteDT.getSettingsDefinitions();
Settings settings = byteDT.getDefaultSettings();
FormatSettingsDefinition.DEF.setChoice(settings, FormatSettingsDefinition.OCTAL);
@@ -418,7 +419,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testDefaultSettingsOnTypedef2() throws Exception {
- DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
+ DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
Settings settings = byteDT.getDefaultSettings();
TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT);
@@ -438,7 +439,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testDefaultSettingsOnTypedefUndoRedo() throws Exception {
- DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
+ DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
Settings settings = byteDT.getDefaultSettings();
settings.setLong("format", FormatSettingsDefinition.OCTAL);
endTransaction();
@@ -466,7 +467,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testDefaultSettingsOnDeletedTypdef() throws Exception {
- DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
+ DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
Settings settings = byteDT.getDefaultSettings();
settings.setLong("format", FormatSettingsDefinition.OCTAL);
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/function/FunctionManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/function/FunctionManagerTest.java
index af88484ae9..f3cec3642f 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/function/FunctionManagerTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/function/FunctionManagerTest.java
@@ -17,8 +17,8 @@ package ghidra.program.database.function;
import static org.junit.Assert.*;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import org.junit.*;
@@ -453,25 +453,12 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(defaultModel, protoModel);
}
- @Test
- public void testGetCallingConventions() throws Exception {
- PrototypeModel[] protoModels = functionManager.getCallingConventions();
- assertTrue(protoModels.length >= 1);
- }
-
@Test
public void testGetCallingConventionNames() throws Exception {
-
- List names = functionManager.getCallingConventionNames();
+ Collection names = functionManager.getCallingConventionNames();
assertTrue(names.size() >= 1);
-
for (String name : names) {
- if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
- assertNull(functionManager.getCallingConvention(name));
- }
- else {
- assertNotNull(functionManager.getCallingConvention(name));
- }
+ assertNotNull(functionManager.getCallingConvention(name));
}
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
index 3c9f2bd335..52282a5823 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
@@ -15,10 +15,7 @@
*/
package ghidra.app.util.cparser;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import java.io.InputStream;
import java.util.ArrayList;
@@ -28,30 +25,9 @@ import org.junit.Test;
import ghidra.app.util.cparser.C.CParser;
import ghidra.app.util.cparser.C.ParseException;
-import ghidra.program.model.data.Array;
-import ghidra.program.model.data.BuiltInDataType;
-import ghidra.program.model.data.CategoryPath;
-import ghidra.program.model.data.CharDataType;
-import ghidra.program.model.data.DataType;
-import ghidra.program.model.data.DataTypeComponent;
-import ghidra.program.model.data.DataTypeConflictHandler;
-import ghidra.program.model.data.DataTypeManager;
+import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
-import ghidra.program.model.data.FunctionDefinition;
-import ghidra.program.model.data.GenericCallingConvention;
-import ghidra.program.model.data.LongLongDataType;
-import ghidra.program.model.data.ParameterDefinition;
-import ghidra.program.model.data.Pointer;
-import ghidra.program.model.data.ShortDataType;
-import ghidra.program.model.data.StandAloneDataTypeManager;
-import ghidra.program.model.data.Structure;
-import ghidra.program.model.data.StructureDataType;
-import ghidra.program.model.data.TypeDef;
-import ghidra.program.model.data.TypedefDataType;
-import ghidra.program.model.data.UnsignedLongDataType;
-import ghidra.program.model.data.UnsignedLongLongDataType;
-import ghidra.program.model.data.UnsignedShortDataType;
-import ghidra.program.model.data.WideCharDataType;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
@@ -246,11 +222,11 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
String parseMessages = parser.getParseMessages();
System.out.println(parseMessages);
- assertTrue("Duplicate ENUM message", parseMessages.contains("duplicate enum value: options_enum : PLUS_SET : 16"));
+ assertTrue("Duplicate ENUM message missing", parseMessages.contains("duplicate enum value: options_enum : PLUS_SET : 16"));
- assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\""));
+ assertTrue("Duplicate ENUM message missing", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\""));
- assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\""));
+ assertTrue("Duplicate ENUM message missing", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\""));
DataType dt;
DataType pointedToDT;
@@ -285,14 +261,14 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _Once(_Once_t * , _func_anon_ * )", replaceAnonFuncName(str));
- assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
+ assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
funcArgs = funcDef.getArguments();
assertTrue("struct fstruct", funcArgs[0].getDataType() instanceof Pointer);
assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer);
pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT;
- assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
+ assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
@@ -301,12 +277,12 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
assertTrue("_Twice function definition", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString();
- assertEquals("calling convention _Twice", "__stdcall", funcDef.getGenericCallingConvention().getDeclarationName());
+ assertEquals("calling convention _Twice", "__stdcall", funcDef.getCallingConventionName());
funcArgs = funcDef.getArguments();
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT;
- assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
+ assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
@@ -315,12 +291,12 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
assertTrue("_Twice function definition", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString();
- assertEquals("calling convention _Thrice", "", funcDef.getGenericCallingConvention().getDeclarationName());
+ assertEquals("calling convention _Thrice", "unknown", funcDef.getCallingConventionName());
funcArgs = funcDef.getArguments();
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT;
- assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
+ assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
@@ -368,22 +344,34 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
dt = dtMgr.getDataType(new CategoryPath("/functions"), "stdcall_func");
assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
- assertTrue("Callee should not purge", ((FunctionDefinition) dt)
- .getGenericCallingConvention() == GenericCallingConvention.stdcall);
+ assertTrue("Callee should not purge", CompilerSpec.CALLING_CONVENTION_stdcall
+ .equals(((FunctionDefinition) dt).getCallingConventionName()));
assertTrue("signature not correct", str.equals("int stdcall_func(int b)"));
dt = dtMgr.getDataType(new CategoryPath("/functions"), "cdecl_func");
assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
- assertTrue("Caller should purge", ((FunctionDefinition) dt)
- .getGenericCallingConvention() != GenericCallingConvention.stdcall);
+ assertTrue("Caller should purge", CompilerSpec.CALLING_CONVENTION_cdecl
+ .equals(((FunctionDefinition) dt).getCallingConventionName()));
assertTrue("signature not correct", str.equals("int cdecl_func(int a)"));
dt = dtMgr.getDataType(new CategoryPath("/functions"), "cdecl_func_after");
assertTrue("not a function", dt instanceof FunctionDefinition);
- assertTrue("Caller should purge", ((FunctionDefinition) dt)
- .getGenericCallingConvention() != GenericCallingConvention.stdcall);
+ assertTrue("Caller should purge", CompilerSpec.CALLING_CONVENTION_cdecl
+ .equals(((FunctionDefinition) dt).getCallingConventionName()));
+ dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Noreturn_exit");
+ assertTrue("not a function", dt instanceof FunctionDefinition);
+ assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
+
+ dt = dtMgr.getDataType(new CategoryPath("/functions"), "win_exit");
+ assertTrue("not a function", dt instanceof FunctionDefinition);
+ assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
+
+ dt = dtMgr.getDataType(new CategoryPath("/functions"), "gcc_exit");
+ assertTrue("not a function", dt instanceof FunctionDefinition);
+ assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
+
dt = dtMgr.getDataType(new CategoryPath("/"), "UINT2");
assertTrue(dt instanceof TypeDef);
assertEquals("ushort", ((TypeDef) dt).getBaseDataType().getName());
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java
index 1b77911757..938d53d520 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java
@@ -48,8 +48,11 @@ public class PreProcessorTest extends AbstractGenericTest {
super();
}
- @BeforeClass
- public static void init() {
+ @Before
+ public void init() {
+ if (dtMgr != null) {
+ return; // do only once - but not too soon
+ }
URL url = PreProcessorTest.class.getResource(resourceName);
String[] args = new String[] { "-I" + url.getPath() + "/..", "-DFROM_ARG_VALUE=300",
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/AbstractCompositeTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/AbstractCompositeTest.java
index f203f1e15a..5939c6b36b 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/AbstractCompositeTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/AbstractCompositeTest.java
@@ -20,13 +20,13 @@ import static org.junit.Assert.*;
import java.io.*;
import java.util.HashMap;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.app.util.cparser.C.CParser;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.util.Msg;
import resources.ResourceManager;
-abstract class AbstractCompositeTest extends AbstractGTest {
+abstract class AbstractCompositeTest extends AbstractGenericTest {
private HashMap copyMap = new HashMap<>();
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/StructureDataTypeTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/StructureDataTypeTest.java
index 5a60944385..b6a2032a1e 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/StructureDataTypeTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/StructureDataTypeTest.java
@@ -22,12 +22,12 @@ import java.util.List;
import org.apache.commons.compress.utils.Sets;
import org.junit.*;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
/**
*
*/
-public class StructureDataTypeTest extends AbstractGTest {
+public class StructureDataTypeTest extends AbstractGenericTest {
private Structure struct;
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/UnionDataTypeTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/UnionDataTypeTest.java
index ddfbe019c8..e31e986100 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/UnionDataTypeTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/UnionDataTypeTest.java
@@ -21,12 +21,12 @@ import org.junit.*;
import com.google.common.collect.Sets;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
/**
*
*/
-public class UnionDataTypeTest extends AbstractGTest {
+public class UnionDataTypeTest extends AbstractGenericTest {
private Union union;
diff --git a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
index c26101d2d1..6dd802956c 100644
--- a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
+++ b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
@@ -378,12 +378,18 @@ int fputs( char * , void * ) __asm("_" "fputs" "$FPOOTS");
void _exit(int) __attribute__((noreturn));
+// NoReturn
+
+extern void gcc_exit (int __status) __attribute__ ((__noreturn__));
+
+__declspec(noreturn) void __cdecl win_exit(int _Code);
+
+void _exit(int) __attribute__((noreturn));
+
// C11 noreturn
void _Noreturn _Noreturn_exit(int);
-
-
// C23 Attributes
int [[deprecated]] imDeprecated(int);
int [[gnu::deprecated]] imDeprecatedToo(int) ;
diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java
index d513aacc11..1ab51f942c 100644
--- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java
+++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java
@@ -8187,7 +8187,7 @@ public class RecoveredClassHelper {
if ((DataTypeUtilities.equalsIgnoreConflict(signature.getName(), definition.getName())) &&
DataTypeUtilities.isSameOrEquivalentDataType(definition.getReturnType(),
signature.getReturnType()) &&
- (definition.getGenericCallingConvention() == signature.getGenericCallingConvention()) &&
+ signature.getCallingConventionName().equals(definition.getCallingConventionName()) &&
(definition.hasVarArgs() == signature.hasVarArgs())) {
ParameterDefinition[] sigargs = signature.getArguments();
ParameterDefinition[] defArgs = definition.getArguments();
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DeletePrototypeOverrideAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DeletePrototypeOverrideAction.java
index 1c5ef22bb2..b8d5483354 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DeletePrototypeOverrideAction.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/DeletePrototypeOverrideAction.java
@@ -20,12 +20,14 @@ import ghidra.app.decompiler.ClangToken;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.util.HelpTopics;
import ghidra.program.database.symbol.CodeSymbol;
+import ghidra.program.model.data.ProgramBasedDataTypeManager;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.symbol.*;
-import ghidra.util.*;
+import ghidra.util.HelpLocation;
+import ghidra.util.UndefinedFunction;
public class DeletePrototypeOverrideAction extends AbstractDecompilerAction {
@@ -84,14 +86,13 @@ public class DeletePrototypeOverrideAction extends AbstractDecompilerAction {
CodeSymbol sym = getSymbol(func, context.getTokenAtCursor());
Program program = func.getProgram();
SymbolTable symtab = program.getSymbolTable();
- int transaction = program.startTransaction("Remove Override Signature");
- boolean commit = true;
- if (!symtab.removeSymbolSpecial(sym)) {
- commit = false;
- Msg.showError(getClass(), context.getDecompilerPanel(),
- "Removing Override Signature Failed", "Error removing override signature");
+ ProgramBasedDataTypeManager dtm = program.getDataTypeManager();
+ int txId = program.startTransaction("Remove Override Signature");
+ try {
+ symtab.removeSymbolSpecial(sym);
+ }
+ finally {
+ program.endTransaction(txId, true);
}
- program.endTransaction(transaction, commit);
-
}
}
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java
index 2c22a7f3e3..826133f6f9 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java
@@ -32,6 +32,7 @@ import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.InvalidInputException;
public class OverridePrototypeAction extends AbstractDecompilerAction {
@@ -220,7 +221,13 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
}
PcodeOp callOp = getCallOp(context.getProgram(), context.getTokenAtCursor());
- return callOp != null;
+ if (callOp == null) {
+ return false;
+ }
+
+ // don't enable if override already in place
+ return DeletePrototypeOverrideAction.getSymbol(context.getFunction(),
+ context.getTokenAtCursor()) == null;
}
@Override
@@ -295,7 +302,7 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
* @param conv initial calling convention
*/
public ProtoOverrideDialog(PluginTool tool, Function func, String signature, String conv) {
- super(tool, "Override Signature", func, false, false, false);
+ super(tool, "Override Signature", func, false, true, false);
setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ActionOverrideSignature"));
this.initialSignature = signature;
this.initialConvention = conv;
@@ -331,9 +338,15 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
return false;
}
- GenericCallingConvention convention =
- GenericCallingConvention.guessFromName(getCallingConvention());
- functionDefinition.setGenericCallingConvention(convention);
+ functionDefinition.setNoReturn(hasNoReturnSelected());
+
+ try {
+ functionDefinition.setCallingConvention(getCallingConvention());
+ }
+ catch (InvalidInputException e) {
+ // should not occur since dialog restricts calling convention choice
+ }
+
return true;
}
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SpecifyCPrototypeAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SpecifyCPrototypeAction.java
index d825ac8516..294f5ed8d1 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SpecifyCPrototypeAction.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SpecifyCPrototypeAction.java
@@ -47,6 +47,8 @@ public class SpecifyCPrototypeAction extends AbstractDecompilerAction {
*/
private void verifyDynamicEditorModel(HighFunction hf, FunctionEditorModel model) {
+ // TODO: devise alternative approach - bad practice to manipulate model in this fashion
+
FunctionPrototype functionPrototype = hf.getFunctionPrototype();
int decompParamCnt = functionPrototype.getNumParams();
@@ -125,6 +127,7 @@ public class SpecifyCPrototypeAction extends AbstractDecompilerAction {
}
fsig.setArguments(args);
fsig.setVarArgs(functionPrototype.isVarArg());
+ fsig.setNoReturn(functionPrototype.hasNoReturn());
return fsig;
}
diff --git a/Ghidra/Features/DecompilerDependent/src/test/java/ghidra/app/plugin/core/string/variadic/FormatStringParserTest.java b/Ghidra/Features/DecompilerDependent/src/test/java/ghidra/app/plugin/core/string/variadic/FormatStringParserTest.java
index a2ce29af66..aff7b2564c 100644
--- a/Ghidra/Features/DecompilerDependent/src/test/java/ghidra/app/plugin/core/string/variadic/FormatStringParserTest.java
+++ b/Ghidra/Features/DecompilerDependent/src/test/java/ghidra/app/plugin/core/string/variadic/FormatStringParserTest.java
@@ -23,8 +23,7 @@ import org.junit.Before;
import org.junit.Test;
import generic.test.AbstractGenericTest;
-import ghidra.program.database.ProgramBuilder;
-import ghidra.program.database.ProgramDB;
+import ghidra.program.database.*;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.data.*;
diff --git a/Ghidra/Features/FileFormats/ghidra_scripts/UpgradeDexToGhidra71Script.java b/Ghidra/Features/FileFormats/ghidra_scripts/UpgradeDexToGhidra71Script.java
index 39aa3e33ba..121c255e2b 100644
--- a/Ghidra/Features/FileFormats/ghidra_scripts/UpgradeDexToGhidra71Script.java
+++ b/Ghidra/Features/FileFormats/ghidra_scripts/UpgradeDexToGhidra71Script.java
@@ -24,9 +24,7 @@ import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.FunctionDefinitionDataType;
-import ghidra.program.model.data.GenericCallingConvention;
-import ghidra.program.model.lang.Language;
-import ghidra.program.model.lang.Register;
+import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.SourceType;
@@ -114,7 +112,12 @@ public class UpgradeDexToGhidra71Script extends GhidraScript {
private void processFunction(Function func) {
monitor.setMessage("Updating: "+func.getName());
FunctionDefinitionDataType sig = new FunctionDefinitionDataType(func,false);
- sig.setGenericCallingConvention(GenericCallingConvention.stdcall);
+ try {
+ sig.setCallingConvention(CompilerSpec.CALLING_CONVENTION_stdcall);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertException(e);
+ }
func.setCustomVariableStorage(false);
ApplyFunctionSignatureCmd cmd = new ApplyFunctionSignatureCmd(func.getEntryPoint(),sig,SourceType.ANALYSIS);
cmd.applyTo(func.getProgram());
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java
index 6952549667..c423356045 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java
@@ -20,8 +20,11 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention;
-import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.FunctionDefinitionDataType;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.InvalidInputException;
/**
* Applier for certain function types.
@@ -226,9 +229,9 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
private void setCallingConvention(DefaultPdbApplicator applicator,
CallingConvention callingConvention, boolean hasThisPointer) {
- GenericCallingConvention convention;
+ String convention;
if (hasThisPointer) {
- convention = GenericCallingConvention.thiscall;
+ convention = CompilerSpec.CALLING_CONVENTION_thiscall;
}
else {
// Since we are a member function, we will always assume a _thiscall...
@@ -236,24 +239,30 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
switch (callingConvention) {
// TODO: figure all of these out.
case THISCALL: // "this" passed in register (we have not yet seen this)
- convention = GenericCallingConvention.thiscall; // Is this correct if in reg?
+ convention = CompilerSpec.CALLING_CONVENTION_thiscall; // Is this correct if in reg?
break;
case NEAR_C: // we have seen this one
- convention = GenericCallingConvention.cdecl;
+ convention = CompilerSpec.CALLING_CONVENTION_cdecl;
break;
case NEAR_VECTOR: // we have seen this one
- convention = GenericCallingConvention.vectorcall;
+ convention = CompilerSpec.CALLING_CONVENTION_vectorcall;
break;
default:
// applicator.getLog().appendMsg(
// "TODO: calling convention not implemented for value " + callingConventionVal +
// " in " + funcName);
//convention = GenericCallingConvention.cdecl;
- convention = GenericCallingConvention.cdecl;
+ convention = CompilerSpec.CALLING_CONVENTION_cdecl;
break;
}
}
- functionDefinition.setGenericCallingConvention(convention);
+ try {
+ functionDefinition.setCallingConvention(convention);
+ }
+ catch (InvalidInputException e) {
+ applicator.appendLogMsg("Failed to set calling convention `" + convention + "` for " +
+ functionDefinition.getName());
+ }
}
}
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java
index 0f4af41818..7dd3b66408 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java
@@ -25,8 +25,10 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import mdemangler.*;
import mdemangler.object.MDObjectCPP;
@@ -498,7 +500,7 @@ public class PdbResearch {
//==============================================================================================
//==============================================================================================
static void studyDataTypeConflicts(DefaultPdbApplicator applicator, TaskMonitor monitor)
- throws CancelledException {
+ throws CancelledException, InvalidInputException {
DataTypeConflictHandler handler =
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER;
DataTypeManager dtm = applicator.getDataTypeManager();
@@ -510,7 +512,7 @@ public class PdbResearch {
FunctionDefinitionDataType fn1 =
new FunctionDefinitionDataType(CategoryPath.ROOT, "____fn1____", dtm);
fn1.setReturnType(pointer1);
- fn1.setGenericCallingConvention(GenericCallingConvention.cdecl);
+ fn1.setCallingConvention(CompilerSpec.CALLING_CONVENTION_cdecl);
fn1.setArguments(new ParameterDefinition[0]);
Composite internalStruct1 = createComposite(dtm, "____internal____");
@@ -526,7 +528,7 @@ public class PdbResearch {
FunctionDefinitionDataType fn2 =
new FunctionDefinitionDataType(CategoryPath.ROOT, "____fn2____", dtm);
fn2.setReturnType(pointer2);
- fn2.setGenericCallingConvention(GenericCallingConvention.cdecl);
+ fn2.setCallingConvention(CompilerSpec.CALLING_CONVENTION_cdecl);
fn2.setArguments(new ParameterDefinition[0]);
Composite internalStruct2 = createComposite(dtm, "____internal____");
diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java
index 7789e04139..6dd99d64e6 100644
--- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java
+++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java
@@ -25,6 +25,7 @@ import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
@@ -66,7 +67,7 @@ public class ConflictHandlerTest2 extends AbstractGhidraHeadedIntegrationTest {
}
@Test
- public void testDataTypeConflicts() {
+ public void testDataTypeConflicts() throws Exception {
DataTypeConflictHandler handler =
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER;
@@ -77,7 +78,7 @@ public class ConflictHandlerTest2 extends AbstractGhidraHeadedIntegrationTest {
FunctionDefinitionDataType fn1 =
new FunctionDefinitionDataType(CategoryPath.ROOT, "fn1", dtm);
fn1.setReturnType(pointer1);
- fn1.setGenericCallingConvention(GenericCallingConvention.cdecl);
+ fn1.setCallingConvention(CompilerSpec.CALLING_CONVENTION_cdecl);
fn1.setArguments(new ParameterDefinition[0]);
Composite internalStruct1 = createComposite(dtm, "inner");
@@ -93,7 +94,7 @@ public class ConflictHandlerTest2 extends AbstractGhidraHeadedIntegrationTest {
FunctionDefinitionDataType fn2 =
new FunctionDefinitionDataType(CategoryPath.ROOT, "fn2", dtm);
fn2.setReturnType(pointer2);
- fn2.setGenericCallingConvention(GenericCallingConvention.cdecl);
+ fn2.setCallingConvention(CompilerSpec.CALLING_CONVENTION_cdecl);
fn2.setArguments(new ParameterDefinition[0]);
Composite internalStruct2 = createComposite(dtm, "inner");
diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/stringable/FunctionSignatureStringable.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/stringable/FunctionSignatureStringable.java
index cd69c3a8f0..3ce13bbc51 100644
--- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/stringable/FunctionSignatureStringable.java
+++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/stringable/FunctionSignatureStringable.java
@@ -85,9 +85,7 @@ public class FunctionSignatureStringable extends Stringable {
this.signatureSource = function.getSignatureSource();
this.hasCustomStorage = function.hasCustomVariableStorage();
- GenericCallingConvention guessedCallingConvention =
- GenericCallingConvention.guessFromName(function.getCallingConventionName());
- isThisCall = (guessedCallingConvention == GenericCallingConvention.thiscall);
+ isThisCall = CompilerSpec.CALLING_CONVENTION_thiscall.equals(callingConventionName);
// ignore source from function return which is same as signature source
returnInfo = getParameterInfo(function.getReturn(), SourceType.DEFAULT);
@@ -531,7 +529,7 @@ public class FunctionSignatureStringable extends Stringable {
if (hasCustomStorage != toFunction.hasCustomVariableStorage()) {
// This should only change to use custom storage if same language.
boolean sameLanguage =
- FunctionUtility.isSameLanguage(toFunction.getProgram(), program);
+ FunctionUtility.isSameLanguageAndCompilerSpec(toFunction.getProgram(), program);
if (!hasCustomStorage || (hasCustomStorage && sameLanguage)) {
useCustomStorage = hasCustomStorage;
}
@@ -673,7 +671,7 @@ public class FunctionSignatureStringable extends Stringable {
}
if (callFixupChoice == ReplaceChoices.REPLACE) {
// Check that you have the same cspec before trying to apply call fixup.
- if (FunctionUtility.isSameLanguage(toFunction.getProgram(), program)) {
+ if (FunctionUtility.isSameLanguageAndCompilerSpec(toFunction.getProgram(), program)) {
toFunction.setCallFixup(fromFunctionCallFixup);
}
}
@@ -692,7 +690,7 @@ public class FunctionSignatureStringable extends Stringable {
switch (callingConventionChoice) {
case SAME_LANGUAGE:
- if (FunctionUtility.isSameLanguage(program, toProgram)) {
+ if (FunctionUtility.isSameLanguageAndCompilerSpec(program, toProgram)) {
return callingConventionName;
}
break;
diff --git a/Ghidra/Framework/DB/src/main/java/db/DBHandle.java b/Ghidra/Framework/DB/src/main/java/db/DBHandle.java
index c3d9299e4e..98909d6ee4 100644
--- a/Ghidra/Framework/DB/src/main/java/db/DBHandle.java
+++ b/Ghidra/Framework/DB/src/main/java/db/DBHandle.java
@@ -1055,7 +1055,7 @@ public class DBHandle {
Table table;
synchronized (this) {
if (tables.containsKey(name)) {
- throw new IOException("Table already exists");
+ throw new IOException("Table already exists: " + name);
}
checkTransaction();
table = new Table(this, masterTable.createTableRecord(name, schema, -1));
@@ -1084,7 +1084,7 @@ public class DBHandle {
}
checkTransaction();
if (tables.containsKey(newName)) {
- throw new DuplicateNameException("Table already exists");
+ throw new DuplicateNameException("Table already exists: " + newName);
}
Table table = tables.remove(oldName);
if (table == null) {
diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/xml/SpecXmlUtils.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/xml/SpecXmlUtils.java
index fadf2b4786..58d7b92187 100644
--- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/xml/SpecXmlUtils.java
+++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/xml/SpecXmlUtils.java
@@ -64,6 +64,14 @@ public class SpecXmlUtils {
return false;
}
+ static public boolean decodeBoolean(String val, boolean defaultValue) {
+ Boolean returnValue = decodeNullableBoolean(val);
+ if (returnValue != null) {
+ return returnValue;
+ }
+ return defaultValue;
+ }
+
static public String encodeBoolean(boolean val) {
return val ? "true" : "false";
}
diff --git a/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg b/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg
index ade4ca69e3..7ab59e71a6 100644
--- a/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg
+++ b/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg
@@ -345,11 +345,6 @@
-
-
-
-
-
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java
index 6648157c64..5806c3cf89 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java
@@ -23,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);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
index 80cfeb8140..17d754799e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java
@@ -36,7 +36,6 @@ import ghidra.program.database.code.InstructionDB;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.database.external.ExternalManagerDB;
import ghidra.program.database.function.FunctionManagerDB;
-import ghidra.program.database.map.AddressMap;
import ghidra.program.database.map.AddressMapDB;
import ghidra.program.database.mem.MemoryMapDB;
import ghidra.program.database.module.TreeManager;
@@ -745,13 +744,13 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
/**
* Returns this programs address map.
- * NOTE: This method has been dropped from the Program interface to help
- * discourage the use of the program's address map since bad assumptions
+ * NOTE: This method should be dropped from the {@link Program} interface to help
+ * discourage the its use external to this implementation since bad assumptions
* are frequently made about address keys which may not be ordered or sequential
* across an entire address space.
*/
@Override
- public AddressMap getAddressMap() {
+ public AddressMapDB getAddressMap() {
return addrMap;
}
@@ -1678,7 +1677,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
monitor.checkCanceled();
try {
- managers[SYMBOL_MGR] = new SymbolManager(dbh, addrMap, openMode, lock, monitor);
+ managers[SYMBOL_MGR] = new SymbolManager(dbh, addrMap, openMode, this, lock, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
@@ -2069,6 +2068,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
contextMgr.initializeDefaultValues(language, compilerSpec);
}
+ // Update datatype manager data organization
+ getDataTypeManager().languageChanged(monitor);
+
// Force function manager to reconcile calling conventions
managers[FUNCTION_MGR].setProgram(this);
managers[FUNCTION_MGR].programReady(UPDATE, getStoredVersion(), monitor);
@@ -2443,6 +2445,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
lock.acquire();
try {
((ProgramCompilerSpec) compilerSpec).installExtensions();
+ getFunctionManager().invalidateCache(true);
+ getDataTypeManager().invalidateCache();
}
finally {
lock.release();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProjectDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java
similarity index 76%
rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProjectDataTypeManager.java
rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java
index 41b4f5b6fd..abace47dc5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProjectDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java
@@ -13,17 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.program.database.data;
+package ghidra.program.database;
import java.io.IOException;
-import java.util.Iterator;
import java.util.LinkedList;
+import javax.help.UnsupportedOperationException;
+
import db.*;
import db.util.ErrorHandler;
import ghidra.framework.model.DomainFile;
-import ghidra.program.database.DataTypeArchiveDB;
+import ghidra.framework.store.LockException;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.util.DataTypeArchiveChangeManager;
import ghidra.util.InvalidNameException;
import ghidra.util.Lock;
@@ -35,13 +38,23 @@ import ghidra.util.task.TaskMonitor;
* Class for managing data types in a project archive
* NOTE: default data organization is used.
*/
-public class ProjectDataTypeManager extends DataTypeManagerDB
+public class ProjectDataTypeManager extends StandAloneDataTypeManager
implements ProjectArchiveBasedDataTypeManager {
- private DataTypeArchiveDB dataTypeArchive;
+ private final DataTypeArchiveDB dataTypeArchive;
/**
- * Constructor
+ * Constructor for a data-type manager using a specified DBHandle.
+ *
+ * NOTE: If archive has an assigned architecture, issues may arise due to a revised or
+ * missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
+ * prevent the archive from being opened. Such a warning condition will ne logged and may
+ * result in missing or stale information for existing datatypes which have architecture related
+ * data. In some case it may be appropriate to
+ * {@link FileDataTypeManager#getWarning() check for warnings} on the returned archive
+ * object prior to its use.
+ *
+ * @param dataTypeArchive associated archive
* @param handle open database handle
* @param openMode the program open mode
* @param errHandler the database I/O error handler
@@ -51,17 +64,12 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
* @throws VersionException if the database does not match the expected version.
* @throws IOException if a database I/O error occurs.
*/
- public ProjectDataTypeManager(DBHandle handle, int openMode, ErrorHandler errHandler, Lock lock,
+ ProjectDataTypeManager(DataTypeArchiveDB dataTypeArchive, DBHandle handle, int openMode,
+ ErrorHandler errHandler, Lock lock,
TaskMonitor monitor) throws CancelledException, VersionException, IOException {
- super(handle, null, openMode, errHandler, lock, monitor);
- }
-
- /**
- * Set the associated Archive
- * @param dtArchive associated archive
- */
- public void setDataTypeArchive(DataTypeArchiveDB dtArchive) {
- this.dataTypeArchive = dtArchive;
+ super(handle, openMode, errHandler, lock, monitor);
+ this.dataTypeArchive = dataTypeArchive;
+ reportWarning();
}
@Override
@@ -69,11 +77,6 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
return dataTypeArchive.getDomainFile().getName();
}
- @Override
- public Pointer getPointer(DataType dt) {
- return PointerDataType.getPointer(dt, dataTypeArchive.getDefaultPointerSize());
- }
-
@Override
public void setName(String name) throws InvalidNameException {
if (name == null || name.length() == 0) {
@@ -84,6 +87,23 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
categoryRenamed(CategoryPath.ROOT, null);
}
+ @Override
+ public void clearProgramArchitecture(TaskMonitor monitor)
+ throws CancelledException, IOException, LockException {
+ dataTypeArchive.checkExclusiveAccess();
+ super.clearProgramArchitecture(monitor);
+ }
+
+ @Override
+ public void setProgramArchitecture(Language language, CompilerSpecID compilerSpecId,
+ LanguageUpdateOption updateOption, TaskMonitor monitor)
+ throws CompilerSpecNotFoundException, LanguageNotFoundException, IOException,
+ LockException, UnsupportedOperationException, IncompatibleLanguageException,
+ CancelledException {
+ dataTypeArchive.checkExclusiveAccess();
+ super.setProgramArchitecture(language, compilerSpecId, updateOption, monitor);
+ }
+
////////////////////
@Override
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
@@ -169,21 +189,12 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
///////////////////
@Override
protected void replaceDataTypeIDs(long oldDataTypeID, long newDataTypeID) {
-// dataTypeArchive.getCodeManager().replace(oldID, newID, monitor);
- // TODO
+ // do nothing
}
@Override
- protected void deleteDataTypeIDs(LinkedList deletedIds, TaskMonitor monitor)
- throws CancelledException {
- long[] ids = new long[deletedIds.size()];
- Iterator it = deletedIds.iterator();
- int i = 0;
- while (it.hasNext()) {
- ids[i++] = it.next().longValue();
- }
-// dataTypeArchive.getCodeManager().clearData(ids, monitor);
- // TODO
+ protected void deleteDataTypeIDs(LinkedList deletedIds, TaskMonitor monitor) {
+ // do nothing
}
@Override
@@ -191,6 +202,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
return dataTypeArchive.openTransaction(description);
}
+ @SuppressWarnings("sync-override")
@Override
public int startTransaction(String description) {
return dataTypeArchive.startTransaction(description);
@@ -201,6 +213,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
dataTypeArchive.flushEvents();
}
+ @SuppressWarnings("sync-override")
@Override
public void endTransaction(int transactionID, boolean commit) {
dataTypeArchive.endTransaction(transactionID, commit);
@@ -231,7 +244,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
public void archiveReady(int openMode, TaskMonitor monitor)
throws IOException, CancelledException {
if (openMode == DBConstants.UPGRADE) {
- doSourceArchiveUpdates(null, monitor);
+ doSourceArchiveUpdates(monitor);
migrateOldFlexArrayComponentsIfRequired(monitor);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java
index 01372bef38..cab9d93887 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java
@@ -721,7 +721,7 @@ public class SpecExtension {
PrototypeModel currentModel = function.getCallingConvention();
if (currentModel != null && currentModel.getName().equals(modelName)) {
try {
- function.setCallingConvention("unknown");
+ function.setCallingConvention(Function.UNKNOWN_CALLING_CONVENTION_STRING);
}
catch (InvalidInputException e) {
// shouldn't reach here
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java
index 270e02355b..3d41a57d4f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java
@@ -47,6 +47,7 @@ class DataDB extends CodeUnitDB implements Data {
protected DataType baseDataType;
protected int level = 0;
+
protected ProgramDataTypeManager dataMgr;
private Boolean hasMutabilitySetting;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapter.java
index ba42612d9e..af5ed4b49e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapter.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -33,13 +34,25 @@ abstract class ArrayDBAdapter {
static final int ARRAY_ELEMENT_LENGTH_COL = ArrayDBAdapterV1.V1_ARRAY_ELEMENT_LENGTH_COL;
static final int ARRAY_CAT_COL = ArrayDBAdapterV1.V1_ARRAY_CAT_COL;
- static ArrayDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ /**
+ * Gets an adapter for working with the {@link ArrayDB} database table.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
+ * @return adapter instance
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is a problem accessing the database.
+ * @throws CancelledException task cancelled
+ */
+ static ArrayDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new ArrayDBAdapterV1(handle, true);
+ return new ArrayDBAdapterV1(handle, tablePrefix, true);
}
try {
- return new ArrayDBAdapterV1(handle, false);
+ return new ArrayDBAdapterV1(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -47,33 +60,36 @@ abstract class ArrayDBAdapter {
}
ArrayDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
}
- static ArrayDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
+ private static ArrayDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
return new ArrayDBAdapterV0(handle);
}
- static ArrayDBAdapter upgrade(DBHandle handle, ArrayDBAdapter oldAdapter)
- throws VersionException, IOException {
+ private static ArrayDBAdapter upgrade(DBHandle handle, ArrayDBAdapter oldAdapter,
+ String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
ArrayDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new ArrayDBAdapterV1(tmpHandle, true);
+ tmpAdapter = new ArrayDBAdapterV1(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- ArrayDBAdapterV1 newAdapter = new ArrayDBAdapterV1(handle, true);
+ ArrayDBAdapterV1 newAdapter = new ArrayDBAdapterV1(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV0.java
index 8e6c3e10e5..3ef1f94bc5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV0.java
@@ -24,13 +24,14 @@ import ghidra.util.exception.VersionException;
*
*/
class ArrayDBAdapterV0 extends ArrayDBAdapter {
+
+ private static final int VERSION = 0;
+
private static final String ARRAY_TABLE_NAME = "Arrays";
private static final int V0_ARRAY_DT_ID_COL = 0;
private static final int V0_ARRAY_DIM_COL = 1;
private static final int V0_ARRAY_ELEMENT_LENGTH_COL = 2; // applies to sizable dynamic types only
- private Table table;
-
// DO NOT REMOVE - this documents the schema used in version 0.
// public static final Schema SCHEMA = new Schema(0, "Array ID",
// new Class[] {LongField.class, IntField.class,
@@ -38,9 +39,13 @@ class ArrayDBAdapterV0 extends ArrayDBAdapter {
// new String[] {"Data Type ID", "Dimension",
// "Length"});
+ private Table table;
+
/**
- * Constructor
- *
+ * Gets a version 0 read-only adapter for the {@link ArrayDB} database table.
+ * @param handle handle to the database containing the table.
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
*/
public ArrayDBAdapterV0(DBHandle handle) throws VersionException {
@@ -48,9 +53,8 @@ class ArrayDBAdapterV0 extends ArrayDBAdapter {
if (table == null) {
throw new VersionException("Missing Table: " + ARRAY_TABLE_NAME);
}
- else if (table.getSchema().getVersion() != 0) {
- throw new VersionException("Expected version 0 for table " + ARRAY_TABLE_NAME +
- " but got " + table.getSchema().getVersion());
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException();
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV1.java
index c1ec6c3779..938f736c9c 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDBAdapterV1.java
@@ -25,40 +25,49 @@ import ghidra.util.exception.VersionException;
* To change the template for this generated type comment go to
* {@literal Window>Preferences>Java>Code Generation>Code and Comments}
*
- *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class ArrayDBAdapterV1 extends ArrayDBAdapter {
+
static final int VERSION = 1;
+
static final String ARRAY_TABLE_NAME = "Arrays";
static final int V1_ARRAY_DT_ID_COL = 0;
static final int V1_ARRAY_DIM_COL = 1;
static final int V1_ARRAY_ELEMENT_LENGTH_COL = 2; // applies to sizable dynamic types only
static final int V1_ARRAY_CAT_COL = 3;
- private Table table;
-
public static final Schema V1_SCHEMA =
new Schema(VERSION, "Array ID",
new Field[] { LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE,
LongField.INSTANCE },
new String[] { "Data Type ID", "Dimension", "Length", "Cat ID" });
- /**
- * Constructor
- *
- */
- public ArrayDBAdapterV1(DBHandle handle, boolean create) throws VersionException, IOException {
+ private Table table;
+ /**
+ * Gets a version 1 adapter for the {@link ArrayDB} database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create create table if true else acquire for read-only or update use
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
+ * @throws IOException an IO error occured during table creation
+ */
+ public ArrayDBAdapterV1(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + ARRAY_TABLE_NAME;
if (create) {
- table = handle.createTable(ARRAY_TABLE_NAME, V1_SCHEMA, new int[] { V1_ARRAY_CAT_COL });
+ table = handle.createTable(tableName, V1_SCHEMA, new int[] { V1_ARRAY_CAT_COL });
}
else {
- table = handle.getTable(ARRAY_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + ARRAY_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- else if (table.getSchema().getVersion() != VERSION) {
- throw new VersionException(VersionException.NEWER_VERSION, false);
+ int version = table.getSchema().getVersion();
+ if (version != VERSION) {
+ throw new VersionException(version < VERSION);
}
}
}
@@ -67,11 +76,7 @@ class ArrayDBAdapterV1 extends ArrayDBAdapter {
public DBRecord createRecord(long dataTypeID, int numberOfElements, int length, long catID)
throws IOException {
- long tableKey = table.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.ARRAY, tableKey);
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.ARRAY, table.getKey());
DBRecord record = V1_SCHEMA.createRecord(key);
record.setLongValue(V1_ARRAY_DT_ID_COL, dataTypeID);
@@ -105,7 +110,7 @@ class ArrayDBAdapterV1 extends ArrayDBAdapter {
@Override
void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(ARRAY_TABLE_NAME);
+ handle.deleteTable(table.getName());
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapter.java
index 809a6f4097..b146cf8e80 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapter.java
@@ -19,7 +19,6 @@ import java.io.IOException;
import db.*;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
/**
* Database adapter for managing built-in data types.
@@ -35,14 +34,14 @@ public abstract class BuiltinDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
- * @param monitor the monitor to use for displaying status or for canceling.
+ * @param tablePrefix prefix to be used with default table name
* @return the adapter for accessing the table of built-in data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there was a problem accessing the database
*/
- static BuiltinDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
+ static BuiltinDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
- return new BuiltinDBAdapterV0(handle, openMode == DBConstants.CREATE);
+ return new BuiltinDBAdapterV0(handle, tablePrefix, openMode == DBConstants.CREATE);
}
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapterV0.java
index 9075a5c7f8..c6525617f0 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltinDBAdapterV0.java
@@ -24,38 +24,44 @@ import ghidra.util.exception.VersionException;
* Version 0 implementation of the adapter for accessing the built-ins table.
*/
class BuiltinDBAdapterV0 extends BuiltinDBAdapter {
+
+ private static final int VERSION = 0;
+
static final String BUILT_IN_TABLE_NAME = "Built-in datatypes";
static final int V0_BUILT_IN_NAME_COL = 0;
static final int V0_BUILT_IN_CLASSNAME_COL = 1;
static final int V0_BUILT_IN_CAT_COL = 2;
+
static final Schema V0_SCHEMA = new Schema(0, "Data Type ID",
new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE },
new String[] { "Name", "Class Name", "Category ID" });
+
private Table table;
/**
* Gets a version 0 adapter for the Built-Ins database table.
* @param handle handle to the database containing the table.
- * @param create true if this constructor should create the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create create table if true else acquire for read-only or update use
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if there is trouble accessing the database.
*/
- public BuiltinDBAdapterV0(DBHandle handle, boolean create)
+ public BuiltinDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
+ String tableName = tablePrefix + BUILT_IN_TABLE_NAME;
if (create) {
- table = handle.createTable(BUILT_IN_TABLE_NAME, V0_SCHEMA,
+ table = handle.createTable(tableName, V0_SCHEMA,
new int[] { V0_BUILT_IN_CAT_COL });
}
else {
- table = handle.getTable(BUILT_IN_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + BUILT_IN_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- else if (table.getSchema().getVersion() != 0) {
- throw new VersionException("Expected version 0 for table " + BUILT_IN_TABLE_NAME +
- " but got " + table.getSchema().getVersion());
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapter.java
new file mode 100644
index 0000000000..8001512af3
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapter.java
@@ -0,0 +1,119 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.database.data;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import db.*;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.VersionException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * Adapter to access the Function Calling Conventions tables.
+ */
+abstract class CallingConventionDBAdapter {
+
+ static final byte UNKNOWN_CALLING_CONVENTION_ID = (byte) 0;
+ static final byte DEFAULT_CALLING_CONVENTION_ID = (byte) 1;
+ static final byte FIRST_CALLING_CONVENTION_ID = (byte) 2;
+
+ static final String CALLING_CONVENTION_TABLE_NAME = "Calling Conventions";
+
+ static final Schema CALLING_CONVENTION_SCHEMA =
+ CallingConventionDBAdapterV0.V0_CALLING_CONVENTION_SCHEMA;
+ // Calling Convention Columns
+ static final int CALLING_CONVENTION_NAME_COL =
+ CallingConventionDBAdapterV0.V0_CALLING_CONVENTION_NAME_COL;
+
+ /**
+ * Gets an adapter for working with the calling convention database table.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
+ * @return adapter instance
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is a problem accessing the database.
+ * @throws CancelledException if task is cancelled
+ */
+ static CallingConventionDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
+ if (openMode == DBConstants.CREATE) {
+ return new CallingConventionDBAdapterV0(handle, tablePrefix, true);
+ }
+ try {
+ return new CallingConventionDBAdapterV0(handle, tablePrefix, false);
+ }
+ catch (VersionException e) {
+ if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
+ throw e;
+ }
+ CallingConventionDBAdapter adapter = findReadOnlyAdapter(handle);
+ if (openMode == DBConstants.UPGRADE) {
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
+ }
+ return adapter;
+ }
+ }
+
+ private static CallingConventionDBAdapter findReadOnlyAdapter(DBHandle handle) {
+ return new CallingConventionDBAdapterNoTable();
+ }
+
+ private static CallingConventionDBAdapter upgrade(DBHandle handle,
+ CallingConventionDBAdapter oldAdapter, String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException {
+ return new CallingConventionDBAdapterV0(handle, tablePrefix, true);
+ }
+
+ /**
+ * Get (and assign if needed thus requiring open transaction) the ID associated with the
+ * specified calling convention name. If name is a new convention and the number of stored
+ * convention names exceeds 127 the returned ID will correspond to the unknown calling
+ * convention.
+ * @param name calling convention name or null if unknown
+ * @param conventionAdded callback when new calling convention is added
+ * @return calling convention ID
+ * @throws IOException if an IO error occurs
+ */
+ abstract byte getCallingConventionId(String name, Consumer conventionAdded)
+ throws IOException;
+
+ /**
+ * Get calling convention name which corresponds to the specified id.
+ * @param id calling convention storage ID
+ * @return calling convention name or null if unknown call convention
+ * @throws IOException if IO error occurs
+ */
+ abstract String getCallingConventionName(byte id) throws IOException;
+
+ /**
+ * Clear calling convention cached lookup maps
+ */
+ abstract void invalidateCache();
+
+ /**
+ * Get all stored calling convention names. The "default" and "unknown"
+ * names are excluded from this set.
+ * @return set of all stored calling convention names
+ * @throws IOException if an IO error occurs
+ */
+ abstract Set getCallingConventionNames() throws IOException;
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterNoTable.java
new file mode 100644
index 0000000000..d09de20140
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterNoTable.java
@@ -0,0 +1,56 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.database.data;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import javax.help.UnsupportedOperationException;
+
+/**
+ * Adapter when no Calling Convention table exists.
+ */
+class CallingConventionDBAdapterNoTable extends CallingConventionDBAdapter {
+
+ /**
+ * Gets a no-table adapter for the calling convention database table.
+ */
+ CallingConventionDBAdapterNoTable() {
+ // no table - do nothing
+ }
+
+ @Override
+ byte getCallingConventionId(String name, Consumer conventionAdded) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ String getCallingConventionName(byte id) throws IOException {
+ return null;
+ }
+
+ @Override
+ void invalidateCache() {
+ // do nothing
+ }
+
+ @Override
+ Set getCallingConventionNames() throws IOException {
+ return Set.of();
+ }
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterV0.java
new file mode 100644
index 0000000000..8815377062
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CallingConventionDBAdapterV0.java
@@ -0,0 +1,187 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.database.data;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.function.Consumer;
+
+import com.google.common.collect.Range;
+import com.google.common.collect.TreeRangeSet;
+
+import db.*;
+import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.listing.Function;
+import ghidra.util.Msg;
+import ghidra.util.exception.VersionException;
+
+/**
+ * Version 0 implementation for the calling conventions tables adapter.
+ *
+ */
+class CallingConventionDBAdapterV0 extends CallingConventionDBAdapter {
+
+ private static final int VERSION = 0;
+
+ // Calling Convention Columns
+ // Key field is the Calling convention ID, which is a Byte field.
+ static final int V0_CALLING_CONVENTION_NAME_COL = 0;
+
+ static final Schema V0_CALLING_CONVENTION_SCHEMA = new Schema(0, ByteField.INSTANCE, "ID",
+ new Field[] { StringField.INSTANCE }, new String[] { "Name" });
+
+ private Table callingConventionTable;
+
+ private Map callingConventionNameToIDMap;
+ private Map callingConventionIDToNameMap;
+
+ // There is currently no method for removing an allocated calling convention name/ID,
+ // therefor we can assume key consumption will be sequential until the ability
+ // to delete is added. Use of freeKeySet can be eliminated if delete ability never added.
+ private TreeRangeSet freeKeySet; // closed-ranges only
+
+ /**
+ * Gets a version 0 adapter for the calling convention database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create true if this constructor should create the table.
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
+ * @throws IOException if an IO error occurs
+ */
+ CallingConventionDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + CALLING_CONVENTION_TABLE_NAME;
+ if (create) {
+ // No additional indexed fields.
+ callingConventionTable = handle.createTable(tableName,
+ V0_CALLING_CONVENTION_SCHEMA, new int[] {});
+ }
+ else {
+ callingConventionTable = handle.getTable(tableName);
+ if (callingConventionTable == null) {
+ throw new VersionException(true);
+ }
+ if (callingConventionTable.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
+ }
+ }
+ }
+
+ /**
+ * Remove next available free key value from freeKeySet.
+ * @return the next available key. A negative value indicates that all allowed IDs have
+ * been used.
+ */
+ private byte removeFirstAvailableKey() {
+ Iterator> it = freeKeySet.asRanges().iterator();
+ if (!it.hasNext()) {
+ return -1;
+ }
+ Range r = it.next();
+ it.remove();
+ byte nextId = r.lowerEndpoint();
+ byte lastId = r.upperEndpoint();
+ if (nextId != lastId) {
+ freeKeySet.add(Range.closed((byte) (nextId + 1), lastId));
+ }
+ return nextId;
+ }
+
+ @Override
+ void invalidateCache() {
+ callingConventionNameToIDMap = null;
+ callingConventionIDToNameMap = null;
+ freeKeySet = null;
+ }
+
+ private void populateCache() throws IOException {
+ if (callingConventionNameToIDMap != null) {
+ return;
+ }
+ callingConventionNameToIDMap = new HashMap<>();
+ callingConventionIDToNameMap = new HashMap<>();
+
+ freeKeySet = TreeRangeSet.create();
+ int nextKey = FIRST_CALLING_CONVENTION_ID;
+ RecordIterator iterator = callingConventionTable.iterator();
+ while (iterator.hasNext()) {
+ DBRecord rec = iterator.next();
+
+ byte id = (byte) rec.getKey();
+ String name = rec.getString(V0_CALLING_CONVENTION_NAME_COL);
+ callingConventionIDToNameMap.put(id, name);
+ callingConventionNameToIDMap.put(name, id);
+
+ if (nextKey != id) {
+ freeKeySet.add(Range.closed((byte) nextKey, (byte) (id - 1)));
+ }
+ nextKey = id + 1;
+ }
+ if (nextKey <= Byte.MAX_VALUE) {
+ freeKeySet.add(Range.closed((byte) nextKey, Byte.MAX_VALUE));
+ }
+ }
+
+ @Override
+ byte getCallingConventionId(String name, Consumer conventionAdded) throws IOException {
+ if (name == null || name.equals(CompilerSpec.CALLING_CONVENTION_unknown)) {
+ return UNKNOWN_CALLING_CONVENTION_ID;
+ }
+ else if (name.equals(CompilerSpec.CALLING_CONVENTION_default)) {
+ return DEFAULT_CALLING_CONVENTION_ID;
+ }
+ populateCache();
+ Byte id = callingConventionNameToIDMap.get(name);
+ if (id != null) {
+ return id;
+ }
+
+ byte newId = removeFirstAvailableKey();
+ if (newId < 0) {
+ Msg.error(this, "Unable to assign calling convention `" + name +
+ "` - allocation capacity exceeded");
+ return UNKNOWN_CALLING_CONVENTION_ID;
+ }
+
+ DBRecord record = V0_CALLING_CONVENTION_SCHEMA.createRecord(new ByteField(newId));
+ record.setString(V0_CALLING_CONVENTION_NAME_COL, name);
+ callingConventionTable.putRecord(record);
+
+ callingConventionIDToNameMap.put(newId, name);
+ callingConventionNameToIDMap.put(name, newId);
+ conventionAdded.accept(name);
+ return newId;
+ }
+
+ @Override
+ String getCallingConventionName(byte id) throws IOException {
+ if (id == DEFAULT_CALLING_CONVENTION_ID) {
+ return Function.DEFAULT_CALLING_CONVENTION_STRING;
+ }
+ else if (id == UNKNOWN_CALLING_CONVENTION_ID) {
+ return null;
+ }
+ populateCache();
+ return callingConventionIDToNameMap.get(id);
+ }
+
+ @Override
+ Set getCallingConventionNames() throws IOException {
+ populateCache();
+ return callingConventionNameToIDMap.keySet();
+ }
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapter.java
index 1cf7867ef7..3f0783ac78 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapter.java
@@ -18,16 +18,25 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.program.model.data.Category;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
abstract class CategoryDBAdapter {
static final int CATEGORY_NAME_COL = CategoryDBAdapterV0.V0_CATEGORY_NAME_COL;
static final int CATEGORY_PARENT_COL = CategoryDBAdapterV0.V0_CATEGORY_PARENT_COL;
- static CategoryDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
+ /**
+ * Gets an adapter for working with the {@link Category} database table.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @return adapter instance
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is a problem accessing the database.
+ */
+ static CategoryDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
- return new CategoryDBAdapterV0(handle, openMode);
+ return new CategoryDBAdapterV0(handle, tablePrefix, openMode == DBConstants.CREATE);
}
/**
@@ -81,7 +90,16 @@ abstract class CategoryDBAdapter {
*/
abstract DBRecord getRootRecord() throws IOException;
+ /**
+ * Update record in database
+ * @param record category record
+ * @throws IOException if IO error occurs
+ */
abstract void putRecord(DBRecord record) throws IOException;
+ /**
+ * Get the total number of category records
+ * @return category record count
+ */
abstract int getRecordCount();
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapterV0.java
index 62f260be8c..6c45bab1bb 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDBAdapterV0.java
@@ -21,9 +21,13 @@ import db.*;
import ghidra.util.exception.VersionException;
class CategoryDBAdapterV0 extends CategoryDBAdapter {
+
+ private static final int VERSION = 0;
+
static final String CATEGORY_TABLE_NAME = "Categories";
static final int V0_CATEGORY_NAME_COL = 0;
static final int V0_CATEGORY_PARENT_COL = 1;
+
static final Schema V0_SCHEMA =
new Schema(0, "Category ID", new Field[] { StringField.INSTANCE, LongField.INSTANCE },
new String[] { "Name", "Parent ID" });
@@ -31,34 +35,38 @@ class CategoryDBAdapterV0 extends CategoryDBAdapter {
private Table table;
/**
- * Constructor
- *
+ * Gets a version 0 adapter for the Category database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create true if this constructor should create the table.
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
+ * @throws IOException if an IO error occurs
*/
- public CategoryDBAdapterV0(DBHandle handle, int openMode) throws VersionException, IOException {
-
- if (openMode == DBConstants.CREATE) {
- table = handle.createTable(CATEGORY_TABLE_NAME, V0_SCHEMA,
- new int[] { V0_CATEGORY_PARENT_COL });
+ CategoryDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + CATEGORY_TABLE_NAME;
+ if (create) {
+ table = handle.createTable(tableName, V0_SCHEMA, new int[] { V0_CATEGORY_PARENT_COL });
}
else {
- table = handle.getTable(CATEGORY_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + CATEGORY_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- else if (table.getSchema().getVersion() != 0) {
- throw new VersionException("Expected version 0 for table " + CATEGORY_TABLE_NAME +
- " but got " + table.getSchema().getVersion());
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
@Override
- public DBRecord getRecord(long categoryID) throws IOException {
+ DBRecord getRecord(long categoryID) throws IOException {
return table.getRecord(categoryID);
}
@Override
- public Field[] getRecordIdsWithParent(long categoryID) throws IOException {
+ Field[] getRecordIdsWithParent(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), V0_CATEGORY_PARENT_COL);
}
@@ -76,7 +84,7 @@ class CategoryDBAdapterV0 extends CategoryDBAdapter {
}
@Override
- public DBRecord createCategory(String name, long parentID) throws IOException {
+ DBRecord createCategory(String name, long parentID) throws IOException {
long key = table.getKey();
if (key == 0) {
key = 1;
@@ -90,12 +98,12 @@ class CategoryDBAdapterV0 extends CategoryDBAdapter {
}
@Override
- public boolean removeCategory(long categoryID) throws IOException {
+ boolean removeCategory(long categoryID) throws IOException {
return table.deleteRecord(categoryID);
}
@Override
- public DBRecord getRootRecord() throws IOException {
+ DBRecord getRootRecord() throws IOException {
Field[] keys = table.findRecords(new LongField(-1), V0_CATEGORY_PARENT_COL);
if (keys.length != 1) {
throw new IOException("Found " + keys.length + " entries for root category");
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java
index 021e0c8114..f70793ad9d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java
@@ -19,7 +19,6 @@ import java.io.IOException;
import db.*;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
/**
* Adapter to access the Component database table.
@@ -43,14 +42,14 @@ abstract class ComponentDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
- * @param monitor the monitor to use for displaying status or for canceling.
+ * @param tablePrefix prefix to be used with default table name
* @return the adapter for accessing the table of component data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is a problem accessing the database.
*/
- static ComponentDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
+ static ComponentDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
- return new ComponentDBAdapterV0(handle, openMode == DBConstants.CREATE);
+ return new ComponentDBAdapterV0(handle, tablePrefix, openMode == DBConstants.CREATE);
}
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java
index 69f8f3a1aa..614ccfa3aa 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java
@@ -40,48 +40,41 @@ class ComponentDBAdapterV0 extends ComponentDBAdapter {
StringField.INSTANCE, StringField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE },
new String[] { "Parent", "Offset", "Data Type ID", "Field Name", "Comment",
"Component Size", "Ordinal" });
+
private Table componentTable;
/**
* Gets a version 0 adapter for the Component database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
+ * @throws IOException if an IO error occurs
*/
- public ComponentDBAdapterV0(DBHandle handle, boolean create)
+ ComponentDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + COMPONENT_TABLE_NAME;
if (create) {
- componentTable = handle.createTable(COMPONENT_TABLE_NAME, V0_COMPONENT_SCHEMA,
+ componentTable = handle.createTable(tableName, V0_COMPONENT_SCHEMA,
new int[] { V0_COMPONENT_PARENT_ID_COL });
}
else {
- componentTable = handle.getTable(COMPONENT_TABLE_NAME);
+ componentTable = handle.getTable(tableName);
if (componentTable == null) {
- throw new VersionException("Missing Table: " + COMPONENT_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- int version = componentTable.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + COMPONENT_TABLE_NAME +
- " but got " + componentTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (componentTable.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
@Override
- public DBRecord createRecord(long dataTypeID, long parentID, int length, int ordinal, int offset,
+ DBRecord createRecord(long dataTypeID, long parentID, int length, int ordinal, int offset,
String name, String comment) throws IOException {
-
- long tableKey = componentTable.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.COMPONENT, tableKey);
+ long key =
+ DataTypeManagerDB.createKey(DataTypeManagerDB.COMPONENT, componentTable.getKey());
DBRecord record = ComponentDBAdapter.COMPONENT_SCHEMA.createRecord(key);
record.setLongValue(ComponentDBAdapter.COMPONENT_PARENT_ID_COL, parentID);
record.setLongValue(ComponentDBAdapter.COMPONENT_OFFSET_COL, offset);
@@ -95,22 +88,22 @@ class ComponentDBAdapterV0 extends ComponentDBAdapter {
}
@Override
- public DBRecord getRecord(long componentID) throws IOException {
+ DBRecord getRecord(long componentID) throws IOException {
return componentTable.getRecord(componentID);
}
@Override
- public void updateRecord(DBRecord record) throws IOException {
+ void updateRecord(DBRecord record) throws IOException {
componentTable.putRecord(record);
}
@Override
- public boolean removeRecord(long componentID) throws IOException {
+ boolean removeRecord(long componentID) throws IOException {
return componentTable.deleteRecord(componentID);
}
@Override
- public Field[] getComponentIdsInComposite(long compositeID) throws IOException {
+ Field[] getComponentIdsInComposite(long compositeID) throws IOException {
return componentTable.findRecords(new LongField(compositeID),
ComponentDBAdapter.COMPONENT_PARENT_ID_COL);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java
index 291dc5120e..c27e3fe2ee 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java
@@ -60,8 +60,8 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
protected abstract void initialize();
/**
- * Get the preferred length for a new component. For Unions and internally
- * aligned structures the preferred component length for a fixed-length dataType
+ * Get the preferred length for a new component. For Unions and packed
+ * structures the preferred component length for a fixed-length dataType
* will be the length of that dataType. Otherwise the length returned will be no
* larger than the specified length.
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapter.java
index 2541cdbc82..5ac775aebd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapter.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.program.database.util.DBRecordAdapter;
import ghidra.program.model.data.CompositeInternal;
import ghidra.util.UniversalID;
import ghidra.util.exception.CancelledException;
@@ -27,7 +28,7 @@ import ghidra.util.task.TaskMonitor;
/**
* Adapter to access the Composite database table.
*/
-abstract class CompositeDBAdapter {
+abstract class CompositeDBAdapter implements DBRecordAdapter {
static final String COMPOSITE_TABLE_NAME = "Composite Data Types";
static final Schema COMPOSITE_SCHEMA = CompositeDBAdapterV5V6.V5V6_COMPOSITE_SCHEMA;
@@ -73,24 +74,25 @@ abstract class CompositeDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of composite data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
* @throws CancelledException task cancelled
*/
- static CompositeDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException, CancelledException {
+ static CompositeDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
try {
- return new CompositeDBAdapterV5V6(handle, openMode);
+ return new CompositeDBAdapterV5V6(handle, openMode, tablePrefix);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
throw e;
}
- CompositeDBAdapter adapter = findReadOnlyAdapter(handle);
+ CompositeDBAdapter adapter = findReadOnlyAdapter(handle, tablePrefix);
if (openMode == DBConstants.UPGRADE) {
- return upgrade(handle, adapter, monitor);
+ return upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -99,14 +101,15 @@ abstract class CompositeDBAdapter {
/**
* Tries to get a read only adapter for the database whose handle is passed to this method.
* @param handle handle to prior version of the database.
+ * @param tablePrefix prefix to be used with default table name
* @return the read only Composite data type table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
* @throws IOException if IO error occurs
*/
- static CompositeDBAdapter findReadOnlyAdapter(DBHandle handle)
+ private static CompositeDBAdapter findReadOnlyAdapter(DBHandle handle, String tablePrefix)
throws VersionException, IOException {
try {
- return new CompositeDBAdapterV5V6(handle, DBConstants.READ_ONLY);
+ return new CompositeDBAdapterV5V6(handle, DBConstants.READ_ONLY, tablePrefix);
}
catch (VersionException e) {
// ignore
@@ -130,6 +133,7 @@ abstract class CompositeDBAdapter {
* Upgrades the Composite data type table from the oldAdapter's version to the current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
* @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
@@ -137,14 +141,15 @@ abstract class CompositeDBAdapter {
* @throws IOException if the database can't be read or written.
* @throws CancelledException user cancelled upgrade
*/
- static CompositeDBAdapter upgrade(DBHandle handle, CompositeDBAdapter oldAdapter,
- TaskMonitor monitor) throws VersionException, IOException, CancelledException {
+ private static CompositeDBAdapter upgrade(DBHandle handle, CompositeDBAdapter oldAdapter,
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
CompositeDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new CompositeDBAdapterV5V6(tmpHandle, DBConstants.CREATE);
+ tmpAdapter = new CompositeDBAdapterV5V6(tmpHandle, DBConstants.CREATE, tablePrefix);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
monitor.checkCanceled();
@@ -152,7 +157,8 @@ abstract class CompositeDBAdapter {
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
- CompositeDBAdapter newAdapter = new CompositeDBAdapterV5V6(handle, DBConstants.CREATE);
+ CompositeDBAdapter newAdapter =
+ new CompositeDBAdapterV5V6(handle, DBConstants.CREATE, tablePrefix);
if (oldAdapter.getVersion() < FLEX_ARRAY_ELIMINATION_SCHEMA_VERSION) {
newAdapter.flexArrayMigrationRequired = true;
}
@@ -211,7 +217,7 @@ abstract class CompositeDBAdapter {
* @return the composite data type record iterator.
* @throws IOException if the database can't be accessed.
*/
- abstract RecordIterator getRecords() throws IOException;
+ public abstract RecordIterator getRecords() throws IOException;
/**
* Updates the composite data type table with the provided record.
@@ -269,6 +275,6 @@ abstract class CompositeDBAdapter {
* Get the number of composite records
* @return total number of composite records
*/
- abstract int getRecordCount();
+ public abstract int getRecordCount();
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV0.java
index 3ed7feb480..646f3eb7c9 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV0.java
@@ -35,11 +35,12 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
static final int V0_COMPOSITE_LENGTH_COL = 4;
static final int V0_COMPOSITE_NUM_COMPONENTS_COL = 5;
- static final Schema V0_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
- new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
- LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE },
- new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
- "Number Of Components" });
+// DO NOT REMOVE - this documents the schema used in version 0.
+// static final Schema V0_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
+// new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
+// LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE },
+// new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
+// "Number Of Components" });
private Table compositeTable;
@@ -49,20 +50,14 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public CompositeDBAdapterV0(DBHandle handle) throws VersionException {
+ CompositeDBAdapterV0(DBHandle handle) throws VersionException {
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
if (compositeTable == null) {
throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
}
- int version = compositeTable.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + COMPOSITE_TABLE_NAME +
- " but got " + compositeTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (compositeTable.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
@@ -71,12 +66,12 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- int getRecordCount() {
+ public int getRecordCount() {
return compositeTable.getRecordCount();
}
@Override
- public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
+ DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
long lastChangeTime, int packValue, int minAlignment) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
@@ -84,7 +79,7 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public DBRecord getRecord(long dataTypeID) throws IOException {
+ DBRecord getRecord(long dataTypeID) throws IOException {
return translateRecord(compositeTable.getRecord(dataTypeID));
}
@@ -94,18 +89,18 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long compositeID) throws IOException {
+ boolean removeRecord(long compositeID) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
" of " + COMPOSITE_TABLE_NAME + " table.");
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return compositeTable.findRecords(new LongField(categoryID),
CompositeDBAdapter.COMPOSITE_CAT_COL);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV1.java
index 71a367b6f2..4a01f3628e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV1.java
@@ -38,6 +38,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
static final int V1_COMPOSITE_SOURCE_SYNC_TIME_COL = 8;
static final int V1_COMPOSITE_LAST_CHANGE_TIME_COL = 9;
+// DO NOT REMOVE - this documents the schema used in version 1.
// static final Schema V1_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
// new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
// LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, LongField.INSTANCE,
@@ -54,7 +55,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public CompositeDBAdapterV1(DBHandle handle) throws VersionException {
+ CompositeDBAdapterV1(DBHandle handle) throws VersionException {
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
if (compositeTable == null) {
@@ -62,12 +63,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
int version = compositeTable.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + COMPOSITE_TABLE_NAME +
- " but got " + compositeTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
@@ -76,12 +72,12 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- int getRecordCount() {
+ public int getRecordCount() {
return compositeTable.getRecordCount();
}
@Override
- public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
+ DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
long lastChangeTime, int packValue, int minAlignment) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
@@ -89,7 +85,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public DBRecord getRecord(long dataTypeID) throws IOException {
+ DBRecord getRecord(long dataTypeID) throws IOException {
return translateRecord(compositeTable.getRecord(dataTypeID));
}
@@ -99,12 +95,12 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long compositeID) throws IOException {
+ boolean removeRecord(long compositeID) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
" of " + COMPOSITE_TABLE_NAME + " table.");
}
@@ -115,7 +111,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return compositeTable.findRecords(new LongField(categoryID),
CompositeDBAdapter.COMPOSITE_CAT_COL);
}
@@ -126,9 +122,6 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
V1_COMPOSITE_SOURCE_ARCHIVE_ID_COL);
}
- /* (non-Javadoc)
- * @see db.RecordTranslator#translateRecord(db.Record)
- */
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV2V4.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV2V4.java
index afc02c2a11..881dbb2bc9 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV2V4.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV2V4.java
@@ -51,14 +51,15 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
static final int V2V4_COMPOSITE_PACK_COL = 10; // renamed from Internal Alignment
static final int V2V4_COMPOSITE_MIN_ALIGN_COL = 11; // renamed from External Alignment
- static final Schema V2V4_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
- new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
- LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, LongField.INSTANCE,
- LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE,
- IntField.INSTANCE },
- new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
- "Number Of Components", "Source Archive ID", "Source Data Type ID", "Source Sync Time",
- "Last Change Time", "Pack", "MinAlign" });
+// DO NOT REMOVE - this documents the schema used in versions 2 thru 4.
+// static final Schema V2V4_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
+// new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
+// LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, LongField.INSTANCE,
+// LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE,
+// IntField.INSTANCE },
+// new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
+// "Number Of Components", "Source Archive ID", "Source Data Type ID", "Source Sync Time",
+// "Last Change Time", "Pack", "MinAlign" });
private Table compositeTable;
@@ -68,7 +69,7 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public CompositeDBAdapterV2V4(DBHandle handle) throws VersionException {
+ CompositeDBAdapterV2V4(DBHandle handle) throws VersionException {
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
if (compositeTable == null) {
throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
@@ -90,12 +91,12 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
}
@Override
- int getRecordCount() {
+ public int getRecordCount() {
return compositeTable.getRecordCount();
}
@Override
- public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
+ DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
long lastChangeTime, int packValue, int minAlignment) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
@@ -103,7 +104,7 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
}
@Override
- public DBRecord getRecord(long dataTypeID) throws IOException {
+ DBRecord getRecord(long dataTypeID) throws IOException {
return translateRecord(compositeTable.getRecord(dataTypeID));
}
@@ -113,12 +114,12 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long compositeID) throws IOException {
+ boolean removeRecord(long compositeID) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
" of " + COMPOSITE_TABLE_NAME + " table.");
}
@@ -129,7 +130,7 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return compositeTable.findRecords(new LongField(categoryID),
CompositeDBAdapter.COMPOSITE_CAT_COL);
}
@@ -140,9 +141,6 @@ class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTransla
V2V4_COMPOSITE_SOURCE_ARCHIVE_ID_COL);
}
- /* (non-Javadoc)
- * @see db.RecordTranslator#translateRecord(db.Record)
- */
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV5V6.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV5V6.java
index d2b3b3e914..cb22520b8d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV5V6.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDBAdapterV5V6.java
@@ -32,6 +32,8 @@ import ghidra.util.exception.VersionException;
* Version 6 did not change the schema but corresponds to the elimination
* of Structure flex-arrays which are supported in read-only mode under
* the older version 5 adapter version.
+ *
+ * NOTE: Use of tablePrefix introduced with adapter V6.
*/
class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
@@ -66,33 +68,30 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
/**
* Gets an adapter for the Composite database table.
* @param handle handle to the database containing the table.
- * @param openMode
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if IO error occurs
*/
- public CompositeDBAdapterV5V6(DBHandle handle, int openMode)
+ CompositeDBAdapterV5V6(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
+ String tableName = tablePrefix + COMPOSITE_TABLE_NAME;
if (openMode == DBConstants.CREATE) {
- compositeTable = handle.createTable(COMPOSITE_TABLE_NAME, V5V6_COMPOSITE_SCHEMA,
+ compositeTable = handle.createTable(tableName, V5V6_COMPOSITE_SCHEMA,
new int[] { V5V6_COMPOSITE_CAT_COL, V5V6_COMPOSITE_UNIVERSAL_DT_ID_COL });
}
else {
- compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
+ compositeTable = handle.getTable(tableName);
if (compositeTable == null) {
- throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
int version = compositeTable.getSchema().getVersion();
- if (version == V5_VERSION && openMode == DBConstants.READ_ONLY) {
- return; // StructureDB handles read-only flex-array migration
- }
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + COMPOSITE_TABLE_NAME +
- " but got " + version;
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
+ if (version == V5_VERSION && openMode == DBConstants.READ_ONLY) {
+ return; // StructureDB handles read-only flex-array migration
}
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
}
@@ -102,12 +101,12 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
}
@Override
- int getRecordCount() {
+ public int getRecordCount() {
return compositeTable.getRecordCount();
}
@Override
- public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
+ DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
long lastChangeTime, int packValue, int minAlignment) throws IOException {
if (compositeTable.getSchema().getVersion() == V5_VERSION) {
@@ -141,7 +140,7 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
}
@Override
- public DBRecord getRecord(long dataTypeID) throws IOException {
+ DBRecord getRecord(long dataTypeID) throws IOException {
return compositeTable.getRecord(dataTypeID);
}
@@ -151,7 +150,7 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
if (compositeTable.getSchema().getVersion() == V5_VERSION) {
throw new UnsupportedOperationException();
}
@@ -163,7 +162,7 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
}
@Override
- public boolean removeRecord(long compositeID) throws IOException {
+ boolean removeRecord(long compositeID) throws IOException {
if (compositeTable.getSchema().getVersion() == V5_VERSION) {
throw new UnsupportedOperationException();
}
@@ -172,11 +171,11 @@ class CompositeDBAdapterV5V6 extends CompositeDBAdapter {
@Override
void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(COMPOSITE_TABLE_NAME);
+ handle.deleteTable(compositeTable.getName());
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return compositeTable.findRecords(new LongField(categoryID),
CompositeDBAdapter.COMPOSITE_CAT_COL);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformer.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformer.java
index b7800805aa..c214cc2ae8 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformer.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeArchiveTransformer.java
@@ -37,6 +37,7 @@ import ghidra.framework.ApplicationConfiguration;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.Enum;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.util.*;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.*;
@@ -63,8 +64,27 @@ public class DataTypeArchiveTransformer implements GhidraLaunchable {
FileDataTypeManager newFileArchive = null;
try {
monitor.initialize(100);
+
oldFileArchive = FileDataTypeManager.openFileArchive(oldFile, false);
+ ArchiveWarning warning = oldFileArchive.getWarning();
+ if (warning == ArchiveWarning.LANGUAGE_UPGRADE_REQURED) {
+ throw new IOException("Archive requires language upgrade: " + oldFile);
+ }
+ if (warning != ArchiveWarning.NONE) {
+ throw new IOException("Archive language error occured: " + oldFile,
+ oldFileArchive.getWarningDetail());
+ }
+
newFileArchive = FileDataTypeManager.openFileArchive(newFile, true);
+ warning = newFileArchive.getWarning();
+ if (warning == ArchiveWarning.LANGUAGE_UPGRADE_REQURED) {
+ throw new IOException("Archive requires language upgrade: " + newFile);
+ }
+ if (warning != ArchiveWarning.NONE) {
+ throw new IOException("Archive language error occured: " + newFile,
+ newFileArchive.getWarningDetail());
+ }
+
UniversalID oldUniversalID = oldFileArchive.getUniversalID();
UniversalID newUniversalID = newFileArchive.getUniversalID();
Msg.info(DataTypeArchiveTransformer.class, "Old file ID = " + oldUniversalID);
@@ -739,12 +759,10 @@ public class DataTypeArchiveTransformer implements GhidraLaunchable {
FileDataTypeManager destinationFileArchive =
FileDataTypeManager.openFileArchive(destinationFile, false);
- if (destinationFileArchive != null) {
- UniversalID destinationUniversalID = destinationFileArchive.getUniversalID();
- destinationFileArchive.close();
- Msg.info(DataTypeArchiveTransformer.class,
- "Resulting file ID = " + destinationUniversalID.getValue());
- }
+ UniversalID destinationUniversalID = destinationFileArchive.getUniversalID();
+ destinationFileArchive.close();
+ Msg.info(DataTypeArchiveTransformer.class,
+ "Resulting file ID = " + destinationUniversalID.getValue());
}
static File myOldFile = null;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java
index 2235dbfa24..412334180f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java
@@ -305,10 +305,10 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
return false;
}
DataType myParent = getParent();
- boolean aligned =
+ boolean isPacked =
(myParent instanceof Composite) ? ((Composite) myParent).isPackingEnabled() : false;
- // Components don't need to have matching offset when they are aligned
- if ((!aligned && (offset != dtc.getOffset())) ||
+ // Components don't need to have matching offset when structure has packing enabled
+ if ((!isPacked && (offset != dtc.getOffset())) ||
!SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) ||
!SystemUtilities.isEqual(getComment(), dtc.getComment())) {
return false;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java
index 930c028bcf..7996a6a226 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java
@@ -518,9 +518,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType {
@Override
public SourceArchive getSourceArchive() {
- if (dataMgr == null) {
- return null;
- }
return dataMgr.getSourceArchive(getSourceArchiveID());
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeIDConverter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeIDConverter.java
index 63a8026254..9cf7192734 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeIDConverter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeIDConverter.java
@@ -23,6 +23,7 @@ import ghidra.GhidraLaunchable;
import ghidra.framework.Application;
import ghidra.framework.ApplicationConfiguration;
import ghidra.program.model.data.*;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.util.NumericUtilities;
import ghidra.util.UniversalID;
import ghidra.util.datastruct.LongLongHashtable;
@@ -90,6 +91,10 @@ public class DataTypeIDConverter implements GhidraLaunchable {
FileDataTypeManager oldFileArchive = null;
try {
oldFileArchive = FileDataTypeManager.openFileArchive(inFile, false);
+ if (oldFileArchive.getWarning() != ArchiveWarning.NONE) {
+ System.out.println("Archive ID Conversion aborted");
+ return;
+ }
UniversalID oldFileUID = oldFileArchive.getUniversalID();
long newID = idMap.get(oldFileUID.getValue());
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
index e7fa3194f8..45aeb46c00 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
@@ -19,24 +19,30 @@ import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javax.help.UnsupportedOperationException;
+
import db.*;
import db.util.ErrorHandler;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
import ghidra.docking.settings.*;
+import ghidra.framework.Application;
import ghidra.framework.store.db.PackedDBHandle;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.graph.*;
import ghidra.graph.algo.GraphNavigator;
import ghidra.program.database.*;
import ghidra.program.database.map.AddressMap;
+import ghidra.program.database.symbol.VariableStorageManager;
+import ghidra.program.database.util.DBRecordAdapter;
import ghidra.program.model.data.*;
import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult;
import ghidra.program.model.data.Enum;
-import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.lang.*;
import ghidra.util.*;
import ghidra.util.classfinder.ClassTranslator;
import ghidra.util.datastruct.FixedSizeHashMap;
@@ -89,9 +95,15 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
// Data map keys
private static final String DTM_DB_VERSION_KEY = "DB Version";
+ private static final String DTM_GHIDRA_VERSION_KEY = "GHIDRA Version";
private static final String SETTINGS_TABLE_NAME = "Default Settings";
+ public static final byte UNKNOWN_CALLING_CONVENTION_ID =
+ CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID;
+ public static final byte DEFAULT_CALLING_CONVENTION_ID =
+ CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID;
+
private BuiltinDBAdapter builtinAdapter;
private ComponentDBAdapter componentAdapter;
private CompositeDBAdapter compositeAdapter;
@@ -107,7 +119,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private ParentChildAdapter parentChildAdapter;
protected SourceArchiveAdapter sourceArchiveAdapter;
+ private CallingConventionDBAdapter callingConventionAdapter;
+ private TreeSet knownCallingConventions;
+ private TreeSet definedCallingConventions;
+
protected DBHandle dbHandle;
+ private int mode; // open mode (see DBConstants)
+ protected final String tablePrefix;
protected final ErrorHandler errHandler;
private DataTypeConflictHandler currentHandler;
@@ -143,8 +161,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
protected AddressMap addrMap;
- protected DataOrganization dataOrganization;
-
+ private DataOrganization dataOrganization;
+ private ProgramArchitecture programArchitecture;
+ private VariableStorageManager variableStorageMgr;
+
protected final Lock lock;
private static class ResolvePair implements Comparable {
@@ -186,13 +206,15 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
/**
* Construct a new temporary data-type manager. Note that this manager does not
- * support the save or saveAs operation.
+ * support the save or saveAs operation. No Language is associated with instance.
+ *
* @param dataOrganization applicable data organization
*/
protected DataTypeManagerDB(DataOrganization dataOrganization) {
this.lock = new Lock("DataTypeManagerDB");
this.errHandler = new DbErrorHandler();
this.dataOrganization = dataOrganization;
+ this.tablePrefix = "";
try {
dbHandle = new DBHandle();
@@ -224,10 +246,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* @throws IOException a low-level IO error. This exception may also be thrown
* when a version error occurs (cause is VersionException).
*/
- protected DataTypeManagerDB(ResourceFile packedDBfile, int openMode) throws IOException {
+ protected DataTypeManagerDB(ResourceFile packedDBfile, int openMode)
+ throws IOException {
this.errHandler = new DbErrorHandler();
- lock = new Lock("DataTypeManagerDB");
+ this.lock = new Lock("DataTypeManagerDB");
+ this.tablePrefix = "";
File file = packedDBfile.getFile(false);
if (file == null && openMode != DBConstants.READ_ONLY) {
@@ -267,14 +291,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
boolean initSuccess = false;
try {
- // TODO: In the future it may be neccessary to store additional properties
- // within the archive to failitate use of a language specified data organization.
- // It will likely be neccessary to have a different CREATE constructor which accepts
- // a DataOrganization
-
- dataOrganization = DataOrganizationImpl.getDefaultOrganization();
-
- initPackedDatabase(packedDBfile, openMode);
+ initPackedDatabase(packedDBfile, openMode); // performs upgrade if needed
if (openMode == DBConstants.CREATE) {
// preserve UniversalID if it has been established
@@ -329,8 +346,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
*
* @param handle database handle
* @param addrMap address map (may be null)
- * @param openMode open mode CREATE, READ_ONLY or UPDATE (see
- * {@link DBConstants}).
+ * @param openMode open mode CREATE, READ_ONLY or UPDATE (see {@link DBConstants}).
+ * @param tablePrefix DB table prefix to be applied to all associated table names. This
+ * need only be specified when using multiple instances with the same
+ * DB handle (null or empty string for no-prefix).
* @param errHandler the error handler
* @param lock database lock
* @param monitor the current task monitor
@@ -340,9 +359,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* This exception will never be thrown in READ_ONLY mode.
*/
protected DataTypeManagerDB(DBHandle handle, AddressMap addrMap, int openMode,
- ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
+ String tablePrefix, ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
throws CancelledException, IOException, VersionException {
-
+ this.tablePrefix = tablePrefix != null ? tablePrefix : "";
this.dbHandle = handle;
this.addrMap = addrMap;
this.errHandler = errHandler;
@@ -352,10 +371,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private void init(int openMode, TaskMonitor monitor)
throws CancelledException, IOException, VersionException {
+ this.mode = openMode;
updateID();
initializeAdapters(openMode, monitor);
if (checkForSourceArchiveUpdatesNeeded(openMode, monitor)) {
- doSourceArchiveUpdates(null, monitor);
+ doSourceArchiveUpdates(monitor);
}
dtCache = new DBObjectCache<>(10);
sourceArchiveDBCache = new DBObjectCache<>(10);
@@ -371,97 +391,110 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
throws CancelledException, IOException, VersionException {
//
- // IMPORTANT! All adapter version must retain read-only capability to permit
+ // IMPORTANT! All adapter versions must retain read-only capability to permit
// opening older archives without requiring an upgrade. Failure to do so may
// present severe usability issues when the ability to open for update is not
// possible.
//
- checkAndUpdateManagerVersion(openMode);
+ checkManagerVersion(openMode);
VersionException versionExc = null;
try {
- builtinAdapter = BuiltinDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ callingConventionAdapter =
+ CallingConventionDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- categoryAdapter = CategoryDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ builtinAdapter = BuiltinDBAdapter.getAdapter(dbHandle, openMode, tablePrefix);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- arrayAdapter = ArrayDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ categoryAdapter = CategoryDBAdapter.getAdapter(dbHandle, openMode, tablePrefix);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- typedefAdapter = TypedefDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ arrayAdapter = ArrayDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- compositeAdapter = CompositeDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ typedefAdapter = TypedefDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- componentAdapter = ComponentDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ compositeAdapter =
+ CompositeDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
+ }
+ catch (VersionException e) {
+ versionExc = e.combine(versionExc);
+ }
+ try {
+ componentAdapter = ComponentDBAdapter.getAdapter(dbHandle, openMode, tablePrefix);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
functionDefAdapter =
- FunctionDefinitionDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ FunctionDefinitionDBAdapter.getAdapter(dbHandle, openMode, tablePrefix,
+ callingConventionAdapter, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- paramAdapter = FunctionParameterAdapter.getAdapter(dbHandle, openMode, monitor);
+ paramAdapter =
+ FunctionParameterAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- settingsAdapter = SettingsDBAdapter.getAdapter(SETTINGS_TABLE_NAME, dbHandle, openMode,
+ settingsAdapter =
+ SettingsDBAdapter.getAdapter(tablePrefix + SETTINGS_TABLE_NAME, dbHandle, openMode,
null, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- pointerAdapter = PointerDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ pointerAdapter = PointerDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- enumAdapter = EnumDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ enumAdapter = EnumDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- enumValueAdapter = EnumValueDBAdapter.getAdapter(dbHandle, openMode, monitor);
+ enumValueAdapter =
+ EnumValueDBAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- parentChildAdapter = ParentChildAdapter.getAdapter(dbHandle, openMode, monitor);
+ parentChildAdapter = ParentChildAdapter.getAdapter(dbHandle, openMode, tablePrefix);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
}
try {
- sourceArchiveAdapter = SourceArchiveAdapter.getAdapter(dbHandle, openMode, monitor);
+ sourceArchiveAdapter =
+ SourceArchiveAdapter.getAdapter(dbHandle, openMode, tablePrefix, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
@@ -477,6 +510,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (versionExc != null) {
throw versionExc;
}
+
+ updateManagerAndAppVersion(openMode);
}
/**
@@ -539,20 +574,16 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
/**
* Check data map for overall manager version for compatibility.
- * If not open read-only the map will be immediately updated to latest version.
* @throws VersionException if database is a newer unsupported version
* @throws IOException if an IO error occurs
*/
- private void checkAndUpdateManagerVersion(int openMode) throws IOException, VersionException {
+ private void checkManagerVersion(int openMode) throws IOException, VersionException {
if (openMode == DBConstants.CREATE) {
- DBStringMapAdapter dataMap = getDataMap(true);
- dataMap.put(DTM_DB_VERSION_KEY, Integer.toString(DB_VERSION));
return;
}
// Check data map for overall manager version for compatibility.
- // If not open read-only the map will be immediately updated to latest version.
DBStringMapAdapter dataMap = getDataMap(openMode == DBConstants.UPGRADE);
if (dataMap != null) {
// verify that we are compatible with stored data
@@ -560,14 +591,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (dbVersion > DB_VERSION) {
throw new VersionException(false);
}
- if (dbVersion < DB_VERSION) {
- if (openMode == DBConstants.UPGRADE) {
- // Upgrade mode required to advance overall DB version
- dataMap.put(DTM_DB_VERSION_KEY, Integer.toString(DB_VERSION));
- }
- else if (openMode == DBConstants.UPDATE) {
- throw new VersionException(true);
- }
+ if (dbVersion < DB_VERSION && openMode == DBConstants.UPDATE) {
+ // Force upgrade if open for update
+ throw new VersionException(true);
}
}
else if (openMode == DBConstants.UPDATE) {
@@ -576,6 +602,14 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
+ private void updateManagerAndAppVersion(int openMode) throws IOException {
+ if (openMode == DBConstants.CREATE || openMode == DBConstants.UPGRADE) {
+ DBStringMapAdapter dataMap = getDataMap(true);
+ dataMap.put(DTM_DB_VERSION_KEY, Integer.toString(DB_VERSION));
+ dataMap.put(DTM_GHIDRA_VERSION_KEY, Application.getApplicationVersion());
+ }
+ }
+
/**
* Get the manager string data map.
* @param createIfNeeded if true map will be created if it does not exist
@@ -736,6 +770,132 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
+ /**
+ * Set the architecture-specific details associated with this datatype manager.
+ * The data organization will be obtained from the compiler spec specified by
+ * the program architecture. Fixup of all composites will be performed, if store is
+ * true, to reflect any changes in the data organization.
+ * The caller is resposible for ensuring that this setting is done consistent
+ * with the {@link #addrMap} setting used during construction if applicable.
+ * @param programArchitecture program architecture details (may be null) in which case
+ * default data organization will be used.
+ * @param variableStorageMgr variable storage manager (within same database) or null
+ * to disable variable storage support. Ignored if programArchitecture is null;
+ * @param store if true database update will occur and datatypes will be updated if
+ * any change to the data organization is detected (a stored copy may be used to
+ * detect this condition). This should never be passed as true if opened read-only.
+ * @param monitor task monitor
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if processing cancelled - data types may not properly reflect
+ * updated compiler specification
+ * @throws UnsupportedOperationException if language was previously set
+ */
+ protected void setProgramArchitecture(ProgramArchitecture programArchitecture,
+ VariableStorageManager variableStorageMgr, boolean store, TaskMonitor monitor)
+ throws IOException, CancelledException {
+
+ this.programArchitecture = programArchitecture;
+ this.variableStorageMgr = programArchitecture != null ? variableStorageMgr : null;
+
+ dataOrganization = programArchitecture != null
+ ? programArchitecture.getCompilerSpec().getDataOrganization()
+ : DataOrganizationImpl.getDefaultOrganization();
+
+ if (mode == DBConstants.CREATE) {
+ saveDataOrganization();
+ }
+ else if (store) {
+ compilerSpecChanged(monitor);
+ updateLastChangeTime();
+ }
+ }
+
+ /**
+ * Perform updates related to a compiler spec change, including:
+ *
+ * - data organization changes which may impact datatype components and packing
+ *
+ * NOTE: this manager must be open for update.
+ * @param monitor task monitor
+ * @throws ReadOnlyException if this manager has not been open for update
+ * @throws IOException if an IO error occurs while performing updates
+ * @throws CancelledException if processing cancelled - data types may not properly reflect
+ * updated compiler specification
+ */
+ private void compilerSpecChanged(TaskMonitor monitor) throws IOException, CancelledException {
+
+ if (mode == DBConstants.READ_ONLY) {
+ throw new ReadOnlyException();
+ }
+
+ DataOrganization oldDataOrganization = readDataOrganization();
+
+ try {
+ saveDataOrganization();
+
+ if (oldDataOrganization != null &&
+ !oldDataOrganization.equals(dataOrganization)) {
+ Msg.info(this,
+ "Fixing datatypes to reflect data organization change: " + getPath());
+ doCompositeFixup(monitor);
+ }
+
+ // FUTURE: may need to handle calling convention and data organization change impact
+ // on function definitions
+
+ }
+ finally {
+ invalidateCache();
+ }
+ }
+
+ private void saveDataOrganization() throws IOException {
+ if (dataOrganization == null) {
+ return;
+ }
+ DataOrganizationImpl.save(dataOrganization, getDataMap(true), "dataOrg.");
+ }
+
+ private DataOrganization readDataOrganization() throws IOException {
+ DBStringMapAdapter dataMap = getDataMap(false);
+ if (dataMap == null) {
+ return null;
+ }
+ return DataOrganizationImpl.restore(dataMap, "dataOrg.");
+ }
+
+ @Override
+ public ProgramArchitecture getProgramArchitecture() {
+ return programArchitecture;
+ }
+
+ protected static String getProgramArchitectureSummary(LanguageID languageId,
+ int languageVersion, CompilerSpecID compilerSpecId) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(languageId.getIdAsString());
+ buf.append(" / ");
+ buf.append(compilerSpecId.getIdAsString());
+ return buf.toString();
+ }
+
+ @Override
+ public String getProgramArchitectureSummary() {
+ if (programArchitecture != null) {
+ return getProgramArchitectureSummary(programArchitecture.getLanguage().getLanguageID(),
+ programArchitecture.getLanguage().getVersion(),
+ programArchitecture.getCompilerSpec().getCompilerSpecID());
+ }
+ return null;
+ }
+
+ /**
+ * Get the variable storage manager if it has been established.
+ * @return variable storage manager or null if no associated architecture.
+ */
+ protected VariableStorageManager getVariableStorageManager() {
+ return variableStorageMgr;
+ }
+
/**
* Determine if transaction is active. With proper lock established
* this method may be useful for determining if a lazy record update
@@ -1130,7 +1290,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
int storageSize = bitFieldDataType.getStorageSize();
int storageSizeBits = 8 * storageSize;
if ((bitOffset + bitSize) > storageSizeBits) {
- // should get recomputed during packing when used within aligned structure
+ // should get recomputed during packing when used within structure with packing enabled
int effectiveBitSize = Math.min(bitSize, baseLengthBits);
bitOffset = getDataOrganization().isBigEndian() ? baseLengthBits - effectiveBitSize : 0;
storageSize = baseLength;
@@ -1574,11 +1734,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (sourceArchive == null) {
return null;
}
- if (getSourceArchive(sourceArchive.getSourceArchiveID()) != null) {
- // already have it
- return getSourceArchive(sourceArchive.getSourceArchiveID());
- }
+ lock.acquire();
try {
+ SourceArchive existingArchive = getSourceArchive(sourceArchive.getSourceArchiveID());
+ if (existingArchive != null) {
+ return existingArchive; // already have it
+ }
DBRecord record = sourceArchiveAdapter.createRecord(sourceArchive);
SourceArchive newSourceArchive = getSourceArchiveDB(record);
invalidateSourceArchiveCache();
@@ -1587,8 +1748,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
catch (IOException e) {
dbError(e);
- return null;
}
+ finally {
+ lock.release();
+ }
+ return null;
}
@Override
@@ -1602,15 +1766,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
throw new IllegalArgumentException("Attempted to delete the local archive!");
}
disassociateAllDataTypes(sourceArchiveID);
- try {
- sourceArchiveAdapter.deleteRecord(sourceArchiveID);
- }
- catch (IOException e) {
- dbError(e);
- }
- sourceArchiveChanged(sourceArchiveID);
+ sourceArchiveAdapter.deleteRecord(sourceArchiveID);
+ sourceArchiveChanged(sourceArchiveID); // must occur before invalidateSourceArchiveCache
invalidateSourceArchiveCache();
}
+ catch (IOException e) {
+ dbError(e);
+ }
finally {
lock.release();
}
@@ -1747,6 +1909,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
+ /**
+ * Replace all datatype uses external to the datatype manager if applicable.
+ * @param oldID old datatype ID
+ * @param newID new datatype ID
+ */
abstract protected void replaceDataTypeIDs(long oldID, long newID);
/**
@@ -2167,6 +2334,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
idsToDelete.add(Long.valueOf(id));
}
+ /**
+ * Delete all datatype uses external to the datatype manager if applicable.
+ * @param deletedIds old datatype IDs which were deleted
+ * @param monitor task monitor
+ * @throws CancelledException if operation cancelled
+ */
abstract protected void deleteDataTypeIDs(LinkedList deletedIds, TaskMonitor monitor)
throws CancelledException;
@@ -2442,26 +2615,36 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private DataType getDataType(long dataTypeID, DBRecord record) {
int tableId = getTableID(dataTypeID);
+ DataType dt = null;
switch (tableId) {
case BUILT_IN:
- return getBuiltInDataType(dataTypeID, record);
+ dt = getBuiltInDataType(dataTypeID, record);
+ break;
case COMPOSITE:
- return getCompositeDataType(dataTypeID, record);
+ dt = getCompositeDataType(dataTypeID, record);
+ break;
case ARRAY:
- return getArrayDataType(dataTypeID, record);
+ dt = getArrayDataType(dataTypeID, record);
+ break;
case POINTER:
- return getPointerDataType(dataTypeID, record);
+ dt = getPointerDataType(dataTypeID, record);
+ break;
case TYPEDEF:
- return getTypedefDataType(dataTypeID, record);
+ dt = getTypedefDataType(dataTypeID, record);
+ break;
case FUNCTION_DEF:
- return getFunctionDefDataType(dataTypeID, record);
+ dt = getFunctionDefDataType(dataTypeID, record);
+ break;
case ENUM:
- return getEnumDataType(dataTypeID, record);
+ dt = getEnumDataType(dataTypeID, record);
+ break;
case BITFIELD:
- return BitFieldDBDataType.getBitFieldDataType(dataTypeID, this);
+ dt = BitFieldDBDataType.getBitFieldDataType(dataTypeID, this);
+ break;
default:
return null;
}
+ return dt;
}
private DataType getBuiltInDataType(long dataTypeID, DBRecord record) {
@@ -2938,7 +3121,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return arrayDB;
}
- private void updateLastChangeTime() {
+ protected void updateLastChangeTime() {
SourceArchive mySourceArchive = getSourceArchive(getUniversalID());
if (mySourceArchive == null) {
return;
@@ -3105,10 +3288,14 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
try {
creatingDataType++;
+ byte callingConventionId =
+ callingConventionAdapter.getCallingConventionId(funDef.getCallingConventionName(),
+ cc -> callingConventionNameAdded(cc));
DBRecord record =
functionDefAdapter.createRecord(name, funDef.getComment(), cat.getID(),
- DEFAULT_DATATYPE_ID, funDef.hasVarArgs(), funDef.getGenericCallingConvention(),
- sourceArchiveIdValue, universalIdValue, funDef.getLastChangeTime());
+ DEFAULT_DATATYPE_ID, funDef.hasNoReturn(), funDef.hasVarArgs(),
+ callingConventionId, sourceArchiveIdValue, universalIdValue,
+ funDef.getLastChangeTime());
FunctionDefinitionDB funDefDb =
new FunctionDefinitionDB(this, dtCache, functionDefAdapter, paramAdapter, record);
@@ -3127,13 +3314,16 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
creatingDataType--;
}
}
-
- class StructureIterator implements Iterator {
+
+ class DataTypeIterator implements Iterator {
private RecordIterator it;
- private StructureDB nextStruct;
+ private T nextDataType;
+ private Predicate predicate;
- StructureIterator() throws IOException {
- it = compositeAdapter.getRecords();
+ DataTypeIterator(DBRecordAdapter adapter, Predicate predicate)
+ throws IOException {
+ it = adapter.getRecords();
+ this.predicate = predicate;
}
@Override
@@ -3143,29 +3333,30 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public boolean hasNext() {
- if (nextStruct == null) {
- getNextStruct();
+ if (nextDataType == null) {
+ getNextDataType();
}
- return nextStruct != null;
+ return nextDataType != null;
}
@Override
- public StructureDB next() {
+ public T next() {
if (hasNext()) {
- StructureDB s = nextStruct;
- nextStruct = null;
- return s;
+ T dt = nextDataType;
+ nextDataType = null;
+ return dt;
}
return null;
}
- private void getNextStruct() {
+ @SuppressWarnings("unchecked")
+ private void getNextDataType() {
try {
while (it.hasNext()) {
DBRecord rec = it.next();
DataType dt = getDataType(rec.getKey(), rec);
- if (dt instanceof Structure) {
- nextStruct = (StructureDB) dt;
+ if (predicate.test(dt)) {
+ nextDataType = (T) dt;
return;
}
}
@@ -3176,50 +3367,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
- class CompositeIterator implements Iterator {
- private RecordIterator it;
- private CompositeDB nextComposite;
-
- CompositeIterator() throws IOException {
- it = compositeAdapter.getRecords();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException("Remove not supported");
- }
-
- @Override
- public boolean hasNext() {
- if (nextComposite == null) {
- getNextComposite();
- }
- return nextComposite != null;
- }
-
- @Override
- public CompositeDB next() {
- if (hasNext()) {
- CompositeDB c = nextComposite;
- nextComposite = null;
- return c;
- }
- return null;
- }
-
- private void getNextComposite() {
- try {
- if (it.hasNext()) {
- DBRecord rec = it.next();
- nextComposite = (CompositeDB) getDataType(rec.getKey(), rec);
- }
- }
- catch (IOException e) {
- Msg.error(this, "Unexpected exception iterating composites", e);
- }
- }
- }
-
private class NameComparator implements Comparator {
/**
* Compares its two arguments for order. Returns a negative integer, zero, or a
@@ -3321,10 +3468,23 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
+ @Override
+ public Iterator getAllFunctionDefinitions() {
+ try {
+ return new DataTypeIterator(functionDefAdapter, dt -> true);
+ }
+ catch (IOException e) {
+ dbError(e);
+ }
+ List emptyList = List.of();
+ return emptyList.iterator();
+ }
+
@Override
public Iterator getAllStructures() {
try {
- return new StructureIterator();
+ return new DataTypeIterator(compositeAdapter,
+ dt -> (dt instanceof Structure));
}
catch (IOException e) {
dbError(e);
@@ -3335,7 +3495,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public Iterator getAllComposites() {
try {
- return new CompositeIterator();
+ return new DataTypeIterator(compositeAdapter, dt -> true);
}
catch (IOException e) {
dbError(e);
@@ -3359,6 +3519,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
public void invalidateCache() {
lock.acquire();
try {
+ callingConventionAdapter.invalidateCache();
+ knownCallingConventions = null;
+ definedCallingConventions = null;
dtCache.invalidate();
sourceArchiveDBCache.invalidate();
invalidateSourceArchiveCache();
@@ -3540,12 +3703,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
@Override
- public Pointer getPointer(DataType dt) {
+ public final Pointer getPointer(DataType dt) {
return new PointerDataType(dt, this);
}
@Override
- public Pointer getPointer(DataType dt, int size) {
+ public final Pointer getPointer(DataType dt, int size) {
return new PointerDataType(dt, size, this);
}
@@ -3576,7 +3739,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (dt instanceof Enum) {
enumValueMap = null;
}
- if (creatingDataType == 0) {
+ if (!isAutoChange && creatingDataType == 0) {
+ // auto-changes should not be synced
updateLastChangeTime();
setDirtyFlag(dt);
}
@@ -3762,13 +3926,192 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
@Override
- public DataOrganization getDataOrganization() {
+ public AddressMap getAddressMap() {
+ return addrMap;
+ }
+
+ @Override
+ public final DataOrganization getDataOrganization() {
if (dataOrganization == null) {
dataOrganization = DataOrganizationImpl.getDefaultOrganization();
}
return dataOrganization;
}
+ /**
+ * Get calling convention name corresponding to existing specified id.
+ * @param id calling convention ID
+ * @return calling convention name if found else unknown
+ */
+ public String getCallingConventionName(byte id) {
+ lock.acquire();
+ try {
+ String callingConvention = callingConventionAdapter.getCallingConventionName(id);
+ return callingConvention != null ? callingConvention
+ : CompilerSpec.CALLING_CONVENTION_unknown;
+ }
+ catch (IOException e) {
+ dbError(e);
+ }
+ finally {
+ lock.release();
+ }
+ return null;
+ }
+
+ /**
+ * Get (and assign if needed thus requiring open transaction) the ID associated with the
+ * specified calling convention name. If name is a new convention and the number of stored
+ * convention names exceeds 127 the returned ID will correspond to the unknown calling
+ * convention.
+ * @param name calling convention name
+ * @param restrictive if true an error will be thrown if name is not defined by
+ * {@link GenericCallingConvention} or the associated compiler specification if
+ * datatype manager has an associated program architecture.
+ * @return calling convention ID
+ * @throws IOException if database IO error occurs
+ * @throws InvalidInputException if restrictive is true and name is not defined by
+ * {@link GenericCallingConvention} or the associated compiler specification if
+ * datatype manager has an associated program architecture.
+ */
+ public byte getCallingConventionID(String name, boolean restrictive)
+ throws InvalidInputException, IOException {
+
+ if (name == null || CompilerSpec.CALLING_CONVENTION_unknown.equals(name)) {
+ return UNKNOWN_CALLING_CONVENTION_ID;
+ }
+ if (CompilerSpec.CALLING_CONVENTION_default.equals(name)) {
+ return DEFAULT_CALLING_CONVENTION_ID;
+ }
+
+ lock.acquire();
+ try {
+ // If restrictive only permit a name which is known
+ if (restrictive &&
+ GenericCallingConvention
+ .getGenericCallingConvention(name) == GenericCallingConvention.unknown &&
+ !getKnownCallingConventionNames().contains(name) &&
+ getCallingConvention(name) == null) {
+
+ throw new InvalidInputException("Invalid calling convention name: " + name);
+ }
+
+ return callingConventionAdapter.getCallingConventionId(name,
+ cc -> callingConventionNameAdded(cc));
+ }
+ catch (IOException e) {
+ dbError(e);
+ }
+ finally {
+ lock.release();
+ }
+ return UNKNOWN_CALLING_CONVENTION_ID;
+ }
+
+ private void callingConventionNameAdded(String name) {
+ getKnownCallingConventionSet().add(name);
+ }
+
+ private Set getDefinedCallingConventionSet() {
+ if (definedCallingConventions == null) {
+ definedCallingConventions = buildDefinedCallingConventionSet();
+ }
+ return definedCallingConventions;
+ }
+
+ private TreeSet buildDefinedCallingConventionSet() {
+
+ // Include all calling conventions defined by associated architecure compiler spec
+ TreeSet nameSet = new TreeSet<>();
+ ProgramArchitecture arch = getProgramArchitecture();
+ if (arch != null) {
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ PrototypeModel[] namedCallingConventions = compilerSpec.getCallingConventions();
+ for (PrototypeModel model : namedCallingConventions) {
+ nameSet.add(model.getName());
+ }
+ }
+
+ // Include all generic calling convention names without cspec
+ else {
+ for (GenericCallingConvention conv : GenericCallingConvention.values()) {
+ if (conv == GenericCallingConvention.unknown) {
+ continue; // added below
+ }
+ nameSet.add(conv.getDeclarationName());
+ }
+ }
+
+ return nameSet;
+ }
+
+ @Override
+ public Collection getDefinedCallingConventionNames() {
+ lock.acquire();
+ try {
+ return new ArrayList<>(getDefinedCallingConventionSet());
+ }
+ finally {
+ lock.release();
+ }
+ }
+
+ private Set getKnownCallingConventionSet() {
+ if (knownCallingConventions == null) {
+ knownCallingConventions = buildKnownCallingConventionSet();
+ }
+ return knownCallingConventions;
+ }
+
+ private TreeSet buildKnownCallingConventionSet() {
+ TreeSet nameSet = new TreeSet<>();
+ try {
+ // Include defined call convention names
+ nameSet.addAll(getDefinedCallingConventionSet());
+
+ // Include all calling convention names previously added to DB
+ for (String name : callingConventionAdapter.getCallingConventionNames()) {
+ nameSet.add(name);
+ }
+ }
+ catch (IOException e) {
+ dbError(e);
+ }
+
+ return nameSet;
+ }
+
+ @Override
+ public Collection getKnownCallingConventionNames() {
+ lock.acquire();
+ try {
+ return new ArrayList<>(getKnownCallingConventionSet());
+ }
+ finally {
+ lock.release();
+ }
+ }
+
+ @Override
+ public PrototypeModel getDefaultCallingConvention() {
+ ProgramArchitecture arch = getProgramArchitecture();
+ if (arch != null) {
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ return compilerSpec.getDefaultCallingConvention();
+ }
+ return null;
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention(String name) {
+ ProgramArchitecture arch = getProgramArchitecture();
+ if (arch != null) {
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ return compilerSpec.getCallingConvention(name);
+ }
+ return null;
+ }
+
private boolean checkForSourceArchiveUpdatesNeeded(int openMode, TaskMonitor monitor)
throws IOException, CancelledException {
if (openMode == DBConstants.CREATE || openMode == DBConstants.READ_ONLY) {
@@ -3816,16 +4159,15 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
/**
* This method is only invoked during an upgrade.
*
- * @param compilerSpec compiler spec
* @param monitor task monitor
* @throws CancelledException if task cancelled
*/
- protected void doSourceArchiveUpdates(CompilerSpec compilerSpec, TaskMonitor monitor)
+ protected void doSourceArchiveUpdates(TaskMonitor monitor)
throws CancelledException {
SourceArchiveUpgradeMap upgradeMap = new SourceArchiveUpgradeMap();
for (SourceArchive sourceArchive : getSourceArchives()) {
SourceArchive mappedSourceArchive =
- upgradeMap.getMappedSourceArchive(sourceArchive, compilerSpec);
+ upgradeMap.getMappedSourceArchive(sourceArchive);
if (mappedSourceArchive != null) {
replaceSourceArchive(sourceArchive, mappedSourceArchive);
}
@@ -3854,36 +4196,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* that this program be open with exclusive access before invoking this method to avoid
* excessive merge conflicts with other users.
* @param monitor task monitor
- * @throws CancelledException if operation is cancelled
+ * @throws CancelledException if processing cancelled - data types may not properly reflect
+ * updated compiler specification
*/
public void fixupComposites(TaskMonitor monitor) throws CancelledException {
lock.acquire();
try {
-
- // NOTE: Any composite could be indirectly affected by a component size change
- // based upon type relationships
-
- // NOTE: Composites brought in from archive may have incorrect component size
- // if not aligned and should not be used to guage a primitive size change
-
- // Unfortunately parent table does not track use of primitives so a brute
- // force search is required. Since all composites must be checked, this
- // is combined with the composite graph generation to get ordered list
- // of composites for subsequent size change operation.
-
- List orderedComposites = getAllCompositesInPostDependencyOrder(monitor);
-
- monitor.setProgress(0);
- monitor.setMaximum(orderedComposites.size());
- monitor.setMessage("Updating Datatype Sizes...");
-
- int count = 0;
- for (CompositeDB c : orderedComposites) {
- monitor.checkCanceled();
- c.fixupComponents();
- monitor.setProgress(++count);
- }
-
+ doCompositeFixup(monitor);
}
catch (IOException e) {
dbError(e);
@@ -3892,6 +4211,34 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
lock.release();
}
}
+
+ private void doCompositeFixup(TaskMonitor monitor) throws CancelledException, IOException {
+
+ // NOTE: Any composite could be indirectly affected by a component size change
+ // based upon type relationships. In addition, an architecture change could
+ // alter the size and alignment of any datatype.
+
+ // NOTE: Composites brought in from archive may have incorrect component size
+ // if packing disabled and should not be used to guage a primitive size change
+
+ // Unfortunately parent table does not track use of primitives so a brute
+ // force search is required. Since all composites must be checked, this
+ // is combined with the composite graph generation to get ordered list
+ // of composites for subsequent size change operation.
+
+ List orderedComposites = getAllCompositesInPostDependencyOrder(monitor);
+
+ monitor.setProgress(0);
+ monitor.setMaximum(orderedComposites.size());
+ monitor.setMessage("Updating Datatype Sizes...");
+
+ int count = 0;
+ for (CompositeDB c : orderedComposites) {
+ monitor.checkCanceled();
+ c.fixupComponents();
+ monitor.setProgress(++count);
+ }
+ }
/**
* Get composite base type which corresponds to a specified datatype.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapter.java
index 1644fa4a7c..8a5e73d441 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapter.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import db.*;
import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -45,26 +46,26 @@ abstract class EnumDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of enumeration data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task cancelled
*/
- static EnumDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static EnumDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new EnumDBAdapterV1(handle, true);
+ return new EnumDBAdapterV1(handle, tablePrefix, true);
}
try {
- return new EnumDBAdapterV1(handle, false);
+ return new EnumDBAdapterV1(handle, tablePrefix, false);
}
catch (VersionException e) {
-// if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
-// throw e;
-// }
EnumDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -76,7 +77,7 @@ abstract class EnumDBAdapter {
* @return the read only Enumeration data type table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static EnumDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
+ private static EnumDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
try {
return new EnumDBAdapterV0(handle);
}
@@ -93,28 +94,35 @@ abstract class EnumDBAdapter {
* Upgrades the Enumeration data type table from the oldAdapter's version to the current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task cancelled
*/
- static EnumDBAdapter upgrade(DBHandle handle, EnumDBAdapter oldAdapter)
- throws VersionException, IOException {
+ private static EnumDBAdapter upgrade(DBHandle handle, EnumDBAdapter oldAdapter,
+ String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
EnumDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new EnumDBAdapterV1(tmpHandle, true);
+ tmpAdapter = new EnumDBAdapterV1(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
- EnumDBAdapterV1 newAdapter = new EnumDBAdapterV1(handle, true);
+ EnumDBAdapterV1 newAdapter = new EnumDBAdapterV1(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec, false);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV0.java
index 733b9a9708..3bcd715bfd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV0.java
@@ -28,6 +28,7 @@ import ghidra.util.exception.VersionException;
* Version 0 implementation for accessing the Enumeration database table.
*/
class EnumDBAdapterV0 extends EnumDBAdapter implements RecordTranslator {
+
static final int VERSION = 0;
// Enum Columns
@@ -36,10 +37,11 @@ class EnumDBAdapterV0 extends EnumDBAdapter implements RecordTranslator {
static final int V0_ENUM_CAT_COL = 2;
static final int V0_ENUM_SIZE_COL = 3;
- static final Schema V0_ENUM_SCHEMA = new Schema(
- VERSION, "Enum ID", new Field[] { StringField.INSTANCE, StringField.INSTANCE,
- LongField.INSTANCE, ByteField.INSTANCE },
- new String[] { "Name", "Comment", "Category ID", "Size" });
+// DO NOT REMOVE - this documents the schema used in version 0.
+// static final Schema V0_ENUM_SCHEMA = new Schema(
+// VERSION, "Enum ID", new Field[] { StringField.INSTANCE, StringField.INSTANCE,
+// LongField.INSTANCE, ByteField.INSTANCE },
+// new String[] { "Name", "Comment", "Category ID", "Size" });
private Table enumTable;
@@ -53,16 +55,11 @@ class EnumDBAdapterV0 extends EnumDBAdapter implements RecordTranslator {
enumTable = handle.getTable(ENUM_TABLE_NAME);
if (enumTable == null) {
- throw new VersionException("Missing Table: " + ENUM_TABLE_NAME);
+ throw new VersionException(true);
}
int version = enumTable.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + ENUM_TABLE_NAME +
- " but got " + enumTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(false);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV1.java
index aa37beae15..06b3e7ce1b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDBAdapterV1.java
@@ -24,6 +24,8 @@ import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for accessing the Enumeration database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class EnumDBAdapterV1 extends EnumDBAdapter {
static final int VERSION = 1;
@@ -50,29 +52,27 @@ class EnumDBAdapterV1 extends EnumDBAdapter {
/**
* Gets a version 1 adapter for the Enumeration database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
+ * @throws IOException an IO error occured during table creation
*/
- public EnumDBAdapterV1(DBHandle handle, boolean create) throws VersionException, IOException {
-
+ public EnumDBAdapterV1(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + ENUM_TABLE_NAME;
if (create) {
- enumTable = handle.createTable(ENUM_TABLE_NAME, V1_ENUM_SCHEMA,
+ enumTable = handle.createTable(tableName, V1_ENUM_SCHEMA,
new int[] { V1_ENUM_CAT_COL, V1_ENUM_UNIVERSAL_DT_ID_COL });
}
else {
- enumTable = handle.getTable(ENUM_TABLE_NAME);
+ enumTable = handle.getTable(tableName);
if (enumTable == null) {
- throw new VersionException("Missing Table: " + ENUM_TABLE_NAME);
+ throw new VersionException(true);
}
int version = enumTable.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + ENUM_TABLE_NAME +
- " but got " + enumTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
}
@@ -121,7 +121,7 @@ class EnumDBAdapterV1 extends EnumDBAdapter {
@Override
protected void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(ENUM_TABLE_NAME);
+ handle.deleteTable(enumTable.getName());
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java
index bb0adfeba2..1b0d8403d6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java
@@ -24,6 +24,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -46,18 +47,20 @@ abstract class EnumValueDBAdapter implements RecordTranslator {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of enumeration data type values.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
- static EnumValueDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static EnumValueDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new EnumValueDBAdapterV1(handle, true);
+ return new EnumValueDBAdapterV1(handle, tablePrefix, true);
}
try {
- return new EnumValueDBAdapterV1(handle, false);
+ return new EnumValueDBAdapterV1(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -65,13 +68,13 @@ abstract class EnumValueDBAdapter implements RecordTranslator {
}
EnumValueDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
}
- static EnumValueDBAdapter findReadOnlyAdapter(DBHandle handle) {
+ private static EnumValueDBAdapter findReadOnlyAdapter(DBHandle handle) {
try {
return new EnumValueDBAdapterV0(handle);
}
@@ -85,28 +88,34 @@ abstract class EnumValueDBAdapter implements RecordTranslator {
* version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static EnumValueDBAdapter upgrade(DBHandle handle, EnumValueDBAdapter oldAdapter)
- throws VersionException, IOException {
+ private static EnumValueDBAdapter upgrade(DBHandle handle, EnumValueDBAdapter oldAdapter,
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
EnumValueDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new EnumValueDBAdapterV1(tmpHandle, true);
+ tmpAdapter = new EnumValueDBAdapterV1(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- EnumValueDBAdapter newAdapter = new EnumValueDBAdapterV1(handle, true);
+ EnumValueDBAdapter newAdapter = new EnumValueDBAdapterV1(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
@@ -149,9 +158,7 @@ abstract class EnumValueDBAdapter implements RecordTranslator {
* @param handle the handle used to delete the table
* @throws IOException if there was a problem accessing the database
*/
- void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(ENUM_VALUE_TABLE_NAME);
- }
+ abstract void deleteTable(DBHandle handle) throws IOException;
/**
* Remove the record for the given enum Value ID.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java
index a07ff31f4e..8afa4fb1df 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java
@@ -32,33 +32,33 @@ class EnumValueDBAdapterNoTable extends EnumValueDBAdapter {
* Gets a pre-table version of the adapter for the enumeration data type values database table.
* @param handle handle to the database which doesn't contain the table.
*/
- public EnumValueDBAdapterNoTable(DBHandle handle) {
+ EnumValueDBAdapterNoTable(DBHandle handle) {
// no table needed
}
@Override
- public void createRecord(long enumID, String name, long value, String comment)
+ void createRecord(long enumID, String name, long value, String comment)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public DBRecord getRecord(long valueID) throws IOException {
+ DBRecord getRecord(long valueID) throws IOException {
return null;
}
@Override
- public void updateRecord(DBRecord record) throws IOException {
+ void updateRecord(DBRecord record) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public void removeRecord(long valueID) throws IOException {
+ void removeRecord(long valueID) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public Field[] getValueIdsInEnum(long enumID) throws IOException {
+ Field[] getValueIdsInEnum(long enumID) throws IOException {
return Field.EMPTY_ARRAY;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java
index 87dfa5fd83..68226355e4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java
@@ -39,7 +39,7 @@ class EnumValueDBAdapterV0 extends EnumValueDBAdapter {
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public EnumValueDBAdapterV0(DBHandle handle) throws VersionException {
+ EnumValueDBAdapterV0(DBHandle handle) throws VersionException {
table = handle.getTable(ENUM_VALUE_TABLE_NAME);
if (table == null) {
@@ -55,31 +55,35 @@ class EnumValueDBAdapterV0 extends EnumValueDBAdapter {
}
@Override
- public void createRecord(long enumID, String name, long value, String comment)
+ void createRecord(long enumID, String name, long value, String comment)
throws IOException {
throw new UnsupportedOperationException("Cannot update Version 0");
}
@Override
- public DBRecord getRecord(long valueID) throws IOException {
+ DBRecord getRecord(long valueID) throws IOException {
return translateRecord(table.getRecord(valueID));
}
@Override
- public void removeRecord(long valueID) throws IOException {
+ void removeRecord(long valueID) throws IOException {
throw new UnsupportedOperationException("Cannot remove Version 0");
}
@Override
- public void updateRecord(DBRecord record) throws IOException {
+ void updateRecord(DBRecord record) throws IOException {
throw new UnsupportedOperationException("Cannot update Version 0");
}
@Override
- public Field[] getValueIdsInEnum(long enumID) throws IOException {
+ Field[] getValueIdsInEnum(long enumID) throws IOException {
return table.findRecords(new LongField(enumID), ENUMVAL_ID_COL);
}
+ void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(ENUM_VALUE_TABLE_NAME);
+ }
+
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV1.java
index 1b3b922767..33522350c3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV1.java
@@ -22,6 +22,8 @@ import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for the enumeration tables adapter.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
@@ -36,36 +38,32 @@ class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
/**
* Gets a version 1 adapter for the Enumeration Data Type Values database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if IO error occurs
*/
- public EnumValueDBAdapterV1(DBHandle handle, boolean create)
+ EnumValueDBAdapterV1(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + ENUM_VALUE_TABLE_NAME;
if (create) {
- table = handle.createTable(ENUM_VALUE_TABLE_NAME, SCHEMA, new int[] { ENUMVAL_ID_COL });
+ table = handle.createTable(tableName, SCHEMA, new int[] { ENUMVAL_ID_COL });
}
else {
- table = handle.getTable(ENUM_VALUE_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
throw new VersionException(true);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + ENUM_VALUE_TABLE_NAME +
- " but got " + table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
}
@Override
- public void createRecord(long enumID, String name, long value, String comment)
+ void createRecord(long enumID, String name, long value, String comment)
throws IOException {
DBRecord record = SCHEMA.createRecord(table.getKey());
record.setLongValue(ENUMVAL_ID_COL, enumID);
@@ -76,22 +74,22 @@ class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
}
@Override
- public DBRecord getRecord(long valueID) throws IOException {
+ DBRecord getRecord(long valueID) throws IOException {
return table.getRecord(valueID);
}
@Override
- public void removeRecord(long valueID) throws IOException {
+ void removeRecord(long valueID) throws IOException {
table.deleteRecord(valueID);
}
@Override
- public void updateRecord(DBRecord record) throws IOException {
+ void updateRecord(DBRecord record) throws IOException {
table.putRecord(record);
}
@Override
- public Field[] getValueIdsInEnum(long enumID) throws IOException {
+ Field[] getValueIdsInEnum(long enumID) throws IOException {
return table.findRecords(new LongField(enumID), ENUMVAL_ID_COL);
}
@@ -100,6 +98,10 @@ class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
return table.iterator();
}
+ void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(table.getName());
+ }
+
@Override
public DBRecord translateRecord(DBRecord r) {
return r;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java
index b0fdce3a9b..9c1ccb91d2 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java
@@ -24,12 +24,14 @@ import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsImpl;
import ghidra.program.database.DBObjectCache;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.symbol.SourceType;
-import ghidra.util.Msg;
import ghidra.util.UniversalID;
+import ghidra.util.exception.AssertException;
+import ghidra.util.exception.InvalidInputException;
class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
@@ -108,13 +110,17 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
try {
checkIsValid();
StringBuffer buf = new StringBuffer();
+ if (includeCallingConvention && hasNoReturn()) {
+ buf.append(NORETURN_DISPLAY_STRING);
+ buf.append(" ");
+ }
DataType returnType = getReturnType();
buf.append((returnType != null ? returnType.getDisplayName() : "void"));
buf.append(" ");
if (includeCallingConvention) {
- GenericCallingConvention genericCallingConvention = getGenericCallingConvention();
- if (genericCallingConvention != GenericCallingConvention.unknown) {
- buf.append(genericCallingConvention.name());
+ String callingConvention = getCallingConventionName();
+ if (!Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConvention)) {
+ buf.append(callingConvention);
buf.append(" ");
}
}
@@ -188,7 +194,6 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
lock.acquire();
try {
checkDeleted();
-
setArguments(functionDefinition.getArguments());
try {
setReturnType(functionDefinition.getReturnType());
@@ -197,7 +202,16 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
setReturnType(DEFAULT);
}
setVarArgs(functionDefinition.hasVarArgs());
- setGenericCallingConvention(functionDefinition.getGenericCallingConvention());
+ setNoReturn(functionDefinition.hasNoReturn());
+ try {
+ setCallingConvention(functionDefinition.getCallingConventionName(), false);
+ }
+ catch (InvalidInputException e) {
+ // will not happen
+ }
+ }
+ catch (IOException e) {
+ dataMgr.dbError(e);
}
finally {
lock.release();
@@ -394,8 +408,9 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
(comment != null && comment.equals(myComment))) &&
(DataTypeUtilities.isSameOrEquivalentDataType(getReturnType(),
signature.getReturnType())) &&
- (getGenericCallingConvention() == signature.getGenericCallingConvention()) &&
- (hasVarArgs() == signature.hasVarArgs())) {
+ getCallingConventionName().equals(signature.getCallingConventionName()) &&
+ (hasVarArgs() == signature.hasVarArgs()) &&
+ (hasNoReturn() == signature.hasNoReturn())) {
ParameterDefinition[] args = signature.getArguments();
ParameterDefinition[] thisArgs = this.getArguments();
if (args.length == thisArgs.length) {
@@ -517,6 +532,22 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
}
}
+ @Override
+ public boolean hasNoReturn() {
+ lock.acquire();
+ try {
+ checkIsValid();
+ if (record == null) {
+ return false;
+ }
+ byte flags = record.getByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL);
+ return ((flags & FunctionDefinitionDBAdapter.FUNCTION_DEF_NORETURN_FLAG) != 0);
+ }
+ finally {
+ lock.release();
+ }
+ }
+
@Override
public void setVarArgs(boolean hasVarArgs) {
lock.acquire();
@@ -544,20 +575,17 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
}
@Override
- public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention) {
+ public void setNoReturn(boolean hasNoReturn) {
lock.acquire();
try {
checkDeleted();
- int ordinal = genericCallingConvention.ordinal();
- if (ordinal < 0 ||
- ordinal > FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_MASK) {
- Msg.error(this, "GenericCallingConvention ordinal unsupported: " + ordinal);
- return;
- }
byte flags = record.getByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL);
- flags &=
- ~(FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_MASK << FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_SHIFT);
- flags |= ordinal << FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_SHIFT;
+ if (hasNoReturn) {
+ flags |= FunctionDefinitionDBAdapter.FUNCTION_DEF_NORETURN_FLAG;
+ }
+ else {
+ flags &= ~FunctionDefinitionDBAdapter.FUNCTION_DEF_NORETURN_FLAG;
+ }
record.setByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL, flags);
try {
funDefAdapter.updateRecord(record, true);
@@ -573,18 +601,70 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
}
@Override
- public GenericCallingConvention getGenericCallingConvention() {
+ public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention) {
+ lock.acquire();
+ try {
+ checkDeleted();
+ setCallingConvention(genericCallingConvention.name(), false);
+ }
+ catch (IOException e) {
+ dataMgr.dbError(e);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertException(e);
+ }
+ finally {
+ lock.release();
+ }
+ }
+
+ @Override
+ public void setCallingConvention(String conventionName) throws InvalidInputException {
+ lock.acquire();
+ try {
+ checkDeleted();
+ setCallingConvention(conventionName, true);
+ }
+ catch (IOException e) {
+ dataMgr.dbError(e);
+ }
+ finally {
+ lock.release();
+ }
+ }
+
+ private void setCallingConvention(String conventionName, boolean restrictive)
+ throws InvalidInputException, IOException {
+ byte id = dataMgr.getCallingConventionID(conventionName, restrictive);
+ record.setByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_CALLCONV_COL, id);
+ funDefAdapter.updateRecord(record, true);
+ dataMgr.dataTypeChanged(this, false);
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention() {
+ ProgramArchitecture arch = dataMgr.getProgramArchitecture();
+ if (arch == null) {
+ return null;
+ }
+ String callingConvention = getCallingConventionName();
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ return compilerSpec.getCallingConvention(callingConvention);
+ }
+
+ @Override
+ public String getCallingConventionName() {
lock.acquire();
try {
checkIsValid();
if (record == null) {
- return GenericCallingConvention.unknown;
+ return Function.UNKNOWN_CALLING_CONVENTION_STRING;
}
- byte flags = record.getByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL);
- int ordinal =
- (flags >> FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_SHIFT) &
- FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_MASK;
- return GenericCallingConvention.get(ordinal);
+ byte id = record.getByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_CALLCONV_COL);
+ if (funDefAdapter.usesGenericCallingConventionId()) {
+ return FunctionDefinitionDBAdapter.getGenericCallingConventionName(id);
+ }
+ return dataMgr.getCallingConventionName(id);
}
finally {
lock.release();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapter.java
index cefe1f96bb..d840224fac 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapter.java
@@ -18,68 +18,81 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.program.database.util.DBRecordAdapter;
import ghidra.program.model.data.GenericCallingConvention;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
/**
* Adapter to access the Function Signature Definition database table.
*/
-abstract class FunctionDefinitionDBAdapter {
+abstract class FunctionDefinitionDBAdapter implements DBRecordAdapter {
static final String FUNCTION_DEF_TABLE_NAME = "Function Definitions";
- static final Schema FUN_DEF_SCHEMA = FunctionDefinitionDBAdapterV1.V1_FUN_DEF_SCHEMA;
+ static final Schema FUN_DEF_SCHEMA = FunctionDefinitionDBAdapterV2.V2_FUN_DEF_SCHEMA;
- static final int FUNCTION_DEF_NAME_COL = FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_NAME_COL;
+ static final int FUNCTION_DEF_NAME_COL = FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_NAME_COL;
static final int FUNCTION_DEF_COMMENT_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_COMMENT_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_COMMENT_COL;
static final int FUNCTION_DEF_CAT_ID_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_CAT_ID_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_CAT_ID_COL;
static final int FUNCTION_DEF_RETURN_ID_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_RETURN_ID_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_RETURN_ID_COL;
static final int FUNCTION_DEF_FLAGS_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_FLAGS_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_FLAGS_COL;
+ static final int FUNCTION_DEF_CALLCONV_COL =
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_CALLCONV_COL;
static final int FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL;
static final int FUNCTION_DEF_SOURCE_DT_ID_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_UNIVERSAL_DT_ID_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL;
static final int FUNCTION_DEF_SOURCE_SYNC_TIME_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_SOURCE_SYNC_TIME_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_SOURCE_SYNC_TIME_COL;
static final int FUNCTION_DEF_LAST_CHANGE_TIME_COL =
- FunctionDefinitionDBAdapterV1.V1_FUNCTION_DEF_LAST_CHANGE_TIME_COL;
+ FunctionDefinitionDBAdapterV2.V2_FUNCTION_DEF_LAST_CHANGE_TIME_COL;
static final byte FUNCTION_DEF_VARARG_FLAG = (byte) 0x1; // Bit 0 is flag for "has vararg".
-
- // Flags Bits 1..4 used for generic calling convention ID
- static final int GENERIC_CALLING_CONVENTION_FLAG_MASK = 0xf;
- static final int GENERIC_CALLING_CONVENTION_FLAG_SHIFT = 1;
+ static final byte FUNCTION_DEF_NORETURN_FLAG = (byte) 0x2; // Bit 1 is flag for "has noreturn" (added with V2).
/**
* Gets an adapter for working with the function definition data type database table. The adapter is based
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @param callConvAdapter calling convention table adapter suitable to add new conventions
+ * (e.g., this adapter being used during upgrade operation). Only used when openMode is
+ * {@link DBConstants#UPGRADE} when adding new calling conventions must be permitted.
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of function definition data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
static FunctionDefinitionDBAdapter getAdapter(DBHandle handle, int openMode,
- TaskMonitor monitor) throws VersionException, IOException {
+ String tablePrefix, CallingConventionDBAdapter callConvAdapter, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
+
if (openMode == DBConstants.CREATE) {
- return new FunctionDefinitionDBAdapterV1(handle, true);
+ return new FunctionDefinitionDBAdapterV2(handle, tablePrefix, true);
}
try {
- return new FunctionDefinitionDBAdapterV1(handle, false);
+ return new FunctionDefinitionDBAdapterV2(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
throw e;
}
- FunctionDefinitionDBAdapter adapter = findReadOnlyAdapter(handle);
+ FunctionDefinitionDBAdapter adapter;
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = findReadOnlyAdapter(handle, tablePrefix, callConvAdapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
+ }
+ else {
+ adapter = findReadOnlyAdapter(handle, tablePrefix, null);
}
return adapter;
}
@@ -88,18 +101,27 @@ abstract class FunctionDefinitionDBAdapter {
/**
* Tries to get a read only adapter for the database whose handle is passed to this method.
* @param handle handle to prior version of the database.
+ * @param tablePrefix prefix to be used with default table name
+ * @param callConvAdapter calling convention table adapter suitable to add new conventions
+ * (e.g., this adapter being used during upgrade operation). Should be null if not performing
+ * an upgrade.
* @return the read only Function Definition data type table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static FunctionDefinitionDBAdapter findReadOnlyAdapter(DBHandle handle)
+ private static FunctionDefinitionDBAdapter findReadOnlyAdapter(DBHandle handle,
+ String tablePrefix, CallingConventionDBAdapter callConvAdapter)
throws VersionException {
+ try {
+ return new FunctionDefinitionDBAdapterV1(handle, tablePrefix, callConvAdapter);
+ }
+ catch (VersionException e) {
+ // ignore
+ }
try {
return new FunctionDefinitionDBAdapterV0(handle);
}
catch (VersionException e) {
- if (!e.isUpgradable()) {
- throw e;
- }
+ // ignore
}
return new FunctionDefinitionDBAdapterNoTable(handle);
@@ -109,29 +131,35 @@ abstract class FunctionDefinitionDBAdapter {
* Upgrades the Function Definition data type table from the oldAdapter's version to the current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static FunctionDefinitionDBAdapter upgrade(DBHandle handle,
- FunctionDefinitionDBAdapter oldAdapter) throws VersionException, IOException {
+ private static FunctionDefinitionDBAdapter upgrade(DBHandle handle,
+ FunctionDefinitionDBAdapter oldAdapter, String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
FunctionDefinitionDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new FunctionDefinitionDBAdapterV1(tmpHandle, true);
+ tmpAdapter = new FunctionDefinitionDBAdapterV2(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
- FunctionDefinitionDBAdapterV1 newAdapter =
- new FunctionDefinitionDBAdapterV1(handle, true);
+ FunctionDefinitionDBAdapter newAdapter =
+ new FunctionDefinitionDBAdapterV2(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec, false);
}
@@ -150,7 +178,8 @@ abstract class FunctionDefinitionDBAdapter {
* @param categoryID the ID for the category that contains this data type.
* @param returnDtID the ID of the data type that is returned by this function definition.
* @param hasVarArgs true if this function definition has a variable length argument list.
- * @param genericCallingConvention generic calling convention
+ * @param hasNoReturn true if this function definition has noreturn enabled
+ * @param callingConventionID calling convention ID
* @param sourceArchiveID the ID for the source archive where this data type originated.
* @param sourceDataTypeID the ID of the associated data type in the source archive.
* @param lastChangeTime the time this data type was last changed.
@@ -158,8 +187,8 @@ abstract class FunctionDefinitionDBAdapter {
* @throws IOException if the database can't be accessed.
*/
abstract DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
- boolean hasVarArgs, GenericCallingConvention genericCallingConvention,
- long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException;
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException;
/**
* Gets a function signature definition data type record from the database based on its ID.
@@ -174,7 +203,7 @@ abstract class FunctionDefinitionDBAdapter {
* @return the function definition data type record iterator.
* @throws IOException if the database can't be accessed.
*/
- abstract RecordIterator getRecords() throws IOException;
+ public abstract RecordIterator getRecords() throws IOException;
/**
* Removes the function definition data type record with the specified ID.
@@ -227,4 +256,27 @@ abstract class FunctionDefinitionDBAdapter {
abstract DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID)
throws IOException;
+ /**
+ * Determine if the calling convention ID within record reflects a Generic Calling Convention
+ * ordinal (i.e., true if V1 adapter in use for read-only mode).
+ * See {@link #getGenericCallingConventionName(int)} for Generic Calling Convention name lookup.
+ * @return true if calling convention ID within record reflects a Generic Calling Convention
+ * ordinal.
+ */
+ boolean usesGenericCallingConventionId() {
+ return false;
+ }
+
+ /**
+ * Get old GenericCallingConvention name for specified ordinal value.
+ * @param ordinal old GenericCallingConvention ordinal
+ * @return old GenericCallingConvention name
+ */
+ static String getGenericCallingConventionName(int ordinal) {
+ GenericCallingConvention genericCallingConvention = GenericCallingConvention.get(ordinal);
+ return genericCallingConvention != GenericCallingConvention.unknown
+ ? genericCallingConvention.getDeclarationName()
+ : CompilerSpec.CALLING_CONVENTION_unknown;
+ }
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterNoTable.java
index cd149d79c1..38721f487b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterNoTable.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterNoTable.java
@@ -19,7 +19,6 @@ import java.io.IOException;
import db.*;
import ghidra.program.database.util.EmptyRecordIterator;
-import ghidra.program.model.data.GenericCallingConvention;
import ghidra.util.UniversalID;
/**
@@ -37,15 +36,19 @@ class FunctionDefinitionDBAdapterNoTable extends FunctionDefinitionDBAdapter {
}
@Override
- public DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
- boolean hasVarArgs, GenericCallingConvention genericCallingConvention,
- long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
- throw new UnsupportedOperationException(
- "Not allowed to update version prior to existence of Function Definition Data Types table.");
+ DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
- public DBRecord getRecord(long functionDefID) throws IOException {
+ public int getRecordCount() {
+ return 0;
+ }
+
+ @Override
+ DBRecord getRecord(long functionDefID) throws IOException {
return null;
}
@@ -55,22 +58,22 @@ class FunctionDefinitionDBAdapterNoTable extends FunctionDefinitionDBAdapter {
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long functionDefID) throws IOException {
+ boolean removeRecord(long functionDefID) throws IOException {
return false;
}
@Override
- protected void deleteTable(DBHandle handle) {
+ void deleteTable(DBHandle handle) {
// do nothing
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return Field.EMPTY_ARRAY;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV0.java
index 5697a0069b..34ee8aec09 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV0.java
@@ -18,7 +18,8 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
-import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.util.UniversalID;
import ghidra.util.UniversalIdGenerator;
import ghidra.util.exception.VersionException;
@@ -28,12 +29,15 @@ import ghidra.util.exception.VersionException;
*/
class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
implements RecordTranslator {
+
static final int VERSION = 0;
+
static final int V0_FUNCTION_DEF_NAME_COL = 0;
static final int V0_FUNCTION_DEF_COMMENT_COL = 1;
static final int V0_FUNCTION_DEF_CAT_ID_COL = 2;
static final int V0_FUNCTION_DEF_RETURN_ID_COL = 3;
static final int V0_FUNCTION_DEF_FLAGS_COL = 4;
+
// DO NOT REMOVE WHAT'S BELOW - this documents the schema used in version 0.
// static final Schema V0_FUN_DEF_SCHEMA = new Schema(VERSION, "Data Type ID",
// new Class[] {StringField.class, StringField.class,
@@ -51,33 +55,31 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public FunctionDefinitionDBAdapterV0(DBHandle handle) throws VersionException {
+ FunctionDefinitionDBAdapterV0(DBHandle handle) throws VersionException {
table = handle.getTable(FUNCTION_DEF_TABLE_NAME);
if (table == null) {
- throw new VersionException("Missing Table: " + FUNCTION_DEF_TABLE_NAME);
+ throw new VersionException(true);
}
- int version = table.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + FUNCTION_DEF_TABLE_NAME +
- " but got " + table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
@Override
- public DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
- boolean hasVarArgs, GenericCallingConvention genericCallingConvention,
- long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
- throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
- " of " + FUNCTION_DEF_TABLE_NAME + " table.");
+ public int getRecordCount() {
+ return table.getRecordCount();
}
@Override
- public DBRecord getRecord(long functionDefID) throws IOException {
+ DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ DBRecord getRecord(long functionDefID) throws IOException {
return translateRecord(table.getRecord(functionDefID));
}
@@ -87,22 +89,22 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
- public boolean removeRecord(long functionDefID) throws IOException {
- return table.deleteRecord(functionDefID);
+ boolean removeRecord(long functionDefID) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
- protected void deleteTable(DBHandle handle) throws IOException {
+ void deleteTable(DBHandle handle) throws IOException {
handle.deleteTable(FUNCTION_DEF_TABLE_NAME);
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), V0_FUNCTION_DEF_CAT_ID_COL);
}
@@ -111,6 +113,11 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
return Field.EMPTY_ARRAY;
}
+ @Override
+ DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
+ return null;
+ }
+
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
@@ -123,6 +130,8 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
rec.setLongValue(FUNCTION_DEF_RETURN_ID_COL,
oldRec.getLongValue(V0_FUNCTION_DEF_RETURN_ID_COL));
rec.setByteValue(FUNCTION_DEF_FLAGS_COL, oldRec.getByteValue(V0_FUNCTION_DEF_FLAGS_COL));
+ rec.setByteValue(FUNCTION_DEF_CALLCONV_COL,
+ DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID);
rec.setLongValue(FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL, DataTypeManager.LOCAL_ARCHIVE_KEY);
rec.setLongValue(FUNCTION_DEF_SOURCE_DT_ID_COL, UniversalIdGenerator.nextID().getValue());
rec.setLongValue(FUNCTION_DEF_SOURCE_SYNC_TIME_COL, DataType.NO_SOURCE_SYNC_TIME);
@@ -130,9 +139,4 @@ class FunctionDefinitionDBAdapterV0 extends FunctionDefinitionDBAdapter
return rec;
}
- @Override
- DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
- return null;
- }
-
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV1.java
index b3fa3de5ba..3c89118faa 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV1.java
@@ -16,19 +16,24 @@
package ghidra.program.database.data;
import java.io.IOException;
-import java.util.Date;
import db.*;
-import ghidra.program.model.data.GenericCallingConvention;
-import ghidra.util.Msg;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.util.UniversalID;
+import ghidra.util.UniversalIdGenerator;
import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for accessing the Function Signature Definition database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
-class FunctionDefinitionDBAdapterV1 extends FunctionDefinitionDBAdapter {
+class FunctionDefinitionDBAdapterV1 extends FunctionDefinitionDBAdapter
+ implements RecordTranslator {
+
static final int VERSION = 1;
+
static final int V1_FUNCTION_DEF_NAME_COL = 0;
static final int V1_FUNCTION_DEF_COMMENT_COL = 1;
static final int V1_FUNCTION_DEF_CAT_ID_COL = 2;
@@ -38,116 +43,91 @@ class FunctionDefinitionDBAdapterV1 extends FunctionDefinitionDBAdapter {
static final int V1_FUNCTION_DEF_UNIVERSAL_DT_ID_COL = 6;
static final int V1_FUNCTION_DEF_SOURCE_SYNC_TIME_COL = 7;
static final int V1_FUNCTION_DEF_LAST_CHANGE_TIME_COL = 8;
- static final Schema V1_FUN_DEF_SCHEMA = new Schema(VERSION, "Data Type ID",
- new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
- LongField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
- LongField.INSTANCE, LongField.INSTANCE },
- new String[] { "Name", "Comment", "Category ID", "Return Type ID", "Flags",
- "Source Archive ID", "Source Data Type ID", "Source Sync Time", "Last Change Time" });
+
+// DO NOT REMOVE WHAT'S BELOW - this documents the schema used in version 0.
+// static final Schema V1_FUN_DEF_SCHEMA = new Schema(VERSION, "Data Type ID",
+// new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
+// LongField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
+// LongField.INSTANCE, LongField.INSTANCE },
+// new String[] { "Name", "Comment", "Category ID", "Return Type ID", "Flags",
+// "Source Archive ID", "Source Data Type ID", "Source Sync Time", "Last Change Time" });
+
+ // Flags Bits 1..4 used for generic calling convention ID
+ private static final int GENERIC_CALLING_CONVENTION_FLAG_MASK = 0xf;
+ private static final int GENERIC_CALLING_CONVENTION_FLAG_SHIFT = 1;
private Table table;
+ private CallingConventionDBAdapter callConvAdapter; // must be null if not performing upgrade
/**
- * Gets a version 1 adapter for the Function Definition database table.
+ * Gets a version 1 read-only adapter for the Function Definition database table.
* @param handle handle to the database containing the table.
- * @param create true if this constructor should create the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param callConvAdapter calling convention table adapter suitable to add new conventions
+ * (e.g., this adapter being used during upgrade operation). Should be null if not performing
+ * an upgrade in which case calling convention IDs will reflect generic convention ordinals.
+ *
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
- public FunctionDefinitionDBAdapterV1(DBHandle handle, boolean create)
- throws VersionException, IOException {
-
- if (create) {
- table = handle.createTable(FUNCTION_DEF_TABLE_NAME, V1_FUN_DEF_SCHEMA,
- new int[] { V1_FUNCTION_DEF_CAT_ID_COL, V1_FUNCTION_DEF_UNIVERSAL_DT_ID_COL });
+ public FunctionDefinitionDBAdapterV1(DBHandle handle, String tablePrefix,
+ CallingConventionDBAdapter callConvAdapter) throws VersionException {
+ this.callConvAdapter = callConvAdapter;
+ String tableName = tablePrefix + FUNCTION_DEF_TABLE_NAME;
+ table = handle.getTable(tableName);
+ if (table == null) {
+ throw new VersionException(true);
}
- else {
- table = handle.getTable(FUNCTION_DEF_TABLE_NAME);
- if (table == null) {
- throw new VersionException("Missing Table: " + FUNCTION_DEF_TABLE_NAME);
- }
- int version = table.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " +
- FUNCTION_DEF_TABLE_NAME + " but got " + table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
- }
+ int version = table.getSchema().getVersion();
+ if (version != VERSION) {
+ throw new VersionException(version < VERSION);
}
}
@Override
- public DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
- boolean hasVarArgs, GenericCallingConvention genericCallingConvention,
- long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
- byte flags = (byte) 0;
- if (hasVarArgs) {
- flags |= FunctionDefinitionDBAdapter.FUNCTION_DEF_VARARG_FLAG;
- }
- if (genericCallingConvention != null) {
- int ordinal = genericCallingConvention.ordinal();
- if (ordinal < 0 ||
- ordinal > FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_MASK) {
- Msg.error(this, "GenericCallingConvention ordinal unsupported: " + ordinal);
- }
- else {
- flags |=
- ordinal << FunctionDefinitionDBAdapter.GENERIC_CALLING_CONVENTION_FLAG_SHIFT;
- }
- }
- long tableKey = table.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.FUNCTION_DEF, tableKey);
- DBRecord record = V1_FUN_DEF_SCHEMA.createRecord(key);
-
- record.setString(V1_FUNCTION_DEF_NAME_COL, name);
- record.setString(V1_FUNCTION_DEF_COMMENT_COL, comments);
- record.setLongValue(V1_FUNCTION_DEF_CAT_ID_COL, categoryID);
- record.setLongValue(V1_FUNCTION_DEF_RETURN_ID_COL, returnDtID);
- record.setByteValue(V1_FUNCTION_DEF_FLAGS_COL, flags);
- record.setLongValue(V1_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
- record.setLongValue(V1_FUNCTION_DEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
- record.setLongValue(V1_FUNCTION_DEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
- record.setLongValue(V1_FUNCTION_DEF_LAST_CHANGE_TIME_COL, lastChangeTime);
- table.putRecord(record);
- return record;
+ boolean usesGenericCallingConventionId() {
+ return callConvAdapter == null;
}
@Override
- public DBRecord getRecord(long functionDefID) throws IOException {
- return table.getRecord(functionDefID);
+ public int getRecordCount() {
+ return table.getRecordCount();
}
@Override
- public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
- if (setLastChangeTime) {
- record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_LAST_CHANGE_TIME_COL,
- (new Date()).getTime());
- }
- table.putRecord(record);
+ DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ DBRecord getRecord(long functionDefID) throws IOException {
+ return translateRecord(table.getRecord(functionDefID));
+ }
+
+ @Override
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
public RecordIterator getRecords() throws IOException {
- return table.iterator();
+ return new TranslatedRecordIterator(table.iterator(), this);
}
@Override
- public boolean removeRecord(long functionDefID) throws IOException {
- return table.deleteRecord(functionDefID);
+ boolean removeRecord(long functionDefID) throws IOException {
+ throw new UnsupportedOperationException();
}
@Override
- protected void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(FUNCTION_DEF_TABLE_NAME);
+ void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(table.getName());
}
@Override
- public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), V1_FUNCTION_DEF_CAT_ID_COL);
}
@@ -169,4 +149,48 @@ class FunctionDefinitionDBAdapterV1 extends FunctionDefinitionDBAdapter {
}
return null;
}
+
+ @Override
+ public DBRecord translateRecord(DBRecord oldRec) {
+ if (oldRec == null) {
+ return null;
+ }
+ DBRecord rec = FunctionDefinitionDBAdapter.FUN_DEF_SCHEMA.createRecord(oldRec.getKey());
+ rec.setString(FUNCTION_DEF_NAME_COL, oldRec.getString(V1_FUNCTION_DEF_NAME_COL));
+ rec.setString(FUNCTION_DEF_COMMENT_COL, oldRec.getString(V1_FUNCTION_DEF_COMMENT_COL));
+ rec.setLongValue(FUNCTION_DEF_CAT_ID_COL, oldRec.getLongValue(V1_FUNCTION_DEF_CAT_ID_COL));
+ rec.setLongValue(FUNCTION_DEF_RETURN_ID_COL, oldRec.getLongValue(V1_FUNCTION_DEF_RETURN_ID_COL));
+
+ byte flags = oldRec.getByteValue(V1_FUNCTION_DEF_FLAGS_COL);
+ int mask = GENERIC_CALLING_CONVENTION_FLAG_MASK << GENERIC_CALLING_CONVENTION_FLAG_SHIFT;
+ int genericCallConvId = (flags & mask) >> GENERIC_CALLING_CONVENTION_FLAG_SHIFT;
+ flags &= (byte) (~mask); // clear old flag bits used for calling convention
+
+ byte callingConventionId = DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID;
+ try {
+ if (callConvAdapter == null) {
+ // Must use old generic calling convention ordinal as ID
+ callingConventionId = (byte) genericCallConvId;
+ }
+ else {
+ // It is expected that an open transaction exists during upgrade use
+ // and that all records are upgraded prior to general use
+ String callingConvention = getGenericCallingConventionName(genericCallConvId);
+ callingConventionId = callConvAdapter.getCallingConventionId(callingConvention,
+ cc -> {
+ /* ignore */ });
+ }
+ }
+ catch (IOException e) {
+ // ignore - use unknown convention ID
+ }
+
+ rec.setByteValue(FUNCTION_DEF_FLAGS_COL, flags);
+ rec.setByteValue(FUNCTION_DEF_CALLCONV_COL, callingConventionId);
+ rec.setLongValue(FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL, DataTypeManager.LOCAL_ARCHIVE_KEY);
+ rec.setLongValue(FUNCTION_DEF_SOURCE_DT_ID_COL, UniversalIdGenerator.nextID().getValue());
+ rec.setLongValue(FUNCTION_DEF_SOURCE_SYNC_TIME_COL, DataType.NO_SOURCE_SYNC_TIME);
+ rec.setLongValue(FUNCTION_DEF_LAST_CHANGE_TIME_COL, DataType.NO_LAST_CHANGE_TIME);
+ return rec;
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV2.java
new file mode 100644
index 0000000000..e57118173b
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDBAdapterV2.java
@@ -0,0 +1,164 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.database.data;
+
+import java.io.IOException;
+import java.util.Date;
+
+import db.*;
+import ghidra.util.UniversalID;
+import ghidra.util.exception.VersionException;
+
+/**
+ * Version 2 implementation for accessing the Function Signature Definition database table.
+ */
+class FunctionDefinitionDBAdapterV2 extends FunctionDefinitionDBAdapter {
+
+ static final int VERSION = 2;
+ static final int V2_FUNCTION_DEF_NAME_COL = 0;
+ static final int V2_FUNCTION_DEF_COMMENT_COL = 1;
+ static final int V2_FUNCTION_DEF_CAT_ID_COL = 2;
+ static final int V2_FUNCTION_DEF_RETURN_ID_COL = 3;
+ static final int V2_FUNCTION_DEF_FLAGS_COL = 4;
+ static final int V2_FUNCTION_DEF_CALLCONV_COL = 5;
+ static final int V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL = 6;
+ static final int V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL = 7;
+ static final int V2_FUNCTION_DEF_SOURCE_SYNC_TIME_COL = 8;
+ static final int V2_FUNCTION_DEF_LAST_CHANGE_TIME_COL = 9;
+ static final Schema V2_FUN_DEF_SCHEMA = new Schema(VERSION, "Data Type ID",
+ new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
+ LongField.INSTANCE, ByteField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE,
+ LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
+ new String[] { "Name", "Comment", "Category ID", "Return Type ID", "Flags", "Call Conv ID",
+ "Source Archive ID", "Source Data Type ID", "Source Sync Time", "Last Change Time" });
+
+ private Table table;
+
+ /**
+ * Gets a version 2 adapter for the Function Definition database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create true if this constructor should create the table.
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
+ * @throws IOException if an IO error occurs
+ */
+ public FunctionDefinitionDBAdapterV2(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + FUNCTION_DEF_TABLE_NAME;
+ if (create) {
+ table = handle.createTable(tableName, V2_FUN_DEF_SCHEMA,
+ new int[] { V2_FUNCTION_DEF_CAT_ID_COL, V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL });
+ }
+ else {
+ table = handle.getTable(tableName);
+ if (table == null) {
+ throw new VersionException(true);
+ }
+ int version = table.getSchema().getVersion();
+ if (version != VERSION) {
+ throw new VersionException(version < VERSION);
+ }
+ }
+ }
+
+ @Override
+ public int getRecordCount() {
+ return table.getRecordCount();
+ }
+
+ @Override
+ DBRecord createRecord(String name, String comments, long categoryID, long returnDtID,
+ boolean hasNoReturn, boolean hasVarArgs, byte callingConventionID, long sourceArchiveID,
+ long sourceDataTypeID, long lastChangeTime) throws IOException {
+ byte flags = (byte) 0;
+ if (hasVarArgs) {
+ flags |= FUNCTION_DEF_VARARG_FLAG;
+ }
+ if (hasNoReturn) {
+ flags |= FUNCTION_DEF_NORETURN_FLAG;
+ }
+ long tableKey = table.getKey();
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.FUNCTION_DEF, tableKey);
+ DBRecord record = V2_FUN_DEF_SCHEMA.createRecord(key);
+
+ record.setString(V2_FUNCTION_DEF_NAME_COL, name);
+ record.setString(V2_FUNCTION_DEF_COMMENT_COL, comments);
+ record.setLongValue(V2_FUNCTION_DEF_CAT_ID_COL, categoryID);
+ record.setLongValue(V2_FUNCTION_DEF_RETURN_ID_COL, returnDtID);
+ record.setByteValue(V2_FUNCTION_DEF_FLAGS_COL, flags);
+ record.setByteValue(V2_FUNCTION_DEF_CALLCONV_COL, callingConventionID);
+ record.setLongValue(V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
+ record.setLongValue(V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
+ record.setLongValue(V2_FUNCTION_DEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
+ record.setLongValue(V2_FUNCTION_DEF_LAST_CHANGE_TIME_COL, lastChangeTime);
+ table.putRecord(record);
+ return record;
+ }
+
+ @Override
+ DBRecord getRecord(long functionDefID) throws IOException {
+ return table.getRecord(functionDefID);
+ }
+
+ @Override
+ void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
+ if (setLastChangeTime) {
+ record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_LAST_CHANGE_TIME_COL,
+ (new Date()).getTime());
+ }
+ table.putRecord(record);
+ }
+
+ @Override
+ public RecordIterator getRecords() throws IOException {
+ return table.iterator();
+ }
+
+ @Override
+ boolean removeRecord(long functionDefID) throws IOException {
+ return table.deleteRecord(functionDefID);
+ }
+
+ @Override
+ void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(table.getName());
+ }
+
+ @Override
+ Field[] getRecordIdsInCategory(long categoryID) throws IOException {
+ return table.findRecords(new LongField(categoryID), V2_FUNCTION_DEF_CAT_ID_COL);
+ }
+
+ @Override
+ Field[] getRecordIdsForSourceArchive(long archiveID) throws IOException {
+ return table.findRecords(new LongField(archiveID), V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL);
+ }
+
+ @Override
+ DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
+ Field[] keys = table.findRecords(new LongField(datatypeID.getValue()),
+ V2_FUNCTION_DEF_UNIVERSAL_DT_ID_COL);
+
+ for (int i = 0; i < keys.length; i++) {
+ DBRecord record = table.getRecord(keys[i]);
+ if (record.getLongValue(V2_FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
+ return record;
+ }
+ }
+ return null;
+ }
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapter.java
index ef141fc156..6dc3b77bdd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapter.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -39,22 +40,24 @@ abstract class FunctionParameterAdapter {
FunctionParameterAdapterV1.V1_PARAMETER_DT_LENGTH_COL;
/**
- * Gets an adapter for working with the function definition parameters database table. The adapter is based
- * on the version of the database associated with the specified database handle and the openMode.
+ * Gets an adapter for working with the function definition parameters database table.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of function definition parameters.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
- static FunctionParameterAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static FunctionParameterAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new FunctionParameterAdapterV1(handle, true);
+ return new FunctionParameterAdapterV1(handle, tablePrefix, true);
}
try {
- return new FunctionParameterAdapterV1(handle, false);
+ return new FunctionParameterAdapterV1(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -62,7 +65,7 @@ abstract class FunctionParameterAdapter {
}
FunctionParameterAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -74,7 +77,8 @@ abstract class FunctionParameterAdapter {
* @return the read only Function Definition Parameters table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static FunctionParameterAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
+ private static FunctionParameterAdapter findReadOnlyAdapter(DBHandle handle)
+ throws VersionException {
try {
return new FunctionParameterAdapterV0(handle);
}
@@ -91,28 +95,35 @@ abstract class FunctionParameterAdapter {
* current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static FunctionParameterAdapter upgrade(DBHandle handle, FunctionParameterAdapter oldAdapter)
- throws VersionException, IOException {
+ private static FunctionParameterAdapter upgrade(DBHandle handle,
+ FunctionParameterAdapter oldAdapter, String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
FunctionParameterAdapter tmpAdapter = null;
try {
- tmpAdapter = new FunctionParameterAdapterV1(tmpHandle, true);
+ tmpAdapter = new FunctionParameterAdapterV1(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- FunctionParameterAdapterV1 newAdapter = new FunctionParameterAdapterV1(handle, true);
+ FunctionParameterAdapterV1 newAdapter =
+ new FunctionParameterAdapterV1(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV0.java
index b23f18271c..fb0b4dfaee 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV0.java
@@ -26,6 +26,7 @@ import ghidra.util.exception.VersionException;
class FunctionParameterAdapterV0 extends FunctionParameterAdapter implements RecordTranslator {
static final int VERSION = 0;
+
// Parameter Table Columns
static final int V0_PARAMETER_PARENT_ID_COL = 0;
static final int V0_PARAMETER_DT_ID_COL = 1;
@@ -52,34 +53,15 @@ class FunctionParameterAdapterV0 extends FunctionParameterAdapter implements Rec
if (parameterTable == null) {
throw new VersionException(true);
}
- int version = parameterTable.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + PARAMETER_TABLE_NAME +
- " but got " + parameterTable.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (parameterTable.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
@Override
public DBRecord createRecord(long dataTypeID, long parentID, int ordinal, String name,
String comment, int dtLength) throws IOException {
-
- long tableKey = parameterTable.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.PARAMETER, tableKey);
- DBRecord record = V0_PARAMETER_SCHEMA.createRecord(key);
- record.setLongValue(V0_PARAMETER_PARENT_ID_COL, parentID);
- record.setLongValue(V0_PARAMETER_DT_ID_COL, dataTypeID);
- record.setString(V0_PARAMETER_NAME_COL, name);
- record.setString(V0_PARAMETER_COMMENT_COL, comment);
- record.setIntValue(V0_PARAMETER_ORDINAL_COL, ordinal);
- parameterTable.putRecord(record);
- return record;
+ throw new UnsupportedOperationException();
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV1.java
index f67a7ea810..3a063a4550 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionParameterAdapterV1.java
@@ -22,6 +22,8 @@ import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for accessing the Function Definition Parameters database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class FunctionParameterAdapterV1 extends FunctionParameterAdapter {
static final int VERSION = 1;
@@ -45,30 +47,27 @@ class FunctionParameterAdapterV1 extends FunctionParameterAdapter {
/**
* Gets a version 1 adapter for the Function Definition Parameter database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
+ * @throws IOException if an IO error occurs
*/
- public FunctionParameterAdapterV1(DBHandle handle, boolean create)
+ public FunctionParameterAdapterV1(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + PARAMETER_TABLE_NAME;
if (create) {
- table = handle.createTable(PARAMETER_TABLE_NAME, V1_PARAMETER_SCHEMA,
+ table = handle.createTable(tableName, V1_PARAMETER_SCHEMA,
new int[] { V1_PARAMETER_PARENT_ID_COL });
}
else {
- table = handle.getTable(PARAMETER_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
throw new VersionException(true);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + PARAMETER_TABLE_NAME +
- " but got " + table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
}
@@ -76,12 +75,7 @@ class FunctionParameterAdapterV1 extends FunctionParameterAdapter {
@Override
public DBRecord createRecord(long dataTypeID, long parentID, int ordinal, String name,
String comment, int dtLength) throws IOException {
-
- long tableKey = table.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.PARAMETER, tableKey);
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.PARAMETER, table.getKey());
DBRecord record = V1_PARAMETER_SCHEMA.createRecord(key);
record.setLongValue(V1_PARAMETER_PARENT_ID_COL, parentID);
record.setLongValue(V1_PARAMETER_DT_ID_COL, dataTypeID);
@@ -115,7 +109,7 @@ class FunctionParameterAdapterV1 extends FunctionParameterAdapter {
@Override
protected void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(PARAMETER_TABLE_NAME);
+ handle.deleteTable(table.getName());
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildAdapter.java
index 6b2b8daabb..4a7b69a1a4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildAdapter.java
@@ -21,7 +21,6 @@ import java.util.Set;
import db.DBConstants;
import db.DBHandle;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
/**
*
@@ -31,16 +30,25 @@ import ghidra.util.task.TaskMonitor;
*
*/
abstract class ParentChildAdapter {
- static final String TABLE_NAME = "DT_PARENT_CHILD";
+ static final String PARENT_CHILD_TABLE_NAME = "DT_PARENT_CHILD";
- static ParentChildAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
+ /**
+ * Gets an adapter for working with the function definition parameters database table.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @return the adapter for accessing the table of function definition parameters.
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is trouble accessing the database.
+ */
+ static ParentChildAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix)
throws VersionException, IOException {
if (openMode == DBConstants.CREATE) {
- return new ParentChildDBAdapterV0(handle, true);
+ return new ParentChildDBAdapterV0(handle, tablePrefix, true);
}
try {
- return new ParentChildDBAdapterV0(handle, false);
+ return new ParentChildDBAdapterV0(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -48,20 +56,20 @@ abstract class ParentChildAdapter {
}
ParentChildAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix);
}
return adapter;
}
}
- static ParentChildAdapter findReadOnlyAdapter(DBHandle handle) {
+ private static ParentChildAdapter findReadOnlyAdapter(DBHandle handle) {
return new ParentChildDBAdapterNoTable(handle);
}
- static ParentChildAdapter upgrade(DBHandle handle, ParentChildAdapter oldAdapter)
- throws VersionException, IOException {
+ private static ParentChildAdapter upgrade(DBHandle handle, ParentChildAdapter oldAdapter,
+ String tablePrefix) throws VersionException, IOException {
- ParentChildDBAdapterV0 adapter = new ParentChildDBAdapterV0(handle, true);
+ ParentChildDBAdapterV0 adapter = new ParentChildDBAdapterV0(handle, tablePrefix, true);
adapter.setNeedsInitializing();
return adapter;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildDBAdapterV0.java
index d2278d3f40..e9f4a22984 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ParentChildDBAdapterV0.java
@@ -22,6 +22,11 @@ import java.util.Set;
import db.*;
import ghidra.util.exception.VersionException;
+/**
+ * Version 0 implementation for accessing the datatype parent/child database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
+ */
class ParentChildDBAdapterV0 extends ParentChildAdapter {
private static final int VERSION = 0;
@@ -35,19 +40,28 @@ class ParentChildDBAdapterV0 extends ParentChildAdapter {
private Table table;
private boolean needsInitializing = false;
- ParentChildDBAdapterV0(DBHandle handle, boolean create) throws VersionException, IOException {
-
+ /**
+ * Gets a version 1 adapter for the datatype parent/child database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create true if this constructor should create the table.
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
+ * @throws IOException if an IO error occurs
+ */
+ ParentChildDBAdapterV0(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + PARENT_CHILD_TABLE_NAME;
if (create) {
- table = handle.createTable(TABLE_NAME, V0_SCHEMA, new int[] { PARENT_COL, CHILD_COL });
+ table = handle.createTable(tableName, V0_SCHEMA, new int[] { PARENT_COL, CHILD_COL });
}
else {
- table = handle.getTable(TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
throw new VersionException(true);
}
- if (table.getSchema().getVersion() != 0) {
- throw new VersionException("Expected version 0 for table " + TABLE_NAME +
- " but got " + table.getSchema().getVersion());
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapter.java
index 3d45173f83..95e3f9bfdc 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapter.java
@@ -18,6 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -36,14 +37,26 @@ abstract class PointerDBAdapter implements RecordTranslator {
static final int PTR_CATEGORY_COL = 1;
static final int PTR_LENGTH_COL = 2;
- static PointerDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ /**
+ * Gets an adapter for working with the enumeration data type values database table. The adapter is based
+ * on the version of the database associated with the specified database handle and the openMode.
+ * @param handle handle to the database to be accessed.
+ * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor the monitor to use for displaying status or for canceling.
+ * @return the adapter for accessing the table of enumeration data type values.
+ * @throws VersionException if the database handle's version doesn't match the expected version.
+ * @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
+ */
+ static PointerDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new PointerDBAdapterV2(handle, true);
+ return new PointerDBAdapterV2(handle, tablePrefix, true);
}
try {
- return new PointerDBAdapterV2(handle, false);
+ return new PointerDBAdapterV2(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -51,7 +64,7 @@ abstract class PointerDBAdapter implements RecordTranslator {
}
PointerDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter, monitor);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -67,22 +80,25 @@ abstract class PointerDBAdapter implements RecordTranslator {
}
static PointerDBAdapter upgrade(DBHandle handle, PointerDBAdapter oldAdapter,
- TaskMonitor monitor) throws VersionException, IOException {
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
PointerDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new PointerDBAdapterV2(tmpHandle, true);
+ tmpAdapter = new PointerDBAdapterV2(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- PointerDBAdapter newAdapter = new PointerDBAdapterV2(handle, true);
+ PointerDBAdapter newAdapter = new PointerDBAdapterV2(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapterV2.java
index 3890b5e22a..ec5a2a82b4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapterV2.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDBAdapterV2.java
@@ -20,36 +20,46 @@ import java.io.IOException;
import db.*;
import ghidra.util.exception.VersionException;
+/**
+ * Version 2 implementation for accessing the PointerDB database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
+ */
class PointerDBAdapterV2 extends PointerDBAdapter {
final static int VERSION = 2;
private Table table;
- PointerDBAdapterV2(DBHandle handle, boolean create) throws VersionException, IOException {
-
+ /**
+ * Gets a version 2 adapter for the PointerDB database table.
+ * @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
+ * @param create true if this constructor should create the table.
+ * @throws VersionException if the the table's version does not match the expected version
+ * for this adapter.
+ * @throws IOException if IO error occurs
+ */
+ PointerDBAdapterV2(DBHandle handle, String tablePrefix, boolean create)
+ throws VersionException, IOException {
+ String tableName = tablePrefix + POINTER_TABLE_NAME;
if (create) {
- table = handle.createTable(POINTER_TABLE_NAME, SCHEMA, new int[] { PTR_CATEGORY_COL });
+ table = handle.createTable(tableName, SCHEMA, new int[] { PTR_CATEGORY_COL });
}
else {
- table = handle.getTable(POINTER_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + POINTER_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
- else if (table.getSchema().getVersion() != VERSION) {
- int version = table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(true);
- }
- throw new VersionException(VersionException.NEWER_VERSION, false);
+ int version = table.getSchema().getVersion();
+ if (version != VERSION) {
+ throw new VersionException(version < VERSION);
}
}
}
@Override
DBRecord createRecord(long dataTypeID, long categoryID, int length) throws IOException {
- long tableKey = table.getKey();
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.POINTER, tableKey);
-
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.POINTER, table.getKey());
DBRecord record = SCHEMA.createRecord(key);
record.setLongValue(PTR_DT_ID_COL, dataTypeID);
record.setLongValue(PTR_CATEGORY_COL, categoryID);
@@ -85,7 +95,7 @@ class PointerDBAdapterV2 extends PointerDBAdapter {
@Override
void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(POINTER_TABLE_NAME);
+ handle.deleteTable(table.getName());
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java
index 20cde8ca57..d004105cd5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java
@@ -50,6 +50,9 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
* @param handle open database handle
* @param addrMap the address map (instance settings not supported if null)
* @param openMode the program open mode (see {@link DBConstants})
+ * @param tablePrefix DB table prefix to be applied to all associated table names. This
+ * need only be specified when using multiple instances with the same
+ * DB handle (null or empty string for no-prefix).
* @param errHandler the database io error handler
* @param lock the program synchronization lock
* @param monitor the progress monitor
@@ -57,18 +60,18 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
* @throws VersionException if the database does not match the expected version.
* @throws IOException if a database IO error occurs.
*/
- public ProgramBasedDataTypeManagerDB(DBHandle handle, AddressMap addrMap, int openMode,
- ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
+ protected ProgramBasedDataTypeManagerDB(DBHandle handle, AddressMap addrMap, int openMode,
+ String tablePrefix, ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
throws CancelledException, VersionException, IOException {
- super(handle, addrMap, openMode, errHandler, lock, monitor);
+ super(handle, addrMap, openMode, tablePrefix, errHandler, lock, monitor);
}
protected void initializeOtherAdapters(int openMode, TaskMonitor monitor)
throws CancelledException, IOException, VersionException {
if (addrMap != null) {
instanceSettingsAdapter =
- SettingsDBAdapter.getAdapter(INSTANCE_SETTINGS_TABLE_NAME, dbHandle, openMode,
- addrMap, monitor);
+ SettingsDBAdapter.getAdapter(tablePrefix + INSTANCE_SETTINGS_TABLE_NAME, dbHandle,
+ openMode, addrMap, monitor);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java
index 2db4e3c414..2f73ce80fd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java
@@ -31,8 +31,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ChangeManager;
import ghidra.util.*;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.exception.VersionException;
+import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
@@ -61,7 +60,7 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB
public ProgramDataTypeManager(DBHandle handle, AddressMap addrMap, int openMode,
ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
throws CancelledException, VersionException, IOException {
- super(handle, addrMap, openMode, errHandler, lock, monitor);
+ super(handle, addrMap, openMode, null, errHandler, lock, monitor);
upgrade = (openMode == DBConstants.UPGRADE);
}
@@ -79,8 +78,16 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB
@Override
public void setProgram(ProgramDB p) {
this.program = p;
- dataOrganization = p.getCompilerSpec().getDataOrganization();
- removeOldFileNameList();
+ try {
+ setProgramArchitecture(p, p.getSymbolTable().getVariableStorageManager(), false,
+ TaskMonitor.DUMMY);
+ }
+ catch (CancelledException e) {
+ throw new AssertException(e); // unexpected - no IO performed
+ }
+ catch (IOException e) {
+ errHandler.dbError(e);
+ }
if (upgrade) {
removeOldFileNameList();
}
@@ -102,11 +109,22 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB
public void programReady(int openMode, int currentRevision, TaskMonitor monitor)
throws IOException, CancelledException {
if (openMode == DBConstants.UPGRADE) {
- doSourceArchiveUpdates(program.getCompilerSpec(), monitor);
+ doSourceArchiveUpdates(monitor);
migrateOldFlexArrayComponentsIfRequired(monitor);
}
}
+ /**
+ * Update program-architecture information following a language upgrade/change
+ * @param monitor task monitor
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if task monitor cancelled
+ */
+ public void languageChanged(TaskMonitor monitor) throws IOException, CancelledException {
+ setProgramArchitecture(program, program.getSymbolTable().getVariableStorageManager(), true,
+ monitor);
+ }
+
@Override
public String getName() {
return program.getName();
@@ -296,12 +314,4 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB
return ArchiveType.PROGRAM;
}
- @Override
- public DataOrganization getDataOrganization() {
- if (dataOrganization == null) {
- dataOrganization = program.getCompilerSpec().getDataOrganization();
- }
- return dataOrganization;
- }
-
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapter.java
index debb9cae8c..645ada0f5f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapter.java
@@ -22,6 +22,7 @@ import java.util.List;
import db.*;
import ghidra.program.model.data.SourceArchive;
import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -32,8 +33,10 @@ import ghidra.util.task.TaskMonitor;
*/
abstract class SourceArchiveAdapter {
- static final String TABLE_NAME = "Data Type Archive IDs";
+ static final String SOURCE_ARCHIVE_TABLE_NAME = "Data Type Archive IDs";
+
static final Schema SCHEMA = SourceArchiveAdapterV0.V0_SCHEMA;
+
// Data Type Archive ID Columns
static final int ARCHIVE_ID_DOMAIN_FILE_ID_COL =
SourceArchiveAdapterV0.V0_ARCHIVE_ID_DOMAIN_FILE_ID_COL;
@@ -52,18 +55,20 @@ abstract class SourceArchiveAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of data type archive ID entries.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
- static SourceArchiveAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static SourceArchiveAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor) throws VersionException, IOException, CancelledException {
if (openMode == DBConstants.CREATE) {
- return new SourceArchiveAdapterV0(handle, true);
+ return new SourceArchiveAdapterV0(handle, tablePrefix, true);
}
try {
- return new SourceArchiveAdapterV0(handle, false);
+ return new SourceArchiveAdapterV0(handle, tablePrefix, false);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -71,7 +76,7 @@ abstract class SourceArchiveAdapter {
}
SourceArchiveAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -83,7 +88,8 @@ abstract class SourceArchiveAdapter {
* @return the read only Data Type Archive ID table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static SourceArchiveAdapter findReadOnlyAdapter(DBHandle handle) {
+ private static SourceArchiveAdapter findReadOnlyAdapter(DBHandle handle)
+ throws VersionException {
return new SourceArchiveAdapterNoTable(handle);
}
@@ -95,24 +101,28 @@ abstract class SourceArchiveAdapter {
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static SourceArchiveAdapter upgrade(DBHandle handle, SourceArchiveAdapter oldAdapter)
- throws VersionException, IOException {
+ private static SourceArchiveAdapter upgrade(DBHandle handle, SourceArchiveAdapter oldAdapter,
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
SourceArchiveAdapter tmpAdapter = null;
try {
- tmpAdapter = new SourceArchiveAdapterV0(tmpHandle, true);
+ tmpAdapter = new SourceArchiveAdapterV0(tmpHandle, tablePrefix, true);
Iterator it = oldAdapter.getRecords().iterator();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
- SourceArchiveAdapter newAdapter = new SourceArchiveAdapterV0(handle, true);
+ SourceArchiveAdapter newAdapter = new SourceArchiveAdapterV0(handle, tablePrefix, true);
it = tmpAdapter.getRecords().iterator();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
@@ -125,22 +135,33 @@ abstract class SourceArchiveAdapter {
}
}
+ /**
+ * Delete table from database
+ * @param handle database handle
+ * @throws IOException if IO error occurs
+ */
abstract void deleteTable(DBHandle handle) throws IOException;
/**
* Creates a new source archive record using the information from the given source archive.
* @param sourceArchive the source archive from which to get the archive information.
+ * @return new archive record which corresponds to specified sourceArchive
+ * @throws IOException if IO error occurs
*/
abstract DBRecord createRecord(SourceArchive sourceArchive) throws IOException;
/**
* Returns a list containing all records in the archive table
- * @return
+ * @return list of all archive records
+ * @throws IOException if IO error occurs
*/
abstract List getRecords() throws IOException;
/**
* Returns the record for the given key (sourceArchiveID)
+ * @param key ID of data type archive record
+ * @return archive record or null if not found
+ * @throws IOException if IO error occurs
*/
abstract DBRecord getRecord(long key) throws IOException;
@@ -153,7 +174,7 @@ abstract class SourceArchiveAdapter {
/**
* Remove the record for the given data type archive ID.
- * @param dataTypeArchiveID ID of data type archive record to delete
+ * @param key ID of data type archive record to delete
* @return true if the record was deleted
* @throws IOException if there was a problem accessing the database
*/
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapterV0.java
index f1dd2e7951..906fb60ad3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveAdapterV0.java
@@ -26,6 +26,8 @@ import ghidra.util.exception.VersionException;
/**
* Version 0 implementation for accessing the Data Type Archive ID database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
static final int VERSION = 0;
@@ -45,38 +47,33 @@ class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
/**
* Gets a version 1 adapter for the Data Type Archive ID table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
+ * @throws IOException if an IO errr occurs
*/
- public SourceArchiveAdapterV0(DBHandle handle, boolean create)
+ public SourceArchiveAdapterV0(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + SOURCE_ARCHIVE_TABLE_NAME;
if (create) {
- table = handle.createTable(TABLE_NAME, V0_SCHEMA);
-
+ table = handle.createTable(tableName, V0_SCHEMA);
createRecordForLocalManager();
}
else {
- table = handle.getTable(TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
throw new VersionException(true);
}
- int version = table.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + TABLE_NAME +
- " but got " + table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
}
/**
- *
- * @throws IOException
+ * Create standard entry which corresponds to local datatype manager
+ * @throws IOException if an IO error occurs
*/
private void createRecordForLocalManager() throws IOException {
DBRecord record = V0_SCHEMA.createRecord(DataTypeManager.LOCAL_ARCHIVE_KEY);
@@ -129,6 +126,7 @@ class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
@Override
protected void deleteTable(DBHandle handle) throws IOException {
+ handle.deleteTable(table.getName());
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveUpgradeMap.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveUpgradeMap.java
index 3b59b71c03..745a69d886 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveUpgradeMap.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/SourceArchiveUpgradeMap.java
@@ -19,7 +19,6 @@ import java.util.HashMap;
import java.util.Map;
import ghidra.program.model.data.*;
-import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.CompilerSpecID;
import ghidra.util.UniversalID;
@@ -31,8 +30,8 @@ public class SourceArchiveUpgradeMap {
new long[] { OLD_CLIB_ARCHIVE_ID, OLD_NTDDK_ARCHIVE_ID, OLD_WINDOWS_ARCHIVE_ID };
private CompilerSpecID WINDOWS_CSPEC_ID = new CompilerSpecID("windows");
- private Map windowsMap;
- private Map defaultMap;
+
+ private Map oldArchiveRemappings;
public SourceArchiveUpgradeMap() {
@@ -47,34 +46,25 @@ public class SourceArchiveUpgradeMap {
SourceArchive newDefaultClibArchive =
new SourceArchiveImpl(NEW_DEFAULT_CLIB_ARCHIVE_ID, NEW_DEFAULT_CLIB_ARCHIVE_NAME);
- // create mapping for WINDOWS
- windowsMap = new HashMap();
- windowsMap.put(new UniversalID(OLD_CLIB_ARCHIVE_ID), newWindowsArchive);
- windowsMap.put(new UniversalID(OLD_WINDOWS_ARCHIVE_ID), newWindowsArchive);
- windowsMap.put(new UniversalID(OLD_NTDDK_ARCHIVE_ID), newWindowsArchive);
+ oldArchiveRemappings = new HashMap();
- // create defaultMap
- defaultMap = new HashMap();
- defaultMap.put(new UniversalID(OLD_CLIB_ARCHIVE_ID), newDefaultClibArchive);
+ // create mappings for old Windows archives
+ oldArchiveRemappings.put(new UniversalID(OLD_CLIB_ARCHIVE_ID), newWindowsArchive);
+ oldArchiveRemappings.put(new UniversalID(OLD_WINDOWS_ARCHIVE_ID), newWindowsArchive);
+ oldArchiveRemappings.put(new UniversalID(OLD_NTDDK_ARCHIVE_ID), newWindowsArchive);
+
+ // create mappings for old default archives
+ oldArchiveRemappings.put(new UniversalID(OLD_CLIB_ARCHIVE_ID), newDefaultClibArchive);
+
+ // create mappings for old removed archives
SourceArchive removedSourceArchive = new SourceArchiveImpl();
- defaultMap.put(new UniversalID(OLD_WINDOWS_ARCHIVE_ID), removedSourceArchive);
- defaultMap.put(new UniversalID(OLD_NTDDK_ARCHIVE_ID), removedSourceArchive);
+ oldArchiveRemappings.put(new UniversalID(OLD_WINDOWS_ARCHIVE_ID), removedSourceArchive);
+ oldArchiveRemappings.put(new UniversalID(OLD_NTDDK_ARCHIVE_ID), removedSourceArchive);
}
- public SourceArchive getMappedSourceArchive(SourceArchive sourceArchive,
- CompilerSpec compiler) {
- if (compiler != null) {
- CompilerSpecID compilerSpecID = compiler.getCompilerSpecID();
- if (WINDOWS_CSPEC_ID.equals(compilerSpecID)) {
- SourceArchive replacementSourceArchive =
- windowsMap.get(sourceArchive.getSourceArchiveID());
- if (replacementSourceArchive != null) {
- return replacementSourceArchive;
- }
- }
- }
- return defaultMap.get(sourceArchive.getSourceArchiveID());
+ public SourceArchive getMappedSourceArchive(SourceArchive sourceArchive) {
+ return oldArchiveRemappings.get(sourceArchive.getSourceArchiveID());
}
public static boolean isReplacedSourceArchive(long id) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java
index 6fbbece0c1..19987ba5ac 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java
@@ -376,7 +376,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
componentName, comment);
}
- // handle aligned bitfield insertion
+ // handle aligned bitfield insertion (packing enabled)
BitFieldDataType bitFieldDt = new BitFieldDBDataType(baseDataType, bitSize, 0);
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
}
@@ -1860,7 +1860,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
@Override
protected void fixupComponents() throws IOException {
boolean isPacked = isPackingEnabled();
- boolean didChange = false;
+ boolean forceRepack = false;
+ boolean changed = false;
boolean warn = false;
int n = components.size();
for (int i = 0; i < n; i++) {
@@ -1870,7 +1871,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
continue; // length can't change
}
if (dt instanceof BitFieldDataType) {
- // TODO: could get messy
+ // Always repack if bitfields present and packing enabled
+ forceRepack |= isPacked;
continue;
}
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength();
@@ -1881,18 +1883,18 @@ class StructureDB extends CompositeDB implements StructureInternal {
if (dtcLen != length) {
if (isPacked) {
dtc.setLength(length, true);
- didChange = true;
+ changed = true;
}
else if (length < dtcLen) {
dtc.setLength(length, true);
shiftOffsets(i + 1, dtcLen - length, 0); // updates structure record and last modified time
- didChange = true;
+ changed = true;
}
else if (length > dtcLen) {
int consumed = consumeBytesAfter(i, length - dtcLen); // updates component record
if (consumed > 0) {
shiftOffsets(i + 1, -consumed, 0); // updates structure record and last modified time
- didChange = true;
+ changed = true;
}
}
if (dtc.getLength() != length) {
@@ -1900,11 +1902,14 @@ class StructureDB extends CompositeDB implements StructureInternal {
}
}
}
- if (didChange) {
+ if (changed || forceRepack) {
// Do not notify parents - must be invoked in composite dependency order
- repack(false, false);
- compositeAdapter.updateRecord(record, true);
- dataMgr.dataTypeChanged(this, false);
+ // Treat as an auto-change as a result of data organization change
+ changed |= repack(true, false);
+ }
+ if (changed) {
+ compositeAdapter.updateRecord(record, false); // force record update
+ dataMgr.dataTypeChanged(this, true);
}
if (warn) {
Msg.warn(this, "Failed to resize one or more structure components: " + getPathName());
@@ -2238,10 +2243,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
checkAncestry(replacementDt);
}
catch (Exception e) {
- // TODO: should we use Undefined1 instead to avoid cases where DEFAULT datatype can
- // not be used (bitfield, aligned structure, etc.)
- // TODO: failing silently is rather hidden
- replacementDt = DataType.DEFAULT;
+ // TODO: should we flag bad replacement
+ replacementDt = isPackingEnabled() ? Undefined1DataType.dataType : DataType.DEFAULT;
}
boolean changed = false;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapter.java
index a2746aa88a..f8a07fd032 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapter.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import db.*;
import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@@ -51,15 +52,18 @@ abstract class TypedefDBAdapter {
* on the version of the database associated with the specified database handle and the openMode.
* @param handle handle to the database to be accessed.
* @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE).
+ * @param tablePrefix prefix to be used with default table name
* @param monitor the monitor to use for displaying status or for canceling.
* @return the adapter for accessing the table of Typedef data types.
* @throws VersionException if the database handle's version doesn't match the expected version.
* @throws IOException if there is trouble accessing the database.
+ * @throws CancelledException if task is cancelled
*/
- static TypedefDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
+ static TypedefDBAdapter getAdapter(DBHandle handle, int openMode, String tablePrefix,
+ TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
try {
- return new TypedefDBAdapterV2(handle, openMode == DBConstants.CREATE);
+ return new TypedefDBAdapterV2(handle, tablePrefix, openMode == DBConstants.CREATE);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@@ -67,7 +71,7 @@ abstract class TypedefDBAdapter {
}
TypedefDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
+ adapter = upgrade(handle, adapter, tablePrefix, monitor);
}
return adapter;
}
@@ -79,7 +83,7 @@ abstract class TypedefDBAdapter {
* @return the read only Typedef table adapter
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
- static TypedefDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
+ private static TypedefDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
try {
return new TypedefDBAdapterV1(handle);
}
@@ -93,28 +97,34 @@ abstract class TypedefDBAdapter {
* Upgrades the Typedef data type table from the oldAdapter's version to the current version.
* @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded.
+ * @param tablePrefix prefix to be used with default table name
+ * @param monitor task monitor
* @return the adapter for the new upgraded version of the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if the database can't be read or written.
+ * @throws CancelledException if task is cancelled
*/
- static TypedefDBAdapter upgrade(DBHandle handle, TypedefDBAdapter oldAdapter)
- throws VersionException, IOException {
+ private static TypedefDBAdapter upgrade(DBHandle handle, TypedefDBAdapter oldAdapter,
+ String tablePrefix, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
TypedefDBAdapter tmpAdapter = null;
try {
- tmpAdapter = new TypedefDBAdapterV2(tmpHandle, true);
+ tmpAdapter = new TypedefDBAdapterV2(tmpHandle, tablePrefix, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
- TypedefDBAdapter newAdapter = new TypedefDBAdapterV2(handle, true);
+ TypedefDBAdapter newAdapter = new TypedefDBAdapterV2(handle, tablePrefix, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
+ monitor.checkCanceled();
DBRecord rec = it.next();
newAdapter.updateRecord(rec, false);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV0.java
index 6eaa2a2d3c..3bbac383f5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV0.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV0.java
@@ -28,15 +28,19 @@ import ghidra.util.exception.VersionException;
* Version 0 implementation for accessing the Typedef database table.
*/
class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
+
static final int VERSION = 0;
+
private static final int V0_TYPEDEF_DT_ID_COL = 0;
private static final int V0_TYPEDEF_NAME_COL = 1;
private static final int V0_TYPEDEF_CAT_COL = 2;
+
// DO NOT REMOVE WHAT'S BELOW - this documents the schema used in version 0.
// static final Schema V0_SCHEMA = new Schema(VERSION, "Typedef ID",
// new Class[] {LongField.class, StringField.class,
// LongField.class},
// new String[] {"Data Type ID", "Name", "Category ID"});
+
private Table table;
/**
@@ -51,14 +55,8 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
if (table == null) {
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
}
- int version = table.getSchema().getVersion();
- if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
- " but got " + table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ if (table.getSchema().getVersion() != VERSION) {
+ throw new VersionException(false);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV1.java
index d89c386594..dde15e7e51 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV1.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV1.java
@@ -25,7 +25,9 @@ import ghidra.util.exception.VersionException;
* Version 1 implementation for accessing the Typedef database table.
*/
class TypedefDBAdapterV1 extends TypedefDBAdapter implements RecordTranslator {
+
static final int VERSION = 1;
+
static final int V1_TYPEDEF_DT_ID_COL = 0;
static final int V1_TYPEDEF_NAME_COL = 1;
static final int V1_TYPEDEF_CAT_COL = 2;
@@ -40,6 +42,7 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter implements RecordTranslator {
// LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
// new String[] { "Data Type ID", "Name", "Category ID", "Source Archive ID",
// "Universal Data Type ID", "Source Sync Time", "Last Change Time" });
+
private Table table;
/**
@@ -56,12 +59,7 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter implements RecordTranslator {
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
- " but got " + table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV2.java
index 39226fa23d..d67dd66eb5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV2.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDBAdapterV2.java
@@ -24,9 +24,13 @@ import ghidra.util.exception.VersionException;
/**
* Version 2 implementation for accessing the Typedef database table.
+ *
+ * NOTE: Use of tablePrefix introduced with this adapter version.
*/
class TypedefDBAdapterV2 extends TypedefDBAdapter {
+
static final int VERSION = 2;
+
static final int V2_TYPEDEF_DT_ID_COL = 0;
static final int V2_TYPEDEF_FLAGS_COL = 1;
static final int V2_TYPEDEF_NAME_COL = 2;
@@ -35,61 +39,53 @@ class TypedefDBAdapterV2 extends TypedefDBAdapter {
static final int V2_TYPEDEF_UNIVERSAL_DT_ID_COL = 5;
static final int V2_TYPEDEF_SOURCE_SYNC_TIME_COL = 6;
static final int V2_TYPEDEF_LAST_CHANGE_TIME_COL = 7;
+
static final Schema V2_SCHEMA = new Schema(VERSION, "Typedef ID",
new Field[] { LongField.INSTANCE, ShortField.INSTANCE, StringField.INSTANCE,
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
LongField.INSTANCE },
new String[] { "Data Type ID", "Flags", "Name", "Category ID", "Source Archive ID",
"Universal Data Type ID", "Source Sync Time", "Last Change Time" });
+
private Table table;
/**
* Gets a version 1 adapter for the Typedef database table.
* @param handle handle to the database containing the table.
+ * @param tablePrefix prefix to be used with default table name
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if IO error occurs
*/
- public TypedefDBAdapterV2(DBHandle handle, boolean create)
+ public TypedefDBAdapterV2(DBHandle handle, String tablePrefix, boolean create)
throws VersionException, IOException {
-
+ String tableName = tablePrefix + TYPEDEF_TABLE_NAME;
if (create) {
- table = handle.createTable(TYPEDEF_TABLE_NAME, V2_SCHEMA,
+ table = handle.createTable(tableName, V2_SCHEMA,
new int[] { V2_TYPEDEF_CAT_COL, V2_TYPEDEF_UNIVERSAL_DT_ID_COL });
}
else {
- table = handle.getTable(TYPEDEF_TABLE_NAME);
+ table = handle.getTable(tableName);
if (table == null) {
- throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
+ throw new VersionException("Missing Table: " + tableName);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
- String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
- " but got " + table.getSchema().getVersion();
- if (version < VERSION) {
- throw new VersionException(msg, VersionException.OLDER_VERSION, true);
- }
- throw new VersionException(msg, VersionException.NEWER_VERSION, false);
+ throw new VersionException(version < VERSION);
}
}
}
@Override
void deleteTable(DBHandle handle) throws IOException {
- handle.deleteTable(TYPEDEF_TABLE_NAME);
+ handle.deleteTable(table.getName());
}
@Override
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
-
- long tableKey = table.getKey();
-// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
-// tableKey = DataManager.VOID_DATATYPE_ID +1;
-// }
- long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, tableKey);
-
+ long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, table.getKey());
DBRecord record = V2_SCHEMA.createRecord(key);
record.setLongValue(V2_TYPEDEF_DT_ID_COL, dataTypeID);
record.setShortValue(V2_TYPEDEF_FLAGS_COL, flags);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java
index dd8869a237..3072a52070 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java
@@ -497,12 +497,10 @@ class UnionDB extends CompositeDB implements UnionInternal {
}
}
if (changed) {
- // NOTE: since we do not retain our external alignment we have no way of knowing if
- // it has changed, so we must assume it has if we are an aligned union
- // Do not notify parents
- if (!repack(false, false)) {
- dataMgr.dataTypeChanged(this, false);
- }
+ // Do not notify parents - must be invoked in composite dependency order
+ // Treat as an auto-change as a result of data organization change
+ repack(true, false);
+ dataMgr.dataTypeChanged(this, true);
}
}
@@ -562,8 +560,8 @@ class UnionDB extends CompositeDB implements UnionInternal {
DataType baseDataType = bitfieldDt.getBaseDataType();
baseDataType = resolve(baseDataType);
- // Both aligned and non-packed bitfields use same adjustment
- // non-packed must force bitfield placement at byte offset 0
+ // Both packed and non-packed bitfields use same adjustment
+ // Non-packed must force bitfield placement at byte offset 0
int bitSize = bitfieldDt.getDeclaredBitSize();
int effectiveBitSize =
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
@@ -795,9 +793,8 @@ class UnionDB extends CompositeDB implements UnionInternal {
checkAncestry(replacementDt);
}
catch (Exception e) {
- // TODO: should we use Undefined instead since we do not support
- // DEFAULT in Unions
- replacementDt = DataType.DEFAULT;
+ // TODO: should we flag bad replacement
+ replacementDt = Undefined1DataType.dataType;
}
boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapter.java
deleted file mode 100644
index 0c7bcc1e45..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/* ###
- * IP: GHIDRA
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package ghidra.program.database.function;
-
-import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
-
-import java.io.IOException;
-
-import db.*;
-
-/**
- * Adapter to access the Function Calling Conventions tables.
- */
-abstract class CallingConventionDBAdapter {
- static final byte UNKNOWN_CALLING_CONVENTION_ID = (byte) 0;
- static final byte DEFAULT_CALLING_CONVENTION_ID = (byte) 1;
-
- static final Schema CALLING_CONVENTION_SCHEMA =
- CallingConventionDBAdapterV0.V0_CALLING_CONVENTION_SCHEMA;
- // Calling Convention Columns
- static final int CALLING_CONVENTION_NAME_COL =
- CallingConventionDBAdapterV0.V0_CALLING_CONVENTION_NAME_COL;
-
- static CallingConventionDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
- throws VersionException, IOException {
- if (openMode == DBConstants.CREATE) {
- return new CallingConventionDBAdapterV0(handle, true);
- }
- try {
- return new CallingConventionDBAdapterV0(handle, false);
- }
- catch (VersionException e) {
- if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
- throw e;
- }
- CallingConventionDBAdapter adapter = findReadOnlyAdapter(handle);
- if (openMode == DBConstants.UPGRADE) {
- adapter = upgrade(handle, adapter);
- }
- return adapter;
- }
- }
-
- static CallingConventionDBAdapter findReadOnlyAdapter(DBHandle handle) throws IOException {
- try {
- return new CallingConventionDBAdapterV0(handle, false);
- }
- catch (VersionException e) {
- }
-
- return new CallingConventionDBAdapterNoTable();
- }
-
- static CallingConventionDBAdapter upgrade(DBHandle handle, CallingConventionDBAdapter oldAdapter)
- throws VersionException, IOException {
- return new CallingConventionDBAdapterV0(handle, true);
- }
-
- abstract DBRecord createCallingConventionRecord(String name) throws IOException;
-
- abstract DBRecord getCallingConventionRecord(byte callingConventionID) throws IOException;
-
- abstract DBRecord getCallingConventionRecord(String name) throws IOException;
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterNoTable.java
deleted file mode 100644
index ac7033ef0e..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterNoTable.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ###
- * IP: GHIDRA
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package ghidra.program.database.function;
-
-import java.io.IOException;
-
-import db.DBRecord;
-
-/**
- * Adapter needed for a read-only version of Program that is not going
- * to be upgraded, and there is no Calling Convention table in the Program.
- *
- */
-class CallingConventionDBAdapterNoTable extends CallingConventionDBAdapter {
-
- /**
- *
- */
- public CallingConventionDBAdapterNoTable() {
- }
-
- /* (non-Javadoc)
- * @see ghidra.program.database.function.CallingConventionDBAdapter#createCallingConventionRecord(java.lang.String)
- */
- @Override
- public DBRecord createCallingConventionRecord(String name) throws IOException {
- return null;
- }
-
- /* (non-Javadoc)
- * @see ghidra.program.database.function.CallingConventionDBAdapter#getCallingConventionRecord(byte)
- */
- @Override
- public DBRecord getCallingConventionRecord(byte callingConventionID) throws IOException {
- return null;
- }
-
- /* (non-Javadoc)
- * @see ghidra.program.database.function.CallingConventionDBAdapter#getCallingConventionRecord(java.lang.String)
- */
- @Override
- public DBRecord getCallingConventionRecord(String name) throws IOException {
- return null;
- }
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterV0.java
deleted file mode 100644
index 8e9f9e2942..0000000000
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/CallingConventionDBAdapterV0.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/* ###
- * IP: GHIDRA
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package ghidra.program.database.function;
-
-import java.io.IOException;
-
-import db.*;
-import ghidra.util.exception.VersionException;
-
-/**
- * Version 0 implementation for the calling conventions tables adapter.
- *
- */
-class CallingConventionDBAdapterV0 extends CallingConventionDBAdapter {
-
- static final String CALLING_CONVENTION_TABLE_NAME = "Calling Conventions";
-
- // Calling Convention Columns
- // Key field is the Calling convention ID, which is a Byte field.
- static final int V0_CALLING_CONVENTION_NAME_COL = 0;
-
- static final Schema V0_CALLING_CONVENTION_SCHEMA = new Schema(0, ByteField.INSTANCE, "ID",
- new Field[] { StringField.INSTANCE }, new String[] { "Name" });
-
- private Table callingConventionTable;
-
- /**
- * Constructor
- *
- */
- public CallingConventionDBAdapterV0(DBHandle handle, boolean create)
- throws VersionException, IOException {
-
- if (create) {
- // No additional indexed fields.
- callingConventionTable = handle.createTable(CALLING_CONVENTION_TABLE_NAME,
- V0_CALLING_CONVENTION_SCHEMA, new int[] {});
- }
- else {
- callingConventionTable = handle.getTable(CALLING_CONVENTION_TABLE_NAME);
- if (callingConventionTable == null) {
- throw new VersionException(true);
- }
- if (callingConventionTable.getSchema().getVersion() != 0) {
- throw new VersionException(VersionException.NEWER_VERSION, false);
- }
- }
- }
-
- @Override
- public DBRecord createCallingConventionRecord(String name) throws IOException {
- byte key = getFirstAvailableKey();
- DBRecord record = V0_CALLING_CONVENTION_SCHEMA.createRecord(new ByteField(key));
- record.setString(V0_CALLING_CONVENTION_NAME_COL, name);
- callingConventionTable.putRecord(record);
- return record;
- }
-
- /**
- * Get the first unused key value. Remember 0 is reserved for unknown and 1 for default.
- * @return the first available key. This is a number for 2 to 255.
- * @throws IOException if there are no more available keys.
- */
- private byte getFirstAvailableKey() throws IOException {
- byte key = 2;
- for (; key < 256; key++) {
- DBRecord record = getCallingConventionRecord(key);
- if (record == null) {
- return key;
- }
- }
- if (key >= 256) {
- throw new IOException("No more keys available for calling conventions.");
- }
- return key;
- }
-
- @Override
- public DBRecord getCallingConventionRecord(byte callingConventionID) throws IOException {
- return callingConventionTable.getRecord(new ByteField(callingConventionID));
- }
-
- @Override
- public DBRecord getCallingConventionRecord(String name) throws IOException {
- RecordIterator iterator = callingConventionTable.iterator();
- while (iterator.hasNext()) {
- DBRecord record = iterator.next();
- String callingConventionName = record.getString(V0_CALLING_CONVENTION_NAME_COL);
- if (callingConventionName.equals(name)) {
- return record;
- }
- }
- return null;
- }
-
-}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapterV3.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapterV3.java
index 0d64b65a70..f45946f00b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapterV3.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapterV3.java
@@ -15,15 +15,15 @@
*/
package ghidra.program.database.function;
+import java.io.IOException;
+
+import db.*;
+import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.database.map.AddressMap;
import ghidra.program.model.listing.Function;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.VersionException;
-import java.io.IOException;
-
-import db.*;
-
class FunctionAdapterV3 extends FunctionAdapter {
//
@@ -116,7 +116,7 @@ class FunctionAdapterV3 extends FunctionAdapter {
rec.setByteValue(FUNCTION_FLAGS_COL, getSignatureSourceFlagBits(SourceType.DEFAULT));
rec.setLongValue(RETURN_DATA_TYPE_ID_COL, returnDataTypeId);
rec.setByteValue(CALLING_CONVENTION_ID_COL,
- CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID);
+ DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID);
rec.setIntValue(STACK_PURGE_COL, Function.UNKNOWN_STACK_DEPTH_CHANGE);
table.putRecord(rec);
return rec;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
index fa60100546..5cf78369dc 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
@@ -229,11 +229,6 @@ public class FunctionDB extends DatabaseObject implements Function {
return super.hashCode();
}
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Object#toString()
- */
@Override
public String toString() {
return getName(true);
@@ -826,7 +821,7 @@ public class FunctionDB extends DatabaseObject implements Function {
PrototypeModel callingConvention = getCallingConvention();
if (callingConvention == null) {
- callingConvention = getDefaultCallingConvention();
+ callingConvention = manager.getDefaultCallingConvention();
}
if (callingConvention == null) {
return;
@@ -1310,6 +1305,7 @@ public class FunctionDB extends DatabaseObject implements Function {
source);
}
+
/**
* Increment updateInProgressCount indicating that an update operation is in progress and
* that any attempted refresh should be deferred. The updateRefreshReqd flag will be set
@@ -2517,11 +2513,6 @@ public class FunctionDB extends DatabaseObject implements Function {
}
}
- /*
- * (non-Javadoc)
- *
- * @see ghidra.program.model.listing.Function#getCallingConvention()
- */
@Override
public PrototypeModel getCallingConvention() {
String name = getCallingConventionName();
@@ -2535,11 +2526,6 @@ public class FunctionDB extends DatabaseObject implements Function {
return functionMgr.getCallingConvention(name);
}
- /*
- * (non-Javadoc)
- *
- * @see ghidra.program.model.listing.Function#getCallingConventionName()
- */
@Override
public String getCallingConventionName() {
manager.lock.acquire();
@@ -2551,14 +2537,13 @@ public class FunctionDB extends DatabaseObject implements Function {
return thunkedFunction.getCallingConventionName();
}
byte callingConventionID = rec.getByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL);
- if (callingConventionID == CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID) {
+ if (callingConventionID == DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID) {
return Function.UNKNOWN_CALLING_CONVENTION_STRING;
}
- if (callingConventionID == CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID) {
+ if (callingConventionID == DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID) {
return Function.DEFAULT_CALLING_CONVENTION_STRING;
}
- String name = manager.getCallingConventionName(callingConventionID);
- return name != null ? name : UNKNOWN_CALLING_CONVENTION_STRING;
+ return program.getDataTypeManager().getCallingConventionName(callingConventionID);
}
finally {
manager.lock.release();
@@ -2569,36 +2554,16 @@ public class FunctionDB extends DatabaseObject implements Function {
if (thunkedFunction != null) {
return thunkedFunction.getRealCallingConventionName();
}
- String name = null;
byte callingConventionID = rec.getByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL);
- if (callingConventionID != CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID &&
- callingConventionID != CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID) {
- name = manager.getCallingConventionName(callingConventionID);
+ String name = program.getDataTypeManager().getCallingConventionName(callingConventionID);
+ if (UNKNOWN_CALLING_CONVENTION_STRING.equals(name) ||
+ DEFAULT_CALLING_CONVENTION_STRING.equals(name)) {
+ name = null;
}
// null returned for unknown or default calling convention
return name;
}
- private PrototypeModel getDefaultCallingConvention() {
- CompilerSpec compilerSpec = getProgram().getCompilerSpec();
- if (compilerSpec != null) {
- return compilerSpec.getDefaultCallingConvention();
- }
- return null;
- }
-
- @Override
- public String getDefaultCallingConventionName() {
- PrototypeModel defaultPrototype = getDefaultCallingConvention();
- if (defaultPrototype != null) {
- String defaultPrototypeName = defaultPrototype.getName();
- if (defaultPrototypeName != null) {
- return defaultPrototypeName;
- }
- }
- return Function.DEFAULT_CALLING_CONVENTION_STRING;
- }
-
@Override
public void setCallingConvention(String name) throws InvalidInputException {
manager.lock.acquire();
@@ -2610,36 +2575,38 @@ public class FunctionDB extends DatabaseObject implements Function {
return;
}
- byte newCallingConventionID = manager.getCallingConventionID(name);
+ byte newCallingConventionID =
+ program.getDataTypeManager().getCallingConventionID(name, true);
byte oldCallingConventionID =
rec.getByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL);
- if (oldCallingConventionID != newCallingConventionID) {
+ if (oldCallingConventionID == newCallingConventionID) {
+ return; // no change
+ }
+ loadVariables();
+
+ rec.setByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL, newCallingConventionID);
+ manager.getFunctionAdapter().updateFunctionRecord(rec);
+
+ boolean hasCustomStorage = hasCustomVariableStorage();
+ if (!hasCustomStorage) {
+ // remove 'this' param if switching to __thiscall with dynamic storage
+ removeExplicitThisParameter();
+ }
+
+ frame.setInvalid();
+
+ if (!hasCustomStorage) {
+ createClassStructIfNeeded(); // TODO: How should thunks within Class namespace be handled?
loadVariables();
-
- rec.setByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL, newCallingConventionID);
- manager.getFunctionAdapter().updateFunctionRecord(rec);
-
- boolean hasCustomStorage = hasCustomVariableStorage();
- if (!hasCustomStorage) {
- // remove 'this' param if switching to __thiscall with dynamic storage
- removeExplicitThisParameter();
- }
-
- frame.setInvalid();
-
- if (!hasCustomStorage) {
- createClassStructIfNeeded(); // TODO: How should thunks within Class namespace be handled?
- loadVariables();
- removeExplicitThisParameter();
- updateParametersAndReturn(); // assign dynamic storage
- manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS);
- manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_RETURN);
- }
- else {
- manager.functionChanged(this, 0); // change did not affect parameters
- }
+ removeExplicitThisParameter();
+ updateParametersAndReturn(); // assign dynamic storage
+ manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS);
+ manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_RETURN);
+ }
+ else {
+ manager.functionChanged(this, 0); // change did not affect parameters
}
}
catch (IOException e) {
@@ -2654,7 +2621,7 @@ public class FunctionDB extends DatabaseObject implements Function {
void createClassStructIfNeeded() {
PrototypeModel callingConvention = getCallingConvention();
if (callingConvention == null ||
- callingConvention.getGenericCallingConvention() != GenericCallingConvention.thiscall) {
+ !CompilerSpec.CALLING_CONVENTION_thiscall.equals(callingConvention.getName())) {
return;
}
Namespace parent = getParentNamespace();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java
index 24053a6151..72eb40c7a4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java
@@ -26,6 +26,7 @@ import generic.FilteredIterator;
import ghidra.program.database.DBObjectCache;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.code.CodeManager;
+import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.database.external.ExternalLocationDB;
import ghidra.program.database.map.AddressMap;
import ghidra.program.database.symbol.*;
@@ -60,12 +61,10 @@ public class FunctionManagerDB implements FunctionManager {
private DBObjectCache cache;
private FunctionAdapter adapter;
private ThunkFunctionAdapter thunkAdapter;
- private CallingConventionDBAdapter callingConventionAdapter;
- private Map callingConventionNameToIDMap = new HashMap<>();
- private Map callingConventionIDToNameMap = new HashMap<>();
private NamespaceManager namespaceMgr;
private SymbolManager symbolMgr;
private CodeManager codeMgr;
+ private DataTypeManagerDB dtMgr;
private FunctionTagManagerDB functionTagManager;
private Namespace globalNamespace;
@@ -125,8 +124,6 @@ public class FunctionManagerDB implements FunctionManager {
}
adapter = FunctionAdapter.getAdapter(dbHandle, openMode, addrMap, monitor);
thunkAdapter = ThunkFunctionAdapter.getAdapter(dbHandle, openMode, addrMap, monitor);
- callingConventionAdapter =
- CallingConventionDBAdapter.getAdapter(dbHandle, openMode, monitor);
}
@Override
@@ -138,136 +135,21 @@ public class FunctionManagerDB implements FunctionManager {
return adapter;
}
- /**
- * Get calling convention name corresponding to existing ID. If id is no longer valid,
- * null will be returned.
- * @param id
- * @return
- */
- String getCallingConventionName(byte id) {
- if (id == CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID) {
- return Function.DEFAULT_CALLING_CONVENTION_STRING;
- }
- else if (id == CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID) {
- return null;
- }
- String name = callingConventionIDToNameMap.get(id);
- if (name != null) {
- return name;
- }
- try {
- DBRecord record = callingConventionAdapter.getCallingConventionRecord(id);
- if (record == null) {
- return null;
- }
-
- name = record.getString(CallingConventionDBAdapter.CALLING_CONVENTION_NAME_COL);
- CompilerSpec compilerSpec = program.getCompilerSpec();
- PrototypeModel callingConvention = compilerSpec.getCallingConvention(name);
- if (callingConvention != null) {
- callingConventionIDToNameMap.put(id, name);
- callingConventionNameToIDMap.put(name, id);
- return name;
- }
- }
- catch (IOException e) {
- dbError(e);
- }
- return null;
- }
-
- /**
- * Get (and assign if needed) the ID associated with the specified calling convention name.
- * @param name calling convention name
- * @return calling convention ID
- * @throws IOException
- * @throws InvalidInputException
- */
- byte getCallingConventionID(String name) throws InvalidInputException, IOException {
- if (name == null || name.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
- return CallingConventionDBAdapter.UNKNOWN_CALLING_CONVENTION_ID;
- }
- else if (name.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
- return CallingConventionDBAdapter.DEFAULT_CALLING_CONVENTION_ID;
- }
- Byte id = callingConventionNameToIDMap.get(name);
- if (id != null) {
- return id;
- }
- CompilerSpec compilerSpec = program.getCompilerSpec();
- PrototypeModel callingConvention = compilerSpec.getCallingConvention(name);
- if (callingConvention == null) {
- throw new InvalidInputException("Invalid calling convention name: " + name);
- }
- DBRecord record = callingConventionAdapter.getCallingConventionRecord(name);
- if (record == null) {
- record = callingConventionAdapter.createCallingConventionRecord(name);
- }
- byte newId = record.getKeyField().getByteValue();
- callingConventionIDToNameMap.put(newId, name);
- callingConventionNameToIDMap.put(name, newId);
- return newId;
- }
-
@Override
- public List getCallingConventionNames() {
- CompilerSpec compilerSpec = program.getCompilerSpec();
- PrototypeModel[] namedCallingConventions = compilerSpec.getCallingConventions();
- List names = new ArrayList<>(namedCallingConventions.length + 2);
- names.add(Function.UNKNOWN_CALLING_CONVENTION_STRING);
- names.add(Function.DEFAULT_CALLING_CONVENTION_STRING);
- for (PrototypeModel model : namedCallingConventions) {
- names.add(model.getName());
- }
- return names;
+ public Collection getCallingConventionNames() {
+ return dtMgr.getDefinedCallingConventionNames();
}
@Override
public PrototypeModel getDefaultCallingConvention() {
CompilerSpec compilerSpec = program.getCompilerSpec();
- if (compilerSpec == null) {
- return null;
- }
return compilerSpec.getDefaultCallingConvention();
}
@Override
public PrototypeModel getCallingConvention(String name) {
CompilerSpec compilerSpec = program.getCompilerSpec();
- if (compilerSpec == null) {
- return null;
- }
- if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
- return null;
- }
- if (Function.DEFAULT_CALLING_CONVENTION_STRING.equals(name)) {
- return getDefaultCallingConvention();
- }
- PrototypeModel[] models = compilerSpec.getCallingConventions();
- for (PrototypeModel model : models) {
- String modelName = model.getName();
- if (modelName != null && modelName.equals(name)) {
- return model;
- }
- }
- return null;
- }
-
- @Override
- public PrototypeModel[] getCallingConventions() {
- CompilerSpec compilerSpec = program.getCompilerSpec();
- if (compilerSpec == null) {
- return new PrototypeModel[0];
- }
- ArrayList namedList = new ArrayList<>();
- PrototypeModel[] models = compilerSpec.getCallingConventions();
- for (PrototypeModel model : models) {
- String name = model.getName();
- if (name != null && name.length() > 0) {
- namedList.add(model);
- }
- }
- return namedList.toArray(new PrototypeModel[namedList.size()]);
+ return compilerSpec.getCallingConvention(name);
}
/**
@@ -751,7 +633,8 @@ public class FunctionManagerDB implements FunctionManager {
this.program = program;
namespaceMgr = program.getNamespaceManager();
codeMgr = program.getCodeManager();
- symbolMgr = (SymbolManager) program.getSymbolTable();
+ dtMgr = program.getDataTypeManager();
+ symbolMgr = program.getSymbolTable();
globalNamespace = program.getGlobalNamespace();
functionTagManager.setProgram(program);
}
@@ -935,8 +818,6 @@ public class FunctionManagerDB implements FunctionManager {
callFixupMap = null;
lastFuncID = -1;
cache.invalidate();
- callingConventionIDToNameMap.clear();
- callingConventionNameToIDMap.clear();
}
finally {
lock.release();
@@ -1037,9 +918,8 @@ public class FunctionManagerDB implements FunctionManager {
}
/**
- * Construct a function iterator over all functions residing in memory starting from the specified
- * entry point address.
- * @param start starting address for iteration
+ * Construct a function iterator over all functions residing in specified address set.
+ * @param addrSet address set over which to iterate
* @param forward if true iterate forward from start, otherwise iterate in reverse
*/
FunctionIteratorDB(AddressSetView addrSet, boolean forward) {
@@ -1096,9 +976,6 @@ public class FunctionManagerDB implements FunctionManager {
return list.iterator();
}
- /**
- * Set the new body for the function.
- */
void setFunctionBody(FunctionDB function, AddressSetView newBody)
throws OverlappingFunctionException {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java
index 5fa6301a53..61aa942f18 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java
@@ -24,6 +24,7 @@ import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import db.*;
+import db.util.ErrorHandler;
import ghidra.program.database.*;
import ghidra.program.database.code.CodeManager;
import ghidra.program.database.external.ExternalManagerDB;
@@ -63,6 +64,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
private LabelHistoryAdapter historyAdapter;
private DBObjectCache cache;
+ private ErrorHandler errHandler;
private ProgramDB program;
private ReferenceDBManager refManager;
private NamespaceManager namespaceMgr;
@@ -81,22 +83,26 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* @param handle the database handler
* @param addrMap the address map.
* @param openMode the open mode.
+ * @param errHandler database error handler
* @param lock the program synchronization lock
* @param monitor the progress monitor used when upgrading.
* @throws CancelledException if the user cancels the upgrade.
* @throws IOException if a database io error occurs.
* @throws VersionException if the database version doesn't match the current version.
*/
- public SymbolManager(DBHandle handle, AddressMap addrMap, int openMode, Lock lock,
- TaskMonitor monitor) throws CancelledException, IOException, VersionException {
+ public SymbolManager(DBHandle handle, AddressMap addrMap, int openMode, ErrorHandler errHandler,
+ Lock lock, TaskMonitor monitor)
+ throws CancelledException, IOException, VersionException {
this.addrMap = addrMap;
+ this.errHandler = errHandler;
this.lock = lock;
dynamicSymbolAddressMap = new AddressMapImpl((byte) 0x40, addrMap.getAddressFactory());
initializeAdapters(handle, openMode, monitor);
cache = new DBObjectCache<>(100);
- variableStorageMgr = new VariableStorageManagerDB(handle, addrMap, openMode, lock, monitor);
+ variableStorageMgr =
+ new VariableStorageManagerDB(handle, addrMap, openMode, errHandler, lock, monitor);
if (openMode == DBConstants.UPGRADE &&
OldVariableStorageManagerDB.isOldVariableStorageManagerUpgradeRequired(handle)) {
@@ -140,7 +146,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
this.program = program;
refManager = program.getReferenceManager();
namespaceMgr = program.getNamespaceManager();
- variableStorageMgr.setProgram(program);
+ variableStorageMgr.setProgramArchitecture(program);
}
@Override
@@ -177,6 +183,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
}
+ /**
+ * Get the variable storage manager used by this symbol table
+ * @return varable storage manager
+ */
+ public VariableStorageManager getVariableStorageManager() {
+ return variableStorageMgr;
+ }
+
/**
* Check for and upgrade old namespace symbol addresses which included a namespace ID.
*
@@ -1579,7 +1593,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
void dbError(IOException e) {
- program.dbError(e);
+ errHandler.dbError(e);
}
void validateSource(String name, Address address, SymbolType symbolType, SourceType source) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapter.java
index 273eaa1943..f6a179343b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapter.java
@@ -39,6 +39,7 @@ abstract class VariableStorageDBAdapter {
* @param openMode the openmode
* @param addrMap the address map
* @param monitor the progress monitor.
+ * @return variable storage table adapter
* @throws VersionException if the database table does not match the adapter.
* @throws CancelledException if the user cancels an upgrade.
* @throws IOException if a database io error occurs.
@@ -95,4 +96,6 @@ abstract class VariableStorageDBAdapter {
abstract int getRecordCount();
+ abstract void deleteTable() throws IOException;
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterNoTable.java
index 3440fdbd6f..451f8f1876 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterNoTable.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterNoTable.java
@@ -60,4 +60,9 @@ public class VariableStorageDBAdapterNoTable extends VariableStorageDBAdapter {
int getRecordCount() {
return 0;
}
+
+ @Override
+ void deleteTable() {
+ // do nothing
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterV2.java
index 0314bdac08..0980897408 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterV2.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageDBAdapterV2.java
@@ -26,10 +26,11 @@ public class VariableStorageDBAdapterV2 extends VariableStorageDBAdapter {
private static final int TABLE_VERSION = 2;
private Table variableStorageTable;
+ private DBHandle handle;
VariableStorageDBAdapterV2(DBHandle handle, boolean create)
throws VersionException, IOException {
-
+ this.handle = handle;
if (create) {
variableStorageTable = handle.createTable(VARIABLE_STORAGE_TABLE_NAME,
VARIABLE_STORAGE_SCHEMA, new int[] { HASH_COL });
@@ -49,6 +50,11 @@ public class VariableStorageDBAdapterV2 extends VariableStorageDBAdapter {
}
}
+ @Override
+ void deleteTable() throws IOException {
+ handle.deleteTable(VARIABLE_STORAGE_TABLE_NAME);
+ }
+
@Override
long getNextStorageID() {
long nextKey = variableStorageTable.getMaxKey() + 1;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManager.java
new file mode 100644
index 0000000000..bad8835c3f
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManager.java
@@ -0,0 +1,34 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.database.symbol;
+
+import java.io.IOException;
+
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.VariableStorage;
+
+public interface VariableStorageManager {
+
+ /**
+ * Get a variable address for the given storage specification.
+ * @param storage variable storage specification
+ * @param create if true a new variable address will be allocated if needed
+ * @return variable address which corresponds to the storage specification or null if not found
+ * and create is false.
+ * @throws IOException if an IO error occurs
+ */
+ Address getVariableStorageAddress(VariableStorage storage, boolean create) throws IOException;
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManagerDB.java
index e0a07e9d76..f116150b68 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableStorageManagerDB.java
@@ -19,10 +19,13 @@ import java.io.IOException;
import java.util.List;
import db.*;
-import ghidra.program.database.*;
+import db.util.ErrorHandler;
+import ghidra.program.database.DBObjectCache;
+import ghidra.program.database.DatabaseObject;
import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.lang.ProgramArchitecture;
import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.util.LanguageTranslator;
@@ -32,11 +35,11 @@ import ghidra.util.datastruct.WeakValueHashMap;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
-public class VariableStorageManagerDB {
+public class VariableStorageManagerDB implements VariableStorageManager {
- private ProgramDB program;
- private AddressMap addrMap;
+ private ProgramArchitecture arch;
private Lock lock;
+ private ErrorHandler errorHandler;
private VariableStorageDBAdapter adapter;
@@ -47,45 +50,55 @@ public class VariableStorageManagerDB {
/**
* Construct a new variable manager.
* @param handle the database handle.
- * @param addrMap the address map
+ * @param addrMap the address map (required for legacy adpter use only)
* @param openMode the open mode
+ * @param errorHandler database error handler
* @param lock the program synchronization lock
* @param monitor the task monitor.
* @throws IOException if a database error occurs.
* @throws VersionException if the table version is different from this adapter.
- * @throws IOException
+ * @throws IOException if an IO error occurs
* @throws CancelledException if the user cancels the upgrade.
*/
- public VariableStorageManagerDB(DBHandle handle, AddressMap addrMap, int openMode, Lock lock,
- TaskMonitor monitor) throws VersionException, IOException, CancelledException {
-
- this.addrMap = addrMap;
+ public VariableStorageManagerDB(DBHandle handle, AddressMap addrMap, int openMode,
+ ErrorHandler errorHandler, Lock lock, TaskMonitor monitor)
+ throws VersionException, IOException, CancelledException {
+ this.errorHandler = errorHandler;
this.lock = lock;
-
adapter = VariableStorageDBAdapter.getAdapter(handle, openMode, addrMap, monitor);
}
+ /**
+ * Set program architecture.
+ * @param arch program architecture
+ */
+ public void setProgramArchitecture(ProgramArchitecture arch) {
+ this.arch = arch;
+ }
+
+ /**
+ * Delete the DB table which correspnds to this variable storage implementation
+ * @param dbHandle database handle
+ * @throws IOException if an IO error occurs
+ */
+ public static void delete(DBHandle dbHandle) throws IOException {
+ dbHandle.deleteTable(VariableStorageDBAdapter.VARIABLE_STORAGE_TABLE_NAME);
+ }
+
+ /**
+ * Determine if the variable storage manager table already exists
+ * @param dbHandle database handle
+ * @return true if storage table exists
+ */
+ public static boolean exists(DBHandle dbHandle) {
+ return dbHandle.getTable(VariableStorageDBAdapter.VARIABLE_STORAGE_TABLE_NAME) != null;
+ }
+
void invalidateCache(boolean all) {
cache.invalidate();
cacheMap.clear();
}
- void setProgram(ProgramDB program) {
- this.program = program;
- }
-
-// private void cacheNamespaceStorage(long namespaceID) throws IOException {
-// variableAddrLookupCache.clear();
-// storageLookupCache.clear();
-// lastNamespaceCacheID = namespaceID;
-// Record[] records = adapter.getRecordsForNamespace(namespaceID);
-// for (Record rec : records) {
-// MyVariableStorage varStore = new MyVariableStorage(rec);
-// variableAddrLookupCache.put(varStore.getVariableAddress(), varStore);
-// storageLookupCache.put(varStore.getVariableStorage(), varStore);
-// }
-// }
-
private MyVariableStorage getMyVariableStorage(Address variableAddr) throws IOException {
if (!variableAddr.isVariableAddress()) {
throw new IllegalArgumentException("Address is not a VariableAddress: " + variableAddr);
@@ -103,6 +116,14 @@ public class VariableStorageManagerDB {
return varStore;
}
+ /**
+ * Get the list of varnodes associated with the specified variable storage address.
+ * NOTE: The program architecture and error handler must be set appropriately prior to
+ * invocation of this method (see {@link #setProgramArchitecture(ProgramArchitecture, ErrorHandler)}.
+ * @param variableAddr variable storage address
+ * @return storage varnode list or null if address unknown
+ * @throws IOException if a database IO error occurs
+ */
List getStorageVarnodes(Address variableAddr) throws IOException {
if (!variableAddr.isVariableAddress()) {
throw new IllegalArgumentException();
@@ -112,7 +133,7 @@ public class VariableStorageManagerDB {
return null;
}
try {
- return VariableStorage.getVarnodes(program.getAddressFactory(),
+ return VariableStorage.getVarnodes(arch.getAddressFactory(),
rec.getString(VariableStorageDBAdapter.STORAGE_COL));
}
catch (InvalidInputException e) {
@@ -121,6 +142,14 @@ public class VariableStorageManagerDB {
return null;
}
+ /**
+ * Get the variable storage object associated with the specified variable storage address.
+ * NOTE: The program architecture and error handler must be set appropriately prior to
+ * invocation of this method (see {@link #setProgramArchitecture(ProgramArchitecture, ErrorHandler)}.
+ * @param variableAddr variable storage address
+ * @return variable storage object or null if address unknown
+ * @throws IOException if a database IO error occurs
+ */
VariableStorage getVariableStorage(Address variableAddr) throws IOException {
MyVariableStorage myStorage = getMyVariableStorage(variableAddr);
if (myStorage != null) {
@@ -129,6 +158,17 @@ public class VariableStorageManagerDB {
return null;
}
+ /**
+ * Get a variable address for the given storage specification.
+ * NOTE: The program architecture and error handler must be set appropriately prior to
+ * invocation of this method (see {@link #setProgramArchitecture(ProgramArchitecture, ErrorHandler)}.
+ * @param storage variable storage specification
+ * @param create if true a new variable address will be allocated if needed
+ * @return variable address which corresponds to the storage specification or null if not found
+ * and create is false.
+ * @throws IOException if an IO error occurs
+ */
+ @Override
public Address getVariableStorageAddress(VariableStorage storage, boolean create)
throws IOException {
long hash = storage.getLongHash();
@@ -215,7 +255,7 @@ public class VariableStorageManagerDB {
super(cache, record.getKey());
this.record = record;
try {
- storage = VariableStorage.deserialize(program,
+ storage = VariableStorage.deserialize(arch,
record.getString(VariableStorageDBAdapter.STORAGE_COL));
}
catch (InvalidInputException e) {
@@ -250,7 +290,7 @@ public class VariableStorageManagerDB {
}
record = rec;
try {
- storage = VariableStorage.deserialize(program,
+ storage = VariableStorage.deserialize(arch,
record.getString(VariableStorageDBAdapter.STORAGE_COL));
}
catch (InvalidInputException e) {
@@ -260,7 +300,7 @@ public class VariableStorageManagerDB {
}
}
catch (IOException e) {
- program.dbError(e);
+ errorHandler.dbError(e);
}
finally {
lock.release();
@@ -272,10 +312,13 @@ public class VariableStorageManagerDB {
/**
* Perform language translation.
+ * Following the invocation of this method it is important to ensure that the program
+ * architecure is adjusted if neccessary.
* Update variable storage specifications to reflect address space and register mappings
- * @param translator
- * @param monitor
- * @throws CancelledException
+ * @param translator language translator to be used for mapping storage varnodes to new
+ * architecture.
+ * @param monitor task monitor
+ * @throws CancelledException if task is cancelled
*/
public void setLanguage(LanguageTranslator translator, TaskMonitor monitor)
throws CancelledException {
@@ -308,7 +351,7 @@ public class VariableStorageManagerDB {
}
}
catch (IOException e) {
- program.dbError(e);
+ errorHandler.dbError(e);
}
finally {
invalidateCache(true);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/DBRecordAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/DBRecordAdapter.java
index 8b939d0536..d07edefa77 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/DBRecordAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/DBRecordAdapter.java
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
- * REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +15,6 @@
*/
package ghidra.program.database.util;
-import ghidra.program.model.address.Address;
-
import java.io.IOException;
import db.RecordIterator;
@@ -29,11 +26,15 @@ import db.RecordIterator;
public interface DBRecordAdapter {
/**
- * Get a record iterator.
- * @param start start of iterator
- * @param end end of iterator
- * @param colIndex index column
+ * Get a record iterator for all records.
+ * @return record iterator
* @throws IOException if there was a problem accessing the database
*/
- public RecordIterator getRecords(Address start, Address end, int colIndex) throws IOException;
+ public RecordIterator getRecords() throws IOException;
+
+ /**
+ * Get the number of records in table
+ * @return total record count
+ */
+ public int getRecordCount();
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java
index 4d09c023f1..2aa7b34763 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java
@@ -36,7 +36,6 @@ public abstract class AbstractDataType implements DataType {
protected String name;
protected CategoryPath categoryPath;
protected final DataTypeManager dataMgr;
- private DataOrganization dataOrganization;
protected AbstractDataType(CategoryPath path, String name, DataTypeManager dataTypeManager) {
if (path == null) {
@@ -75,16 +74,8 @@ public abstract class AbstractDataType implements DataType {
@Override
public final DataOrganization getDataOrganization() {
- if (dataOrganization != null) {
- return dataOrganization;
- }
- if (dataMgr != null) {
- dataOrganization = dataMgr.getDataOrganization();
- }
- if (dataOrganization == null) {
- dataOrganization = DataOrganizationImpl.getDefaultOrganization();
- }
- return dataOrganization;
+ return dataMgr != null ? dataMgr.getDataOrganization()
+ : DataOrganizationImpl.getDefaultOrganization();
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java
index 0e5d906ed6..3e17923920 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java
@@ -56,18 +56,14 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
private static SettingsDefinition[] SETTINGS_DEFS =
{ FormatSettingsDefinition.DEF_HEX, PADDING, ENDIAN, MNEMONIC };
- private final boolean signed;
-
/**
* Constructor
*
* @param name a unique signed/unsigned data-type name (also used as the mnemonic)
- * @param signed true if signed, false if unsigned
* @param dtm data-type manager whose data organization should be used
*/
- public AbstractIntegerDataType(String name, boolean signed, DataTypeManager dtm) {
+ public AbstractIntegerDataType(String name, DataTypeManager dtm) {
super(null, name, dtm);
- this.signed = signed;
}
/**
@@ -86,11 +82,10 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
}
/**
+ * Determine if this type is signed.
* @return true if this is a signed integer data-type
*/
- public boolean isSigned() {
- return signed;
- }
+ public abstract boolean isSigned();
@Override
public String getDefaultLabelPrefix() {
@@ -134,6 +129,7 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
if (size <= 0) {
return null;
}
+ boolean signed = isSigned();
DataOrganization dataOrganization = getDataOrganization();
if (size == dataOrganization.getCharSize()) {
return signed ? C_SIGNED_CHAR : C_UNSIGNED_CHAR;
@@ -311,7 +307,7 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
boolean negative = bigInt.signum() < 0;
- if (negative && (!signed || (format != FormatSettingsDefinition.DECIMAL))) {
+ if (negative && (!isSigned() || (format != FormatSettingsDefinition.DECIMAL))) {
// force use of unsigned value
bigInt = bigInt.add(BigInteger.valueOf(2).pow(bitLength));
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractSignedIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractSignedIntegerDataType.java
new file mode 100644
index 0000000000..67231bd75e
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractSignedIntegerDataType.java
@@ -0,0 +1,37 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.model.data;
+
+/**
+ * Base type for unsigned integer data types.
+ */
+public abstract class AbstractSignedIntegerDataType extends AbstractIntegerDataType {
+
+ /**
+ * Constructor
+ *
+ * @param name a signed data-type name (also used as the mnemonic)
+ * @param dtm data-type manager whose data organization should be used
+ */
+ protected AbstractSignedIntegerDataType(String name, DataTypeManager dtm) {
+ super(name, dtm);
+ }
+
+ @Override
+ public final boolean isSigned() {
+ return true;
+ }
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractUnsignedIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractUnsignedIntegerDataType.java
new file mode 100644
index 0000000000..2c03452ea5
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractUnsignedIntegerDataType.java
@@ -0,0 +1,37 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.model.data;
+
+/**
+ * Base type for unsigned integer data types.
+ */
+public abstract class AbstractUnsignedIntegerDataType extends AbstractIntegerDataType {
+
+ /**
+ * Constructor
+ *
+ * @param name a unsigned data-type name (also used as the mnemonic)
+ * @param dtm data-type manager whose data organization should be used
+ */
+ protected AbstractUnsignedIntegerDataType(String name, DataTypeManager dtm) {
+ super(name, dtm);
+ }
+
+ @Override
+ public final boolean isSigned() {
+ return false;
+ }
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AddressSpaceSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AddressSpaceSettingsDefinition.java
index b6177add8b..2f9093c63f 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AddressSpaceSettingsDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AddressSpaceSettingsDefinition.java
@@ -21,8 +21,8 @@ import org.apache.commons.lang3.StringUtils;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.StringSettingsDefinition;
-import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.lang.ProgramArchitecture;
public class AddressSpaceSettingsDefinition
implements StringSettingsDefinition, TypeDefSettingsDefinition {
@@ -118,12 +118,14 @@ public class AddressSpaceSettingsDefinition
@Override
public boolean addPreferredValues(Object settingsOwner, Set set) {
- if (settingsOwner instanceof ProgramBasedDataTypeManager) {
- ProgramBasedDataTypeManager dtm = (ProgramBasedDataTypeManager) settingsOwner;
- AddressFactory addressFactory = dtm.getProgram().getAddressFactory();
- for (AddressSpace space : addressFactory.getAllAddressSpaces()) {
- if (space.isLoadedMemorySpace()) {
- set.add(space.getName());
+ if (settingsOwner instanceof DataTypeManager) {
+ DataTypeManager dtm = (DataTypeManager) settingsOwner;
+ ProgramArchitecture arch = dtm.getProgramArchitecture();
+ if (arch != null) {
+ for (AddressSpace space : arch.getAddressFactory().getAllAddressSpaces()) {
+ if (space.isLoadedMemorySpace()) {
+ set.add(space.getName());
+ }
}
}
return true;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java
index 1419616ff4..ff7ae47c9b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java
@@ -20,6 +20,7 @@ import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
+import ghidra.program.database.DBStringMapAdapter;
import ghidra.program.model.pcode.Encoder;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
@@ -27,9 +28,13 @@ import ghidra.xml.XmlPullParser;
public class BitFieldPackingImpl implements BitFieldPacking {
- private boolean useMSConvention = false;
- private boolean typeAlignmentEnabled = true;
- private int zeroLengthBoundary = 0;
+ public static final boolean DEFAULT_USE_MS_CONVENTION = false;
+ public static final boolean DEFAULT_TYPE_ALIGNMENT_ENABLED = true;
+ public static final int DEFAULT_ZERO_LENGTH_BOUNDARY = 0;
+
+ private boolean useMSConvention = DEFAULT_USE_MS_CONVENTION;
+ private boolean typeAlignmentEnabled = DEFAULT_TYPE_ALIGNMENT_ENABLED;
+ private int zeroLengthBoundary = DEFAULT_ZERO_LENGTH_BOUNDARY;
@Override
public boolean useMSConvention() {
@@ -76,26 +81,81 @@ public class BitFieldPackingImpl implements BitFieldPacking {
}
/**
- * Write configuration to a stream as a \ element
- * @param encoder is the stream encoder
- * @throws IOException for errors writing to the underlying stream
+ * Save the specified bitfield packing options to the specified DB data map.
+ * @param bitfieldPacking bitfield packing options
+ * @param dataMap DB data map
+ * @param keyPrefix key prefix for all map entries
+ * @throws IOException if an IO error occurs
+ */
+ static void save(BitFieldPacking bitfieldPacking, DBStringMapAdapter dataMap,
+ String keyPrefix) throws IOException {
+
+ boolean useMSConvention = bitfieldPacking.useMSConvention();
+ if (useMSConvention != DEFAULT_USE_MS_CONVENTION) {
+ dataMap.put(keyPrefix + "use_MS_convention", Boolean.toString(useMSConvention));
+ }
+
+ boolean typeAlignmentEnabled = bitfieldPacking.isTypeAlignmentEnabled();
+ if (typeAlignmentEnabled != DEFAULT_TYPE_ALIGNMENT_ENABLED) {
+ dataMap.put(keyPrefix + "type_alignment_enabled",
+ Boolean.toString(typeAlignmentEnabled));
+ }
+
+ int zeroLengthBoundary = bitfieldPacking.getZeroLengthBoundary();
+ if (zeroLengthBoundary != DEFAULT_ZERO_LENGTH_BOUNDARY) {
+ dataMap.put(keyPrefix + "zero_length_boundary", Integer.toString(zeroLengthBoundary));
+ }
+ }
+
+ /**
+ * Restore a data organization from the specified DB data map.
+ * @param dataMap DB data map
+ * @param keyPrefix key prefix for all map entries
+ * @return data organization
+ * @throws IOException if an IO error occurs
+ */
+ static BitFieldPackingImpl restore(DBStringMapAdapter dataMap, String keyPrefix)
+ throws IOException {
+
+ BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl();
+
+ bitFieldPacking.useMSConvention =
+ dataMap.getBoolean(keyPrefix + ELEM_USE_MS_CONVENTION.name(),
+ bitFieldPacking.useMSConvention);
+
+ bitFieldPacking.typeAlignmentEnabled = dataMap.getBoolean(
+ keyPrefix + ELEM_TYPE_ALIGNMENT_ENABLED.name(), bitFieldPacking.typeAlignmentEnabled);
+
+ bitFieldPacking.zeroLengthBoundary =
+ dataMap.getInt(keyPrefix + ELEM_ZERO_LENGTH_BOUNDARY.name(),
+ bitFieldPacking.zeroLengthBoundary);
+
+ return bitFieldPacking;
+ }
+
+ /**
+ * Output the details of this bitfield packing to a encoded document formatter.
+ * @param encoder the output document encoder.
+ * @throws IOException if an IO error occurs while encoding/writing output
*/
public void encode(Encoder encoder) throws IOException {
- if (!useMSConvention && typeAlignmentEnabled && zeroLengthBoundary == 0) {
+ if (useMSConvention == DEFAULT_USE_MS_CONVENTION &&
+ typeAlignmentEnabled == DEFAULT_TYPE_ALIGNMENT_ENABLED &&
+ zeroLengthBoundary == DEFAULT_ZERO_LENGTH_BOUNDARY) {
return; // All defaults
}
encoder.openElement(ELEM_BITFIELD_PACKING);
- if (useMSConvention) {
+ if (useMSConvention != DEFAULT_USE_MS_CONVENTION) {
encoder.openElement(ELEM_USE_MS_CONVENTION);
encoder.writeBool(ATTRIB_VALUE, true);
encoder.closeElement(ELEM_USE_MS_CONVENTION);
}
- if (!typeAlignmentEnabled) {
+ if (typeAlignmentEnabled != DEFAULT_TYPE_ALIGNMENT_ENABLED) {
encoder.openElement(ELEM_TYPE_ALIGNMENT_ENABLED);
encoder.writeBool(ATTRIB_VALUE, false);
encoder.closeElement(ELEM_TYPE_ALIGNMENT_ENABLED);
}
- if (zeroLengthBoundary != 0) {
+ if (zeroLengthBoundary != DEFAULT_ZERO_LENGTH_BOUNDARY) {
encoder.openElement(ELEM_ZERO_LENGTH_BOUNDARY);
encoder.writeSignedInteger(ATTRIB_VALUE, zeroLengthBoundary);
encoder.closeElement(ELEM_ZERO_LENGTH_BOUNDARY);
@@ -115,13 +175,13 @@ public class BitFieldPackingImpl implements BitFieldPacking {
String name = subel.getName();
String value = subel.getAttribute("value");
- if (name.equals("use_MS_convention")) {
+ if (name.equals(ELEM_USE_MS_CONVENTION.name())) {
useMSConvention = SpecXmlUtils.decodeBoolean(value);
}
- else if (name.equals("type_alignment_enabled")) {
+ else if (name.equals(ELEM_TYPE_ALIGNMENT_ENABLED.name())) {
typeAlignmentEnabled = SpecXmlUtils.decodeBoolean(value);
}
- else if (name.equals("zero_length_boundary")) {
+ else if (name.equals(ELEM_ZERO_LENGTH_BOUNDARY.name())) {
zeroLengthBoundary = SpecXmlUtils.decodeInt(value);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java
index ca300be5ef..48ba33918a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java
@@ -26,7 +26,7 @@ import ghidra.program.model.mem.MemoryAccessException;
/**
* Provides a definition of an Ascii byte in a program.
*/
-public class BooleanDataType extends AbstractIntegerDataType {
+public class BooleanDataType extends AbstractUnsignedIntegerDataType {
private static SettingsDefinition[] SETTINGS_DEFS = {};
@@ -40,7 +40,7 @@ public class BooleanDataType extends AbstractIntegerDataType {
}
public BooleanDataType(DataTypeManager dtm) {
- super("bool", false, dtm);
+ super("bool", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java
index 8f4588dad9..094939e06a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java
@@ -15,24 +15,29 @@
*/
package ghidra.program.model.data;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import javax.help.UnsupportedOperationException;
import javax.swing.event.ChangeListener;
import ghidra.framework.ShutdownHookRegistry;
import ghidra.framework.ShutdownPriority;
+import ghidra.program.database.symbol.VariableStorageManager;
+import ghidra.program.model.lang.ProgramArchitecture;
import ghidra.util.*;
import ghidra.util.classfinder.ClassFilter;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.AssertException;
+import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Data type manager for built in types that do not live anywhere except
* in memory.
*/
-public class BuiltInDataTypeManager extends StandAloneDataTypeManager {
+public final class BuiltInDataTypeManager extends StandAloneDataTypeManager {
// TODO: There appear to be many public methods in DataTypeManagerDB which could potentially modify the
// underlying database - these methods should probably be overridden
@@ -64,6 +69,17 @@ public class BuiltInDataTypeManager extends StandAloneDataTypeManager {
initialize();
}
+ protected final void setProgramArchitecture(ProgramArchitecture programArchitecture,
+ VariableStorageManager variableStorageMgr, boolean force, TaskMonitor monitor)
+ throws IOException, CancelledException {
+ throw new UnsupportedOperationException("program architecture change not permitted");
+ }
+
+ @Override
+ protected final boolean isArchitectureChangeAllowed() {
+ return false;
+ }
+
@Override
public synchronized int startTransaction(String description) {
if (manager != null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ByteDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ByteDataType.java
index de99b576dc..95213aa4f8 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ByteDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ByteDataType.java
@@ -20,9 +20,7 @@ import ghidra.program.model.lang.DecompilerLanguage;
/**
* Provides a definition of a Byte within a program.
*/
-public class ByteDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class ByteDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined ByteDataType instance.*/
public final static ByteDataType dataType = new ByteDataType();
@@ -32,7 +30,7 @@ public class ByteDataType extends AbstractIntegerDataType {
}
public ByteDataType(DataTypeManager dtm) {
- super("byte", false, dtm);
+ super("byte", dtm);
}
@Override
@@ -52,8 +50,9 @@ public class ByteDataType extends AbstractIntegerDataType {
@Override
public String getDecompilerDisplayName(DecompilerLanguage language) {
- if (language == DecompilerLanguage.JAVA_LANGUAGE)
+ if (language == DecompilerLanguage.JAVA_LANGUAGE) {
return "ubyte";
+ }
return name;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharDataType.java
index 38afef95e6..18be5b3488 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CharDataType.java
@@ -26,7 +26,6 @@ import ghidra.util.classfinder.ClassTranslator;
* determined by the data organization of the associated data type manager.
*/
public class CharDataType extends AbstractIntegerDataType implements DataTypeWithCharset {
- private final static long serialVersionUID = 1;
static {
ClassTranslator.put("ghidra.program.model.data.AsciiDataType",
@@ -54,12 +53,13 @@ public class CharDataType extends AbstractIntegerDataType implements DataTypeWit
this("char", dtm);
}
- protected CharDataType(String name, boolean signed, DataTypeManager dtm) {
- super(name, signed, dtm);
+ protected CharDataType(String name, DataTypeManager dtm) {
+ super(name, dtm);
}
- private CharDataType(String name, DataTypeManager dtm) {
- super(name, isSignedChar(dtm), dtm);
+ @Override
+ public boolean isSigned() {
+ return getDataOrganization().isSignedChar();
}
@Override
@@ -76,12 +76,6 @@ public class CharDataType extends AbstractIntegerDataType implements DataTypeWit
return getLength() != 1;
}
- private static boolean isSignedChar(DataTypeManager dtm) {
- DataOrganization dataOrganization =
- dtm != null ? dtm.getDataOrganization() : DataOrganizationImpl.getDefaultOrganization();
- return dataOrganization.isSignedChar();
- }
-
/**
* Returns the C style data-type declaration for this data-type. Null is returned if no
* appropriate declaration exists.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DWordDataType.java
index e404ccfd44..1108770383 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DWordDataType.java
@@ -18,7 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a definition of a Double Word within a program.
*/
-public class DWordDataType extends AbstractIntegerDataType {
+public class DWordDataType extends AbstractUnsignedIntegerDataType {
private static final long serialVersionUID = 1L;
@@ -30,7 +30,7 @@ public class DWordDataType extends AbstractIntegerDataType {
}
public DWordDataType(DataTypeManager dtm) {
- super("dword", false, dtm);
+ super("dword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java
index fea8581459..c15d05ba0b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java
@@ -164,15 +164,6 @@ public interface DataOrganization {
*/
int getAlignment(DataType dataType);
-// /**
-// * Determines the offset where the specified data type should be placed to be properly aligned.
-// * @param minimumOffset the minimum allowable offset where the data type can be placed.
-// * @param dataType the data type
-// * @param dtSize the data type's size
-// * @return the aligned offset for the data type
-// */
-// int getAlignmentOffset(int minimumOffset, DataType dataType, int dtSize);
-
/**
* Determine if this DataOrganization is equivalent to another specific instance
* @param obj is the other instance
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java
index fa33af396c..b16292b30d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java
@@ -21,6 +21,7 @@ import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
import java.util.*;
+import ghidra.program.database.DBStringMapAdapter;
import ghidra.program.model.lang.Language;
import ghidra.program.model.pcode.Encoder;
import ghidra.util.exception.NoValueException;
@@ -34,26 +35,48 @@ import ghidra.xml.XmlPullParser;
*/
public class DataOrganizationImpl implements DataOrganization {
+ // NOTE: it is important that defaults match Decompiler defaults
+ public static final int DEFAULT_MACHINE_ALIGNMENT = 8;
+ public static final int DEFAULT_DEFAULT_ALIGNMENT = 1;
+ public static final int DEFAULT_DEFAULT_POINTER_ALIGNMENT = 4;
+ public static final int DEFAULT_POINTER_SHIFT = 0;
+ public static final int DEFAULT_POINTER_SIZE = 4;
+ public static final int DEFAULT_CHAR_SIZE = 1;
+ public static final boolean DEFAULT_CHAR_IS_SIGNED = true;
+ public static final int DEFAULT_WIDE_CHAR_SIZE = 2;
+ public static final int DEFAULT_SHORT_SIZE = 2;
+ public static final int DEFAULT_INT_SIZE = 4;
+ public static final int DEFAULT_LONG_SIZE = 4;
+ public static final int DEFAULT_LONG_LONG_SIZE = 8;
+ public static final int DEFAULT_FLOAT_SIZE = 4;
+ public static final int DEFAULT_DOUBLE_SIZE = 8;
+ public static final int DEFAULT_LONG_DOUBLE_SIZE = 8;
+
+ // DBStringMapAdapter save/restore keys
+ private static final String BIG_ENDIAN_NAME = "big_endian";
+ private static final String SIGNED_CHAR_TYPE_NAME = "signed_char_type";
+
private int absoluteMaxAlignment = NO_MAXIMUM_ALIGNMENT;
- private int machineAlignment = 8;
- private int defaultAlignment = 1;
- private int defaultPointerAlignment = 4;
+ private int machineAlignment = DEFAULT_MACHINE_ALIGNMENT;
+ private int defaultAlignment = DEFAULT_DEFAULT_ALIGNMENT;
+ private int defaultPointerAlignment = DEFAULT_DEFAULT_POINTER_ALIGNMENT;
// Default sizes for primitive data types.
- private int pointerShift = 0;
- private int pointerSize = 4;
- private int charSize = 1;
- private int wideCharSize = 2;
- private int shortSize = 2;
- private int integerSize = 4;
- private int longSize = 4;
- private int longLongSize = 8;
- private int floatSize = 4;
- private int doubleSize = 8;
- private int longDoubleSize = 8;
+ private int pointerShift = DEFAULT_POINTER_SHIFT;
+ private int pointerSize = DEFAULT_POINTER_SIZE;
+ private int charSize = DEFAULT_CHAR_SIZE;
+ private boolean isSignedChar = DEFAULT_CHAR_IS_SIGNED;
+ private int wideCharSize = DEFAULT_WIDE_CHAR_SIZE;
+ private int shortSize = DEFAULT_SHORT_SIZE;
+ private int integerSize = DEFAULT_INT_SIZE;
+ private int longSize = DEFAULT_LONG_SIZE;
+ private int longLongSize = DEFAULT_LONG_LONG_SIZE;
+ private int floatSize = DEFAULT_FLOAT_SIZE;
+ private int doubleSize = DEFAULT_DOUBLE_SIZE;
+ private int longDoubleSize = DEFAULT_LONG_DOUBLE_SIZE;
+ // Endianess explicitly set and not supported by saveXml/restore
private boolean bigEndian = false;
- private boolean isSignedChar = true;
private BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl();
@@ -86,7 +109,9 @@ public class DataOrganizationImpl implements DataOrganization {
dataOrganization.setSizeAlignment(4, 4);
dataOrganization.setSizeAlignment(8, 4);
if (language != null) {
+ // NOTE: Ensure that saveXml always saves pointer size
dataOrganization.setPointerSize(language.getDefaultSpace().getPointerSize());
+ // NOTE: Endianess is not handled by saveXml/restore
dataOrganization.setBigEndian(language.isBigEndian());
}
return dataOrganization;
@@ -556,84 +581,300 @@ public class DataOrganizationImpl implements DataOrganization {
return (value2 != 0) ? getGreatestCommonDenominator(value2, value1 % value2) : value1;
}
+ /**
+ * Save the specified data organization to the specified DB data map.
+ * All existing map entries starting with keyPrefix will be removed prior
+ * to ading the new map entries.
+ * @param dataOrg data organization
+ * @param dataMap DB data map
+ * @param keyPrefix key prefix for all map entries
+ * @throws IOException if an IO error occurs
+ */
+ public static void save(DataOrganization dataOrg, DBStringMapAdapter dataMap, String keyPrefix)
+ throws IOException {
+
+ for (String key : dataMap.keySet()) {
+ if (key.startsWith(keyPrefix)) {
+ dataMap.delete(key);
+ }
+ }
+
+ if (dataOrg.isBigEndian()) { // default is little-endian
+ dataMap.put(keyPrefix + BIG_ENDIAN_NAME, Boolean.TRUE.toString());
+ }
+
+ int absoluteMaxAlignment = dataOrg.getAbsoluteMaxAlignment();
+ if (absoluteMaxAlignment != NO_MAXIMUM_ALIGNMENT) {
+ dataMap.put(keyPrefix + ELEM_ABSOLUTE_MAX_ALIGNMENT.name(),
+ Integer.toString(absoluteMaxAlignment));
+ }
+
+ int machineAlignment = dataOrg.getMachineAlignment();
+ if (machineAlignment != DEFAULT_MACHINE_ALIGNMENT) {
+ dataMap.put(keyPrefix + ELEM_MACHINE_ALIGNMENT.name(),
+ Integer.toString(machineAlignment));
+ }
+
+ int defaultAlignment = dataOrg.getDefaultAlignment();
+ if (defaultAlignment != DEFAULT_DEFAULT_ALIGNMENT) {
+ dataMap.put(keyPrefix + ELEM_DEFAULT_ALIGNMENT.name(),
+ Integer.toString(defaultAlignment));
+ }
+
+ int defaultPointerAlignment = dataOrg.getDefaultPointerAlignment();
+ if (defaultPointerAlignment != DEFAULT_DEFAULT_POINTER_ALIGNMENT) {
+ dataMap.put(keyPrefix + ELEM_DEFAULT_POINTER_ALIGNMENT.name(),
+ Integer.toString(defaultPointerAlignment));
+ }
+
+ int pointerSize = dataOrg.getPointerSize();
+ if (pointerSize != DEFAULT_POINTER_SIZE) {
+ dataMap.put(keyPrefix + ELEM_POINTER_SIZE.name(), Integer.toString(pointerSize));
+ }
+
+ int pointerShift = dataOrg.getPointerShift();
+ if (pointerShift != DEFAULT_POINTER_SHIFT) {
+ dataMap.put(keyPrefix + ELEM_POINTER_SHIFT.name(), Integer.toString(pointerShift));
+ }
+
+ boolean isSignedChar = dataOrg.isSignedChar();
+ if (!isSignedChar) {
+ // NOTE: This differs from XML element name
+ dataMap.put(keyPrefix + SIGNED_CHAR_TYPE_NAME, Boolean.toString(isSignedChar));
+ }
+
+ int charSize = dataOrg.getCharSize();
+ if (charSize != DEFAULT_CHAR_SIZE) {
+ dataMap.put(keyPrefix + ELEM_CHAR_SIZE.name(), Integer.toString(charSize));
+ }
+
+ int wideCharSize = dataOrg.getWideCharSize();
+ if (wideCharSize != DEFAULT_WIDE_CHAR_SIZE) {
+ dataMap.put(keyPrefix + ELEM_WCHAR_SIZE.name(), Integer.toString(wideCharSize));
+ }
+
+ int shortSize = dataOrg.getShortSize();
+ if (shortSize != DEFAULT_SHORT_SIZE) {
+ dataMap.put(keyPrefix + ELEM_SHORT_SIZE.name(), Integer.toString(shortSize));
+ }
+
+ int integerSize = dataOrg.getIntegerSize();
+ if (integerSize != DEFAULT_INT_SIZE) {
+ dataMap.put(keyPrefix + ELEM_INTEGER_SIZE.name(), Integer.toString(integerSize));
+ }
+
+ int longSize = dataOrg.getLongSize();
+ if (longSize != DEFAULT_LONG_SIZE) {
+ dataMap.put(keyPrefix + ELEM_LONG_SIZE.name(), Integer.toString(longSize));
+ }
+
+ int longLongSize = dataOrg.getLongLongSize();
+ if (longLongSize != DEFAULT_LONG_LONG_SIZE) {
+ dataMap.put(keyPrefix + ELEM_LONG_LONG_SIZE.name(), Integer.toString(longLongSize));
+ }
+
+ int floatSize = dataOrg.getFloatSize();
+ if (floatSize != DEFAULT_FLOAT_SIZE) {
+ dataMap.put(keyPrefix + ELEM_FLOAT_SIZE.name(), Integer.toString(floatSize));
+ }
+
+ int doubleSize = dataOrg.getDoubleSize();
+ if (doubleSize != DEFAULT_DOUBLE_SIZE) {
+ dataMap.put(keyPrefix + ELEM_DOUBLE_SIZE.name(), Integer.toString(doubleSize));
+ }
+
+ int longDoubleSize = dataOrg.getLongDoubleSize();
+ if (longDoubleSize != DEFAULT_LONG_DOUBLE_SIZE) {
+ dataMap.put(keyPrefix + ELEM_LONG_DOUBLE_SIZE.name(), Integer.toString(longDoubleSize));
+ }
+
+ for (int size : dataOrg.getSizes()) {
+ try {
+ String key = keyPrefix + ELEM_SIZE_ALIGNMENT_MAP.name() + "." + size;
+ dataMap.put(key, Integer.toString(dataOrg.getSizeAlignment(size)));
+ }
+ catch (NoValueException e) {
+ // skip entry
+ }
+ }
+
+ BitFieldPackingImpl.save(dataOrg.getBitFieldPacking(), dataMap,
+ keyPrefix + ELEM_BITFIELD_PACKING.name() + ".");
+ }
+
+ /**
+ * Restore a data organization from the specified DB data map.
+ * @param dataMap DB data map
+ * @param keyPrefix key prefix for all map entries
+ * @return data organization
+ * @throws IOException if an IO error occurs
+ */
+ public static DataOrganizationImpl restore(DBStringMapAdapter dataMap, String keyPrefix)
+ throws IOException {
+
+ DataOrganizationImpl dataOrg = new DataOrganizationImpl();
+
+ dataOrg.bigEndian = dataMap.getBoolean(BIG_ENDIAN_NAME, false);
+
+ dataOrg.absoluteMaxAlignment =
+ dataMap.getInt(keyPrefix + ELEM_ABSOLUTE_MAX_ALIGNMENT.name(),
+ dataOrg.absoluteMaxAlignment);
+
+ dataOrg.machineAlignment =
+ dataMap.getInt(keyPrefix + ELEM_MACHINE_ALIGNMENT.name(), dataOrg.machineAlignment);
+
+ dataOrg.defaultAlignment =
+ dataMap.getInt(keyPrefix + ELEM_DEFAULT_ALIGNMENT.name(), dataOrg.defaultAlignment);
+
+ dataOrg.defaultPointerAlignment =
+ dataMap.getInt(keyPrefix + ELEM_DEFAULT_POINTER_ALIGNMENT.name(),
+ dataOrg.defaultPointerAlignment);
+
+ dataOrg.pointerSize =
+ dataMap.getInt(keyPrefix + ELEM_POINTER_SIZE.name(), dataOrg.pointerSize);
+
+ dataOrg.pointerShift =
+ dataMap.getInt(keyPrefix + ELEM_POINTER_SHIFT.name(), dataOrg.pointerShift);
+
+ dataOrg.isSignedChar =
+ dataMap.getBoolean(keyPrefix + SIGNED_CHAR_TYPE_NAME, dataOrg.isSignedChar);
+
+ dataOrg.charSize = dataMap.getInt(keyPrefix + ELEM_CHAR_SIZE.name(), dataOrg.charSize);
+
+ dataOrg.wideCharSize =
+ dataMap.getInt(keyPrefix + ELEM_WCHAR_SIZE.name(), dataOrg.wideCharSize);
+
+ dataOrg.shortSize = dataMap.getInt(keyPrefix + ELEM_SHORT_SIZE.name(), dataOrg.shortSize);
+
+ dataOrg.integerSize =
+ dataMap.getInt(keyPrefix + ELEM_INTEGER_SIZE.name(), dataOrg.integerSize);
+
+ dataOrg.longSize = dataMap.getInt(keyPrefix + ELEM_LONG_SIZE.name(), dataOrg.longSize);
+
+ dataOrg.longLongSize =
+ dataMap.getInt(keyPrefix + ELEM_LONG_LONG_SIZE.name(), dataOrg.longLongSize);
+
+ dataOrg.floatSize = dataMap.getInt(keyPrefix + ELEM_FLOAT_SIZE.name(), dataOrg.floatSize);
+
+ dataOrg.doubleSize =
+ dataMap.getInt(keyPrefix + ELEM_DOUBLE_SIZE.name(), dataOrg.doubleSize);
+
+ dataOrg.longDoubleSize =
+ dataMap.getInt(keyPrefix + ELEM_LONG_DOUBLE_SIZE.name(), dataOrg.longDoubleSize);
+
+ boolean firstEntry = true;
+ String alignmentMapKeyPrefix = keyPrefix + ELEM_SIZE_ALIGNMENT_MAP.name() + ".";
+ for (String key : dataMap.keySet()) {
+ if (!key.startsWith(alignmentMapKeyPrefix)) {
+ continue;
+ }
+ try {
+ int size = Integer.valueOf(key.substring(alignmentMapKeyPrefix.length()));
+ int alignment = Integer.valueOf(dataMap.get(key));
+ if (firstEntry) {
+ dataOrg.sizeAlignmentMap.clear();
+ firstEntry = false;
+ }
+ dataOrg.sizeAlignmentMap.put(size, alignment);
+ }
+ catch (NumberFormatException e) {
+ // ignore
+ }
+ }
+
+ dataOrg.bitFieldPacking =
+ BitFieldPackingImpl.restore(dataMap, keyPrefix + ELEM_BITFIELD_PACKING.name() + ".");
+
+ return dataOrg;
+ }
+
+ /**
+ * Output the details of this data organization to a encoded document formatter.
+ * @param encoder the output document encoder.
+ * @throws IOException if an IO error occurs while encoding/writing output
+ */
public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_DATA_ORGANIZATION);
+
+ // NOTE: endianess intentionally omitted from output
+
if (absoluteMaxAlignment != NO_MAXIMUM_ALIGNMENT) {
encoder.openElement(ELEM_ABSOLUTE_MAX_ALIGNMENT);
encoder.writeSignedInteger(ATTRIB_VALUE, absoluteMaxAlignment);
encoder.closeElement(ELEM_ABSOLUTE_MAX_ALIGNMENT);
}
- if (machineAlignment != 8) {
+ if (machineAlignment != DEFAULT_MACHINE_ALIGNMENT) {
encoder.openElement(ELEM_MACHINE_ALIGNMENT);
encoder.writeSignedInteger(ATTRIB_VALUE, machineAlignment);
encoder.closeElement(ELEM_MACHINE_ALIGNMENT);
}
- if (defaultAlignment != 1) {
+ if (defaultAlignment != DEFAULT_DEFAULT_ALIGNMENT) {
encoder.openElement(ELEM_DEFAULT_ALIGNMENT);
encoder.writeSignedInteger(ATTRIB_VALUE, defaultAlignment);
encoder.closeElement(ELEM_DEFAULT_ALIGNMENT);
}
- if (defaultPointerAlignment != 4) {
+ if (defaultPointerAlignment != DEFAULT_DEFAULT_POINTER_ALIGNMENT) {
encoder.openElement(ELEM_DEFAULT_POINTER_ALIGNMENT);
encoder.writeSignedInteger(ATTRIB_VALUE, defaultPointerAlignment);
encoder.closeElement(ELEM_DEFAULT_POINTER_ALIGNMENT);
}
- if (pointerSize != 0) {
- encoder.openElement(ELEM_POINTER_SIZE);
- encoder.writeSignedInteger(ATTRIB_VALUE, pointerSize);
- encoder.closeElement(ELEM_POINTER_SIZE);
- }
- if (pointerShift != 0) {
+
+ // Always output pointer size
+ encoder.openElement(ELEM_POINTER_SIZE);
+ encoder.writeSignedInteger(ATTRIB_VALUE, pointerSize);
+ encoder.closeElement(ELEM_POINTER_SIZE);
+
+ if (pointerShift != DEFAULT_POINTER_SHIFT) {
encoder.openElement(ELEM_POINTER_SHIFT);
encoder.writeSignedInteger(ATTRIB_VALUE, pointerShift);
encoder.closeElement(ELEM_POINTER_SHIFT);
}
- if (!isSignedChar) {
+ if (isSignedChar != DEFAULT_CHAR_IS_SIGNED) {
encoder.openElement(ELEM_CHAR_TYPE);
- encoder.writeBool(ATTRIB_SIGNED, false);
+ encoder.writeBool(ATTRIB_SIGNED, isSignedChar);
encoder.closeElement(ELEM_CHAR_TYPE);
}
- if (charSize != 1) {
+ if (charSize != DEFAULT_CHAR_SIZE) {
encoder.openElement(ELEM_CHAR_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, charSize);
encoder.closeElement(ELEM_CHAR_SIZE);
}
- if (wideCharSize != 2) {
+ if (wideCharSize != DEFAULT_WIDE_CHAR_SIZE) {
encoder.openElement(ELEM_WCHAR_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, wideCharSize);
encoder.closeElement(ELEM_WCHAR_SIZE);
}
- if (shortSize != 2) {
+ if (shortSize != DEFAULT_SHORT_SIZE) {
encoder.openElement(ELEM_SHORT_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, shortSize);
encoder.closeElement(ELEM_SHORT_SIZE);
}
- if (integerSize != 4) {
+ if (integerSize != DEFAULT_INT_SIZE) {
encoder.openElement(ELEM_INTEGER_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, integerSize);
encoder.closeElement(ELEM_INTEGER_SIZE);
}
- if (longSize != 4) {
+ if (longSize != DEFAULT_LONG_SIZE) {
encoder.openElement(ELEM_LONG_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, longSize);
encoder.closeElement(ELEM_LONG_SIZE);
}
- if (longLongSize != 8) {
+ if (longLongSize != DEFAULT_LONG_LONG_SIZE) {
encoder.openElement(ELEM_LONG_LONG_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, longLongSize);
encoder.closeElement(ELEM_LONG_LONG_SIZE);
}
- if (floatSize != 4) {
+ if (floatSize != DEFAULT_FLOAT_SIZE) {
encoder.openElement(ELEM_FLOAT_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, floatSize);
encoder.closeElement(ELEM_FLOAT_SIZE);
}
- if (doubleSize != 8) {
+ if (doubleSize != DEFAULT_DOUBLE_SIZE) {
encoder.openElement(ELEM_DOUBLE_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, doubleSize);
encoder.closeElement(ELEM_DOUBLE_SIZE);
}
- if (longDoubleSize != 8) {
+ if (longDoubleSize != DEFAULT_LONG_DOUBLE_SIZE) {
encoder.openElement(ELEM_LONG_DOUBLE_SIZE);
encoder.writeSignedInteger(ATTRIB_VALUE, longDoubleSize);
encoder.closeElement(ELEM_LONG_DOUBLE_SIZE);
@@ -654,33 +895,39 @@ public class DataOrganizationImpl implements DataOrganization {
}
/**
- * Restore settings from an XML stream. This expects to see a \ tag.
- * The XML is designed to override existing default settings. So this object needs to
- * be pre-populated with defaults, typically via getDefaultOrganization().
+ * Restore settings from an XML stream. This expects to see parser positioned on the
+ * <data_organization> start tag. The XML is designed to override existing language-specific
+ * default settings which are pre-populated with {@link #getDefaultOrganization(Language)}. This
+ * will will ensure that the endianess setting is properly established since it is not included
+ * in the XML.
* @param parser is the XML stream
*/
public void restoreXml(XmlPullParser parser) {
+
+ // NOTE: endianess intentionally omitted from XML.
+
parser.start();
while (parser.peek().isStart()) {
String name = parser.peek().getName();
- if (name.equals("char_type")) {
+ if (name.equals(ELEM_CHAR_TYPE.name())) {
XmlElement subel = parser.start();
- String boolStr = subel.getAttribute("signed");
- isSignedChar = SpecXmlUtils.decodeBoolean(boolStr);
+ String boolStr = subel.getAttribute(ATTRIB_SIGNED.name());
+ isSignedChar = SpecXmlUtils.decodeBoolean(boolStr, isSignedChar);
parser.end(subel);
continue;
}
- else if (name.equals("bitfield_packing")) {
+ else if (name.equals(ELEM_BITFIELD_PACKING.name())) {
bitFieldPacking.restoreXml(parser);
continue;
}
- else if (name.equals("size_alignment_map")) {
+ else if (name.equals(ELEM_SIZE_ALIGNMENT_MAP.name())) {
XmlElement subel = parser.start();
while (parser.peek().isStart()) {
XmlElement subsubel = parser.start();
- int size = SpecXmlUtils.decodeInt(subsubel.getAttribute("size"));
- int alignment = SpecXmlUtils.decodeInt(subsubel.getAttribute("alignment"));
+ int size = SpecXmlUtils.decodeInt(subsubel.getAttribute(ATTRIB_SIZE.name()));
+ int alignment =
+ SpecXmlUtils.decodeInt(subsubel.getAttribute(ATTRIB_ALIGNMENT.name()));
sizeAlignmentMap.put(size, alignment);
parser.end(subsubel);
}
@@ -689,51 +936,51 @@ public class DataOrganizationImpl implements DataOrganization {
}
XmlElement subel = parser.start();
- String value = subel.getAttribute("value");
+ String value = subel.getAttribute(ATTRIB_VALUE.name());
- if (name.equals("absolute_max_alignment")) {
+ if (name.equals(ELEM_ABSOLUTE_MAX_ALIGNMENT.name())) {
absoluteMaxAlignment = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("machine_alignment")) {
+ else if (name.equals(ELEM_MACHINE_ALIGNMENT.name())) {
machineAlignment = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("default_alignment")) {
+ else if (name.equals(ELEM_DEFAULT_ALIGNMENT.name())) {
defaultAlignment = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("default_pointer_alignment")) {
+ else if (name.equals(ELEM_DEFAULT_POINTER_ALIGNMENT.name())) {
defaultPointerAlignment = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("pointer_size")) {
+ else if (name.equals(ELEM_POINTER_SIZE.name())) {
pointerSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("pointer_shift")) {
+ else if (name.equals(ELEM_POINTER_SHIFT.name())) {
pointerShift = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("char_size")) {
+ else if (name.equals(ELEM_CHAR_SIZE.name())) {
charSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("wchar_size")) {
+ else if (name.equals(ELEM_WCHAR_SIZE.name())) {
wideCharSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("short_size")) {
+ else if (name.equals(ELEM_SHORT_SIZE.name())) {
shortSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("integer_size")) {
+ else if (name.equals(ELEM_INTEGER_SIZE.name())) {
integerSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("long_size")) {
+ else if (name.equals(ELEM_LONG_SIZE.name())) {
longSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("long_long_size")) {
+ else if (name.equals(ELEM_LONG_LONG_SIZE.name())) {
longLongSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("float_size")) {
+ else if (name.equals(ELEM_FLOAT_SIZE.name())) {
floatSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("double_size")) {
+ else if (name.equals(ELEM_DOUBLE_SIZE.name())) {
doubleSize = SpecXmlUtils.decodeInt(value);
}
- else if (name.equals("long_double_size")) {
+ else if (name.equals(ELEM_LONG_DOUBLE_SIZE.name())) {
longDoubleSize = SpecXmlUtils.decodeInt(value);
}
parser.end(subel);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeArchiveIdDumper.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeArchiveIdDumper.java
index 9738ee9cb3..e077d58298 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeArchiveIdDumper.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeArchiveIdDumper.java
@@ -39,6 +39,7 @@ public class DataTypeArchiveIdDumper implements GhidraLaunchable {
FileWriter writer = new FileWriter(outputFile);
FileDataTypeManager archive = FileDataTypeManager.openFileArchive(archiveFile, false);
+ archive.reportWarning();
UniversalID universalID2 = archive.getUniversalID();
writer.write("FILE_ID: " + Long.toHexString(universalID2.getValue()));
writer.write("\n");
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java
index 8fc90407c0..3d806e962c 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java
@@ -18,6 +18,11 @@ package ghidra.program.model.data;
import java.util.*;
import db.Transaction;
+import ghidra.program.database.SpecExtension;
+import ghidra.program.database.map.AddressMap;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
import ghidra.util.exception.CancelledException;
@@ -59,6 +64,21 @@ public interface DataTypeManager {
*/
public UniversalID getUniversalID();
+ /**
+ * Get the optional program architecture details associated with this archive
+ * @return program architecture details or null if none
+ */
+ public ProgramArchitecture getProgramArchitecture();
+
+ /**
+ * Get the program architecture information which has been associated with this
+ * datatype manager. If {@link #getProgramArchitecture()} returns null this method
+ * may still return information if the program architecture was set on an archive but unable
+ * to properly instantiate.
+ * @return program architecture summary if it has been set
+ */
+ public String getProgramArchitectureSummary();
+
/**
* Returns true if the given category path exists in this datatype manager
* @param path the path
@@ -138,6 +158,12 @@ public interface DataTypeManager {
*/
public Iterator getAllComposites();
+ /**
+ * Returns an iterator over all function definition data types in this manager
+ * @return the iterator
+ */
+ public Iterator getAllFunctionDefinitions();
+
/**
* Begin searching at the root category for all data types with the
* given name. Places all the data types in this data type manager
@@ -522,6 +548,13 @@ public interface DataTypeManager {
*/
public DataOrganization getDataOrganization();
+ /**
+ * Returns the associated AddressMap used by this datatype manager.
+ * @return the AddressMap used by this datatype manager or null if
+ * one has not be established.
+ */
+ public AddressMap getAddressMap();
+
/**
* Returns a list of source archives not including the builtin or the program's archive.
* @return a list of source archives not including the builtin or the program's archive.
@@ -568,4 +601,49 @@ public interface DataTypeManager {
* @return true if BuiltIn Settings are permitted
*/
public boolean allowsDefaultComponentSettings();
+
+ /**
+ * Get the ordered list of known calling convention names. The reserved names
+ * "unknown" and "default" are not included. The returned collection will include all names
+ * ever used or resolved by associated {@link Function} and {@link FunctionDefinition} objects,
+ * even if not currently defined by the associated {@link CompilerSpec} or {@link Program}
+ * {@link SpecExtension}. To get only those calling conventions formally defined, the method
+ * {@link CompilerSpec#getCallingConventions()} should be used.
+ *
+ * @return all known calling convention names.
+ */
+ public Collection getKnownCallingConventionNames();
+
+ /**
+ * Get the ordered list of defined calling convention names. The reserved names
+ * "unknown" and "default" are not included. The returned collection may not include all names
+ * referenced by various functions and function-definitions. This set is generally limited to
+ * those defined by the associated compiler specification. If this instance does not have an
+ * assigned architecture the {@link GenericCallingConvention} names will be returned.
+ *
+ * For a set of all known names (including those that are not defined by compiler spec)
+ * see {@link #getKnownCallingConventionNames()}.
+ *
+ * @return the set of defined calling convention names.
+ */
+ public Collection getDefinedCallingConventionNames();
+
+ /**
+ * Get the default calling convention's prototype model in this datatype manager if known.
+ *
+ * @return the default calling convention prototype model or null.
+ */
+ public PrototypeModel getDefaultCallingConvention();
+
+ /**
+ * Get the prototype model of the calling convention with the specified name from the
+ * associated compiler specification. If an architecture has not been established this method
+ * will return null. If {@link Function#DEFAULT_CALLING_CONVENTION_STRING}
+ * is specified {@link #getDefaultCallingConvention()} will be returned.
+ *
+ * @param name the calling convention name
+ * @return the named function calling convention prototype model or null.
+ */
+ public PrototypeModel getCallingConvention(String name);
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListener.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListener.java
index 400955df3f..c1791265f4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListener.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListener.java
@@ -123,4 +123,11 @@ public interface DataTypeManagerChangeListener {
*/
public void sourceArchiveAdded(final DataTypeManager dataTypeManager,
final SourceArchive sourceArchive);
+
+ /**
+ * Notification that the program architecture associated with the specified
+ * dataTypeManager has changed.
+ * @param dataTypeManager data type manager referring to the given source information.
+ */
+ public void programArchitectureChanged(DataTypeManager dataTypeManager);
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerAdapter.java
index 82be93f86d..d55f93374d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerAdapter.java
@@ -73,4 +73,8 @@ public class DataTypeManagerChangeListenerAdapter implements DataTypeManagerChan
public void sourceArchiveChanged(DataTypeManager dataTypeManager, SourceArchive dataTypeSource) {
}
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ }
+
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerHandler.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerHandler.java
index db82316e47..f5765860f9 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerHandler.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerChangeListenerHandler.java
@@ -15,18 +15,20 @@
*/
package ghidra.program.model.data;
-import ghidra.util.datastruct.WeakDataStructureFactory;
-import ghidra.util.datastruct.WeakSet;
-
import java.io.IOException;
import java.io.ObjectInputStream;
import javax.swing.SwingUtilities;
+import ghidra.util.datastruct.WeakDataStructureFactory;
+import ghidra.util.datastruct.WeakSet;
+
/**
*
- * Default implementation for a category change listener that sends out the
- * events to its own list of category change listeners.
+ * Default implementation for a {@link DataTypeManagerChangeListener} that sends out the
+ * events to its own list of listeners.
+ *
+ * NOTE: all listener notifications must be asynchronous within a different thread.
*
*/
public class DataTypeManagerChangeListenerHandler implements DataTypeManagerChangeListener {
@@ -51,158 +53,122 @@ public class DataTypeManagerChangeListenerHandler implements DataTypeManagerChan
}
@Override
- public void categoryAdded(final DataTypeManager dtm, final CategoryPath path) {
+ public void categoryAdded(DataTypeManager dtm, CategoryPath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.categoryAdded(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.categoryAdded(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void categoryMoved(final DataTypeManager dtm, final CategoryPath oldPath,
- final CategoryPath newPath) {
+ public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath,
+ CategoryPath newPath) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.categoryMoved(dtm, oldPath, newPath);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.categoryMoved(dtm, oldPath, newPath);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void categoryRemoved(final DataTypeManager dtm, final CategoryPath path) {
+ public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.categoryRemoved(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.categoryRemoved(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void categoryRenamed(final DataTypeManager dtm, final CategoryPath oldPath,
- final CategoryPath newPath) {
+ public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath,
+ CategoryPath newPath) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.categoryRenamed(dtm, oldPath, newPath);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.categoryRenamed(dtm, oldPath, newPath);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeAdded(final DataTypeManager dtm, final DataTypePath path) {
+ public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeAdded(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeAdded(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeChanged(final DataTypeManager dtm, final DataTypePath path) {
+ public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeChanged(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeChanged(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeMoved(final DataTypeManager dtm, final DataTypePath oldPath,
- final DataTypePath newPath) {
+ public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeMoved(dtm, oldPath, newPath);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeMoved(dtm, oldPath, newPath);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeRemoved(final DataTypeManager dtm, final DataTypePath path) {
+ public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeRemoved(dtm, path);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeRemoved(dtm, path);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void dataTypeRenamed(final DataTypeManager dtm, final DataTypePath oldPath,
- final DataTypePath newPath) {
+ public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeRenamed(dtm, oldPath, newPath);
- listener.favoritesChanged(dtm, oldPath, false);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeRenamed(dtm, oldPath, newPath);
+ listener.favoritesChanged(dtm, oldPath, false);
}
- };
- invokeRunnable(r);
+ });
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
@@ -220,73 +186,67 @@ public class DataTypeManagerChangeListenerHandler implements DataTypeManagerChan
}
@Override
- public void dataTypeReplaced(final DataTypeManager dtm, final DataTypePath oldPath,
- final DataTypePath newPath, final DataType newDataType) {
+ public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath, DataType newDataType) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.dataTypeReplaced(dtm, oldPath, newPath, newDataType);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.dataTypeReplaced(dtm, oldPath, newPath, newDataType);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void favoritesChanged(final DataTypeManager dtm, final DataTypePath path,
- final boolean isFavorite) {
+ public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.favoritesChanged(dtm, path, isFavorite);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.favoritesChanged(dtm, path, isFavorite);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void sourceArchiveChanged(final DataTypeManager dataTypeManager,
- final SourceArchive dataTypeSource) {
+ public void sourceArchiveChanged(DataTypeManager dataTypeManager,
+ SourceArchive dataTypeSource) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.sourceArchiveChanged(dataTypeManager, dataTypeSource);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.sourceArchiveChanged(dataTypeManager, dataTypeSource);
}
- };
- invokeRunnable(r);
+ });
}
@Override
- public void sourceArchiveAdded(final DataTypeManager dataTypeManager,
- final SourceArchive dataTypeSource) {
+ public void sourceArchiveAdded(DataTypeManager dataTypeManager,
+ SourceArchive dataTypeSource) {
if (listenerList.isEmpty()) {
return;
}
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (DataTypeManagerChangeListener listener : listenerList) {
- listener.sourceArchiveAdded(dataTypeManager, dataTypeSource);
- }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.sourceArchiveAdded(dataTypeManager, dataTypeSource);
}
- };
- invokeRunnable(r);
+ });
+ }
+
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ if (listenerList.isEmpty()) {
+ return;
+ }
+ invokeRunnable(() -> {
+ for (DataTypeManagerChangeListener listener : listenerList) {
+ listener.programArchitectureChanged(dataTypeManager);
+ }
+ });
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
index 6a1fed94d9..1a9323c165 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
@@ -22,6 +22,8 @@ import db.DBConstants;
import generic.jar.ResourceFile;
import ghidra.framework.store.db.PackedDBHandle;
import ghidra.framework.store.db.PackedDatabase;
+import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.lang.Language;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
import ghidra.util.exception.*;
@@ -48,15 +50,21 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
/**
* Construct a new DataTypeFileManager using the default data organization.
+ *
+ * NOTE: it may be appropriate to {@link #getWarning() check for warnings} after
+ * opening an existing archive file prior to use. While an archive will remain useable
+ * with a warning condition, architecture-specific data may not be available or up-to-date.
+ *
* @param packedDbfile file to load or create based upon openMode
* @param openMode one of the DBConstants: CREATE, UPDATE, READ_ONLY, UPGRADE
- * @throws IOException
+ * @throws IOException if an IO error occurs
*/
private FileDataTypeManager(ResourceFile packedDbfile, int openMode) throws IOException {
super(validateFilename(packedDbfile), openMode);
file = packedDbfile;
name = getRootName(file.getName());
packedDB = ((PackedDBHandle) dbHandle).getPackedDatabase();
+ reportWarning();
}
private static ResourceFile validateFilename(ResourceFile packedDbfile) {
@@ -70,18 +78,27 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
* Create a new data-type file archive using the default data organization
* @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
* @return data-type manager backed by specified packedDbFile
- * @throws IOException
+ * @throws IOException if an IO error occurs
*/
public static FileDataTypeManager createFileArchive(File packedDbfile) throws IOException {
return new FileDataTypeManager(new ResourceFile(packedDbfile), DBConstants.CREATE);
}
/**
- * Open an existing data-type file archive using the default data organization
+ * Open an existing data-type file archive using the default data organization.
+ *
+ * NOTE: If archive has an assigned architecture, issues may arise due to a revised or
+ * missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
+ * prevent the archive from being opened. Such a warning condition will ne logged and may
+ * result in missing or stale information for existing datatypes which have architecture related
+ * data. In some case it may be appropriate to
+ * {@link FileDataTypeManager#getWarning() check for warnings} on the returned archive
+ * object prior to its use.
+ *
* @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
* @param openForUpdate if true archive will be open for update
* @return data-type manager backed by specified packedDbFile
- * @throws IOException
+ * @throws IOException if an IO error occurs
*/
public static FileDataTypeManager openFileArchive(File packedDbfile, boolean openForUpdate)
throws IOException {
@@ -89,11 +106,20 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
}
/**
- * Open an existing data-type file archive using the default data organization
+ * Open an existing data-type file archive using the default data organization.
+ *
+ * NOTE: If archive has an assigned architecture, issues may arise due to a revised or
+ * missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
+ * prevent the archive from being opened. Such a warning condition will ne logged and may
+ * result in missing or stale information for existing datatypes which have architecture related
+ * data. In some case it may be appropriate to
+ * {@link FileDataTypeManager#getWarning() check for warnings} on the returned archive
+ * object prior to its use.
+ *
* @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
* @param openForUpdate if true archive will be open for update
* @return data-type manager backed by specified packedDbFile
- * @throws IOException
+ * @throws IOException if an IO error occurs
*/
public static FileDataTypeManager openFileArchive(ResourceFile packedDbfile,
boolean openForUpdate) throws IOException {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java
index c1c90571c2..7ce46edeca 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java
@@ -16,7 +16,9 @@
package ghidra.program.model.data;
import ghidra.program.model.listing.FunctionSignature;
+import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.SourceType;
+import ghidra.util.exception.InvalidInputException;
/**
* Defines a function signature for things like function pointers.
@@ -49,12 +51,44 @@ public interface FunctionDefinition extends DataType, FunctionSignature {
*/
public void setVarArgs(boolean hasVarArgs);
+ /**
+ * Set whether or not this function has a return.
+ *
+ * @param hasNoReturn true if this function does not return.
+ */
+ public void setNoReturn(boolean hasNoReturn);
+
/**
* Set the generic calling convention associated with this function definition.
+ *
+ * The total number of unique calling convention names used within a given {@link Program}
+ * or {@link DataTypeManager} may be limited (e.g., 127). When this limit is exceeded an error
+ * will be logged and this setting ignored.
+ *
* @param genericCallingConvention generic calling convention
+ * @deprecated Use of {@link GenericCallingConvention} is deprecated since arbitrary calling
+ * convention names are now supported. {@link #setCallingConvention(String)} should be used.
*/
public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention);
+ /**
+ * Set the calling convention associated with this function definition.
+ *
+ * The total number of unique calling convention names used within a given {@link Program}
+ * or {@link DataTypeManager} may be limited (e.g., 127). When this limit is exceeded an error
+ * will be logged and this setting ignored.
+ *
+ * @param conventionName calling convention name or null. This name is restricted to those
+ * defined by {@link GenericCallingConvention}, the associated compiler specification.
+ * The prototype model declaration name form (e.g., "__stdcall") should be specified as it
+ * appears in a compiler specification (*.cspec). The special "unknown" and "default" names
+ * are also allowed.
+ * @throws InvalidInputException if specified conventionName is not defined by
+ * {@link GenericCallingConvention} or the associated compiler specification if
+ * datatype manager has an associated program architecture.
+ */
+ public void setCallingConvention(String conventionName) throws InvalidInputException;
+
/**
* Replace the given argument with another data type
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinitionDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinitionDataType.java
index 4e518c3108..7a407f70f3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinitionDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinitionDataType.java
@@ -19,11 +19,12 @@ import java.util.ArrayList;
import ghidra.docking.settings.Settings;
import ghidra.program.database.data.DataTypeUtilities;
-import ghidra.program.model.lang.PrototypeModel;
+import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.UniversalID;
+import ghidra.util.exception.InvalidInputException;
/**
* Definition of a function for things like function pointers.
@@ -34,7 +35,8 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
private ParameterDefinition[] params;
private String comment;
private boolean hasVarArgs;
- private GenericCallingConvention genericCallingConvention = GenericCallingConvention.unknown;
+ private boolean hasNoReturn;
+ private String callingConventionName = CompilerSpec.CALLING_CONVENTION_unknown;
public FunctionDefinitionDataType(String name) {
this(CategoryPath.ROOT, name, null, null);
@@ -108,15 +110,9 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
params = paramList.toArray(new ParameterDefinition[paramList.size()]);
hasVarArgs = function.hasVarArgs();
+ hasNoReturn = function.hasNoReturn();
- PrototypeModel prototypeModel = function.getCallingConvention();
-
- if (prototypeModel == null) {
- genericCallingConvention = GenericCallingConvention.unknown;
- }
- else {
- genericCallingConvention = prototypeModel.getGenericCallingConvention();
- }
+ callingConventionName = function.getCallingConventionName();
}
private ParameterDefinition getParameterDefinition(Parameter param, boolean useFormalType,
@@ -140,7 +136,8 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
setReturnType(rtnType.clone(getDataTypeManager()));
setArguments(sig.getArguments());
hasVarArgs = sig.hasVarArgs();
- genericCallingConvention = sig.getGenericCallingConvention();
+ hasNoReturn = sig.hasNoReturn();
+ callingConventionName = sig.getCallingConventionName();
}
@Override
@@ -169,14 +166,58 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
}
@Override
- public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention) {
- this.genericCallingConvention = genericCallingConvention;
+ public void setNoReturn(boolean hasNoReturn) {
+ this.hasNoReturn = hasNoReturn;
}
@Override
- public GenericCallingConvention getGenericCallingConvention() {
- return genericCallingConvention != null ? genericCallingConvention
- : GenericCallingConvention.unknown;
+ public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention) {
+ this.callingConventionName = genericCallingConvention.getDeclarationName();
+ }
+
+ @Override
+ public void setCallingConvention(String conventionName) throws InvalidInputException {
+
+ if (conventionName == null ||
+ CompilerSpec.CALLING_CONVENTION_unknown.equals(conventionName)) {
+ this.callingConventionName = CompilerSpec.CALLING_CONVENTION_unknown;
+ return;
+ }
+ if (CompilerSpec.CALLING_CONVENTION_default.equals(conventionName)) {
+ this.callingConventionName = CompilerSpec.CALLING_CONVENTION_default;
+ return;
+ }
+
+ if (GenericCallingConvention
+ .getGenericCallingConvention(conventionName) != GenericCallingConvention.unknown) {
+ ProgramArchitecture arch = dataMgr != null ? dataMgr.getProgramArchitecture() : null;
+ if (arch != null) {
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ PrototypeModel callingConvention =
+ compilerSpec.getCallingConvention(conventionName);
+ if (callingConvention == null) {
+ throw new InvalidInputException(
+ "Invalid calling convention name: " + conventionName);
+ }
+ }
+ }
+
+ this.callingConventionName = conventionName;
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention() {
+ ProgramArchitecture arch = dataMgr != null ? dataMgr.getProgramArchitecture() : null;
+ if (arch == null) {
+ return null;
+ }
+ CompilerSpec compilerSpec = arch.getCompilerSpec();
+ return compilerSpec.getCallingConvention(callingConventionName);
+ }
+
+ @Override
+ public String getCallingConventionName() {
+ return callingConventionName;
}
@Override
@@ -227,11 +268,15 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
@Override
public String getPrototypeString(boolean includeCallingConvention) {
StringBuffer buf = new StringBuffer();
+ if (includeCallingConvention && hasNoReturn) {
+ buf.append(NORETURN_DISPLAY_STRING);
+ buf.append(" ");
+ }
buf.append((returnType != null ? returnType.getDisplayName() : "void"));
buf.append(" ");
if (includeCallingConvention &&
- genericCallingConvention != GenericCallingConvention.unknown) {
- buf.append(genericCallingConvention.name());
+ !Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConventionName)) {
+ buf.append(callingConventionName);
buf.append(" ");
}
buf.append(name);
@@ -279,6 +324,11 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
return hasVarArgs;
}
+ @Override
+ public boolean hasNoReturn() {
+ return hasNoReturn;
+ }
+
/**
* Compare the comment of the given function signature to my comment.
*
@@ -316,7 +366,8 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
(DataTypeUtilities.isSameOrEquivalentDataType(signature.getReturnType(),
this.returnType)) &&
(hasVarArgs == signature.hasVarArgs()) &&
- (genericCallingConvention == signature.getGenericCallingConvention())) {
+ (hasNoReturn == signature.hasNoReturn()) &&
+ callingConventionName.equals(signature.getCallingConventionName())) {
ParameterDefinition[] args = signature.getArguments();
if (args.length == this.params.length) {
for (int i = 0; i < args.length; i++) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/GenericCallingConvention.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/GenericCallingConvention.java
index cdd9ab0248..cecd440ecb 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/GenericCallingConvention.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/GenericCallingConvention.java
@@ -21,6 +21,10 @@ import ghidra.program.model.lang.CompilerSpec;
* GenericCallingConvention identifies the generic calling convention
* associated with a specific function definition. This can be used to help identify
* the appropriate compiler-specific function prototype (i.e., calling convention).
+ *
+ * @deprecated Calling convention name strings should be used instead of this class.
+ * {@link CompilerSpec} provides constants for those included in this enumeration and other
+ * setter/getter methods exist for using the string form.
*/
public enum GenericCallingConvention {
@@ -76,14 +80,11 @@ public enum GenericCallingConvention {
/**
* Returns the GenericCallingConvention corresponding to the specified
- * type string or unknown. Case and underscore prefix is ignored.
- * @param callingConvention calling convention name
- * @return GenericCallingConvention
+ * type string or unknown if name is not defined.
+ * @param callingConvention calling convention declaration name (e.g., "__stdcall")
+ * @return GenericCallingConvention or {@link #unknown} if not found.
*/
public static GenericCallingConvention getGenericCallingConvention(String callingConvention) {
- while (callingConvention.startsWith("_")) {
- callingConvention = callingConvention.substring(1);
- }
for (GenericCallingConvention value : GenericCallingConvention.values()) {
if (value.name().equalsIgnoreCase(callingConvention)) {
return value;
@@ -92,28 +93,6 @@ public enum GenericCallingConvention {
return unknown;
}
- /**
- * Returns the GenericCallingConvention which is likely to correspond with the
- * specified prototype name.
- * @param callingConvention compiler specific calling convention name
- * @return GenericCallingConvention
- */
- public static GenericCallingConvention guessFromName(String callingConvention) {
- if (callingConvention == null) {
- return unknown;
- }
- callingConvention = callingConvention.toLowerCase();
- for (GenericCallingConvention value : GenericCallingConvention.values()) {
- if (value == unknown) {
- continue;
- }
- if (callingConvention.contains(value.name())) {
- return value;
- }
- }
- return unknown;
- }
-
/**
* Returns the GenericCallingConvention corresponding to the specified
* ordinal.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer16DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer16DataType.java
index 132959c615..f37e2d1f90 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer16DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer16DataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* A fixed size 16 byte signed integer (commonly referred to in C as int128_t)
*/
-public class Integer16DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer16DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer16DataType instance.*/
public final static Integer16DataType dataType = new Integer16DataType();
@@ -30,7 +28,7 @@ public class Integer16DataType extends AbstractIntegerDataType {
}
public Integer16DataType(DataTypeManager dtm) {
- super("int16", true, dtm);
+ super("int16", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer3DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer3DataType.java
index 36b682d5b2..cab694606d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer3DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer3DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class Integer3DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer3DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer3DataType instance.*/
public final static Integer3DataType dataType = new Integer3DataType();
@@ -27,7 +25,7 @@ public class Integer3DataType extends AbstractIntegerDataType {
}
public Integer3DataType(DataTypeManager dtm) {
- super("int3", true, dtm);
+ super("int3", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer5DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer5DataType.java
index 8be233505a..6cec0672ea 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer5DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer5DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class Integer5DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer5DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer5DataType instance.*/
public final static Integer5DataType dataType = new Integer5DataType();
@@ -27,7 +25,7 @@ public class Integer5DataType extends AbstractIntegerDataType {
}
public Integer5DataType(DataTypeManager dtm) {
- super("int5", true, dtm);
+ super("int5", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer6DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer6DataType.java
index fe4733b0af..9761bed8b5 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer6DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer6DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class Integer6DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer6DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer6DataType instance.*/
public final static Integer6DataType dataType = new Integer6DataType();
@@ -27,7 +25,7 @@ public class Integer6DataType extends AbstractIntegerDataType {
}
public Integer6DataType(DataTypeManager dtm) {
- super("int6", true, dtm);
+ super("int6", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer7DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer7DataType.java
index 135a74f0c5..eacb1dd002 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer7DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Integer7DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class Integer7DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class Integer7DataType extends AbstractSignedIntegerDataType {
/** A statically defined Integer7DataType instance.*/
public final static Integer7DataType dataType = new Integer7DataType();
@@ -27,7 +25,7 @@ public class Integer7DataType extends AbstractIntegerDataType {
}
public Integer7DataType(DataTypeManager dtm) {
- super("int7", true, dtm);
+ super("int7", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IntegerDataType.java
index 61f713916c..10e0019cf6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IntegerDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IntegerDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for an signed Integer dataType
*/
-public class IntegerDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class IntegerDataType extends AbstractSignedIntegerDataType {
/** A statically defined IntegerDataType instance.*/
public final static IntegerDataType dataType = new IntegerDataType();
@@ -30,7 +28,7 @@ public class IntegerDataType extends AbstractIntegerDataType {
}
public IntegerDataType(DataTypeManager dtm) {
- super("int", true, dtm);
+ super("int", dtm);
}
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDataType.java
index 5c310a809e..48796e6b94 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for a Signed Long Integer dataType
*/
-public class LongDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class LongDataType extends AbstractSignedIntegerDataType {
/** A statically defined LongDataType instance.*/
public final static LongDataType dataType = new LongDataType();
@@ -30,29 +28,19 @@ public class LongDataType extends AbstractIntegerDataType {
}
public LongDataType(DataTypeManager dtm) {
- super("long", true, dtm);
+ super("long", dtm);
}
- /**
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getLongSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Signed Long Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongLongDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongLongDataType.java
index 0c8b95dce4..a913b56067 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongLongDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongLongDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for an Signed LongLong Integer dataType
*/
-public class LongLongDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class LongLongDataType extends AbstractSignedIntegerDataType {
/** A statically defined LongLongDataType instance.*/
public final static LongLongDataType dataType = new LongLongDataType();
@@ -30,29 +28,19 @@ public class LongLongDataType extends AbstractIntegerDataType {
}
public LongLongDataType(DataTypeManager dtm) {
- super("longlong", true, dtm);
+ super("longlong", dtm);
}
- /**
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getLongLongSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Signed Long Long Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramArchitectureTranslator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramArchitectureTranslator.java
new file mode 100644
index 0000000000..67a42c6043
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProgramArchitectureTranslator.java
@@ -0,0 +1,69 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.model.data;
+
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
+import ghidra.program.util.DefaultLanguageService;
+import ghidra.program.util.LanguageTranslatorAdapter;
+
+public class ProgramArchitectureTranslator extends LanguageTranslatorAdapter {
+
+ private CompilerSpec oldCompilerSpec;
+ private CompilerSpec newCompilerSpec;
+
+ public ProgramArchitectureTranslator(Language oldLanguage, CompilerSpecID oldCompilerSpecId,
+ Language newLanguage, CompilerSpecID newCompilerSpecId)
+ throws CompilerSpecNotFoundException, IncompatibleLanguageException {
+ super(oldLanguage, newLanguage);
+ if (!oldLanguage.getProcessor().equals(newLanguage.getProcessor())) {
+ throw new IncompatibleLanguageException("Architecture processors differ: " +
+ oldLanguage.getProcessor() + " vs " + newLanguage.getProcessor());
+ }
+ this.oldCompilerSpec = oldLanguage.getCompilerSpecByID(oldCompilerSpecId);
+ this.newCompilerSpec = newLanguage.getCompilerSpecByID(newCompilerSpecId);
+ validateDefaultSpaceMap();
+ }
+
+ public ProgramArchitectureTranslator(LanguageID oldLanguageId, int oldLanguageVersion,
+ CompilerSpecID oldCompilerSpecId, Language newLanguage,
+ CompilerSpecID newCompilerSpecId)
+ throws LanguageNotFoundException, CompilerSpecNotFoundException,
+ IncompatibleLanguageException {
+ this(getLanguage(oldLanguageId, oldLanguageVersion), oldCompilerSpecId, newLanguage,
+ newCompilerSpecId);
+ }
+
+ private static Language getLanguage(LanguageID languageId, int languageVersion)
+ throws LanguageNotFoundException {
+ Language language = DefaultLanguageService.getLanguageService().getLanguage(languageId);
+ if (languageVersion > 0 && language.getVersion() != languageVersion) {
+ throw new LanguageNotFoundException(
+ "Language not found for '" + languageId + "' version " + languageVersion + ".x");
+ }
+ return language;
+ }
+
+ public CompilerSpec getOldCompilerSpec() {
+ return oldCompilerSpec;
+ }
+
+ public CompilerSpec getNewCompilerSpec() {
+ return newCompilerSpec;
+ }
+
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/QWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/QWordDataType.java
index de85f83a9a..6de4d09765 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/QWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/QWordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a definition of a Quad Word within a program.
*/
-public class QWordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class QWordDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined QWordDataType instance.*/
public final static QWordDataType dataType = new QWordDataType();
@@ -30,7 +28,7 @@ public class QWordDataType extends AbstractIntegerDataType {
}
public QWordDataType(DataTypeManager dtm) {
- super("qword", false, dtm);
+ super("qword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ShortDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ShortDataType.java
index dd1ac9e3e4..83ce54f9ba 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ShortDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ShortDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for a Short Integer dataType
*/
-public class ShortDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class ShortDataType extends AbstractSignedIntegerDataType {
/** A statically defined ShortDataType instance.*/
public final static ShortDataType dataType = new ShortDataType();
@@ -30,29 +28,19 @@ public class ShortDataType extends AbstractIntegerDataType {
}
public ShortDataType(DataTypeManager dtm) {
- super("short", true, dtm);
+ super("short", dtm);
}
- /**
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getShortSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Signed Short Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedByteDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedByteDataType.java
index 50b96dd33b..f41f444b13 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedByteDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedByteDataType.java
@@ -20,9 +20,7 @@ import ghidra.program.model.lang.DecompilerLanguage;
/**
* Provides a definition of a Signed Byte within a program.
*/
-public class SignedByteDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class SignedByteDataType extends AbstractSignedIntegerDataType {
/** A statically defined SignedByteDataType instance.*/
public final static SignedByteDataType dataType = new SignedByteDataType();
@@ -32,7 +30,7 @@ public class SignedByteDataType extends AbstractIntegerDataType {
}
public SignedByteDataType(DataTypeManager dtm) {
- super("sbyte", true, dtm);
+ super("sbyte", dtm);
}
@Override
@@ -52,8 +50,9 @@ public class SignedByteDataType extends AbstractIntegerDataType {
@Override
public String getDecompilerDisplayName(DecompilerLanguage language) {
- if (language == DecompilerLanguage.JAVA_LANGUAGE)
+ if (language == DecompilerLanguage.JAVA_LANGUAGE) {
return "byte";
+ }
return name;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedCharDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedCharDataType.java
index e79ef3bcf3..2ef633df67 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedCharDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedCharDataType.java
@@ -22,7 +22,6 @@ package ghidra.program.model.data;
* associated data type manager.
*/
public class SignedCharDataType extends CharDataType {
- private final static long serialVersionUID = 1;
public static final SignedCharDataType dataType = new SignedCharDataType();
@@ -34,7 +33,12 @@ public class SignedCharDataType extends CharDataType {
}
public SignedCharDataType(DataTypeManager dtm) {
- super("schar", true, dtm);
+ super("schar", dtm);
+ }
+
+ @Override
+ public boolean isSigned() {
+ return true;
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedDWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedDWordDataType.java
index b1e5e1a3de..fbcf50ebd2 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedDWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedDWordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a definition of a Signed Double Word within a program.
*/
-public class SignedDWordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class SignedDWordDataType extends AbstractSignedIntegerDataType {
/** A statically defined SignedDWordDataType instance.*/
public final static SignedDWordDataType dataType = new SignedDWordDataType();
@@ -30,7 +28,7 @@ public class SignedDWordDataType extends AbstractIntegerDataType {
}
public SignedDWordDataType(DataTypeManager dtm) {
- super("sdword", true, dtm);
+ super("sdword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedQWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedQWordDataType.java
index 1a2800f0f8..c81df3d093 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedQWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedQWordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a definition of a Signed Quad Word within a program.
*/
-public class SignedQWordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class SignedQWordDataType extends AbstractSignedIntegerDataType {
/** A statically defined SignedQWordDataType instance.*/
public final static SignedQWordDataType dataType = new SignedQWordDataType();
@@ -30,7 +28,7 @@ public class SignedQWordDataType extends AbstractIntegerDataType {
}
public SignedQWordDataType(DataTypeManager dtm) {
- super("sqword", true, dtm);
+ super("sqword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedWordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedWordDataType.java
index 7e909ce939..ed6dad3ef0 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedWordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/SignedWordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a basic implementation of a signed word datatype
*/
-public class SignedWordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class SignedWordDataType extends AbstractSignedIntegerDataType {
/** A statically defined SignedWordDataType instance.*/
public final static SignedWordDataType dataType = new SignedWordDataType();
@@ -30,7 +28,7 @@ public class SignedWordDataType extends AbstractIntegerDataType {
}
public SignedWordDataType(DataTypeManager dtm) {
- super("sword", true, dtm);
+ super("sword", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java
index 9ee458c209..e25c6d4b99 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java
@@ -15,26 +15,100 @@
*/
package ghidra.program.model.data;
+import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
-import db.Transaction;
-import db.DBConstants;
+import javax.help.UnsupportedOperationException;
+
+import com.google.common.collect.ImmutableList;
+
+import db.*;
+import db.util.ErrorHandler;
import generic.jar.ResourceFile;
+import ghidra.framework.store.LockException;
+import ghidra.program.database.DBStringMapAdapter;
+import ghidra.program.database.ProgramAddressFactory;
import ghidra.program.database.data.DataTypeManagerDB;
-import ghidra.util.InvalidNameException;
+import ghidra.program.database.symbol.VariableStorageManager;
+import ghidra.program.database.symbol.VariableStorageManagerDB;
+import ghidra.program.model.address.AddressFactory;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
+import ghidra.program.util.DefaultLanguageService;
+import ghidra.program.util.LanguageTranslator;
+import ghidra.util.*;
+import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
* Basic implementation of the DataTypeManger interface
*/
-public class StandAloneDataTypeManager extends DataTypeManagerDB {
+public class StandAloneDataTypeManager extends DataTypeManagerDB implements Closeable {
+
+ private static final String LANGUAGE_VERSION = "Language Version"; // major version only
+ private static final String LANGUAGE_ID = "Language ID";
+ private static final String COMPILER_SPEC_ID = "Compiler Spec ID";
- protected String name;
private int transactionCount;
private Long transaction;
private boolean commitTransaction;
+ private LanguageTranslator languageUpgradeTranslator;
+ private String programArchitectureSummary; // summary of expected program architecture
+
+ protected String name;
+
+ public static enum ArchiveWarning {
+ /**
+ * {@link #NONE} indicates a normal archive condition
+ */
+ NONE,
+
+ /**
+ * {@link #UPGRADED_LANGUAGE_VERSION} indicates an archive which has been open for update
+ * was upgraded to a newer language version. This is expected when the {@link Language}
+ * required by the associated {@link ProgramArchitecture} has a major version change
+ * which involves significant {@link Register} changes. Sharing an upgraded archive
+ * may impact others who do not have access to the updated {@link Language} module.
+ */
+ UPGRADED_LANGUAGE_VERSION,
+
+ // programArchitectureSummary must be set for the warnings below
+
+ /**
+ * {@link #LANGUAGE_NOT_FOUND} indicates the {@link Language} or its appropriate version,
+ * required by the associated {@link ProgramArchitecture}, was not found or encountered
+ * a problem being loaded. The {@link FileDataTypeManager#getWarningDetail()} may provide
+ * additional insight to the underlying cause.
+ */
+ LANGUAGE_NOT_FOUND,
+
+ /**
+ * {@link #COMPILER_SPEC_NOT_FOUND} indicates the {@link CompilerSpec},
+ * required by the associated {@link ProgramArchitecture}, was not found or encountered
+ * a problem being loaded. The {@link FileDataTypeManager#getWarningDetail()} may provide
+ * additional insight to the underlying cause. This condition can only occur if the
+ * required {@link Language} was found.
+ */
+ COMPILER_SPEC_NOT_FOUND,
+
+ /**
+ * {@link #LANGUAGE_UPGRADE_REQURED} indicates an archive which has been open read-only
+ * requires an upgraded to a newer language version. This is expected when the
+ * {@link Language} required by the associated {@link ProgramArchitecture} has a major
+ * version change within the current installation. Major version changes for a
+ * {@link Language} rarely occur but are required when significant {@link Register}
+ * or addressing changes have been made. Upgrading a shared archive may impact others
+ * who do not have access to the updated {@link Language} module and should be
+ * coordinated with others who may be affected.
+ */
+ LANGUAGE_UPGRADE_REQURED,
+ }
+
+ private ArchiveWarning warning;
+ private Exception warningDetail;
+
/**
* Constructor for new temporary data-type manager using the default DataOrganization.
* Note that this manager does not support the save or saveAs operation.
@@ -59,6 +133,12 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
/**
* Constructor for a data-type manager backed by a packed database file.
* When opening for UPDATE an automatic upgrade will be performed if required.
+ *
+ * NOTE: {@link #reportWarning()} should be invoked immediately after
+ * instantiating a {@link StandAloneDataTypeManager} for an existing database after
+ * {@link #getName()} and {@link #getPath()} can be invoked safely. In addition, it
+ * may be appropriate to use {@link #getWarning() check for warnings} prior to use.
+ *
* @param packedDbfile packed datatype archive file (i.e., *.gdt resource).
* @param openMode open mode CREATE, READ_ONLY or UPDATE (see {@link DBConstants})
* @throws IOException a low-level IO error. This exception may also be thrown
@@ -69,6 +149,579 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
super(packedDbfile, openMode);
}
+ /**
+ * Constructor for a data-type manager using a specified DBHandle.
+ *
+ * NOTE: {@link #reportWarning()} should be invoked immediately after
+ * instantiating a {@link StandAloneDataTypeManager} for an existing database after
+ * {@link #getName()} and {@link #getPath()} can be invoked safely. In addition, it
+ * may be appropriate to use {@link #getWarning() check for warnings} prior to use.
+ *
+ * @param handle open database handle
+ * @param openMode the program open mode
+ * @param errHandler the database I/O error handler
+ * @param lock the program synchronization lock
+ * @param monitor the progress monitor
+ * @throws CancelledException if the user cancels an upgrade
+ * @throws VersionException if the database does not match the expected version.
+ * @throws IOException if a database I/O error occurs.
+ */
+ protected StandAloneDataTypeManager(DBHandle handle, int openMode, ErrorHandler errHandler,
+ Lock lock, TaskMonitor monitor)
+ throws CancelledException, VersionException, IOException {
+ super(handle, null, openMode, null, errHandler, lock, monitor);
+ }
+
+ /**
+ * Get the {@link ArchiveWarning} which may have occured immediately following
+ * instatiation of this {@link StandAloneDataTypeManager}. {@link ArchiveWarning#NONE}
+ * will be returned if not warning condition.
+ * @return warning type.
+ */
+ public ArchiveWarning getWarning() {
+ return warning;
+ }
+
+ /**
+ * Get the detail exception associated with {@link ArchiveWarning#LANGUAGE_NOT_FOUND} or
+ * {@link ArchiveWarning#COMPILER_SPEC_NOT_FOUND} warning (see {@link #getWarning()})
+ * immediately following instatiation of this {@link StandAloneDataTypeManager}.
+ * @return warning detail exception or null
+ */
+ public Exception getWarningDetail() {
+ return warningDetail;
+ }
+
+ /**
+ * Due to the supression of error and warning conditions during instantiation this method should
+ * be invoked at the end of instatiation when {@link #getName()} and {@link #getPath()} are
+ * ready to be invoked safely. Logging will be performed via {@link Msg}.
+ */
+ protected void reportWarning() {
+ String msg;
+ switch (warning) {
+ case NONE:
+ break;
+ case LANGUAGE_NOT_FOUND:
+ msg = "Language not found for Archive '" + getName() + "': " +
+ warningDetail.getMessage();
+ Msg.error(this, msg);
+ break;
+ case COMPILER_SPEC_NOT_FOUND:
+ msg = "Compiler specification not found for Archive '" + getName() + "': " +
+ warningDetail.getMessage();
+ Msg.error(this, msg);
+ break;
+ case LANGUAGE_UPGRADE_REQURED:
+ msg = "Language upgrade required for Archive '" + getName() + "': " +
+ programArchitectureSummary;
+ Msg.warn(this, msg);
+ break;
+ case UPGRADED_LANGUAGE_VERSION:
+ ProgramArchitecture arch = getProgramArchitecture();
+ LanguageDescription languageDescription =
+ arch.getLanguage().getLanguageDescription();
+ msg =
+ "Upgraded program-architecture for Archive: '" + getName() +
+ "'\n Language: " +
+ languageDescription.getLanguageID() + " Version " +
+ languageDescription.getVersion() + ".x" +
+ ", CompilerSpec: " + arch.getCompilerSpec().getCompilerSpecID();
+ Msg.info(this, msg);
+ }
+
+ }
+
+ @Override
+ protected void initializeOtherAdapters(int openMode, TaskMonitor monitor)
+ throws CancelledException, IOException, VersionException {
+
+ warning = ArchiveWarning.NONE;
+ if (openMode == DBConstants.CREATE) {
+ return; // optional program architecture is set after initialization is complete
+ }
+
+ // Check for optional program architecture data (LanguageID, etc.)
+ // The DB data map is also used by the base implementation to store the data organization
+ DBStringMapAdapter dataMap = getDataMap(false);
+ if (dataMap == null) {
+ return;
+ }
+
+ String languageIdStr = dataMap.get(LANGUAGE_ID);
+ if (languageIdStr == null) {
+ return; // assume architecture info is missing
+ }
+ LanguageID languageId = new LanguageID(languageIdStr);
+ CompilerSpecID compilerSpecId = new CompilerSpecID(dataMap.get(COMPILER_SPEC_ID));
+ int languageVersion = 1;
+ try {
+ languageVersion = Integer.parseInt(dataMap.get(LANGUAGE_VERSION));
+ }
+ catch (Exception e) {
+ // Ignore
+ }
+
+ VariableStorageManagerDB variableStorageMgr = null;
+ if (VariableStorageManagerDB.exists(dbHandle)) {
+ variableStorageMgr =
+ new VariableStorageManagerDB(dbHandle, null, openMode, errHandler, lock, monitor);
+ }
+
+ programArchitectureSummary =
+ getProgramArchitectureSummary(languageId, languageVersion, compilerSpecId);
+
+ Language language = null;
+ LanguageVersionException languageVersionExc = null;
+ try {
+ language = DefaultLanguageService.getLanguageService().getLanguage(languageId);
+ languageVersionExc =
+ LanguageVersionException.check(language, languageVersion, -1); // don't care about minor version
+ }
+ catch (LanguageNotFoundException e) {
+ warning = ArchiveWarning.LANGUAGE_NOT_FOUND;
+ warningDetail = e;
+ try {
+ languageVersionExc =
+ LanguageVersionException.checkForLanguageChange(e, languageId, languageVersion);
+ }
+ catch (LanguageNotFoundException e2) {
+ // Missing language or language translation
+ warningDetail = e2;
+ return; // allow archive to open without error
+ }
+ }
+
+ if (languageVersionExc != null && !languageVersionExc.isUpgradable()) {
+ // Inability to translate language treated like language-not-found
+ warning = ArchiveWarning.LANGUAGE_NOT_FOUND;
+ warningDetail = languageVersionExc;
+ }
+ else if (languageVersionExc != null) {
+ warning = ArchiveWarning.LANGUAGE_UPGRADE_REQURED;
+ languageUpgradeTranslator = languageVersionExc.getLanguageTranslator();
+
+ // language upgrade required
+ if (openMode == DBConstants.READ_ONLY) {
+ // read-only mode - do not set program architecture - upgrade flag has been set
+ return;
+ }
+
+ if (openMode == DBConstants.UPDATE) {
+ throw languageVersionExc;
+ }
+
+ // else UPGRADE mode falls-through
+ language = languageUpgradeTranslator.getNewLanguage();
+ compilerSpecId = languageUpgradeTranslator.getNewCompilerSpecID(compilerSpecId);
+ }
+
+ assert (language != null);
+
+ CompilerSpec compilerSpec;
+ try {
+ compilerSpec = language.getCompilerSpecByID(compilerSpecId);
+ }
+ catch (CompilerSpecNotFoundException e) {
+ warning = ArchiveWarning.COMPILER_SPEC_NOT_FOUND;
+ warningDetail = e;
+ return; // allow archive to open without error
+ }
+
+ if (warning == ArchiveWarning.LANGUAGE_UPGRADE_REQURED) {
+
+ if (variableStorageMgr != null) {
+ variableStorageMgr.setLanguage(languageUpgradeTranslator, monitor);
+ }
+
+ // update data map with language upgrade info
+ dataMap.put(LANGUAGE_ID, language.getLanguageID().getIdAsString());
+ dataMap.put(LANGUAGE_VERSION, Integer.toString(language.getVersion()));
+ dataMap.put(COMPILER_SPEC_ID, compilerSpecId.getIdAsString());
+
+ warning = ArchiveWarning.UPGRADED_LANGUAGE_VERSION;
+ }
+
+ programArchitectureSummary = null; // not needed
+
+ final Language lang = language;
+ final CompilerSpec cspec = compilerSpec;
+ final AddressFactory addrFactory = new ProgramAddressFactory(lang, cspec);
+
+ super.setProgramArchitecture(new ProgramArchitecture() {
+
+ @Override
+ public Language getLanguage() {
+ return lang;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return cspec;
+ }
+
+ @Override
+ public AddressFactory getAddressFactory() {
+ return addrFactory;
+ }
+ }, variableStorageMgr, false, monitor);
+
+ if (variableStorageMgr != null) {
+ variableStorageMgr.setProgramArchitecture(getProgramArchitecture());
+ }
+
+ }
+
+ /**
+ * Get the program architecture information which has been associated with this
+ * datatype manager. If {@link #getProgramArchitecture()} returns null this method
+ * may still return information if the program architecture was set on an archive
+ * and either {@link #isProgramArchitectureMissing()} or
+ * {@link #isProgramArchitectureUpgradeRequired()} returns true.
+ * @return program architecture summary if it has been set
+ */
+ @Override
+ public String getProgramArchitectureSummary() {
+ if (programArchitectureSummary != null) {
+ return programArchitectureSummary;
+ }
+ return super.getProgramArchitectureSummary();
+ }
+
+ /**
+ * Delete all program architecture related data in response to an
+ * architecture change when all related data should be removed.
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if task cancelled
+ */
+ private void deleteAllProgramArchitectureData(TaskMonitor monitor)
+ throws IOException, CancelledException {
+
+ clearCustomStorageUse(monitor);
+
+ DBStringMapAdapter dataMap = getDataMap(false);
+ if (dataMap != null) {
+ dataMap.delete(LANGUAGE_ID);
+ dataMap.delete(LANGUAGE_VERSION);
+ dataMap.delete(COMPILER_SPEC_ID);
+ }
+
+ VariableStorageManagerDB.delete(dbHandle);
+
+ warning = ArchiveWarning.NONE;
+ programArchitectureSummary = null;
+ }
+
+ private VariableStorageManagerDB createProgramArchitectureData(
+ ProgramArchitecture programArchitecture, VariableStorageManagerDB variableStorageMgr)
+ throws IOException {
+ Language newLanguage = programArchitecture.getLanguage();
+ LanguageID newLanguageId = newLanguage.getLanguageID();
+ CompilerSpec newCompilerSpec = programArchitecture.getCompilerSpec();
+ CompilerSpecID newCmpilerSpecID = newCompilerSpec.getCompilerSpecID();
+
+ DBStringMapAdapter dataMap = getDataMap(true);
+ dataMap.put(LANGUAGE_ID, newLanguageId.getIdAsString());
+ dataMap.put(COMPILER_SPEC_ID, newCmpilerSpecID.getIdAsString());
+ dataMap.put(LANGUAGE_VERSION, Integer.toString(newLanguage.getVersion())); // major version only
+
+ if (variableStorageMgr == null) { // TODO: may re-use if translation performed
+ try {
+ variableStorageMgr = new VariableStorageManagerDB(dbHandle, null,
+ DBConstants.CREATE, errHandler, lock, TaskMonitor.DUMMY);
+ variableStorageMgr.setProgramArchitecture(programArchitecture);
+ }
+ catch (VersionException | CancelledException e) {
+ throw new AssertException(e); // unexpected
+ }
+ }
+
+ variableStorageMgr.setProgramArchitecture(programArchitecture);
+
+ warning = ArchiveWarning.NONE;
+ programArchitectureSummary = null;
+
+ return variableStorageMgr;
+ }
+
+ /**
+ * Indicates that an program architecture upgrade is required in order
+ * to constitute associated data. If true, the associated archive
+ * must be open for update to allow the upgrade to complete, or a new
+ * program architecture may be set/cleared if such an operation is supported.
+ * @return true if a program architecture upgrade is required, else false
+ */
+ public boolean isProgramArchitectureUpgradeRequired() {
+ return warning == ArchiveWarning.LANGUAGE_UPGRADE_REQURED;
+ }
+
+ /**
+ * Indicates that a failure occured establishing the program architecture
+ * for the associated archive.
+ * @return true if a failure occured establishing the program architecture
+ */
+ public boolean isProgramArchitectureMissing() {
+ return warning == ArchiveWarning.LANGUAGE_NOT_FOUND ||
+ warning == ArchiveWarning.COMPILER_SPEC_NOT_FOUND;
+ }
+
+
+ /**
+ * Clear the program architecture setting and all architecture-specific data from this archive.
+ * Archive will revert to using the default {@link DataOrganization}.
+ * Archive must be open for update for this method to be used.
+ * @param monitor task monitor
+ * @throws CancelledException if task cancelled. If thrown, this data type manager is no longer
+ * stable and should be closed without saving.
+ * @throws IOException if IO error occurs
+ * @throws LockException failure if exclusive access is required
+ * @throws UnsupportedOperationException if architecture change is not permitted by
+ * implementation (e.g., {@link BuiltInDataTypeManager}).
+ */
+ public void clearProgramArchitecture(TaskMonitor monitor)
+ throws CancelledException, IOException, LockException {
+ lock.acquire();
+ try {
+
+ if (!isArchitectureChangeAllowed()) {
+ throw new UnsupportedOperationException(
+ "Program-architecture change not permitted");
+ }
+
+ if (!dbHandle.canUpdate()) {
+ throw new ReadOnlyException("Read-only Archive: " + getName());
+ }
+
+ if (getProgramArchitecture() == null && !isProgramArchitectureMissing()) {
+ return;
+ }
+
+ Msg.info(this, "Removing program-architecture for Archive: " + getName());
+
+ int txId = startTransaction("Remove Program Architecture");
+ try {
+ if (!isArchitectureChangeAllowed()) {
+ throw new UnsupportedOperationException(
+ "Program-architecture change not permitted");
+ }
+ deleteAllProgramArchitectureData(monitor);
+
+ super.setProgramArchitecture((ProgramArchitecture) null, null, true, monitor);
+ }
+ finally {
+ // TODO: ensure state is restored if transaction rollback/cancel occurs
+ endTransaction(txId, !monitor.isCancelled());
+ }
+
+ defaultListener.programArchitectureChanged(this);
+ }
+ finally {
+ invalidateCache();
+ lock.release();
+ }
+ }
+
+ public static enum LanguageUpdateOption {
+ /**
+ * All existing storage data should be cleared
+ */
+ CLEAR,
+ /**
+ * An attempt should be made to translate from old-to-new language.
+ * This has limitations (i.e., similar architecture) and may result in
+ * poor register mappings.
+ */
+ TRANSLATE,
+ /**
+ * Variable storage data will be retained as-is but may not de-serialize
+ * properly when used.
+ */
+ UNCHANGED // TODO: Need to test to see if this option is safe and useable
+ }
+
+ /**
+ * Establish the program architecture for this datatype manager. The current setting can be
+ * determined from {@link #getProgramArchitecture()}. Archive must be open for update for
+ * this method to be used.
+ * @param language language
+ * @param compilerSpecId compiler specification ID defined by the language.
+ * @param updateOption indicates how variable storage data should be transitioned. If {@link #isProgramArchitectureMissing()}
+ * is true and {@link LanguageUpdateOption#TRANSLATE} specified, the translator will be based on whatever language version can
+ * be found. In this situation it may be best to force a {@link LanguageUpdateOption#CLEAR}.
+ * @param monitor task monitor (cancel not permitted to avoid corrupt state)
+ * @throws CompilerSpecNotFoundException if invalid compilerSpecId specified for language
+ * @throws LanguageNotFoundException if current language is not found (if required for data transition)
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if task cancelled. If thrown, this data type manager is no longer
+ * stable and should be closed without saving.
+ * @throws LockException failure if exclusive access is required
+ * @throws UnsupportedOperationException if architecture change is not permitted
+ * @throws IncompatibleLanguageException if translation requested but not possible due to incompatible language architectures
+ */
+ public void setProgramArchitecture(Language language, CompilerSpecID compilerSpecId,
+ LanguageUpdateOption updateOption, TaskMonitor monitor)
+ throws CompilerSpecNotFoundException, LanguageNotFoundException, IOException,
+ CancelledException, LockException, UnsupportedOperationException,
+ IncompatibleLanguageException {
+
+ lock.acquire();
+ try {
+
+ if (!isArchitectureChangeAllowed()) {
+ throw new UnsupportedOperationException(
+ "Program-architecture change not permitted");
+ }
+
+ if (!dbHandle.canUpdate()) {
+ throw new ReadOnlyException("Read-only Archive: " + getName());
+ }
+
+ Msg.info(this,
+ "Updating program-architecture for Archive: " + getName() + "\n Language: " +
+ language.getLanguageID() + " version " + language.getVersion() + ".x" +
+ ", CompilerSpec: " + compilerSpecId);
+
+ CompilerSpec compilerSpec = language.getCompilerSpecByID(compilerSpecId);
+
+ // This type of datatype manager only uses VariableStorageManagerDB
+ VariableStorageManagerDB variableStorageMgr =
+ (VariableStorageManagerDB) getVariableStorageManager();
+
+ int txId = startTransaction("Set Program Architecture");
+ try {
+ ProgramArchitectureTranslator translator = null;
+
+ ProgramArchitecture oldArch = getProgramArchitecture();
+ if (oldArch != null || isProgramArchitectureMissing()) {
+
+ if (updateOption == LanguageUpdateOption.CLEAR) {
+ deleteAllProgramArchitectureData(monitor);
+ variableStorageMgr = null;
+ }
+ else if (isProgramArchitectureMissing()) {
+
+ assert (variableStorageMgr == null);
+
+ if (updateOption == LanguageUpdateOption.TRANSLATE) {
+ // Go out on a limb and use any version of old language if available
+ DBStringMapAdapter dataMap = getDataMap(false);
+ LanguageID oldLanguageId =
+ new LanguageID(getDataMap(false).get(LANGUAGE_ID));
+ CompilerSpecID oldCompilerSpecId =
+ new CompilerSpecID(dataMap.get(COMPILER_SPEC_ID));
+ translator = new ProgramArchitectureTranslator(oldLanguageId, -1,
+ oldCompilerSpecId, language, compilerSpecId);
+ }
+
+ if (VariableStorageManagerDB.exists(dbHandle)) {
+ try {
+ variableStorageMgr = new VariableStorageManagerDB(dbHandle, null,
+ DBConstants.UPDATE, errHandler, lock, monitor);
+ }
+ catch (VersionException e) {
+ throw new IOException(
+ "Unexpected version error for VariableStorageManagerDB");
+ }
+ }
+ }
+ else if (updateOption == LanguageUpdateOption.TRANSLATE) {
+ translator = new ProgramArchitectureTranslator(oldArch.getLanguage(),
+ oldArch.getCompilerSpec().getCompilerSpecID(), language,
+ compilerSpecId);
+ }
+
+ if (translator != null && variableStorageMgr != null) {
+ variableStorageMgr.setLanguage(translator, monitor);
+ }
+ }
+
+ ProgramArchitecture programArchitecture = new ProgramArchitecture() {
+
+ @Override
+ public Language getLanguage() {
+ return language;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return compilerSpec;
+ }
+
+ @Override
+ public AddressFactory getAddressFactory() {
+ return language.getAddressFactory();
+ }
+ };
+
+ variableStorageMgr =
+ createProgramArchitectureData(programArchitecture, variableStorageMgr);
+
+ super.setProgramArchitecture(programArchitecture, variableStorageMgr, true,
+ monitor);
+ }
+ finally {
+ // TODO: ensure state is restored if transaction rollback/cancel occurs
+ endTransaction(txId, !monitor.isCancelled());
+ }
+
+ defaultListener.programArchitectureChanged(this);
+ }
+ finally {
+ invalidateCache();
+ lock.release();
+ }
+ }
+
+ /**
+ * Set the architecture-specific details associated with a new datatype manager.
+ * This method is intended to be used during instantiation of derived implementations.
+ * @param programArchitecture program architecture details (required)
+ * @param variableStorageMgr variable storage manager. Must be null.
+ * @param store if true database update will occur and datatypes will be updated if
+ * any change to the data organization is detected (a stored copy may be used to
+ * detect this condition). This should never be passed as true if opened read-only.
+ * If true and no variable storage is specified it will be created.
+ * @param monitor task monitor
+ * @throws IOException if IO error occurs
+ * @throws CancelledException if task cancelled
+ * @throws UnsupportedOperationException if language was previously set
+ */
+ @Override
+ protected void setProgramArchitecture(ProgramArchitecture programArchitecture,
+ VariableStorageManager variableStorageMgr, boolean store, TaskMonitor monitor)
+ throws IOException, CancelledException {
+
+ // TODO: Determine if cancelling can leave in bad state
+
+ if (programArchitecture == null) {
+ throw new IllegalArgumentException("ProgramArchitecture must be specified");
+ }
+ if (variableStorageMgr != null) {
+ throw new IllegalArgumentException("VariableStorageManager may not be specified");
+ }
+
+ if (getProgramArchitecture() != null || isProgramArchitectureUpgradeRequired() ||
+ isProgramArchitectureMissing()) {
+ throw new UnsupportedOperationException(
+ "Program-architecture change not permitted with this method");
+ }
+
+ if (store) {
+ variableStorageMgr = createProgramArchitectureData(programArchitecture, null);
+ }
+
+ // super handles possible change to data organization and update if store is true
+ super.setProgramArchitecture(programArchitecture, variableStorageMgr, store, monitor);
+ }
+
+ /**
+ * Determine if a program architecture change is permitted
+ * @return true if change allowed else false if disallowed
+ */
+ protected boolean isArchitectureChangeAllowed() {
+ return true;
+ }
+
@Override
public String getName() {
return name;
@@ -83,12 +736,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
defaultListener.categoryRenamed(this, CategoryPath.ROOT, CategoryPath.ROOT);
}
-
- @Override
- public final DataOrganization getDataOrganization() {
- return super.getDataOrganization();
- }
-
+
@Override
public Transaction openTransaction(String description) throws IllegalStateException {
return new Transaction() {
@@ -173,8 +821,13 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
return null;
}
+ /**
+ * Get the path name associated with the storage of this stand alone
+ * datatype manager.
+ * @return path name or null if not applicable
+ */
@Override
- protected String getPath() {
+ public String getPath() {
return null;
}
@@ -182,4 +835,30 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB {
public ArchiveType getType() {
return ArchiveType.TEST;
}
+
+ /**
+ * Update custom storage for function definitions to be unassigned.
+ * @param monitor task monitor
+ * @throws CancelledException if task cancelled
+ */
+ private void clearCustomStorageUse(TaskMonitor monitor) throws CancelledException {
+
+ // Get copy of all function defs to avoid concurrent modification of underlaying table
+ ImmutableList defs = ImmutableList.copyOf(getAllFunctionDefinitions());
+
+ monitor.initialize(defs.size());
+ monitor.setMessage("Clear custom storage use...");
+
+// for (FunctionDefinition def : ImmutableList.copyOf(getAllFunctionDefinitions())) {
+ monitor.checkCanceled();
+// monitor.incrementProgress(1);
+//
+// // TODO: update function definition
+// if (def.hasCustomStorage()) {
+//
+//
+// }
+// }
+
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedCharDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedCharDataType.java
index cc088cf221..1b9f27d0ad 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedCharDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedCharDataType.java
@@ -34,7 +34,12 @@ public class UnsignedCharDataType extends CharDataType {
}
public UnsignedCharDataType(DataTypeManager dtm) {
- super("uchar", false, dtm);
+ super("uchar", dtm);
+ }
+
+ @Override
+ public boolean isSigned() {
+ return false;
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger16DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger16DataType.java
index 883f75815d..09bb37dc20 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger16DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger16DataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* A fixed size 16 byte unsigned integer (commonly referred to in C as uint128_t)
*/
-public class UnsignedInteger16DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger16DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger16DataType instance.*/
public final static UnsignedInteger16DataType dataType = new UnsignedInteger16DataType();
@@ -30,7 +28,7 @@ public class UnsignedInteger16DataType extends AbstractIntegerDataType {
}
public UnsignedInteger16DataType(DataTypeManager dtm) {
- super("uint16", false, dtm);
+ super("uint16", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger3DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger3DataType.java
index e9ac687917..eb1ee6c391 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger3DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger3DataType.java
@@ -17,9 +17,7 @@ package ghidra.program.model.data;
import ghidra.util.classfinder.ClassTranslator;
-public class UnsignedInteger3DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger3DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger3DataType instance.*/
public final static UnsignedInteger3DataType dataType = new UnsignedInteger3DataType();
@@ -34,7 +32,7 @@ public class UnsignedInteger3DataType extends AbstractIntegerDataType {
}
public UnsignedInteger3DataType(DataTypeManager dtm) {
- super("uint3", false, dtm);
+ super("uint3", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger5DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger5DataType.java
index 6acdeb20e9..c0001cc35d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger5DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger5DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class UnsignedInteger5DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger5DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger5DataType instance.*/
public final static UnsignedInteger5DataType dataType = new UnsignedInteger5DataType();
@@ -27,7 +25,7 @@ public class UnsignedInteger5DataType extends AbstractIntegerDataType {
}
public UnsignedInteger5DataType(DataTypeManager dtm) {
- super("uint5", false, dtm);
+ super("uint5", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger6DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger6DataType.java
index e98562d40f..e952b0e144 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger6DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger6DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class UnsignedInteger6DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger6DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger6DataType instance.*/
public final static UnsignedInteger6DataType dataType = new UnsignedInteger6DataType();
@@ -27,7 +25,7 @@ public class UnsignedInteger6DataType extends AbstractIntegerDataType {
}
public UnsignedInteger6DataType(DataTypeManager dtm) {
- super("uint6", false, dtm);
+ super("uint6", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger7DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger7DataType.java
index 381c790f14..b69b0d2123 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger7DataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedInteger7DataType.java
@@ -15,9 +15,7 @@
*/
package ghidra.program.model.data;
-public class UnsignedInteger7DataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class UnsignedInteger7DataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedInteger7DataType instance.*/
public final static UnsignedInteger7DataType dataType = new UnsignedInteger7DataType();
@@ -27,7 +25,7 @@ public class UnsignedInteger7DataType extends AbstractIntegerDataType {
}
public UnsignedInteger7DataType(DataTypeManager dtm) {
- super("uint7", false, dtm);
+ super("uint7", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedIntegerDataType.java
index 76ca393b36..e3445d53f8 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedIntegerDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedIntegerDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for an unsigned Integer dataType
*/
-public class UnsignedIntegerDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class UnsignedIntegerDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedIntegerDataType instance.*/
public final static UnsignedIntegerDataType dataType = new UnsignedIntegerDataType();
@@ -30,30 +28,19 @@ public class UnsignedIntegerDataType extends AbstractIntegerDataType {
}
public UnsignedIntegerDataType(DataTypeManager dtm) {
- super("uint", false, dtm);
+ super("uint", dtm);
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getIntegerSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Unsigned Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongDataType.java
index 4fb6e2aa87..f4e662f2c9 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for a Signed Long Integer dataType
*/
-public class UnsignedLongDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class UnsignedLongDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedLongDataType instance.*/
public final static UnsignedLongDataType dataType = new UnsignedLongDataType();
@@ -30,30 +28,19 @@ public class UnsignedLongDataType extends AbstractIntegerDataType {
}
public UnsignedLongDataType(DataTypeManager dtm) {
- super("ulong", false, dtm);
+ super("ulong", dtm);
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getLongSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Unsigned Long Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongLongDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongLongDataType.java
index c46bb4a33c..b6f653ea90 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongLongDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedLongLongDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for an Signed LongLong Integer dataType
*/
-public class UnsignedLongLongDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class UnsignedLongLongDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedLongLongDataType instance.*/
public final static UnsignedLongLongDataType dataType = new UnsignedLongLongDataType();
@@ -30,30 +28,19 @@ public class UnsignedLongLongDataType extends AbstractIntegerDataType {
}
public UnsignedLongLongDataType(DataTypeManager dtm) {
- super("ulonglong", false, dtm);
+ super("ulonglong", dtm);
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getLongLongSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Unsigned Long Long Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedShortDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedShortDataType.java
index 57d40651f0..a1bfd44203 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedShortDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnsignedShortDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Basic implementation for a Short Integer dataType
*/
-public class UnsignedShortDataType extends AbstractIntegerDataType {
-
- private final static long serialVersionUID = 1;
+public class UnsignedShortDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined UnsignedShortDataType instance.*/
public final static UnsignedShortDataType dataType = new UnsignedShortDataType();
@@ -30,30 +28,19 @@ public class UnsignedShortDataType extends AbstractIntegerDataType {
}
public UnsignedShortDataType(DataTypeManager dtm) {
- super("ushort", false, dtm);
+ super("ushort", dtm);
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getLength()
- */
@Override
public int getLength() {
return getDataOrganization().getShortSize();
}
- /**
- * @see ghidra.program.model.data.DataType#hasLanguageDependantLength()
- */
@Override
public boolean hasLanguageDependantLength() {
return true;
}
- /**
- *
- * @see ghidra.program.model.data.DataType#getDescription()
- */
@Override
public String getDescription() {
return "Unsigned Short Integer (compiler-specific size)";
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WordDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WordDataType.java
index f33ed19a70..9ffea46759 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WordDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WordDataType.java
@@ -18,9 +18,7 @@ package ghidra.program.model.data;
/**
* Provides a basic implementation of a word datatype
*/
-public class WordDataType extends AbstractIntegerDataType {
-
- private static final long serialVersionUID = 1L;
+public class WordDataType extends AbstractUnsignedIntegerDataType {
/** A statically defined WordDataType instance.*/
public final static WordDataType dataType = new WordDataType();
@@ -30,7 +28,7 @@ public class WordDataType extends AbstractIntegerDataType {
}
public WordDataType(DataTypeManager dtm) {
- super("word", false, dtm);
+ super("word", dtm);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java
index 78487bfba8..09e34cc9b4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java
@@ -32,9 +32,9 @@ import generic.jar.ResourceFile;
import generic.stl.Pair;
import ghidra.app.plugin.processors.sleigh.*;
import ghidra.program.model.address.*;
-import ghidra.program.model.data.*;
-import ghidra.program.model.listing.DefaultProgramContext;
-import ghidra.program.model.listing.Parameter;
+import ghidra.program.model.data.DataOrganization;
+import ghidra.program.model.data.DataOrganizationImpl;
+import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.*;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
@@ -312,6 +312,12 @@ public class BasicCompilerSpec implements CompilerSpec {
@Override
public PrototypeModel getCallingConvention(String name) {
+ if (name == null || Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
+ return null;
+ }
+ if (Function.DEFAULT_CALLING_CONVENTION_STRING.equals(name)) {
+ return getDefaultCallingConvention();
+ }
return callingConventionMap.get(name);
}
@@ -1077,12 +1083,14 @@ public class BasicCompilerSpec implements CompilerSpec {
}
@Override
- public PrototypeModel matchConvention(GenericCallingConvention genericCallingConvention) {
- if (genericCallingConvention == GenericCallingConvention.unknown) {
+ public PrototypeModel matchConvention(String conventionName) {
+ if (conventionName == null ||
+ CALLING_CONVENTION_unknown.equals(conventionName) ||
+ CALLING_CONVENTION_default.equals(conventionName)) {
return defaultModel;
}
for (PrototypeModel model : models) {
- if (model.getGenericCallingConvention() == genericCallingConvention) {
+ if (model.getName().equals(conventionName)) {
return model;
}
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java
index f208ee8c33..061f6057a4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java
@@ -21,7 +21,6 @@ import java.util.Set;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.DataOrganization;
-import ghidra.program.model.data.GenericCallingConvention;
import ghidra.program.model.listing.DefaultProgramContext;
import ghidra.program.model.listing.Parameter;
import ghidra.program.model.pcode.Encoder;
@@ -40,6 +39,9 @@ import ghidra.program.model.pcode.Encoder;
*/
public interface CompilerSpec {
+ public static final String CALLING_CONVENTION_unknown = "unknown";
+ public static final String CALLING_CONVENTION_default = "default";
+
public final static String CALLING_CONVENTION_cdecl = "__cdecl";
public final static String CALLING_CONVENTION_pascal = "__pascal";
public final static String CALLING_CONVENTION_thiscall = "__thiscall";
@@ -174,15 +176,16 @@ public interface CompilerSpec {
public PcodeInjectLibrary getPcodeInjectLibrary();
/**
- * Get the PrototypeModel corresponding to the given generic calling convention
- * @param genericCallingConvention is the given generic calling convention
+ * Get the PrototypeModel which corresponds to the given calling convention name.
+ * If no match is found the default prototype model is returned.
+ * @param conventionName calling convention name.
* @return the matching model or the defaultModel if nothing matches
*/
- public PrototypeModel matchConvention(GenericCallingConvention genericCallingConvention);
+ public PrototypeModel matchConvention(String conventionName);
/**
* Find the best guess at a calling convention model from this compiler spec
- * given an ordered list of (potential) parameters.
+ * given an ordered list of (potential) parameters with storage assignments.
* @param params is the ordered list of parameters
* @return prototype model corresponding to the specified function signature
*/
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpecID.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpecID.java
index 421c6f9d81..53b1b21202 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpecID.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpecID.java
@@ -18,17 +18,20 @@ package ghidra.program.model.lang;
/**
* Represents an opinion's compiler (gcc, borlandcpp, etc).
*/
-public class CompilerSpecID implements Comparable {
+public final class CompilerSpecID implements Comparable {
+
+ public static final String DEFAULT_ID = "default";
private final String id;
/**
* Creates a new compiler spec ID.
*
- * @param id The compiler ID (gcc, borlandcpp, etc).
+ * @param id The compiler ID (gcc, borlandcpp, etc) as defined in the appropriate
+ * {@link LanguageDescription}. If null the value of "default" will be assumed.
*/
public CompilerSpecID(String id) {
- this.id = id;
+ this.id = id != null ? id : DEFAULT_ID;
}
/**
@@ -38,12 +41,6 @@ public class CompilerSpecID implements Comparable {
* @throws IllegalArgumentException if the compiler spec ID is null or empty.
*/
public String getIdAsString() {
- if (id == null) {
- throw new IllegalArgumentException("id == null not allowed");
- }
- if ("".equals(id)) {
- throw new IllegalArgumentException("empty id not allowed");
- }
return id;
}
@@ -51,7 +48,7 @@ public class CompilerSpecID implements Comparable {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + id.hashCode();
return result;
}
@@ -67,15 +64,7 @@ public class CompilerSpecID implements Comparable {
return false;
}
final CompilerSpecID other = (CompilerSpecID) obj;
- if (id == null) {
- if (other.id != null) {
- return false;
- }
- }
- else if (!id.equals(other.id)) {
- return false;
- }
- return true;
+ return id.equals(other.id);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java
index a74ad79b44..2496c4b6c6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java
@@ -16,7 +16,8 @@
package ghidra.program.model.lang;
import ghidra.program.model.address.Address;
-import ghidra.program.model.listing.*;
+import ghidra.program.model.listing.AutoParameterType;
+import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.pcode.Varnode;
import ghidra.util.exception.InvalidInputException;
@@ -56,7 +57,8 @@ public class DynamicVariableStorage extends VariableStorage {
* @param size varnode size
* @throws InvalidInputException
*/
- public DynamicVariableStorage(Program program, AutoParameterType autoParamType, Address address,
+ public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType,
+ Address address,
int size) throws InvalidInputException {
super(program, address, size);
this.autoParamType = autoParamType;
@@ -69,7 +71,8 @@ public class DynamicVariableStorage extends VariableStorage {
* @param varnodes one or more ordered storage varnodes
* @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public DynamicVariableStorage(Program program, AutoParameterType autoParamType, Varnode... varnodes)
+ public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType,
+ Varnode... varnodes)
throws InvalidInputException {
super(program, varnodes);
this.autoParamType = autoParamType;
@@ -84,7 +87,8 @@ public class DynamicVariableStorage extends VariableStorage {
* @param size varnode size
* @throws InvalidInputException
*/
- public DynamicVariableStorage(Program program, boolean forcedIndirect, Address address, int size)
+ public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect,
+ Address address, int size)
throws InvalidInputException {
super(program, address, size);
this.forcedIndirect = forcedIndirect;
@@ -98,7 +102,8 @@ public class DynamicVariableStorage extends VariableStorage {
* @param varnodes one or more ordered storage varnodes
* @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public DynamicVariableStorage(Program program, boolean forcedIndirect, Varnode... varnodes)
+ public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect,
+ Varnode... varnodes)
throws InvalidInputException {
super(program, varnodes);
this.forcedIndirect = forcedIndirect;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/LanguageCompilerSpecPair.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/LanguageCompilerSpecPair.java
index 408a60c535..b561b3cb26 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/LanguageCompilerSpecPair.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/LanguageCompilerSpecPair.java
@@ -70,6 +70,22 @@ public final class LanguageCompilerSpecPair implements Comparable languageMinorVersion) {
// Minor version change - translator not needed (languageUpgradeTranslator is null)
- return new LanguageVersionException();
+ String fromVer = languageVersion + "." + languageMinorVersion;
+ String toVer = languageVersion + "." + language.getMinorVersion();
+ return new LanguageVersionException("Minor language change " + fromVer + " -> " + toVer,
+ true);
}
else if (language.getMinorVersion() != languageMinorVersion ||
language.getVersion() != languageVersion) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ProgramArchitecture.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ProgramArchitecture.java
new file mode 100644
index 0000000000..e38ebb7139
--- /dev/null
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ProgramArchitecture.java
@@ -0,0 +1,57 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.program.model.lang;
+
+import ghidra.program.model.address.AddressFactory;
+import ghidra.program.model.address.OverlayAddressSpace;
+import ghidra.program.model.listing.Program;
+
+/**
+ * ProgramArchitecture which identifies program architecture details required to
+ * utilize language/compiler-specific memory and variable storage specifications.
+ */
+public interface ProgramArchitecture {
+
+ /**
+ * Get the processor language
+ * @return processor language
+ */
+ Language getLanguage();
+
+ /**
+ * Get the address factory for this architecture. In the case of a {@link Program} this should
+ * be the extended address factory that includes the stack space and any defined overlay
+ * spaces (i.e., {@link OverlayAddressSpace}).
+ * @return address factory
+ */
+ AddressFactory getAddressFactory();
+
+ /**
+ * Get the compiler specification
+ * @return compiler specification
+ */
+ CompilerSpec getCompilerSpec();
+
+ /**
+ * Get the language/compiler spec ID pair associated with this program architecture.
+ * @return language/compiler spec ID pair
+ */
+ public default LanguageCompilerSpecPair getLanguageCompilerSpecPair() {
+ return new LanguageCompilerSpecPair(getLanguage().getLanguageID(),
+ getCompilerSpec().getCompilerSpecID());
+ }
+
+}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java
index 52a7dd2c34..b67b21b472 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java
@@ -55,7 +55,6 @@ public class PrototypeModel {
private AddressSet localRange; // Range on the stack considered for local storage
private AddressSet paramRange; // Range on the stack considered for parameter storage
private InputListType inputListType = InputListType.STANDARD;
- private GenericCallingConvention genericCallingConvention;
private boolean hasThis; // Convention has a this (auto-parameter)
private boolean isConstruct; // Convention is used for object construction
private boolean hasUponEntry; // Does this have an uponentry injection
@@ -88,7 +87,6 @@ public class PrototypeModel {
paramRange = new AddressSet(model.paramRange);
hasThis = model.hasThis || name.equals(CompilerSpec.CALLING_CONVENTION_thiscall);
isConstruct = model.isConstruct;
- genericCallingConvention = GenericCallingConvention.getGenericCallingConvention(name);
hasUponEntry = model.hasUponEntry;
hasUponReturn = model.hasUponReturn;
}
@@ -107,21 +105,12 @@ public class PrototypeModel {
compatModel = null;
localRange = null;
paramRange = null;
- genericCallingConvention = GenericCallingConvention.unknown;
hasThis = false;
isConstruct = false;
hasUponEntry = false;
hasUponReturn = false;
}
- /**
- * Get the generic calling convention enum associated with this
- * @return the enum
- */
- public GenericCallingConvention getGenericCallingConvention() {
- return genericCallingConvention;
- }
-
/**
* @return list of registers unaffected by called functions
*/
@@ -439,10 +428,6 @@ public class PrototypeModel {
encoder.writeString(ATTRIB_EXTRAPOP, "unknown");
}
encoder.writeSignedInteger(ATTRIB_STACKSHIFT, stackshift);
- GenericCallingConvention nameType = GenericCallingConvention.guessFromName(name);
- if (nameType != genericCallingConvention) {
- encoder.writeString(ATTRIB_TYPE, genericCallingConvention.getDeclarationName());
- }
if (hasThis) {
encoder.writeBool(ATTRIB_HASTHIS, true);
}
@@ -602,13 +587,6 @@ public class PrototypeModel {
extrapop = SpecXmlUtils.decodeInt(extpopStr);
}
stackshift = SpecXmlUtils.decodeInt(protoElement.getAttribute("stackshift"));
- String type = protoElement.getAttribute("type");
- if (type != null) {
- genericCallingConvention = GenericCallingConvention.getGenericCallingConvention(type);
- }
- else {
- genericCallingConvention = GenericCallingConvention.guessFromName(name);
- }
hasThis = false;
isConstruct = false;
String thisString = protoElement.getAttribute("hasthis");
@@ -742,9 +720,6 @@ public class PrototypeModel {
if (extrapop != obj.extrapop || stackshift != obj.stackshift) {
return false;
}
- if (genericCallingConvention != obj.genericCallingConvention) {
- return false;
- }
if (hasThis != obj.hasThis || isConstruct != obj.isConstruct) {
return false;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java
index a8f48cccf8..cae228ceda 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java
@@ -24,6 +24,7 @@ import java.util.*;
import ghidra.app.plugin.processors.sleigh.SleighException;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Parameter;
+import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.pcode.Encoder;
import ghidra.xml.*;
@@ -101,7 +102,11 @@ public class PrototypeModelMerged extends PrototypeModel {
for (int i = 0; i < modellist.length; ++i) {
ScoreProtoModel scoremodel = new ScoreProtoModel(true, modellist[i], params.length);
for (Parameter p : params) {
- scoremodel.addParameter(p.getMinAddress(), p.getLength());
+ VariableStorage storage = p.getVariableStorage();
+ if (storage.isUnassignedStorage() || storage.isBadStorage()) {
+ continue;
+ }
+ scoremodel.addParameter(storage.getMinAddress(), p.getLength());
}
scoremodel.doScore();
int score = scoremodel.getScore();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.java
index 96b8d793bd..9de3080709 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.java
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
- * REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,10 +15,10 @@
*/
package ghidra.program.model.listing;
-import ghidra.program.model.data.DataTypeManagerDomainObject;
-
import java.util.Date;
+import ghidra.program.model.data.DataTypeManagerDomainObject;
+
/**
* This interface represents the main entry point into an object which
* stores all information relating to a single data type archive.
@@ -37,6 +36,13 @@ public interface DataTypeArchive extends DataTypeManagerDomainObject {
/** A date from January 1, 1970 */
public static final Date JANUARY_1_1970 = new Date(0);
+ /**
+ * Determine if this archive has exclusive-write access which may be neccessary for some
+ * operations.
+ * @return true if archive has exclusive-write access
+ */
+ public boolean hasExclusiveAccess();
+
/**
* Gets the default pointer size as it may be stored within the data type archive.
* @return default pointer size.
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java
index eb3dbb09ad..a4437ef4c2 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java
@@ -22,6 +22,8 @@ import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.DataTypeManager;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.DuplicateNameException;
@@ -42,8 +44,10 @@ public interface Function extends Namespace {
public static final String DEFAULT_LOCAL_RESERVED_PREFIX = "local_res";
public static final String DEFAULT_LOCAL_TEMP_PREFIX = "temp_";
public static final int DEFAULT_LOCAL_PREFIX_LEN = DEFAULT_LOCAL_PREFIX.length();
- public static final String UNKNOWN_CALLING_CONVENTION_STRING = "unknown";
- public static final String DEFAULT_CALLING_CONVENTION_STRING = "default";
+ public static final String UNKNOWN_CALLING_CONVENTION_STRING =
+ CompilerSpec.CALLING_CONVENTION_unknown;
+ public static final String DEFAULT_CALLING_CONVENTION_STRING =
+ CompilerSpec.CALLING_CONVENTION_default;
public static final String INLINE = "inline";
public static final String NORETURN = "noreturn";
public static final String THUNK = "thunk";
@@ -177,7 +181,7 @@ public interface Function extends Namespace {
/**
* Set the function's return type.
* @param type the dataType that will define this functions return type.
- * @param source TODO
+ * @param source signature source
* @throws InvalidInputException if data type is not a fixed length.
*/
public void setReturnType(DataType type, SourceType source) throws InvalidInputException;
@@ -399,11 +403,13 @@ public interface Function extends Namespace {
Variable... params) throws DuplicateNameException, InvalidInputException;
/**
- * Replace all current parameters with the given list of parameters and optionally change the calling convention
- * and function return.
+ * Replace all current parameters with the given list of parameters and optionally change the
+ * calling convention and function return.
* The {@link VariableUtilities#checkVariableConflict(Function, Variable, VariableStorage, boolean)}
* method may be used to check and remove conflicting variables which already exist in the function.
- * @param callingConvention updated calling convention name or null if no change is required
+ * @param callingConvention updated calling convention name or null if no change is required.
+ * Only {@link DataTypeManager#getKnownCallingConventionNames() known calling convention names}
+ * may be specified which will always include those defined by the associated {@link CompilerSpec}.
* @param returnValue return variable or null if no change required
* @param updateType function update type
* @param force if true any conflicting local parameters will be removed
@@ -422,11 +428,13 @@ public interface Function extends Namespace {
throws DuplicateNameException, InvalidInputException;
/**
- * Replace all current parameters with the given list of parameters and optionally change the calling convention
- * and function return.
+ * Replace all current parameters with the given list of parameters and optionally change the
+ * calling convention and function return.
* The {@link VariableUtilities#checkVariableConflict(Function, Variable, VariableStorage, boolean)}
* method may be used to check and remove conflicting variables which already exist in the function.
- * @param callingConvention updated calling convention name or null if no change is required
+ * @param callingConvention updated calling convention name or null if no change is required.
+ * Only {@link DataTypeManager#getKnownCallingConventionNames() known calling convention names}
+ * may be specified which will always include those defined by the associated {@link CompilerSpec}.
* @param returnVar return variable or null if no change required
* @param updateType function update type
* @param force if true any conflicting local parameters will be removed
@@ -614,6 +622,14 @@ public interface Function extends Namespace {
*/
public PrototypeModel getCallingConvention();
+ /**
+ * Determine if this signature has an unknown or unrecognized calling convention name.
+ * @return true if calling convention is unknown or unrecognized name, else false.
+ */
+ public default boolean hasUnknownCallingConventionName() {
+ return getCallingConvention() == null;
+ }
+
/**
* Gets the calling convention's name for this function.
*
@@ -626,22 +642,19 @@ public interface Function extends Namespace {
public String getCallingConventionName();
/**
- * Gets the name of the default calling convention.
- *
Note: The name in the PrototypeModel of the default calling convention may be null.
- *
- * @return the name of the default calling convention.
- */
- public String getDefaultCallingConventionName();
-
- /**
- * Sets the calling convention for this function to the named calling convention.
- * @param name the name of the calling convention. "unknown" and "default" are reserved names
- * that can also be used here.
- *
Null or Function.UNKNOWN_CALLING_CONVENTION_STRING sets this function to not have a
- * calling convention (i.e. unknown).
- *
Function.DEFAULT_CALLING_CONVENTION_STRING sets this function to use the default calling
- * convention. (i.e. default)
- * @throws InvalidInputException if the specified name is not a recognized calling convention name.
+ * Sets the calling convention for this function to the named calling convention. Only
+ * {@link DataTypeManager#getKnownCallingConventionNames() known calling convention names}
+ * may be specified which will always include those defined by the associated
+ * {@link CompilerSpec}.
+ * @param name the name of the calling convention. Only
+ * {@link DataTypeManager#getKnownCallingConventionNames() known calling convention names}
+ * may be specified which will always include those defined by the associated
+ * {@link CompilerSpec}. In addition the reserved names
+ * {@link Function#UNKNOWN_CALLING_CONVENTION_STRING "unknown"} and
+ * {@link Function#DEFAULT_CALLING_CONVENTION_STRING "default"} may also be
+ * used here.
+ * @throws InvalidInputException if the specified name is not a recognized calling
+ * convention name.
*/
public void setCallingConvention(String name) throws InvalidInputException;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionManager.java
index be598d8661..5194a53efe 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionManager.java
@@ -15,13 +15,14 @@
*/
package ghidra.program.model.listing;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import ghidra.program.database.ManagerDB;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SourceType;
@@ -41,13 +42,18 @@ public interface FunctionManager extends ManagerDB {
public Program getProgram();
/**
- * Gets the names associated with each of the current calling conventions associated with this
- * program. Within the exception of "unknown", all of these calling convention names should have
- * a PrototypeModel.
+ * Get the ordered list of defined calling convention names. The reserved names
+ * "unknown" and "default" are not included. The returned collection may not include all names
+ * referenced by various functions and function-definitions. This set is limited to those
+ * defined by the associated compiler specification.
+ * See {@link DataTypeManager#getDefinedCallingConventionNames}.
+ *
+ * For a set of all known names (including those that are not defined by compiler spec)
+ * see {@link DataTypeManager#getKnownCallingConventionNames()}.
*
* @return the calling convention names.
*/
- public List getCallingConventionNames();
+ public Collection getCallingConventionNames();
/**
* Gets the default calling convention's prototype model in this program.
@@ -63,13 +69,6 @@ public interface FunctionManager extends ManagerDB {
*/
public PrototypeModel getCallingConvention(String name);
- /**
- * Gets all the calling convention prototype models in this program that have names.
- *
- * @return the function calling convention prototype models.
- */
- public PrototypeModel[] getCallingConventions();
-
/**
* Create a function with the given body at entry point within the global namespace.
*
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionSignature.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionSignature.java
index cef0ffe7ce..8ae21a15db 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionSignature.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/FunctionSignature.java
@@ -15,7 +15,9 @@
*/
package ghidra.program.model.listing;
-import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.ParameterDefinition;
+import ghidra.program.model.lang.PrototypeModel;
/**
* Interface describing all the things about a function that are portable
@@ -23,6 +25,7 @@ import ghidra.program.model.data.*;
*/
public interface FunctionSignature {
+ public static final String NORETURN_DISPLAY_STRING = "noreturn";
public static final String VAR_ARGS_DISPLAY_STRING = "...";
public static final String VOID_PARAM_DISPLAY_STRING = "void";
@@ -32,43 +35,73 @@ public interface FunctionSignature {
public String getName();
/**
- * Return a string representation of the function signature without the
+ * Get string representation of the function signature without the
* calling convention specified.
+ * @return function signature string
*/
public String getPrototypeString();
/**
- * Return a string representation of the function signature
+ * Get string representation of the function signature
* @param includeCallingConvention if true prototype will include call convention
- * declaration if known.
+ * declaration if known as well as noreturn indicator if applicable.
+ * @return function signature string
*/
public String getPrototypeString(boolean includeCallingConvention);
/**
- * Return an array of parameters for the function
+ * Get function signature parameter arguments
+ * @return an array of parameters for the function
*/
public ParameterDefinition[] getArguments();
/**
- * Return the return data type
+ * Get function signature return type
+ * @return the return data type
*/
public DataType getReturnType();
/**
- * Return the comment string
+ * Get descriptive comment for signature
+ * @return the comment string
*/
public String getComment();
/**
- * Returns true if this function signature has a variable argument list (VarArgs).
+ * @return true if this function signature has a variable argument list (VarArgs).
*/
public boolean hasVarArgs();
/**
- * Returns the generic calling convention associated with this function definition.
- * The "unknown" convention should be returned instead of null.
+ * @return true if this function signature corresponds to a non-returning function.
*/
- public GenericCallingConvention getGenericCallingConvention();
+ public boolean hasNoReturn();
+
+ /**
+ * Gets the calling convention prototype model for this function if associated with a
+ * compiler specificfation. This method will always return null if signature is not
+ * associated with a specific program architecture.
+ *
+ * @return the prototype model of the function's current calling convention or null.
+ */
+ public PrototypeModel getCallingConvention();
+
+ /**
+ * Returns the calling convention name associated with this function definition.
+ * Reserved names may also be returned: {@link Function#UNKNOWN_CALLING_CONVENTION_STRING},
+ * {@link Function#DEFAULT_CALLING_CONVENTION_STRING}.
+ * The "unknown" convention must be returned instead of null.
+ * @return calling convention name
+ */
+ public String getCallingConventionName();
+
+ /**
+ * Determine if this signature has an unknown or unrecognized calling convention name.
+ * @return true if calling convention is unknown or unrecognized name, else false.
+ */
+ public default boolean hasUnknownCallingConventionName() {
+ return getCallingConvention() == null;
+ }
/**
* Returns true if the given signature is equivalent to this signature. The
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java
index cdcfad4752..fff8540d5e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java
@@ -46,7 +46,7 @@ import ghidra.util.task.TaskMonitor;
* For example, the createCodeUnit() method of listing will fail if memory is
* undefined at the address where the codeUnit is to be created.
*/
-public interface Program extends DataTypeManagerDomainObject {
+public interface Program extends DataTypeManagerDomainObject, ProgramArchitecture {
public static final String ANALYSIS_PROPERTIES = "Analyzers";
public static final String DISASSEMBLER_PROPERTIES = "Disassembler";
@@ -85,8 +85,10 @@ public interface Program extends DataTypeManagerDomainObject {
/**
* Get the internal program address map
* @return internal address map
+ * @deprecated Method intended for internal ProgramDB use and is not intended for general use.
+ * This method may be removed from this interface in a future release.
*/
- // FIXME!! Should not expose on interface - anything using this should use ProgramDB or avoid using map!
+ @Deprecated(forRemoval = true)
public AddressMap getAddressMap();
/**
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java
index db51390974..f314185b5a 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java
@@ -20,8 +20,7 @@ import java.util.List;
import generic.algorithms.CRC64;
import ghidra.program.model.address.*;
-import ghidra.program.model.lang.Register;
-import ghidra.program.model.lang.UnknownRegister;
+import ghidra.program.model.lang.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.util.LanguageTranslator;
import ghidra.util.exception.InvalidInputException;
@@ -58,7 +57,7 @@ public class VariableStorage implements Comparable {
public static final VariableStorage VOID_STORAGE = new VariableStorage();
protected final Varnode[] varnodes;
- protected final Program program;
+ protected final ProgramArchitecture programArch;
private List registers;
private int size;
@@ -69,42 +68,45 @@ public class VariableStorage implements Comparable {
* Construct an empty variable storage for reserved usage (i.e., BAD_STORAGE, UNMAPPED_STORAGE)
*/
protected VariableStorage() {
- this.program = null;
+ this.programArch = null;
this.varnodes = null;
}
/**
* Construct variable storage
- * @param program
+ * @param programArch program architecture details
* @param varnodes one or more ordered storage varnodes
* @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public VariableStorage(Program program, Varnode... varnodes) throws InvalidInputException {
- this.program = program;
+ public VariableStorage(ProgramArchitecture programArch, Varnode... varnodes)
+ throws InvalidInputException {
+ this.programArch = programArch;
this.varnodes = varnodes.clone();
checkVarnodes();
}
/**
* Construct register variable storage
- * @param program
+ * @param programArch program architecture details
* @param registers one or more ordered registers
* @throws InvalidInputException if specified registers violate storage restrictions
*/
- public VariableStorage(Program program, Register... registers) throws InvalidInputException {
- this(program, getVarnodeList(registers));
+ public VariableStorage(ProgramArchitecture programArch, Register... registers)
+ throws InvalidInputException {
+ this(programArch, getVarnodeList(registers));
}
/**
* Construct stack variable storage
- * @param program
+ * @param programArch program architecture details
* @param stackOffset stack offset
* @param size stack element size
* @throws InvalidInputException if specified registers violate storage restrictions
*/
- public VariableStorage(Program program, int stackOffset, int size) throws InvalidInputException {
- this(program, new Varnode(program.getAddressFactory().getStackSpace().getAddress(
- stackOffset), size));
+ public VariableStorage(ProgramArchitecture programArch, int stackOffset, int size)
+ throws InvalidInputException {
+ this(programArch, new Varnode(
+ programArch.getAddressFactory().getStackSpace().getAddress(stackOffset), size));
}
private static Varnode[] getVarnodeList(Register[] registers) {
@@ -117,34 +119,37 @@ public class VariableStorage implements Comparable {
/**
* Construct variable storage
- * @param program
+ * @param programArch program architecture details
* @param varnodes one or more ordered storage varnodes
* @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public VariableStorage(Program program, List varnodes) throws InvalidInputException {
- this.program = program;
+ public VariableStorage(ProgramArchitecture programArch, List varnodes)
+ throws InvalidInputException {
+ this.programArch = programArch;
this.varnodes = varnodes.toArray(new Varnode[varnodes.size()]);
checkVarnodes();
}
/**
* Construct variable storage
- * @param program
- * @param address
- * @param size
- * @throws InvalidInputException
+ * @param programArch program architecture details
+ * @param address varnode address
+ * @param size varnode size
+ * @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public VariableStorage(Program program, Address address, int size) throws InvalidInputException {
- this(program, new Varnode(address, size));
+ public VariableStorage(ProgramArchitecture programArch, Address address, int size)
+ throws InvalidInputException {
+ this(programArch, new Varnode(address, size));
}
/**
* Construct variable storage
- * @param program
+ * @param programArch program architecture details
* @param serialization storage serialization string
- * @throws InvalidInputException
+ * @return deserialized variable storage. {@link #BAD_STORAGE} may be returned on failure.
+ * @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public static VariableStorage deserialize(Program program, String serialization)
+ public static VariableStorage deserialize(ProgramArchitecture programArch, String serialization)
throws InvalidInputException {
if (serialization == null || UNASSIGNED.equals(serialization)) {
return UNASSIGNED_STORAGE;
@@ -155,18 +160,18 @@ public class VariableStorage implements Comparable {
if (BAD.equals(serialization)) {
return BAD_STORAGE;
}
- List varnodes = getVarnodes(program.getAddressFactory(), serialization);
+ List varnodes = getVarnodes(programArch.getAddressFactory(), serialization);
if (varnodes == null) {
return BAD_STORAGE;
}
- return new VariableStorage(program, varnodes);
+ return new VariableStorage(programArch, varnodes);
}
/**
* @return program for which this storage is associated
*/
- public Program getProgram() {
- return program;
+ public ProgramArchitecture getProgramArchitecture() {
+ return programArch;
}
/**
@@ -181,7 +186,7 @@ public class VariableStorage implements Comparable {
throw new IllegalArgumentException("A minimum of one varnode must be specified");
}
- AddressFactory addrFactory = program.getAddressFactory();
+ AddressFactory addrFactory = programArch.getAddressFactory();
size = 0;
for (int i = 0; i < varnodes.length; i++) {
Varnode varnode = varnodes[i];
@@ -212,7 +217,8 @@ public class VariableStorage implements Comparable {
}
if (!storageAddr.isStackAddress()) {
- Register reg = program.getRegister(storageAddr, varnode.getSize());
+ Register reg =
+ programArch.getLanguage().getRegister(storageAddr, varnode.getSize());
if (reg != null && !(reg instanceof UnknownRegister)) {
isRegister = true;
if (registers == null) {
@@ -255,12 +261,12 @@ public class VariableStorage implements Comparable {
/**
* Attempt to clone variable storage for use in a different program.
* Dynamic storage characteristics will not be preserved.
- * @param newProgram target program
+ * @param newProgramArch target program architecture details
* @return cloned storage
- * @throws InvalidInputException
+ * @throws InvalidInputException if specified varnodes violate storage restrictions
*/
- public VariableStorage clone(Program newProgram) throws InvalidInputException {
- if (program == null || newProgram == program) {
+ public VariableStorage clone(ProgramArchitecture newProgramArch) throws InvalidInputException {
+ if (programArch == null || newProgramArch == programArch) {
if (getClass().equals(VariableStorage.class)) {
return this; // only reuse if simple VariableStorage instance
}
@@ -270,14 +276,14 @@ public class VariableStorage implements Comparable {
if (isBadStorage()) {
return BAD_STORAGE;
}
- return new VariableStorage(newProgram, varnodes);
+ return new VariableStorage(newProgramArch, varnodes);
}
- if (!newProgram.getLanguage().equals(program.getLanguage())) {
+ if (!newProgramArch.getLanguage().equals(programArch.getLanguage())) {
throw new IllegalArgumentException(
"Variable storage incompatible with program language: " +
- newProgram.getLanguage().toString());
+ newProgramArch.getLanguage().toString());
}
- AddressFactory newAddressFactory = newProgram.getAddressFactory();
+ AddressFactory newAddressFactory = newProgramArch.getAddressFactory();
Varnode[] v = getVarnodes();
Varnode[] newVarnodes = new Varnode[v.length];
for (int i = 0; i < v.length; i++) {
@@ -291,7 +297,7 @@ public class VariableStorage implements Comparable {
newVarnodes[i] =
new Varnode(newSpace.getAddress(v[i].getOffset()), v[i].getSize());
}
- return new VariableStorage(newProgram, newVarnodes);
+ return new VariableStorage(newProgramArch, newVarnodes);
}
@Override
@@ -322,9 +328,9 @@ public class VariableStorage implements Comparable {
builder.append(varnode.getSize());
}
- private String getAddressString(Address address, int size) {
+ private String getAddressString(Address address, int sz) {
if (address.isRegisterAddress() || address.isMemoryAddress()) {
- Register register = program.getRegister(address, size);
+ Register register = programArch.getLanguage().getRegister(address, sz);
if (register != null) {
return register.toString();
}
@@ -610,7 +616,7 @@ public class VariableStorage implements Comparable {
/**
* Determine if this variable storage intersects the specified variable storage
- * @param variableStorage
+ * @param variableStorage other variable storage
* @return true if any intersection exists between this storage and the specified
* variable storage
*/
@@ -666,8 +672,8 @@ public class VariableStorage implements Comparable {
/**
* Determine if the specified address is contained within this storage
- * @param address
- * @return
+ * @param address address
+ * @return true if this storage varnode(s) contain specified address
*/
public boolean contains(Address address) {
if (varnodes == null) {
@@ -751,7 +757,7 @@ public class VariableStorage implements Comparable {
/**
* Generate VariableStorage serialization string
- * @param varnodes
+ * @param varnodes one or more storage varnodes
* @return storage serialization string useful for subsequent reconstruction
* of a VariableStorage object
*/
@@ -773,9 +779,10 @@ public class VariableStorage implements Comparable {
/**
* Parse a storage serialization string to produce an array or varnodes
- * @param addrFactory
- * @param serialization
+ * @param addrFactory address factory
+ * @param serialization serialized variable storage string (see {@link #getSerializationString()}).
* @return array of varnodes or null if invalid
+ * @throws InvalidInputException if specified registers violate storage restrictions
*/
public static List getVarnodes(AddressFactory addrFactory, String serialization)
throws InvalidInputException {
@@ -866,7 +873,7 @@ public class VariableStorage implements Comparable {
translator.getOldLanguage().getAddressFactory().getRegisterSpace().getAddress(
offset);
String newOffsetStr =
- translateRegisterVarnodeOffset(oldRegAddr, size, translator, space);
+ translateRegisterVarnodeOffset(oldRegAddr, size, translator);
if (newOffsetStr != null) {
// if mapping failed - leave it unchanged
offsetStr = newOffsetStr;
@@ -896,15 +903,15 @@ public class VariableStorage implements Comparable {
}
/**
- * Translate register varnode address offsetStr
- * @param translator
- * @param space
- * @param offsetStr
- * @param sizeStr
- * @return translated offsetStr or null if BAD translation
+ * Translate old register storage defined by oldRegAddr and varnodeSize using the
+ * specified translator.
+ * @param oldRegAddr old register address
+ * @param varnodeSize varnode size
+ * @param translator language translator
+ * @return new register offset within same space as oldRegAddr or null if translation failed.
*/
private static String translateRegisterVarnodeOffset(Address oldRegAddr, int varnodeSize,
- LanguageTranslator translator, AddressSpace newRegisterSpace) {
+ LanguageTranslator translator) {
// Handle register movement within register space only
// Assumes all translators will map register space properly
// If old or new register not found no adjustment is made
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java
index 066e7871fd..9196b23385 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java
@@ -243,7 +243,7 @@ public class VariableUtilities {
}
if (dtLen < storageSize && storage.isRegisterStorage()) {
// TODO: this could be expanded to handle other storage
- return new VariableStorage(storage.getProgram(),
+ return new VariableStorage(storage.getProgramArchitecture(),
shrinkRegister(storage.getRegister(), storageSize - dtLen));
}
throw new InvalidInputException(
@@ -721,7 +721,7 @@ public class VariableUtilities {
@Deprecated
public static ParameterImpl getThisParameter(Function function, PrototypeModel convention) {
if (convention != null &&
- convention.getGenericCallingConvention() == GenericCallingConvention.thiscall) {
+ CompilerSpec.CALLING_CONVENTION_thiscall.equals(convention.getName())) {
DataType dt = findOrCreateClassStruct(function);
if (dt == null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java
index 64393e2dd4..31b80daffb 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java
@@ -36,7 +36,6 @@ public class FunctionPrototype {
private LocalSymbolMap localsyms; // Prototype backed by symbol map
private String modelname; // Name of prototype model
- private GenericCallingConvention gconv; // Generic name for the model
private String injectname; // Name of pcode inject associated with this prototype
private DataType returntype; // Output parameter
private VariableStorage returnstorage; // Where the output value is stored
@@ -64,7 +63,6 @@ public class FunctionPrototype {
public FunctionPrototype(LocalSymbolMap ls, Function func) {
localsyms = ls;
modelname = null;
- gconv = null;
injectname = null;
returntype = null;
returnstorage = null;
@@ -90,10 +88,9 @@ public class FunctionPrototype {
*/
public FunctionPrototype(FunctionSignature proto, CompilerSpec cspec,
boolean voidimpliesdotdotdot) {
- modelname = proto.getGenericCallingConvention().getDeclarationName();
- PrototypeModel model = cspec.matchConvention(proto.getGenericCallingConvention());
+ modelname = proto.getName();
+ PrototypeModel model = cspec.matchConvention(modelname);
localsyms = null;
- gconv = proto.getGenericCallingConvention();
injectname = null;
returntype = proto.getReturnType();
returnstorage = null;
@@ -103,7 +100,7 @@ public class FunctionPrototype {
outputlock = true;
dotdotdot = proto.hasVarArgs();
isinline = false;
- noreturn = false;
+ noreturn = proto.hasNoReturn();
custom = false;
extrapop = model.getExtrapop();
hasThis = model.hasThisPointer();
@@ -135,8 +132,7 @@ public class FunctionPrototype {
protoModel = f.getProgram().getCompilerSpec().getDefaultCallingConvention();
}
hasThis = protoModel.hasThisPointer();
- modellock =
- ((modelname != null) && (modelname != Function.UNKNOWN_CALLING_CONVENTION_STRING));
+ modellock = !f.hasUnknownCallingConventionName();
injectname = f.getCallFixup();
voidinputlock = false;
Parameter returnparam = f.getReturn();
@@ -310,13 +306,6 @@ public class FunctionPrototype {
return modelname;
}
- /**
- * @return generic calling convention
- */
- public GenericCallingConvention getGenericCallingConvention() {
- return gconv;
- }
-
/**
* Encode this function prototype to a stream.
* @param encoder is the stream encoder
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunctionDBUtil.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunctionDBUtil.java
index b7145c7b09..c85958659e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunctionDBUtil.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunctionDBUtil.java
@@ -696,10 +696,11 @@ public class HighFunctionDBUtil {
ParameterDefinition[] params = sig.getArguments();
FunctionDefinitionDataType fsig = new FunctionDefinitionDataType("tmpname"); // Empty datatype, will get renamed later
- fsig.setGenericCallingConvention(sig.getGenericCallingConvention());
+ fsig.setCallingConvention(sig.getCallingConventionName());
fsig.setArguments(params);
fsig.setReturnType(sig.getReturnType());
fsig.setVarArgs(sig.hasVarArgs());
+ fsig.setNoReturn(sig.hasNoReturn());
DataTypeSymbol datsym = new DataTypeSymbol(fsig, "prt", AUTO_CAT);
Program program = function.getProgram();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java
index 94255200a2..904ffaf698 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java
@@ -501,8 +501,8 @@ public class HighSymbol {
AutoParameterType autoType =
isThis ? AutoParameterType.THIS : AutoParameterType.RETURN_STORAGE_PTR;
try {
- VariableStorage newStorage = new DynamicVariableStorage(storage.getProgram(),
- autoType, storage.getFirstVarnode());
+ VariableStorage newStorage = new DynamicVariableStorage(
+ storage.getProgramArchitecture(), autoType, storage.getFirstVarnode());
entryList[0] = new MappedEntry(this, newStorage, entry.getPCAdress());
}
catch (InvalidInputException e) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java
index 0fa2f22c38..2e03b03a56 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java
@@ -20,7 +20,6 @@ import java.util.*;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataOrganization;
-import ghidra.program.model.data.GenericCallingConvention;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Encoder;
@@ -55,7 +54,7 @@ public abstract class LanguageTranslatorAdapter implements LanguageTranslator {
* @param oldLanguage
* @param newLanguage
*/
- private LanguageTranslatorAdapter(Language oldLanguage, Language newLanguage) {
+ protected LanguageTranslatorAdapter(Language oldLanguage, Language newLanguage) {
this.oldLanguage = oldLanguage;
this.newLanguage = newLanguage;
oldLanguageID = oldLanguage.getLanguageID();
@@ -483,7 +482,7 @@ public abstract class LanguageTranslatorAdapter implements LanguageTranslator {
* @param newLanguage
* @return default translator or null if reasonable mappings can not be determined.
*/
- static LanguageTranslator getDefaultLanguageTranslator(Language oldLanguage,
+ public static LanguageTranslator getDefaultLanguageTranslator(Language oldLanguage,
Language newLanguage) {
DefaultLanguageTranslator translator =
@@ -626,7 +625,7 @@ class TemporaryCompilerSpec implements CompilerSpec {
}
@Override
- public PrototypeModel matchConvention(GenericCallingConvention genericCallingConvention) {
+ public PrototypeModel matchConvention(String callingConvention) {
throw new UnsupportedOperationException("Language for upgrade use only (matchConvention)");
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java
index e861d8a285..5bedbfd670 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java
@@ -21,13 +21,13 @@ import java.util.NoSuchElementException;
import org.junit.*;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.util.task.TaskMonitor;
/**
* Tests for Enum data types.
*/
-public class EnumTest extends AbstractGTest {
+public class EnumTest extends AbstractGenericTest {
private DataTypeManager dataMgr;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FileDataTypeManagerTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FileDataTypeManagerTest.java
index f5adb2f71e..5db5c46761 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FileDataTypeManagerTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FileDataTypeManagerTest.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
import org.junit.*;
import generic.test.AbstractGenericTest;
+import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
public class FileDataTypeManagerTest extends AbstractGenericTest {
@@ -68,6 +69,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
dtMgr = null;
dtMgr = FileDataTypeManager.openFileArchive(testArchiveFile, false);
+ assertEquals(ArchiveWarning.NONE, dtMgr.getWarning());
assertFalse(dtMgr.isUpdatable());
ArrayList list = new ArrayList<>();
@@ -94,7 +96,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
dtMgr = null;
}
catch (IOException e) {
- Assert.fail("Unexpected Exception");
+ failWithException("Unexpected exception", e);
}
finally {
if (dtMgr != null) {
@@ -113,6 +115,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
FileDataTypeManager dtMgr = null;
try {
dtMgr = FileDataTypeManager.openFileArchive(testArchiveFile, true);
+ assertEquals(ArchiveWarning.NONE, dtMgr.getWarning());
assertTrue("Archive not updateable, i=" + i, dtMgr.isUpdatable());
int txId = dtMgr.startTransaction("Add Type");
@@ -143,6 +146,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
try {
dtMgr = FileDataTypeManager.openFileArchive(testArchiveFile, false);
+ assertEquals(ArchiveWarning.NONE, dtMgr.getWarning());
assertFalse(dtMgr.isUpdatable());
ArrayList list = new ArrayList<>();
diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FunctionDefinitionDataTypeTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FunctionDefinitionDataTypeTest.java
index 795d55324b..ee01baebde 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FunctionDefinitionDataTypeTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FunctionDefinitionDataTypeTest.java
@@ -19,9 +19,9 @@ import static org.junit.Assert.*;
import org.junit.*;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
-public class FunctionDefinitionDataTypeTest extends AbstractGTest {
+public class FunctionDefinitionDataTypeTest extends AbstractGenericTest {
private StandAloneDataTypeManager dtm;
private FunctionDefinition functionDt;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/BitFieldDBDataTypeTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/BitFieldDBDataTypeTest.java
index c5d3f621ec..0aa7334fb6 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/BitFieldDBDataTypeTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/BitFieldDBDataTypeTest.java
@@ -15,15 +15,15 @@
*/
package ghidra.program.database.data;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.program.model.data.*;
-public class BitFieldDBDataTypeTest extends AbstractGTest {
+public class BitFieldDBDataTypeTest extends AbstractGenericTest {
private DataTypeManagerDB dataMgr;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java
index 2f8fc607d4..e9b0b581a7 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java
@@ -23,13 +23,13 @@ import org.junit.*;
import com.google.common.collect.Sets;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.program.model.data.*;
import ghidra.util.InvalidNameException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
-public class StructureDBTest extends AbstractGTest {
+public class StructureDBTest extends AbstractGenericTest {
private StructureDB struct;
private DataTypeManagerDB dataMgr;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java
index 6a0f1d6566..6152b93453 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java
@@ -21,14 +21,14 @@ import org.junit.*;
import com.google.common.collect.Sets;
-import generic.test.AbstractGTest;
+import generic.test.AbstractGenericTest;
import ghidra.program.model.data.*;
import ghidra.util.task.TaskMonitor;
/**
*
*/
-public class UnionDBTest extends AbstractGTest {
+public class UnionDBTest extends AbstractGenericTest {
private DataTypeManager dataMgr;
private UnionDB union;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java
index e7b4344ea2..8f3f8094bc 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java
@@ -383,12 +383,7 @@ public class FunctionTestDouble implements Function {
@Override
public String getCallingConventionName() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getDefaultCallingConventionName() {
- throw new UnsupportedOperationException();
+ return Function.UNKNOWN_CALLING_CONVENTION_STRING;
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java
index 530aa56f84..d388eff5dd 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java
@@ -53,11 +53,6 @@ public class StubFunctionManager implements FunctionManager {
throw new UnsupportedOperationException();
}
- @Override
- public PrototypeModel[] getCallingConventions() {
- throw new UnsupportedOperationException();
- }
-
@Override
public Function createFunction(String name, Address entryPoint, AddressSetView body,
SourceType source) throws InvalidInputException, OverlappingFunctionException {
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/TestDoubleFunctionSignature.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/TestDoubleFunctionSignature.java
index 165b47a3b5..bac52f7e74 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/TestDoubleFunctionSignature.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/TestDoubleFunctionSignature.java
@@ -15,7 +15,10 @@
*/
package ghidra.program.model;
-import ghidra.program.model.data.*;
+import ghidra.program.model.data.DataType;
+import ghidra.program.model.data.ParameterDefinition;
+import ghidra.program.model.lang.PrototypeModel;
+import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
/**
@@ -65,10 +68,20 @@ public class TestDoubleFunctionSignature implements FunctionSignature {
}
@Override
- public GenericCallingConvention getGenericCallingConvention() {
+ public boolean hasNoReturn() {
throw new UnsupportedOperationException();
}
+ @Override
+ public PrototypeModel getCallingConvention() {
+ return null;
+ }
+
+ @Override
+ public String getCallingConventionName() {
+ return Function.UNKNOWN_CALLING_CONVENTION_STRING;
+ }
+
@Override
public String getPrototypeString() {
return funtionSignature;
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java
index 643944123a..e6dedcd54c 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java
@@ -18,6 +18,9 @@ package ghidra.program.model.data;
import java.util.*;
import db.Transaction;
+import ghidra.program.database.map.AddressMap;
+import ghidra.program.model.lang.ProgramArchitecture;
+import ghidra.program.model.lang.PrototypeModel;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@@ -39,6 +42,26 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
return id;
}
+ @Override
+ public AddressMap getAddressMap() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ProgramArchitecture getProgramArchitecture() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProgramArchitectureSummary() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DataOrganization getDataOrganization() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public boolean containsCategory(CategoryPath path) {
throw new UnsupportedOperationException();
@@ -85,6 +108,11 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
throw new UnsupportedOperationException();
}
+ @Override
+ public Iterator getAllFunctionDefinitions() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void findDataTypes(String name, List list) {
throw new UnsupportedOperationException();
@@ -322,11 +350,6 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
throw new UnsupportedOperationException();
}
- @Override
- public DataOrganization getDataOrganization() {
- throw new UnsupportedOperationException();
- }
-
@Override
public List getSourceArchives() {
throw new UnsupportedOperationException();
@@ -356,4 +379,24 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
public boolean allowsDefaultComponentSettings() {
return false;
}
+
+ @Override
+ public Collection getKnownCallingConventionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Collection getDefinedCallingConventionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PrototypeModel getDefaultCallingConvention() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention(String name) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java
index d07ddef22e..b68306cc03 100644
--- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java
@@ -18,6 +18,9 @@ package ghidra.program.model.data;
import java.util.*;
import db.Transaction;
+import ghidra.program.database.map.AddressMap;
+import ghidra.program.model.lang.ProgramArchitecture;
+import ghidra.program.model.lang.PrototypeModel;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
import ghidra.util.exception.CancelledException;
@@ -88,6 +91,12 @@ public class TestDummyDataTypeManager implements DataTypeManager {
return null;
}
+ @Override
+ public Iterator getAllFunctionDefinitions() {
+ // stub
+ return null;
+ }
+
@Override
public void findDataTypes(String name, List list) {
// stub
@@ -371,6 +380,23 @@ public class TestDummyDataTypeManager implements DataTypeManager {
return false;
}
+ @Override
+ public AddressMap getAddressMap() {
+ // stub
+ return null;
+ }
+
+ @Override
+ public ProgramArchitecture getProgramArchitecture() {
+ // stub
+ return null;
+ }
+
+ @Override
+ public String getProgramArchitectureSummary() {
+ return null;
+ }
+
@Override
public DataOrganization getDataOrganization() {
// stub
@@ -413,4 +439,24 @@ public class TestDummyDataTypeManager implements DataTypeManager {
return false;
}
+ @Override
+ public Collection getKnownCallingConventionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Collection getDefinedCallingConventionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PrototypeModel getDefaultCallingConvention() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PrototypeModel getCallingConvention(String name) {
+ throw new UnsupportedOperationException();
+ }
+
}
diff --git a/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs b/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs
index 421644f47e..a33d0cac6a 100644
--- a/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs
+++ b/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs
@@ -9,7 +9,7 @@
processorspec="AARCH64.pspec"
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:LE:64:v8A">
- Generic ARM v8.5-A LE instructions, LE data, missing some 8.5 vector
+ Generic ARM64 v8.5-A LE instructions, LE data, missing some 8.5 vector
@@ -25,7 +25,7 @@
processorspec="AARCH64.pspec"
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:BE:64:v8A">
- Generic ARM v8.5-A LE instructions, BE data, missing some 8.5 vector
+ Generic ARM64 v8.5-A LE instructions, BE data, missing some 8.5 vector
@@ -39,7 +39,7 @@
processorspec="AARCH64.pspec"
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:LE:32:ilp32">
- Generic ARM v8.5-A LE instructions, LE data, ilp32
+ Generic ARM64 v8.5-A LE instructions, LE data, ilp32
@@ -55,7 +55,7 @@
processorspec="AARCH64.pspec"
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:BE:32:ilp32">
- Generic ARM v8.5-A LE instructions, BE data, ilp32
+ Generic ARM64 v8.5-A LE instructions, BE data, ilp32
diff --git a/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java b/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java
index 121d95c7dd..4682daca4a 100644
--- a/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java
+++ b/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java
@@ -31,6 +31,7 @@ import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.CPP.DefineTable;
import ghidra.app.util.cparser.CPP.ParseException;
import ghidra.app.util.cparser.CPP.PreProcessor;
@@ -395,17 +396,14 @@ public class CreateAVR8GDTArchiveScript extends GhidraScript {
*/
private void parseProcessorDefs(String procName, FileDataTypeManager dtMgr, DataTypeManager[] openTypes)
throws ParseException, ghidra.app.util.cparser.C.ParseException, IOException {
- PreProcessor cpp;
String args[] = Arrays.append(orig_args, "-D__AVR_"+procName+"__");
-
- cpp = new PreProcessor();
- String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, "avr8:LE:16:atmega256", "gcc", cpp, monitor);
+ CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, "avr8:LE:16:atmega256", "gcc", monitor);
- Msg.info(this, messages);
+ Msg.info(this, results.getFormattedParseMessage(null));
- storeExtraDefinitions(procName, dtMgr, openTypes, cpp);
+ storeExtraDefinitions(procName, dtMgr, openTypes, results.preProcessor());
}
/**
diff --git a/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java b/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java
index f7480d2538..942527c795 100644
--- a/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java
+++ b/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java
@@ -23,10 +23,12 @@ import ghidra.file.formats.android.dex.format.*;
import ghidra.file.formats.android.dex.util.DexUtil;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.ConstantPool;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
+import ghidra.util.exception.InvalidInputException;
/**
* Map Ghidra's generic ConstantPool interface onto the Dex specific constant pool
@@ -121,8 +123,14 @@ public class ConstantPoolDex extends ConstantPool {
String defName = res.token + '_' + Integer.toHexString(methodID);
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(defName, dtManager);
res.type = new PointerDataType(funcDef);
- funcDef.setGenericCallingConvention(
- isStatic ? GenericCallingConvention.stdcall : GenericCallingConvention.thiscall);
+ try {
+ funcDef.setCallingConvention(
+ isStatic ? CompilerSpec.CALLING_CONVENTION_stdcall
+ : CompilerSpec.CALLING_CONVENTION_thiscall);
+ }
+ catch (InvalidInputException e) {
+ // unexpected
+ }
int prototypeIndex = methodIDItem.getProtoIndex() & 0xffff;
PrototypesIDItem prototype = dexHeader.getPrototypes().get(prototypeIndex);
diff --git a/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java b/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java
index 9d55d457d1..4091798a8f 100644
--- a/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java
+++ b/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java
@@ -33,6 +33,7 @@ import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
@@ -64,9 +65,9 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
- String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
+ CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, monitor);
- Msg.info(this, messages);
+ Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save();
dtMgr.close();
@@ -113,7 +114,6 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
"-D__builtin_va_list=void *",
"-D__DO_NOT_DEFINE_COMPILE",
"-D_Complex",
- "-D_WCHAR_T",
"-D__NO_STRING_INLINES",
"-D__signed__",
"-D__extension__=",
@@ -159,7 +159,6 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
"-D__builtin_va_list=void *",
"-D__DO_NOT_DEFINE_COMPILE",
"-D_Complex",
- "-D_WCHAR_T",
"-D__NO_STRING_INLINES",
"-D__signed__",
"-D__extension__=",
diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java
index 9ec1451e6b..4e06fb49ee 100644
--- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java
+++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java
@@ -21,8 +21,11 @@ import java.util.List;
import ghidra.javaclass.format.*;
import ghidra.javaclass.format.constantpool.*;
import ghidra.program.model.data.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.ConstantPool;
import ghidra.program.model.listing.Program;
+import ghidra.util.exception.AssertException;
+import ghidra.util.exception.InvalidInputException;
public class ConstantPoolJava extends ConstantPool {
@@ -103,20 +106,30 @@ public class ConstantPoolJava extends ConstantPool {
new ParameterDefinitionImpl("", params.get(i), null);
paramDefs[i] = currentParam;
}
- funcDef.setGenericCallingConvention(GenericCallingConvention.stdcall);
+ try {
+ funcDef.setCallingConvention(CompilerSpec.CALLING_CONVENTION_stdcall);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertException(e); // unexpected
+ }
}
//invokeinterface, invokespecial, and invokevirtual do have a this pointer
else {
paramDefs = new ParameterDefinitionImpl[params.size() + 1];
ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef",
- new Pointer32DataType(DataType.VOID), null);
+ new Pointer32DataType(VoidDataType.dataType), null);
paramDefs[0] = thisParam;
for (int i = 1, max = params.size(); i <= max; ++i) {
ParameterDefinitionImpl currentParam =
new ParameterDefinitionImpl("", params.get(i - 1), null);
paramDefs[i] = currentParam;
}
- funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall);
+ try {
+ funcDef.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertException(e); // unexpected
+ }
}
funcDef.setArguments(paramDefs);
res.type = new PointerDataType(funcDef);
@@ -282,7 +295,7 @@ public class ConstantPoolJava extends ConstantPool {
break;
case CPOOL_MULTIANEWARRAY:
res.tag = ConstantPool.CLASS_REFERENCE;
- res.type = new PointerDataType(DataType.VOID);
+ res.type = new PointerDataType(VoidDataType.dataType);
int nameIndex = ((ConstantPoolClassInfo) poolRef).getNameIndex();
ConstantPoolUtf8Info utf8Info = (ConstantPoolUtf8Info) constantPool[nameIndex];
String classNameWithSemicolon = utf8Info.getString();
diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LanguageProviderPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LanguageProviderPluginScreenShots.java
index f17d1c14c1..64af927171 100644
--- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LanguageProviderPluginScreenShots.java
+++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/LanguageProviderPluginScreenShots.java
@@ -37,7 +37,8 @@ public class LanguageProviderPluginScreenShots extends GhidraScreenShotGenerator
@Test
public void testLanguages() {
- final SetLanguageDialog dialog = new SetLanguageDialog(tool, program);
+ final SetLanguageDialog dialog = new SetLanguageDialog(tool, program,
+ "Set Language: " + program.getDomainFile().getName());
Object newLanguagePanel = getInstanceField("selectLangPanel", dialog);
final GTableFilterPanel> filterPanel =
(GTableFilterPanel>) getInstanceField("tableFilterPanel", newLanguagePanel);