Merge branch 'GP-2308_1633_ghidra1_FunctionDefinitionCallingConventions'

(Closes #4537, Closes #4898, Closes #3723, Closes #3267)
This commit is contained in:
ghidra1 2023-04-20 14:36:23 -04:00
commit 2cdaebf0c3
273 changed files with 8249 additions and 3415 deletions

View file

@ -264,9 +264,9 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
// TODO: Does the decompiler communicate the inferred calling convention? // TODO: Does the decompiler communicate the inferred calling convention?
try { try {
PrototypeModel convention = program.getCompilerSpec().findBestCallingConvention(params); 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" // Whatever, just leave sig at "unknown"
} }
return sig; return sig;
@ -352,7 +352,7 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
throw new PcodeExecutionException("Cannot get stack change for indirect call: " + op); throw new PcodeExecutionException("Cannot get stack change for indirect call: " + op);
} }
PrototypeModel convention = PrototypeModel convention =
program.getCompilerSpec().matchConvention(sig.getGenericCallingConvention()); program.getCompilerSpec().matchConvention(sig.getCallingConventionName());
if (convention == null) { if (convention == null) {
warnings.add(new UnspecifiedConventionStackUnwindWarning(null)); warnings.add(new UnspecifiedConventionStackUnwindWarning(null));
convention = program.getCompilerSpec().getDefaultCallingConvention(); convention = program.getCompilerSpec().getDefaultCallingConvention();

View file

@ -24,7 +24,9 @@ import db.DBHandle;
import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFile;
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB; import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceManager; import ghidra.trace.database.DBTraceManager;
import ghidra.trace.model.data.TraceBasedDataTypeManager; import ghidra.trace.model.data.TraceBasedDataTypeManager;
@ -38,15 +40,36 @@ import ghidra.util.task.TaskMonitor;
public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
implements TraceBasedDataTypeManager, DBTraceManager { implements TraceBasedDataTypeManager, DBTraceManager {
protected final ReadWriteLock lock; protected final ReadWriteLock lock; // TODO: This lock object is not used
protected final DBTrace trace; protected final DBTrace trace;
private static final String INSTANCE_TABLE_PREFIX = null; // placeholder only
public DBTraceDataTypeManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock, public DBTraceDataTypeManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
TaskMonitor monitor, DBTrace trace) TaskMonitor monitor, DBTrace trace)
throws CancelledException, VersionException, IOException { 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.lock = lock; // TODO: nothing uses this local lock - not sure what its purpose is
this.trace = trace; 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 @Override
@ -233,12 +256,4 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
*/ */
return ArchiveType.PROGRAM; 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; package ghidra.trace.database.program;
import static ghidra.lifecycle.Unfinished.TODO; import static ghidra.lifecycle.Unfinished.*;
import java.io.IOException; import java.io.IOException;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import generic.NestedIterator; import generic.NestedIterator;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
@ -64,7 +64,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
} }
@Override @Override
public List<String> getCallingConventionNames() { public Collection<String> getCallingConventionNames() {
return functions.getCallingConventionNames(); return functions.getCallingConventionNames();
} }
@ -78,11 +78,6 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
return functions.getCallingConvention(name); return functions.getCallingConvention(name);
} }
@Override
public PrototypeModel[] getCallingConventions() {
return functions.getCallingConventions();
}
@Override @Override
public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body, public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body,
SourceType source) throws InvalidInputException, OverlappingFunctionException { 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 org.apache.commons.lang3.tuple.Pair;
import db.DBRecord; import db.DBRecord;
import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.database.function.OverlappingFunctionException; import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; 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.AddressDBFieldCodec;
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
import ghidra.trace.database.bookmark.DBTraceBookmarkType; import ghidra.trace.database.bookmark.DBTraceBookmarkType;
import ghidra.trace.database.data.DBTraceDataTypeManager;
import ghidra.trace.database.listing.DBTraceCommentAdapter; import ghidra.trace.database.listing.DBTraceCommentAdapter;
import ghidra.trace.database.listing.DBTraceData; import ghidra.trace.database.listing.DBTraceData;
import ghidra.trace.database.program.DBTraceProgramView; import ghidra.trace.database.program.DBTraceProgramView;
@ -122,7 +124,7 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
@DBAnnotatedField(column = FIXUP_COLUMN_NAME) @DBAnnotatedField(column = FIXUP_COLUMN_NAME)
protected String callFixup; protected String callFixup;
@DBAnnotatedField(column = CALLING_CONVENTION_COLUMN_NAME) @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 // TODO: Pack into flags if more bits needed
@DBAnnotatedField(column = SIGNATURE_SOURCE_COLUMN_NAME) @DBAnnotatedField(column = SIGNATURE_SOURCE_COLUMN_NAME)
protected SourceType signatureSource = SourceType.ANALYSIS; // Assumed default, 0-ordinal protected SourceType signatureSource = SourceType.ANALYSIS; // Assumed default, 0-ordinal
@ -484,7 +486,8 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
} }
protected boolean hasExplicitCallingConvention() { protected boolean hasExplicitCallingConvention() {
return callingConventionID != -1 && callingConventionID != -2; return callingConventionID != DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID &&
callingConventionID != DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID;
} }
@Override @Override
@ -1734,16 +1737,14 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
if (cs == null) { if (cs == null) {
return null; return null;
} }
if (DBTraceSymbolManager.UNKNOWN_CALLING_CONVENTION_ID == callingConventionID) { DBTraceDataTypeManager dtm = manager.dataTypeManager;
if (callingConventionID == DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID) {
return null; return null;
} }
if (DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_ID == callingConventionID) { if (callingConventionID == DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID) {
return cs.getDefaultCallingConvention(); return cs.getDefaultCallingConvention();
} }
String ccName = manager.callingConventionMap.getKey(callingConventionID); String ccName = dtm.getCallingConventionName(callingConventionID);
if (ccName == null) {
return null;
}
return cs.getCallingConvention(ccName); return cs.getCallingConvention(ccName);
} }
} }
@ -1751,28 +1752,8 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
@Override @Override
public String getCallingConventionName() { public String getCallingConventionName() {
try (LockHold hold = LockHold.lock(manager.lock.readLock())) { try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
if (DBTraceSymbolManager.UNKNOWN_CALLING_CONVENTION_ID == callingConventionID) { DBTraceDataTypeManager dtm = manager.dataTypeManager;
return null; return dtm.getCallingConventionName(callingConventionID);
}
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;
} }
} }
@ -1783,12 +1764,16 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
thunked.setCallingConvention(name); thunked.setCallingConvention(name);
return; return;
} }
if (Objects.equals(getCallingConventionName(), name)) {
return; DBTraceDataTypeManager dtm = manager.dataTypeManager;
byte id = dtm.getCallingConventionID(name, true);
if (id == callingConventionID) {
return; // no change
} }
doLoadVariables(); doLoadVariables();
this.callingConventionID = manager.findOrRecordCallingConvention(name); callingConventionID = id;
update(CALLING_CONVENTION_COLUMN); update(CALLING_CONVENTION_COLUMN);
boolean hasCustomStorage = hasCustomVariableStorage(); boolean hasCustomStorage = hasCustomVariableStorage();
@ -1813,11 +1798,14 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), this)); new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), this));
} }
} }
catch (IOException e) {
manager.dbError(e);
}
} }
protected void createClassStructIfNeeded() { protected void createClassStructIfNeeded() {
PrototypeModel cc = getCallingConvention(); PrototypeModel cc = getCallingConvention();
if (cc == null || cc.getGenericCallingConvention() != GenericCallingConvention.thiscall) { if (cc == null || !CompilerSpec.CALLING_CONVENTION_thiscall.equals(cc.getName())) {
return; return;
} }
Namespace parentNS = getParentNamespace(); Namespace parentNS = getParentNamespace();

View file

@ -15,8 +15,7 @@
*/ */
package ghidra.trace.database.symbol; package ghidra.trace.database.symbol;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import ghidra.program.database.function.OverlappingFunctionException; import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.database.symbol.OverlappingNamespaceException; 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 @Override
public List<String> getCallingConventionNames() { public Collection<String> getCallingConventionNames() {
// TODO: Allow for user-selected compiler spec(s) return manager.dataTypeManager.getDefinedCallingConventionNames();
return getCallingConventionNames(manager.trace.getBaseCompilerSpec());
} }
@Override @Override
public PrototypeModel getDefaultCallingConvention() { public PrototypeModel getDefaultCallingConvention() {
CompilerSpec cs = manager.trace.getBaseCompilerSpec(); return manager.dataTypeManager.getDefaultCallingConvention();
if (cs == null) {
return null;
}
return cs.getDefaultCallingConvention();
} }
@Override @Override
public PrototypeModel getCallingConvention(String name) { public PrototypeModel getCallingConvention(String name) {
CompilerSpec cs = manager.trace.getBaseCompilerSpec(); return manager.dataTypeManager.getCallingConvention(name);
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();
} }
// TODO: Move this into a FunctionUtilities class? // TODO: Move this into a FunctionUtilities class?

View file

@ -20,9 +20,6 @@ import java.lang.reflect.Field;
import java.util.*; import java.util.*;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
import db.*; import db.*;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType; 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. * TODO: See if CALL-type references produce dynamic labels or functions.
*/ */
public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager { 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 long TYPE_MASK = 0xFF;
private static final int TYPE_SHIFT = 64 - 8; 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) @DBAnnotatedObjectInfo(version = 0)
public static class DBTraceFunctionTag extends DBAnnotatedObject implements FunctionTag { 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 DBTraceAddressSnapRangePropertyMap<Long, DBTraceSymbolIDEntry> idMap;
protected final DBCachedObjectStore<DBTraceCallingConventionEntry> callingConventionStore;
protected final BidiMap<String, Byte> callingConventionMap = new DualHashBidiMap<>();
protected final DBCachedObjectStore<DBTraceFunctionTag> tagStore; protected final DBCachedObjectStore<DBTraceFunctionTag> tagStore;
protected final DBCachedObjectIndex<String, DBTraceFunctionTag> tagsByName; protected final DBCachedObjectIndex<String, DBTraceFunctionTag> tagsByName;
@ -494,11 +457,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
baseLanguage, trace, threadManager, DBTraceSymbolIDEntry.class, baseLanguage, trace, threadManager, DBTraceSymbolIDEntry.class,
DBTraceSymbolIDEntry::new); DBTraceSymbolIDEntry::new);
callingConventionStore =
factory.getOrCreateCachedStore(DBTraceCallingConventionEntry.TABLE_NAME,
DBTraceCallingConventionEntry.class, DBTraceCallingConventionEntry::new, true);
loadCallingConventions();
tagStore = factory.getOrCreateCachedStore(DBTraceFunctionTag.TABLE_NAME, tagStore = factory.getOrCreateCachedStore(DBTraceFunctionTag.TABLE_NAME,
DBTraceFunctionTag.class, (s, r) -> new DBTraceFunctionTag(this, s, r), true); DBTraceFunctionTag.class, (s, r) -> new DBTraceFunctionTag(this, s, r), true);
tagsByName = tagStore.getIndex(String.class, DBTraceFunctionTag.NAME_COLUMN); tagsByName = tagStore.getIndex(String.class, DBTraceFunctionTag.NAME_COLUMN);
@ -570,9 +528,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
if (ptrSize != dataTypeManager.getDataOrganization().getPointerSize()) { if (ptrSize != dataTypeManager.getDataOrganization().getPointerSize()) {
return dataTypeManager.getPointer(formal, ptrSize); return dataTypeManager.getPointer(formal, ptrSize);
} }
else { return dataTypeManager.getPointer(formal);
return dataTypeManager.getPointer(formal);
}
} }
protected <T extends AbstractDBTraceSymbolSingleTypeView<?>> T putInMap(T view) { protected <T extends AbstractDBTraceSymbolSingleTypeView<?>> T putInMap(T view) {
@ -608,25 +564,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
return (symbolID >> KEY_SHIFT) & KEY_MASK; 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) { protected int findOrRecordVariableStorage(VariableStorage storage) {
DBTraceVariableStorageEntry entry = storageByStorage.getOne(storage); DBTraceVariableStorageEntry entry = storageByStorage.getOne(storage);
if (entry == null) { if (entry == null) {
@ -645,9 +582,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
public void invalidateCache(boolean all) { public void invalidateCache(boolean all) {
try (LockHold hold = LockHold.lock(lock.writeLock())) { try (LockHold hold = LockHold.lock(lock.writeLock())) {
idMap.invalidateCache(all); idMap.invalidateCache(all);
callingConventionStore.invalidateCache();
callingConventionMap.clear();
loadCallingConventions();
for (AbstractDBTraceSymbolSingleTypeView<?> view : symbolViews.values()) { for (AbstractDBTraceSymbolSingleTypeView<?> view : symbolViews.values()) {
view.invalidateCache(); view.invalidateCache();

View file

@ -15,7 +15,7 @@
*/ */
package ghidra.trace.model.symbol; package ghidra.trace.model.symbol;
import java.util.List; import java.util.Collection;
import ghidra.program.database.function.OverlappingFunctionException; import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.Address; 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); return add(Lifespan.nowOn(snap), entryPoint, body, name, thunked, parent, source);
} }
PrototypeModel[] getCallingConventions(); /**
* Get the ordered unmodifiable set of defined calling convention names. The reserved names
List<String> getCallingConventionNames(); * "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(); 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); PrototypeModel getCallingConvention(String name);
} }

View file

@ -19,8 +19,8 @@ import static ghidra.lifecycle.Unfinished.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import org.junit.*; import org.junit.*;
@ -423,25 +423,12 @@ public class DBTraceProgramViewFunctionManagerTest extends AbstractGhidraHeadles
assertEquals(defaultModel, protoModel); assertEquals(defaultModel, protoModel);
} }
@Test
public void testGetCallingConventions() throws Exception {
PrototypeModel[] protoModels = functionManager.getCallingConventions();
assertTrue(protoModels.length >= 1);
}
@Test @Test
public void testGetCallingConventionNames() throws Exception { public void testGetCallingConventionNames() throws Exception {
Collection<String> names = functionManager.getCallingConventionNames();
List<String> names = functionManager.getCallingConventionNames();
assertTrue(names.size() >= 1); assertTrue(names.size() >= 1);
for (String name : names) { for (String name : names) {
if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) { assertNotNull(functionManager.getCallingConvention(name));
assertNull(functionManager.getCallingConvention(name));
}
else {
assertNotNull(functionManager.getCallingConvention(name));
}
} }
} }

View file

@ -30,8 +30,9 @@ data/parserprofiles/MacOSX_10.9.prf||GHIDRA||||END|
data/parserprofiles/MacOSX_Cocoa.prf||GHIDRA||||END| data/parserprofiles/MacOSX_Cocoa.prf||GHIDRA||||END|
data/parserprofiles/VisualStudio12_32.prf||GHIDRA||||END| data/parserprofiles/VisualStudio12_32.prf||GHIDRA||||END|
data/parserprofiles/VisualStudio12_64.prf||GHIDRA||||END| data/parserprofiles/VisualStudio12_64.prf||GHIDRA||||END|
data/parserprofiles/VisualStudio9.prf||GHIDRA||reviewed||END| data/parserprofiles/VisualStudio22_64.prf||GHIDRA||||END|
data/parserprofiles/clib.prf||GHIDRA||reviewed||END| data/parserprofiles/VisualStudio9.prf||GHIDRA||||END|
data/parserprofiles/clib.prf||GHIDRA||||END|
data/parserprofiles/generic_clib_32.prf||GHIDRA||||END| data/parserprofiles/generic_clib_32.prf||GHIDRA||||END|
data/parserprofiles/generic_clib_64.prf||GHIDRA||||END| data/parserprofiles/generic_clib_64.prf||GHIDRA||||END|
data/parserprofiles/linux_32.prf||GHIDRA||||END| data/parserprofiles/linux_32.prf||GHIDRA||||END|

View file

@ -207,7 +207,6 @@ zlib.h
-DTARGET_API_MAC_OSX -DTARGET_API_MAC_OSX
-DTARGET_COCOA -DTARGET_COCOA
-DHANDLE="unsigned long" -DHANDLE="unsigned long"
-D_WCHAR_T
-D_Complex -D_Complex
-Drestrict -Drestrict
-D__restrict -D__restrict

View file

@ -323,7 +323,6 @@ zlib.h
-D_MAC_ -D_MAC_
-DTARGET_API_MAC_OSX -DTARGET_API_MAC_OSX
-DHANDLE="unsigned long" -DHANDLE="unsigned long"
-D_WCHAR_T
-D_Complex -D_Complex
-Drestrict -Drestrict
-D__restrict -D__restrict

View file

@ -28,7 +28,6 @@ Cocoa\Cocoa.h
-D_MAC_ -D_MAC_
-DTARGET_API_MAC_OSX=1 -DTARGET_API_MAC_OSX=1
-DHANDLE="unsigned long" -DHANDLE="unsigned long"
-D_WCHAR_T
-D_Complex -D_Complex
-Drestrict -Drestrict
-D__restrict -D__restrict

View file

@ -172,12 +172,8 @@ wpcapi.h
wscapi.h wscapi.h
wsdapi.h wsdapi.h
wspiapi.h wspiapi.h
rpcproxy.h rpcproxy.h
-I/VC/VS12/src
-I/VC/VS12/include
-I/VC/SDK/v7.1A/Include
-D_M_IX86=300 -D_M_IX86=300
-D_MSC_VER=1200 -D_MSC_VER=1200
-D_INTEGRAL_MAX_BITS=32 -D_INTEGRAL_MAX_BITS=32
@ -191,7 +187,6 @@ rpcproxy.h
-DSTRSAFE_LIB -DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL -DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM -DLPSKBINFO=LPARAM
-D_WCHAR_T_DEFINED
-DCONST=const -DCONST=const
-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
@ -205,3 +200,14 @@ rpcproxy.h
-D_ThrowInfo=ThrowInfo -D_ThrowInfo=ThrowInfo
-v0 -v0
-D__inner_checkReturn="" -D__inner_checkReturn=""
/data/HeaderFiles/VC/VS12/src
/data/HeaderFiles/VC/VS12/include
/data/HeaderFiles/VC/SDK/v7.1A/Include
x86:LE:32:default
windows

View file

@ -172,12 +172,8 @@ wpcapi.h
wscapi.h wscapi.h
wsdapi.h wsdapi.h
wspiapi.h wspiapi.h
rpcproxy.h rpcproxy.h
-I/VC/VS12/src
-I/VC/VS12/include
-I/VC/SDK/v7.1A/Include
-D_M_IX86=300 -D_M_IX86=300
-D_MSC_VER=1200 -D_MSC_VER=1200
-D_INTEGRAL_MAX_BITS=64 -D_INTEGRAL_MAX_BITS=64
@ -193,7 +189,6 @@ rpcproxy.h
-DSTRSAFE_LIB -DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL -DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM -DLPSKBINFO=LPARAM
-D_WCHAR_T_DEFINED
-DCONST=const -DCONST=const
-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
@ -208,3 +203,11 @@ rpcproxy.h
-D__unaligned="" -D__unaligned=""
-v0 -v0
-D__inner_checkReturn="" -D__inner_checkReturn=""
/data/HeaderFiles/VC/VS12/include
/data/HeaderFiles/VC/VS12/src
/data/HeaderFiles/VC/SDK/v7.1A/Include

View file

@ -0,0 +1,341 @@
# Core necessary files
winapifamily.h
winpackagefamily.h
sdkddkver.h
sal.h
no_sal2.h
corecrt.h
wtypes.h
winnt.h
winternl.h
#ntdef.h
# Common headers
dos.h
errno.h
malloc.h
signal.h
stdalign.h
stddef.h
stdio.h
stdlib.h
assert.h
crtdbg.h
ctype.h
conio.h
direct.h
fcntl.h
float.h
fpieee.h
inttypes.h
io.h
locale.h
complex.h
math.h
mbctype.h
mbstring.h
memory.h
minmax.h
new.h
process.h
search.h
share.h
winbase.h
winuser.h
Windows.h
# Security and identity (https://docs.microsoft.com/en-us/windows/win32/api/_security/)
accctrl.h
aclapi.h
aclui.h
advapi32.h
adtgen.h
authz.h
azroles.h
bcrypt.h
casetup.h
ccgplugins.h
celib.h
ntlsa.h
sspi.h
ntsecapi.h
ntsecpkg.h
schannel.h
certadm.h
certbcli.h
certcli.h
certenroll.h
certexit.h
certif.h
certmod.h
certpol.h
certpoleng.h
certsrv.h
certview.h
credssp.h
cryptdlg.h
cryptuiapi.h
cryptxml.h
diagnosticdataquery.h
diagnosticdataquerytypes.h
dpapi.h
dssec.h
iads.h
identitycommon.h
identityprovider.h
identitystore.h
keycredmgr.h
lmaccess.h
lsalookup.h
mmcobj.h
mscat.h
mssip.h
namedpipeapi.h
ncrypt.h
ncryptprotect.h
npapi.h
processthreadsapi.h
sas.h
scesvc.h
sddl.h
securityappcontainer.h
securitybaseapi.h
slpublic.h
subauth.h
tokenbinding.h
tpmvscmgr.h
wincred.h
wincrypt.h
winnetwk.h
winreg.h
winsafer.h
winscard.h
winsvc.h
wintrust.h
winwlx.h
xenroll.h
# Windows sockets
af_irda.h
in6addr.h
mstcpip.h
ws2def.h
winsock.h
winsock2.h
nsemail.h
nspapi.h
socketapi.h
# Nothing includes this; is it necessary?
#sporder.h
transportsettingcommon.h
ws2atm.h
ws2spi.h
mswsock.h
ws2tcpip.h
wsipv6ok.h
wsnwlink.h
wsrm.h
mswsockdef.h
# Remote Procedure Call (RPC)
midles.h
midlbase.h
rpc.h
rpcndr.h
rpcasync.h
rpcdcep.h
rpcnsi.h
rpcproxy.h
rpcssl.h
# COM
accctrl.h
callobj.h
combaseapi.h
comcat.h
ctxtcall.h
dmerror.h
docobj.h
eventsys.h
guiddef.h
iaccess.h
hstring.h
imessagedispatcher.h
messagedispatcherapi.h
objbase.h
objidlbase.h
objidl.h
ocidl.h
ole.h
ole2.h
oledlg.h
oleidl.h
roapi.h
rpcdce.h
servprov.h
shobjidl.h
txlogpub.h
unknwnbase.h
unknwn.h
urlmon.h
vbinterf.h
winddi.h
winerror.h
wtypesbase.h
# COM+
comadmin.h
mtxdm.h
# More
inspectable.h
# Windows Internet
proofofpossessioncookieinfo.h
wininet.h
winineti.h
# Windows HTTP Services
winhttp.h
# Compression
compressapi.h
# TraceLogging
#traceloggingactivity.h
#traceloggingprovider.h
# Windows Error Reporting
errorrep.h
werapi.h
# Windows and MEssages
olectl.h
windef.h
windowsx.h
# Shell
appmgmt.h
appnotify.h
cpl.h
credentialprovider.h
dimm.h
imagetranscode.h
inputpanelconfiguration.h
intsafe.h
intshcut.h
mobsync.h
objectarray.h
pathcch.h
profinfo.h
propkeydef.h
scrnsave.h
shappmgr.h
shdeprecated.h
shidfact.h
shimgdata.h
shlwapi.h
shtypes.h
storageprovider.h
syncmgr.h
thumbcache.h
thumbnailstreamcache.h
tlogstg.h
userenv.h
# Windows Controls
commctrl.h
commoncontrols.h
dpa_dsa.h
prsht.h
richedit.h
richole.h
shlobj_core.h
shlobj.h
#textserv.h // C++
tom.h
uxtheme.h
# Menus and other resources
resourceindexer.h
strsafe.h
verrsrc.h
winver.h
# Windows Accessibility Features
oleacc.h
uiautomationcore.h
uiautomationclient.h
uiautomationcoreapi.h
# Internationalization
datetimeapi.h
elscore.h
gb18030.h
imepad.h
imm.h
immdev.h
msime.h
msimeapi.h
muiload.h
spellcheck.h
spellcheckprovider.h
stringapiset.h
usp10.h
winnls.h
# HTTP Server API
#http.h // included by something else
# IP Helper
ifdef.h
inaddr.h
ip2string.h
ipexport.h
iphlpapi.h
icmpapi.h
iprtrmib.h
iptypes.h
netioapi.h
nldef.h
tcpestats.h
ws2ipdef.h
# Network Management
atacct.h
lmalert.h
lmapibuf.h
lmat.h
lmaudit.h
lmconfig.h
lmerrlog.h
lmjoin.h
lmmsg.h
lmremutl.h
lmserver.h
lmsvc.h
lmuse.h
lmwksta.h
-D_MSC_VER=1924
-D_INTEGRAL_MAX_BITS=64
-DWINVER=0x0a00
-D_WIN32_WINNT=0x0a00
-D_AMD64_
-D_M_AMD64
-D_M_X64
-D_WIN64
-D_WIN32
-D_USE_ATTRIBUTES_FOR_SAL
-D_CRTBLD
-D_OPENMP_NOFORCE_MANIFEST
-DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
-DCONST=const
-D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE
-D_CRT_NONSTDC_NO_WARNINGS
-D_CRT_OBSOLETE_NO_DEPRECATE
-D_ALLOW_KEYWORD_MACROS
-D_ASSERT_OK
-DSTRSAFE_NO_DEPRECATE
-D__possibly_notnullterminated
"-Dtype_info=\"void *\"",
-D_ThrowInfo=ThrowInfo
-D__unaligned=
-v0
-D__inner_checkReturn=
-DWINAPI_PARTITION_APP=1
-DWINAPI_PARTITION_SYSTEM=1
-DWINAPI_PARTITION_GAMES=1
-DSECURITY_WIN32
/data/HeaderFiles/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include
/data/HeaderFiles/VC/VS22/10.0.19041.0/shared
/data/HeaderFiles/VC/VS22/10.0.19041.0/ucrt
/data/HeaderFiles/VC/VS22/10.0.19041.0/um
/data/HeaderFiles/VC/VS22/10.0.19041.0/winrt
x86:LE:64:default
windows

View file

@ -58,13 +58,10 @@ yvals.h
CommDlg.h CommDlg.h
WinUser.h WinUser.h
WinNls.h WinNls.h
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src\internal.h internal.h
strsafe.h strsafe.h
penwin.h penwin.h
-IC:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Include
-IC:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include
-IC:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
-D_M_IX86=500 -D_M_IX86=500
-D_MSC_VER=9090 -D_MSC_VER=9090
-D_MSC_EXTENSIONS -D_MSC_EXTENSIONS
@ -85,5 +82,11 @@ penwin.h
-DSTRSAFE_LIB_IMPL -DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM -DLPSKBINFO=LPARAM
-D_PHNDLR=void * -D_PHNDLR=void *
-D_WCHAR_T_DEFINED
-DCONST=const -DCONST=const
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Include
C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
x86:LE:64:default

View file

@ -78,13 +78,17 @@ wchar.h
wctype.h wctype.h
wordexp.h wordexp.h
-IU:\linux_include\include
-IU:\linux_include\include\sys
-IU:\linux_include\i386-redhat-linux\4.1.2\include
-D_X86_ -D_X86_
-D__STDC__ -D__STDC__
-D__WORDSIZE=32 -D__WORDSIZE=32
-D__builtin_va_list=void * -D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE -D__DO_NOT_DEFINE_COMPILE
-D_Complex -D_Complex
-D_WCHAR_T
U:\linux_include\include
U:\linux_include\include\sys
U:\linux_include\i386-redhat-linux\4.1.2\include
x86:LE:32:default
gcc

View file

@ -219,11 +219,6 @@ arpa/nameser_compat.h
arpa/telnet.h arpa/telnet.h
arpa/tftp.h arpa/tftp.h
-I/linux/include
-I/linux/include/sys
-I/linux/gcc/include
-I/linux/x86_64-redhat-linux5E/include
-I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_ -D_X86_
-D__STDC__ -D__STDC__
-D_GNU_SOURCE -D_GNU_SOURCE
@ -231,10 +226,19 @@ arpa/tftp.h
-D__builtin_va_list=void * -D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE -D__DO_NOT_DEFINE_COMPILE
-D_Complex -D_Complex
-D_WCHAR_T
-D__NO_STRING_INLINES -D__NO_STRING_INLINES
-D__NO_LONG_DOUBLE_MATH -D__NO_LONG_DOUBLE_MATH
-D__signed__ -D__signed__
-D__extension__="" -D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1 -D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t -Daligned_u64=uint64_t
/data/HeaderFiles/linux/include
/data/HeaderFiles/linux/include/sys
/data/HeaderFiles/linux/gcc/include
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
x86:LE:32:default
gcc

View file

@ -219,11 +219,6 @@ arpa/nameser_compat.h
arpa/telnet.h arpa/telnet.h
arpa/tftp.h arpa/tftp.h
-I/linux/include
-I/linux/include/sys
-I/linux/gcc/include
-I/linux/x86_64-redhat-linux5E/include
-I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_ -D_X86_
-D__STDC__ -D__STDC__
-D_GNU_SOURCE -D_GNU_SOURCE
@ -231,10 +226,19 @@ arpa/tftp.h
-D__builtin_va_list=void * -D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE -D__DO_NOT_DEFINE_COMPILE
-D_Complex -D_Complex
-D_WCHAR_T
-D__NO_STRING_INLINES -D__NO_STRING_INLINES
-D__signed__ -D__signed__
-D__extension__="" -D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1 -D__GLIBC_HAVE_LONG_LONG=1
-D__need_sigset_t -D__need_sigset_t
-Daligned_u64=uint64_t -Daligned_u64=uint64_t
/data/HeaderFiles/linux/include
/data/HeaderFiles/linux/include/sys
/data/HeaderFiles/linux/gcc/include
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
x86:LE:64:default
gcc

View file

@ -515,11 +515,6 @@ mechglue.h
auth_gss.h auth_gss.h
auth_gssapi.h auth_gssapi.h
-I/linux/include
-I/linux/include/sys
-I/linux/gcc/include
-I/linux/x86_64-redhat-linux5E/include
-I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_ -D_X86_
-D__STDC__ -D__STDC__
-D_POSIX_C_SOURCE -D_POSIX_C_SOURCE
@ -528,10 +523,19 @@ auth_gssapi.h
-D__builtin_va_list=void * -D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE -D__DO_NOT_DEFINE_COMPILE
-D_Complex -D_Complex
-D_WCHAR_T
-D__NO_STRING_INLINES -D__NO_STRING_INLINES
-D__NO_LONG_DOUBLE_MATH -D__NO_LONG_DOUBLE_MATH
-D__signed__ -D__signed__
-D__extension__="" -D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1 -D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t -Daligned_u64=uint64_t
/data/HeaderFiles/linux/include
/data/HeaderFiles/linux/include/sys
/data/HeaderFiles/linux/gcc/include
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
x86:LE:32:default
gcc

View file

@ -515,11 +515,6 @@ mechglue.h
auth_gss.h auth_gss.h
auth_gssapi.h auth_gssapi.h
-I/linux/include
-I/linux/include/sys
-I/linux/gcc/include
-I/linux/x86_64-redhat-linux5E/include
-I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_ -D_X86_
-D__STDC__ -D__STDC__
-D_POSIX_C_SOURCE -D_POSIX_C_SOURCE
@ -528,9 +523,18 @@ auth_gssapi.h
-D__builtin_va_list=void * -D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE -D__DO_NOT_DEFINE_COMPILE
-D_Complex -D_Complex
-D_WCHAR_T
-D__NO_STRING_INLINES -D__NO_STRING_INLINES
-D__signed__ -D__signed__
-D__extension__="" -D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1 -D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t -Daligned_u64=uint64_t
/data/HeaderFiles/linux/include
/data/HeaderFiles/linux/include/sys
/data/HeaderFiles/linux/gcc/include
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
x86:LE:64:default
gcc

View file

@ -222,9 +222,6 @@ wscapi.h
wsdapi.h wsdapi.h
wspiapi.h wspiapi.h
-I/VisualStudio/VS12/include
-I/VisualStudio/Windows/v7.0a/Include
-I/VisualStudio/VS12/src
-D_M_IX86 -D_M_IX86
-D_MSC_VER=9090 -D_MSC_VER=9090
-D_INTEGRAL_MAX_BITS=32 -D_INTEGRAL_MAX_BITS=32
@ -239,7 +236,6 @@ wspiapi.h
-DSTRSAFE_LIB -DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL -DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM -DLPSKBINFO=LPARAM
-D_WCHAR_T_DEFINED
-DCONST=const -DCONST=const
-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
@ -250,3 +246,12 @@ wspiapi.h
-D__possibly_notnullterminated -D__possibly_notnullterminated
-Dtype_info="void *" -Dtype_info="void *"
-v0 -v0
/data/HeaderFiles/VC/VS12/include
/data/HeaderFiles/VC/Windows/v7.0a/Include
/data/HeaderFiles/VC/VS12/src
x86:LE:32:default
windows

View file

@ -26,6 +26,7 @@ import java.util.Iterator;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.util.UniversalID; import ghidra.util.UniversalID;
public class CompareGDTs extends GhidraScript { public class CompareGDTs extends GhidraScript {
@ -54,13 +55,28 @@ public class CompareGDTs extends GhidraScript {
return; 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?", matchByName = askYesNo("Match Data Types By Path Name?",
"Do you want to match data types by their path names (rather than by Universal ID)?"); "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?"); checkPointers = askYesNo("Check Pointers?", "Do you want to check Pointers?");
checkArrays = askYesNo("Check Arrays?", "Do you want to check Arrays?"); checkArrays = askYesNo("Check Arrays?", "Do you want to check Arrays?");
firstArchive = FileDataTypeManager.openFileArchive(firstFile, false);
secondArchive = FileDataTypeManager.openFileArchive(secondFile, false);
printWriter = new PrintWriter(outputFile); printWriter = new PrintWriter(outputFile);
try { try {
compareDataTypes(); compareDataTypes();

View file

@ -31,6 +31,7 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils; import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException; import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.data.FileDataTypeManager;
@ -55,14 +56,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
} }
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
String[] filenames, String includePaths[], String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
DataTypeManager openTypes[] = null; DataTypeManager openTypes[] = null;
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args); parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
} }
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
String[] filenames, String[] includePaths, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt"; String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
@ -71,9 +74,9 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor); CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
Msg.info(this, messages); Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save(); dtMgr.save();
dtMgr.close(); dtMgr.close();
@ -276,14 +279,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"wscapi.h", "wscapi.h",
"wsdapi.h", "wsdapi.h",
"wspiapi.h", "wspiapi.h",
"rpcproxy.h", "rpcproxy.h",
}; };
String includePaths[] = {
headerFilePath+"/VC/VS12/src",
headerFilePath+"/VC/VS12/include",
headerFilePath+"/VC/SDK/v7.1A/Include",
};
String args[] = { String args[] = {
"-I"+headerFilePath+"/VC/VS12/src",
"-I"+headerFilePath+"/VC/VS12/include",
"-I"+headerFilePath+"/VC/SDK/v7.1A/Include",
"-D_M_IX86=300", "-D_M_IX86=300",
"-D_MSC_VER=1200", "-D_MSC_VER=1200",
"-D_INTEGRAL_MAX_BITS=32", "-D_INTEGRAL_MAX_BITS=32",
@ -294,8 +299,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D_USE_ATTRIBUTES_FOR_SAL", "-D_USE_ATTRIBUTES_FOR_SAL",
"-D_CRTBLD", "-D_CRTBLD",
"-D_OPENMP_NOFORCE_MANIFEST", "-D_OPENMP_NOFORCE_MANIFEST",
"-DSTRSAFE_LIB",
"-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM", "-DLPSKBINFO=LPARAM",
"-DCONST=const", "-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS", "-D_CRT_SECURE_NO_WARNINGS",
@ -312,7 +315,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D__inner_checkReturn=", "-D__inner_checkReturn=",
}; };
parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, args); parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, includePaths, args);
} }
@ -494,14 +497,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"wscapi.h", "wscapi.h",
"wsdapi.h", "wsdapi.h",
"wspiapi.h", "wspiapi.h",
"rpcproxy.h", "rpcproxy.h",
}; };
String includePaths[] = {
headerFilePath+"/VC/VS12/src",
headerFilePath+"/VC/VS12/include",
headerFilePath+"/VC/SDK/v7.1A/Include",
};
String args[] = { String args[] = {
"-I"+headerFilePath+"/VC/VS12/src",
"-I"+headerFilePath+"/VC/VS12/include",
"-I"+headerFilePath+"/VC/SDK/v7.1A/Include",
"-D_MSC_VER=1200", "-D_MSC_VER=1200",
"-D_INTEGRAL_MAX_BITS=64", "-D_INTEGRAL_MAX_BITS=64",
"-DWINVER=0x0900", "-DWINVER=0x0900",
@ -513,8 +518,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D_USE_ATTRIBUTES_FOR_SAL", "-D_USE_ATTRIBUTES_FOR_SAL",
"-D_CRTBLD", "-D_CRTBLD",
"-D_OPENMP_NOFORCE_MANIFEST", "-D_OPENMP_NOFORCE_MANIFEST",
"-DSTRSAFE_LIB",
"-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM", "-DLPSKBINFO=LPARAM",
"-DCONST=const", "-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS", "-D_CRT_SECURE_NO_WARNINGS",
@ -532,7 +535,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D__inner_checkReturn=", "-D__inner_checkReturn=",
}; };
parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, args); parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, includePaths, args);
} }
@ -761,12 +764,15 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"arpa/tftp.h", "arpa/tftp.h",
}; };
String includePaths[] = {
headerFilePath+"/linux/include",
headerFilePath+"/linux/include/sys",
headerFilePath+"/linux/gcc/include",
headerFilePath+"/linux/x86_64-redhat-linux5E/include",
headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
};
String args[] = { String args[] = {
"-I"+headerFilePath+"/linux/include",
"-I"+headerFilePath+"/linux/include/sys",
"-I"+headerFilePath+"/linux/gcc/include",
"-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include",
"-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
"-D_X86_", "-D_X86_",
"-D__STDC__", "-D__STDC__",
"-D_GNU_SOURCE", "-D_GNU_SOURCE",
@ -782,7 +788,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-Daligned_u64=uint64_t", "-Daligned_u64=uint64_t",
}; };
parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, args); parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, includePaths, args);
} }
@ -1011,12 +1017,15 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"arpa/tftp.h", "arpa/tftp.h",
}; };
String includePaths[] = {
headerFilePath+"/linux/include",
headerFilePath+"/linux/include/sys",
headerFilePath+"/linux/gcc/include",
headerFilePath+"/linux/x86_64-redhat-linux5E/include",
headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
};
String args[] = { String args[] = {
"-I"+headerFilePath+"/linux/include",
"-I"+headerFilePath+"/linux/include/sys",
"-I"+headerFilePath+"/linux/gcc/include",
"-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include",
"-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
"-D_X86_", "-D_X86_",
"-D__STDC__", "-D__STDC__",
"-D_GNU_SOURCE", "-D_GNU_SOURCE",
@ -1032,6 +1041,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-Daligned_u64=uint64_t", "-Daligned_u64=uint64_t",
}; };
parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, args); parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, includePaths, args);
} }
} }

View file

@ -31,6 +31,7 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils; import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException; import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.data.FileDataTypeManager;
@ -52,14 +53,16 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
parseGDT_WinVS22(); parseGDT_WinVS22();
} }
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
String[] filenames, String includePaths[], String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
DataTypeManager openTypes[] = null; DataTypeManager openTypes[] = null;
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args); parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
} }
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
String[] filenames, String[] includePaths, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt"; String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
@ -68,9 +71,9 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor); CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
Msg.info(this, messages); Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save(); dtMgr.save();
dtMgr.close(); dtMgr.close();
@ -79,7 +82,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
/** /**
* Turn string into a file, delete old archive if it exists * Turn string into a file, delete old archive if it exists
* *
* @param dataTypeFile * @param dataTypeFile name of archive file
* *
* @return file * @return file
*/ */
@ -112,12 +115,15 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"dsound.h", "dsound.h",
}; };
String includeFiles[] = {
headerFilePath+"/VC/VS22/10.0.190141.0",
headerFilePath+"/VC/VS22/10.0.19041.0/um",
headerFilePath+"/VC/VS22/10.0.19041.0/shared",
headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include",
};
String args[] = { String args[] = {
"-I"+headerFilePath+"/VC/VS22/10.0.190141.0",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
"-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include",
"-D_AMD64_", "-D_AMD64_",
"-D_M_AMD64", "-D_M_AMD64",
"-D_M_X64", "-D_M_X64",
@ -126,7 +132,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-v0", "-v0",
}; };
parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, args); parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, includeFiles, args);
} }
public void parseGDT_WinVS22() throws Exception { public void parseGDT_WinVS22() throws Exception {
@ -167,7 +173,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"complex.h", "complex.h",
"math.h", "math.h",
"mbctype.h", "mbctype.h",
"mbstring.hs", "mbstring.h",
"memory.h", "memory.h",
"minmax.h", "minmax.h",
"new.h", "new.h",
@ -216,7 +222,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"dssec.h", "dssec.h",
"iads.h", "iads.h",
"identitycommon.h", "identitycommon.h",
"identityproviders.h", "identityprovider.h",
"identitystore.h", "identitystore.h",
"keycredmgr.h", "keycredmgr.h",
"lmaccess.h", "lmaccess.h",
@ -237,7 +243,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"slpublic.h", "slpublic.h",
"subauth.h", "subauth.h",
"tokenbinding.h", "tokenbinding.h",
"tpmsvcmgr.h", "tpmvscmgr.h",
"wincred.h", "wincred.h",
"wincrypt.h", "wincrypt.h",
"winnetwk.h", "winnetwk.h",
@ -267,7 +273,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"mswsock.h", "mswsock.h",
"ws2tcpip.h", "ws2tcpip.h",
"wsipv6ok.h", "wsipv6ok.h",
"wslwlink.h", "wsnwlink.h",
"wsrm.h", "wsrm.h",
"mswsockdef.h", "mswsockdef.h",
@ -375,7 +381,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"thumbcache.h", "thumbcache.h",
"thumbnailstreamcache.h", "thumbnailstreamcache.h",
"tlogstg.h", "tlogstg.h",
"usereng.h", "userenv.h",
"# Windows Controls", "# Windows Controls",
"commctrl.h", "commctrl.h",
@ -452,12 +458,15 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"lmwksta.h" "lmwksta.h"
}; };
String includeFiles[] = {
headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
headerFilePath+"/VC/VS22/10.0.19041.0/shared",
headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
headerFilePath+"/VC/VS22/10.0.19041.0/um",
headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
};
String args[] = { String args[] = {
"-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
"-D_MSC_VER=1924", "-D_MSC_VER=1924",
"-D_INTEGRAL_MAX_BITS=64", "-D_INTEGRAL_MAX_BITS=64",
"-DWINVER=0x0a00", "-DWINVER=0x0a00",
@ -473,7 +482,6 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-DSTRSAFE_LIB", "-DSTRSAFE_LIB",
"-DSTRSAFE_LIB_IMPL", "-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM", "-DLPSKBINFO=LPARAM",
"-D_WCHAR_T_DEFINED",
"-DCONST=const", "-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS", "-D_CRT_SECURE_NO_WARNINGS",
"-D_CRT_NONSTDC_NO_DEPRECATE", "-D_CRT_NONSTDC_NO_DEPRECATE",
@ -494,6 +502,6 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-DSECURITY_WIN32", "-DSECURITY_WIN32",
}; };
parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, args); parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, includeFiles, args);
} }
} }

View file

@ -29,6 +29,7 @@ import ghidra.app.script.GhidraScript;
import ghidra.app.services.DataTypeManagerService; import ghidra.app.services.DataTypeManagerService;
import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFile;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProjectDataTypeManager;
import ghidra.program.database.data.*; import ghidra.program.database.data.*;
import ghidra.program.model.data.BuiltInDataTypeManager; import ghidra.program.model.data.BuiltInDataTypeManager;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;

View file

@ -24,43 +24,59 @@ import java.io.File;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.program.model.data.Category; import ghidra.program.model.data.Category;
import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.data.FileDataTypeManager;
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.util.InvalidNameException; import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
public class SynchronizeGDTCategoryPaths extends GhidraScript { public class SynchronizeGDTCategoryPaths extends GhidraScript {
private File firstFile;
private File secondFile;
private FileDataTypeManager firstArchive;
private FileDataTypeManager secondArchive;
@Override @Override
protected void run() throws Exception { protected void run() throws Exception {
firstFile = askFile("Select First GDT File", "Select 1st");
secondFile = askFile("Select Second GDT File", "Select 2nd");
try { File firstFile = askFile("Select First GDT File", "Select 1st");
firstArchive = FileDataTypeManager.openFileArchive(firstFile, false); try (FileDataTypeManager firstArchive =
secondArchive = FileDataTypeManager.openFileArchive(secondFile, true); FileDataTypeManager.openFileArchive(firstFile, false)) {
if (hasWarning(firstArchive, firstFile)) {
int transactionID = secondArchive.startTransaction("Synchronize Category Path Names"); return;
Category firstCategory = firstArchive.getRootCategory();
Category secondCategory = secondArchive.getRootCategory();
synchronizeCategory(firstCategory, secondCategory);
secondArchive.endTransaction(transactionID, true);
}
finally {
if (firstArchive != null) {
firstArchive.close();
} }
secondArchive.save();
if (secondArchive != null) { File secondFile = askFile("Select Second GDT File", "Select 2nd");
secondArchive.close(); 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) { private void synchronizeCategory(Category firstCategory, Category secondCategory) {
Category[] firstCategories = firstCategory.getCategories(); Category[] firstCategories = firstCategory.getCategories();
for (Category categoryA : firstCategories) { for (Category categoryA : firstCategories) {

View file

@ -123,18 +123,27 @@
<tocdef id="Ghidra Functionality" <tocdef id="Ghidra Functionality"
sortgroup="e" sortgroup="e"
text="Ghidra Functionality" text="Ghidra Functionality"
target = "help/topics/Intro/GhidraFunctionality.htm"> target = "help/topics/Intro/GhidraFunctionality.htm">
<tocdef id="Code Browser" text="Code Browser" target="help/topics/CodeBrowserPlugin/CodeBrowser.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="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="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="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 id="Code Browser Configuration Options" sortgroup="d" text="Configuration Options" target="help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm" />
</tocdef> </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="Assembler" text="Assembler" target="help/topics/AssemblerPlugin/Assembler.htm"></tocdef>
<tocdef id="Entropy Overview" text="Entropy Overview" target="help/topics/OverviewPlugin/Overview.htm#EntropyOverviewBar" > <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="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="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 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="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 id="Save Image" sortgroup="e" text="Save Image" target="help/topics/ResourceActionsPlugin/ResourceActions.html" />
</tocdef> </tocdef>

View file

@ -353,6 +353,14 @@
editing, since they support sharing and version control and therefore allow more than one 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 user to modify them at a time. Only one user at a time can have a file archive opened for
editing.</P> 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>
<BLOCKQUOTE> <BLOCKQUOTE>
@ -406,6 +414,51 @@
Archive.</P> Archive.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
</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> <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, func.updateFunction(conventionName, returnParam, params,
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, false, source); FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, false, source);
func.setVarArgs(signature.hasVarArgs()); func.setVarArgs(signature.hasVarArgs());
func.setNoReturn(signature.hasNoReturn());
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
// should not happen unless caused by a concurrent operation // 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) { private String getCallingConvention(Function function, CompilerSpec compilerSpec) {
PrototypeModel preferredModel = null;
if (signature.getGenericCallingConvention() != GenericCallingConvention.unknown) { // Ignore signature's calling convention if unknown/not-defined
preferredModel = compilerSpec.matchConvention(signature.getGenericCallingConvention()); String callingConvention = signature.getCallingConventionName();
if (compilerSpec.getCallingConvention(callingConvention) == null) {
callingConvention = null;
} }
PrototypeModel convention = function.getCallingConvention(); // Continue using function's current calling convention if valid and either
if (convention == null || !preserveCallingConvention) { // reservation was requested or signature's convention is unknown/not-defined.
convention = preferredModel; PrototypeModel currentConvention = function.getCallingConvention();
// NOTE: This has been disable since it can cause imported signature information to be if (currentConvention != null && (callingConvention == null || preserveCallingConvention)) {
// ignored and overwritten by subsequent analysis callingConvention = function.getCallingConventionName();
// 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;
// }
} }
// Calling convention is permitted to change return callingConvention;
String conventionName = function.getCallingConventionName();
if (!preserveCallingConvention && convention != null) {
conventionName = convention.getName();
}
return conventionName;
} }
private static void updateStackPurgeSize(Function function, Program program) { private static void updateStackPurgeSize(Function function, Program program) {

View file

@ -1473,6 +1473,7 @@ public class DataTypeMergeManager implements MergeResolver {
ParameterDefinition[] sourceVars = sourceFunctionDefDt.getArguments(); ParameterDefinition[] sourceVars = sourceFunctionDefDt.getArguments();
ParameterDefinition[] destVars = new ParameterDefinition[sourceVars.length]; ParameterDefinition[] destVars = new ParameterDefinition[sourceVars.length];
boolean sourceHasVarArgs = sourceFunctionDefDt.hasVarArgs(); boolean sourceHasVarArgs = sourceFunctionDefDt.hasVarArgs();
boolean sourceHasNoReturn = sourceFunctionDefDt.hasNoReturn();
DataType resolvedRDT = DataType.DEFAULT; DataType resolvedRDT = DataType.DEFAULT;
if (sourceReturnType != null) { if (sourceReturnType != null) {
@ -1492,6 +1493,7 @@ public class DataTypeMergeManager implements MergeResolver {
} }
destDt.setArguments(destVars); destDt.setArguments(destVars);
destDt.setVarArgs(sourceHasVarArgs); destDt.setVarArgs(sourceHasVarArgs);
destDt.setNoReturn(sourceHasNoReturn);
destDt.setLastChangeTime(oldLastChangeTime); destDt.setLastChangeTime(oldLastChangeTime);
destDt.setLastChangeTimeInSourceArchive(oldLastChangeTimeInSourceArchive); destDt.setLastChangeTimeInSourceArchive(oldLastChangeTimeInSourceArchive);

View file

@ -29,6 +29,7 @@ import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition; import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature; import ghidra.program.model.listing.FunctionSignature;
import ghidra.util.StringUtilities; import ghidra.util.StringUtilities;
import ghidra.util.UniversalID; import ghidra.util.UniversalID;
@ -348,7 +349,14 @@ class DataTypePanel extends JPanel {
ParameterDefinition[] vars = fd.getArguments(); ParameterDefinition[] vars = fd.getArguments();
DataType returnType = fd.getReturnType(); DataType returnType = fd.getReturnType();
if (fd.hasNoReturn()) {
insertString(FunctionSignature.NORETURN_DISPLAY_STRING + " ", contentAttrSet);
}
insertString(returnType.getDisplayName(), 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(" " + fd.getDisplayName(), nameAttrSet);
insertString(" (", contentAttrSet); insertString(" (", contentAttrSet);
boolean hasVarArgs = fd.hasVarArgs(); boolean hasVarArgs = fd.hasVarArgs();

View file

@ -15,7 +15,13 @@
*/ */
package ghidra.app.plugin.core.compositeeditor; package ghidra.app.plugin.core.compositeeditor;
import java.io.IOException;
import ghidra.program.model.data.*; 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 { 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. * The data type manager for original composite data type being edited.
* This is where the edited datatype will be written back to. * This is where the edited datatype will be written back to.
*/ */
private DataTypeManager originalDTM; private final DataTypeManager originalDTM;
private Composite originalComposite; private final Composite originalComposite;
private Composite viewComposite; private final Composite viewComposite;
private int transactionID; private final int transactionID;
/** /**
* Creates a data type manager that the structure editor will use * Creates a data type manager that the structure editor will use
@ -39,16 +45,42 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
this.originalComposite = originalComposite; this.originalComposite = originalComposite;
transactionID = startTransaction(""); transactionID = startTransaction("");
originalDTM = originalComposite.getDataTypeManager(); 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); viewComposite = (Composite) super.resolve(originalComposite, null);
} }
@Override
protected final boolean isArchitectureChangeAllowed() {
return false;
}
@Override @Override
public void close() { public void close() {
endTransaction(transactionID, true); endTransaction(transactionID, true);
super.close(); super.close();
} }
/**
* Get the {@link DataTypeManager} associated with the original composite datatype being edited.
* @return original datatype manager
*/
public DataTypeManager getOriginalDataTypeManager() {
return originalDTM;
}
@Override @Override
public ArchiveType getType() { public ArchiveType getType() {
return originalDTM.getType(); return originalDTM.getType();

View file

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

View file

@ -15,19 +15,13 @@
*/ */
package ghidra.app.plugin.core.cparser; package ghidra.app.plugin.core.cparser;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.IOException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.apache.commons.io.DirectoryWalker.CancelException;
import docking.ActionContext; import docking.ActionContext;
import docking.action.DockingAction; import docking.action.DockingAction;
import docking.action.MenuData; import docking.action.MenuData;
@ -38,21 +32,17 @@ import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin; import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.services.DataTypeManagerService; import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.C.CParser; import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.CPP.PreProcessor; import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.framework.options.SaveState; import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginInfo; import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.database.data.ProgramDataTypeManager; import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.data.BuiltInDataTypeManager; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.HTMLUtilities; import ghidra.util.*;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -66,22 +56,20 @@ import ghidra.util.task.TaskMonitor;
) )
//@formatter:on //@formatter:on
public class CParserPlugin extends ProgramPlugin { public class CParserPlugin extends ProgramPlugin {
final static String PARSE_ACTION_NAME = "Import C DataTypes"; public final static String PARSE_ACTION_NAME = "Import C DataTypes";
final static String USER_PROFILES_DIR = final static String USER_PROFILES_DIR =
Application.getUserSettingsDirectory().getAbsolutePath() + File.separatorChar + Application.getUserSettingsDirectory().getAbsolutePath() + File.separatorChar +
"parserprofiles"; "parserprofiles";
private ParseDialog parseDialog; private ParseDialog parseDialog;
private File userProfileDir; private File userProfileDir;
private String parserMessages; private CParseResults results;
private String cppMessages;
final static String DESCRIPTION = final static String DESCRIPTION =
"Parse C and C Header files, extracting data definitions and function signatures."; "Parse C and C Header files, extracting data definitions and function signatures.";
private static final String PARSER_DEBUG_OUTFILE = "CParserPlugin.out";
public CParserPlugin(PluginTool plugintool) { public CParserPlugin(PluginTool plugintool) {
super(plugintool); super(plugintool);
createActions(); createActions();
@ -155,26 +143,37 @@ public class CParserPlugin extends ProgramPlugin {
if (parseDialog == null) { if (parseDialog == null) {
parseDialog = new ParseDialog(this); parseDialog = new ParseDialog(this);
} }
else { parseDialog.setupForDisplay();
parseDialog.toFront();
}
tool.showDialog(parseDialog); tool.showDialog(parseDialog);
} }
/* /*
* Parse into a saved data type data base file * Parse into a saved data type data base file
*/ */
protected void parse(String[] filenames, String options, String dataFilename) { protected void parse(String[] filenames, String includePaths[], String options,
CParserTask parseTask = new CParserTask(this, filenames, options, dataFilename); String languageIDString, String compilerSpecID, String dataFilename) {
CParserTask parseTask = new CParserTask(this, dataFilename)
.setFileNames(filenames)
.setIncludePaths(includePaths)
.setOptions(options)
.setLanguageID(languageIDString)
.setCompilerID(compilerSpecID);
this.getTool().execute(parseTask, 500); this.getTool().execute(parseTask, 500);
} }
/* /*
* Parse C-source into a data type manager * Parse C-source into a data type manager
*/ */
protected void parse(String[] filenames, String options, DataTypeManager dtMgr, protected void parse(String[] filenames, String includePaths[], String options,
String languageIDString, String compilerSpecID, DataTypeManager dtMgr,
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException { ghidra.app.util.cparser.CPP.ParseException {
results = null;
String[] args = parseOptions(options); String[] args = parseOptions(options);
DataTypeManager openDTmanagers[] = null; DataTypeManager openDTmanagers[] = null;
@ -184,100 +183,22 @@ public class CParserPlugin extends ProgramPlugin {
return; // parse canceled return; // parse canceled
} }
cppMessages = "";
PreProcessor cpp = new PreProcessor();
cpp.setArgs(args);
PrintStream os = System.out;
String homeDir = System.getProperty("user.home");
String fName = homeDir + File.separator + "CParserPlugin.out";
try { try {
os = new PrintStream(new FileOutputStream(fName)); results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
} args, dtMgr, languageIDString, compilerSpecID, monitor);
catch (FileNotFoundException e2) {
Msg.error(this, "Unexpected Exception: " + e2.getMessage(), e2);
}
PrintStream old = System.out;
System.setOut(os);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setOutputStream(bos);
cpp.setMonitor(monitor);
try {
for (String filename : filenames) {
if (monitor.isCancelled()) {
break;
}
// any file beginning with a "#" is assumed to be a comment
if (filename.trim().startsWith("#")) {
continue;
}
File file = new File(filename);
if (file.isDirectory()) {
// process each header file in the directory
String[] children = file.list();
if (children == null) {
continue;
}
for (String element : children) {
File child = new File(file.getAbsolutePath() + "/" + element);
if (child.getName().endsWith(".h")) {
parseFile(child.getAbsolutePath(), monitor, cpp);
}
}
}
else {
parseFile(filename, monitor, cpp);
}
}
}
catch (RuntimeException re) {
os.close();
throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
}
// process all the defines and add any that are integer values into
// the Equates table
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
System.out.println(bos.toString());
System.setOut(old);
os.close();
if (!monitor.isCancelled()) {
monitor.setMessage("Parsing C");
CParser cParser = new CParser(dtMgr, true, openDTmanagers);
cParser.setParseFileName(PARSER_DEBUG_OUTFILE);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
try {
parserMessages = "";
cParser.setParseFileName(fName);
cParser.setMonitor(monitor);
cParser.parse(bis);
}
finally {
parserMessages = cParser.getParseMessages();
}
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager); final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager);
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
// CParserTask will show any errors // CParserTask will show any errors
if (!cParser.didParseSucceed()) { if (!results.successful()) {
return; return;
} }
if (isProgramDtMgr) { if (isProgramDtMgr) {
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(), MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
"C-Parse of Header Files Complete", "C-Parse of Header Files Complete",
"Successfully parsed header file(s) to Program.", "Successfully parsed header file(s) to Program.",
getFormattedParseMessage( getFormattedParseMessage("Check the Manage Data Types window for added data types."),
"Check the Manage Data Types window for added data types."),
MultiLineMessageDialog.INFORMATION_MESSAGE); MultiLineMessageDialog.INFORMATION_MESSAGE);
} }
else { else {
@ -286,20 +207,22 @@ public class CParserPlugin extends ProgramPlugin {
archiveName = ((FileDataTypeManager) dtMgr).getFilename(); archiveName = ((FileDataTypeManager) dtMgr).getFilename();
} }
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(), MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
"C-Parse of Header Files Complete. ", "C-Parse of Header Files Complete",
"Successfully parsed header file(s) to Archive File: " + archiveName, "Successfully parsed header file(s) to Archive File: " + archiveName,
getFormattedParseMessage(null), MultiLineMessageDialog.INFORMATION_MESSAGE); getFormattedParseMessage(null),
MultiLineMessageDialog.INFORMATION_MESSAGE);
} }
}); });
} }
catch (IOException e) {
// ignore
}
} }
/** /**
* Get open data type managers. * Get open data type managers.
* User can Use Open managers, Select not to use, or Cancel * User can Use Open managers, Select not to use, or Cancel
* *
* @param openDTmanagers open mgrs, null if don't use
* @return array of open data type managers * @return array of open data type managers
* *
* @throws CancelledException if user cancels * @throws CancelledException if user cancels
@ -335,7 +258,7 @@ public class CParserPlugin extends ProgramPlugin {
"</ul>" + "<p><b>The new archive will become dependent on these archives<br>" + "</ul>" + "<p><b>The new archive will become dependent on these archives<br>" +
"for any datatypes already defined in them </b>(only unique <br>" + "for any datatypes already defined in them </b>(only unique <br>" +
"data types will be added to the new archive).", "data types will be added to the new archive).",
"Use Open Archives?", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE); "Use Open Archives", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE);
if (result == OptionDialog.CANCEL_OPTION) { if (result == OptionDialog.CANCEL_OPTION) {
throw new CancelledException("User Cancelled"); throw new CancelledException("User Cancelled");
} }
@ -346,62 +269,40 @@ public class CParserPlugin extends ProgramPlugin {
return openDTmanagers; return openDTmanagers;
} }
public CParseResults getParseResults() {
return results;
}
public String getParseMessage() {
return (results != null ? results.cParseMessages() : "");
}
public String getFormattedParseMessage(String errMsg) { protected String getFormattedParseMessage(String errMsg) {
String message = ""; String message = "";
if (errMsg != null) { if (errMsg != null) {
message += errMsg + "\n\n"; message += errMsg + "\n\n";
} }
String msg = getParseMessage(); String msg = (results == null ? null : results.cParseMessages());
if (msg != null && msg.length() != 0) { if (msg != null && msg.length() != 0) {
message += "CParser Messages:\n" + msg + "\n\n"; message += "CParser Messages:\n" + msg + "\n\n";
} }
msg = getPreProcessorMessage(); msg = (results == null ? null : results.cppParseMessages());
if (msg != null && msg.length() != 0) { if (msg != null && msg.length() != 0) {
message += "PreProcessor Messages:\n" + getPreProcessorMessage(); message += "PreProcessor Messages:\n" + msg;
} }
return message; return message;
} }
/**
* Get any parse messages produced by parsing good, or informational
*
* @return messages from parser
*/
public String getParseMessage() {
return parserMessages;
}
public String getPreProcessorMessage() {
return cppMessages;
}
private void parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
throws ghidra.app.util.cparser.CPP.ParseException {
monitor.setMessage("PreProcessing " + filename);
try {
Msg.info(this, "parse " + filename);
cpp.parse(filename);
}
catch (Throwable e) {
Msg.error(this, "Parsing file :" + filename);
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
}
finally {
cppMessages += cpp.getParseMessages();
}
}
/* /*
* Parse into the current programs data type manager * Parse into the current programs data type manager
*/ */
protected void parse(String[] filenames, String options) { protected void parse(String[] filenames, String[] includePaths, String options,
String languageIDString, String compilerIDString) {
if (currentProgram == null) { if (currentProgram == null) {
Msg.showInfo(getClass(), parseDialog.getComponent(), "No Open Program", Msg.showInfo(getClass(), parseDialog.getComponent(), "No Open Program",
"A program must be open to \"Parse to Program\""); "A program must be open to \"Parse to Program\"");
@ -413,8 +314,14 @@ public class CParserPlugin extends ProgramPlugin {
if (result == OptionDialog.CANCEL_OPTION) { if (result == OptionDialog.CANCEL_OPTION) {
return; return;
} }
CParserTask parseTask = CParserTask parseTask =
new CParserTask(this, filenames, options, currentProgram.getDataTypeManager()); new CParserTask(this, currentProgram.getDataTypeManager())
.setFileNames(filenames)
.setIncludePaths(includePaths)
.setOptions(options)
.setLanguageID(languageIDString)
.setCompilerID(compilerIDString);
tool.execute(parseTask); tool.execute(parseTask);
} }

View file

@ -20,44 +20,97 @@ import java.io.File;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import docking.widgets.dialogs.MultiLineMessageDialog; import docking.widgets.dialogs.MultiLineMessageDialog;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.*;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.DuplicateFileException; import ghidra.util.exception.DuplicateFileException;
import ghidra.util.task.Task; import ghidra.util.task.Task;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
/** /**
* This is called by the dialog box. * Background task to parse files for cparser plugin
* *
* *
*/ */
class CParserTask extends Task { class CParserTask extends Task {
private String[] filenames;
private String options;
private CParserPlugin plugin; private CParserPlugin plugin;
private String dataFileName; private String dataFileName;
private String[] filenames;
private String[] includePaths;
private String options;
private String languageString;
private String compilerString;
private DataTypeManager dtMgr; private DataTypeManager dtMgr;
CParserTask(CParserPlugin plugin, String[] filenames, String options, String dataFileName) {
/**
* Create task to parse to a dataFile
*
* @param plugin CParserPlugin that will do the work
* @param dataFileName name of the file to parse to
*/
CParserTask(CParserPlugin plugin, String dataFileName) {
super("Parsing C Files", true, false, false); super("Parsing C Files", true, false, false);
this.plugin = plugin; this.plugin = plugin;
this.filenames = filenames;
this.options = options;
this.dataFileName = dataFileName; this.dataFileName = dataFileName;
} }
public CParserTask(CParserPlugin plugin, String[] filenames, String options, /**
DataTypeManager dataTypeManager) { * Create task to parse to a dataTypeManager
*
* @param plugin
* @param dataTypeManager
*/
public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) {
super("Parsing C Files", true, false, false); super("Parsing C Files", true, false, false);
this.plugin = plugin; this.plugin = plugin;
this.filenames = filenames;
this.options = options;
this.dtMgr = dataTypeManager; this.dtMgr = dataTypeManager;
} }
/**
* Create task to parse to a ProgramDataTypeManager
*
* @param plugin
* @param dataTypeManager
*/
public CParserTask(CParserPlugin plugin, ProgramBasedDataTypeManager dataTypeManager) {
super("Parsing C Files", true, false, false);
this.plugin = plugin;
this.dtMgr = dataTypeManager;
}
public CParserTask setLanguageID(String languageID) {
this.languageString = languageID;
return this;
}
public CParserTask setCompilerID(String compilerID) {
this.compilerString = compilerID;
return this;
}
public CParserTask setIncludePaths(String includePaths[]) {
this.includePaths = includePaths.clone();
return this;
}
public CParserTask setFileNames(String names[]) {
this.filenames = names.clone();
return this;
}
public CParserTask setOptions(String options) {
this.options = options;
return this;
}
private String getFirstMessageLine(final String errMsg) { private String getFirstMessageLine(final String errMsg) {
int indexOf = errMsg.indexOf('\n'); int indexOf = errMsg.indexOf('\n');
String msg = errMsg; String msg = errMsg;
@ -77,8 +130,9 @@ class CParserTask extends Task {
fileDtMgr = dtMgr; fileDtMgr = dtMgr;
} }
plugin.parse(filenames, options, dtMgr, monitor); plugin.parse(filenames, includePaths, options, languageString, compilerString, dtMgr, monitor);
if (dataFileName != null) { if (dataFileName != null) {
// TODO: does not consider existing datatypes
if (dtMgr.getDataTypeCount(true) != 0) { if (dtMgr.getDataTypeCount(true) != 0) {
try { try {
((FileDataTypeManager) dtMgr).save(); ((FileDataTypeManager) dtMgr).save();
@ -102,6 +156,10 @@ class CParserTask extends Task {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
// no results, was canceled
if (plugin.getParseResults() == null) {
return;
}
MultiLineMessageDialog.showModalMessageDialog( MultiLineMessageDialog.showModalMessageDialog(
plugin.getDialog().getComponent(), "Parse Errors", plugin.getDialog().getComponent(), "Parse Errors",
"File was not created due to parse errors: " + "File was not created due to parse errors: " +

View file

@ -15,31 +15,44 @@
*/ */
package ghidra.app.plugin.core.cparser; package ghidra.app.plugin.core.cparser;
import java.awt.BorderLayout; import java.awt.*;
import java.awt.Dimension;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.awt.event.ItemListener; import java.awt.event.ItemListener;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.List;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.*; import javax.swing.event.*;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import org.apache.commons.lang3.ObjectUtils;
import docking.*; import docking.*;
import docking.action.*; import docking.action.*;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.button.BrowseButton;
import docking.widgets.combobox.GhidraComboBox; import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.dialogs.InputDialog; import docking.widgets.dialogs.InputDialog;
import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.filechooser.GhidraFileChooserMode;
import docking.widgets.label.GLabel;
import docking.widgets.pathmanager.PathnameTablePanel; import docking.widgets.pathmanager.PathnameTablePanel;
import docking.widgets.table.GTableCellRenderer;
import docking.widgets.table.GTableCellRenderingData;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import generic.theme.GThemeDefaults.Colors.Tables;
import ghidra.app.plugin.core.processors.SetLanguageDialog;
import ghidra.app.util.Option;
import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.exporter.Exporter;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.framework.options.SaveState; import ghidra.framework.options.SaveState;
import ghidra.framework.preferences.Preferences; import ghidra.framework.preferences.Preferences;
import ghidra.framework.store.db.PackedDatabase; import ghidra.framework.store.db.PackedDatabase;
import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.data.FileDataTypeManager;
import ghidra.program.model.lang.CompilerSpecID;
import ghidra.program.model.lang.LanguageID;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.filechooser.ExtensionFileFilter; import ghidra.util.filechooser.ExtensionFileFilter;
@ -75,6 +88,13 @@ class ParseDialog extends ReusableDialogComponentProvider {
private PathnameTablePanel pathPanel; private PathnameTablePanel pathPanel;
private JTextArea parseOptionsField; private JTextArea parseOptionsField;
protected JComponent languagePanel;
protected JTextField languageTextField;
protected JButton languageButton;
protected String languageIDString = null;
protected String compilerIDString = null;
private GhidraComboBox<ComboBoxItem> comboBox; private GhidraComboBox<ComboBoxItem> comboBox;
private DefaultComboBoxModel<ComboBoxItem> comboModel; private DefaultComboBoxModel<ComboBoxItem> comboModel;
private DockingAction saveAction; private DockingAction saveAction;
@ -86,44 +106,75 @@ class ParseDialog extends ReusableDialogComponentProvider {
private TableModelListener tableListener; private TableModelListener tableListener;
private ItemListener comboItemListener; private ItemListener comboItemListener;
private TableModel tableModel; private TableModel tableModel;
private PathnameTablePanel includePathPanel;
private TableModel parsePathTableModel;
private TableModelListener parsePathTableListener;
private ArrayList<ComboBoxItem> itemList; private ArrayList<ComboBoxItem> itemList;
private ComboBoxItemComparator comparator; private ComboBoxItemComparator comparator;
private ResourceFile parentUserFile; private ResourceFile parentUserFile;
private boolean saveAsInProgress; private boolean saveAsInProgress;
private boolean initialBuild = true;
private boolean userDefined = false;
private String currentProfileName = null;
ParseDialog(CParserPlugin plugin) { ParseDialog(CParserPlugin plugin) {
super("Parse C Source", false, true, true, false); super("Parse C Source", false, true, true, false);
this.plugin = plugin; this.plugin = plugin;
itemList = new ArrayList<>();
comparator = new ComboBoxItemComparator();
addWorkPanel(buildMainPanel());
addDismissButton();
createActions();
setActionsEnabled();
} }
public void setupForDisplay() {
if (initialBuild) {
itemList = new ArrayList<>();
comparator = new ComboBoxItemComparator();
addWorkPanel(buildMainPanel());
addDismissButton();
createActions();
setActionsEnabled();
// setup based on save state
if (currentProfileName != null) {
for (int i = 0; i < itemList.size(); i++) {
ComboBoxItem item = itemList.get(i);
if (userDefined == item.isUserDefined && currentProfileName.equals(item.file.getName())) {
comboBox.setSelectedIndex(i);
break;
}
}
}
} else {
toFront();
}
}
void writeState(SaveState saveState) { void writeState(SaveState saveState) {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem(); // Get the current state if the dialog has been displayed
saveState.putString(CURRENT_PROFILE, item.file.getName()); if (!initialBuild) {
saveState.putBoolean(USER_DEFINED, item.isUserDefined); ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
currentProfileName = item.file.getName();
userDefined = item.isUserDefined;
}
saveState.putString(CURRENT_PROFILE, currentProfileName);
saveState.putBoolean(USER_DEFINED, userDefined);
} }
void readState(SaveState saveState) { void readState(SaveState saveState) {
String name = saveState.getString(CURRENT_PROFILE, null); currentProfileName = saveState.getString(CURRENT_PROFILE, null);
if (name != null) { if (currentProfileName != null) {
boolean userDefined = saveState.getBoolean(USER_DEFINED, true); userDefined = saveState.getBoolean(USER_DEFINED, true);
for (int i = 0; i < itemList.size(); i++) {
ComboBoxItem item = itemList.get(i);
if (userDefined == item.isUserDefined && name.equals(item.file.getName())) {
comboBox.setSelectedIndex(i);
break;
}
}
} }
} }
void closeProfile() { void closeProfile() {
// dialog not built yet
if (initialBuild) {
return;
}
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem(); ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
if (item.isChanged) { if (item.isChanged) {
processItemChanged(item); processItemChanged(item);
@ -136,6 +187,8 @@ class ParseDialog extends ReusableDialogComponentProvider {
} }
protected JPanel buildMainPanel() { protected JPanel buildMainPanel() {
initialBuild = true;
mainPanel = new JPanel(new BorderLayout(10, 5)); mainPanel = new JPanel(new BorderLayout(10, 5));
comboModel = new DefaultComboBoxModel<>(); comboModel = new DefaultComboBoxModel<>();
@ -164,14 +217,64 @@ class ParseDialog extends ReusableDialogComponentProvider {
pathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY, pathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY,
GhidraFileChooserMode.FILES_AND_DIRECTORIES, true, GhidraFileChooserMode.FILES_AND_DIRECTORIES, true,
new ExtensionFileFilter(new String[] { "h" }, "C Header Files")); new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
// Set default render to display red if file would not we found
// Using include paths
pathPanel.getTable().setDefaultRenderer(String.class, new GTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
Object value = data.getValue();
String pathName = (String) value;
pathName = (pathName == null ? "" : pathName.trim());
if (pathName.length() == 0 || pathName.startsWith("#")) {
return label;
}
boolean fileExists = true;
File file = new File(pathName);
fileExists = file.exists();
// file not found directly, see if one of the include paths will find the file
if (!fileExists) {
fileExists = doesFileExist(pathName, fileExists);
}
label.setText(pathName.toString());
if (!fileExists) {
label.setForeground(data.isSelected() ? Tables.FG_ERROR_SELECTED
: Tables.FG_ERROR_UNSELECTED);
}
return label;
}
});
tableListener = e -> { tableListener = e -> {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem(); ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
item.isChanged = true; item.isChanged = !initialBuild;
setActionsEnabled(); setActionsEnabled();
}; };
tableModel = pathPanel.getTable().getModel(); tableModel = pathPanel.getTable().getModel();
tableModel.addTableModelListener(tableListener); tableModel.addTableModelListener(tableListener);
includePathPanel = new PathnameTablePanel(null, true, false);
includePathPanel.setBorder(BorderFactory.createTitledBorder("Include paths"));
includePathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY,
GhidraFileChooserMode.FILES_AND_DIRECTORIES, true,
new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
parsePathTableListener = e -> {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
item.isChanged = !initialBuild;
setActionsEnabled();
pathPanel.getTable().repaint();
};
parsePathTableModel = includePathPanel.getTable().getModel();
parsePathTableModel.addTableModelListener(parsePathTableListener);
JPanel optionsPanel = new JPanel(new BorderLayout()); JPanel optionsPanel = new JPanel(new BorderLayout());
optionsPanel.setBorder(BorderFactory.createTitledBorder("Parse Options")); optionsPanel.setBorder(BorderFactory.createTitledBorder("Parse Options"));
@ -182,7 +285,13 @@ class ParseDialog extends ReusableDialogComponentProvider {
JScrollPane pane = new JScrollPane(parseOptionsField); JScrollPane pane = new JScrollPane(parseOptionsField);
pane.getViewport().setPreferredSize(new Dimension(300, 200)); pane.getViewport().setPreferredSize(new Dimension(300, 200));
optionsPanel.add(pane, BorderLayout.CENTER); optionsPanel.add(pane, BorderLayout.CENTER);
JPanel archPanel = new JPanel(new BorderLayout());
archPanel.setBorder(BorderFactory.createTitledBorder("Program Architecture:"));
archPanel.add(new GLabel(" ", SwingConstants.RIGHT));
languagePanel = buildLanguagePanel();
archPanel.add(languagePanel);
// create Parse Button // create Parse Button
parseButton = new JButton("Parse to Program"); parseButton = new JButton("Parse to Program");
@ -195,23 +304,103 @@ class ParseDialog extends ReusableDialogComponentProvider {
parseToFileButton.setToolTipText("Parse files and output to archive file"); parseToFileButton.setToolTipText("Parse files and output to archive file");
addButton(parseToFileButton); addButton(parseToFileButton);
pathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pathPanel, optionsPanel);
splitPane.setResizeWeight(0.50);
mainPanel.add(comboPanel, BorderLayout.NORTH); mainPanel.add(comboPanel, BorderLayout.NORTH);
mainPanel.add(splitPane, BorderLayout.CENTER);
includePathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
JSplitPane optionsPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, includePathPanel, optionsPanel);
optionsPane.setResizeWeight(0.50);
pathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
JSplitPane outerPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pathPanel, optionsPane);
outerPane.setResizeWeight(0.50);
mainPanel.add(outerPane, BorderLayout.CENTER);
mainPanel.add(archPanel, BorderLayout.SOUTH);
setHelpLocation(new HelpLocation(plugin.getName(), "Parse_C_Source")); setHelpLocation(new HelpLocation(plugin.getName(), "Parse_C_Source"));
loadProfile(); loadProfile();
initialBuild = false;
return mainPanel; return mainPanel;
} }
private boolean doesFileExist(String pathName, boolean fileExists) {
String[] includePaths = includePathPanel.getPaths();
for (String path : includePaths) {
File file = CParserUtils.getFile(path, pathName);
if (file == null) {
continue;
}
fileExists = file.exists();
if (fileExists) {
break;
}
}
return fileExists;
}
private JComponent buildLanguagePanel() {
languageTextField = new JTextField();
languageTextField.setEditable(false);
languageTextField.setFocusable(false);
languageButton = new BrowseButton();
languageButton.addActionListener(e -> {
SetLanguageDialog dialog = new SetLanguageDialog(plugin.getTool(), languageIDString, compilerIDString,
"Select Program Architecture for File DataType Archive");
LanguageID languageId = dialog.getLanguageDescriptionID();
CompilerSpecID compilerSpecId = dialog.getCompilerSpecDescriptionID();
if ((languageId == null) || (compilerSpecId == null)) {
return;
}
String newLanguageIDString = languageId.getIdAsString();
String newCompilerIDString = compilerSpecId.getIdAsString();
if (!Objects.equals(newLanguageIDString, languageIDString) ||
!Objects.equals(newCompilerIDString, compilerIDString)) {
itemChanged();
}
languageIDString = newLanguageIDString;
compilerIDString = newCompilerIDString;
updateArchitectureDescription();
});
updateArchitectureDescription();
languageButton.setName("Set Processor Architecture");
Font font = languageButton.getFont();
languageButton.setFont(font.deriveFont(Font.BOLD));
JPanel panel = new JPanel(new BorderLayout());
panel.add(languageTextField, BorderLayout.CENTER);
panel.add(languageButton, BorderLayout.EAST);
return panel;
}
private void updateArchitectureDescription() {
String newProgramArchitectureSummary = "64/32 (primarily for backward compatibility)";
if (languageIDString != null) {
StringBuilder buf = new StringBuilder();
buf.append(languageIDString);
buf.append(" / ");
buf.append(compilerIDString != null ? compilerIDString : "none");
newProgramArchitectureSummary = buf.toString();
}
languageTextField.setText(newProgramArchitectureSummary);
}
private void selectionChanged(ItemEvent e) { private void selectionChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.DESELECTED) { if (e.getStateChange() == ItemEvent.DESELECTED) {
ComboBoxItem item = (ComboBoxItem) e.getItem(); ComboBoxItem item = (ComboBoxItem) e.getItem();
if (item.isChanged && !saveAsInProgress) { if (item.isChanged && !saveAsInProgress && !initialBuild) {
if (item.isUserDefined) { if (item.isUserDefined) {
if (OptionDialog.showOptionDialog(rootPanel, "Save Changes to Profile?", if (OptionDialog.showOptionDialog(rootPanel, "Save Changes to Profile?",
"Profile " + item.file.getName() + "Profile " + item.file.getName() +
@ -256,53 +445,6 @@ class ParseDialog extends ReusableDialogComponentProvider {
} }
} }
private void loadProfile() {
if (docListener != null) {
parseOptionsField.getDocument().removeDocumentListener(docListener);
}
tableModel.removeTableModelListener(tableListener);
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
StringBuffer sb = new StringBuffer();
ArrayList<String> pathList = new ArrayList<>();
try {
BufferedReader br =
new BufferedReader(new InputStreamReader(item.file.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.startsWith("-") || (line.length() == 0 && sb.length() > 0)) {
// this is a compiler directive
sb.append(line + "\n");
}
else if (line.length() > 0) {
File f = new File(line);
pathList.add(f.getPath());
}
}
String[] paths = new String[pathList.size()];
paths = pathList.toArray(paths);
pathPanel.setPaths(paths);
parseOptionsField.setText(sb.toString());
br.close();
}
catch (FileNotFoundException e) {
Msg.showInfo(getClass(), getComponent(), "File Not Found",
"Could not find file\n" + item.file.getAbsolutePath());
}
catch (IOException e) {
Msg.showError(this, getComponent(), "Error Loading Profile",
"Exception occurred while reading file\n" + item.file.getAbsolutePath() + ": " + e);
}
finally {
// add a document listener to the options field
addDocumentListener();
tableModel.addTableModelListener(tableListener);
setActionsEnabled();
}
}
private void addDocumentListener() { private void addDocumentListener() {
if (docListener == null) { if (docListener == null) {
docListener = new DocumentListener() { docListener = new DocumentListener() {
@ -327,6 +469,9 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void itemChanged() { private void itemChanged() {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem(); ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
if (item == null) {
return;
}
item.isChanged = true; item.isChanged = true;
setActionsEnabled(); setActionsEnabled();
} }
@ -466,6 +611,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
} }
file.delete(); file.delete();
} }
saveAsInProgress = true;
ComboBoxItem newItem = new ComboBoxItem(file, true); ComboBoxItem newItem = new ComboBoxItem(file, true);
if (itemList.contains(newItem)) { if (itemList.contains(newItem)) {
itemList.remove(newItem); itemList.remove(newItem);
@ -476,7 +622,6 @@ class ParseDialog extends ReusableDialogComponentProvider {
index = -index - 1; index = -index - 1;
} }
itemList.add(index, newItem); itemList.add(index, newItem);
saveAsInProgress = true;
writeProfile(newItem.file); writeProfile(newItem.file);
newItem.isChanged = false; newItem.isChanged = false;
item.isChanged = false; item.isChanged = false;
@ -491,6 +636,97 @@ class ParseDialog extends ReusableDialogComponentProvider {
} }
} }
private void loadProfile() {
if (docListener != null) {
parseOptionsField.getDocument().removeDocumentListener(docListener);
}
tableModel.removeTableModelListener(tableListener);
parsePathTableModel.removeTableModelListener(parsePathTableListener);
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
item.isChanged = false;
StringBuffer sb = new StringBuffer();
ArrayList<String> pathList = new ArrayList<>();
ArrayList<String> includeList = new ArrayList<>();
String langString = null;
String compileString = null;
try {
BufferedReader br =
new BufferedReader(new InputStreamReader(item.file.getInputStream()));
String line = null;
while ((line = br.readLine()) != null && line.trim().length() > 0) {
line = line.trim();
pathList.add(line);
}
while ((line = br.readLine()) != null && line.trim().length() > 0) {
line = line.trim();
sb.append(line + "\n");
}
// get paths
while ((line = br.readLine()) != null && line.trim().length() > 0) {
line = line.trim();
includeList.add(line);
}
// get language
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.length() > 0) {
langString = (line.length() == 0 ? null : line);
break;
}
}
// get compiler spec
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.length() > 0) {
compileString = (line.length() == 0 ? null : line);
break;
}
}
String[] paths = new String[pathList.size()];
paths = pathList.toArray(paths);
pathPanel.setPaths(paths);
String[] incpaths = new String[includeList.size()];
incpaths = includeList.toArray(incpaths);
includePathPanel.setPaths(incpaths);
parseOptionsField.setText(sb.toString());
languageIDString = langString;
compilerIDString = compileString;
updateArchitectureDescription();
br.close();
}
catch (FileNotFoundException e) {
Msg.showInfo(getClass(), getComponent(), "File Not Found",
"Could not find file\n" + item.file.getAbsolutePath());
}
catch (IOException e) {
Msg.showError(this, getComponent(), "Error Loading Profile",
"Exception occurred while reading file\n" + item.file.getAbsolutePath() + ": " + e);
}
finally {
// add a document listener to the options field
addDocumentListener();
tableModel.addTableModelListener(tableListener);
parsePathTableModel.addTableModelListener(parsePathTableListener);
setActionsEnabled();
}
}
private void writeProfile(ResourceFile outputFile) { private void writeProfile(ResourceFile outputFile) {
// write the pathnames // write the pathnames
try { try {
@ -498,7 +734,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
new BufferedWriter(new OutputStreamWriter(outputFile.getOutputStream())); new BufferedWriter(new OutputStreamWriter(outputFile.getOutputStream()));
String[] paths = pathPanel.getPaths(); String[] paths = pathPanel.getPaths();
for (String path : paths) { for (String path : paths) {
writer.write(path); writer.write(path.trim());
writer.newLine(); writer.newLine();
} }
writer.newLine(); writer.newLine();
@ -510,6 +746,30 @@ class ParseDialog extends ReusableDialogComponentProvider {
writer.write(tok); writer.write(tok);
writer.newLine(); writer.newLine();
} }
writer.newLine();
// Write paths
String [] includePaths = includePathPanel.getPaths();
for (String path : includePaths) {
writer.write(path.trim());
writer.newLine();
}
writer.newLine();
// Write Language ID Spec
if (languageIDString != null) {
writer.write(languageIDString);
}
writer.newLine();
writer.newLine();
// Write Compiler ID Spec
if (compilerIDString != null) {
writer.write(compilerIDString);
}
writer.newLine();
writer.newLine();
writer.close(); writer.close();
} }
catch (IOException e) { catch (IOException e) {
@ -537,6 +797,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void doParse(boolean parseToFile) { private void doParse(boolean parseToFile) {
clearStatusText(); clearStatusText();
String options = getParseOptions(); String options = getParseOptions();
String[] includePaths = includePathPanel.getPaths();
String[] paths = pathPanel.getPaths(); String[] paths = pathPanel.getPaths();
if (paths.length == 0) { if (paths.length == 0) {
@ -547,15 +808,21 @@ class ParseDialog extends ReusableDialogComponentProvider {
paths = expandPaths(paths); paths = expandPaths(paths);
pathPanel.setPaths(paths); pathPanel.setPaths(paths);
if (languageIDString == null || compilerIDString == null ) {
Msg.showWarn(getClass(), rootPanel, "Program Architecture not Specified",
"A Program Architecture must be specified in order to parse to a file.");
return;
}
if (parseToFile) { if (parseToFile) {
File file = getSaveFile(); File file = getSaveFile();
if (file != null) { if (file != null) {
plugin.parse(paths, options, file.getAbsolutePath()); plugin.parse(paths, includePaths, options, languageIDString, compilerIDString, file.getAbsolutePath());
} }
} }
else { else {
plugin.parse(paths, options); plugin.parse(paths, includePaths, options, languageIDString, compilerIDString);
} }
} }
@ -605,7 +872,12 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void addToComboModel(ResourceFile parent, boolean isUserDefined) { private void addToComboModel(ResourceFile parent, boolean isUserDefined) {
ResourceFile[] children = parent.listFiles(); ResourceFile[] children = parent.listFiles();
for (ResourceFile resourceFile : children) { List<ResourceFile> sorted = Arrays.asList(children);
// sort each set of files, system will go first
// User local files second
// new files at the end
Collections.sort(sorted);
for (ResourceFile resourceFile : sorted) {
if (resourceFile.getName().startsWith(".")) { if (resourceFile.getName().startsWith(".")) {
continue; continue;
} }
@ -687,7 +959,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
return parseOptionsField.getText(); return parseOptionsField.getText();
} }
private class ComboBoxItem { class ComboBoxItem {
private ResourceFile file; private ResourceFile file;
private boolean isUserDefined; private boolean isUserDefined;
private boolean isChanged; private boolean isChanged;
@ -745,4 +1017,55 @@ class ParseDialog extends ReusableDialogComponentProvider {
return 1; return 1;
} }
} }
//==================================================================================================
// Methods for Testing
//==================================================================================================
GhidraComboBox<ParseDialog.ComboBoxItem> getParseComboBox() {
return comboBox;
}
PathnameTablePanel getSourceFiles() {
return this.pathPanel;
}
PathnameTablePanel getIncludePaths() {
return this.includePathPanel;
}
JTextArea getParseOptionsTextField() {
return this.parseOptionsField;
}
JButton getLanguageButton() {
return this.languageButton;
}
JTextField getLanguageText() {
return this.languageTextField;
}
JButton getParseButton() {
return this.parseButton;
}
JButton getParseToFileButton() {
return this.parseToFileButton;
}
ArrayList<ComboBoxItem> getProfiles() {
return this.itemList;
}
ComboBoxItem getCurrentItem() {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
return item;
}
ResourceFile getUserProfileParent() {
return parentUserFile;
}
} }

View file

@ -180,6 +180,10 @@ public class DataTypesProvider extends ComponentProviderAdapter {
addLocalAction(new LockArchiveAction(plugin)); // Archive addLocalAction(new LockArchiveAction(plugin)); // Archive
addLocalAction(new UnlockArchiveAction(plugin)); // Archive addLocalAction(new UnlockArchiveAction(plugin)); // Archive
// Arch group
addLocalAction(new SetArchiveArchitectureAction(plugin)); // Archive
addLocalAction(new ClearArchiveArchitectureAction(plugin)); // Archive
// Repository group : version control actions // Repository group : version control actions
addVersionControlActions(); // Archive 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) { public DeleteArchiveAction(DataTypeManagerPlugin plugin) {
super("Delete Archive", plugin.getName()); super("Delete Archive", plugin.getName());
// ACTIONS - auto generated setPopupMenuData(new MenuData(new String[] { "Delete Archive" }, null, "File"));
setPopupMenuData(new MenuData(new String[] { "Delete Archive" }, null, "Edit"));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_DELETE, 0)); 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; return true;
} }
catch (ReadOnlyException e) { 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) { 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" + "Unable to obtain lock for archive: " + archive.getName() + "\n" +
exc.getMessage()); exc.getMessage());
} }
catch (IOException ioe) { catch (IOException ioe) {
Msg.showError(log, null, "Unable to Lock File for Writing", Throwable cause = ioe.getCause();
"Problem attempting to lock archive: " + archive.getName() + "\n" + if (cause == null) {
ioe.getMessage()); 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; return false;
} }

View file

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

View file

@ -437,12 +437,13 @@ public class DataTypeManagerHandler {
return openArchive(new ResourceFile(file), acquireWriteLock, isUserAction); 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 { throws IOException, DuplicateIdException {
file = file.getCanonicalFile(); file = file.getCanonicalFile();
Archive archive = getArchiveForFile(file); FileArchive archive = getArchiveForFile(file);
if (archive == null) { if (archive == null) {
archive = new FileArchive(this, file, acquireWriteLock); archive = new FileArchive(this, file, acquireWriteLock);
Archive existingArchive = Archive existingArchive =
@ -451,11 +452,10 @@ public class DataTypeManagerHandler {
archive.close(); archive.close();
throw new DuplicateIdException(archive.getName(), existingArchive.getName()); throw new DuplicateIdException(archive.getName(), existingArchive.getName());
} }
addArchivePath(file); addArchivePath(file);
addArchive(archive); addArchive(archive);
} }
if (isUserAction && (archive instanceof FileArchive)) { if (isUserAction) {
userOpenedFileArchiveNames.add(getSaveableArchive(file.getAbsolutePath())); userOpenedFileArchiveNames.add(getSaveableArchive(file.getAbsolutePath()));
} }
return archive; return archive;
@ -524,7 +524,7 @@ public class DataTypeManagerHandler {
return null; return null;
} }
private Archive getArchiveForFile(ResourceFile file) { private FileArchive getArchiveForFile(ResourceFile file) {
for (Archive archive : openArchives) { for (Archive archive : openArchives) {
if (archive instanceof FileArchive) { if (archive instanceof FileArchive) {
FileArchive fileArchive = (FileArchive) archive; FileArchive fileArchive = (FileArchive) archive;
@ -1230,6 +1230,13 @@ public class DataTypeManagerHandler {
listener.sourceArchiveChanged(dataTypeManager, dataTypeSource); 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 * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 DomainFile getDomainFile();
public abstract DomainObject getDomainObject(); public abstract DomainObject getDomainObject();
public abstract boolean hasExclusiveAccess();
} }

View file

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

View file

@ -93,6 +93,11 @@ public class ProgramArchive implements DomainFileArchive {
// Can't directly close the program archive. Instead you must close the Program. // Can't directly close the program archive. Instead you must close the Program.
} }
@Override
public boolean hasExclusiveAccess() {
return program.hasExclusiveAccess();
}
@Override @Override
public boolean isChanged() { public boolean isChanged() {
return false; return false;

View file

@ -87,6 +87,10 @@ public class ProjectArchive implements DomainFileArchive {
return Objects.equals(originalDomainFile.getFileID(), other.originalDomainFile.getFileID()); return Objects.equals(originalDomainFile.getFileID(), other.originalDomainFile.getFileID());
} }
public boolean hasExclusiveAccess() {
return dataTypeArchive.hasExclusiveAccess();
}
@Override @Override
public boolean isModifiable() { public boolean isModifiable() {
DomainFile domainFile = getDomainObject().getDomainFile(); DomainFile domainFile = getDomainObject().getDomainFile();
@ -213,5 +217,10 @@ public class ProjectArchive implements DomainFileArchive {
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) { public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
fireStateChanged(); fireStateChanged();
} }
@Override
public void programArchitectureChanged(DataTypeManager dtm) {
fireStateChanged();
}
} }
} }

View file

@ -15,8 +15,7 @@
*/ */
package ghidra.app.plugin.core.datamgr.editor; package ghidra.app.plugin.core.datamgr.editor;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import docking.ComponentProvider; import docking.ComponentProvider;
import docking.actions.DockingToolActions; import docking.actions.DockingToolActions;
@ -28,11 +27,9 @@ import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
import ghidra.program.model.listing.FunctionSignature; import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Program;
import ghidra.util.*; import ghidra.util.*;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.*;
import ghidra.util.exception.DuplicateNameException;
/** /**
* Manages program and archive data type editors. * 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. * Use of this editor requires the presence of the tool-based datatype manager service.
*/ */
private class DTMEditFunctionSignatureDialog extends AbstractEditFunctionSignatureDialog { private class DTMEditFunctionSignatureDialog extends AbstractEditFunctionSignatureDialog {
private final FunctionDefinition functionDefinition; private final FunctionDefinition functionDefinition; // may be null
private final FunctionSignature oldSignature; private final FunctionSignature oldSignature;
private final Category category; 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, DTMEditFunctionSignatureDialog(PluginTool pluginTool, String title, Category category,
FunctionDefinition functionDefinition) { FunctionDefinition functionDefinition) {
super(pluginTool, title, false, false, false); super(pluginTool, title, false, true, false);
this.functionDefinition = functionDefinition; this.functionDefinition = functionDefinition;
this.category = category; this.category = category;
this.oldSignature = buildSignature(); 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() { private FunctionSignature buildSignature() {
if (functionDefinition != null) { if (functionDefinition != null) {
if (category.getDataTypeManager() != functionDefinition.getDataTypeManager()) { if (category.getDataTypeManager() != functionDefinition.getDataTypeManager()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"functionDefinition and category must have same Datatypemanager"); "FunctionDefinition and Category must have same DataTypeManager");
} }
return functionDefinition; return functionDefinition;
} }
return new FunctionDefinitionDataType("newFunction"); return new FunctionDefinitionDataType("newFunction", category.getDataTypeManager());
}
@Override
protected boolean hasNoReturn() {
return functionDefinition != null ? functionDefinition.hasNoReturn() : false;
} }
@Override @Override
@ -586,17 +609,21 @@ public class DataTypeEditorManager
@Override @Override
protected String getCallingConventionName() { protected String getCallingConventionName() {
return getFunctionSignature().getGenericCallingConvention().toString(); return getFunctionSignature().getCallingConventionName();
} }
@Override @Override
protected List<String> getCallingConventionNames() { protected List<String> getCallingConventionNames() {
GenericCallingConvention[] values = GenericCallingConvention.values(); // can't rely on functionDefinition which may be null for new definition
List<String> choices = new ArrayList<>(); DataTypeManager dtMgr = getDataTypeManager();
for (GenericCallingConvention value : values) { if (dtMgr instanceof CompositeViewerDataTypeManager) {
choices.add(value.toString()); 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 @Override
@ -620,36 +647,53 @@ public class DataTypeEditorManager
return false; return false;
} }
GenericCallingConvention callingConvention = String callingConvention = getCallingConvention();
GenericCallingConvention.getGenericCallingConvention(getCallingConvention()); boolean hasNoReturn = hasNoReturnSelected();
newDefinition.setGenericCallingConvention(callingConvention); try {
newDefinition.setCallingConvention(callingConvention);
newDefinition.setNoReturn(hasNoReturn);
DataTypeManager manager = getDataTypeManager(); DataTypeManager manager = getDataTypeManager();
SourceArchive sourceArchive = manager.getLocalSourceArchive(); SourceArchive sourceArchive = manager.getLocalSourceArchive();
if (functionDefinition == null) { if (functionDefinition == null) {
newDefinition.setSourceArchive(sourceArchive); newDefinition.setSourceArchive(sourceArchive);
newDefinition.setCategoryPath(category.getCategoryPath()); newDefinition.setCategoryPath(category.getCategoryPath());
int id = manager.startTransaction("Create Function Definition"); int id = manager.startTransaction("Create Function Definition");
manager.addDataType(newDefinition, DataTypeConflictHandler.REPLACE_HANDLER); try {
manager.endTransaction(id, true); manager.addDataType(newDefinition, DataTypeConflictHandler.REPLACE_HANDLER);
} }
else { finally {
int id = manager.startTransaction("Edit Function Definition"); manager.endTransaction(id, true);
try {
if (!functionDefinition.getName().equals(newDefinition.getName())) {
functionDefinition.setName(newDefinition.getName());
} }
functionDefinition.setArguments(newDefinition.getArguments());
functionDefinition.setGenericCallingConvention(
newDefinition.getGenericCallingConvention());
functionDefinition.setReturnType(newDefinition.getReturnType());
functionDefinition.setVarArgs(newDefinition.hasVarArgs());
} }
catch (InvalidNameException | DuplicateNameException e) { else {
// not sure why we are squashing this? ...assuming this can't happen int id = manager.startTransaction("Edit Function Definition");
Msg.error(this, "Unexpected Exception", e); 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; return true;

View file

@ -21,12 +21,17 @@ import javax.swing.Icon;
import docking.widgets.tree.GTree; import docking.widgets.tree.GTree;
import docking.widgets.tree.GTreeNode; import docking.widgets.tree.GTreeNode;
import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.plugin.core.datamgr.archive.Archive; import ghidra.app.plugin.core.datamgr.archive.Archive;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.HTMLUtilities;
import ghidra.util.task.SwingUpdateManager; import ghidra.util.task.SwingUpdateManager;
public class ArchiveNode extends CategoryNode { public class ArchiveNode extends CategoryNode {
protected static final String DEFAULT_DATA_ORG_DESCRIPTION =
"[Using Default Data Organization]";
protected Archive archive; protected Archive archive;
protected ArchiveNodeCategoryChangeListener listener; protected ArchiveNodeCategoryChangeListener listener;
private DataTypeManager dataTypeManager; // may be null private DataTypeManager dataTypeManager; // may be null
@ -45,6 +50,43 @@ public class ArchiveNode extends CategoryNode {
this.archive = archive; 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() { protected void archiveStateChanged() {
nodeChanged(); nodeChanged();
} }
@ -172,11 +214,11 @@ public class ArchiveNode extends CategoryNode {
return -1; // All ArchiveNodes are before any other types of nodes 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 * 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. * archive. This must be consistent with the equals method implementation.
*/ */
@Override
public int hashCode() { public int hashCode() {
return getArchive().hashCode(); return getArchive().hashCode();
} }
@ -424,5 +466,13 @@ public class ArchiveNode extends CategoryNode {
public void sourceArchiveChanged(DataTypeManager manager, SourceArchive sourceArchive) { public void sourceArchiveChanged(DataTypeManager manager, SourceArchive sourceArchive) {
nodeChangedUpdater.update(); 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 javax.swing.Icon;
import ghidra.app.plugin.core.datamgr.archive.BuiltInArchive; import ghidra.app.plugin.core.datamgr.archive.BuiltInArchive;
import ghidra.util.HTMLUtilities;
import resources.MultiIcon; import resources.MultiIcon;
public class BuiltInArchiveNode extends ArchiveNode { public class BuiltInArchiveNode extends ArchiveNode {
@ -35,7 +36,13 @@ public class BuiltInArchiveNode extends ArchiveNode {
@Override @Override
public String getToolTip() { 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.DomainFile;
import ghidra.framework.model.DomainObject; import ghidra.framework.model.DomainObject;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.HTMLUtilities;
import resources.MultiIcon; import resources.MultiIcon;
import resources.icons.TranslateIcon; import resources.icons.TranslateIcon;
public class DomainFileArchiveNode extends ArchiveNode { public abstract class DomainFileArchiveNode extends ArchiveNode {
//@formatter:off //@formatter:off
private static Icon CHECKED_OUT_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out"); 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 @Override
public String getToolTip() { public abstract String getToolTip();
DomainFile file = ((DomainFileArchive) archive).getDomainFile();
if (file != null) {
return "<html>" + HTMLUtilities.escapeHTML(file.getPathname());
}
return "[Unsaved New Domain File Archive]";
}
@Override @Override
public boolean canDelete() { public boolean canDelete() {
@ -120,7 +113,7 @@ public class DomainFileArchiveNode extends ArchiveNode {
multiIcon.addIcon(baseIcon); multiIcon.addIcon(baseIcon);
if (isReadOnly) { if (isReadOnly) {
multiIcon.addIcon(new TranslateIcon(READ_ONLY_ICON, 6, 6)); multiIcon.addIcon(new TranslateIcon(READ_ONLY_ICON, 14, 3));
} }
else if (isHijacked) { else if (isHijacked) {
multiIcon.addIcon(new TranslateIcon(HIJACKED_ICON, 8, -4)); multiIcon.addIcon(new TranslateIcon(HIJACKED_ICON, 8, -4));
@ -137,6 +130,8 @@ public class DomainFileArchiveNode extends ArchiveNode {
} }
} }
// TODO: add program architecture state
return multiIcon; return multiIcon;
} }

View file

@ -20,7 +20,6 @@ import javax.swing.Icon;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import generic.theme.GIcon; import generic.theme.GIcon;
import ghidra.app.plugin.core.datamgr.archive.FileArchive; import ghidra.app.plugin.core.datamgr.archive.FileArchive;
import ghidra.util.HTMLUtilities;
import resources.MultiIcon; import resources.MultiIcon;
import resources.icons.TranslateIcon; import resources.icons.TranslateIcon;
@ -46,16 +45,16 @@ public class FileArchiveNode extends ArchiveNode {
if (hasWriteLock) { if (hasWriteLock) {
multiIcon.addIcon(new TranslateIcon(CHECKED_OUT_EXCLUSIVE_ICON, 8, -4)); multiIcon.addIcon(new TranslateIcon(CHECKED_OUT_EXCLUSIVE_ICON, 8, -4));
} }
// TODO: add program architecture state
return multiIcon; return multiIcon;
} }
@Override @Override
public String getToolTip() { public String getToolTip() {
ResourceFile file = fileArchive.getFile(); ResourceFile file = fileArchive.getFile();
if (file != null) { return buildTooltip(file != null ? file.getAbsolutePath() : "[Unsaved New Archive]");
return "<html>" + HTMLUtilities.escapeHTML(file.getAbsolutePath());
}
return "[Unsaved New Archive]";
} }
public boolean hasWriteLock() { 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.app.plugin.core.datamgr.archive.ProgramArchive;
import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFile;
import ghidra.program.model.data.DataTypeManager;
import ghidra.util.HTMLUtilities; import ghidra.util.HTMLUtilities;
public class ProgramArchiveNode extends DomainFileArchiveNode { public class ProgramArchiveNode extends DomainFileArchiveNode {
@ -27,10 +28,19 @@ public class ProgramArchiveNode extends DomainFileArchiveNode {
@Override @Override
public String getToolTip() { public String getToolTip() {
DataTypeManager dtm = archive.getDataTypeManager();
DomainFile file = ((ProgramArchive) archive).getDomainFile(); DomainFile file = ((ProgramArchive) archive).getDomainFile();
StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
if (file != null) { 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.app.plugin.core.datamgr.archive.ProjectArchive;
import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFile;
import ghidra.util.HTMLUtilities;
public class ProjectArchiveNode extends DomainFileArchiveNode { public class ProjectArchiveNode extends DomainFileArchiveNode {
@ -35,10 +34,7 @@ public class ProjectArchiveNode extends DomainFileArchiveNode {
@Override @Override
public String getToolTip() { public String getToolTip() {
DomainFile file = ((ProjectArchive) archive).getDomainFile(); DomainFile file = ((ProjectArchive) archive).getDomainFile();
if (file != null) { return buildTooltip(file != null ? file.getPathname() : "[Unsaved New Project Archive]");
return "<html>" + HTMLUtilities.escapeHTML(file.getPathname());
}
return "[Unsaved New Project Archive]";
} }
public boolean hasWriteLock() { public boolean hasWriteLock() {

View file

@ -361,6 +361,7 @@ public class DataTypeTreeCopyMoveTask extends Task {
DataTypeManager dtm = toCategory.getDataTypeManager(); DataTypeManager dtm = toCategory.getDataTypeManager();
DataTypeManager nodeDtm = dataType.getDataTypeManager(); DataTypeManager nodeDtm = dataType.getDataTypeManager();
boolean sameManager = (dtm == nodeDtm); boolean sameManager = (dtm == nodeDtm);
DataType newDt = !sameManager ? dataType.clone(nodeDtm) : dataType.copy(nodeDtm); DataType newDt = !sameManager ? dataType.clone(nodeDtm) : dataType.copy(nodeDtm);
if (!sameManager && toCategory.isRoot()) { if (!sameManager && toCategory.isRoot()) {

View file

@ -24,7 +24,6 @@ import javax.swing.Icon;
import generic.theme.GColor; import generic.theme.GColor;
import generic.theme.GIcon; import generic.theme.GIcon;
import ghidra.app.services.DataTypeQueryService; import ghidra.app.services.DataTypeQueryService;
import ghidra.program.database.data.ProjectDataTypeManager;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
import ghidra.util.Msg; 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" + msg = "The archive file is not modifiable!\nYou must open the archive for editing\n" +
"before performing this operation.\n" + dtm.getName(); "before performing this operation.\n" + dtm.getName();
} }
else if (dtm instanceof ProjectDataTypeManager) { else if (dtm instanceof ProjectArchiveBasedDataTypeManager) {
ProjectDataTypeManager projectDtm = (ProjectDataTypeManager) dtm; ProjectArchiveBasedDataTypeManager projectDtm =
(ProjectArchiveBasedDataTypeManager) dtm;
if (!projectDtm.isUpdatable() && !projectDtm.getDomainFile().canCheckout()) { if (!projectDtm.isUpdatable() && !projectDtm.getDomainFile().canCheckout()) {
msg = "The project archive is not modifiable!\n" + dtm.getName(); 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.Component;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.util.List; import java.util.List;
import java.util.Objects;
import javax.swing.*; import javax.swing.*;
@ -32,6 +33,7 @@ import ghidra.app.util.parser.FunctionSignatureParser;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FunctionDefinitionDataType; import ghidra.program.model.data.FunctionDefinitionDataType;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature; import ghidra.program.model.listing.FunctionSignature;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@ -110,7 +112,7 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
protected abstract String getPrototypeString(); protected abstract String getPrototypeString();
/** /**
* @return initial calling convention name * @return initial calling convention name or null for unknown
*/ */
protected abstract String getCallingConventionName(); protected abstract String getCallingConventionName();
@ -282,17 +284,33 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
} }
private void setCallingConventionChoices() { private void setCallingConventionChoices() {
String callingConventionName = getCallingConventionName();
callingConventionComboBox.removeAllItems(); callingConventionComboBox.removeAllItems();
for (String element : getCallingConventionNames()) { for (String element : getCallingConventionNames()) {
if (element.equals(callingConventionName)) {
callingConventionName = null;
}
callingConventionComboBox.addItem(element); 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() { protected final String getCallingConvention() {
return (String) callingConventionComboBox.getSelectedItem(); 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( FunctionSignatureParser parser = new FunctionSignatureParser(
getDataTypeManager(), tool.getService(DataTypeManagerService.class)); getDataTypeManager(), tool.getService(DataTypeManagerService.class));
try { try {
// FIXME: Parser returns FunctionDefinition which only supports GenericCallingConventions
return parser.parse(getFunctionSignature(), getSignature()); return parser.parse(getFunctionSignature(), getSignature());
} }
catch (ParseException e) { catch (ParseException e) {
@ -402,22 +419,7 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
*/ */
protected final boolean isCallingConventionChanged() { protected final boolean isCallingConventionChanged() {
String current = getCallingConventionName(); String current = getCallingConventionName();
if (current == null && this.getCallingConvention() == null) { return !Objects.equals(current, getCallingConvention());
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;
} }
@Override @Override

View file

@ -15,6 +15,7 @@
*/ */
package ghidra.app.plugin.core.function; package ghidra.app.plugin.core.function;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd; import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
@ -77,7 +78,11 @@ public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDi
@Override @Override
protected List<String> getCallingConventionNames() { 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 @Override
@ -182,12 +187,6 @@ public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDi
public boolean applyTo(DomainObject obj) { public boolean applyTo(DomainObject obj) {
try { try {
String conventionName = getCallingConvention(); String conventionName = getCallingConvention();
if ("unknown".equals(conventionName)) {
conventionName = null;
}
else if ("default".equals(conventionName)) {
conventionName = function.getDefaultCallingConventionName();
}
function.setCallingConvention(conventionName); function.setCallingConvention(conventionName);
return true; return true;
} }

View file

@ -124,15 +124,24 @@ public class FunctionEditorModel {
return false; return false;
} }
public List<String> getCallingConventionNames() { List<String> getCallingConventionNames() {
return functionManager.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(); return program.getCompilerSpec().getPcodeInjectLibrary().getCallFixupNames();
} }
public void setName(String name) { void setName(String name) {
if (this.name.equals(name)) { if (this.name.equals(name)) {
return; return;
} }
@ -147,20 +156,20 @@ public class FunctionEditorModel {
notifyDataChanged(); notifyDataChanged();
} }
public String getCallingConventionName() { String getCallingConventionName() {
return callingConventionName; return callingConventionName;
} }
public void setHasVarArgs(boolean b) { void setHasVarArgs(boolean b) {
hasVarArgs = b; hasVarArgs = b;
notifyDataChanged(); notifyDataChanged();
} }
public String getName() { String getName() {
return name; return name;
} }
public void dispose() { void dispose() {
listener = new ModelChangeListener() { listener = new ModelChangeListener() {
@Override @Override
public void tableRowsChanged() { public void tableRowsChanged() {
@ -316,7 +325,7 @@ public class FunctionEditorModel {
return true; return true;
} }
public boolean hasValidName() { boolean hasValidName() {
if (name.length() == 0) { if (name.length() == 0) {
statusText = "Missing function name"; statusText = "Missing function name";
return false; return false;
@ -381,11 +390,11 @@ public class FunctionEditorModel {
return true; return true;
} }
public boolean isValid() { boolean isValid() {
return isValid; return isValid;
} }
public String getFunctionSignatureTextFromModel() { String getFunctionSignatureTextFromModel() {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append(returnInfo.getFormalDataType().getName()).append(" "); buf.append(returnInfo.getFormalDataType().getName()).append(" ");
buf.append(getNameString()); buf.append(getNameString());
@ -420,7 +429,7 @@ public class FunctionEditorModel {
return buf.toString(); return buf.toString();
} }
public String getNameString() { String getNameString() {
return name.length() == 0 ? "?" : name; return name.length() == 0 ? "?" : name;
} }
@ -428,15 +437,15 @@ public class FunctionEditorModel {
return param.getName(); return param.getName();
} }
public boolean hasVarArgs() { boolean hasVarArgs() {
return hasVarArgs; return hasVarArgs;
} }
public DataType getReturnType() { DataType getReturnType() {
return returnInfo.getDataType(); return returnInfo.getDataType();
} }
public DataType getFormalReturnType() { DataType getFormalReturnType() {
return returnInfo.getFormalDataType(); return returnInfo.getFormalDataType();
} }
@ -444,14 +453,14 @@ public class FunctionEditorModel {
return setParameterFormalDataType(returnInfo, formalReturnType); return setParameterFormalDataType(returnInfo, formalReturnType);
} }
public String getStatusText() { String getStatusText() {
if (isInParsingMode) { if (isInParsingMode) {
return PARSING_MODE_STATUS_TEXT; return PARSING_MODE_STATUS_TEXT;
} }
return statusText; return statusText;
} }
public void setIsInLine(boolean isInLine) { void setIsInLine(boolean isInLine) {
if (isInLine == this.isInLine) { if (isInLine == this.isInLine) {
return; return;
} }
@ -462,12 +471,12 @@ public class FunctionEditorModel {
notifyDataChanged(); notifyDataChanged();
} }
public void setNoReturn(boolean isNoReturn) { void setNoReturn(boolean isNoReturn) {
this.isNoReturn = isNoReturn; this.isNoReturn = isNoReturn;
notifyDataChanged(); notifyDataChanged();
} }
public boolean isInlineAllowed() { boolean isInlineAllowed() {
return !getAffectiveFunction().isExternal(); return !getAffectiveFunction().isExternal();
} }
@ -481,19 +490,19 @@ public class FunctionEditorModel {
return function.isThunk() ? function.getThunkedFunction(true) : function; return function.isThunk() ? function.getThunkedFunction(true) : function;
} }
public boolean isInLine() { boolean isInLine() {
return isInLine; return isInLine;
} }
public boolean isNoReturn() { boolean isNoReturn() {
return isNoReturn; return isNoReturn;
} }
public String getCallFixupName() { String getCallFixupName() {
return callFixupName; return callFixupName;
} }
public void setCallFixupName(String callFixupName) { void setCallFixupName(String callFixupName) {
if (callFixupName.equals(this.callFixupName)) { if (callFixupName.equals(this.callFixupName)) {
return; return;
} }
@ -555,11 +564,11 @@ public class FunctionEditorModel {
} }
} }
public int[] getSelectedParameterRows() { int[] getSelectedParameterRows() {
return selectedFunctionRows; return selectedFunctionRows;
} }
public void addParameter() { void addParameter() {
if (listener != null) { if (listener != null) {
listener.tableRowsChanged(); listener.tableRowsChanged();
} }
@ -700,7 +709,7 @@ public class FunctionEditorModel {
notifyDataChanged(); notifyDataChanged();
} }
public void moveSelectedParameterUp() { void moveSelectedParameterUp() {
if (!canMoveParameterUp()) { if (!canMoveParameterUp()) {
throw new AssertException("Attempted to move parameters up when not allowed."); throw new AssertException("Attempted to move parameters up when not allowed.");
} }
@ -716,7 +725,7 @@ public class FunctionEditorModel {
notifyDataChanged(); notifyDataChanged();
} }
public void moveSelectedParameterDown() { void moveSelectedParameterDown() {
if (!canMoveParameterDown()) { if (!canMoveParameterDown()) {
throw new AssertException("Attempted to move parameters down when not allowed."); throw new AssertException("Attempted to move parameters down when not allowed.");
} }
@ -736,7 +745,7 @@ public class FunctionEditorModel {
return parameters; return parameters;
} }
public boolean canRemoveParameters() { boolean canRemoveParameters() {
if (selectedFunctionRows.length == 0) { if (selectedFunctionRows.length == 0) {
return false; return false;
} }
@ -748,7 +757,7 @@ public class FunctionEditorModel {
return true; return true;
} }
public boolean canMoveParameterUp() { boolean canMoveParameterUp() {
// remember first row (return type) and auto-params cannot be moved. // remember first row (return type) and auto-params cannot be moved.
int minRowToMoveUp = 2 + autoParamCount; int minRowToMoveUp = 2 + autoParamCount;
if (parameters.size() > 0 && parameters.get(0).getName().equals("this")) { if (parameters.size() > 0 && parameters.get(0).getName().equals("this")) {
@ -757,7 +766,7 @@ public class FunctionEditorModel {
return selectedFunctionRows.length == 1 && selectedFunctionRows[0] >= minRowToMoveUp; return selectedFunctionRows.length == 1 && selectedFunctionRows[0] >= minRowToMoveUp;
} }
public boolean canMoveParameterDown() { boolean canMoveParameterDown() {
if (selectedFunctionRows.length != 1) { if (selectedFunctionRows.length != 1) {
return false; return false;
} }
@ -770,12 +779,12 @@ public class FunctionEditorModel {
return selectedRow >= minRowToMoveDown && selectedRow < parameters.size(); return selectedRow >= minRowToMoveDown && selectedRow < parameters.size();
} }
public void setParameterName(ParamInfo param, String newName) { void setParameterName(ParamInfo param, String newName) {
param.setName(newName); param.setName(newName);
notifyDataChanged(); notifyDataChanged();
} }
public boolean setParameterFormalDataType(ParamInfo param, DataType formalDataType) { boolean setParameterFormalDataType(ParamInfo param, DataType formalDataType) {
boolean isReturn = (param.getOrdinal() == Parameter.RETURN_ORIDINAL); boolean isReturn = (param.getOrdinal() == Parameter.RETURN_ORIDINAL);
try { try {
formalDataType = VariableUtilities.checkDataType(formalDataType, isReturn, 0, program); formalDataType = VariableUtilities.checkDataType(formalDataType, isReturn, 0, program);
@ -839,11 +848,11 @@ public class FunctionEditorModel {
} }
} }
public VariableStorage getReturnStorage() { VariableStorage getReturnStorage() {
return returnInfo.getStorage(); return returnInfo.getStorage();
} }
public Function getFunction() { Function getFunction() {
return function; return function;
} }
@ -940,7 +949,7 @@ public class FunctionEditorModel {
return allowCustomStorage; return allowCustomStorage;
} }
public boolean apply() { boolean apply() {
if (!modelChanged) { if (!modelChanged) {
return true; return true;
} }
@ -1085,16 +1094,10 @@ public class FunctionEditorModel {
} }
public void setFunctionData(FunctionDefinitionDataType functionDefinition) { public void setFunctionData(FunctionDefinitionDataType functionDefinition) {
name = functionDefinition.getName(); name = functionDefinition.getName();
GenericCallingConvention genericCallingConvention = setCallingConventionName(functionDefinition.getCallingConventionName());
functionDefinition.getGenericCallingConvention();
if (genericCallingConvention != null &&
genericCallingConvention != GenericCallingConvention.unknown) {
PrototypeModel matchConvention =
function.getProgram().getCompilerSpec().matchConvention(genericCallingConvention);
setCallingConventionName(matchConvention.getName());
}
if (!isSameSize(returnInfo.getFormalDataType(), functionDefinition.getReturnType())) { if (!isSameSize(returnInfo.getFormalDataType(), functionDefinition.getReturnType())) {
returnInfo.setStorage(VariableStorage.UNASSIGNED_STORAGE); returnInfo.setStorage(VariableStorage.UNASSIGNED_STORAGE);
@ -1110,6 +1113,7 @@ public class FunctionEditorModel {
parameters.add(new ParamInfo(this, paramDefinition)); parameters.add(new ParamInfo(this, paramDefinition));
} }
hasVarArgs = functionDefinition.hasVarArgs(); hasVarArgs = functionDefinition.hasVarArgs();
fixupOrdinals(); fixupOrdinals();
if (allowCustomStorage) { if (allowCustomStorage) {
@ -1162,11 +1166,11 @@ public class FunctionEditorModel {
return null; return null;
} }
public boolean isInParsingMode() { boolean isInParsingMode() {
return isInParsingMode; return isInParsingMode;
} }
public void setSignatureFieldText(String text) { void setSignatureFieldText(String text) {
signatureFieldText = text; signatureFieldText = text;
boolean signatureTextFieldInSync = boolean signatureTextFieldInSync =
signatureFieldText.equals(getFunctionSignatureTextFromModel()); signatureFieldText.equals(getFunctionSignatureTextFromModel());
@ -1177,24 +1181,32 @@ public class FunctionEditorModel {
} }
} }
public void resetSignatureTextField() { void resetSignatureTextField() {
setSignatureFieldText(getFunctionSignatureTextFromModel()); setSignatureFieldText(getFunctionSignatureTextFromModel());
} }
public boolean hasChanges() { boolean hasChanges() {
return !Objects.equals(getFunctionSignatureTextFromModel(), signatureFieldText); return !Objects.equals(getFunctionSignatureTextFromModel(), signatureFieldText);
} }
public void parseSignatureFieldText() throws ParseException, CancelledException { void parseSignatureFieldText() throws ParseException, CancelledException {
FunctionSignatureParser parser = FunctionSignatureParser parser =
new FunctionSignatureParser(program.getDataTypeManager(), dataTypeManagerService); new FunctionSignatureParser(program.getDataTypeManager(), dataTypeManagerService);
FunctionDefinitionDataType f = parser.parse(getFunctionSignature(), signatureFieldText); 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); setFunctionData(f);
isInParsingMode = false; isInParsingMode = false;
} }
public int getFunctionNameStartPosition() { int getFunctionNameStartPosition() {
return returnInfo.getFormalDataType().getName().length() + 1; return returnInfo.getFormalDataType().getName().length() + 1;
} }

View file

@ -221,7 +221,8 @@ public final class LanguageProviderPlugin extends Plugin implements ApplicationL
Program program = (Program) dobj; Program program = (Program) dobj;
monitor.setMessage("Identify Language..."); 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(); LanguageID langDescID = dialog.getLanguageDescriptionID();
CompilerSpecID compilerSpecDescID = dialog.getCompilerSpecDescriptionID(); CompilerSpecID compilerSpecDescID = dialog.getCompilerSpecDescriptionID();
if ((langDescID == null) || (compilerSpecDescID == null)) { 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.LcsSelectionListener;
import ghidra.plugin.importer.NewLanguagePanel; import ghidra.plugin.importer.NewLanguagePanel;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Program;
import ghidra.program.util.DefaultLanguageService; import ghidra.program.util.DefaultLanguageService;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.Msg;
public class SetLanguageDialog extends DialogComponentProvider { public class SetLanguageDialog extends DialogComponentProvider {
private NewLanguagePanel selectLangPanel; private NewLanguagePanel selectLangPanel;
private LanguageService langService;
private PluginTool tool; private PluginTool tool;
private Program currProgram; private LanguageCompilerSpecPair currentLCSPair;
private LanguageID dialogLanguageDescID; private LanguageID dialogLanguageID;
private CompilerSpecID dialogCompilerSpecDescID; private CompilerSpecID dialogCompilerSpecID;
LcsSelectionListener listener = e -> { LcsSelectionListener listener = e -> {
LanguageID langID = null; LanguageID langID = null;
CompilerSpecID compilerSpecID = null; CompilerSpecID compilerSpecID = null;
if (e.selection != null) { if (e != null && e.selection != null) {
langID = e.selection.languageID; langID = e.selection.languageID;
compilerSpecID = e.selection.compilerSpecID; compilerSpecID = e.selection.compilerSpecID;
} }
if ((langID != null) && (langID.equals(currProgram.getLanguageID()))) { if ((currentLCSPair != null) && (langID != null) &&
if ((compilerSpecID != null) && (langID.equals(currentLCSPair.getLanguageID()))) {
(compilerSpecID.equals(currProgram.getCompilerSpec().getCompilerSpecID()))) { if (compilerSpecID != null &&
//selectLangPanel.setNotificationText("Please select a different Language or Compiler Spec."); compilerSpecID.equals(currentLCSPair.getCompilerSpecID())) {
setStatusText("Please select a different Language or Compiler Spec."); setStatusText("Please select a different Language or Compiler Spec.");
setOkEnabled(false); setOkEnabled(false);
} }
else { else {
//selectLangPanel.setNotificationText(null);
setStatusText(null); setStatusText(null);
setOkEnabled(true); setOkEnabled(true);
} }
return; return;
} }
//selectLangPanel.setNotificationText("Setting the language from '" + currProgram.getLanguageName() + "' to '" + langDesc.getName() + "'...");
//selectLangPanel.setNotificationText(null);
setStatusText(null); setStatusText(null);
setOkEnabled(langID != null); setOkEnabled(langID != null);
}; };
public SetLanguageDialog(PluginTool tool, Program program) { /**
super(getTitle(program), true, true, true, false); * Construct set Language/Compiler-Spec dialog
currProgram = program; * @param tool parent tool
this.tool = 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(); selectLangPanel = new NewLanguagePanel();
LanguageCompilerSpecPair lcsPair = new LanguageCompilerSpecPair(currProgram.getLanguageID(), if (lcsPair != null) {
currProgram.getCompilerSpec().getCompilerSpecID()); selectLangPanel.setSelectedLcsPair(lcsPair);
selectLangPanel.setSelectedLcsPair(lcsPair); }
selectLangPanel.addSelectionListener(listener); selectLangPanel.addSelectionListener(listener);
@ -83,35 +105,57 @@ public class SetLanguageDialog extends DialogComponentProvider {
addWorkPanel(selectLangPanel); addWorkPanel(selectLangPanel);
addOKButton(); addOKButton();
addCancelButton(); addCancelButton();
//getComponent().setPreferredSize(new Dimension(450, 430));
setOkEnabled(false); setOkEnabled(false);
setHelpLocation(new HelpLocation("LanguageProviderPlugin", "set language")); setHelpLocation(new HelpLocation("LanguageProviderPlugin", "set language"));
selectLangPanel.setShowRecommendedCheckbox(false); selectLangPanel.setShowRecommendedCheckbox(false);
listener.valueChanged(null); // kick to establish initial button enablement
} }
private static String getTitle(Program program) { private static LanguageCompilerSpecPair getLanguageCompilerSpecPair(String languageIdStr,
return "Set Language: " + program.getDomainFile().getName(); 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); tool.showDialog(this);
return dialogLanguageDescID; return dialogLanguageID;
} }
CompilerSpecID getCompilerSpecDescriptionID() { public CompilerSpecID getCompilerSpecDescriptionID() {
return dialogCompilerSpecDescID; return dialogCompilerSpecID;
} }
@Override @Override
protected void okCallback() { protected void okCallback() {
LanguageCompilerSpecPair selectedLcsPair = selectLangPanel.getSelectedLcsPair(); LanguageCompilerSpecPair selectedLcsPair = selectLangPanel.getSelectedLcsPair();
if (selectedLcsPair == null) { if (selectedLcsPair == null) {
dialogLanguageDescID = null; dialogLanguageID = null;
dialogCompilerSpecDescID = null; dialogCompilerSpecID = null;
} }
else { else {
dialogLanguageDescID = selectedLcsPair.languageID; dialogLanguageID = selectedLcsPair.languageID;
dialogCompilerSpecDescID = selectedLcsPair.compilerSpecID; dialogCompilerSpecID = selectedLcsPair.compilerSpecID;
} }
close(); close();
} }

View file

@ -16,6 +16,8 @@
package ghidra.app.util; package ghidra.app.util;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
import ghidra.util.InvalidNameException; import ghidra.util.InvalidNameException;
public class DataTypeNamingUtil { public class DataTypeNamingUtil {
@ -42,12 +44,16 @@ public class DataTypeNamingUtil {
StringBuilder sb = new StringBuilder(ANONYMOUS_FUNCTION_DEF_PREFIX); StringBuilder sb = new StringBuilder(ANONYMOUS_FUNCTION_DEF_PREFIX);
GenericCallingConvention convention = functionDefinition.getGenericCallingConvention(); if (functionDefinition.hasNoReturn()) {
if (convention != null && convention != GenericCallingConvention.unknown) { sb.append("_").append(FunctionSignature.NORETURN_DISPLAY_STRING);
sb.append(convention.getDeclarationName());
} }
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())); sb.append(mangleDTName(returnType.getName()));
for (ParameterDefinition p : parameters) { for (ParameterDefinition p : parameters) {
sb.append("_").append(mangleDTName(p.getDataType().getName())); sb.append("_").append(mangleDTName(p.getDataType().getName()));

View file

@ -289,12 +289,20 @@ public class ToolTipUtils {
} }
buffy.append(friendlyEncodeHTML(function.getReturnType().getName())); buffy.append(friendlyEncodeHTML(function.getReturnType().getName()));
buffy.append(HTML_SPACE); buffy.append(HTML_SPACE);
PrototypeModel callingConvention = function.getCallingConvention();
if (isNonDefaultCallingConvention(callingConvention)) { String callingConvention = function.getCallingConventionName();
buffy.append(friendlyEncodeHTML(callingConvention.getName())); 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); buffy.append(HTML_SPACE);
} }
String functionName = StringUtilities.trimMiddle(function.getName(), LINE_LENGTH); String functionName = StringUtilities.trimMiddle(function.getName(), LINE_LENGTH);
buffy.append(colorString(FunctionColors.NAME, friendlyEncodeHTML(functionName))); buffy.append(colorString(FunctionColors.NAME, friendlyEncodeHTML(functionName)));
buffy.append(HTML_SPACE).append("("); buffy.append(HTML_SPACE).append("(");
@ -304,14 +312,6 @@ public class ToolTipUtils {
return buffy.toString(); 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) { private static void buildParameterPreview(Function function, StringBuilder buffy) {
int rawTextLength = 0; int rawTextLength = 0;

View file

@ -16,13 +16,11 @@
package ghidra.app.util.bin.format.dwarf4.next; 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.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.*;
import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.DW_TAG_subrange_type;
import java.util.*;
import java.util.stream.Collectors;
import java.io.IOException; import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -35,7 +33,9 @@ import ghidra.program.database.DatabaseObject;
import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.InvalidInputException;
/** /**
* Creates Ghidra {@link DataType}s using information from DWARF debug entries. The caller * Creates Ghidra {@link DataType}s using information from DWARF debug entries. The caller
@ -301,6 +301,7 @@ public class DWARFDataTypeImporter {
FunctionDefinitionDataType funcDef = FunctionDefinitionDataType funcDef =
new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager); new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager);
funcDef.setReturnType(returnType.dataType); funcDef.setReturnType(returnType.dataType);
funcDef.setNoReturn(diea.getBool(DW_AT_noreturn, false));
funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()])); funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()]));
if (!diea.getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) { if (!diea.getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) {
@ -308,7 +309,12 @@ public class DWARFDataTypeImporter {
} }
if (foundThisParam) { 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) { if (dni.isAnon() && mangleAnonFuncNames) {

View file

@ -15,22 +15,22 @@
*/ */
package ghidra.app.util.bin.format.dwarf4.next; package ghidra.app.util.bin.format.dwarf4.next;
import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.io.IOException;
import ghidra.app.util.bin.format.dwarf4.*; import ghidra.app.util.bin.format.dwarf4.*;
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFEncoding; import ghidra.app.util.bin.format.dwarf4.encoding.*;
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException; import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
import ghidra.app.util.bin.format.dwarf4.next.DWARFDataTypeImporter.DWARFDataType; import ghidra.app.util.bin.format.dwarf4.next.DWARFDataTypeImporter.DWARFDataType;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.Swing; import ghidra.util.Swing;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import utility.function.Dummy; import utility.function.Dummy;
@ -726,13 +726,19 @@ public class DWARFDataTypeManager {
FunctionDefinitionDataType funcDef = FunctionDefinitionDataType funcDef =
new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager); new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager);
funcDef.setReturnType(returnDataType); funcDef.setReturnType(returnDataType);
funcDef.setNoReturn(diea.getBool(DWARFAttribute.DW_AT_noreturn, false));
funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()])); funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()]));
if (!diea.getHeadFragment().getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) { if (!diea.getHeadFragment().getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) {
funcDef.setVarArgs(true); funcDef.setVarArgs(true);
} }
if (foundThisParam) { 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; return funcDef;

View file

@ -388,7 +388,8 @@ public class DWARFFunctionImporter {
Parameter curparam = buildParameter(gfunc, i, dfunc.params.get(i), diea); Parameter curparam = buildParameter(gfunc, i, dfunc.params.get(i), diea);
params.add(curparam); params.add(curparam);
if (i == 0 && checkThisParameter(dfunc.params.get(0), diea)) { if (i == 0 && checkThisParameter(dfunc.params.get(0), diea)) {
convention = compilerSpec.matchConvention(GenericCallingConvention.thiscall); convention =
compilerSpec.matchConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
} }
} }

View file

@ -17,27 +17,52 @@ package ghidra.app.util.cparser.C;
import java.io.*; import java.io.*;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator;
import javax.help.UnsupportedOperationException;
import generic.theme.GThemeDefaults.Colors; import generic.theme.GThemeDefaults.Colors;
import generic.theme.GThemeDefaults.Colors.Messages; import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.services.DataTypeManagerService; import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.CPP.PreProcessor; import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.framework.plugintool.ServiceProvider; import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.database.ProgramDB; import ghidra.framework.store.LockException;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.util.DefaultLanguageService; import ghidra.program.util.DefaultLanguageService;
import ghidra.util.*; import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class CParserUtils { public class CParserUtils {
private CParserUtils() { private CParserUtils() {
// utils class // utils class
} }
public record CParseResults(PreProcessor preProcessor, String cppParseMessages, String cParseMessages, boolean successful) {
public String getFormattedParseMessage(String errMsg) {
String message = "";
if (errMsg != null) {
message += errMsg + "\n\n";
}
String msg = cppParseMessages;
if (msg != null && msg.length() != 0) {
message += "CParser Messages:\n" + msg + "\n\n";
}
msg = cppParseMessages;
if (msg != null && msg.length() != 0) {
message += "PreProcessor Messages:\n" + msg;
}
return message;
}
}
/** /**
* Parse the given function signature text. Any exceptions will be handled herein * Parse the given function signature text. Any exceptions will be handled herein
@ -88,7 +113,7 @@ public class CParserUtils {
* [0]= part before function name * [0]= part before function name
* [1]= function name * [1]= function name
* [2]= parameter body after function name * [2]= parameter body after function name
* @param signature * @param signature function signature string to split
* @return parts array or null if split failed * @return parts array or null if split failed
*/ */
private static String[] splitFunctionSignature(String signature) { private static String[] splitFunctionSignature(String signature) {
@ -136,7 +161,7 @@ public class CParserUtils {
/** /**
* Get a temporary name of a specified length (tttt....) * Get a temporary name of a specified length (tttt....)
* @param length * @param length of temporary string
* @return temporary name string * @return temporary name string
*/ */
private static String getTempName(int length) { private static String getTempName(int length) {
@ -158,6 +183,7 @@ public class CParserUtils {
* parsing exceptions. This allows clients to perform exception handling that * parsing exceptions. This allows clients to perform exception handling that
* better matches their workflow. * better matches their workflow.
* @return the data type that is created as a result of parsing; null if there was a problem * @return the data type that is created as a result of parsing; null if there was a problem
* @throws ParseException for catastrophic errors in C parsing
*/ */
public static FunctionDefinitionDataType parseSignature(DataTypeManagerService service, public static FunctionDefinitionDataType parseSignature(DataTypeManagerService service,
Program program, String signatureText, boolean handleExceptions) throws ParseException { Program program, String signatureText, boolean handleExceptions) throws ParseException {
@ -237,8 +263,6 @@ public class CParserUtils {
* *
* @param dataFileName name of data type archive file (include the .gdt extension) * @param dataFileName name of data type archive file (include the .gdt extension)
* *
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
*
* @param monitor used to cancel or provide results * @param monitor used to cancel or provide results
* *
* @return the data types in the ghidra .gdt archive file * @return the data types in the ghidra .gdt archive file
@ -250,15 +274,48 @@ public class CParserUtils {
*/ */
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName, public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException { ghidra.app.util.cparser.CPP.ParseException, IOException {
File file = new File(dataFileName);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, cpp, monitor); return parseHeaderFiles(openDTMgrs, filenames, null, args, dataFileName, monitor);
}
/**
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
* with in the provided dataFileName.
*
* Note: Using another open archive while parsing will cause:
* - a dependence on the other archive
* - any missing data types while parsing are supplied if present from an openDTMgr
* - after parsing all data types parsed with an equivalent data type in any openDTMgr
* replaced by the data type from the openDTMgr
*
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
*
* @param openDTMgrs array of datatypes managers to use for undefined data types
*
* @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments
* @param includePaths paths to include files, instead of using "-I<includepath>" in args
* @param args arguments for parsing, "-D<defn>=", ( "-I<includepath>" use includePaths parm instead)
*
* @param dataFileName name of data type archive file (include the .gdt extension)
*
* @param monitor used to cancel or provide results
*
* @return the data types in the ghidra .gdt archive file
*
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
* @throws IOException if there io are errors saving the archive
*
*/
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
dtMgr.save(); return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dataFileName, null, null, monitor);
return dtMgr;
} }
@ -280,6 +337,7 @@ public class CParserUtils {
* *
* @param filenames names of files in order to parse, could include strings with * @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments * "#" at start, which are ignored as comments
* @param includePaths path to include files, could also be in args with "-I<includepath>"
* @param args arguments for parsing, "-D<defn>=", "-I<includepath>" * @param args arguments for parsing, "-D<defn>=", "-I<includepath>"
* *
* @param dataFileName name of data type archive file (include the .gdt extension) * @param dataFileName name of data type archive file (include the .gdt extension)
@ -287,8 +345,6 @@ public class CParserUtils {
* @param languageId language identication to use for data type organization definitions (int, long, ptr size) * @param languageId language identication to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing * @param compileSpecId compiler specification to use for parsing
* *
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
*
* @param monitor used to cancel or provide results * @param monitor used to cancel or provide results
* *
* @return the data types in the ghidra .gdt archive file * @return the data types in the ghidra .gdt archive file
@ -298,14 +354,17 @@ public class CParserUtils {
* @throws IOException if there io are errors saving the archive * @throws IOException if there io are errors saving the archive
* *
*/ */
public static DataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName, public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException { ghidra.app.util.cparser.CPP.ParseException, IOException {
File file = new File(dataFileName); File file = new File(dataFileName);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file); FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
String messages = parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, languageId, compileSpecId, cpp, monitor); CParseResults results;
results = parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, languageId, compileSpecId, monitor);
String messages = results.getFormattedParseMessage(null);
Msg.info(CParserUtils.class, messages); Msg.info(CParserUtils.class, messages);
dtMgr.save(); dtMgr.save();
@ -331,15 +390,13 @@ public class CParserUtils {
* *
* @param filenames names of files in order to parse, could include strings with * @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments * "#" at start, which are ignored as comments
* @param args arguments for parsing, "-D<defn>=", "-I<includepath>" * @param args arguments for parsing, "-D<defn>=", ( "-I<includepath>" use includePaths parm instead)
* *
* @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr * @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
* *
* @param languageId language identication to use for data type organization definitions (int, long, ptr size) * @param languageId language identication to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing * @param compileSpecId compiler specification to use for parsing
* *
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
*
* @param monitor used to cancel or provide results * @param monitor used to cancel or provide results
* *
* @return a formatted string of any output from pre processor parsing or C parsing * @return a formatted string of any output from pre processor parsing or C parsing
@ -349,39 +406,84 @@ public class CParserUtils {
* @throws IOException if there io are errors saving the archive * @throws IOException if there io are errors saving the archive
* *
*/ */
public static String parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr, public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
return parseHeaderFiles(openDTMgrs, filenames, null, args, existingDTMgr, languageId, compileSpecId, monitor);
}
/**
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided
* DTMgr.
*
* Note: Using another open archive while parsing will cause:
* - a dependence on the other archive
* - any missing data types while parsing are supplied if present from an openDTMgr
* - after parsing all data types parsed with an equivalent data type in any openDTMgr
* replaced by the data type from the openDTMgr
*
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
*
* NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
* @param openDTMgrs array of datatypes managers to use for undefined data types
*
* @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments
* @param includePaths paths to include files, instead of using "-I<includepath>" in args
* @param args arguments for parsing, "-D<defn>=", ( "-I<includepath>" use includePaths parm instead)
*
* @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
*
* @param languageId language identication to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing
*
* @param monitor used to cancel or provide results
*
* @return a formatted string of any output from pre processor parsing or C parsing
*
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
* @throws IOException if there io are errors saving the archive
*
*/
public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], DataTypeManager existingDTMgr,
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException { ghidra.app.util.cparser.CPP.ParseException, IOException {
Language language = DefaultLanguageService.getLanguageService().getLanguage(new LanguageID(languageId)); Language language = DefaultLanguageService.getLanguageService().getLanguage(new LanguageID(languageId));
CompilerSpec compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compileSpecId)); CompilerSpec compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compileSpecId));
String dtmgrName = existingDTMgr.getName();
if (existingDTMgr instanceof FileDataTypeManager) {
dtmgrName = ((FileDataTypeManager) existingDTMgr).getPath();
}
ProgramDB program = new ProgramDB(dtmgrName, language, compilerSpec, CParserUtils.class);
try {
DataTypeManager programDtm = program.getDataTypeManager();
String messages = parseHeaderFiles(openDTMgrs, filenames, args, programDtm, cpp, monitor);
int txId = existingDTMgr.startTransaction("Add Types");
try {
Iterator<DataType> allDataTypes = programDtm.getAllDataTypes();
while (allDataTypes.hasNext()) {
existingDTMgr.resolve(allDataTypes.next(), null);
}
}
finally {
existingDTMgr.endTransaction(txId, true);
}
return messages; if (existingDTMgr instanceof StandAloneDataTypeManager) {
} try {
finally { ((StandAloneDataTypeManager) existingDTMgr).setProgramArchitecture(language, compilerSpec.getCompilerSpecID(),
program.release(CParserUtils.class); StandAloneDataTypeManager.LanguageUpdateOption.UNCHANGED, monitor);
}
catch (CompilerSpecNotFoundException e) {
e.printStackTrace();
}
catch (LanguageNotFoundException e) {
e.printStackTrace();
}
catch (CancelledException e) {
// ignore
}
catch (LockException e) {
e.printStackTrace();
}
catch (UnsupportedOperationException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (IncompatibleLanguageException e) {
// Shouldn't happen, unless already had a language
e.printStackTrace();
}
} }
return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, existingDTMgr, monitor);
} }
/** /**
@ -405,12 +507,11 @@ public class CParserUtils {
* *
* @param filenames names of files in order to parse, could include strings with * @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments * "#" at start, which are ignored as comments
* @param args arguments for parsing, "-D<defn>=", "-I<includepath>" * @param includePaths paths to include files, instead of using "-I<includepath>" in args
* @param args arguments for parsing, "-D<defn>=", ( "-I<includepath>" use includePaths parm instead)
* *
* @param dtMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr * @param dtMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
* *
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
*
* @param monitor used to cancel or provide results * @param monitor used to cancel or provide results
* *
* @return a formatted string of any output from pre processor parsing or C parsing * @return a formatted string of any output from pre processor parsing or C parsing
@ -418,22 +519,31 @@ public class CParserUtils {
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
*/ */
public static String parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames, public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames, String[] includePaths,
String args[], DataTypeManager dtMgr, PreProcessor cpp, TaskMonitor monitor) String args[], DataTypeManager dtMgr, TaskMonitor monitor)
throws ghidra.app.util.cparser.C.ParseException, throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException { ghidra.app.util.cparser.CPP.ParseException {
String cppMessages = ""; String cppMessages = "";
if (cpp == null) { PreProcessor cpp = new PreProcessor();
cpp = new PreProcessor();
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setArgs(args); cpp.setArgs(args);
cpp.addIncludePaths(includePaths);
PrintStream os = System.out; PrintStream os = System.out;
String fName = dtMgr.getName().replace(".gdt","")+"_CParser.out";
String fName = dtMgr.getName();
// make a path to tmpdir with name of data type manager
String path = System.getProperty("java.io.tmpdir") + File.pathSeparator + fName;
// if file data type manager, use path to .gdt file
if (dtMgr instanceof FileDataTypeManager) {
path = ((FileDataTypeManager) dtMgr).getPath();
}
path = path + "_CParser.out";
try { try {
os = new PrintStream(new FileOutputStream(fName)); os = new PrintStream(new FileOutputStream(path));
} catch (FileNotFoundException e2) { } catch (FileNotFoundException e2) {
Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2); Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2);
} }
@ -442,8 +552,10 @@ public class CParserUtils {
System.setOut(os); System.setOut(os);
cpp.setMonitor(monitor); cpp.setMonitor(monitor);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setOutputStream(bos); cpp.setOutputStream(bos);
boolean parseSucceeded = false;
try { try {
for (String filename : filenames) { for (String filename : filenames) {
if (monitor.isCancelled()) { if (monitor.isCancelled()) {
@ -469,9 +581,9 @@ public class CParserUtils {
parseFile(filename, monitor, cpp); parseFile(filename, monitor, cpp);
} }
} }
} catch (RuntimeException re) { parseSucceeded = true;
} catch (Throwable e) {
Msg.info(cpp, cpp.getParseMessages()); Msg.info(cpp, cpp.getParseMessages());
throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
} finally { } finally {
System.out.println(bos); System.out.println(bos);
os.flush(); os.flush();
@ -481,12 +593,16 @@ public class CParserUtils {
} }
cppMessages = cpp.getParseMessages(); cppMessages = cpp.getParseMessages();
if (!parseSucceeded) {
return new CParseResults(cpp, "", cppMessages, false);
}
// process all the defines and add any that are integer values into // process all the defines and add any that are integer values into
// the Equates table // the Equates table
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr); cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
String parserMessages = ""; String parserMessages = "";
boolean cparseSucceeded = false;
if (!monitor.isCancelled()) { if (!monitor.isCancelled()) {
monitor.setMessage("Parsing C"); monitor.setMessage("Parsing C");
@ -497,12 +613,15 @@ public class CParserUtils {
cParser.setParseFileName(fName); cParser.setParseFileName(fName);
cParser.setMonitor(monitor); cParser.setMonitor(monitor);
cParser.parse(bis); cParser.parse(bis);
cparseSucceeded = cParser.didParseSucceed();
} catch (RuntimeException re) {
Msg.info(cpp, cpp.getParseMessages());
} finally { } finally {
parserMessages = cParser.getParseMessages(); parserMessages = cParser.getParseMessages();
} }
} }
return getFormattedParseMessage(parserMessages, cppMessages, null); return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded);
} }
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp) private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
@ -522,26 +641,6 @@ public class CParserUtils {
return cpp.getParseMessages(); return cpp.getParseMessages();
} }
private static String getFormattedParseMessage(String parseMessage, String cppMessage, String errMsg) {
String message = "";
if (errMsg != null) {
message += errMsg + "\n\n";
}
String msg = parseMessage;
if (msg != null && msg.length() != 0) {
message += "CParser Messages:\n" + msg + "\n\n";
}
msg = cppMessage;
if (msg != null && msg.length() != 0) {
message += "PreProcessor Messages:\n" + msg;
}
return message;
}
private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) { private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) {
if (service == null) { if (service == null) {
@ -680,4 +779,54 @@ public class CParserUtils {
errorIndex + "<br>" + successFailureBuffer; errorIndex + "<br>" + successFailureBuffer;
} }
public static File getFile(String parent, String filename) {
File file = findFile(parent, filename);
if (file != null) {
return file;
}
// filename lower
file = findFile(parent, filename.toLowerCase());
if (file != null) {
return file;
}
// parent and filename lower
file = findFile(parent.toLowerCase(), filename.toLowerCase());
if (file != null) {
return file;
}
// parent and filename upper
file = findFile(parent.toUpperCase(), filename.toUpperCase());
return file;
}
private static File findFile(String parent, String filename) {
File iFile = null;
iFile = new File(parent + File.separator + filename);
if (iFile.exists())
return iFile;
// try just in this directory
File sameiFile = new File(parent + File.separator
+ (new File(filename)).getName());
if (sameiFile.exists())
return sameiFile;
// try all files in this directory doing to-lower on both input file and output file
// if match return it
File folder = new File(parent);
if (folder.isDirectory()) {
File[] listOfFiles = folder.listFiles();
if (listOfFiles != null) {
for (File file : listOfFiles) {
if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) {
return file;
}
}
}
}
return null;
}
} }

View file

@ -21,10 +21,12 @@ import java.awt.Color;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.util.ToolTipUtils; import ghidra.app.util.ToolTipUtils;
import ghidra.app.util.html.diff.DataTypeDiff; import ghidra.app.util.html.diff.DataTypeDiff;
import ghidra.app.util.html.diff.DataTypeDiffBuilder; import ghidra.app.util.html.diff.DataTypeDiffBuilder;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature; import ghidra.program.model.listing.FunctionSignature;
import ghidra.util.HTMLUtilities; import ghidra.util.HTMLUtilities;
import ghidra.util.StringUtilities; import ghidra.util.StringUtilities;
@ -113,14 +115,26 @@ public class FunctionDataTypeHTMLRepresentation extends HTMLDataTypeRepresentati
} }
private TextLine buildReturnType(FunctionDefinition functionDefinition) { private TextLine buildReturnType(FunctionDefinition functionDefinition) {
DataType returnDataType = functionDefinition.getReturnType(); DataType returnDataType = functionDefinition.getReturnType();
GenericCallingConvention genericCallingConvention = String rtHtml = friendlyEncodeHTML(returnDataType.getDisplayName());
functionDefinition.getGenericCallingConvention();
String modifier = genericCallingConvention != GenericCallingConvention.unknown String noReturnHtml = "";
? (" " + genericCallingConvention.getDeclarationName()) if (functionDefinition.hasNoReturn()) {
: ""; noReturnHtml = FunctionSignature.NORETURN_DISPLAY_STRING + HTML_SPACE;
return new TextLine( }
HTMLUtilities.friendlyEncodeHTML(returnDataType.getDisplayName()) + modifier);
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 // display name to name pairs

View file

@ -123,12 +123,11 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
if (callingConvention.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) { if (callingConvention.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
callingConvention = function.getCallingConvention().getName(); callingConvention = function.getCallingConvention().getName();
} }
if (callingConvention != null && if (!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
as = new AttributedString(callingConvention + " ", FunctionColors.RETURN_TYPE, as = new AttributedString(callingConvention + " ", FunctionColors.RETURN_TYPE,
getMetrics()); getMetrics());
textElements textElements
.add(new FunctionCallingConventionFieldElement(as, elementIndex, 0, startCol)); .add(new FunctionCallingConventionFieldElement(as, elementIndex, 0, startCol));
startCol += as.length(); startCol += as.length();
elementIndex++; elementIndex++;
} }

View file

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

View file

@ -36,6 +36,8 @@ import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; 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.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.program.model.scalar.Scalar; import ghidra.program.model.scalar.Scalar;
@ -2486,7 +2488,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 archiveFile the archive file to open
* @param readOnly should file be opened read only * @param readOnly should file be opened read only
* @return the data type manager * @return the data type manager
@ -2494,8 +2505,7 @@ public class FlatProgramAPI {
*/ */
public final FileDataTypeManager openDataTypeArchive(File archiveFile, boolean readOnly) public final FileDataTypeManager openDataTypeArchive(File archiveFile, boolean readOnly)
throws Exception { throws Exception {
FileDataTypeManager dtfm = FileDataTypeManager.openFileArchive(archiveFile, !readOnly); return FileDataTypeManager.openFileArchive(archiveFile, !readOnly);
return dtfm;
} }
/** /**

View file

@ -20,7 +20,6 @@ import java.util.*;
import generic.theme.GThemeDefaults.Colors.Palette; import generic.theme.GThemeDefaults.Colors.Palette;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.GenericCallingConvention;
import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@ -64,7 +63,7 @@ public class FunctionUtility {
Program sourceProgram = sourceFunction.getProgram(); Program sourceProgram = sourceFunction.getProgram();
Program destinationProgram = destinationFunction.getProgram(); Program destinationProgram = destinationFunction.getProgram();
boolean sameLanguage = isSameLanguage(destinationProgram, sourceProgram); boolean sameLanguage = isSameLanguageAndCompilerSpec(destinationProgram, sourceProgram);
String callingConventionName = String callingConventionName =
determineCallingConventionName(destinationFunction, sourceFunction, sameLanguage); determineCallingConventionName(destinationFunction, sourceFunction, sameLanguage);
@ -274,7 +273,7 @@ public class FunctionUtility {
* @param program2 the second program * @param program2 the second program
* @return true if the two programs have the same processor language and compiler spec. * @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 language1 = program1.getLanguage();
Language language2 = program2.getLanguage(); Language language2 = program2.getLanguage();
if (language1.getLanguageID() != language2.getLanguageID()) { if (language1.getLanguageID() != language2.getLanguageID()) {
@ -289,17 +288,9 @@ public class FunctionUtility {
} }
private static String determineCallingConventionName(Function destinationFunction, private static String determineCallingConventionName(Function destinationFunction,
Function sourceFunction, boolean sameLanguage) { Function sourceFunction, boolean sameLanguageAndCompilerSpec) {
String sourceCallingConventionName = sourceFunction.getCallingConventionName(); return sameLanguageAndCompilerSpec ? sourceFunction.getCallingConventionName()
if (sameLanguage) { : destinationFunction.getCallingConventionName();
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.
} }
private static boolean determineCustomStorageUse(Function destinationFunction, 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.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Function.FunctionUpdateType; 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"); ResourceFile emuTestingArchive = Application.getModuleDataFile("pcodetest/EmuTesting.gdt");
archiveDtMgr = FileDataTypeManager.openFileArchive(emuTestingArchive, false); archiveDtMgr = FileDataTypeManager.openFileArchive(emuTestingArchive, false);
assertEquals(ArchiveWarning.NONE, archiveDtMgr.getWarning());
DataType dt = archiveDtMgr.getDataType(CategoryPath.ROOT, TEST_INFO_STRUCT_NAME); DataType dt = archiveDtMgr.getDataType(CategoryPath.ROOT, TEST_INFO_STRUCT_NAME);
if (dt == null || !(dt instanceof Structure)) { if (dt == null || !(dt instanceof Structure)) {
fail(TEST_INFO_STRUCT_NAME + fail(TEST_INFO_STRUCT_NAME +

View file

@ -218,6 +218,11 @@ public class UndefinedFunction implements Function {
return p.getCompilerSpec().getDefaultCallingConvention(); return p.getCompilerSpec().getDefaultCallingConvention();
} }
@Override
public boolean hasUnknownCallingConventionName() {
return true;
}
@Override @Override
public String getCallingConventionName() { public String getCallingConventionName() {
return Function.UNKNOWN_CALLING_CONVENTION_STRING; return Function.UNKNOWN_CALLING_CONVENTION_STRING;
@ -233,11 +238,6 @@ public class UndefinedFunction implements Function {
return new String[0]; return new String[0];
} }
@Override
public String getDefaultCallingConventionName() {
return p.getCompilerSpec().getDefaultCallingConvention().getName();
}
@Override @Override
public Address getEntryPoint() { public Address getEntryPoint() {
return entry; return entry;

View file

@ -622,11 +622,12 @@ public class CParser {
* @param dec Declaration * @param dec Declaration
* @param funcDT function data type to qualify * @param funcDT function data type to qualify
*/ */
private void applyFunctionQualifiers(Declaration dec, FunctionDefinitionDataType funcDT) { private void applyFunctionQualifiers(Declaration dec, FunctionDefinition funcDT) {
List<Integer> qualifierList = dec.getQualifiers(); List<Integer> qualifierList = dec.getQualifiers();
if (qualifierList.contains(NORETURN) ) { 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) { for (Integer qualifier : qualifierList) {
switch (qualifier) { switch (qualifier) {
case CDECL: case CDECL:
@ -1772,18 +1773,18 @@ Declaration TypeQualifier(Declaration dec) : {}
<STATIC> | <STATIC> |
<PACKED> | <PACKED> |
<UNALIGNED> | <UNALIGNED> |
( DeclSpec() ) ( DeclSpec(dec) )
) )
{ {
return dec; return dec;
} }
} }
void AttributeSpec() : {} void AttributeSpec(Declaration dec) : {}
{ {
( <ATTRIBUTE> ("(") SubIdent() (")") ) | ( <ATTRIBUTE> ("(") SubIdent(dec) (")") ) |
AsmStatement() | AsmStatement() |
( "[" "[" AttributeList() "]" "]" ) | ( "[" "[" AttributeList(dec) "]" "]" ) |
AlignmentSpecifier() AlignmentSpecifier()
} }
@ -1793,48 +1794,59 @@ void AlignmentSpecifier() : { Declaration dt = new Declaration(); }
< ALIGNAS > "(" ( TypeQualifier(dt) | AssignmentExpression() ) ")" < ALIGNAS > "(" ( TypeQualifier(dt) | AssignmentExpression() ) ")"
} }
void AttributeList() : { } void AttributeList(Declaration dec) : { }
{ {
AttributeToken() [ ("," AttributeToken())+ ] AttributeToken(dec) [ ("," AttributeToken(dec))+ ]
} }
void AttributeToken() : { Declaration dt = new Declaration(); } void AttributeToken(Declaration dec) : { }
{ {
( < IDENTIFIER > | TypeQualifier(dt) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dt) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ] ( < IDENTIFIER > | TypeQualifier(dec) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dec) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ]
} }
void AttributeSpecList() : {} void AttributeSpecList(Declaration dec) : {}
{ {
( AttributeSpec() )+ ( AttributeSpec(dec) )+
} }
void SubIdent() : { Declaration dt = new Declaration(); } void SubIdent(Declaration dec) : {
Token id = null;
Declaration dt = new Declaration();
}
{ {
( ( "(" [SubIdent()] ")" ) | ( ( "(" [SubIdent(dec)] ")" ) |
(<IDENTIFIER> | TypeQualifier(dt)) [ ( "(" [SubIdent()] ")") | ("=" SubIdent()) ] (id=<IDENTIFIER> | TypeQualifier(dec)) [ ( "(" [SubIdent(dt)] ")") | ("=" SubIdent(dt)) ]
[ "," [ ","
SubIdent() SubIdent(dt)
] | ] |
Constant() [ "," Constant() [ ","
SubIdent() SubIdent(dt)
] ]
) )
{
if (id != null && "noreturn".equals(id.image.replace("_", ""))) {
dec.addQualifier(NORETURN);
if (dec.getDataType() instanceof FunctionDefinition) {
applyFunctionQualifiers(dec, (FunctionDefinition) dec.getDataType());
}
}
}
} }
void DeclSpec() : { void DeclSpec(Declaration dec) : {
} }
{ {
( ( <DECLSPEC> | <READABLETO> ) "(" DeclSpecifier() ")" ) | ( ( <DECLSPEC> | <READABLETO> ) "(" DeclSpecifier(dec) ")" ) |
AttributeSpecList() AttributeSpecList(dec)
} }
void DeclSpecifier() : { void DeclSpecifier(Declaration dec) : {
Token id = null;
} }
{ {
"(" DeclSpecifier() ")" | "(" DeclSpecifier(dec) ")" |
(<IDENTIFIER>)+ [ "(" (id=<IDENTIFIER> { if (id != null && "noreturn".equals(id.image)) dec.addQualifier(NORETURN); } )+
DeclConstant() ( DeclConstant() )* [ "(" DeclConstant() ( DeclConstant() )* ")" ]
")" ]
} }
void DeclConstant() : {} void DeclConstant() : {}
@ -1970,6 +1982,7 @@ DataType StructOrUnionSpecifier() : {
Token parent; Token parent;
Token sname; Token sname;
Composite comp; Composite comp;
Declaration dec = new Declaration();
} }
{ {
{ {
@ -1982,7 +1995,7 @@ DataType StructOrUnionSpecifier() : {
LOOKAHEAD(3) LOOKAHEAD(3)
[ t= <IDENTIFIER> [ ":" parent=<IDENTIFIER>] [ t= <IDENTIFIER> [ ":" parent=<IDENTIFIER>]
{ comp=defineNamedComposite(t, null, comp); } // no parent yet, since there are no guts { comp=defineNamedComposite(t, null, comp); } // no parent yet, since there are no guts
] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList() ] ] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList(dec) ]
| |
sname= <IDENTIFIER> sname= <IDENTIFIER>
) )
@ -1997,10 +2010,13 @@ DataType StructOrUnionSpecifier() : {
} }
} }
Composite StructOrUnion() : {Composite comp;} Composite StructOrUnion() : {
Composite comp;
Declaration dec = new Declaration();
}
{ {
( (
<STRUCT> ( DeclSpec() | PragmaSpec() )* <STRUCT> ( DeclSpec(dec) | PragmaSpec() )*
{ {
comp = new StructureDataType(getCurrentCategoryPath(), ANONYMOUS_STRUCT_PREFIX + cnt++, 0, dtMgr); comp = new StructureDataType(getCurrentCategoryPath(), ANONYMOUS_STRUCT_PREFIX + cnt++, 0, dtMgr);
@ -2014,7 +2030,7 @@ Composite StructOrUnion() : {Composite comp;}
} }
| |
<UNION> ( DeclSpec() )* { <UNION> ( DeclSpec(dec) )* {
comp = new UnionDataType(getCurrentCategoryPath(), ANONYMOUS_UNION_PREFIX + cnt++, dtMgr); comp = new UnionDataType(getCurrentCategoryPath(), ANONYMOUS_UNION_PREFIX + cnt++, dtMgr);
// Always set the packing, because by default structures should be aligned // Always set the packing, because by default structures should be aligned
@ -2067,6 +2083,7 @@ void InitDeclarator(Declaration dt) : { Declaration dec; }
void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : { void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
Declaration dt = null; Declaration dt = null;
Declaration dec = new Declaration();
} }
{ {
LineDef() | LineDef() |
@ -2077,7 +2094,7 @@ void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
[ [
StructDeclaratorList(dt, comp, compositeHandler) { dt= null; } StructDeclaratorList(dt, comp, compositeHandler) { dt= null; }
] ]
[ AttributeSpecList() ] [ AttributeSpecList(dec) ]
";" ";"
) )
{ {
@ -2173,12 +2190,13 @@ DataType EnumSpecifier() : {
Token t= null; Token t= null;
DataType dt; DataType dt;
ArrayList<EnumMember> list; ArrayList<EnumMember> list;
Declaration dec = new Declaration();
} }
{ {
<ENUM> <ENUM>
( (
LOOKAHEAD(3) LOOKAHEAD(3)
[AttributeSpecList()] [ t= <IDENTIFIER> ] "{" list= EnumeratorList() "}" [AttributeSpecList(dec)] [ t= <IDENTIFIER> ] "{" list= EnumeratorList() "}"
{ {
String enumName= (t != null ? t.image : ("enum_" + cnt++)); String enumName= (t != null ? t.image : ("enum_" + cnt++));
EnumDataType enuum= new EnumDataType(getCurrentCategoryPath(), enumName, 4, dtMgr); EnumDataType enuum= new EnumDataType(getCurrentCategoryPath(), enumName, 4, dtMgr);
@ -2247,7 +2265,7 @@ Declaration Declarator(Declaration dt, DataType container) : {
} }
{ {
( (
[ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList() ] [ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList(dec) ]
) )
{ {
return dec; return dec;

View file

@ -1172,6 +1172,16 @@ public class PreProcessor {
public void addIncludePath(String path) { public void addIncludePath(String path) {
pathList.addElement(path); pathList.addElement(path);
} }
public void addIncludePaths(String[] paths) {
if (paths == null || paths.length < 1) {
return;
}
for (String path : paths) {
addIncludePath(path);
}
}
public int getNumericType(String val) { public int getNumericType(String val) {
try { try {
@ -1246,7 +1256,7 @@ public class PreProcessor {
outputStream = new PrintStream(fos); outputStream = new PrintStream(fos);
} }
public void parse(String filename) throws ParseException { public boolean parse(String filename) throws ParseException {
if (verboseLevel == 1) { if (verboseLevel == 1) {
addParseMessage(null, addParseMessage(null,
"PreProcessor: Reading from file " + filename + " . . ."); "PreProcessor: Reading from file " + filename + " . . .");
@ -1269,7 +1279,7 @@ public class PreProcessor {
} }
if (fis == null) { if (fis == null) {
addParseMessage(null, "PreProcessor: File " + filename + " not found."); addParseMessage(null, "PreProcessor: File " + filename + " not found.");
return; return false;
} }
fileStack.push(filename); fileStack.push(filename);
alreadyDone = new HashMap<String, Integer>(); alreadyDone = new HashMap<String, Integer>();
@ -1290,6 +1300,7 @@ public class PreProcessor {
addParseMessage(filename, "PreProcessor Token Error: " + e.getMessage()); addParseMessage(filename, "PreProcessor Token Error: " + e.getMessage());
throw e; throw e;
} }
return true;
} }
PreProcessor(PreProcessor parent) { PreProcessor(PreProcessor parent) {

View file

@ -45,17 +45,12 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeEditedInMy() throws Exception { public void testDataTypeEditedInMy() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
// Make no changes to Latest. // Make no changes to Latest.
} }
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -99,9 +94,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeEditedInBoth() throws Exception { public void testDataTypeEditedInBoth() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -171,9 +161,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedChanged() throws Exception { public void testDataTypeRenamedChanged() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -235,9 +220,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedChanged2() throws Exception { public void testDataTypeRenamedChanged2() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -309,9 +289,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedChanged3() throws Exception { public void testDataTypeRenamedChanged3() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -383,9 +358,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedChanged4() throws Exception { public void testDataTypeRenamedChanged4() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -458,9 +428,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDataTypeRenamedInBoth() throws Exception { public void testDataTypeRenamedInBoth() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -532,9 +497,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testRenamedChanged() throws Exception { public void testRenamedChanged() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -602,9 +562,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// in Latest move data type; in MY change the name; // in Latest move data type; in MY change the name;
// should be a conflict // should be a conflict
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -666,9 +621,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testRenamedChangedMoved() throws Exception { public void testRenamedChangedMoved() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -739,9 +689,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testRenamedChangedMovedNoConflict() throws Exception { public void testRenamedChangedMovedNoConflict() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -813,9 +758,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testRenamedChangedMovedNoConflict2() throws Exception { public void testRenamedChangedMovedNoConflict2() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -889,9 +829,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// edit DLL_Table in latest; edit DLL_Table in private // edit DLL_Table in latest; edit DLL_Table in private
// only DLL_Table should be in conflict; not the ones where it is used. // only DLL_Table should be in conflict; not the ones where it is used.
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -963,9 +898,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// edit DLL_Table in latest; edit DLL_Table in private // edit DLL_Table in latest; edit DLL_Table in private
// only DLL_Table should be in conflict; not the ones where it is used. // only DLL_Table should be in conflict; not the ones where it is used.
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -1037,9 +967,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// edit ArrayStruct in latest; edit ArrayStruct in private // edit ArrayStruct in latest; edit ArrayStruct in private
// only ArrayStruct should be in conflict; not the ones where it is used. // only ArrayStruct should be in conflict; not the ones where it is used.
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -1337,9 +1262,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testDeletedInLatest() throws Exception { public void testDeletedInLatest() throws Exception {
mtf.initialize("notepad2", new ProgramModifierListener() { mtf.initialize("notepad2", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -1429,9 +1349,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testAddedFuncSig() throws Exception { public void testAddedFuncSig() throws Exception {
mtf.initialize("notepad2", new ProgramModifierListener() { mtf.initialize("notepad2", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -1496,9 +1411,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testEditFuncSig() throws Exception { public void testEditFuncSig() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() { mtf.initialize("notepad3", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false; boolean commit = false;
@ -1562,9 +1472,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testEditFuncSig2() throws Exception { public void testEditFuncSig2() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() { mtf.initialize("notepad3", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false; boolean commit = false;
@ -1629,9 +1534,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testEditFuncSig3() throws Exception { public void testEditFuncSig3() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() { mtf.initialize("notepad3", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false; boolean commit = false;
@ -1642,6 +1545,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
try { try {
fd.setVarArgs(true); fd.setVarArgs(true);
fd.setNoReturn(true);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
dtm.remove(foo, TaskMonitor.DUMMY); dtm.remove(foo, TaskMonitor.DUMMY);
commit = true; commit = true;
@ -1651,9 +1555,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
} }
} }
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false; boolean commit = false;
@ -1689,16 +1590,15 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals(DataType.DEFAULT, vars[0].getDataType()); assertEquals(DataType.DEFAULT, vars[0].getDataType());
assertEquals("this is a comment", vars[0].getComment()); assertEquals("this is a comment", vars[0].getComment());
assertEquals(DataType.DEFAULT, vars[1].getDataType()); assertEquals(DataType.DEFAULT, vars[1].getDataType());
assertEquals(false, fd.hasVarArgs()); assertFalse(fd.hasVarArgs());
assertFalse(fd.hasNoReturn());
} }
@Test @Test
public void testEditFuncSig4() throws Exception { public void testEditFuncSig4() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() { mtf.initialize("notepad3", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false; boolean commit = false;
@ -1709,6 +1609,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
try { try {
fd.setVarArgs(true); fd.setVarArgs(true);
fd.setNoReturn(true);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
dtm.remove(foo, TaskMonitor.DUMMY); dtm.remove(foo, TaskMonitor.DUMMY);
commit = true; commit = true;
@ -1718,9 +1619,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
} }
} }
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false; boolean commit = false;
@ -1759,16 +1657,15 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
checkDataType(new CharDataType(), vars[1].getDataType()); checkDataType(new CharDataType(), vars[1].getDataType());
checkDataType(new Undefined4DataType(), vars[2].getDataType()); checkDataType(new Undefined4DataType(), vars[2].getDataType());
checkDataType(new Undefined4DataType(), vars[3].getDataType()); checkDataType(new Undefined4DataType(), vars[3].getDataType());
assertEquals(true, fd.hasVarArgs()); assertTrue(fd.hasVarArgs());
assertTrue(fd.hasNoReturn());
} }
@Test @Test
public void testEditFuncSig5() throws Exception { public void testEditFuncSig5() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() { mtf.initialize("notepad3", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false; boolean commit = false;
@ -1808,6 +1702,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
"this is another comment"); "this is another comment");
fd.setArguments(newVars); fd.setArguments(newVars);
fd.setVarArgs(true); fd.setVarArgs(true);
fd.setNoReturn(true);
commit = true; commit = true;
} }
finally { finally {
@ -1831,6 +1726,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals("Bar", vars[4].getName()); assertEquals("Bar", vars[4].getName());
assertEquals("this is another comment", vars[4].getComment()); assertEquals("this is another comment", vars[4].getComment());
assertTrue(fd.hasVarArgs()); assertTrue(fd.hasVarArgs());
assertTrue(fd.hasNoReturn());
} }
private void checkDataType(DataType expectedDataType, DataType actualDataType) { private void checkDataType(DataType expectedDataType, DataType actualDataType) {
@ -1842,9 +1738,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
public void testAddConflictFuncSig1() throws Exception { public void testAddConflictFuncSig1() throws Exception {
mtf.initialize("notepad3", new ProgramModifierListener() { mtf.initialize("notepad3", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
boolean commit = false; 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 @Override
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
boolean commit = false; boolean commit = false;
@ -1902,7 +1793,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals("format", vars[0].getName()); assertEquals("format", vars[0].getName());
assertEquals(null, vars[0].getComment()); assertEquals(null, vars[0].getComment());
checkDataType(new WordDataType(), fd1.getReturnType()); checkDataType(new WordDataType(), fd1.getReturnType());
assertEquals(false, fd1.hasVarArgs()); assertFalse(fd1.hasVarArgs());
FunctionDefinition fd2 = FunctionDefinition fd2 =
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "printf.conflict"); (FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "printf.conflict");
@ -1913,7 +1804,80 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals("format", vars2[0].getName()); assertEquals("format", vars2[0].getName());
assertEquals(null, vars2[0].getComment()); assertEquals(null, vars2[0].getComment());
checkDataType(new WordDataType(), fd2.getReturnType()); 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

@ -0,0 +1,613 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.cparser;
import static org.junit.Assert.*;
import java.awt.Window;
import java.io.File;
import java.util.ArrayList;
import javax.swing.JTextArea;
import org.junit.*;
import docking.action.DockingActionIf;
import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.dialogs.InputDialog;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.pathmanager.PathnameTablePanel;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.cparser.ParseDialog.ComboBoxItem;
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
import ghidra.app.plugin.core.processors.SetLanguageDialog;
import ghidra.framework.plugintool.PluginTool;
import ghidra.plugin.importer.NewLanguagePanel;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Program;
import ghidra.test.*;
import utilities.util.FileUtilities;
public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegrationTest {
private static final String TITLE = "CParser Results Summary";
private TestEnv env;
private PluginTool tool;
private Program program;
private CParserPlugin plugin;
private DockingActionIf cparserAction;
private DataTypeManagerPlugin dtmPlugin;
@Before
public void setUp() throws Exception {
program = getNotepad();
env = new TestEnv();
}
private Program getNotepad() throws Exception {
ClassicSampleX86ProgramBuilder builder =
new ClassicSampleX86ProgramBuilder("notepad", false, this);
return builder.getProgram();
}
@After
public void tearDown() throws Exception {
env.dispose();
}
private void initTool(Program prog) throws Exception {
if (prog != null) {
tool = env.showTool(prog);
} else {
tool = env.showTool();
}
tool.addPlugin(CodeBrowserPlugin.class.getName());
tool.addPlugin(GoToAddressLabelPlugin.class.getName());
tool.addPlugin(CParserPlugin.class.getName());
tool.addPlugin(DataTypeManagerPlugin.class.getName());
plugin = getPlugin(tool, CParserPlugin.class);
cparserAction = getAction(plugin, CParserPlugin.PARSE_ACTION_NAME);
dtmPlugin = getPlugin(tool, DataTypeManagerPlugin.class);
}
@Test
public void testImportToProgramNoneOpen() throws Exception {
initTool(null);
ParseDialog parseDialog = showParseDialog();
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
pressButtonByText(parseDialog, "Parse to Program", false);
pressButtonByText(waitForDialogComponent("No Open Program"), "OK", false);
}
@Test
public void testImportToProgramNoArch() throws Exception {
program = getNotepad();
initTool(program);
ParseDialog parseDialog = showParseDialog();
this.setSelectedParseProfile(parseDialog, "MacOSX_10.5.prf");
pressButtonByText(parseDialog, "Parse to Program", false);
String langText = parseDialog.getLanguageText().getText();
assertEquals("64/32 (primarily for backward compatibility)", langText);
pressButtonByText(waitForDialogComponent("Program Architecture not Specified"), "OK", false);
}
@Test
public void testImportToProgramConfirm() throws Exception {
program = getNotepad();
initTool(program);
ParseDialog parseDialog = showParseDialog();
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
pressButtonByText(parseDialog, "Parse to Program", false);
pressButtonByText(waitForDialogComponent("Confirm"), "Cancel", false);
}
@Test
public void testImportToProgram() throws Exception {
initTool(program);
ParseDialog parseDialog = showParseDialog();
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
// write out a dummy header file to read
File dummyHeader = this.createTempFile("dummy.h");
FileUtilities.deleteDir(dummyHeader);
String files[] = {dummyHeader.getPath()};
this.setFiles(parseDialog, files);
pressButtonByText(parseDialog, "Parse to Program", false);
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
// dummy file empty, error
pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
// dummy file full, OK
FileUtilities.writeStringToFile(dummyHeader,
"typedef int wchar_t;\n" +
"struct mystruct {\n" +
" wchar_t defined_wchar_t;\n" +
"};\n");
this.setFiles(parseDialog, files);
pressButtonByText(parseDialog, "Parse to Program", false);
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
waitForBusyTool(tool);
pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
DataType dataType = program.getDataTypeManager().getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
assertNotNull("mystruct parsed into program", dataType);
}
@Test
public void testImportToProgramWithIncludePaths() throws Exception {
initTool(program);
ParseDialog parseDialog = showParseDialog();
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
// write out a dummy header file to read
File dummyHeader = this.createTempFile("dummy.h");
FileUtilities.deleteDir(dummyHeader);
String files[] = {dummyHeader.getName()};
this.setFiles(parseDialog, files);
String includePath[] = {dummyHeader.getParent()};
this.setIncludePaths(parseDialog, includePath);
pressButtonByText(parseDialog, "Parse to Program", false);
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
// dummy file empty, error
pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
// dummy file full, OK
FileUtilities.writeStringToFile(dummyHeader,
"typedef int wchar_t;\n" +
"struct mystruct {\n" +
" wchar_t defined_wchar_t;\n" +
"};\n");
this.setFiles(parseDialog, files);
pressButtonByText(parseDialog, "Parse to Program", false);
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
waitForBusyTool(tool);
pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
DataType dataType = program.getDataTypeManager().getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
assertNotNull("mystruct parsed into program", dataType);
}
@Test
public void testImportToProgramOpenArchives() throws Exception {
initTool(program);
ParseDialog parseDialog = showParseDialog();
// open an archive
dtmPlugin.openDataTypeArchive("windows_vs12_64");
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
pressButtonByText(parseDialog, "Parse to Program", false);
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Don't Use Open Archives", false);
}
// switch between two
// change, test ask save if change
@Test
public void testSetLanguage() throws Exception {
initTool(program);
ParseDialog parseDialog = showParseDialog();
//
// test switch to new profile after changes, NO to save changes
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
setLanguage(parseDialog, "8051:BE:16:default", "default");
runSwing(() -> {
this.setSelectedParseProfile(parseDialog, "VisualStudio12_64.prf");
}, false);
pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "No", false);
assertEquals("VisualStudio12_64.prf",parseDialog.getCurrentItem().getName());
//
// test forced save as new profile, doesn't exist
setLanguage(parseDialog, "8051:BE:16:default", "default");
runSwing(() -> {
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
}, false);
// make sure profile is gone
ResourceFile userProfileParent = parseDialog.getUserProfileParent();
File f = new File(userProfileParent.getAbsolutePath(),"MyTestProfile.prf");
f.delete();
pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "Yes", false);
InputDialog dialog = waitForDialogComponent(InputDialog.class);
dialog.setValue("MyTestProfile");
pressButtonByText(dialog, "OK");
waitForSwing();
assertEquals("MyTestProfile.prf",parseDialog.getCurrentItem().getName());
// test save as forced to an existing profile
runSwing(() -> {
this.setSelectedParseProfile(parseDialog, "VisualStudio12_64.prf");
}, false);
setLanguage(parseDialog, "x86:LE:64:default", "gcc");
runSwing(() -> {
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
}, false);
pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "Yes", false);
dialog = waitForDialogComponent(InputDialog.class);
dialog.setValue("MyTestProfile");
pressButtonByText(dialog, "OK");
waitForSwing();
pressButtonByText(waitForDialogComponent("Overwrite Existing File?"), "Yes", false);
waitForSwing();
assertEquals("MyTestProfile.prf",parseDialog.getCurrentItem().getName());
// test save the current USER profile when switching
runSwing(() -> {
this.setSelectedParseProfile(parseDialog, "MyTestProfile.prf");
}, false);
setLanguage(parseDialog, "8051:BE:16:default", "default");
runSwing(() -> {
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
}, false);
pressButtonByText(waitForDialogComponent("Save Changes to Profile?"), "Yes", false);
assertEquals("VisualStudio12_32.prf",parseDialog.getCurrentItem().getName());
}
private void setLanguage(ParseDialog parseDialog, String langID, String compID) {
runSwing(() -> {
pressButton(parseDialog.getLanguageButton());
}, false);
SetLanguageDialog dlg = waitForDialogComponent(SetLanguageDialog.class);
assertNotNull(dlg);
NewLanguagePanel languagePanel =
(NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
assertNotNull(languagePanel);
waitForSwing();
runSwing(() -> {
NewLanguagePanel selectLangPanel =
(NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
selectLangPanel.setSelectedLcsPair(
new LanguageCompilerSpecPair(new LanguageID(langID), new CompilerSpecID(compID)));
}, true);
waitForSwing();
pressButtonByText(dlg, "OK");
}
// test parse to file, choose file
@Test
public void testImportToFile() throws Exception {
initTool(program);
ParseDialog parseDialog = showParseDialog();
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
setLanguage(parseDialog, "8051:BE:16:default", "default");
final File tmpDir = createTempDirectory("GDT");
FileUtilities.checkedMkdir(tmpDir);
// open an archive
// write out a dummy header file to read
File dummyHeader = this.createTempFile("dummy.h");
FileUtilities.deleteDir(dummyHeader);
String files[] = {dummyHeader.getName()};
this.setFiles(parseDialog, files);
String includePath[] = {dummyHeader.getParent()};
this.setIncludePaths(parseDialog, includePath);
pressButtonByText(parseDialog, "Parse to File...", false);
final GhidraFileChooser fileChooser = waitForDialogComponent(GhidraFileChooser.class);
runSwing(() -> fileChooser.setSelectedFile(new File(tmpDir, "dummy")));
waitForUpdateOnChooser(fileChooser);
pressButtonByName(fileChooser.getComponent(), "OK");
// dummy file empty, error
pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
// dummy file full, OK
FileUtilities.writeStringToFile(dummyHeader,
"typedef int wchar_t;\n" +
"struct mystruct {\n" +
" wchar_t defined_wchar_t;\n" +
"};\n");
this.setFiles(parseDialog, files);
pressButtonByText(parseDialog, "Parse to File...", false);
final GhidraFileChooser existsChooser = waitForDialogComponent(GhidraFileChooser.class);
final File GDTarchiveFile = new File(tmpDir, "dummy.gdt");
runSwing(() -> existsChooser.setSelectedFile(GDTarchiveFile), true);
waitForUpdateOnChooser(existsChooser);
pressButtonByName(existsChooser.getComponent(), "OK");
pressButtonByText(waitForDialogComponent("Overwrite Existing File?"), "Yes", false);
pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
waitForBusyTool(tool);
// open the file archive
FileDataTypeManager fileArchive = FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
try {
DataType dataType =
fileArchive.getDataType("/" + dummyHeader.getName() + "/" + "mystruct");
assertNotNull("mystruct parsed into program", dataType);
}
finally {
fileArchive.close();
}
}
// test parse to file, choose file
@Test
public void testImportToFileUseArchive() throws Exception {
initTool(program);
ParseDialog parseDialog = showParseDialog();
// open an archive
dtmPlugin.openDataTypeArchive("windows_vs12_64");
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
setLanguage(parseDialog, "8051:BE:16:default", "default");
final File tmpDir = createTempDirectory("GDT");
FileUtilities.checkedMkdir(tmpDir);
// open an archive
// write out a dummy header file to read
File dummyHeader = this.createTempFile("dummy.h");
FileUtilities.deleteDir(dummyHeader);
String files[] = {dummyHeader.getName()};
String includePath[] = {dummyHeader.getParent()};
this.setIncludePaths(parseDialog, includePath);
// dummy file full, OK
FileUtilities.writeStringToFile(dummyHeader,
"typedef int wchar_t;\n" +
"struct mystruct {\n" +
" wchar_t defined_wchar_t;\n" +
" wint_t defined_from_windows;\n" +
"};\n");
this.setFiles(parseDialog, files);
pressButtonByText(parseDialog, "Parse to File...", false);
final GhidraFileChooser existsChooser = waitForDialogComponent(GhidraFileChooser.class);
final File GDTarchiveFile = new File(tmpDir, "dummy.gdt");
runSwing(() -> existsChooser.setSelectedFile(GDTarchiveFile), true);
waitForUpdateOnChooser(existsChooser);
pressButtonByName(existsChooser.getComponent(), "OK");
pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Use Open Archives", false);
waitForBusyTool(tool);
pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
// open the file archive
FileDataTypeManager fileArchive = FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
try {
DataType dataType =
fileArchive.getDataType("/" + dummyHeader.getName() + "/" + "mystruct");
assertNotNull("mystruct parsed into program", dataType);
Structure struct = (Structure) dataType;
DataTypeComponent component = struct.getComponent(1);
assertEquals(component.getDataType().getName(), "wint_t");
}
finally {
fileArchive.close();
}
}
private void startSetLanguage(LanguageID languageID, CompilerSpecID compilerSpecID) throws Exception {
if (languageID == null) {
throw new RuntimeException("languageID == null not allowed");
}
if (compilerSpecID == null) {
throw new RuntimeException("compilerSpecID == null not allowed");
}
SetLanguageDialog dlg = waitForDialogComponent(SetLanguageDialog.class);
assertNotNull(dlg);
NewLanguagePanel languagePanel =
(NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
assertNotNull(languagePanel);
waitForSwing();
runSwing(() -> {
NewLanguagePanel selectLangPanel =
(NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
selectLangPanel.setSelectedLcsPair(
new LanguageCompilerSpecPair(languageID, compilerSpecID));
}, true);
waitForSwing();
pressButtonByText(dlg, "OK");
}
private void assertResultDialog() {
Window aboutDialog = waitForWindow(TITLE);
assertNotNull(aboutDialog);
pressButtonByText(aboutDialog, "OK");
}
private ParseDialog showParseDialog() {
//ActionContext actionContext = cbPlugin.getProvider().getActionContext(null);
performAction(cparserAction, false);
ParseDialog parseDialog = waitForDialogComponent(ParseDialog.class);
assertNotNull(parseDialog);
return parseDialog;
}
private void setOption(ParseDialog dialog, String options) {
runSwing(() -> {
JTextArea parseOptionsTextField = dialog.getParseOptionsTextField();
parseOptionsTextField.setText(options);
});
}
private void setIncludePaths(ParseDialog dialog, String paths[]) {
runSwing(() -> {
PathnameTablePanel incPaths = dialog.getIncludePaths();
incPaths.setPaths(paths);
});
}
private void setFiles(ParseDialog dialog, String files[]) {
runSwing(() -> {
PathnameTablePanel sourceFiles = dialog.getSourceFiles();
sourceFiles.setPaths(files);
});
}
private void setSelectedParseProfile(ParseDialog dialog, String profileName) {
runSwing(() -> {
GhidraComboBox<ParseDialog.ComboBoxItem> parseComboBox = dialog.getParseComboBox();
ArrayList<ComboBoxItem> profiles = dialog.getProfiles();
int index = 0;
for (ComboBoxItem comboBoxItem : profiles) {
if (profileName.equals(comboBoxItem.getName())) {
parseComboBox.setSelectedIndex(index);
break;
}
index++;
}
});
}
}

View file

@ -352,17 +352,21 @@ public class ParseDialogTest extends AbstractGhidraHeadedIntegrationTest {
BufferedReader br = new BufferedReader(new InputStreamReader(profileFile.getInputStream())); BufferedReader br = new BufferedReader(new InputStreamReader(profileFile.getInputStream()));
String line = null; String line = null;
while ((line = br.readLine()) != null) {
// read paths
while ((line = br.readLine()) != null && line.trim().length() > 0) {
line = line.trim(); line = line.trim();
if (line.startsWith("-") || (line.length() == 0 && buffy.length() > 0)) {
// this is a compiler directive pathList.add(line);
buffy.append(line + "\n");
}
else if (line.length() > 0) {
File f = new File(line);
pathList.add(f.getPath());
}
} }
// read options
while ((line = br.readLine()) != null && line.trim().length() > 0) {
line = line.trim();
buffy.append(line + "\n");
}
paths = pathList; paths = pathList;
defaultPrfOptions = buffy.toString(); defaultPrfOptions = buffy.toString();

View file

@ -37,10 +37,13 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.StandAloneDataTypeManager.LanguageUpdateOption;
import ghidra.program.model.lang.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv; import ghidra.test.TestEnv;
import ghidra.util.InvalidNameException; import ghidra.util.InvalidNameException;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedIntegrationTest { public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedIntegrationTest {
@ -93,6 +96,45 @@ public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedInte
waitForTree(); 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 { protected void createNewArchive(String archiveName, boolean deleteExisting) throws Exception {
File archiveFile = new File(getTestDirectoryPath(), archiveName); File archiveFile = new File(getTestDirectoryPath(), archiveName);
if (deleteExisting && archiveFile.exists()) { if (deleteExisting && archiveFile.exists()) {
@ -190,10 +232,12 @@ public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedInte
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
SwingUtilities.invokeLater(() -> { if (tool != null) {
ProgramManager pm = tool.getService(ProgramManager.class); SwingUtilities.invokeLater(() -> {
pm.closeProgram(); ProgramManager pm = tool.getService(ProgramManager.class);
}); pm.closeProgram();
});
}
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
// this handles the save changes dialog and potential analysis dialogs // 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.archive.FileArchive;
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode; import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
import ghidra.framework.GenericRunInfo; 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; import ghidra.util.Msg;
public class CreateArchive1Test extends AbstractCreateArchiveTest { public class CreateArchive1Test extends AbstractCreateArchiveTest {
@ -62,6 +64,10 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
createNewArchive(string + FileDataTypeManager.SUFFIX, true); createNewArchive(string + FileDataTypeManager.SUFFIX, true);
ArchiveNode archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive"); ArchiveNode archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
StandAloneDataTypeManager dtm =
(StandAloneDataTypeManager) archiveNode.getCategory().getDataTypeManager();
assertNull(dtm.getProgramArchitecture());
createCategory(archiveNode.getCategory(), "bob"); createCategory(archiveNode.getCategory(), "bob");
waitForTree(); waitForTree();
@ -79,6 +85,9 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
DataTypeTestUtils.performAction(action, tree); DataTypeTestUtils.performAction(action, tree);
waitForTree(); waitForTree();
archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
assertNull(archiveNode);
archiveNode = archiveNode =
DataTypeTestUtils.openArchive(getTestDirectoryPath(), "MyArchive.gdt", false, plugin); DataTypeTestUtils.openArchive(getTestDirectoryPath(), "MyArchive.gdt", false, plugin);
assertNotNull(archiveNode.getChild("bob")); assertNotNull(archiveNode.getChild("bob"));
@ -88,6 +97,65 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
f.deleteOnExit(); 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 @Test
public void testCreateArchiveNameCollision1() throws Exception { public void testCreateArchiveNameCollision1() throws Exception {
// create archive // create archive

View file

@ -27,6 +27,7 @@ import generic.jar.ResourceFile;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
public class DataTypeArchiveIDTest extends AbstractGenericTest { public class DataTypeArchiveIDTest extends AbstractGenericTest {
@ -68,6 +69,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
notFound.remove(path); notFound.remove(path);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false); FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try { try {
assertEquals("Archive UniversalID mismatch: " + path, oldID, assertEquals("Archive UniversalID mismatch: " + path, oldID,
dtm.getUniversalID().toString()); dtm.getUniversalID().toString());
@ -101,6 +103,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckWindowsVS12_32() throws IOException { public void spotCheckWindowsVS12_32() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(WIN_VS12_32_GDT_PATH); ResourceFile gdtFile = Application.getModuleDataFile(WIN_VS12_32_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false); FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try { try {
DataType dt = dtm.getDataType("/winsock.h/fd_set"); DataType dt = dtm.getDataType("/winsock.h/fd_set");
assertNotNull(dt); assertNotNull(dt);
@ -117,6 +120,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckWindowsVS12_64() throws IOException { public void spotCheckWindowsVS12_64() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(WIN_VS12_64_GDT_PATH); ResourceFile gdtFile = Application.getModuleDataFile(WIN_VS12_64_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false); FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try { try {
DataType dt = dtm.getDataType("/winsock.h/fd_set"); DataType dt = dtm.getDataType("/winsock.h/fd_set");
assertNotNull(dt); assertNotNull(dt);
@ -132,6 +136,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckGenericCLib32() throws IOException { public void spotCheckGenericCLib32() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(GENERIC_CLIB_32_GDT_PATH); ResourceFile gdtFile = Application.getModuleDataFile(GENERIC_CLIB_32_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false); FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try { try {
DataType dt = dtm.getDataType("/select.h/fd_set"); DataType dt = dtm.getDataType("/select.h/fd_set");
assertNotNull(dt); assertNotNull(dt);
@ -147,6 +152,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckGenericCLib64() throws IOException { public void spotCheckGenericCLib64() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(GENERIC_CLIB_64_GDT_PATH); ResourceFile gdtFile = Application.getModuleDataFile(GENERIC_CLIB_64_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false); FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try { try {
DataType dt = dtm.getDataType("/select.h/fd_set"); DataType dt = dtm.getDataType("/select.h/fd_set");
assertNotNull(dt); assertNotNull(dt);
@ -162,6 +168,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
public void spotCheckMacOS10_9() throws IOException { public void spotCheckMacOS10_9() throws IOException {
ResourceFile gdtFile = Application.getModuleDataFile(MAC_OS_10_9_GDT_PATH); ResourceFile gdtFile = Application.getModuleDataFile(MAC_OS_10_9_GDT_PATH);
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false); FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
try { try {
DataType dt = dtm.getDataType("/_fd_def.h/fd_set"); DataType dt = dtm.getDataType("/_fd_def.h/fd_set");
assertNotNull(dt); assertNotNull(dt);

View file

@ -25,6 +25,7 @@ import ghidra.program.database.ProgramDB;
import ghidra.program.model.FunctionTestDouble; import ghidra.program.model.FunctionTestDouble;
import ghidra.program.model.TestDoubleFunctionSignature; import ghidra.program.model.TestDoubleFunctionSignature;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.test.*; import ghidra.test.*;
@ -118,11 +119,9 @@ public class EditFunctionSignatureDialogTest extends AbstractGhidraHeadedIntegra
//================================================================================================== //==================================================================================================
private class LocalFunctionStub extends FunctionTestDouble { private class LocalFunctionStub extends FunctionTestDouble {
private DataType returnType;
public LocalFunctionStub(String name, String signature) { public LocalFunctionStub(String name, String signature) {
super("Name", new LocalFunctionSignatureTestDouble(name, signature)); super("Name", new LocalFunctionSignatureTestDouble(name, signature));
this.returnType = returnType;
} }
@Override @Override
@ -132,7 +131,7 @@ public class EditFunctionSignatureDialogTest extends AbstractGhidraHeadedIntegra
@Override @Override
public String getCallingConventionName() { public String getCallingConventionName() {
return GenericCallingConvention.stdcall.toString(); return CompilerSpec.CALLING_CONVENTION_stdcall;
} }
@Override @Override

View file

@ -1113,6 +1113,11 @@ public class DataTypeSelectionDialogTest extends AbstractGhidraHeadedIntegration
SourceArchive sourceArchive) { SourceArchive sourceArchive) {
// don't care for now // don't care for now
} }
@Override
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
// don't care for now
}
} }
private class CustomDataType extends StructureDataType { private class CustomDataType extends StructureDataType {

View file

@ -908,5 +908,10 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
SourceArchive dataTypeSource) { SourceArchive dataTypeSource) {
// don't care // 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 { public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
private ProgramDB program; private ProgramDB program;
private ProgramBasedDataTypeManager dataMgr;
private Listing listing; private Listing listing;
private ProgramBasedDataTypeManager dataMgr;
private AddressSpace space; private AddressSpace space;
private int transactionID; private int transactionID;
@ -62,11 +62,12 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this); program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
listing = program.getListing();
space = program.getAddressFactory().getDefaultAddressSpace(); space = program.getAddressFactory().getDefaultAddressSpace();
dataMgr = program.getDataTypeManager(); dataMgr = program.getDataTypeManager();
listing = program.getListing();
transactionID = program.startTransaction("Test"); transactionID = program.startTransaction("Test");
addBlock(); addBlock();
// pointer-typedef has the largest // pointer-typedef has the largest
// System.out.println("Defined string settings:"); // System.out.println("Defined string settings:");
// for (SettingsDefinition def : StringDataType.dataType.getSettingsDefinitions()) { // for (SettingsDefinition def : StringDataType.dataType.getSettingsDefinitions()) {
@ -164,8 +165,8 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testIsEmpty() throws Exception { public void testIsEmpty() throws Exception {
Data data = listing.getDataAt(addr(10)); DataType dt = dataMgr.resolve(StringDataType.dataType, null);
Settings defaultSettings = data.getDataType().getDefaultSettings(); Settings defaultSettings = dt.getDefaultSettings();
defaultSettings.setString(STRING_SETTING_NAME, "red"); defaultSettings.setString(STRING_SETTING_NAME, "red");
defaultSettings.setLong(LONG_SETTING_NAME, 10); defaultSettings.setLong(LONG_SETTING_NAME, 10);
@ -390,7 +391,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testDefaultSettingsOnTypedef() throws Exception { public void testDefaultSettingsOnTypedef() throws Exception {
DataType byteDT = dataMgr.resolve(new ByteDataType(), null); DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
SettingsDefinition[] settingsDefinitions = byteDT.getSettingsDefinitions(); SettingsDefinition[] settingsDefinitions = byteDT.getSettingsDefinitions();
Settings settings = byteDT.getDefaultSettings(); Settings settings = byteDT.getDefaultSettings();
FormatSettingsDefinition.DEF.setChoice(settings, FormatSettingsDefinition.OCTAL); FormatSettingsDefinition.DEF.setChoice(settings, FormatSettingsDefinition.OCTAL);
@ -418,7 +419,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testDefaultSettingsOnTypedef2() throws Exception { public void testDefaultSettingsOnTypedef2() throws Exception {
DataType byteDT = dataMgr.resolve(new ByteDataType(), null); DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
Settings settings = byteDT.getDefaultSettings(); Settings settings = byteDT.getDefaultSettings();
TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT); TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT);
@ -438,7 +439,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testDefaultSettingsOnTypedefUndoRedo() throws Exception { public void testDefaultSettingsOnTypedefUndoRedo() throws Exception {
DataType byteDT = dataMgr.resolve(new ByteDataType(), null); DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
Settings settings = byteDT.getDefaultSettings(); Settings settings = byteDT.getDefaultSettings();
settings.setLong("format", FormatSettingsDefinition.OCTAL); settings.setLong("format", FormatSettingsDefinition.OCTAL);
endTransaction(); endTransaction();
@ -466,7 +467,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testDefaultSettingsOnDeletedTypdef() throws Exception { public void testDefaultSettingsOnDeletedTypdef() throws Exception {
DataType byteDT = dataMgr.resolve(new ByteDataType(), null); DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
Settings settings = byteDT.getDefaultSettings(); Settings settings = byteDT.getDefaultSettings();
settings.setLong("format", FormatSettingsDefinition.OCTAL); settings.setLong("format", FormatSettingsDefinition.OCTAL);

View file

@ -17,8 +17,8 @@ package ghidra.program.database.function;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import org.junit.*; import org.junit.*;
@ -453,25 +453,12 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals(defaultModel, protoModel); assertEquals(defaultModel, protoModel);
} }
@Test
public void testGetCallingConventions() throws Exception {
PrototypeModel[] protoModels = functionManager.getCallingConventions();
assertTrue(protoModels.length >= 1);
}
@Test @Test
public void testGetCallingConventionNames() throws Exception { public void testGetCallingConventionNames() throws Exception {
Collection<String> names = functionManager.getCallingConventionNames();
List<String> names = functionManager.getCallingConventionNames();
assertTrue(names.size() >= 1); assertTrue(names.size() >= 1);
for (String name : names) { for (String name : names) {
if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) { assertNotNull(functionManager.getCallingConvention(name));
assertNull(functionManager.getCallingConvention(name));
}
else {
assertNotNull(functionManager.getCallingConvention(name));
}
} }
} }

View file

@ -15,10 +15,7 @@
*/ */
package ghidra.app.util.cparser; package ghidra.app.util.cparser;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; 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.CParser;
import ghidra.app.util.cparser.C.ParseException; import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.Array; import ghidra.program.model.data.*;
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.Enum; import ghidra.program.model.data.Enum;
import ghidra.program.model.data.FunctionDefinition; import ghidra.program.model.lang.CompilerSpec;
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.test.AbstractGhidraHeadlessIntegrationTest; import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class CParserTest extends AbstractGhidraHeadlessIntegrationTest { public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
@ -246,11 +222,11 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
String parseMessages = parser.getParseMessages(); String parseMessages = parser.getParseMessages();
System.out.println(parseMessages); System.out.println(parseMessages);
assertTrue("Duplicate ENUM message", parseMessages.contains("duplicate enum value: options_enum : PLUS_SET : 16")); assertTrue("Duplicate ENUM message missing", parseMessages.contains("duplicate enum value: options_enum : PLUS_SET : 16"));
assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\"")); assertTrue("Duplicate ENUM message missing", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\""));
assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\"")); assertTrue("Duplicate ENUM message missing", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\""));
DataType dt; DataType dt;
DataType pointedToDT; DataType pointedToDT;
@ -285,14 +261,14 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
funcDef = (FunctionDefinition) dt; funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString(); str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _Once(_Once_t * , _func_anon_ * )", replaceAnonFuncName(str)); 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(); funcArgs = funcDef.getArguments();
assertTrue("struct fstruct", funcArgs[0].getDataType() instanceof Pointer); assertTrue("struct fstruct", funcArgs[0].getDataType() instanceof Pointer);
assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer); assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer);
pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType(); pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT; funcDef = (FunctionDefinition) pointedToDT;
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName()); assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
str = funcDef.getPrototypeString(); str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str)); 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); assertTrue("_Twice function definition", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt; funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString(); str = funcDef.getPrototypeString();
assertEquals("calling convention _Twice", "__stdcall", funcDef.getGenericCallingConvention().getDeclarationName()); assertEquals("calling convention _Twice", "__stdcall", funcDef.getCallingConventionName());
funcArgs = funcDef.getArguments(); funcArgs = funcDef.getArguments();
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType(); pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT; funcDef = (FunctionDefinition) pointedToDT;
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName()); assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
str = funcDef.getPrototypeString(); str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str)); 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); assertTrue("_Twice function definition", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt; funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString(); str = funcDef.getPrototypeString();
assertEquals("calling convention _Thrice", "", funcDef.getGenericCallingConvention().getDeclarationName()); assertEquals("calling convention _Thrice", "unknown", funcDef.getCallingConventionName());
funcArgs = funcDef.getArguments(); funcArgs = funcDef.getArguments();
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType(); pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT; funcDef = (FunctionDefinition) pointedToDT;
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName()); assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
str = funcDef.getPrototypeString(); str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str)); assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
@ -368,22 +344,34 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
dt = dtMgr.getDataType(new CategoryPath("/functions"), "stdcall_func"); dt = dtMgr.getDataType(new CategoryPath("/functions"), "stdcall_func");
assertTrue("not a function", dt instanceof FunctionDefinition); assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString(); str = ((FunctionDefinition) dt).getPrototypeString();
assertTrue("Callee should not purge", ((FunctionDefinition) dt) assertTrue("Callee should not purge", CompilerSpec.CALLING_CONVENTION_stdcall
.getGenericCallingConvention() == GenericCallingConvention.stdcall); .equals(((FunctionDefinition) dt).getCallingConventionName()));
assertTrue("signature not correct", str.equals("int stdcall_func(int b)")); assertTrue("signature not correct", str.equals("int stdcall_func(int b)"));
dt = dtMgr.getDataType(new CategoryPath("/functions"), "cdecl_func"); dt = dtMgr.getDataType(new CategoryPath("/functions"), "cdecl_func");
assertTrue("not a function", dt instanceof FunctionDefinition); assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString(); str = ((FunctionDefinition) dt).getPrototypeString();
assertTrue("Caller should purge", ((FunctionDefinition) dt) assertTrue("Caller should purge", CompilerSpec.CALLING_CONVENTION_cdecl
.getGenericCallingConvention() != GenericCallingConvention.stdcall); .equals(((FunctionDefinition) dt).getCallingConventionName()));
assertTrue("signature not correct", str.equals("int cdecl_func(int a)")); assertTrue("signature not correct", str.equals("int cdecl_func(int a)"));
dt = dtMgr.getDataType(new CategoryPath("/functions"), "cdecl_func_after"); dt = dtMgr.getDataType(new CategoryPath("/functions"), "cdecl_func_after");
assertTrue("not a function", dt instanceof FunctionDefinition); assertTrue("not a function", dt instanceof FunctionDefinition);
assertTrue("Caller should purge", ((FunctionDefinition) dt) assertTrue("Caller should purge", CompilerSpec.CALLING_CONVENTION_cdecl
.getGenericCallingConvention() != GenericCallingConvention.stdcall); .equals(((FunctionDefinition) dt).getCallingConventionName()));
dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Noreturn_exit");
assertTrue("not a function", dt instanceof FunctionDefinition);
assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
dt = dtMgr.getDataType(new CategoryPath("/functions"), "win_exit");
assertTrue("not a function", dt instanceof FunctionDefinition);
assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
dt = dtMgr.getDataType(new CategoryPath("/functions"), "gcc_exit");
assertTrue("not a function", dt instanceof FunctionDefinition);
assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
dt = dtMgr.getDataType(new CategoryPath("/"), "UINT2"); dt = dtMgr.getDataType(new CategoryPath("/"), "UINT2");
assertTrue(dt instanceof TypeDef); assertTrue(dt instanceof TypeDef);
assertEquals("ushort", ((TypeDef) dt).getBaseDataType().getName()); assertEquals("ushort", ((TypeDef) dt).getBaseDataType().getName());

View file

@ -48,8 +48,11 @@ public class PreProcessorTest extends AbstractGenericTest {
super(); super();
} }
@BeforeClass @Before
public static void init() { public void init() {
if (dtMgr != null) {
return; // do only once - but not too soon
}
URL url = PreProcessorTest.class.getResource(resourceName); URL url = PreProcessorTest.class.getResource(resourceName);
String[] args = new String[] { "-I" + url.getPath() + "/..", "-DFROM_ARG_VALUE=300", 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.io.*;
import java.util.HashMap; 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.CParser;
import ghidra.app.util.cparser.C.ParseException; import ghidra.app.util.cparser.C.ParseException;
import ghidra.util.Msg; import ghidra.util.Msg;
import resources.ResourceManager; import resources.ResourceManager;
abstract class AbstractCompositeTest extends AbstractGTest { abstract class AbstractCompositeTest extends AbstractGenericTest {
private HashMap<Long, DataType> copyMap = new HashMap<>(); 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.apache.commons.compress.utils.Sets;
import org.junit.*; import org.junit.*;
import generic.test.AbstractGTest; import generic.test.AbstractGenericTest;
/** /**
* *
*/ */
public class StructureDataTypeTest extends AbstractGTest { public class StructureDataTypeTest extends AbstractGenericTest {
private Structure struct; private Structure struct;

View file

@ -21,12 +21,12 @@ import org.junit.*;
import com.google.common.collect.Sets; 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; private Union union;

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