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

@ -264,9 +264,9 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
// 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<Sym> {
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();

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

View file

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

View file

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

View file

@ -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) {

View file

@ -123,18 +123,27 @@
<tocdef id="Ghidra Functionality"
sortgroup="e"
text="Ghidra Functionality"
target = "help/topics/Intro/GhidraFunctionality.htm">
<tocdef id="Code Browser" text="Code Browser" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm" >
<tocdef id="Browser Field Formatter" sortgroup="a" text="Browser Field Formatter" target="help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm" />
<tocdef id="Markers" sortgroup="b" text="Markers" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm#CBNavigationMarkers" />
<tocdef id="Cursor Text Highlight" sortgroup="c" text="Cursor Text Highlight" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm#cursorTextHighlight" />
<tocdef id="Code Browser Configuration Options" sortgroup="d" text="Configuration Options" target="help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm" />
sortgroup="e"
text="Ghidra Functionality"
target = "help/topics/Intro/GhidraFunctionality.htm">
<tocdef id="Code Browser" text="Code Browser" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm" >
<tocdef id="Browser Field Formatter" sortgroup="a" text="Browser Field Formatter" target="help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm" />
<tocdef id="Markers" sortgroup="b" text="Markers" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm#CBNavigationMarkers" />
<tocdef id="Cursor Text Highlight" sortgroup="c" text="Cursor Text Highlight" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm#cursorTextHighlight" />
<tocdef id="Code Browser Configuration Options" sortgroup="d" text="Configuration Options" target="help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm" />
</tocdef>
<tocdef id="Data Type Manager" sortgroup="c" text="Data Type Manager" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm">
<tocdef id="DTM Concepts" sortgroup="a" text="Basic Concepts" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Basic_Concepts" />
<tocdef id="DTM Window" sortgroup="b" text="Data Type Window" target="help/topics/DataTypeManagerPlugin/data_type_manager_window.html" />
<tocdef id="DTM Working With Archives" sortgroup="c" text="Archives" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Archives" />
<tocdef id="DTM Working With Categories" sortgroup="d" text="Categories" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Category" />
<tocdef id="DTM Working With Data Types" sortgroup="e" text="Data Types" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Data_Types" />
<tocdef id="DTM Managing Archives" sortgroup="f" text="Managing Archives" target="help/topics/DataTypeManagerPlugin/data_type_manager_archives.html" />
<tocdef id="Structure Editor" sortgroup="d" text="Structure Editor" target="help/topics/DataTypeEditors/StructureEditor.htm" />
<tocdef id="Enum Editor" sortgroup="e" text="Enum Editor" target="help/topics/DataTypeEditors/EnumEditor.htm" />
</tocdef>
<tocdef id="Assembler" text="Assembler" target="help/topics/AssemblerPlugin/Assembler.htm"></tocdef>
<tocdef id="Entropy Overview" text="Entropy Overview" target="help/topics/OverviewPlugin/Overview.htm#EntropyOverviewBar" >
@ -220,16 +229,6 @@
<tocdef id="Data" sortgroup="c" text="Data" target="help/topics/DataPlugin/Data.htm" >
<tocdef id="Create Data" sortgroup="a" text="Create Data" target="help/topics/DataPlugin/Data.htm" />
<tocdef id="Data Types" sortgroup="b" text="Data Types" target="help/topics/DataPlugin/Data.htm#DataTypes" />
<tocdef id="Data Type Manager" sortgroup="c" text="Data Type Manager" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm">
<tocdef id="DTM Concepts" sortgroup="a" text="Basic Concepts" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Basic_Concepts" />
<tocdef id="DTM Window" sortgroup="b" text="Data Type Window" target="help/topics/DataTypeManagerPlugin/data_type_manager_window.html" />
<tocdef id="DTM Working With Archives" sortgroup="c" text="Archives" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Archives" />
<tocdef id="DTM Working With Categories" sortgroup="d" text="Categories" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Category" />
<tocdef id="DTM Working With Data Types" sortgroup="e" text="Data Types" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Data_Types" />
<tocdef id="DTM Managing Archives" sortgroup="f" text="Managing Archives" target="help/topics/DataTypeManagerPlugin/data_type_manager_archives.html" />
</tocdef>
<tocdef id="Structure Editor" sortgroup="d" text="Structure Editor" target="help/topics/DataTypeEditors/StructureEditor.htm" />
<tocdef id="Enum Editor" sortgroup="e" text="Enum Editor" target="help/topics/DataTypeEditors/EnumEditor.htm" />
<tocdef id="Translate Strings" sortgroup="e" text="Translate Strings" target="help/topics/TranslateStringsPlugin/TranslateStringsPlugin.htm" />
<tocdef id="Save Image" sortgroup="e" text="Save Image" target="help/topics/ResourceActionsPlugin/ResourceActions.html" />
</tocdef>

View file

@ -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.</P>
<BLOCKQUOTE>
<P><IMG alt="" src="help/shared/tip.png">You can assign a specific <I>"Architecture"</I>
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 <A href="#Set_Archive_Architecture">Setting
Data Type Archive Architecture</A>).</P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<BLOCKQUOTE>
@ -406,6 +414,51 @@
Archive.</P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H3><A name="Set_Archive_Architecture"></A>Setting Data Type Archive Architecture</H3>
<BLOCKQUOTE>
<P>By default, data type archives are not assigned an architecture and adopt a default
<I>Data Organization</I> 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 <I>Data Organizations</I> 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 <I>Data
Organization</I> differs from the intended target architecture.</P>
<P>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 <I><B>Set Architecture...</B></I> action.
This will popup a processor/compiler-specification selection dialog from which a selection
may be made and the <B>OK</B> button clicked. A final confirmation dialog will be displayed
before completing the change from which the <B>Set Architecture</B> or <B>Cancel</B> 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.</P>
<P>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.</P>
</BLOCKQUOTE>
<H3><A name="Clear_Archive_Architecture"></A>Clearing Data Type Archive Architecture</H3>
<BLOCKQUOTE>
<P>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 <I><B>Clear Architecture</B></I> action.
A final confirmation dialog will be displayed
before completing the change from which the <B>Clear Architecture</B> or <B>Cancel</B> button
must be clicked to confirm or cancel the change. If confirmed, the archive will revert a default
<I>Data Organization</I> and any custom variable storage for Function Definitions
(not yet implemented) will be discarded.
<P>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.</P>
</BLOCKQUOTE>
<H3><A name="Close_Archive"></A>Closing a Data Type Archive</H3>

View file

@ -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) {

View file

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

View file

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

View file

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

View file

@ -1344,4 +1344,8 @@ abstract class CompositeViewerModel extends AbstractTableModel
return originalCompositeId;
}
@Override
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
// don't care
}
}

View file

@ -15,19 +15,12 @@
*/
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.*;
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;
@ -39,6 +32,7 @@ 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.ParseException;
import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.framework.Application;
import ghidra.framework.options.SaveState;
@ -46,13 +40,9 @@ 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;
@ -206,6 +196,7 @@ public class CParserPlugin extends ProgramPlugin {
cpp.setOutputStream(bos);
cpp.setMonitor(monitor);
int fileCount = 0;
try {
for (String filename : filenames) {
if (monitor.isCancelled()) {
@ -230,14 +221,26 @@ public class CParserPlugin extends ProgramPlugin {
}
}
}
else {
else if (file.exists()) {
++fileCount;
parseFile(filename, monitor, cpp);
}
else {
Msg.error(this, "Skipping file not found:" + filename);
}
}
}
catch (RuntimeException re) {
os.close();
throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
throw new ParseException(re.getMessage());
}
if (fileCount == 0) {
throw new ParseException("Failed to find any header files to parse!");
}
else if (fileCount != filenames.length) {
Msg.warn(this,
"Only found " + fileCount + " of " + filenames.length + " specified header files");
}
// process all the defines and add any that are integer values into

View file

@ -79,6 +79,7 @@ class CParserTask extends Task {
plugin.parse(filenames, options, dtMgr, monitor);
if (dataFileName != null) {
// TODO: does not consider existing datatypes
if (dtMgr.getDataTypeCount(true) != 0) {
try {
((FileDataTypeManager) dtMgr).save();

View file

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

View file

@ -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 = "<html>Clear program-architecture for Archive?<BR><font color=\"" +
Messages.NORMAL + "\">" + dtm.getPath() +
"</font><BR> <BR>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);
}
}
}
}
}
}

View file

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

View file

@ -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 =
"<html>Set program-architecture for Archive?<BR><font color=\"" + Messages.NORMAL +
"\">" + dtm.getPath() + "</font><pre>";
if (programArchitectureSummary != null) {
msg +=
"\nChange Language/Compiler\n from: <font color=\"" + Messages.NORMAL +
"\">" +
programArchitectureSummary + "</font>\n to: ";
}
else {
msg += "\n\nLanguage/Compiler: ";
}
msg += "<font color=\"" + Messages.NORMAL + "\">";
msg += newProgramArchitectureSummary;
msg += "</font></pre>";
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",
"<html>Unable to translate storage for specified architecture change.<BR><font color=\"" +
Messages.NORMAL + "\">" + dtm.getPath() +
"</font><BR><BR>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);
}
}
}
}
}
}

View file

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

View file

@ -219,5 +219,10 @@ public class DataTypeIndexer {
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
markStale();
}
@Override
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
markStale();
}
}
}

View file

@ -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);
}
}
}
/**

View file

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

View file

@ -145,7 +145,7 @@ public class FileArchive implements Archive {
}
@Override
public DataTypeManager getDataTypeManager() {
public FileDataTypeManager getDataTypeManager() {
return fileDataTypeManager;
}
@ -274,6 +274,11 @@ public class FileArchive implements Archive {
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
setChanged(true);
}
@Override
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
setChanged(true);
}
}
@Override

View file

@ -72,6 +72,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;

View file

@ -66,6 +66,11 @@ public class ProjectArchive implements DomainFileArchive {
return -1; // Project Archives appear between the ProgramArchive and FileArchives.
}
@Override
public boolean hasExclusiveAccess() {
return dataTypeArchive.hasExclusiveAccess();
}
@Override
public boolean isModifiable() {
DomainFile domainFile = getDomainObject().getDomainFile();
@ -192,5 +197,10 @@ public class ProjectArchive implements DomainFileArchive {
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
fireStateChanged();
}
@Override
public void programArchitectureChanged(DataTypeManager dtm) {
fireStateChanged();
}
}
}

View file

@ -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<String> getCallingConventionNames() {
GenericCallingConvention[] values = GenericCallingConvention.values();
List<String> 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<String> 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;

View file

@ -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(
"<font color=\"" + Messages.ERROR +
"\">** Missing Language/Compiler Specification **</font>");
}
else if (archiveDtm.isProgramArchitectureUpgradeRequired()) {
buf.append(HTMLUtilities.BR);
buf.append("<font color=\"" + Messages.WARNING +
"\">** Language Upgrade Required **</font>");
}
}
}
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();
}
}
}

View file

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

View file

@ -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 "<html>" + 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;
}

View file

@ -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 "<html>" + HTMLUtilities.escapeHTML(file.getAbsolutePath());
}
return "[Unsaved New Archive]";
return buildTooltip(file != null ? file.getAbsolutePath() : "[Unsaved New Archive]");
}
public boolean hasWriteLock() {

View file

@ -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 "<html>" + 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();
}
}

View file

@ -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 "<html>" + HTMLUtilities.escapeHTML(file.getPathname());
}
return "[Unsaved New Project Archive]";
return buildTooltip(file != null ? file.getPathname() : "[Unsaved New Project Archive]");
}
public boolean hasWriteLock() {

View file

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

View file

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

View file

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

View file

@ -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<String> getCallingConventionNames() {
return function.getProgram().getFunctionManager().getCallingConventionNames();
List<String> 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;
}

View file

@ -124,15 +124,24 @@ public class FunctionEditorModel {
return false;
}
public List<String> getCallingConventionNames() {
return functionManager.getCallingConventionNames();
List<String> getCallingConventionNames() {
Collection<String> names =
function.getProgram().getFunctionManager().getCallingConventionNames();
List<String> 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;
}

View file

@ -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)) {

View file

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

View file

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

View file

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

View file

@ -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) {

View file

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

View file

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

View file

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

View file

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

View file

@ -129,6 +129,14 @@ public class LanguageSortedTableModel extends AbstractSortedTableModel<LanguageC
}
++index;
}
// Try again using just LanguageID
index = 0;
for (LanguageCompilerSpecPair pair : languageList) {
if (pair.getLanguageID().equals(toFind.getLanguageID())) {
return index;
}
++index;
}
}
return -1;
}

View file

@ -36,6 +36,8 @@ import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*;
import ghidra.program.model.scalar.Scalar;
@ -2487,7 +2489,16 @@ public class FlatProgramAPI {
}
/**
* Opens a Data Type Archive
* Opens an existing File Data Type Archive.
* <p>
* <B>NOTE:</B> If archive has an assigned architecture, issues may arise due to a revised or
* missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
* prevent the archive from being opened. Such a warning condition will 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
@ -2495,8 +2506,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);
}
/**

View file

@ -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,

View file

@ -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 +

View file

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

View file

@ -625,8 +625,9 @@ public class CParser {
private void applyFunctionQualifiers(Declaration dec, FunctionDefinitionDataType funcDT) {
List<Integer> 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:

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 {

View file

@ -908,5 +908,10 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
SourceArchive dataTypeSource) {
// don't care
}
@Override
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
// don't care
}
}
}

View file

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

View file

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

View file

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

View file

@ -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 {
@ -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,21 +344,25 @@ 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 purge", ((FunctionDefinition) dt).hasNoReturn());
dt = dtMgr.getDataType(new CategoryPath("/"), "UINT2");
assertTrue(dt instanceof TypeDef);

View file

@ -45,8 +45,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",

View file

@ -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<Long, DataType> copyMap = new HashMap<>();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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.*;

View file

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

View file

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

View file

@ -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____");

View file

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

View file

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

View file

@ -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) {

View file

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

View file

@ -345,11 +345,6 @@
<attribute name="extrapop"/>
<attribute name="stackshift"/>
<attribute name="name"/>
<optional>
<attribute name="type">
<ref name="generic_calling_convention_type"/>
</attribute>
</optional>
<optional>
<attribute name="strategy">

View file

@ -23,7 +23,6 @@ import ghidra.framework.Application;
import ghidra.framework.data.DomainObjectAdapterDB;
import ghidra.framework.model.*;
import ghidra.framework.options.Options;
import ghidra.program.database.data.ProjectDataTypeManager;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.listing.DataTypeArchive;
@ -32,7 +31,6 @@ import ghidra.program.util.*;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
/**
* Database implementation for Data Type Archive.
@ -493,7 +491,7 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB
// }
try {
dataTypeManager = new ProjectDataTypeManager(dbh, openMode, this, lock, monitor);
dataTypeManager = new ProjectDataTypeManager(this, dbh, openMode, this, lock, monitor);
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
@ -506,7 +504,6 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB
private void initManagers(int openMode, TaskMonitor monitor)
throws IOException, CancelledException {
monitor.checkCanceled();
dataTypeManager.setDataTypeArchive(this);
dataTypeManager.archiveReady(openMode, monitor);
}

View file

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

View file

@ -13,17 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.data;
package ghidra.program.database;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import javax.help.UnsupportedOperationException;
import db.*;
import db.util.ErrorHandler;
import ghidra.framework.model.DomainFile;
import ghidra.program.database.DataTypeArchiveDB;
import ghidra.framework.store.LockException;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.util.DataTypeArchiveChangeManager;
import ghidra.util.InvalidNameException;
import ghidra.util.Lock;
@ -35,13 +38,23 @@ import ghidra.util.task.TaskMonitor;
* Class for managing data types in a project archive
* NOTE: default data organization is used.
*/
public class ProjectDataTypeManager extends DataTypeManagerDB
public class ProjectDataTypeManager extends StandAloneDataTypeManager
implements ProjectArchiveBasedDataTypeManager {
private DataTypeArchiveDB dataTypeArchive;
private final DataTypeArchiveDB dataTypeArchive;
/**
* Constructor
* Constructor for a data-type manager using a specified DBHandle.
* <p>
* <B>NOTE:</B> If archive has an assigned architecture, issues may arise due to a revised or
* missing {@link Language}/{@link CompilerSpec} which will result in a warning but not
* prevent the archive from being opened. Such a warning condition will ne logged and may
* result in missing or stale information for existing datatypes which have architecture related
* data. In some case it may be appropriate to
* {@link FileDataTypeManager#getWarning() check for warnings} on the returned archive
* object prior to its use.
*
* @param dataTypeArchive associated archive
* @param handle open database handle
* @param openMode the program open mode
* @param errHandler the database I/O error handler
@ -51,17 +64,12 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
* @throws VersionException if the database does not match the expected version.
* @throws IOException if a database I/O error occurs.
*/
public ProjectDataTypeManager(DBHandle handle, int openMode, ErrorHandler errHandler, Lock lock,
ProjectDataTypeManager(DataTypeArchiveDB dataTypeArchive, DBHandle handle, int openMode,
ErrorHandler errHandler, Lock lock,
TaskMonitor monitor) throws CancelledException, VersionException, IOException {
super(handle, null, openMode, errHandler, lock, monitor);
}
/**
* Set the associated Archive
* @param dtArchive associated archive
*/
public void setDataTypeArchive(DataTypeArchiveDB dtArchive) {
this.dataTypeArchive = dtArchive;
super(handle, openMode, errHandler, lock, monitor);
this.dataTypeArchive = dataTypeArchive;
reportWarning();
}
@Override
@ -69,11 +77,6 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
return dataTypeArchive.getDomainFile().getName();
}
@Override
public Pointer getPointer(DataType dt) {
return PointerDataType.getPointer(dt, dataTypeArchive.getDefaultPointerSize());
}
@Override
public void setName(String name) throws InvalidNameException {
if (name == null || name.length() == 0) {
@ -84,6 +87,23 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
categoryRenamed(CategoryPath.ROOT, null);
}
@Override
public void clearProgramArchitecture(TaskMonitor monitor)
throws CancelledException, IOException, LockException {
dataTypeArchive.checkExclusiveAccess();
super.clearProgramArchitecture(monitor);
}
@Override
public void setProgramArchitecture(Language language, CompilerSpecID compilerSpecId,
LanguageUpdateOption updateOption, TaskMonitor monitor)
throws CompilerSpecNotFoundException, LanguageNotFoundException, IOException,
LockException, UnsupportedOperationException, IncompatibleLanguageException,
CancelledException {
dataTypeArchive.checkExclusiveAccess();
super.setProgramArchitecture(language, compilerSpecId, updateOption, monitor);
}
////////////////////
@Override
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
@ -169,21 +189,12 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
///////////////////
@Override
protected void replaceDataTypeIDs(long oldDataTypeID, long newDataTypeID) {
// dataTypeArchive.getCodeManager().replace(oldID, newID, monitor);
// TODO
// do nothing
}
@Override
protected void deleteDataTypeIDs(LinkedList<Long> deletedIds, TaskMonitor monitor)
throws CancelledException {
long[] ids = new long[deletedIds.size()];
Iterator<Long> it = deletedIds.iterator();
int i = 0;
while (it.hasNext()) {
ids[i++] = it.next().longValue();
}
// dataTypeArchive.getCodeManager().clearData(ids, monitor);
// TODO
protected void deleteDataTypeIDs(LinkedList<Long> deletedIds, TaskMonitor monitor) {
// do nothing
}
@Override
@ -191,6 +202,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
return dataTypeArchive.openTransaction(description);
}
@SuppressWarnings("sync-override")
@Override
public int startTransaction(String description) {
return dataTypeArchive.startTransaction(description);
@ -201,6 +213,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
dataTypeArchive.flushEvents();
}
@SuppressWarnings("sync-override")
@Override
public void endTransaction(int transactionID, boolean commit) {
dataTypeArchive.endTransaction(transactionID, commit);
@ -231,7 +244,7 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
public void archiveReady(int openMode, TaskMonitor monitor)
throws IOException, CancelledException {
if (openMode == DBConstants.UPGRADE) {
doSourceArchiveUpdates(null, monitor);
doSourceArchiveUpdates(monitor);
migrateOldFlexArrayComponentsIfRequired(monitor);
}
}

View file

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

View file

@ -47,6 +47,7 @@ class DataDB extends CodeUnitDB implements Data {
protected DataType baseDataType;
protected int level = 0;
protected ProgramDataTypeManager dataMgr;
private Boolean hasMutabilitySetting;

View file

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

View file

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

View file

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

View file

@ -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);
}
/**

Some files were not shown because too many files have changed in this diff Show more