GP-1633/GP-2308 Added ProgramArchitecture to datatype managers.

Refactored ProjectDataTypeManager to extend StandaloneDataTypeManager.
Added actions to datatype tree to allow setting archive architecture.
Added use of storage translators when switching architectures.  Allow
FunctionDefinition to accept arbitrary calling convention
names and many other misc changes.
This commit is contained in:
ghidra1 2021-12-27 17:01:32 -05:00
parent 75a185aa9e
commit a4776892bd
248 changed files with 6282 additions and 2935 deletions

View file

@ -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;
}
}

View file

@ -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<String> getCallingConventionNames() {
public Collection<String> 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 {

View file

@ -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();

View file

@ -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<String> getCallingConventionNames(CompilerSpec cs) {
PrototypeModel[] namedCCs = cs.getCallingConventions();
List<String> 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<String> getCallingConventionNames() {
// TODO: Allow for user-selected compiler spec(s)
return getCallingConventionNames(manager.trace.getBaseCompilerSpec());
public Collection<String> 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?

View file

@ -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<Long, DBTraceSymbolIDEntry> idMap;
protected final DBCachedObjectStore<DBTraceCallingConventionEntry> callingConventionStore;
protected final BidiMap<String, Byte> callingConventionMap = new DualHashBidiMap<>();
protected final DBCachedObjectStore<DBTraceFunctionTag> tagStore;
protected final DBCachedObjectIndex<String, DBTraceFunctionTag> 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 extends AbstractDBTraceSymbolSingleTypeView<?>> 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();

View file

@ -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<Tra
return add(Lifespan.nowOn(snap), entryPoint, body, name, thunked, parent, source);
}
PrototypeModel[] getCallingConventions();
List<String> 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<String> 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);
}

View file

@ -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<String> names = functionManager.getCallingConventionNames();
Collection<String> 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));
}
}