mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Merge branch 'GP-2308_1633_ghidra1_FunctionDefinitionCallingConventions'
(Closes #4537, Closes #4898, Closes #3723, Closes #3267)
This commit is contained in:
commit
2cdaebf0c3
273 changed files with 8249 additions and 3415 deletions
|
@ -264,9 +264,9 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
|
|||
// TODO: Does the decompiler communicate the inferred calling convention?
|
||||
try {
|
||||
PrototypeModel convention = program.getCompilerSpec().findBestCallingConvention(params);
|
||||
sig.setGenericCallingConvention(convention.getGenericCallingConvention());
|
||||
sig.setCallingConvention(convention.getName());
|
||||
}
|
||||
catch (SleighException e) {
|
||||
catch (SleighException | InvalidInputException e) {
|
||||
// Whatever, just leave sig at "unknown"
|
||||
}
|
||||
return sig;
|
||||
|
@ -352,7 +352,7 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
|
|||
throw new PcodeExecutionException("Cannot get stack change for indirect call: " + op);
|
||||
}
|
||||
PrototypeModel convention =
|
||||
program.getCompilerSpec().matchConvention(sig.getGenericCallingConvention());
|
||||
program.getCompilerSpec().matchConvention(sig.getCallingConventionName());
|
||||
if (convention == null) {
|
||||
warnings.add(new UnspecifiedConventionStackUnwindWarning(null));
|
||||
convention = program.getCompilerSpec().getDefaultCallingConvention();
|
||||
|
|
|
@ -24,7 +24,9 @@ import db.DBHandle;
|
|||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceManager;
|
||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||
|
@ -38,15 +40,36 @@ import ghidra.util.task.TaskMonitor;
|
|||
public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||
implements TraceBasedDataTypeManager, DBTraceManager {
|
||||
|
||||
protected final ReadWriteLock lock;
|
||||
protected final ReadWriteLock lock; // TODO: This lock object is not used
|
||||
protected final DBTrace trace;
|
||||
|
||||
private static final String INSTANCE_TABLE_PREFIX = null; // placeholder only
|
||||
|
||||
public DBTraceDataTypeManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
||||
TaskMonitor monitor, DBTrace trace)
|
||||
throws CancelledException, VersionException, IOException {
|
||||
super(dbh, null, openMode.toInteger(), trace, trace.getLock(), monitor);
|
||||
super(dbh, null, openMode.toInteger(), INSTANCE_TABLE_PREFIX, trace, trace.getLock(),
|
||||
monitor);
|
||||
this.lock = lock; // TODO: nothing uses this local lock - not sure what its purpose is
|
||||
this.trace = trace;
|
||||
|
||||
setProgramArchitecture(new ProgramArchitecture() {
|
||||
|
||||
@Override
|
||||
public Language getLanguage() {
|
||||
return trace.getBaseLanguage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilerSpec getCompilerSpec() {
|
||||
return trace.getBaseCompilerSpec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressFactory getAddressFactory() {
|
||||
return trace.getBaseAddressFactory();
|
||||
}
|
||||
}, null, false, monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -233,12 +256,4 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
|||
*/
|
||||
return ArchiveType.PROGRAM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataOrganization getDataOrganization() {
|
||||
if (dataOrganization == null) {
|
||||
dataOrganization = trace.getBaseCompilerSpec().getDataOrganization();
|
||||
}
|
||||
return dataOrganization;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
*/
|
||||
package ghidra.trace.database.program;
|
||||
|
||||
import static ghidra.lifecycle.Unfinished.TODO;
|
||||
import static ghidra.lifecycle.Unfinished.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import generic.NestedIterator;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
|
@ -64,7 +64,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<String> getCallingConventionNames() {
|
||||
public Collection<String> getCallingConventionNames() {
|
||||
return functions.getCallingConventionNames();
|
||||
}
|
||||
|
||||
|
@ -78,11 +78,6 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
|||
return functions.getCallingConvention(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel[] getCallingConventions() {
|
||||
return functions.getCallingConventions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body,
|
||||
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
|
|||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -33,6 +34,7 @@ import ghidra.program.model.symbol.*;
|
|||
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec;
|
||||
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
|
||||
import ghidra.trace.database.bookmark.DBTraceBookmarkType;
|
||||
import ghidra.trace.database.data.DBTraceDataTypeManager;
|
||||
import ghidra.trace.database.listing.DBTraceCommentAdapter;
|
||||
import ghidra.trace.database.listing.DBTraceData;
|
||||
import ghidra.trace.database.program.DBTraceProgramView;
|
||||
|
@ -122,7 +124,7 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
|
|||
@DBAnnotatedField(column = FIXUP_COLUMN_NAME)
|
||||
protected String callFixup;
|
||||
@DBAnnotatedField(column = CALLING_CONVENTION_COLUMN_NAME)
|
||||
protected byte callingConventionID = DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_ID;
|
||||
protected byte callingConventionID = DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID;
|
||||
// TODO: Pack into flags if more bits needed
|
||||
@DBAnnotatedField(column = SIGNATURE_SOURCE_COLUMN_NAME)
|
||||
protected SourceType signatureSource = SourceType.ANALYSIS; // Assumed default, 0-ordinal
|
||||
|
@ -484,7 +486,8 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
|
|||
}
|
||||
|
||||
protected boolean hasExplicitCallingConvention() {
|
||||
return callingConventionID != -1 && callingConventionID != -2;
|
||||
return callingConventionID != DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID &&
|
||||
callingConventionID != DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1734,16 +1737,14 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
|
|||
if (cs == null) {
|
||||
return null;
|
||||
}
|
||||
if (DBTraceSymbolManager.UNKNOWN_CALLING_CONVENTION_ID == callingConventionID) {
|
||||
DBTraceDataTypeManager dtm = manager.dataTypeManager;
|
||||
if (callingConventionID == DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID) {
|
||||
return null;
|
||||
}
|
||||
if (DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_ID == callingConventionID) {
|
||||
if (callingConventionID == DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID) {
|
||||
return cs.getDefaultCallingConvention();
|
||||
}
|
||||
String ccName = manager.callingConventionMap.getKey(callingConventionID);
|
||||
if (ccName == null) {
|
||||
return null;
|
||||
}
|
||||
String ccName = dtm.getCallingConventionName(callingConventionID);
|
||||
return cs.getCallingConvention(ccName);
|
||||
}
|
||||
}
|
||||
|
@ -1751,28 +1752,8 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
|
|||
@Override
|
||||
public String getCallingConventionName() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
if (DBTraceSymbolManager.UNKNOWN_CALLING_CONVENTION_ID == callingConventionID) {
|
||||
return null;
|
||||
}
|
||||
if (DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_ID == callingConventionID) {
|
||||
return DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_NAME;
|
||||
}
|
||||
return manager.callingConventionMap.getKey(callingConventionID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultCallingConventionName() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
PrototypeModel cc = manager.functions.getDefaultCallingConvention();
|
||||
if (cc == null) {
|
||||
return DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_NAME;
|
||||
}
|
||||
String ccName = cc.getName();
|
||||
if (ccName == null) { // Really?
|
||||
return DBTraceSymbolManager.DEFAULT_CALLING_CONVENTION_NAME;
|
||||
}
|
||||
return ccName;
|
||||
DBTraceDataTypeManager dtm = manager.dataTypeManager;
|
||||
return dtm.getCallingConventionName(callingConventionID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1783,12 +1764,16 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
|
|||
thunked.setCallingConvention(name);
|
||||
return;
|
||||
}
|
||||
if (Objects.equals(getCallingConventionName(), name)) {
|
||||
return;
|
||||
|
||||
DBTraceDataTypeManager dtm = manager.dataTypeManager;
|
||||
byte id = dtm.getCallingConventionID(name, true);
|
||||
if (id == callingConventionID) {
|
||||
return; // no change
|
||||
}
|
||||
|
||||
doLoadVariables();
|
||||
|
||||
this.callingConventionID = manager.findOrRecordCallingConvention(name);
|
||||
callingConventionID = id;
|
||||
update(CALLING_CONVENTION_COLUMN);
|
||||
|
||||
boolean hasCustomStorage = hasCustomVariableStorage();
|
||||
|
@ -1813,11 +1798,14 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
|
|||
new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), this));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
manager.dbError(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void createClassStructIfNeeded() {
|
||||
PrototypeModel cc = getCallingConvention();
|
||||
if (cc == null || cc.getGenericCallingConvention() != GenericCallingConvention.thiscall) {
|
||||
if (cc == null || !CompilerSpec.CALLING_CONVENTION_thiscall.equals(cc.getName())) {
|
||||
return;
|
||||
}
|
||||
Namespace parentNS = getParentNamespace();
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.trace.database.symbol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.database.symbol.OverlappingNamespaceException;
|
||||
|
@ -165,54 +164,19 @@ public class DBTraceFunctionSymbolView
|
|||
}
|
||||
}
|
||||
|
||||
public static List<String> getCallingConventionNames(CompilerSpec cs) {
|
||||
PrototypeModel[] namedCCs = cs.getCallingConventions();
|
||||
List<String> names = new ArrayList<>(2 + namedCCs.length);
|
||||
names.add(Function.UNKNOWN_CALLING_CONVENTION_STRING);
|
||||
names.add(Function.DEFAULT_CALLING_CONVENTION_STRING);
|
||||
for (PrototypeModel model : namedCCs) {
|
||||
names.add(model.getName());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getCallingConventionNames() {
|
||||
// TODO: Allow for user-selected compiler spec(s)
|
||||
return getCallingConventionNames(manager.trace.getBaseCompilerSpec());
|
||||
public Collection<String> getCallingConventionNames() {
|
||||
return manager.dataTypeManager.getDefinedCallingConventionNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel getDefaultCallingConvention() {
|
||||
CompilerSpec cs = manager.trace.getBaseCompilerSpec();
|
||||
if (cs == null) {
|
||||
return null;
|
||||
}
|
||||
return cs.getDefaultCallingConvention();
|
||||
return manager.dataTypeManager.getDefaultCallingConvention();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel getCallingConvention(String name) {
|
||||
CompilerSpec cs = manager.trace.getBaseCompilerSpec();
|
||||
if (cs == null) {
|
||||
return null;
|
||||
}
|
||||
if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
|
||||
return null;
|
||||
}
|
||||
if (Function.DEFAULT_CALLING_CONVENTION_STRING.equals(name)) {
|
||||
return cs.getDefaultCallingConvention();
|
||||
}
|
||||
return cs.getCallingConvention(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel[] getCallingConventions() {
|
||||
CompilerSpec cs = manager.trace.getBaseCompilerSpec();
|
||||
if (cs == null) {
|
||||
return EMPTY_MODEL_LIST;
|
||||
}
|
||||
return cs.getCallingConventions();
|
||||
return manager.dataTypeManager.getCallingConvention(name);
|
||||
}
|
||||
|
||||
// TODO: Move this into a FunctionUtilities class?
|
||||
|
|
|
@ -20,9 +20,6 @@ import java.lang.reflect.Field;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import org.apache.commons.collections4.BidiMap;
|
||||
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
@ -60,11 +57,6 @@ import ghidra.util.task.TaskMonitor;
|
|||
* TODO: See if CALL-type references produce dynamic labels or functions.
|
||||
*/
|
||||
public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager {
|
||||
protected static final byte DEFAULT_CALLING_CONVENTION_ID = -1;
|
||||
protected static final byte UNKNOWN_CALLING_CONVENTION_ID = -2;
|
||||
|
||||
protected static final String DEFAULT_CALLING_CONVENTION_NAME = "default";
|
||||
protected static final String UNKNOWN_CALLING_CONVENTION_NAME = "unknown";
|
||||
|
||||
private static final long TYPE_MASK = 0xFF;
|
||||
private static final int TYPE_SHIFT = 64 - 8;
|
||||
|
@ -101,32 +93,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
}
|
||||
}
|
||||
|
||||
@DBAnnotatedObjectInfo(version = 0)
|
||||
public static class DBTraceCallingConventionEntry extends DBAnnotatedObject {
|
||||
static final String TABLE_NAME = "CallingConventions";
|
||||
|
||||
static final String NAME_COLUMN_NAME = "Name";
|
||||
|
||||
@DBAnnotatedColumn(NAME_COLUMN_NAME)
|
||||
static DBObjectColumn NAME_COLUMN;
|
||||
|
||||
@DBAnnotatedField(column = NAME_COLUMN_NAME)
|
||||
String name;
|
||||
|
||||
public DBTraceCallingConventionEntry(DBCachedObjectStore<?> store, DBRecord record) {
|
||||
super(store, record);
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
update(NAME_COLUMN);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@DBAnnotatedObjectInfo(version = 0)
|
||||
public static class DBTraceFunctionTag extends DBAnnotatedObject implements FunctionTag {
|
||||
|
||||
|
@ -435,9 +401,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
|
||||
protected final DBTraceAddressSnapRangePropertyMap<Long, DBTraceSymbolIDEntry> idMap;
|
||||
|
||||
protected final DBCachedObjectStore<DBTraceCallingConventionEntry> callingConventionStore;
|
||||
protected final BidiMap<String, Byte> callingConventionMap = new DualHashBidiMap<>();
|
||||
|
||||
protected final DBCachedObjectStore<DBTraceFunctionTag> tagStore;
|
||||
protected final DBCachedObjectIndex<String, DBTraceFunctionTag> tagsByName;
|
||||
|
||||
|
@ -494,11 +457,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
baseLanguage, trace, threadManager, DBTraceSymbolIDEntry.class,
|
||||
DBTraceSymbolIDEntry::new);
|
||||
|
||||
callingConventionStore =
|
||||
factory.getOrCreateCachedStore(DBTraceCallingConventionEntry.TABLE_NAME,
|
||||
DBTraceCallingConventionEntry.class, DBTraceCallingConventionEntry::new, true);
|
||||
loadCallingConventions();
|
||||
|
||||
tagStore = factory.getOrCreateCachedStore(DBTraceFunctionTag.TABLE_NAME,
|
||||
DBTraceFunctionTag.class, (s, r) -> new DBTraceFunctionTag(this, s, r), true);
|
||||
tagsByName = tagStore.getIndex(String.class, DBTraceFunctionTag.NAME_COLUMN);
|
||||
|
@ -570,9 +528,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
if (ptrSize != dataTypeManager.getDataOrganization().getPointerSize()) {
|
||||
return dataTypeManager.getPointer(formal, ptrSize);
|
||||
}
|
||||
else {
|
||||
return dataTypeManager.getPointer(formal);
|
||||
}
|
||||
return dataTypeManager.getPointer(formal);
|
||||
}
|
||||
|
||||
protected <T extends AbstractDBTraceSymbolSingleTypeView<?>> T putInMap(T view) {
|
||||
|
@ -608,25 +564,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
return (symbolID >> KEY_SHIFT) & KEY_MASK;
|
||||
}
|
||||
|
||||
protected void loadCallingConventions() {
|
||||
// NOTE: Should already own write lock
|
||||
for (DBTraceCallingConventionEntry ent : callingConventionStore.asMap().values()) {
|
||||
// NOTE: No need to check. Only called on new or invalidate.
|
||||
callingConventionMap.put(ent.name, (byte) ent.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
protected byte doRecordCallingConvention(String name) {
|
||||
DBTraceCallingConventionEntry ent = callingConventionStore.create();
|
||||
ent.setName(name);
|
||||
return (byte) ent.getKey();
|
||||
}
|
||||
|
||||
protected byte findOrRecordCallingConvention(String name) {
|
||||
// NOTE: Must already have write lock
|
||||
return callingConventionMap.computeIfAbsent(name, this::doRecordCallingConvention);
|
||||
}
|
||||
|
||||
protected int findOrRecordVariableStorage(VariableStorage storage) {
|
||||
DBTraceVariableStorageEntry entry = storageByStorage.getOne(storage);
|
||||
if (entry == null) {
|
||||
|
@ -645,9 +582,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
public void invalidateCache(boolean all) {
|
||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||
idMap.invalidateCache(all);
|
||||
callingConventionStore.invalidateCache();
|
||||
callingConventionMap.clear();
|
||||
loadCallingConventions();
|
||||
|
||||
for (AbstractDBTraceSymbolSingleTypeView<?> view : symbolViews.values()) {
|
||||
view.invalidateCache();
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.trace.model.symbol;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
@ -37,11 +37,30 @@ public interface TraceFunctionSymbolView extends TraceSymbolWithLocationView<Tra
|
|||
return add(Lifespan.nowOn(snap), entryPoint, body, name, thunked, parent, source);
|
||||
}
|
||||
|
||||
PrototypeModel[] getCallingConventions();
|
||||
|
||||
List<String> getCallingConventionNames();
|
||||
/**
|
||||
* Get the ordered unmodifiable set of defined calling convention names. The reserved names
|
||||
* "unknown" and "default" are not included. The returned collection may not include all names
|
||||
* referenced by various functions and function-definitions. This set is limited to
|
||||
* those defined by the associated compiler specification.
|
||||
*
|
||||
* @return the set of defined calling convention names.
|
||||
*/
|
||||
Collection<String> getCallingConventionNames();
|
||||
|
||||
/**
|
||||
* Get the default calling convention's prototype model.
|
||||
*
|
||||
* @return the default calling convention prototype model.
|
||||
*/
|
||||
PrototypeModel getDefaultCallingConvention();
|
||||
|
||||
/**
|
||||
* Get the prototype model of the calling convention with the specified name from the
|
||||
* associated compiler specification. If {@link Function#DEFAULT_CALLING_CONVENTION_STRING}
|
||||
* is specified {@link #getDefaultCallingConvention()} will be returned.
|
||||
*
|
||||
* @param name the calling convention name
|
||||
* @return the named function calling convention prototype model or null if not defined.
|
||||
*/
|
||||
PrototypeModel getCallingConvention(String name);
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ import static ghidra.lifecycle.Unfinished.*;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
|
@ -423,25 +423,12 @@ public class DBTraceProgramViewFunctionManagerTest extends AbstractGhidraHeadles
|
|||
assertEquals(defaultModel, protoModel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCallingConventions() throws Exception {
|
||||
PrototypeModel[] protoModels = functionManager.getCallingConventions();
|
||||
assertTrue(protoModels.length >= 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCallingConventionNames() throws Exception {
|
||||
|
||||
List<String> names = functionManager.getCallingConventionNames();
|
||||
Collection<String> names = functionManager.getCallingConventionNames();
|
||||
assertTrue(names.size() >= 1);
|
||||
|
||||
for (String name : names) {
|
||||
if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
|
||||
assertNull(functionManager.getCallingConvention(name));
|
||||
}
|
||||
else {
|
||||
assertNotNull(functionManager.getCallingConvention(name));
|
||||
}
|
||||
assertNotNull(functionManager.getCallingConvention(name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,9 @@ data/parserprofiles/MacOSX_10.9.prf||GHIDRA||||END|
|
|||
data/parserprofiles/MacOSX_Cocoa.prf||GHIDRA||||END|
|
||||
data/parserprofiles/VisualStudio12_32.prf||GHIDRA||||END|
|
||||
data/parserprofiles/VisualStudio12_64.prf||GHIDRA||||END|
|
||||
data/parserprofiles/VisualStudio9.prf||GHIDRA||reviewed||END|
|
||||
data/parserprofiles/clib.prf||GHIDRA||reviewed||END|
|
||||
data/parserprofiles/VisualStudio22_64.prf||GHIDRA||||END|
|
||||
data/parserprofiles/VisualStudio9.prf||GHIDRA||||END|
|
||||
data/parserprofiles/clib.prf||GHIDRA||||END|
|
||||
data/parserprofiles/generic_clib_32.prf||GHIDRA||||END|
|
||||
data/parserprofiles/generic_clib_64.prf||GHIDRA||||END|
|
||||
data/parserprofiles/linux_32.prf||GHIDRA||||END|
|
||||
|
|
|
@ -207,7 +207,6 @@ zlib.h
|
|||
-DTARGET_API_MAC_OSX
|
||||
-DTARGET_COCOA
|
||||
-DHANDLE="unsigned long"
|
||||
-D_WCHAR_T
|
||||
-D_Complex
|
||||
-Drestrict
|
||||
-D__restrict
|
||||
|
|
|
@ -323,7 +323,6 @@ zlib.h
|
|||
-D_MAC_
|
||||
-DTARGET_API_MAC_OSX
|
||||
-DHANDLE="unsigned long"
|
||||
-D_WCHAR_T
|
||||
-D_Complex
|
||||
-Drestrict
|
||||
-D__restrict
|
||||
|
|
|
@ -28,7 +28,6 @@ Cocoa\Cocoa.h
|
|||
-D_MAC_
|
||||
-DTARGET_API_MAC_OSX=1
|
||||
-DHANDLE="unsigned long"
|
||||
-D_WCHAR_T
|
||||
-D_Complex
|
||||
-Drestrict
|
||||
-D__restrict
|
||||
|
|
|
@ -172,12 +172,8 @@ wpcapi.h
|
|||
wscapi.h
|
||||
wsdapi.h
|
||||
wspiapi.h
|
||||
|
||||
rpcproxy.h
|
||||
|
||||
-I/VC/VS12/src
|
||||
-I/VC/VS12/include
|
||||
-I/VC/SDK/v7.1A/Include
|
||||
-D_M_IX86=300
|
||||
-D_MSC_VER=1200
|
||||
-D_INTEGRAL_MAX_BITS=32
|
||||
|
@ -191,7 +187,6 @@ rpcproxy.h
|
|||
-DSTRSAFE_LIB
|
||||
-DSTRSAFE_LIB_IMPL
|
||||
-DLPSKBINFO=LPARAM
|
||||
-D_WCHAR_T_DEFINED
|
||||
-DCONST=const
|
||||
-D_CRT_SECURE_NO_WARNINGS
|
||||
-D_CRT_NONSTDC_NO_DEPRECATE
|
||||
|
@ -205,3 +200,14 @@ rpcproxy.h
|
|||
-D_ThrowInfo=ThrowInfo
|
||||
-v0
|
||||
-D__inner_checkReturn=""
|
||||
|
||||
/data/HeaderFiles/VC/VS12/src
|
||||
/data/HeaderFiles/VC/VS12/include
|
||||
/data/HeaderFiles/VC/SDK/v7.1A/Include
|
||||
|
||||
x86:LE:32:default
|
||||
|
||||
windows
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -172,12 +172,8 @@ wpcapi.h
|
|||
wscapi.h
|
||||
wsdapi.h
|
||||
wspiapi.h
|
||||
|
||||
rpcproxy.h
|
||||
|
||||
-I/VC/VS12/src
|
||||
-I/VC/VS12/include
|
||||
-I/VC/SDK/v7.1A/Include
|
||||
-D_M_IX86=300
|
||||
-D_MSC_VER=1200
|
||||
-D_INTEGRAL_MAX_BITS=64
|
||||
|
@ -193,7 +189,6 @@ rpcproxy.h
|
|||
-DSTRSAFE_LIB
|
||||
-DSTRSAFE_LIB_IMPL
|
||||
-DLPSKBINFO=LPARAM
|
||||
-D_WCHAR_T_DEFINED
|
||||
-DCONST=const
|
||||
-D_CRT_SECURE_NO_WARNINGS
|
||||
-D_CRT_NONSTDC_NO_DEPRECATE
|
||||
|
@ -208,3 +203,11 @@ rpcproxy.h
|
|||
-D__unaligned=""
|
||||
-v0
|
||||
-D__inner_checkReturn=""
|
||||
|
||||
/data/HeaderFiles/VC/VS12/include
|
||||
/data/HeaderFiles/VC/VS12/src
|
||||
/data/HeaderFiles/VC/SDK/v7.1A/Include
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
341
Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf
Normal file
341
Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf
Normal 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
|
|
@ -58,13 +58,10 @@ yvals.h
|
|||
CommDlg.h
|
||||
WinUser.h
|
||||
WinNls.h
|
||||
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src\internal.h
|
||||
internal.h
|
||||
strsafe.h
|
||||
penwin.h
|
||||
|
||||
-IC:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Include
|
||||
-IC:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include
|
||||
-IC:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
|
||||
-D_M_IX86=500
|
||||
-D_MSC_VER=9090
|
||||
-D_MSC_EXTENSIONS
|
||||
|
@ -85,5 +82,11 @@ penwin.h
|
|||
-DSTRSAFE_LIB_IMPL
|
||||
-DLPSKBINFO=LPARAM
|
||||
-D_PHNDLR=void *
|
||||
-D_WCHAR_T_DEFINED
|
||||
-DCONST=const
|
||||
|
||||
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Include
|
||||
C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include
|
||||
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
|
||||
|
||||
x86:LE:64:default
|
||||
|
||||
|
|
|
@ -78,13 +78,17 @@ wchar.h
|
|||
wctype.h
|
||||
wordexp.h
|
||||
|
||||
-IU:\linux_include\include
|
||||
-IU:\linux_include\include\sys
|
||||
-IU:\linux_include\i386-redhat-linux\4.1.2\include
|
||||
-D_X86_
|
||||
-D__STDC__
|
||||
-D__WORDSIZE=32
|
||||
-D__builtin_va_list=void *
|
||||
-D__DO_NOT_DEFINE_COMPILE
|
||||
-D_Complex
|
||||
-D_WCHAR_T
|
||||
|
||||
U:\linux_include\include
|
||||
U:\linux_include\include\sys
|
||||
U:\linux_include\i386-redhat-linux\4.1.2\include
|
||||
|
||||
x86:LE:32:default
|
||||
|
||||
gcc
|
||||
|
|
|
@ -219,11 +219,6 @@ arpa/nameser_compat.h
|
|||
arpa/telnet.h
|
||||
arpa/tftp.h
|
||||
|
||||
-I/linux/include
|
||||
-I/linux/include/sys
|
||||
-I/linux/gcc/include
|
||||
-I/linux/x86_64-redhat-linux5E/include
|
||||
-I/linux/x86_64-redhat-linux5E/include/sys
|
||||
-D_X86_
|
||||
-D__STDC__
|
||||
-D_GNU_SOURCE
|
||||
|
@ -231,10 +226,19 @@ arpa/tftp.h
|
|||
-D__builtin_va_list=void *
|
||||
-D__DO_NOT_DEFINE_COMPILE
|
||||
-D_Complex
|
||||
-D_WCHAR_T
|
||||
-D__NO_STRING_INLINES
|
||||
-D__NO_LONG_DOUBLE_MATH
|
||||
-D__signed__
|
||||
-D__extension__=""
|
||||
-D__GLIBC_HAVE_LONG_LONG=1
|
||||
-Daligned_u64=uint64_t
|
||||
|
||||
/data/HeaderFiles/linux/include
|
||||
/data/HeaderFiles/linux/include/sys
|
||||
/data/HeaderFiles/linux/gcc/include
|
||||
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
|
||||
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
|
||||
|
||||
x86:LE:32:default
|
||||
|
||||
gcc
|
||||
|
|
|
@ -219,11 +219,6 @@ arpa/nameser_compat.h
|
|||
arpa/telnet.h
|
||||
arpa/tftp.h
|
||||
|
||||
-I/linux/include
|
||||
-I/linux/include/sys
|
||||
-I/linux/gcc/include
|
||||
-I/linux/x86_64-redhat-linux5E/include
|
||||
-I/linux/x86_64-redhat-linux5E/include/sys
|
||||
-D_X86_
|
||||
-D__STDC__
|
||||
-D_GNU_SOURCE
|
||||
|
@ -231,10 +226,19 @@ arpa/tftp.h
|
|||
-D__builtin_va_list=void *
|
||||
-D__DO_NOT_DEFINE_COMPILE
|
||||
-D_Complex
|
||||
-D_WCHAR_T
|
||||
-D__NO_STRING_INLINES
|
||||
-D__signed__
|
||||
-D__extension__=""
|
||||
-D__GLIBC_HAVE_LONG_LONG=1
|
||||
-D__need_sigset_t
|
||||
-Daligned_u64=uint64_t
|
||||
|
||||
/data/HeaderFiles/linux/include
|
||||
/data/HeaderFiles/linux/include/sys
|
||||
/data/HeaderFiles/linux/gcc/include
|
||||
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
|
||||
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
|
||||
|
||||
x86:LE:64:default
|
||||
|
||||
gcc
|
||||
|
|
|
@ -515,11 +515,6 @@ mechglue.h
|
|||
auth_gss.h
|
||||
auth_gssapi.h
|
||||
|
||||
-I/linux/include
|
||||
-I/linux/include/sys
|
||||
-I/linux/gcc/include
|
||||
-I/linux/x86_64-redhat-linux5E/include
|
||||
-I/linux/x86_64-redhat-linux5E/include/sys
|
||||
-D_X86_
|
||||
-D__STDC__
|
||||
-D_POSIX_C_SOURCE
|
||||
|
@ -528,10 +523,19 @@ auth_gssapi.h
|
|||
-D__builtin_va_list=void *
|
||||
-D__DO_NOT_DEFINE_COMPILE
|
||||
-D_Complex
|
||||
-D_WCHAR_T
|
||||
-D__NO_STRING_INLINES
|
||||
-D__NO_LONG_DOUBLE_MATH
|
||||
-D__signed__
|
||||
-D__extension__=""
|
||||
-D__GLIBC_HAVE_LONG_LONG=1
|
||||
-Daligned_u64=uint64_t
|
||||
|
||||
/data/HeaderFiles/linux/include
|
||||
/data/HeaderFiles/linux/include/sys
|
||||
/data/HeaderFiles/linux/gcc/include
|
||||
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
|
||||
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
|
||||
|
||||
x86:LE:32:default
|
||||
|
||||
gcc
|
||||
|
|
|
@ -515,11 +515,6 @@ mechglue.h
|
|||
auth_gss.h
|
||||
auth_gssapi.h
|
||||
|
||||
-I/linux/include
|
||||
-I/linux/include/sys
|
||||
-I/linux/gcc/include
|
||||
-I/linux/x86_64-redhat-linux5E/include
|
||||
-I/linux/x86_64-redhat-linux5E/include/sys
|
||||
-D_X86_
|
||||
-D__STDC__
|
||||
-D_POSIX_C_SOURCE
|
||||
|
@ -528,9 +523,18 @@ auth_gssapi.h
|
|||
-D__builtin_va_list=void *
|
||||
-D__DO_NOT_DEFINE_COMPILE
|
||||
-D_Complex
|
||||
-D_WCHAR_T
|
||||
-D__NO_STRING_INLINES
|
||||
-D__signed__
|
||||
-D__extension__=""
|
||||
-D__GLIBC_HAVE_LONG_LONG=1
|
||||
-Daligned_u64=uint64_t
|
||||
|
||||
/data/HeaderFiles/linux/include
|
||||
/data/HeaderFiles/linux/include/sys
|
||||
/data/HeaderFiles/linux/gcc/include
|
||||
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
|
||||
/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
|
||||
|
||||
x86:LE:64:default
|
||||
|
||||
gcc
|
||||
|
|
|
@ -222,9 +222,6 @@ wscapi.h
|
|||
wsdapi.h
|
||||
wspiapi.h
|
||||
|
||||
-I/VisualStudio/VS12/include
|
||||
-I/VisualStudio/Windows/v7.0a/Include
|
||||
-I/VisualStudio/VS12/src
|
||||
-D_M_IX86
|
||||
-D_MSC_VER=9090
|
||||
-D_INTEGRAL_MAX_BITS=32
|
||||
|
@ -239,7 +236,6 @@ wspiapi.h
|
|||
-DSTRSAFE_LIB
|
||||
-DSTRSAFE_LIB_IMPL
|
||||
-DLPSKBINFO=LPARAM
|
||||
-D_WCHAR_T_DEFINED
|
||||
-DCONST=const
|
||||
-D_CRT_SECURE_NO_WARNINGS
|
||||
-D_CRT_NONSTDC_NO_DEPRECATE
|
||||
|
@ -250,3 +246,12 @@ wspiapi.h
|
|||
-D__possibly_notnullterminated
|
||||
-Dtype_info="void *"
|
||||
-v0
|
||||
|
||||
/data/HeaderFiles/VC/VS12/include
|
||||
/data/HeaderFiles/VC/Windows/v7.0a/Include
|
||||
/data/HeaderFiles/VC/VS12/src
|
||||
|
||||
x86:LE:32:default
|
||||
|
||||
windows
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -26,6 +26,7 @@ import java.util.Iterator;
|
|||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
public class CompareGDTs extends GhidraScript {
|
||||
|
@ -54,13 +55,28 @@ public class CompareGDTs extends GhidraScript {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
firstArchive = openDataTypeArchive(firstFile, false);
|
||||
if (firstArchive.getWarning() != ArchiveWarning.NONE) {
|
||||
popup(
|
||||
"An architecture language error occured while opening archive (see log for details)\n" +
|
||||
firstFile.getPath());
|
||||
return;
|
||||
}
|
||||
|
||||
secondArchive = openDataTypeArchive(secondFile, false);
|
||||
if (secondArchive.getWarning() != ArchiveWarning.NONE) {
|
||||
popup(
|
||||
"An architecture language error occured while opening archive (see log for details)\n" +
|
||||
secondFile.getPath());
|
||||
return;
|
||||
}
|
||||
|
||||
matchByName = askYesNo("Match Data Types By Path Name?",
|
||||
"Do you want to match data types by their path names (rather than by Universal ID)?");
|
||||
checkPointers = askYesNo("Check Pointers?", "Do you want to check Pointers?");
|
||||
checkArrays = askYesNo("Check Arrays?", "Do you want to check Arrays?");
|
||||
|
||||
firstArchive = FileDataTypeManager.openFileArchive(firstFile, false);
|
||||
secondArchive = FileDataTypeManager.openFileArchive(secondFile, false);
|
||||
printWriter = new PrintWriter(outputFile);
|
||||
try {
|
||||
compareDataTypes();
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.io.IOException;
|
|||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||
import ghidra.app.util.cparser.C.ParseException;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
|
@ -55,14 +56,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
|
||||
}
|
||||
|
||||
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
|
||||
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
|
||||
String[] filenames, String includePaths[], String[] args)
|
||||
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
DataTypeManager openTypes[] = null;
|
||||
|
||||
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args);
|
||||
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
|
||||
}
|
||||
|
||||
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
|
||||
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
|
||||
String[] filenames, String[] includePaths, String[] args)
|
||||
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
|
||||
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
|
||||
|
@ -71,9 +74,9 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
|
||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
|
||||
|
||||
String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
|
||||
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
|
||||
|
||||
Msg.info(this, messages);
|
||||
Msg.info(this, results.getFormattedParseMessage(null));
|
||||
|
||||
dtMgr.save();
|
||||
dtMgr.close();
|
||||
|
@ -276,14 +279,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"wscapi.h",
|
||||
"wsdapi.h",
|
||||
"wspiapi.h",
|
||||
|
||||
"rpcproxy.h",
|
||||
};
|
||||
|
||||
String includePaths[] = {
|
||||
headerFilePath+"/VC/VS12/src",
|
||||
headerFilePath+"/VC/VS12/include",
|
||||
headerFilePath+"/VC/SDK/v7.1A/Include",
|
||||
};
|
||||
|
||||
String args[] = {
|
||||
"-I"+headerFilePath+"/VC/VS12/src",
|
||||
"-I"+headerFilePath+"/VC/VS12/include",
|
||||
"-I"+headerFilePath+"/VC/SDK/v7.1A/Include",
|
||||
"-D_M_IX86=300",
|
||||
"-D_MSC_VER=1200",
|
||||
"-D_INTEGRAL_MAX_BITS=32",
|
||||
|
@ -294,8 +299,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"-D_USE_ATTRIBUTES_FOR_SAL",
|
||||
"-D_CRTBLD",
|
||||
"-D_OPENMP_NOFORCE_MANIFEST",
|
||||
"-DSTRSAFE_LIB",
|
||||
"-DSTRSAFE_LIB_IMPL",
|
||||
"-DLPSKBINFO=LPARAM",
|
||||
"-DCONST=const",
|
||||
"-D_CRT_SECURE_NO_WARNINGS",
|
||||
|
@ -312,7 +315,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"-D__inner_checkReturn=",
|
||||
};
|
||||
|
||||
parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, args);
|
||||
parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, includePaths, args);
|
||||
}
|
||||
|
||||
|
||||
|
@ -494,14 +497,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"wscapi.h",
|
||||
"wsdapi.h",
|
||||
"wspiapi.h",
|
||||
|
||||
"rpcproxy.h",
|
||||
};
|
||||
|
||||
String includePaths[] = {
|
||||
headerFilePath+"/VC/VS12/src",
|
||||
headerFilePath+"/VC/VS12/include",
|
||||
headerFilePath+"/VC/SDK/v7.1A/Include",
|
||||
};
|
||||
|
||||
String args[] = {
|
||||
"-I"+headerFilePath+"/VC/VS12/src",
|
||||
"-I"+headerFilePath+"/VC/VS12/include",
|
||||
"-I"+headerFilePath+"/VC/SDK/v7.1A/Include",
|
||||
"-D_MSC_VER=1200",
|
||||
"-D_INTEGRAL_MAX_BITS=64",
|
||||
"-DWINVER=0x0900",
|
||||
|
@ -513,8 +518,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"-D_USE_ATTRIBUTES_FOR_SAL",
|
||||
"-D_CRTBLD",
|
||||
"-D_OPENMP_NOFORCE_MANIFEST",
|
||||
"-DSTRSAFE_LIB",
|
||||
"-DSTRSAFE_LIB_IMPL",
|
||||
"-DLPSKBINFO=LPARAM",
|
||||
"-DCONST=const",
|
||||
"-D_CRT_SECURE_NO_WARNINGS",
|
||||
|
@ -532,7 +535,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"-D__inner_checkReturn=",
|
||||
};
|
||||
|
||||
parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, args);
|
||||
parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, includePaths, args);
|
||||
}
|
||||
|
||||
|
||||
|
@ -761,12 +764,15 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"arpa/tftp.h",
|
||||
};
|
||||
|
||||
String includePaths[] = {
|
||||
headerFilePath+"/linux/include",
|
||||
headerFilePath+"/linux/include/sys",
|
||||
headerFilePath+"/linux/gcc/include",
|
||||
headerFilePath+"/linux/x86_64-redhat-linux5E/include",
|
||||
headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
|
||||
};
|
||||
|
||||
String args[] = {
|
||||
"-I"+headerFilePath+"/linux/include",
|
||||
"-I"+headerFilePath+"/linux/include/sys",
|
||||
"-I"+headerFilePath+"/linux/gcc/include",
|
||||
"-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include",
|
||||
"-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
|
||||
"-D_X86_",
|
||||
"-D__STDC__",
|
||||
"-D_GNU_SOURCE",
|
||||
|
@ -782,7 +788,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"-Daligned_u64=uint64_t",
|
||||
};
|
||||
|
||||
parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, args);
|
||||
parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, includePaths, args);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1011,12 +1017,15 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"arpa/tftp.h",
|
||||
};
|
||||
|
||||
String includePaths[] = {
|
||||
headerFilePath+"/linux/include",
|
||||
headerFilePath+"/linux/include/sys",
|
||||
headerFilePath+"/linux/gcc/include",
|
||||
headerFilePath+"/linux/x86_64-redhat-linux5E/include",
|
||||
headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
|
||||
};
|
||||
|
||||
String args[] = {
|
||||
"-I"+headerFilePath+"/linux/include",
|
||||
"-I"+headerFilePath+"/linux/include/sys",
|
||||
"-I"+headerFilePath+"/linux/gcc/include",
|
||||
"-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include",
|
||||
"-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
|
||||
"-D_X86_",
|
||||
"-D__STDC__",
|
||||
"-D_GNU_SOURCE",
|
||||
|
@ -1032,6 +1041,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
"-Daligned_u64=uint64_t",
|
||||
};
|
||||
|
||||
parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, args);
|
||||
parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, includePaths, args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.io.IOException;
|
|||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||
import ghidra.app.util.cparser.C.ParseException;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
|
@ -52,14 +53,16 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
parseGDT_WinVS22();
|
||||
}
|
||||
|
||||
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
|
||||
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
|
||||
String[] filenames, String includePaths[], String[] args)
|
||||
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
DataTypeManager openTypes[] = null;
|
||||
|
||||
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args);
|
||||
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
|
||||
}
|
||||
|
||||
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
|
||||
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
|
||||
String[] filenames, String[] includePaths, String[] args)
|
||||
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
|
||||
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
|
||||
|
@ -68,9 +71,9 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
|
||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
|
||||
|
||||
String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
|
||||
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
|
||||
|
||||
Msg.info(this, messages);
|
||||
Msg.info(this, results.getFormattedParseMessage(null));
|
||||
|
||||
dtMgr.save();
|
||||
dtMgr.close();
|
||||
|
@ -79,7 +82,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
/**
|
||||
* Turn string into a file, delete old archive if it exists
|
||||
*
|
||||
* @param dataTypeFile
|
||||
* @param dataTypeFile name of archive file
|
||||
*
|
||||
* @return file
|
||||
*/
|
||||
|
@ -112,12 +115,15 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"dsound.h",
|
||||
};
|
||||
|
||||
String includeFiles[] = {
|
||||
headerFilePath+"/VC/VS22/10.0.190141.0",
|
||||
headerFilePath+"/VC/VS22/10.0.19041.0/um",
|
||||
headerFilePath+"/VC/VS22/10.0.19041.0/shared",
|
||||
headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
|
||||
headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include",
|
||||
};
|
||||
|
||||
String args[] = {
|
||||
"-I"+headerFilePath+"/VC/VS22/10.0.190141.0",
|
||||
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um",
|
||||
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared",
|
||||
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
|
||||
"-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include",
|
||||
"-D_AMD64_",
|
||||
"-D_M_AMD64",
|
||||
"-D_M_X64",
|
||||
|
@ -126,7 +132,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"-v0",
|
||||
};
|
||||
|
||||
parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, args);
|
||||
parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, includeFiles, args);
|
||||
}
|
||||
|
||||
public void parseGDT_WinVS22() throws Exception {
|
||||
|
@ -167,7 +173,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"complex.h",
|
||||
"math.h",
|
||||
"mbctype.h",
|
||||
"mbstring.hs",
|
||||
"mbstring.h",
|
||||
"memory.h",
|
||||
"minmax.h",
|
||||
"new.h",
|
||||
|
@ -216,7 +222,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"dssec.h",
|
||||
"iads.h",
|
||||
"identitycommon.h",
|
||||
"identityproviders.h",
|
||||
"identityprovider.h",
|
||||
"identitystore.h",
|
||||
"keycredmgr.h",
|
||||
"lmaccess.h",
|
||||
|
@ -237,7 +243,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"slpublic.h",
|
||||
"subauth.h",
|
||||
"tokenbinding.h",
|
||||
"tpmsvcmgr.h",
|
||||
"tpmvscmgr.h",
|
||||
"wincred.h",
|
||||
"wincrypt.h",
|
||||
"winnetwk.h",
|
||||
|
@ -267,7 +273,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"mswsock.h",
|
||||
"ws2tcpip.h",
|
||||
"wsipv6ok.h",
|
||||
"wslwlink.h",
|
||||
"wsnwlink.h",
|
||||
"wsrm.h",
|
||||
"mswsockdef.h",
|
||||
|
||||
|
@ -375,7 +381,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"thumbcache.h",
|
||||
"thumbnailstreamcache.h",
|
||||
"tlogstg.h",
|
||||
"usereng.h",
|
||||
"userenv.h",
|
||||
|
||||
"# Windows Controls",
|
||||
"commctrl.h",
|
||||
|
@ -452,12 +458,15 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"lmwksta.h"
|
||||
};
|
||||
|
||||
String includeFiles[] = {
|
||||
headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
|
||||
headerFilePath+"/VC/VS22/10.0.19041.0/shared",
|
||||
headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
|
||||
headerFilePath+"/VC/VS22/10.0.19041.0/um",
|
||||
headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
|
||||
};
|
||||
|
||||
String args[] = {
|
||||
"-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
|
||||
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared",
|
||||
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
|
||||
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um",
|
||||
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
|
||||
"-D_MSC_VER=1924",
|
||||
"-D_INTEGRAL_MAX_BITS=64",
|
||||
"-DWINVER=0x0a00",
|
||||
|
@ -473,7 +482,6 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"-DSTRSAFE_LIB",
|
||||
"-DSTRSAFE_LIB_IMPL",
|
||||
"-DLPSKBINFO=LPARAM",
|
||||
"-D_WCHAR_T_DEFINED",
|
||||
"-DCONST=const",
|
||||
"-D_CRT_SECURE_NO_WARNINGS",
|
||||
"-D_CRT_NONSTDC_NO_DEPRECATE",
|
||||
|
@ -494,6 +502,6 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
"-DSECURITY_WIN32",
|
||||
};
|
||||
|
||||
parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, args);
|
||||
parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, includeFiles, args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import ghidra.app.script.GhidraScript;
|
|||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.ProjectDataTypeManager;
|
||||
import ghidra.program.database.data.*;
|
||||
import ghidra.program.model.data.BuiltInDataTypeManager;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
|
|
|
@ -24,43 +24,59 @@ import java.io.File;
|
|||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.data.Category;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class SynchronizeGDTCategoryPaths extends GhidraScript {
|
||||
|
||||
private File firstFile;
|
||||
private File secondFile;
|
||||
private FileDataTypeManager firstArchive;
|
||||
private FileDataTypeManager secondArchive;
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
firstFile = askFile("Select First GDT File", "Select 1st");
|
||||
secondFile = askFile("Select Second GDT File", "Select 2nd");
|
||||
|
||||
try {
|
||||
firstArchive = FileDataTypeManager.openFileArchive(firstFile, false);
|
||||
secondArchive = FileDataTypeManager.openFileArchive(secondFile, true);
|
||||
|
||||
int transactionID = secondArchive.startTransaction("Synchronize Category Path Names");
|
||||
Category firstCategory = firstArchive.getRootCategory();
|
||||
Category secondCategory = secondArchive.getRootCategory();
|
||||
|
||||
synchronizeCategory(firstCategory, secondCategory);
|
||||
secondArchive.endTransaction(transactionID, true);
|
||||
}
|
||||
finally {
|
||||
if (firstArchive != null) {
|
||||
firstArchive.close();
|
||||
File firstFile = askFile("Select First GDT File", "Select 1st");
|
||||
try (FileDataTypeManager firstArchive =
|
||||
FileDataTypeManager.openFileArchive(firstFile, false)) {
|
||||
if (hasWarning(firstArchive, firstFile)) {
|
||||
return;
|
||||
}
|
||||
secondArchive.save();
|
||||
if (secondArchive != null) {
|
||||
secondArchive.close();
|
||||
|
||||
File secondFile = askFile("Select Second GDT File", "Select 2nd");
|
||||
try (FileDataTypeManager secondArchive =
|
||||
FileDataTypeManager.openFileArchive(secondFile, true)) {
|
||||
if (hasWarning(secondArchive, secondFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int transactionID =
|
||||
secondArchive.startTransaction("Synchronize Category Path Names");
|
||||
try {
|
||||
Category firstCategory = firstArchive.getRootCategory();
|
||||
Category secondCategory = secondArchive.getRootCategory();
|
||||
synchronizeCategory(firstCategory, secondCategory);
|
||||
}
|
||||
finally {
|
||||
secondArchive.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasWarning(FileDataTypeManager archive, File file) {
|
||||
ArchiveWarning warning = archive.getWarning();
|
||||
if (warning == ArchiveWarning.NONE) {
|
||||
return false;
|
||||
}
|
||||
if (warning == ArchiveWarning.UPGRADED_LANGUAGE_VERSION) {
|
||||
return !askYesNo("Archive Upgrade Confirmation",
|
||||
"A language upgrade has been performed on archive " + file.getName() +
|
||||
"\nIs it OK to proceed?");
|
||||
}
|
||||
popup(
|
||||
"An architecture language error occured while opening archive (see log for details)\n" +
|
||||
file.getPath());
|
||||
return true;
|
||||
}
|
||||
|
||||
private void synchronizeCategory(Category firstCategory, Category secondCategory) {
|
||||
Category[] firstCategories = firstCategory.getCategories();
|
||||
for (Category categoryA : firstCategories) {
|
||||
|
|
|
@ -123,18 +123,27 @@
|
|||
|
||||
|
||||
<tocdef id="Ghidra Functionality"
|
||||
sortgroup="e"
|
||||
text="Ghidra Functionality"
|
||||
target = "help/topics/Intro/GhidraFunctionality.htm">
|
||||
<tocdef id="Code Browser" text="Code Browser" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm" >
|
||||
<tocdef id="Browser Field Formatter" sortgroup="a" text="Browser Field Formatter" target="help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm" />
|
||||
<tocdef id="Markers" sortgroup="b" text="Markers" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm#CBNavigationMarkers" />
|
||||
<tocdef id="Cursor Text Highlight" sortgroup="c" text="Cursor Text Highlight" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm#cursorTextHighlight" />
|
||||
<tocdef id="Code Browser Configuration Options" sortgroup="d" text="Configuration Options" target="help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm" />
|
||||
|
||||
|
||||
sortgroup="e"
|
||||
text="Ghidra Functionality"
|
||||
target = "help/topics/Intro/GhidraFunctionality.htm">
|
||||
<tocdef id="Code Browser" text="Code Browser" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm" >
|
||||
<tocdef id="Browser Field Formatter" sortgroup="a" text="Browser Field Formatter" target="help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm" />
|
||||
<tocdef id="Markers" sortgroup="b" text="Markers" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm#CBNavigationMarkers" />
|
||||
<tocdef id="Cursor Text Highlight" sortgroup="c" text="Cursor Text Highlight" target="help/topics/CodeBrowserPlugin/CodeBrowser.htm#cursorTextHighlight" />
|
||||
<tocdef id="Code Browser Configuration Options" sortgroup="d" text="Configuration Options" target="help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm" />
|
||||
</tocdef>
|
||||
|
||||
|
||||
<tocdef id="Data Type Manager" sortgroup="c" text="Data Type Manager" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm">
|
||||
<tocdef id="DTM Concepts" sortgroup="a" text="Basic Concepts" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Basic_Concepts" />
|
||||
<tocdef id="DTM Window" sortgroup="b" text="Data Type Window" target="help/topics/DataTypeManagerPlugin/data_type_manager_window.html" />
|
||||
<tocdef id="DTM Working With Archives" sortgroup="c" text="Archives" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Archives" />
|
||||
<tocdef id="DTM Working With Categories" sortgroup="d" text="Categories" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Category" />
|
||||
<tocdef id="DTM Working With Data Types" sortgroup="e" text="Data Types" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Data_Types" />
|
||||
<tocdef id="DTM Managing Archives" sortgroup="f" text="Managing Archives" target="help/topics/DataTypeManagerPlugin/data_type_manager_archives.html" />
|
||||
<tocdef id="Structure Editor" sortgroup="d" text="Structure Editor" target="help/topics/DataTypeEditors/StructureEditor.htm" />
|
||||
<tocdef id="Enum Editor" sortgroup="e" text="Enum Editor" target="help/topics/DataTypeEditors/EnumEditor.htm" />
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="Assembler" text="Assembler" target="help/topics/AssemblerPlugin/Assembler.htm"></tocdef>
|
||||
|
||||
<tocdef id="Entropy Overview" text="Entropy Overview" target="help/topics/OverviewPlugin/Overview.htm#EntropyOverviewBar" >
|
||||
|
@ -220,16 +229,6 @@
|
|||
<tocdef id="Data" sortgroup="c" text="Data" target="help/topics/DataPlugin/Data.htm" >
|
||||
<tocdef id="Create Data" sortgroup="a" text="Create Data" target="help/topics/DataPlugin/Data.htm" />
|
||||
<tocdef id="Data Types" sortgroup="b" text="Data Types" target="help/topics/DataPlugin/Data.htm#DataTypes" />
|
||||
<tocdef id="Data Type Manager" sortgroup="c" text="Data Type Manager" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm">
|
||||
<tocdef id="DTM Concepts" sortgroup="a" text="Basic Concepts" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Basic_Concepts" />
|
||||
<tocdef id="DTM Window" sortgroup="b" text="Data Type Window" target="help/topics/DataTypeManagerPlugin/data_type_manager_window.html" />
|
||||
<tocdef id="DTM Working With Archives" sortgroup="c" text="Archives" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Archives" />
|
||||
<tocdef id="DTM Working With Categories" sortgroup="d" text="Categories" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Category" />
|
||||
<tocdef id="DTM Working With Data Types" sortgroup="e" text="Data Types" target="help/topics/DataTypeManagerPlugin/data_type_manager_description.htm#Data_Types" />
|
||||
<tocdef id="DTM Managing Archives" sortgroup="f" text="Managing Archives" target="help/topics/DataTypeManagerPlugin/data_type_manager_archives.html" />
|
||||
</tocdef>
|
||||
<tocdef id="Structure Editor" sortgroup="d" text="Structure Editor" target="help/topics/DataTypeEditors/StructureEditor.htm" />
|
||||
<tocdef id="Enum Editor" sortgroup="e" text="Enum Editor" target="help/topics/DataTypeEditors/EnumEditor.htm" />
|
||||
<tocdef id="Translate Strings" sortgroup="e" text="Translate Strings" target="help/topics/TranslateStringsPlugin/TranslateStringsPlugin.htm" />
|
||||
<tocdef id="Save Image" sortgroup="e" text="Save Image" target="help/topics/ResourceActionsPlugin/ResourceActions.html" />
|
||||
</tocdef>
|
||||
|
|
|
@ -353,6 +353,14 @@
|
|||
editing, since they support sharing and version control and therefore allow more than one
|
||||
user to modify them at a time. Only one user at a time can have a file archive opened for
|
||||
editing.</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><IMG alt="" src="help/shared/tip.png">You can assign a specific <I>"Architecture"</I>
|
||||
to a Data Type Archive while it is open for editing. This is recommended when an archive is targeting
|
||||
a specific processor and compiler specification (see <A href="#Set_Archive_Architecture">Setting
|
||||
Data Type Archive Architecture</A>).</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
@ -406,6 +414,51 @@
|
|||
Archive.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Set_Archive_Architecture"></A>Setting Data Type Archive Architecture</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>By default, data type archives are not assigned an architecture and adopt a default
|
||||
<I>Data Organization</I> which determines primitive data type sizing (e.g., int, long, pointer, etc.)
|
||||
as well as alignment and packing behavior. While data types copied between archives or a program
|
||||
with disimilar <I>Data Organizations</I> will generally resolve correctly, unexpected results
|
||||
may sometimes arise (e.g., bit-field packing within structures). In addition, this situation
|
||||
frequently causes some confusion when viewing and editing data types where the <I>Data
|
||||
Organization</I> differs from the intended target architecture.</P>
|
||||
|
||||
<P>With either a file or project data type archive open for editing, a specific architecture
|
||||
may be assigned to the archive. This is done by selecting the open archive node from the
|
||||
data type tree, right-click on it and select the <I><B>Set Architecture...</B></I> action.
|
||||
This will popup a processor/compiler-specification selection dialog from which a selection
|
||||
may be made and the <B>OK</B> button clicked. A final confirmation dialog will be displayed
|
||||
before completing the change from which the <B>Set Architecture</B> or <B>Cancel</B> button
|
||||
must be clicked to confirm or cancel the change. If confirmed, any architecture transition
|
||||
will resolve all data types to the new data organization. Details related to custom variable
|
||||
storage for Function Definitions (not yet implemented) will be preserved if possible but
|
||||
may be discarded.</P>
|
||||
|
||||
<P>At present, the user will be forced to save any unsaved archive changes prior to completing
|
||||
an architecture setting change to allow for a fallback if neccessary.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Clear_Archive_Architecture"></A>Clearing Data Type Archive Architecture</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
||||
<P>With either a file or project data type archive open for editing, a currently assigned architecture
|
||||
may be cleared for a selected archive. This is done by selecting the open archive node from the
|
||||
data type tree, right-click on it and select the <I><B>Clear Architecture</B></I> action.
|
||||
A final confirmation dialog will be displayed
|
||||
before completing the change from which the <B>Clear Architecture</B> or <B>Cancel</B> button
|
||||
must be clicked to confirm or cancel the change. If confirmed, the archive will revert a default
|
||||
<I>Data Organization</I> and any custom variable storage for Function Definitions
|
||||
(not yet implemented) will be discarded.
|
||||
|
||||
<P>At present, the user will be forced to save any unsaved changes prior to clearing the
|
||||
architecture setting to allow for a fallback if neccessary.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Close_Archive"></A>Closing a Data Type Archive</H3>
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
|
|||
func.updateFunction(conventionName, returnParam, params,
|
||||
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, false, source);
|
||||
func.setVarArgs(signature.hasVarArgs());
|
||||
func.setNoReturn(signature.hasNoReturn());
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// should not happen unless caused by a concurrent operation
|
||||
|
@ -212,29 +213,21 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
|
|||
}
|
||||
|
||||
private String getCallingConvention(Function function, CompilerSpec compilerSpec) {
|
||||
PrototypeModel preferredModel = null;
|
||||
if (signature.getGenericCallingConvention() != GenericCallingConvention.unknown) {
|
||||
preferredModel = compilerSpec.matchConvention(signature.getGenericCallingConvention());
|
||||
|
||||
// Ignore signature's calling convention if unknown/not-defined
|
||||
String callingConvention = signature.getCallingConventionName();
|
||||
if (compilerSpec.getCallingConvention(callingConvention) == null) {
|
||||
callingConvention = null;
|
||||
}
|
||||
|
||||
PrototypeModel convention = function.getCallingConvention();
|
||||
if (convention == null || !preserveCallingConvention) {
|
||||
convention = preferredModel;
|
||||
// NOTE: This has been disable since it can cause imported signature information to be
|
||||
// ignored and overwritten by subsequent analysis
|
||||
// if (convention == null && compilerSpec.getCallingConventions().length > 1) {
|
||||
// // use default source for signature if convention is really unknown so that we
|
||||
// // know dynamic storage assignment is unreliable
|
||||
// source = SourceType.DEFAULT;
|
||||
// }
|
||||
// Continue using function's current calling convention if valid and either
|
||||
// reservation was requested or signature's convention is unknown/not-defined.
|
||||
PrototypeModel currentConvention = function.getCallingConvention();
|
||||
if (currentConvention != null && (callingConvention == null || preserveCallingConvention)) {
|
||||
callingConvention = function.getCallingConventionName();
|
||||
}
|
||||
|
||||
// Calling convention is permitted to change
|
||||
String conventionName = function.getCallingConventionName();
|
||||
if (!preserveCallingConvention && convention != null) {
|
||||
conventionName = convention.getName();
|
||||
}
|
||||
return conventionName;
|
||||
return callingConvention;
|
||||
}
|
||||
|
||||
private static void updateStackPurgeSize(Function function, Program program) {
|
||||
|
|
|
@ -1473,6 +1473,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
ParameterDefinition[] sourceVars = sourceFunctionDefDt.getArguments();
|
||||
ParameterDefinition[] destVars = new ParameterDefinition[sourceVars.length];
|
||||
boolean sourceHasVarArgs = sourceFunctionDefDt.hasVarArgs();
|
||||
boolean sourceHasNoReturn = sourceFunctionDefDt.hasNoReturn();
|
||||
|
||||
DataType resolvedRDT = DataType.DEFAULT;
|
||||
if (sourceReturnType != null) {
|
||||
|
@ -1492,6 +1493,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
}
|
||||
destDt.setArguments(destVars);
|
||||
destDt.setVarArgs(sourceHasVarArgs);
|
||||
destDt.setNoReturn(sourceHasNoReturn);
|
||||
|
||||
destDt.setLastChangeTime(oldLastChangeTime);
|
||||
destDt.setLastChangeTimeInSourceArchive(oldLastChangeTimeInSourceArchive);
|
||||
|
|
|
@ -29,6 +29,7 @@ import ghidra.docking.settings.Settings;
|
|||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
import ghidra.util.StringUtilities;
|
||||
import ghidra.util.UniversalID;
|
||||
|
@ -348,7 +349,14 @@ class DataTypePanel extends JPanel {
|
|||
ParameterDefinition[] vars = fd.getArguments();
|
||||
|
||||
DataType returnType = fd.getReturnType();
|
||||
if (fd.hasNoReturn()) {
|
||||
insertString(FunctionSignature.NORETURN_DISPLAY_STRING + " ", contentAttrSet);
|
||||
}
|
||||
insertString(returnType.getDisplayName(), contentAttrSet);
|
||||
String callingConventionName = fd.getCallingConventionName();
|
||||
if (!Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConventionName)) {
|
||||
insertString(callingConventionName + " ", contentAttrSet);
|
||||
}
|
||||
insertString(" " + fd.getDisplayName(), nameAttrSet);
|
||||
insertString(" (", contentAttrSet);
|
||||
boolean hasVarArgs = fd.hasVarArgs();
|
||||
|
|
|
@ -15,7 +15,13 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.compositeeditor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.ProgramArchitecture;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
||||
|
||||
|
@ -23,10 +29,10 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
|||
* The data type manager for original composite data type being edited.
|
||||
* This is where the edited datatype will be written back to.
|
||||
*/
|
||||
private DataTypeManager originalDTM;
|
||||
private Composite originalComposite;
|
||||
private Composite viewComposite;
|
||||
private int transactionID;
|
||||
private final DataTypeManager originalDTM;
|
||||
private final Composite originalComposite;
|
||||
private final Composite viewComposite;
|
||||
private final int transactionID;
|
||||
|
||||
/**
|
||||
* Creates a data type manager that the structure editor will use
|
||||
|
@ -39,16 +45,42 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
|||
this.originalComposite = originalComposite;
|
||||
transactionID = startTransaction("");
|
||||
originalDTM = originalComposite.getDataTypeManager();
|
||||
universalID = originalDTM.getUniversalID(); // mimic original DTM
|
||||
|
||||
ProgramArchitecture arch = originalDTM.getProgramArchitecture();
|
||||
if (arch != null) {
|
||||
try {
|
||||
setProgramArchitecture(arch, null, true, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
throw new AssertException(e); // unexpected
|
||||
}
|
||||
catch (IOException e) {
|
||||
errHandler.dbError(e);
|
||||
}
|
||||
}
|
||||
|
||||
viewComposite = (Composite) super.resolve(originalComposite, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected final boolean isArchitectureChangeAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
endTransaction(transactionID, true);
|
||||
super.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DataTypeManager} associated with the original composite datatype being edited.
|
||||
* @return original datatype manager
|
||||
*/
|
||||
public DataTypeManager getOriginalDataTypeManager() {
|
||||
return originalDTM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArchiveType getType() {
|
||||
return originalDTM.getType();
|
||||
|
|
|
@ -1344,4 +1344,8 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
|||
return originalCompositeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
|
||||
// don't care
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,19 +15,13 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.cparser;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.apache.commons.io.DirectoryWalker.CancelException;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
|
@ -38,21 +32,17 @@ import ghidra.app.CorePluginPackage;
|
|||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.cparser.C.CParser;
|
||||
import ghidra.app.util.cparser.CPP.PreProcessor;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.PluginInfo;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.data.BuiltInDataTypeManager;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -66,22 +56,20 @@ import ghidra.util.task.TaskMonitor;
|
|||
)
|
||||
//@formatter:on
|
||||
public class CParserPlugin extends ProgramPlugin {
|
||||
final static String PARSE_ACTION_NAME = "Import C DataTypes";
|
||||
public final static String PARSE_ACTION_NAME = "Import C DataTypes";
|
||||
|
||||
final static String USER_PROFILES_DIR =
|
||||
Application.getUserSettingsDirectory().getAbsolutePath() + File.separatorChar +
|
||||
"parserprofiles";
|
||||
|
||||
private ParseDialog parseDialog;
|
||||
private File userProfileDir;
|
||||
|
||||
private String parserMessages;
|
||||
private String cppMessages;
|
||||
private CParseResults results;
|
||||
|
||||
final static String DESCRIPTION =
|
||||
"Parse C and C Header files, extracting data definitions and function signatures.";
|
||||
|
||||
private static final String PARSER_DEBUG_OUTFILE = "CParserPlugin.out";
|
||||
|
||||
public CParserPlugin(PluginTool plugintool) {
|
||||
super(plugintool);
|
||||
createActions();
|
||||
|
@ -155,26 +143,37 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
if (parseDialog == null) {
|
||||
parseDialog = new ParseDialog(this);
|
||||
}
|
||||
else {
|
||||
parseDialog.toFront();
|
||||
}
|
||||
parseDialog.setupForDisplay();
|
||||
tool.showDialog(parseDialog);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse into a saved data type data base file
|
||||
*/
|
||||
protected void parse(String[] filenames, String options, String dataFilename) {
|
||||
CParserTask parseTask = new CParserTask(this, filenames, options, dataFilename);
|
||||
protected void parse(String[] filenames, String includePaths[], String options,
|
||||
String languageIDString, String compilerSpecID, String dataFilename) {
|
||||
|
||||
CParserTask parseTask = new CParserTask(this, dataFilename)
|
||||
.setFileNames(filenames)
|
||||
.setIncludePaths(includePaths)
|
||||
.setOptions(options)
|
||||
.setLanguageID(languageIDString)
|
||||
.setCompilerID(compilerSpecID);
|
||||
|
||||
this.getTool().execute(parseTask, 500);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse C-source into a data type manager
|
||||
*/
|
||||
protected void parse(String[] filenames, String options, DataTypeManager dtMgr,
|
||||
protected void parse(String[] filenames, String includePaths[], String options,
|
||||
String languageIDString, String compilerSpecID, DataTypeManager dtMgr,
|
||||
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException {
|
||||
|
||||
results = null;
|
||||
|
||||
String[] args = parseOptions(options);
|
||||
|
||||
DataTypeManager openDTmanagers[] = null;
|
||||
|
@ -184,100 +183,22 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
return; // parse canceled
|
||||
}
|
||||
|
||||
cppMessages = "";
|
||||
PreProcessor cpp = new PreProcessor();
|
||||
|
||||
cpp.setArgs(args);
|
||||
|
||||
PrintStream os = System.out;
|
||||
String homeDir = System.getProperty("user.home");
|
||||
String fName = homeDir + File.separator + "CParserPlugin.out";
|
||||
try {
|
||||
os = new PrintStream(new FileOutputStream(fName));
|
||||
}
|
||||
catch (FileNotFoundException e2) {
|
||||
Msg.error(this, "Unexpected Exception: " + e2.getMessage(), e2);
|
||||
}
|
||||
|
||||
PrintStream old = System.out;
|
||||
System.setOut(os);
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
cpp.setOutputStream(bos);
|
||||
cpp.setMonitor(monitor);
|
||||
|
||||
try {
|
||||
for (String filename : filenames) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
// any file beginning with a "#" is assumed to be a comment
|
||||
if (filename.trim().startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
File file = new File(filename);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
// process each header file in the directory
|
||||
String[] children = file.list();
|
||||
if (children == null) {
|
||||
continue;
|
||||
}
|
||||
for (String element : children) {
|
||||
File child = new File(file.getAbsolutePath() + "/" + element);
|
||||
if (child.getName().endsWith(".h")) {
|
||||
parseFile(child.getAbsolutePath(), monitor, cpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
parseFile(filename, monitor, cpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
os.close();
|
||||
throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
|
||||
}
|
||||
|
||||
// process all the defines and add any that are integer values into
|
||||
// the Equates table
|
||||
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
|
||||
|
||||
System.out.println(bos.toString());
|
||||
|
||||
System.setOut(old);
|
||||
os.close();
|
||||
|
||||
if (!monitor.isCancelled()) {
|
||||
monitor.setMessage("Parsing C");
|
||||
|
||||
CParser cParser = new CParser(dtMgr, true, openDTmanagers);
|
||||
cParser.setParseFileName(PARSER_DEBUG_OUTFILE);
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||
try {
|
||||
parserMessages = "";
|
||||
cParser.setParseFileName(fName);
|
||||
cParser.setMonitor(monitor);
|
||||
cParser.parse(bis);
|
||||
}
|
||||
finally {
|
||||
parserMessages = cParser.getParseMessages();
|
||||
}
|
||||
|
||||
results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
|
||||
args, dtMgr, languageIDString, compilerSpecID, monitor);
|
||||
|
||||
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager);
|
||||
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
// CParserTask will show any errors
|
||||
if (!cParser.didParseSucceed()) {
|
||||
if (!results.successful()) {
|
||||
return;
|
||||
}
|
||||
if (isProgramDtMgr) {
|
||||
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
|
||||
"C-Parse of Header Files Complete",
|
||||
"Successfully parsed header file(s) to Program.",
|
||||
getFormattedParseMessage(
|
||||
"Check the Manage Data Types window for added data types."),
|
||||
getFormattedParseMessage("Check the Manage Data Types window for added data types."),
|
||||
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
||||
}
|
||||
else {
|
||||
|
@ -286,20 +207,22 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
archiveName = ((FileDataTypeManager) dtMgr).getFilename();
|
||||
}
|
||||
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
|
||||
"C-Parse of Header Files Complete. ",
|
||||
"C-Parse of Header Files Complete",
|
||||
"Successfully parsed header file(s) to Archive File: " + archiveName,
|
||||
getFormattedParseMessage(null), MultiLineMessageDialog.INFORMATION_MESSAGE);
|
||||
getFormattedParseMessage(null),
|
||||
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get open data type managers.
|
||||
* User can Use Open managers, Select not to use, or Cancel
|
||||
*
|
||||
* @param openDTmanagers open mgrs, null if don't use
|
||||
* @return array of open data type managers
|
||||
*
|
||||
* @throws CancelledException if user cancels
|
||||
|
@ -335,7 +258,7 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
"</ul>" + "<p><b>The new archive will become dependent on these archives<br>" +
|
||||
"for any datatypes already defined in them </b>(only unique <br>" +
|
||||
"data types will be added to the new archive).",
|
||||
"Use Open Archives?", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE);
|
||||
"Use Open Archives", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE);
|
||||
if (result == OptionDialog.CANCEL_OPTION) {
|
||||
throw new CancelledException("User Cancelled");
|
||||
}
|
||||
|
@ -346,62 +269,40 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
|
||||
return openDTmanagers;
|
||||
}
|
||||
|
||||
public CParseResults getParseResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public String getParseMessage() {
|
||||
return (results != null ? results.cParseMessages() : "");
|
||||
}
|
||||
|
||||
public String getFormattedParseMessage(String errMsg) {
|
||||
protected String getFormattedParseMessage(String errMsg) {
|
||||
String message = "";
|
||||
|
||||
if (errMsg != null) {
|
||||
message += errMsg + "\n\n";
|
||||
}
|
||||
|
||||
String msg = getParseMessage();
|
||||
String msg = (results == null ? null : results.cParseMessages());
|
||||
if (msg != null && msg.length() != 0) {
|
||||
message += "CParser Messages:\n" + msg + "\n\n";
|
||||
}
|
||||
|
||||
msg = getPreProcessorMessage();
|
||||
msg = (results == null ? null : results.cppParseMessages());
|
||||
if (msg != null && msg.length() != 0) {
|
||||
message += "PreProcessor Messages:\n" + getPreProcessorMessage();
|
||||
message += "PreProcessor Messages:\n" + msg;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any parse messages produced by parsing good, or informational
|
||||
*
|
||||
* @return messages from parser
|
||||
*/
|
||||
public String getParseMessage() {
|
||||
return parserMessages;
|
||||
}
|
||||
|
||||
public String getPreProcessorMessage() {
|
||||
return cppMessages;
|
||||
}
|
||||
|
||||
private void parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
|
||||
throws ghidra.app.util.cparser.CPP.ParseException {
|
||||
monitor.setMessage("PreProcessing " + filename);
|
||||
try {
|
||||
Msg.info(this, "parse " + filename);
|
||||
cpp.parse(filename);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Parsing file :" + filename);
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
|
||||
throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
|
||||
}
|
||||
finally {
|
||||
cppMessages += cpp.getParseMessages();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse into the current programs data type manager
|
||||
*/
|
||||
protected void parse(String[] filenames, String options) {
|
||||
protected void parse(String[] filenames, String[] includePaths, String options,
|
||||
String languageIDString, String compilerIDString) {
|
||||
if (currentProgram == null) {
|
||||
Msg.showInfo(getClass(), parseDialog.getComponent(), "No Open Program",
|
||||
"A program must be open to \"Parse to Program\"");
|
||||
|
@ -413,8 +314,14 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
if (result == OptionDialog.CANCEL_OPTION) {
|
||||
return;
|
||||
}
|
||||
|
||||
CParserTask parseTask =
|
||||
new CParserTask(this, filenames, options, currentProgram.getDataTypeManager());
|
||||
new CParserTask(this, currentProgram.getDataTypeManager())
|
||||
.setFileNames(filenames)
|
||||
.setIncludePaths(includePaths)
|
||||
.setOptions(options)
|
||||
.setLanguageID(languageIDString)
|
||||
.setCompilerID(compilerIDString);
|
||||
|
||||
tool.execute(parseTask);
|
||||
}
|
||||
|
|
|
@ -20,44 +20,97 @@ import java.io.File;
|
|||
import javax.swing.SwingUtilities;
|
||||
|
||||
import docking.widgets.dialogs.MultiLineMessageDialog;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
import ghidra.util.task.Task;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* This is called by the dialog box.
|
||||
* Background task to parse files for cparser plugin
|
||||
*
|
||||
*
|
||||
*/
|
||||
class CParserTask extends Task {
|
||||
private String[] filenames;
|
||||
private String options;
|
||||
|
||||
private CParserPlugin plugin;
|
||||
private String dataFileName;
|
||||
|
||||
private String[] filenames;
|
||||
private String[] includePaths;
|
||||
|
||||
private String options;
|
||||
|
||||
private String languageString;
|
||||
private String compilerString;
|
||||
|
||||
private DataTypeManager dtMgr;
|
||||
|
||||
CParserTask(CParserPlugin plugin, String[] filenames, String options, String dataFileName) {
|
||||
|
||||
/**
|
||||
* Create task to parse to a dataFile
|
||||
*
|
||||
* @param plugin CParserPlugin that will do the work
|
||||
* @param dataFileName name of the file to parse to
|
||||
*/
|
||||
CParserTask(CParserPlugin plugin, String dataFileName) {
|
||||
super("Parsing C Files", true, false, false);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.filenames = filenames;
|
||||
this.options = options;
|
||||
this.dataFileName = dataFileName;
|
||||
}
|
||||
|
||||
public CParserTask(CParserPlugin plugin, String[] filenames, String options,
|
||||
DataTypeManager dataTypeManager) {
|
||||
/**
|
||||
* Create task to parse to a dataTypeManager
|
||||
*
|
||||
* @param plugin
|
||||
* @param dataTypeManager
|
||||
*/
|
||||
public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) {
|
||||
super("Parsing C Files", true, false, false);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.filenames = filenames;
|
||||
this.options = options;
|
||||
this.dtMgr = dataTypeManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create task to parse to a ProgramDataTypeManager
|
||||
*
|
||||
* @param plugin
|
||||
* @param dataTypeManager
|
||||
*/
|
||||
public CParserTask(CParserPlugin plugin, ProgramBasedDataTypeManager dataTypeManager) {
|
||||
super("Parsing C Files", true, false, false);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.dtMgr = dataTypeManager;
|
||||
}
|
||||
|
||||
public CParserTask setLanguageID(String languageID) {
|
||||
this.languageString = languageID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CParserTask setCompilerID(String compilerID) {
|
||||
this.compilerString = compilerID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CParserTask setIncludePaths(String includePaths[]) {
|
||||
this.includePaths = includePaths.clone();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CParserTask setFileNames(String names[]) {
|
||||
this.filenames = names.clone();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CParserTask setOptions(String options) {
|
||||
this.options = options;
|
||||
return this;
|
||||
}
|
||||
|
||||
private String getFirstMessageLine(final String errMsg) {
|
||||
int indexOf = errMsg.indexOf('\n');
|
||||
String msg = errMsg;
|
||||
|
@ -77,8 +130,9 @@ class CParserTask extends Task {
|
|||
fileDtMgr = dtMgr;
|
||||
}
|
||||
|
||||
plugin.parse(filenames, options, dtMgr, monitor);
|
||||
plugin.parse(filenames, includePaths, options, languageString, compilerString, dtMgr, monitor);
|
||||
if (dataFileName != null) {
|
||||
// TODO: does not consider existing datatypes
|
||||
if (dtMgr.getDataTypeCount(true) != 0) {
|
||||
try {
|
||||
((FileDataTypeManager) dtMgr).save();
|
||||
|
@ -102,6 +156,10 @@ class CParserTask extends Task {
|
|||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// no results, was canceled
|
||||
if (plugin.getParseResults() == null) {
|
||||
return;
|
||||
}
|
||||
MultiLineMessageDialog.showModalMessageDialog(
|
||||
plugin.getDialog().getComponent(), "Parse Errors",
|
||||
"File was not created due to parse errors: " +
|
||||
|
|
|
@ -15,31 +15,44 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.cparser;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import docking.*;
|
||||
import docking.action.*;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.button.BrowseButton;
|
||||
import docking.widgets.combobox.GhidraComboBox;
|
||||
import docking.widgets.dialogs.InputDialog;
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import docking.widgets.filechooser.GhidraFileChooserMode;
|
||||
import docking.widgets.label.GLabel;
|
||||
import docking.widgets.pathmanager.PathnameTablePanel;
|
||||
import docking.widgets.table.GTableCellRenderer;
|
||||
import docking.widgets.table.GTableCellRenderingData;
|
||||
import generic.jar.ResourceFile;
|
||||
import generic.theme.GThemeDefaults.Colors.Tables;
|
||||
import ghidra.app.plugin.core.processors.SetLanguageDialog;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.exporter.Exporter;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.framework.store.db.PackedDatabase;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.lang.CompilerSpecID;
|
||||
import ghidra.program.model.lang.LanguageID;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||
|
@ -75,6 +88,13 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
|
||||
private PathnameTablePanel pathPanel;
|
||||
private JTextArea parseOptionsField;
|
||||
|
||||
protected JComponent languagePanel;
|
||||
protected JTextField languageTextField;
|
||||
protected JButton languageButton;
|
||||
protected String languageIDString = null;
|
||||
protected String compilerIDString = null;
|
||||
|
||||
private GhidraComboBox<ComboBoxItem> comboBox;
|
||||
private DefaultComboBoxModel<ComboBoxItem> comboModel;
|
||||
private DockingAction saveAction;
|
||||
|
@ -86,44 +106,75 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
private TableModelListener tableListener;
|
||||
private ItemListener comboItemListener;
|
||||
private TableModel tableModel;
|
||||
|
||||
private PathnameTablePanel includePathPanel;
|
||||
private TableModel parsePathTableModel;
|
||||
private TableModelListener parsePathTableListener;
|
||||
|
||||
private ArrayList<ComboBoxItem> itemList;
|
||||
private ComboBoxItemComparator comparator;
|
||||
private ResourceFile parentUserFile;
|
||||
private boolean saveAsInProgress;
|
||||
private boolean initialBuild = true;
|
||||
|
||||
private boolean userDefined = false;
|
||||
private String currentProfileName = null;
|
||||
|
||||
ParseDialog(CParserPlugin plugin) {
|
||||
super("Parse C Source", false, true, true, false);
|
||||
|
||||
this.plugin = plugin;
|
||||
itemList = new ArrayList<>();
|
||||
comparator = new ComboBoxItemComparator();
|
||||
addWorkPanel(buildMainPanel());
|
||||
addDismissButton();
|
||||
createActions();
|
||||
setActionsEnabled();
|
||||
}
|
||||
|
||||
public void setupForDisplay() {
|
||||
if (initialBuild) {
|
||||
itemList = new ArrayList<>();
|
||||
comparator = new ComboBoxItemComparator();
|
||||
addWorkPanel(buildMainPanel());
|
||||
addDismissButton();
|
||||
createActions();
|
||||
setActionsEnabled();
|
||||
|
||||
// setup based on save state
|
||||
if (currentProfileName != null) {
|
||||
for (int i = 0; i < itemList.size(); i++) {
|
||||
ComboBoxItem item = itemList.get(i);
|
||||
if (userDefined == item.isUserDefined && currentProfileName.equals(item.file.getName())) {
|
||||
comboBox.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
toFront();
|
||||
}
|
||||
}
|
||||
|
||||
void writeState(SaveState saveState) {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
saveState.putString(CURRENT_PROFILE, item.file.getName());
|
||||
saveState.putBoolean(USER_DEFINED, item.isUserDefined);
|
||||
// Get the current state if the dialog has been displayed
|
||||
if (!initialBuild) {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
|
||||
currentProfileName = item.file.getName();
|
||||
userDefined = item.isUserDefined;
|
||||
|
||||
}
|
||||
saveState.putString(CURRENT_PROFILE, currentProfileName);
|
||||
saveState.putBoolean(USER_DEFINED, userDefined);
|
||||
}
|
||||
|
||||
void readState(SaveState saveState) {
|
||||
String name = saveState.getString(CURRENT_PROFILE, null);
|
||||
if (name != null) {
|
||||
boolean userDefined = saveState.getBoolean(USER_DEFINED, true);
|
||||
for (int i = 0; i < itemList.size(); i++) {
|
||||
ComboBoxItem item = itemList.get(i);
|
||||
if (userDefined == item.isUserDefined && name.equals(item.file.getName())) {
|
||||
comboBox.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentProfileName = saveState.getString(CURRENT_PROFILE, null);
|
||||
if (currentProfileName != null) {
|
||||
userDefined = saveState.getBoolean(USER_DEFINED, true);
|
||||
}
|
||||
}
|
||||
|
||||
void closeProfile() {
|
||||
// dialog not built yet
|
||||
if (initialBuild) {
|
||||
return;
|
||||
}
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
if (item.isChanged) {
|
||||
processItemChanged(item);
|
||||
|
@ -136,6 +187,8 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
}
|
||||
|
||||
protected JPanel buildMainPanel() {
|
||||
initialBuild = true;
|
||||
|
||||
mainPanel = new JPanel(new BorderLayout(10, 5));
|
||||
|
||||
comboModel = new DefaultComboBoxModel<>();
|
||||
|
@ -164,14 +217,64 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
pathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY,
|
||||
GhidraFileChooserMode.FILES_AND_DIRECTORIES, true,
|
||||
new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
|
||||
|
||||
// Set default render to display red if file would not we found
|
||||
// Using include paths
|
||||
pathPanel.getTable().setDefaultRenderer(String.class, new GTableCellRenderer() {
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||
|
||||
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
|
||||
Object value = data.getValue();
|
||||
|
||||
String pathName = (String) value;
|
||||
pathName = (pathName == null ? "" : pathName.trim());
|
||||
|
||||
if (pathName.length() == 0 || pathName.startsWith("#")) {
|
||||
return label;
|
||||
}
|
||||
|
||||
boolean fileExists = true;
|
||||
File file = new File(pathName);
|
||||
fileExists = file.exists();
|
||||
|
||||
// file not found directly, see if one of the include paths will find the file
|
||||
if (!fileExists) {
|
||||
fileExists = doesFileExist(pathName, fileExists);
|
||||
}
|
||||
|
||||
label.setText(pathName.toString());
|
||||
if (!fileExists) {
|
||||
label.setForeground(data.isSelected() ? Tables.FG_ERROR_SELECTED
|
||||
: Tables.FG_ERROR_UNSELECTED);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
});
|
||||
|
||||
tableListener = e -> {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
item.isChanged = true;
|
||||
item.isChanged = !initialBuild;
|
||||
setActionsEnabled();
|
||||
};
|
||||
tableModel = pathPanel.getTable().getModel();
|
||||
tableModel.addTableModelListener(tableListener);
|
||||
|
||||
includePathPanel = new PathnameTablePanel(null, true, false);
|
||||
includePathPanel.setBorder(BorderFactory.createTitledBorder("Include paths"));
|
||||
includePathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY,
|
||||
GhidraFileChooserMode.FILES_AND_DIRECTORIES, true,
|
||||
new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
|
||||
|
||||
parsePathTableListener = e -> {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
item.isChanged = !initialBuild;
|
||||
setActionsEnabled();
|
||||
pathPanel.getTable().repaint();
|
||||
};
|
||||
parsePathTableModel = includePathPanel.getTable().getModel();
|
||||
parsePathTableModel.addTableModelListener(parsePathTableListener);
|
||||
|
||||
JPanel optionsPanel = new JPanel(new BorderLayout());
|
||||
optionsPanel.setBorder(BorderFactory.createTitledBorder("Parse Options"));
|
||||
|
@ -182,7 +285,13 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
JScrollPane pane = new JScrollPane(parseOptionsField);
|
||||
pane.getViewport().setPreferredSize(new Dimension(300, 200));
|
||||
optionsPanel.add(pane, BorderLayout.CENTER);
|
||||
|
||||
|
||||
JPanel archPanel = new JPanel(new BorderLayout());
|
||||
archPanel.setBorder(BorderFactory.createTitledBorder("Program Architecture:"));
|
||||
archPanel.add(new GLabel(" ", SwingConstants.RIGHT));
|
||||
languagePanel = buildLanguagePanel();
|
||||
archPanel.add(languagePanel);
|
||||
|
||||
// create Parse Button
|
||||
|
||||
parseButton = new JButton("Parse to Program");
|
||||
|
@ -195,23 +304,103 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
parseToFileButton.setToolTipText("Parse files and output to archive file");
|
||||
addButton(parseToFileButton);
|
||||
|
||||
pathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
|
||||
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pathPanel, optionsPanel);
|
||||
splitPane.setResizeWeight(0.50);
|
||||
|
||||
mainPanel.add(comboPanel, BorderLayout.NORTH);
|
||||
mainPanel.add(splitPane, BorderLayout.CENTER);
|
||||
|
||||
includePathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
|
||||
JSplitPane optionsPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, includePathPanel, optionsPanel);
|
||||
optionsPane.setResizeWeight(0.50);
|
||||
|
||||
pathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
|
||||
JSplitPane outerPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pathPanel, optionsPane);
|
||||
outerPane.setResizeWeight(0.50);
|
||||
|
||||
mainPanel.add(outerPane, BorderLayout.CENTER);
|
||||
|
||||
mainPanel.add(archPanel, BorderLayout.SOUTH);
|
||||
|
||||
setHelpLocation(new HelpLocation(plugin.getName(), "Parse_C_Source"));
|
||||
|
||||
loadProfile();
|
||||
|
||||
initialBuild = false;
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
private boolean doesFileExist(String pathName, boolean fileExists) {
|
||||
String[] includePaths = includePathPanel.getPaths();
|
||||
for (String path : includePaths) {
|
||||
File file = CParserUtils.getFile(path, pathName);
|
||||
if (file == null) {
|
||||
continue;
|
||||
}
|
||||
fileExists = file.exists();
|
||||
if (fileExists) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fileExists;
|
||||
}
|
||||
|
||||
private JComponent buildLanguagePanel() {
|
||||
languageTextField = new JTextField();
|
||||
languageTextField.setEditable(false);
|
||||
languageTextField.setFocusable(false);
|
||||
|
||||
languageButton = new BrowseButton();
|
||||
languageButton.addActionListener(e -> {
|
||||
SetLanguageDialog dialog = new SetLanguageDialog(plugin.getTool(), languageIDString, compilerIDString,
|
||||
"Select Program Architecture for File DataType Archive");
|
||||
LanguageID languageId = dialog.getLanguageDescriptionID();
|
||||
CompilerSpecID compilerSpecId = dialog.getCompilerSpecDescriptionID();
|
||||
if ((languageId == null) || (compilerSpecId == null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String newLanguageIDString = languageId.getIdAsString();
|
||||
String newCompilerIDString = compilerSpecId.getIdAsString();
|
||||
|
||||
if (!Objects.equals(newLanguageIDString, languageIDString) ||
|
||||
!Objects.equals(newCompilerIDString, compilerIDString)) {
|
||||
itemChanged();
|
||||
}
|
||||
|
||||
languageIDString = newLanguageIDString;
|
||||
compilerIDString = newCompilerIDString;
|
||||
|
||||
updateArchitectureDescription();
|
||||
});
|
||||
|
||||
updateArchitectureDescription();
|
||||
|
||||
languageButton.setName("Set Processor Architecture");
|
||||
Font font = languageButton.getFont();
|
||||
languageButton.setFont(font.deriveFont(Font.BOLD));
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(languageTextField, BorderLayout.CENTER);
|
||||
panel.add(languageButton, BorderLayout.EAST);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void updateArchitectureDescription() {
|
||||
String newProgramArchitectureSummary = "64/32 (primarily for backward compatibility)";
|
||||
|
||||
if (languageIDString != null) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(languageIDString);
|
||||
buf.append(" / ");
|
||||
buf.append(compilerIDString != null ? compilerIDString : "none");
|
||||
newProgramArchitectureSummary = buf.toString();
|
||||
}
|
||||
|
||||
languageTextField.setText(newProgramArchitectureSummary);
|
||||
}
|
||||
|
||||
private void selectionChanged(ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.DESELECTED) {
|
||||
ComboBoxItem item = (ComboBoxItem) e.getItem();
|
||||
if (item.isChanged && !saveAsInProgress) {
|
||||
if (item.isChanged && !saveAsInProgress && !initialBuild) {
|
||||
if (item.isUserDefined) {
|
||||
if (OptionDialog.showOptionDialog(rootPanel, "Save Changes to Profile?",
|
||||
"Profile " + item.file.getName() +
|
||||
|
@ -256,53 +445,6 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private void loadProfile() {
|
||||
if (docListener != null) {
|
||||
parseOptionsField.getDocument().removeDocumentListener(docListener);
|
||||
}
|
||||
tableModel.removeTableModelListener(tableListener);
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
ArrayList<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() {
|
||||
if (docListener == null) {
|
||||
docListener = new DocumentListener() {
|
||||
|
@ -327,6 +469,9 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
|
||||
private void itemChanged() {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
item.isChanged = true;
|
||||
setActionsEnabled();
|
||||
}
|
||||
|
@ -466,6 +611,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
}
|
||||
file.delete();
|
||||
}
|
||||
saveAsInProgress = true;
|
||||
ComboBoxItem newItem = new ComboBoxItem(file, true);
|
||||
if (itemList.contains(newItem)) {
|
||||
itemList.remove(newItem);
|
||||
|
@ -476,7 +622,6 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
index = -index - 1;
|
||||
}
|
||||
itemList.add(index, newItem);
|
||||
saveAsInProgress = true;
|
||||
writeProfile(newItem.file);
|
||||
newItem.isChanged = false;
|
||||
item.isChanged = false;
|
||||
|
@ -491,6 +636,97 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private void loadProfile() {
|
||||
if (docListener != null) {
|
||||
parseOptionsField.getDocument().removeDocumentListener(docListener);
|
||||
}
|
||||
tableModel.removeTableModelListener(tableListener);
|
||||
parsePathTableModel.removeTableModelListener(parsePathTableListener);
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
item.isChanged = false;
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
ArrayList<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) {
|
||||
// write the pathnames
|
||||
try {
|
||||
|
@ -498,7 +734,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
new BufferedWriter(new OutputStreamWriter(outputFile.getOutputStream()));
|
||||
String[] paths = pathPanel.getPaths();
|
||||
for (String path : paths) {
|
||||
writer.write(path);
|
||||
writer.write(path.trim());
|
||||
writer.newLine();
|
||||
}
|
||||
writer.newLine();
|
||||
|
@ -510,6 +746,30 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
writer.write(tok);
|
||||
writer.newLine();
|
||||
}
|
||||
writer.newLine();
|
||||
|
||||
// Write paths
|
||||
String [] includePaths = includePathPanel.getPaths();
|
||||
for (String path : includePaths) {
|
||||
writer.write(path.trim());
|
||||
writer.newLine();
|
||||
}
|
||||
writer.newLine();
|
||||
|
||||
// Write Language ID Spec
|
||||
if (languageIDString != null) {
|
||||
writer.write(languageIDString);
|
||||
}
|
||||
writer.newLine();
|
||||
writer.newLine();
|
||||
|
||||
// Write Compiler ID Spec
|
||||
if (compilerIDString != null) {
|
||||
writer.write(compilerIDString);
|
||||
}
|
||||
writer.newLine();
|
||||
writer.newLine();
|
||||
|
||||
writer.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -537,6 +797,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
private void doParse(boolean parseToFile) {
|
||||
clearStatusText();
|
||||
String options = getParseOptions();
|
||||
String[] includePaths = includePathPanel.getPaths();
|
||||
String[] paths = pathPanel.getPaths();
|
||||
|
||||
if (paths.length == 0) {
|
||||
|
@ -547,15 +808,21 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
|
||||
paths = expandPaths(paths);
|
||||
pathPanel.setPaths(paths);
|
||||
|
||||
if (languageIDString == null || compilerIDString == null ) {
|
||||
Msg.showWarn(getClass(), rootPanel, "Program Architecture not Specified",
|
||||
"A Program Architecture must be specified in order to parse to a file.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (parseToFile) {
|
||||
File file = getSaveFile();
|
||||
if (file != null) {
|
||||
plugin.parse(paths, options, file.getAbsolutePath());
|
||||
plugin.parse(paths, includePaths, options, languageIDString, compilerIDString, file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
else {
|
||||
plugin.parse(paths, options);
|
||||
plugin.parse(paths, includePaths, options, languageIDString, compilerIDString);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -605,7 +872,12 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
|
||||
private void addToComboModel(ResourceFile parent, boolean isUserDefined) {
|
||||
ResourceFile[] children = parent.listFiles();
|
||||
for (ResourceFile resourceFile : children) {
|
||||
List<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(".")) {
|
||||
continue;
|
||||
}
|
||||
|
@ -687,7 +959,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
return parseOptionsField.getText();
|
||||
}
|
||||
|
||||
private class ComboBoxItem {
|
||||
class ComboBoxItem {
|
||||
private ResourceFile file;
|
||||
private boolean isUserDefined;
|
||||
private boolean isChanged;
|
||||
|
@ -745,4 +1017,55 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Methods for Testing
|
||||
//==================================================================================================
|
||||
|
||||
|
||||
GhidraComboBox<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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,6 +180,10 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
|||
addLocalAction(new LockArchiveAction(plugin)); // Archive
|
||||
addLocalAction(new UnlockArchiveAction(plugin)); // Archive
|
||||
|
||||
// Arch group
|
||||
addLocalAction(new SetArchiveArchitectureAction(plugin)); // Archive
|
||||
addLocalAction(new ClearArchiveArchitectureAction(plugin)); // Archive
|
||||
|
||||
// Repository group : version control actions
|
||||
addVersionControlActions(); // Archive
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -37,8 +37,7 @@ public class DeleteArchiveAction extends DockingAction {
|
|||
public DeleteArchiveAction(DataTypeManagerPlugin plugin) {
|
||||
super("Delete Archive", plugin.getName());
|
||||
|
||||
// ACTIONS - auto generated
|
||||
setPopupMenuData(new MenuData(new String[] { "Delete Archive" }, null, "Edit"));
|
||||
setPopupMenuData(new MenuData(new String[] { "Delete Archive" }, null, "File"));
|
||||
|
||||
setKeyBindingData(new KeyBindingData(KeyEvent.VK_DELETE, 0));
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -96,17 +96,21 @@ public class ArchiveUtils {
|
|||
return true;
|
||||
}
|
||||
catch (ReadOnlyException e) {
|
||||
Msg.showError(log, null, "Unable to Lock File for Writing", e.getMessage());
|
||||
Msg.showError(log, null, "Unable to Lock Archive for Writing", e.getMessage());
|
||||
}
|
||||
catch (LockException exc) {
|
||||
Msg.showError(log, null, "Unable to Lock File for Writing",
|
||||
Msg.showError(log, null, "Unable to Lock Archive for Writing",
|
||||
"Unable to obtain lock for archive: " + archive.getName() + "\n" +
|
||||
exc.getMessage());
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
Msg.showError(log, null, "Unable to Lock File for Writing",
|
||||
"Problem attempting to lock archive: " + archive.getName() + "\n" +
|
||||
ioe.getMessage());
|
||||
Throwable cause = ioe.getCause();
|
||||
if (cause == null) {
|
||||
cause = ioe;
|
||||
}
|
||||
Msg.showError(log, null, "Unable to Lock Archive for Writing",
|
||||
"Problem attempting to open archive for update: " + archive.getName() + "\n" +
|
||||
cause.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -219,5 +219,10 @@ public class DataTypeIndexer {
|
|||
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
|
||||
markStale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
|
||||
markStale();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -437,12 +437,13 @@ public class DataTypeManagerHandler {
|
|||
return openArchive(new ResourceFile(file), acquireWriteLock, isUserAction);
|
||||
}
|
||||
|
||||
public Archive openArchive(ResourceFile file, boolean acquireWriteLock, boolean isUserAction)
|
||||
public FileArchive openArchive(ResourceFile file, boolean acquireWriteLock,
|
||||
boolean isUserAction)
|
||||
throws IOException, DuplicateIdException {
|
||||
|
||||
file = file.getCanonicalFile();
|
||||
|
||||
Archive archive = getArchiveForFile(file);
|
||||
FileArchive archive = getArchiveForFile(file);
|
||||
if (archive == null) {
|
||||
archive = new FileArchive(this, file, acquireWriteLock);
|
||||
Archive existingArchive =
|
||||
|
@ -451,11 +452,10 @@ public class DataTypeManagerHandler {
|
|||
archive.close();
|
||||
throw new DuplicateIdException(archive.getName(), existingArchive.getName());
|
||||
}
|
||||
|
||||
addArchivePath(file);
|
||||
addArchive(archive);
|
||||
}
|
||||
if (isUserAction && (archive instanceof FileArchive)) {
|
||||
if (isUserAction) {
|
||||
userOpenedFileArchiveNames.add(getSaveableArchive(file.getAbsolutePath()));
|
||||
}
|
||||
return archive;
|
||||
|
@ -524,7 +524,7 @@ public class DataTypeManagerHandler {
|
|||
return null;
|
||||
}
|
||||
|
||||
private Archive getArchiveForFile(ResourceFile file) {
|
||||
private FileArchive getArchiveForFile(ResourceFile file) {
|
||||
for (Archive archive : openArchives) {
|
||||
if (archive instanceof FileArchive) {
|
||||
FileArchive fileArchive = (FileArchive) archive;
|
||||
|
@ -1230,6 +1230,13 @@ public class DataTypeManagerHandler {
|
|||
listener.sourceArchiveChanged(dataTypeManager, dataTypeSource);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
|
||||
for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
|
||||
listener.programArchitectureChanged(dataTypeManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,4 +23,6 @@ public interface DomainFileArchive extends Archive {
|
|||
public abstract DomainFile getDomainFile();
|
||||
|
||||
public abstract DomainObject getDomainObject();
|
||||
|
||||
public abstract boolean hasExclusiveAccess();
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ public class FileArchive implements Archive {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager getDataTypeManager() {
|
||||
public FileDataTypeManager getDataTypeManager() {
|
||||
return fileDataTypeManager;
|
||||
}
|
||||
|
||||
|
@ -295,6 +295,11 @@ public class FileArchive implements Archive {
|
|||
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
|
||||
setChanged(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
|
||||
setChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -93,6 +93,11 @@ public class ProgramArchive implements DomainFileArchive {
|
|||
// Can't directly close the program archive. Instead you must close the Program.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasExclusiveAccess() {
|
||||
return program.hasExclusiveAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChanged() {
|
||||
return false;
|
||||
|
|
|
@ -87,6 +87,10 @@ public class ProjectArchive implements DomainFileArchive {
|
|||
return Objects.equals(originalDomainFile.getFileID(), other.originalDomainFile.getFileID());
|
||||
}
|
||||
|
||||
public boolean hasExclusiveAccess() {
|
||||
return dataTypeArchive.hasExclusiveAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModifiable() {
|
||||
DomainFile domainFile = getDomainObject().getDomainFile();
|
||||
|
@ -213,5 +217,10 @@ public class ProjectArchive implements DomainFileArchive {
|
|||
public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
|
||||
fireStateChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager dtm) {
|
||||
fireStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.datamgr.editor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import docking.actions.DockingToolActions;
|
||||
|
@ -28,11 +27,9 @@ import ghidra.framework.model.DomainObject;
|
|||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.*;
|
||||
|
||||
/**
|
||||
* Manages program and archive data type editors.
|
||||
|
@ -541,27 +538,53 @@ public class DataTypeEditorManager
|
|||
* Use of this editor requires the presence of the tool-based datatype manager service.
|
||||
*/
|
||||
private class DTMEditFunctionSignatureDialog extends AbstractEditFunctionSignatureDialog {
|
||||
private final FunctionDefinition functionDefinition;
|
||||
private final FunctionDefinition functionDefinition; // may be null
|
||||
private final FunctionSignature oldSignature;
|
||||
private final Category category;
|
||||
|
||||
/**
|
||||
* Construct function signature editor model
|
||||
* @param pluginTool plugin tool
|
||||
* @param title Dialog title
|
||||
* @param category datatype category
|
||||
* @param functionDefinition function definition to be modified (null for new definition)
|
||||
*/
|
||||
DTMEditFunctionSignatureDialog(PluginTool pluginTool, String title, Category category,
|
||||
FunctionDefinition functionDefinition) {
|
||||
super(pluginTool, title, false, false, false);
|
||||
super(pluginTool, title, false, true, false);
|
||||
this.functionDefinition = functionDefinition;
|
||||
this.category = category;
|
||||
this.oldSignature = buildSignature();
|
||||
if (isAdhocCallingConventionPermitted()) {
|
||||
callingConventionComboBox.setEditable(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an adhoc calling convention entry is permitted (i.e., text entry)
|
||||
* @return true if calling convention name may be edited with text entry, else false
|
||||
*/
|
||||
private boolean isAdhocCallingConventionPermitted() {
|
||||
// DataTypeManager dtm = functionDefinition.getDataTypeManager();
|
||||
// return dtm == null || dtm.getProgramArchitecture() == null;
|
||||
// TODO: not sure we should allow unrestricted entries which could lead to using misspelled names
|
||||
return false;
|
||||
}
|
||||
|
||||
private FunctionSignature buildSignature() {
|
||||
if (functionDefinition != null) {
|
||||
if (category.getDataTypeManager() != functionDefinition.getDataTypeManager()) {
|
||||
throw new IllegalArgumentException(
|
||||
"functionDefinition and category must have same Datatypemanager");
|
||||
"FunctionDefinition and Category must have same DataTypeManager");
|
||||
}
|
||||
return functionDefinition;
|
||||
}
|
||||
return new FunctionDefinitionDataType("newFunction");
|
||||
return new FunctionDefinitionDataType("newFunction", category.getDataTypeManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasNoReturn() {
|
||||
return functionDefinition != null ? functionDefinition.hasNoReturn() : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -586,17 +609,21 @@ public class DataTypeEditorManager
|
|||
|
||||
@Override
|
||||
protected String getCallingConventionName() {
|
||||
return getFunctionSignature().getGenericCallingConvention().toString();
|
||||
return getFunctionSignature().getCallingConventionName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getCallingConventionNames() {
|
||||
GenericCallingConvention[] values = GenericCallingConvention.values();
|
||||
List<String> choices = new ArrayList<>();
|
||||
for (GenericCallingConvention value : values) {
|
||||
choices.add(value.toString());
|
||||
// can't rely on functionDefinition which may be null for new definition
|
||||
DataTypeManager dtMgr = getDataTypeManager();
|
||||
if (dtMgr instanceof CompositeViewerDataTypeManager) {
|
||||
dtMgr = ((CompositeViewerDataTypeManager)dtMgr).getOriginalDataTypeManager();
|
||||
}
|
||||
return choices;
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add(Function.UNKNOWN_CALLING_CONVENTION_STRING);
|
||||
list.add(Function.DEFAULT_CALLING_CONVENTION_STRING);
|
||||
list.addAll(dtMgr.getDefinedCallingConventionNames());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -620,36 +647,53 @@ public class DataTypeEditorManager
|
|||
return false;
|
||||
}
|
||||
|
||||
GenericCallingConvention callingConvention =
|
||||
GenericCallingConvention.getGenericCallingConvention(getCallingConvention());
|
||||
newDefinition.setGenericCallingConvention(callingConvention);
|
||||
String callingConvention = getCallingConvention();
|
||||
boolean hasNoReturn = hasNoReturnSelected();
|
||||
try {
|
||||
newDefinition.setCallingConvention(callingConvention);
|
||||
newDefinition.setNoReturn(hasNoReturn);
|
||||
|
||||
DataTypeManager manager = getDataTypeManager();
|
||||
SourceArchive sourceArchive = manager.getLocalSourceArchive();
|
||||
if (functionDefinition == null) {
|
||||
newDefinition.setSourceArchive(sourceArchive);
|
||||
newDefinition.setCategoryPath(category.getCategoryPath());
|
||||
int id = manager.startTransaction("Create Function Definition");
|
||||
manager.addDataType(newDefinition, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
manager.endTransaction(id, true);
|
||||
}
|
||||
else {
|
||||
int id = manager.startTransaction("Edit Function Definition");
|
||||
try {
|
||||
if (!functionDefinition.getName().equals(newDefinition.getName())) {
|
||||
functionDefinition.setName(newDefinition.getName());
|
||||
DataTypeManager manager = getDataTypeManager();
|
||||
SourceArchive sourceArchive = manager.getLocalSourceArchive();
|
||||
if (functionDefinition == null) {
|
||||
newDefinition.setSourceArchive(sourceArchive);
|
||||
newDefinition.setCategoryPath(category.getCategoryPath());
|
||||
int id = manager.startTransaction("Create Function Definition");
|
||||
try {
|
||||
manager.addDataType(newDefinition, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
}
|
||||
finally {
|
||||
manager.endTransaction(id, true);
|
||||
}
|
||||
functionDefinition.setArguments(newDefinition.getArguments());
|
||||
functionDefinition.setGenericCallingConvention(
|
||||
newDefinition.getGenericCallingConvention());
|
||||
functionDefinition.setReturnType(newDefinition.getReturnType());
|
||||
functionDefinition.setVarArgs(newDefinition.hasVarArgs());
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
// not sure why we are squashing this? ...assuming this can't happen
|
||||
Msg.error(this, "Unexpected Exception", e);
|
||||
else {
|
||||
int id = manager.startTransaction("Edit Function Definition");
|
||||
try {
|
||||
if (!functionDefinition.getName().equals(newDefinition.getName())) {
|
||||
functionDefinition.setName(newDefinition.getName());
|
||||
}
|
||||
functionDefinition.setArguments(newDefinition.getArguments());
|
||||
if (!Objects.equals(callingConvention,
|
||||
functionDefinition.getCallingConventionName())) {
|
||||
functionDefinition.setCallingConvention(callingConvention);
|
||||
}
|
||||
functionDefinition.setReturnType(newDefinition.getReturnType());
|
||||
functionDefinition.setVarArgs(newDefinition.hasVarArgs());
|
||||
functionDefinition.setNoReturn(hasNoReturn);
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
// not sure why we are squashing this? ...assuming this can't happen
|
||||
Msg.error(this, "Unexpected Exception", e);
|
||||
}
|
||||
finally {
|
||||
manager.endTransaction(id, true);
|
||||
}
|
||||
}
|
||||
manager.endTransaction(id, true);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
setStatusText("Unknown calling convention specified: " + callingConvention,
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -21,12 +21,17 @@ import javax.swing.Icon;
|
|||
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.task.SwingUpdateManager;
|
||||
|
||||
public class ArchiveNode extends CategoryNode {
|
||||
|
||||
protected static final String DEFAULT_DATA_ORG_DESCRIPTION =
|
||||
"[Using Default Data Organization]";
|
||||
|
||||
protected Archive archive;
|
||||
protected ArchiveNodeCategoryChangeListener listener;
|
||||
private DataTypeManager dataTypeManager; // may be null
|
||||
|
@ -45,6 +50,43 @@ public class ArchiveNode extends CategoryNode {
|
|||
this.archive = archive;
|
||||
}
|
||||
|
||||
protected String buildTooltip(String path) {
|
||||
DataTypeManager dtm = archive.getDataTypeManager();
|
||||
if (dtm == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
|
||||
buf.append(HTMLUtilities.escapeHTML(path));
|
||||
buf.append(HTMLUtilities.BR);
|
||||
String programArchSummary = dtm.getProgramArchitectureSummary();
|
||||
if (programArchSummary != null) {
|
||||
buf.append(HTMLUtilities.HTML_SPACE);
|
||||
buf.append(HTMLUtilities.HTML_SPACE);
|
||||
buf.append(HTMLUtilities.escapeHTML(programArchSummary));
|
||||
addArchiveWarnings(dtm, buf);
|
||||
}
|
||||
else {
|
||||
buf.append(DEFAULT_DATA_ORG_DESCRIPTION);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void addArchiveWarnings(DataTypeManager dtm, StringBuilder buf) {
|
||||
if (dtm instanceof StandAloneDataTypeManager archiveDtm) {
|
||||
if (archiveDtm.isProgramArchitectureMissing()) {
|
||||
buf.append(HTMLUtilities.BR);
|
||||
buf.append(
|
||||
"<font color=\"" + Messages.ERROR +
|
||||
"\">** Missing Language/Compiler Specification **</font>");
|
||||
}
|
||||
else if (archiveDtm.isProgramArchitectureUpgradeRequired()) {
|
||||
buf.append(HTMLUtilities.BR);
|
||||
buf.append("<font color=\"" + Messages.WARNING +
|
||||
"\">** Language Upgrade Required **</font>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void archiveStateChanged() {
|
||||
nodeChanged();
|
||||
}
|
||||
|
@ -172,11 +214,11 @@ public class ArchiveNode extends CategoryNode {
|
|||
return -1; // All ArchiveNodes are before any other types of nodes
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* The hashcode must not be based on the name since it can change based upon the underlying
|
||||
* archive. This must be consistent with the equals method implementation.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getArchive().hashCode();
|
||||
}
|
||||
|
@ -424,5 +466,13 @@ public class ArchiveNode extends CategoryNode {
|
|||
public void sourceArchiveChanged(DataTypeManager manager, SourceArchive sourceArchive) {
|
||||
nodeChangedUpdater.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager manager) {
|
||||
// need to force all cached datatype tooltips to be cleared
|
||||
// due to change in data organization
|
||||
unloadChildren();
|
||||
nodeChangedUpdater.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.plugin.core.datamgr.tree;
|
|||
import javax.swing.Icon;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.BuiltInArchive;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import resources.MultiIcon;
|
||||
|
||||
public class BuiltInArchiveNode extends ArchiveNode {
|
||||
|
@ -35,7 +36,13 @@ public class BuiltInArchiveNode extends ArchiveNode {
|
|||
|
||||
@Override
|
||||
public String getToolTip() {
|
||||
return "Built In Data Types";
|
||||
StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
|
||||
buf.append("Built In Data Types");
|
||||
buf.append(HTMLUtilities.BR);
|
||||
buf.append(HTMLUtilities.HTML_SPACE);
|
||||
buf.append(HTMLUtilities.HTML_SPACE);
|
||||
buf.append(DEFAULT_DATA_ORG_DESCRIPTION);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,11 +22,10 @@ import ghidra.app.plugin.core.datamgr.archive.DomainFileArchive;
|
|||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import resources.MultiIcon;
|
||||
import resources.icons.TranslateIcon;
|
||||
|
||||
public class DomainFileArchiveNode extends ArchiveNode {
|
||||
public abstract class DomainFileArchiveNode extends ArchiveNode {
|
||||
|
||||
//@formatter:off
|
||||
private static Icon CHECKED_OUT_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out");
|
||||
|
@ -98,13 +97,7 @@ public class DomainFileArchiveNode extends ArchiveNode {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getToolTip() {
|
||||
DomainFile file = ((DomainFileArchive) archive).getDomainFile();
|
||||
if (file != null) {
|
||||
return "<html>" + HTMLUtilities.escapeHTML(file.getPathname());
|
||||
}
|
||||
return "[Unsaved New Domain File Archive]";
|
||||
}
|
||||
public abstract String getToolTip();
|
||||
|
||||
@Override
|
||||
public boolean canDelete() {
|
||||
|
@ -120,7 +113,7 @@ public class DomainFileArchiveNode extends ArchiveNode {
|
|||
multiIcon.addIcon(baseIcon);
|
||||
|
||||
if (isReadOnly) {
|
||||
multiIcon.addIcon(new TranslateIcon(READ_ONLY_ICON, 6, 6));
|
||||
multiIcon.addIcon(new TranslateIcon(READ_ONLY_ICON, 14, 3));
|
||||
}
|
||||
else if (isHijacked) {
|
||||
multiIcon.addIcon(new TranslateIcon(HIJACKED_ICON, 8, -4));
|
||||
|
@ -137,6 +130,8 @@ public class DomainFileArchiveNode extends ArchiveNode {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: add program architecture state
|
||||
|
||||
return multiIcon;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import javax.swing.Icon;
|
|||
import generic.jar.ResourceFile;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.app.plugin.core.datamgr.archive.FileArchive;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import resources.MultiIcon;
|
||||
import resources.icons.TranslateIcon;
|
||||
|
||||
|
@ -46,16 +45,16 @@ public class FileArchiveNode extends ArchiveNode {
|
|||
if (hasWriteLock) {
|
||||
multiIcon.addIcon(new TranslateIcon(CHECKED_OUT_EXCLUSIVE_ICON, 8, -4));
|
||||
}
|
||||
|
||||
// TODO: add program architecture state
|
||||
|
||||
return multiIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTip() {
|
||||
ResourceFile file = fileArchive.getFile();
|
||||
if (file != null) {
|
||||
return "<html>" + HTMLUtilities.escapeHTML(file.getAbsolutePath());
|
||||
}
|
||||
return "[Unsaved New Archive]";
|
||||
return buildTooltip(file != null ? file.getAbsolutePath() : "[Unsaved New Archive]");
|
||||
}
|
||||
|
||||
public boolean hasWriteLock() {
|
||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.app.plugin.core.datamgr.tree;
|
|||
|
||||
import ghidra.app.plugin.core.datamgr.archive.ProgramArchive;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
|
||||
public class ProgramArchiveNode extends DomainFileArchiveNode {
|
||||
|
@ -27,10 +28,19 @@ public class ProgramArchiveNode extends DomainFileArchiveNode {
|
|||
|
||||
@Override
|
||||
public String getToolTip() {
|
||||
DataTypeManager dtm = archive.getDataTypeManager();
|
||||
DomainFile file = ((ProgramArchive) archive).getDomainFile();
|
||||
StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
|
||||
if (file != null) {
|
||||
return "<html>" + HTMLUtilities.escapeHTML(file.getPathname());
|
||||
buf.append(HTMLUtilities.escapeHTML(file.toString()));
|
||||
}
|
||||
return "[Unsaved New Program Archive]";
|
||||
else {
|
||||
buf.append("[Unsaved New Program Archive]");
|
||||
}
|
||||
buf.append(HTMLUtilities.BR);
|
||||
buf.append(HTMLUtilities.HTML_SPACE);
|
||||
buf.append(HTMLUtilities.HTML_SPACE);
|
||||
buf.append(HTMLUtilities.escapeHTML(dtm.getProgramArchitectureSummary()));
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package ghidra.app.plugin.core.datamgr.tree;
|
|||
|
||||
import ghidra.app.plugin.core.datamgr.archive.ProjectArchive;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
|
||||
public class ProjectArchiveNode extends DomainFileArchiveNode {
|
||||
|
||||
|
@ -35,10 +34,7 @@ public class ProjectArchiveNode extends DomainFileArchiveNode {
|
|||
@Override
|
||||
public String getToolTip() {
|
||||
DomainFile file = ((ProjectArchive) archive).getDomainFile();
|
||||
if (file != null) {
|
||||
return "<html>" + HTMLUtilities.escapeHTML(file.getPathname());
|
||||
}
|
||||
return "[Unsaved New Project Archive]";
|
||||
return buildTooltip(file != null ? file.getPathname() : "[Unsaved New Project Archive]");
|
||||
}
|
||||
|
||||
public boolean hasWriteLock() {
|
||||
|
|
|
@ -361,6 +361,7 @@ public class DataTypeTreeCopyMoveTask extends Task {
|
|||
DataTypeManager dtm = toCategory.getDataTypeManager();
|
||||
DataTypeManager nodeDtm = dataType.getDataTypeManager();
|
||||
boolean sameManager = (dtm == nodeDtm);
|
||||
|
||||
DataType newDt = !sameManager ? dataType.clone(nodeDtm) : dataType.copy(nodeDtm);
|
||||
|
||||
if (!sameManager && toCategory.isRoot()) {
|
||||
|
|
|
@ -24,7 +24,6 @@ import javax.swing.Icon;
|
|||
import generic.theme.GColor;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.app.services.DataTypeQueryService;
|
||||
import ghidra.program.database.data.ProjectDataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.util.Msg;
|
||||
|
@ -438,8 +437,9 @@ public class DataTypeUtils {
|
|||
msg = "The archive file is not modifiable!\nYou must open the archive for editing\n" +
|
||||
"before performing this operation.\n" + dtm.getName();
|
||||
}
|
||||
else if (dtm instanceof ProjectDataTypeManager) {
|
||||
ProjectDataTypeManager projectDtm = (ProjectDataTypeManager) dtm;
|
||||
else if (dtm instanceof ProjectArchiveBasedDataTypeManager) {
|
||||
ProjectArchiveBasedDataTypeManager projectDtm =
|
||||
(ProjectArchiveBasedDataTypeManager) dtm;
|
||||
if (!projectDtm.isUpdatable() && !projectDtm.getDomainFile().canCheckout()) {
|
||||
msg = "The project archive is not modifiable!\n" + dtm.getName();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.plugin.core.function;
|
|||
import java.awt.Component;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
|
@ -32,6 +33,7 @@ import ghidra.app.util.parser.FunctionSignatureParser;
|
|||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FunctionDefinitionDataType;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
|
@ -110,7 +112,7 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
|
|||
protected abstract String getPrototypeString();
|
||||
|
||||
/**
|
||||
* @return initial calling convention name
|
||||
* @return initial calling convention name or null for unknown
|
||||
*/
|
||||
protected abstract String getCallingConventionName();
|
||||
|
||||
|
@ -282,17 +284,33 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
|
|||
}
|
||||
|
||||
private void setCallingConventionChoices() {
|
||||
String callingConventionName = getCallingConventionName();
|
||||
callingConventionComboBox.removeAllItems();
|
||||
for (String element : getCallingConventionNames()) {
|
||||
if (element.equals(callingConventionName)) {
|
||||
callingConventionName = null;
|
||||
}
|
||||
callingConventionComboBox.addItem(element);
|
||||
}
|
||||
if (callingConventionName != null) {
|
||||
callingConventionComboBox.addItem(callingConventionName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current calling convention selection from dialog
|
||||
* @return current calling convention selection from dialog. Null will be returned
|
||||
* if unknown is selected.
|
||||
*/
|
||||
protected String getCallingConvention() {
|
||||
return (String) callingConventionComboBox.getSelectedItem();
|
||||
protected final String getCallingConvention() {
|
||||
String callingConvention = (String) callingConventionComboBox.getSelectedItem();
|
||||
if (callingConvention != null) {
|
||||
callingConvention = callingConvention.trim();
|
||||
}
|
||||
if (callingConvention.length() == 0 ||
|
||||
Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConvention)) {
|
||||
callingConvention = null;
|
||||
}
|
||||
return callingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,7 +397,6 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
|
|||
FunctionSignatureParser parser = new FunctionSignatureParser(
|
||||
getDataTypeManager(), tool.getService(DataTypeManagerService.class));
|
||||
try {
|
||||
// FIXME: Parser returns FunctionDefinition which only supports GenericCallingConventions
|
||||
return parser.parse(getFunctionSignature(), getSignature());
|
||||
}
|
||||
catch (ParseException e) {
|
||||
|
@ -402,22 +419,7 @@ public abstract class AbstractEditFunctionSignatureDialog extends DialogComponen
|
|||
*/
|
||||
protected final boolean isCallingConventionChanged() {
|
||||
String current = getCallingConventionName();
|
||||
if (current == null && this.getCallingConvention() == null) {
|
||||
return false;
|
||||
}
|
||||
if (current == null && this.getCallingConvention().equals("default")) {
|
||||
return false;
|
||||
}
|
||||
if (current == null && this.getCallingConvention().equals("unknown")) {
|
||||
return false;
|
||||
}
|
||||
if (current == null) {
|
||||
return true;
|
||||
}
|
||||
if (current.equals(getCallingConvention())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !Objects.equals(current, getCallingConvention());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.function;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
|
||||
|
@ -77,7 +78,11 @@ public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDi
|
|||
|
||||
@Override
|
||||
protected List<String> getCallingConventionNames() {
|
||||
return function.getProgram().getFunctionManager().getCallingConventionNames();
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add(Function.UNKNOWN_CALLING_CONVENTION_STRING);
|
||||
list.add(Function.DEFAULT_CALLING_CONVENTION_STRING);
|
||||
list.addAll(function.getProgram().getFunctionManager().getCallingConventionNames());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -182,12 +187,6 @@ public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDi
|
|||
public boolean applyTo(DomainObject obj) {
|
||||
try {
|
||||
String conventionName = getCallingConvention();
|
||||
if ("unknown".equals(conventionName)) {
|
||||
conventionName = null;
|
||||
}
|
||||
else if ("default".equals(conventionName)) {
|
||||
conventionName = function.getDefaultCallingConventionName();
|
||||
}
|
||||
function.setCallingConvention(conventionName);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -124,15 +124,24 @@ public class FunctionEditorModel {
|
|||
return false;
|
||||
}
|
||||
|
||||
public List<String> getCallingConventionNames() {
|
||||
return functionManager.getCallingConventionNames();
|
||||
List<String> getCallingConventionNames() {
|
||||
Collection<String> names =
|
||||
function.getProgram().getFunctionManager().getCallingConventionNames();
|
||||
List<String> list = new ArrayList<>(names);
|
||||
if (callingConventionName != null && !names.contains(callingConventionName)) {
|
||||
list.add(callingConventionName);
|
||||
Collections.sort(list);
|
||||
}
|
||||
list.add(0, Function.DEFAULT_CALLING_CONVENTION_STRING);
|
||||
list.add(0, Function.UNKNOWN_CALLING_CONVENTION_STRING);
|
||||
return list;
|
||||
}
|
||||
|
||||
public String[] getCallFixupNames() {
|
||||
String[] getCallFixupNames() {
|
||||
return program.getCompilerSpec().getPcodeInjectLibrary().getCallFixupNames();
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
void setName(String name) {
|
||||
if (this.name.equals(name)) {
|
||||
return;
|
||||
}
|
||||
|
@ -147,20 +156,20 @@ public class FunctionEditorModel {
|
|||
notifyDataChanged();
|
||||
}
|
||||
|
||||
public String getCallingConventionName() {
|
||||
String getCallingConventionName() {
|
||||
return callingConventionName;
|
||||
}
|
||||
|
||||
public void setHasVarArgs(boolean b) {
|
||||
void setHasVarArgs(boolean b) {
|
||||
hasVarArgs = b;
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
void dispose() {
|
||||
listener = new ModelChangeListener() {
|
||||
@Override
|
||||
public void tableRowsChanged() {
|
||||
|
@ -316,7 +325,7 @@ public class FunctionEditorModel {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean hasValidName() {
|
||||
boolean hasValidName() {
|
||||
if (name.length() == 0) {
|
||||
statusText = "Missing function name";
|
||||
return false;
|
||||
|
@ -381,11 +390,11 @@ public class FunctionEditorModel {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
boolean isValid() {
|
||||
return isValid;
|
||||
}
|
||||
|
||||
public String getFunctionSignatureTextFromModel() {
|
||||
String getFunctionSignatureTextFromModel() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(returnInfo.getFormalDataType().getName()).append(" ");
|
||||
buf.append(getNameString());
|
||||
|
@ -420,7 +429,7 @@ public class FunctionEditorModel {
|
|||
return buf.toString();
|
||||
}
|
||||
|
||||
public String getNameString() {
|
||||
String getNameString() {
|
||||
return name.length() == 0 ? "?" : name;
|
||||
}
|
||||
|
||||
|
@ -428,15 +437,15 @@ public class FunctionEditorModel {
|
|||
return param.getName();
|
||||
}
|
||||
|
||||
public boolean hasVarArgs() {
|
||||
boolean hasVarArgs() {
|
||||
return hasVarArgs;
|
||||
}
|
||||
|
||||
public DataType getReturnType() {
|
||||
DataType getReturnType() {
|
||||
return returnInfo.getDataType();
|
||||
}
|
||||
|
||||
public DataType getFormalReturnType() {
|
||||
DataType getFormalReturnType() {
|
||||
return returnInfo.getFormalDataType();
|
||||
}
|
||||
|
||||
|
@ -444,14 +453,14 @@ public class FunctionEditorModel {
|
|||
return setParameterFormalDataType(returnInfo, formalReturnType);
|
||||
}
|
||||
|
||||
public String getStatusText() {
|
||||
String getStatusText() {
|
||||
if (isInParsingMode) {
|
||||
return PARSING_MODE_STATUS_TEXT;
|
||||
}
|
||||
return statusText;
|
||||
}
|
||||
|
||||
public void setIsInLine(boolean isInLine) {
|
||||
void setIsInLine(boolean isInLine) {
|
||||
if (isInLine == this.isInLine) {
|
||||
return;
|
||||
}
|
||||
|
@ -462,12 +471,12 @@ public class FunctionEditorModel {
|
|||
notifyDataChanged();
|
||||
}
|
||||
|
||||
public void setNoReturn(boolean isNoReturn) {
|
||||
void setNoReturn(boolean isNoReturn) {
|
||||
this.isNoReturn = isNoReturn;
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
public boolean isInlineAllowed() {
|
||||
boolean isInlineAllowed() {
|
||||
return !getAffectiveFunction().isExternal();
|
||||
}
|
||||
|
||||
|
@ -481,19 +490,19 @@ public class FunctionEditorModel {
|
|||
return function.isThunk() ? function.getThunkedFunction(true) : function;
|
||||
}
|
||||
|
||||
public boolean isInLine() {
|
||||
boolean isInLine() {
|
||||
return isInLine;
|
||||
}
|
||||
|
||||
public boolean isNoReturn() {
|
||||
boolean isNoReturn() {
|
||||
return isNoReturn;
|
||||
}
|
||||
|
||||
public String getCallFixupName() {
|
||||
String getCallFixupName() {
|
||||
return callFixupName;
|
||||
}
|
||||
|
||||
public void setCallFixupName(String callFixupName) {
|
||||
void setCallFixupName(String callFixupName) {
|
||||
if (callFixupName.equals(this.callFixupName)) {
|
||||
return;
|
||||
}
|
||||
|
@ -555,11 +564,11 @@ public class FunctionEditorModel {
|
|||
}
|
||||
}
|
||||
|
||||
public int[] getSelectedParameterRows() {
|
||||
int[] getSelectedParameterRows() {
|
||||
return selectedFunctionRows;
|
||||
}
|
||||
|
||||
public void addParameter() {
|
||||
void addParameter() {
|
||||
if (listener != null) {
|
||||
listener.tableRowsChanged();
|
||||
}
|
||||
|
@ -700,7 +709,7 @@ public class FunctionEditorModel {
|
|||
notifyDataChanged();
|
||||
}
|
||||
|
||||
public void moveSelectedParameterUp() {
|
||||
void moveSelectedParameterUp() {
|
||||
if (!canMoveParameterUp()) {
|
||||
throw new AssertException("Attempted to move parameters up when not allowed.");
|
||||
}
|
||||
|
@ -716,7 +725,7 @@ public class FunctionEditorModel {
|
|||
notifyDataChanged();
|
||||
}
|
||||
|
||||
public void moveSelectedParameterDown() {
|
||||
void moveSelectedParameterDown() {
|
||||
if (!canMoveParameterDown()) {
|
||||
throw new AssertException("Attempted to move parameters down when not allowed.");
|
||||
}
|
||||
|
@ -736,7 +745,7 @@ public class FunctionEditorModel {
|
|||
return parameters;
|
||||
}
|
||||
|
||||
public boolean canRemoveParameters() {
|
||||
boolean canRemoveParameters() {
|
||||
if (selectedFunctionRows.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
@ -748,7 +757,7 @@ public class FunctionEditorModel {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean canMoveParameterUp() {
|
||||
boolean canMoveParameterUp() {
|
||||
// remember first row (return type) and auto-params cannot be moved.
|
||||
int minRowToMoveUp = 2 + autoParamCount;
|
||||
if (parameters.size() > 0 && parameters.get(0).getName().equals("this")) {
|
||||
|
@ -757,7 +766,7 @@ public class FunctionEditorModel {
|
|||
return selectedFunctionRows.length == 1 && selectedFunctionRows[0] >= minRowToMoveUp;
|
||||
}
|
||||
|
||||
public boolean canMoveParameterDown() {
|
||||
boolean canMoveParameterDown() {
|
||||
if (selectedFunctionRows.length != 1) {
|
||||
return false;
|
||||
}
|
||||
|
@ -770,12 +779,12 @@ public class FunctionEditorModel {
|
|||
return selectedRow >= minRowToMoveDown && selectedRow < parameters.size();
|
||||
}
|
||||
|
||||
public void setParameterName(ParamInfo param, String newName) {
|
||||
void setParameterName(ParamInfo param, String newName) {
|
||||
param.setName(newName);
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
public boolean setParameterFormalDataType(ParamInfo param, DataType formalDataType) {
|
||||
boolean setParameterFormalDataType(ParamInfo param, DataType formalDataType) {
|
||||
boolean isReturn = (param.getOrdinal() == Parameter.RETURN_ORIDINAL);
|
||||
try {
|
||||
formalDataType = VariableUtilities.checkDataType(formalDataType, isReturn, 0, program);
|
||||
|
@ -839,11 +848,11 @@ public class FunctionEditorModel {
|
|||
}
|
||||
}
|
||||
|
||||
public VariableStorage getReturnStorage() {
|
||||
VariableStorage getReturnStorage() {
|
||||
return returnInfo.getStorage();
|
||||
}
|
||||
|
||||
public Function getFunction() {
|
||||
Function getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
|
@ -940,7 +949,7 @@ public class FunctionEditorModel {
|
|||
return allowCustomStorage;
|
||||
}
|
||||
|
||||
public boolean apply() {
|
||||
boolean apply() {
|
||||
if (!modelChanged) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1085,16 +1094,10 @@ public class FunctionEditorModel {
|
|||
}
|
||||
|
||||
public void setFunctionData(FunctionDefinitionDataType functionDefinition) {
|
||||
|
||||
name = functionDefinition.getName();
|
||||
|
||||
GenericCallingConvention genericCallingConvention =
|
||||
functionDefinition.getGenericCallingConvention();
|
||||
if (genericCallingConvention != null &&
|
||||
genericCallingConvention != GenericCallingConvention.unknown) {
|
||||
PrototypeModel matchConvention =
|
||||
function.getProgram().getCompilerSpec().matchConvention(genericCallingConvention);
|
||||
setCallingConventionName(matchConvention.getName());
|
||||
}
|
||||
setCallingConventionName(functionDefinition.getCallingConventionName());
|
||||
|
||||
if (!isSameSize(returnInfo.getFormalDataType(), functionDefinition.getReturnType())) {
|
||||
returnInfo.setStorage(VariableStorage.UNASSIGNED_STORAGE);
|
||||
|
@ -1110,6 +1113,7 @@ public class FunctionEditorModel {
|
|||
parameters.add(new ParamInfo(this, paramDefinition));
|
||||
}
|
||||
hasVarArgs = functionDefinition.hasVarArgs();
|
||||
|
||||
fixupOrdinals();
|
||||
|
||||
if (allowCustomStorage) {
|
||||
|
@ -1162,11 +1166,11 @@ public class FunctionEditorModel {
|
|||
return null;
|
||||
}
|
||||
|
||||
public boolean isInParsingMode() {
|
||||
boolean isInParsingMode() {
|
||||
return isInParsingMode;
|
||||
}
|
||||
|
||||
public void setSignatureFieldText(String text) {
|
||||
void setSignatureFieldText(String text) {
|
||||
signatureFieldText = text;
|
||||
boolean signatureTextFieldInSync =
|
||||
signatureFieldText.equals(getFunctionSignatureTextFromModel());
|
||||
|
@ -1177,24 +1181,32 @@ public class FunctionEditorModel {
|
|||
}
|
||||
}
|
||||
|
||||
public void resetSignatureTextField() {
|
||||
void resetSignatureTextField() {
|
||||
setSignatureFieldText(getFunctionSignatureTextFromModel());
|
||||
}
|
||||
|
||||
public boolean hasChanges() {
|
||||
boolean hasChanges() {
|
||||
return !Objects.equals(getFunctionSignatureTextFromModel(), signatureFieldText);
|
||||
}
|
||||
|
||||
public void parseSignatureFieldText() throws ParseException, CancelledException {
|
||||
void parseSignatureFieldText() throws ParseException, CancelledException {
|
||||
FunctionSignatureParser parser =
|
||||
new FunctionSignatureParser(program.getDataTypeManager(), dataTypeManagerService);
|
||||
FunctionDefinitionDataType f = parser.parse(getFunctionSignature(), signatureFieldText);
|
||||
|
||||
// Preserve calling convention and noreturn flag from current model
|
||||
f.setNoReturn(isNoReturn);
|
||||
try {
|
||||
f.setCallingConvention(callingConventionName);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// ignore
|
||||
}
|
||||
setFunctionData(f);
|
||||
isInParsingMode = false;
|
||||
}
|
||||
|
||||
public int getFunctionNameStartPosition() {
|
||||
int getFunctionNameStartPosition() {
|
||||
return returnInfo.getFormalDataType().getName().length() + 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -221,7 +221,8 @@ public final class LanguageProviderPlugin extends Plugin implements ApplicationL
|
|||
Program program = (Program) dobj;
|
||||
|
||||
monitor.setMessage("Identify Language...");
|
||||
SetLanguageDialog dialog = new SetLanguageDialog(tool, program);
|
||||
SetLanguageDialog dialog = new SetLanguageDialog(tool, program,
|
||||
"Set Language: " + program.getDomainFile().getName());
|
||||
LanguageID langDescID = dialog.getLanguageDescriptionID();
|
||||
CompilerSpecID compilerSpecDescID = dialog.getCompilerSpecDescriptionID();
|
||||
if ((langDescID == null) || (compilerSpecDescID == null)) {
|
||||
|
|
|
@ -22,59 +22,81 @@ import ghidra.framework.plugintool.PluginTool;
|
|||
import ghidra.plugin.importer.LcsSelectionListener;
|
||||
import ghidra.plugin.importer.NewLanguagePanel;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.DefaultLanguageService;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class SetLanguageDialog extends DialogComponentProvider {
|
||||
|
||||
private NewLanguagePanel selectLangPanel;
|
||||
private LanguageService langService;
|
||||
private PluginTool tool;
|
||||
private Program currProgram;
|
||||
private LanguageCompilerSpecPair currentLCSPair;
|
||||
|
||||
private LanguageID dialogLanguageDescID;
|
||||
private CompilerSpecID dialogCompilerSpecDescID;
|
||||
private LanguageID dialogLanguageID;
|
||||
private CompilerSpecID dialogCompilerSpecID;
|
||||
|
||||
LcsSelectionListener listener = e -> {
|
||||
LanguageID langID = null;
|
||||
CompilerSpecID compilerSpecID = null;
|
||||
if (e.selection != null) {
|
||||
if (e != null && e.selection != null) {
|
||||
langID = e.selection.languageID;
|
||||
compilerSpecID = e.selection.compilerSpecID;
|
||||
}
|
||||
if ((langID != null) && (langID.equals(currProgram.getLanguageID()))) {
|
||||
if ((compilerSpecID != null) &&
|
||||
(compilerSpecID.equals(currProgram.getCompilerSpec().getCompilerSpecID()))) {
|
||||
//selectLangPanel.setNotificationText("Please select a different Language or Compiler Spec.");
|
||||
if ((currentLCSPair != null) && (langID != null) &&
|
||||
(langID.equals(currentLCSPair.getLanguageID()))) {
|
||||
if (compilerSpecID != null &&
|
||||
compilerSpecID.equals(currentLCSPair.getCompilerSpecID())) {
|
||||
setStatusText("Please select a different Language or Compiler Spec.");
|
||||
setOkEnabled(false);
|
||||
}
|
||||
else {
|
||||
//selectLangPanel.setNotificationText(null);
|
||||
setStatusText(null);
|
||||
setOkEnabled(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
//selectLangPanel.setNotificationText("Setting the language from '" + currProgram.getLanguageName() + "' to '" + langDesc.getName() + "'...");
|
||||
//selectLangPanel.setNotificationText(null);
|
||||
setStatusText(null);
|
||||
setOkEnabled(langID != null);
|
||||
};
|
||||
|
||||
public SetLanguageDialog(PluginTool tool, Program program) {
|
||||
super(getTitle(program), true, true, true, false);
|
||||
currProgram = program;
|
||||
this.tool = tool;
|
||||
/**
|
||||
* Construct set Language/Compiler-Spec dialog
|
||||
* @param tool parent tool
|
||||
* @param programArch current program architecture or null
|
||||
* @param title dialog title
|
||||
*/
|
||||
public SetLanguageDialog(PluginTool tool, ProgramArchitecture programArch, String title) {
|
||||
this(tool, programArch != null ? programArch.getLanguageCompilerSpecPair() : null, title);
|
||||
}
|
||||
|
||||
langService = DefaultLanguageService.getLanguageService();
|
||||
/**
|
||||
* Construct set Language/Compiler-Spec dialog
|
||||
* @param tool parent tool
|
||||
* @param languageId initial language ID or null
|
||||
* @param compilerSpecId initial Compiler-Spec ID or null
|
||||
* @param title dialog title
|
||||
*/
|
||||
public SetLanguageDialog(PluginTool tool, String languageId, String compilerSpecId,
|
||||
String title) {
|
||||
this(tool, getLanguageCompilerSpecPair(languageId, compilerSpecId), title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct set Language/Compiler-Spec dialog
|
||||
* @param tool parent tool
|
||||
* @param lcsPair language/compiler-spec ID pair or null
|
||||
* @param title dialog title
|
||||
*/
|
||||
public SetLanguageDialog(PluginTool tool, LanguageCompilerSpecPair lcsPair, String title) {
|
||||
super(title, true, true, true, false);
|
||||
currentLCSPair = lcsPair;
|
||||
this.tool = tool;
|
||||
|
||||
selectLangPanel = new NewLanguagePanel();
|
||||
|
||||
LanguageCompilerSpecPair lcsPair = new LanguageCompilerSpecPair(currProgram.getLanguageID(),
|
||||
currProgram.getCompilerSpec().getCompilerSpecID());
|
||||
selectLangPanel.setSelectedLcsPair(lcsPair);
|
||||
if (lcsPair != null) {
|
||||
selectLangPanel.setSelectedLcsPair(lcsPair);
|
||||
}
|
||||
|
||||
selectLangPanel.addSelectionListener(listener);
|
||||
|
||||
|
@ -83,35 +105,57 @@ public class SetLanguageDialog extends DialogComponentProvider {
|
|||
addWorkPanel(selectLangPanel);
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
//getComponent().setPreferredSize(new Dimension(450, 430));
|
||||
|
||||
setOkEnabled(false);
|
||||
setHelpLocation(new HelpLocation("LanguageProviderPlugin", "set language"));
|
||||
selectLangPanel.setShowRecommendedCheckbox(false);
|
||||
|
||||
listener.valueChanged(null); // kick to establish initial button enablement
|
||||
}
|
||||
|
||||
private static String getTitle(Program program) {
|
||||
return "Set Language: " + program.getDomainFile().getName();
|
||||
private static LanguageCompilerSpecPair getLanguageCompilerSpecPair(String languageIdStr,
|
||||
String compilerSpecIdStr) {
|
||||
if (languageIdStr == null) {
|
||||
return null;
|
||||
}
|
||||
LanguageService languageService = DefaultLanguageService.getLanguageService();
|
||||
try {
|
||||
LanguageID languageId = new LanguageID(languageIdStr);
|
||||
LanguageDescription descr = languageService.getLanguageDescription(languageId);
|
||||
CompilerSpecID compilerSpecId = new CompilerSpecID(compilerSpecIdStr);
|
||||
try {
|
||||
descr.getCompilerSpecDescriptionByID(compilerSpecId);
|
||||
}
|
||||
catch (CompilerSpecNotFoundException e) {
|
||||
Msg.warn(SetLanguageDialog.class, e.getMessage());
|
||||
}
|
||||
return new LanguageCompilerSpecPair(languageId, compilerSpecId);
|
||||
}
|
||||
catch (LanguageNotFoundException e) {
|
||||
Msg.warn(SetLanguageDialog.class, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
LanguageID getLanguageDescriptionID() {
|
||||
public LanguageID getLanguageDescriptionID() {
|
||||
tool.showDialog(this);
|
||||
return dialogLanguageDescID;
|
||||
return dialogLanguageID;
|
||||
}
|
||||
|
||||
CompilerSpecID getCompilerSpecDescriptionID() {
|
||||
return dialogCompilerSpecDescID;
|
||||
public CompilerSpecID getCompilerSpecDescriptionID() {
|
||||
return dialogCompilerSpecID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
LanguageCompilerSpecPair selectedLcsPair = selectLangPanel.getSelectedLcsPair();
|
||||
if (selectedLcsPair == null) {
|
||||
dialogLanguageDescID = null;
|
||||
dialogCompilerSpecDescID = null;
|
||||
dialogLanguageID = null;
|
||||
dialogCompilerSpecID = null;
|
||||
}
|
||||
else {
|
||||
dialogLanguageDescID = selectedLcsPair.languageID;
|
||||
dialogCompilerSpecDescID = selectedLcsPair.compilerSpecID;
|
||||
dialogLanguageID = selectedLcsPair.languageID;
|
||||
dialogCompilerSpecID = selectedLcsPair.compilerSpecID;
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
package ghidra.app.util;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
import ghidra.util.InvalidNameException;
|
||||
|
||||
public class DataTypeNamingUtil {
|
||||
|
@ -42,12 +44,16 @@ public class DataTypeNamingUtil {
|
|||
|
||||
StringBuilder sb = new StringBuilder(ANONYMOUS_FUNCTION_DEF_PREFIX);
|
||||
|
||||
GenericCallingConvention convention = functionDefinition.getGenericCallingConvention();
|
||||
if (convention != null && convention != GenericCallingConvention.unknown) {
|
||||
sb.append(convention.getDeclarationName());
|
||||
if (functionDefinition.hasNoReturn()) {
|
||||
sb.append("_").append(FunctionSignature.NORETURN_DISPLAY_STRING);
|
||||
}
|
||||
sb.append("_");
|
||||
|
||||
String convention = functionDefinition.getCallingConventionName();
|
||||
if (convention != null && !Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(convention)) {
|
||||
sb.append("_").append(convention);
|
||||
}
|
||||
|
||||
sb.append("_");
|
||||
sb.append(mangleDTName(returnType.getName()));
|
||||
for (ParameterDefinition p : parameters) {
|
||||
sb.append("_").append(mangleDTName(p.getDataType().getName()));
|
||||
|
|
|
@ -289,12 +289,20 @@ public class ToolTipUtils {
|
|||
}
|
||||
buffy.append(friendlyEncodeHTML(function.getReturnType().getName()));
|
||||
buffy.append(HTML_SPACE);
|
||||
PrototypeModel callingConvention = function.getCallingConvention();
|
||||
if (isNonDefaultCallingConvention(callingConvention)) {
|
||||
buffy.append(friendlyEncodeHTML(callingConvention.getName()));
|
||||
|
||||
String callingConvention = function.getCallingConventionName();
|
||||
if (callingConvention.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
|
||||
callingConvention = function.getCallingConvention().getName();
|
||||
}
|
||||
if (!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
|
||||
String ccHtml = friendlyEncodeHTML(callingConvention);
|
||||
if (function.hasUnknownCallingConventionName()) {
|
||||
ccHtml = colorString(Color.RED, ccHtml);
|
||||
}
|
||||
buffy.append(ccHtml);
|
||||
buffy.append(HTML_SPACE);
|
||||
}
|
||||
|
||||
|
||||
String functionName = StringUtilities.trimMiddle(function.getName(), LINE_LENGTH);
|
||||
buffy.append(colorString(FunctionColors.NAME, friendlyEncodeHTML(functionName)));
|
||||
buffy.append(HTML_SPACE).append("(");
|
||||
|
@ -304,14 +312,6 @@ public class ToolTipUtils {
|
|||
return buffy.toString();
|
||||
}
|
||||
|
||||
private static boolean isNonDefaultCallingConvention(PrototypeModel callingConvention) {
|
||||
if (callingConvention == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Function.DEFAULT_CALLING_CONVENTION_STRING.equals(callingConvention.getName());
|
||||
}
|
||||
|
||||
private static void buildParameterPreview(Function function, StringBuilder buffy) {
|
||||
|
||||
int rawTextLength = 0;
|
||||
|
|
|
@ -16,13 +16,11 @@
|
|||
package ghidra.app.util.bin.format.dwarf4.next;
|
||||
|
||||
import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
|
||||
import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.DW_TAG_base_type;
|
||||
import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.DW_TAG_subrange_type;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -35,7 +33,9 @@ import ghidra.program.database.DatabaseObject;
|
|||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* Creates Ghidra {@link DataType}s using information from DWARF debug entries. The caller
|
||||
|
@ -301,6 +301,7 @@ public class DWARFDataTypeImporter {
|
|||
FunctionDefinitionDataType funcDef =
|
||||
new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager);
|
||||
funcDef.setReturnType(returnType.dataType);
|
||||
funcDef.setNoReturn(diea.getBool(DW_AT_noreturn, false));
|
||||
funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()]));
|
||||
|
||||
if (!diea.getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) {
|
||||
|
@ -308,7 +309,12 @@ public class DWARFDataTypeImporter {
|
|||
}
|
||||
|
||||
if (foundThisParam) {
|
||||
funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall);
|
||||
try {
|
||||
funcDef.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(this, "Unexpected calling convention error", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (dni.isAnon() && mangleAnonFuncNames) {
|
||||
|
|
|
@ -15,22 +15,22 @@
|
|||
*/
|
||||
package ghidra.app.util.bin.format.dwarf4.next;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.format.dwarf4.*;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFEncoding;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.*;
|
||||
import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
|
||||
import ghidra.app.util.bin.format.dwarf4.next.DWARFDataTypeImporter.DWARFDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utility.function.Dummy;
|
||||
|
||||
|
@ -726,13 +726,19 @@ public class DWARFDataTypeManager {
|
|||
FunctionDefinitionDataType funcDef =
|
||||
new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager);
|
||||
funcDef.setReturnType(returnDataType);
|
||||
funcDef.setNoReturn(diea.getBool(DWARFAttribute.DW_AT_noreturn, false));
|
||||
funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()]));
|
||||
|
||||
if (!diea.getHeadFragment().getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) {
|
||||
funcDef.setVarArgs(true);
|
||||
}
|
||||
if (foundThisParam) {
|
||||
funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall);
|
||||
try {
|
||||
funcDef.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(this, "Unexpected calling convention error", e);
|
||||
}
|
||||
}
|
||||
|
||||
return funcDef;
|
||||
|
|
|
@ -388,7 +388,8 @@ public class DWARFFunctionImporter {
|
|||
Parameter curparam = buildParameter(gfunc, i, dfunc.params.get(i), diea);
|
||||
params.add(curparam);
|
||||
if (i == 0 && checkThisParameter(dfunc.params.get(0), diea)) {
|
||||
convention = compilerSpec.matchConvention(GenericCallingConvention.thiscall);
|
||||
convention =
|
||||
compilerSpec.matchConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,27 +17,52 @@ package ghidra.app.util.cparser.C;
|
|||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.cparser.CPP.PreProcessor;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.IncompatibleLanguageException;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.DefaultLanguageService;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class CParserUtils {
|
||||
|
||||
|
||||
private CParserUtils() {
|
||||
// utils class
|
||||
}
|
||||
|
||||
public record CParseResults(PreProcessor preProcessor, String cppParseMessages, String cParseMessages, boolean successful) {
|
||||
public String getFormattedParseMessage(String errMsg) {
|
||||
String message = "";
|
||||
|
||||
if (errMsg != null) {
|
||||
message += errMsg + "\n\n";
|
||||
}
|
||||
|
||||
String msg = cppParseMessages;
|
||||
if (msg != null && msg.length() != 0) {
|
||||
message += "CParser Messages:\n" + msg + "\n\n";
|
||||
}
|
||||
|
||||
msg = cppParseMessages;
|
||||
if (msg != null && msg.length() != 0) {
|
||||
message += "PreProcessor Messages:\n" + msg;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given function signature text. Any exceptions will be handled herein
|
||||
|
@ -88,7 +113,7 @@ public class CParserUtils {
|
|||
* [0]= part before function name
|
||||
* [1]= function name
|
||||
* [2]= parameter body after function name
|
||||
* @param signature
|
||||
* @param signature function signature string to split
|
||||
* @return parts array or null if split failed
|
||||
*/
|
||||
private static String[] splitFunctionSignature(String signature) {
|
||||
|
@ -136,7 +161,7 @@ public class CParserUtils {
|
|||
|
||||
/**
|
||||
* Get a temporary name of a specified length (tttt....)
|
||||
* @param length
|
||||
* @param length of temporary string
|
||||
* @return temporary name string
|
||||
*/
|
||||
private static String getTempName(int length) {
|
||||
|
@ -158,6 +183,7 @@ public class CParserUtils {
|
|||
* parsing exceptions. This allows clients to perform exception handling that
|
||||
* better matches their workflow.
|
||||
* @return the data type that is created as a result of parsing; null if there was a problem
|
||||
* @throws ParseException for catastrophic errors in C parsing
|
||||
*/
|
||||
public static FunctionDefinitionDataType parseSignature(DataTypeManagerService service,
|
||||
Program program, String signatureText, boolean handleExceptions) throws ParseException {
|
||||
|
@ -237,8 +263,6 @@ public class CParserUtils {
|
|||
*
|
||||
* @param dataFileName name of data type archive file (include the .gdt extension)
|
||||
*
|
||||
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
|
||||
*
|
||||
* @param monitor used to cancel or provide results
|
||||
*
|
||||
* @return the data types in the ghidra .gdt archive file
|
||||
|
@ -250,15 +274,48 @@ public class CParserUtils {
|
|||
*/
|
||||
|
||||
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
|
||||
PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
File file = new File(dataFileName);
|
||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
|
||||
|
||||
parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, cpp, monitor);
|
||||
return parseHeaderFiles(openDTMgrs, filenames, null, args, dataFileName, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
|
||||
* with in the provided dataFileName.
|
||||
*
|
||||
* Note: Using another open archive while parsing will cause:
|
||||
* - a dependence on the other archive
|
||||
* - any missing data types while parsing are supplied if present from an openDTMgr
|
||||
* - after parsing all data types parsed with an equivalent data type in any openDTMgr
|
||||
* replaced by the data type from the openDTMgr
|
||||
*
|
||||
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
|
||||
*
|
||||
* @param openDTMgrs array of datatypes managers to use for undefined data types
|
||||
*
|
||||
* @param filenames names of files in order to parse, could include strings with
|
||||
* "#" at start, which are ignored as comments
|
||||
* @param includePaths paths to include files, instead of using "-I<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 dtMgr;
|
||||
return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dataFileName, null, null, monitor);
|
||||
}
|
||||
|
||||
|
||||
|
@ -280,6 +337,7 @@ public class CParserUtils {
|
|||
*
|
||||
* @param filenames names of files in order to parse, could include strings with
|
||||
* "#" at start, which are ignored as comments
|
||||
* @param includePaths path to include files, could also be in args with "-I<includepath>"
|
||||
* @param args arguments for parsing, "-D<defn>=", "-I<includepath>"
|
||||
*
|
||||
* @param dataFileName name of data type archive file (include the .gdt extension)
|
||||
|
@ -287,8 +345,6 @@ public class CParserUtils {
|
|||
* @param languageId language identication to use for data type organization definitions (int, long, ptr size)
|
||||
* @param compileSpecId compiler specification to use for parsing
|
||||
*
|
||||
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
|
||||
*
|
||||
* @param monitor used to cancel or provide results
|
||||
*
|
||||
* @return the data types in the ghidra .gdt archive file
|
||||
|
@ -298,14 +354,17 @@ public class CParserUtils {
|
|||
* @throws IOException if there io are errors saving the archive
|
||||
*
|
||||
*/
|
||||
public static DataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
|
||||
String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
|
||||
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
|
||||
File file = new File(dataFileName);
|
||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
|
||||
|
||||
String messages = parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, languageId, compileSpecId, cpp, monitor);
|
||||
CParseResults results;
|
||||
results = parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, languageId, compileSpecId, monitor);
|
||||
|
||||
String messages = results.getFormattedParseMessage(null);
|
||||
Msg.info(CParserUtils.class, messages);
|
||||
|
||||
dtMgr.save();
|
||||
|
@ -331,15 +390,13 @@ public class CParserUtils {
|
|||
*
|
||||
* @param filenames names of files in order to parse, could include strings with
|
||||
* "#" at start, which are ignored as comments
|
||||
* @param args arguments for parsing, "-D<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 languageId language identication to use for data type organization definitions (int, long, ptr size)
|
||||
* @param compileSpecId compiler specification to use for parsing
|
||||
*
|
||||
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
|
||||
*
|
||||
* @param monitor used to cancel or provide results
|
||||
*
|
||||
* @return a formatted string of any output from pre processor parsing or C parsing
|
||||
|
@ -349,39 +406,84 @@ public class CParserUtils {
|
|||
* @throws IOException if there io are errors saving the archive
|
||||
*
|
||||
*/
|
||||
public static String parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
|
||||
String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
|
||||
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
|
||||
return parseHeaderFiles(openDTMgrs, filenames, null, args, existingDTMgr, languageId, compileSpecId, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided
|
||||
* DTMgr.
|
||||
*
|
||||
* Note: Using another open archive while parsing will cause:
|
||||
* - a dependence on the other archive
|
||||
* - any missing data types while parsing are supplied if present from an openDTMgr
|
||||
* - after parsing all data types parsed with an equivalent data type in any openDTMgr
|
||||
* replaced by the data type from the openDTMgr
|
||||
*
|
||||
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
|
||||
*
|
||||
* NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
|
||||
* @param openDTMgrs array of datatypes managers to use for undefined data types
|
||||
*
|
||||
* @param filenames names of files in order to parse, could include strings with
|
||||
* "#" at start, which are ignored as comments
|
||||
* @param includePaths paths to include files, instead of using "-I<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 {
|
||||
|
||||
Language language = DefaultLanguageService.getLanguageService().getLanguage(new LanguageID(languageId));
|
||||
CompilerSpec compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compileSpecId));
|
||||
|
||||
String dtmgrName = existingDTMgr.getName();
|
||||
if (existingDTMgr instanceof FileDataTypeManager) {
|
||||
dtmgrName = ((FileDataTypeManager) existingDTMgr).getPath();
|
||||
}
|
||||
|
||||
ProgramDB program = new ProgramDB(dtmgrName, language, compilerSpec, CParserUtils.class);
|
||||
try {
|
||||
DataTypeManager programDtm = program.getDataTypeManager();
|
||||
String messages = parseHeaderFiles(openDTMgrs, filenames, args, programDtm, cpp, monitor);
|
||||
|
||||
int txId = existingDTMgr.startTransaction("Add Types");
|
||||
try {
|
||||
Iterator<DataType> allDataTypes = programDtm.getAllDataTypes();
|
||||
while (allDataTypes.hasNext()) {
|
||||
existingDTMgr.resolve(allDataTypes.next(), null);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
existingDTMgr.endTransaction(txId, true);
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
finally {
|
||||
program.release(CParserUtils.class);
|
||||
if (existingDTMgr instanceof StandAloneDataTypeManager) {
|
||||
try {
|
||||
((StandAloneDataTypeManager) existingDTMgr).setProgramArchitecture(language, compilerSpec.getCompilerSpecID(),
|
||||
StandAloneDataTypeManager.LanguageUpdateOption.UNCHANGED, monitor);
|
||||
}
|
||||
catch (CompilerSpecNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (LanguageNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// ignore
|
||||
}
|
||||
catch (LockException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (IncompatibleLanguageException e) {
|
||||
// Shouldn't happen, unless already had a language
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, existingDTMgr, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -405,12 +507,11 @@ public class CParserUtils {
|
|||
*
|
||||
* @param filenames names of files in order to parse, could include strings with
|
||||
* "#" at start, which are ignored as comments
|
||||
* @param args arguments for parsing, "-D<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 cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
|
||||
*
|
||||
* @param monitor used to cancel or provide results
|
||||
*
|
||||
* @return a formatted string of any output from pre processor parsing or C parsing
|
||||
|
@ -418,22 +519,31 @@ public class CParserUtils {
|
|||
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
|
||||
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
|
||||
*/
|
||||
public static String parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames,
|
||||
String args[], DataTypeManager dtMgr, PreProcessor cpp, TaskMonitor monitor)
|
||||
public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames, String[] includePaths,
|
||||
String args[], DataTypeManager dtMgr, TaskMonitor monitor)
|
||||
throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException {
|
||||
|
||||
String cppMessages = "";
|
||||
if (cpp == null) {
|
||||
cpp = new PreProcessor();
|
||||
}
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
PreProcessor cpp = new PreProcessor();
|
||||
|
||||
cpp.setArgs(args);
|
||||
cpp.addIncludePaths(includePaths);
|
||||
|
||||
PrintStream os = System.out;
|
||||
String fName = dtMgr.getName().replace(".gdt","")+"_CParser.out";
|
||||
|
||||
String fName = dtMgr.getName();
|
||||
|
||||
// make a path to tmpdir with name of data type manager
|
||||
String path = System.getProperty("java.io.tmpdir") + File.pathSeparator + fName;
|
||||
// if file data type manager, use path to .gdt file
|
||||
if (dtMgr instanceof FileDataTypeManager) {
|
||||
path = ((FileDataTypeManager) dtMgr).getPath();
|
||||
}
|
||||
path = path + "_CParser.out";
|
||||
|
||||
try {
|
||||
os = new PrintStream(new FileOutputStream(fName));
|
||||
os = new PrintStream(new FileOutputStream(path));
|
||||
} catch (FileNotFoundException e2) {
|
||||
Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2);
|
||||
}
|
||||
|
@ -442,8 +552,10 @@ public class CParserUtils {
|
|||
System.setOut(os);
|
||||
|
||||
cpp.setMonitor(monitor);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
cpp.setOutputStream(bos);
|
||||
|
||||
boolean parseSucceeded = false;
|
||||
try {
|
||||
for (String filename : filenames) {
|
||||
if (monitor.isCancelled()) {
|
||||
|
@ -469,9 +581,9 @@ public class CParserUtils {
|
|||
parseFile(filename, monitor, cpp);
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException re) {
|
||||
parseSucceeded = true;
|
||||
} catch (Throwable e) {
|
||||
Msg.info(cpp, cpp.getParseMessages());
|
||||
throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
|
||||
} finally {
|
||||
System.out.println(bos);
|
||||
os.flush();
|
||||
|
@ -481,12 +593,16 @@ public class CParserUtils {
|
|||
}
|
||||
|
||||
cppMessages = cpp.getParseMessages();
|
||||
if (!parseSucceeded) {
|
||||
return new CParseResults(cpp, "", cppMessages, false);
|
||||
}
|
||||
|
||||
// process all the defines and add any that are integer values into
|
||||
// the Equates table
|
||||
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
|
||||
|
||||
String parserMessages = "";
|
||||
boolean cparseSucceeded = false;
|
||||
if (!monitor.isCancelled()) {
|
||||
monitor.setMessage("Parsing C");
|
||||
|
||||
|
@ -497,12 +613,15 @@ public class CParserUtils {
|
|||
cParser.setParseFileName(fName);
|
||||
cParser.setMonitor(monitor);
|
||||
cParser.parse(bis);
|
||||
cparseSucceeded = cParser.didParseSucceed();
|
||||
} catch (RuntimeException re) {
|
||||
Msg.info(cpp, cpp.getParseMessages());
|
||||
} finally {
|
||||
parserMessages = cParser.getParseMessages();
|
||||
}
|
||||
}
|
||||
|
||||
return getFormattedParseMessage(parserMessages, cppMessages, null);
|
||||
return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded);
|
||||
}
|
||||
|
||||
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
|
||||
|
@ -522,26 +641,6 @@ public class CParserUtils {
|
|||
return cpp.getParseMessages();
|
||||
}
|
||||
|
||||
private static String getFormattedParseMessage(String parseMessage, String cppMessage, String errMsg) {
|
||||
String message = "";
|
||||
|
||||
if (errMsg != null) {
|
||||
message += errMsg + "\n\n";
|
||||
}
|
||||
|
||||
String msg = parseMessage;
|
||||
if (msg != null && msg.length() != 0) {
|
||||
message += "CParser Messages:\n" + msg + "\n\n";
|
||||
}
|
||||
|
||||
msg = cppMessage;
|
||||
if (msg != null && msg.length() != 0) {
|
||||
message += "PreProcessor Messages:\n" + msg;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) {
|
||||
|
||||
if (service == null) {
|
||||
|
@ -680,4 +779,54 @@ public class CParserUtils {
|
|||
errorIndex + "<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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,12 @@ import java.awt.Color;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.app.util.html.diff.DataTypeDiff;
|
||||
import ghidra.app.util.html.diff.DataTypeDiffBuilder;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
@ -113,14 +115,26 @@ public class FunctionDataTypeHTMLRepresentation extends HTMLDataTypeRepresentati
|
|||
}
|
||||
|
||||
private TextLine buildReturnType(FunctionDefinition functionDefinition) {
|
||||
|
||||
DataType returnDataType = functionDefinition.getReturnType();
|
||||
GenericCallingConvention genericCallingConvention =
|
||||
functionDefinition.getGenericCallingConvention();
|
||||
String modifier = genericCallingConvention != GenericCallingConvention.unknown
|
||||
? (" " + genericCallingConvention.getDeclarationName())
|
||||
: "";
|
||||
return new TextLine(
|
||||
HTMLUtilities.friendlyEncodeHTML(returnDataType.getDisplayName()) + modifier);
|
||||
String rtHtml = friendlyEncodeHTML(returnDataType.getDisplayName());
|
||||
|
||||
String noReturnHtml = "";
|
||||
if (functionDefinition.hasNoReturn()) {
|
||||
noReturnHtml = FunctionSignature.NORETURN_DISPLAY_STRING + HTML_SPACE;
|
||||
}
|
||||
|
||||
String ccHtml = "";
|
||||
String callingConvention = functionDefinition.getCallingConventionName();
|
||||
if (!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
|
||||
ccHtml = friendlyEncodeHTML(callingConvention);
|
||||
if (functionDefinition.hasUnknownCallingConventionName()) {
|
||||
ccHtml = colorString(Messages.ERROR, ccHtml);
|
||||
}
|
||||
ccHtml = HTML_SPACE + ccHtml;
|
||||
}
|
||||
|
||||
return new TextLine(noReturnHtml + rtHtml + ccHtml);
|
||||
}
|
||||
|
||||
// display name to name pairs
|
||||
|
|
|
@ -123,12 +123,11 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
|
|||
if (callingConvention.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
|
||||
callingConvention = function.getCallingConvention().getName();
|
||||
}
|
||||
if (callingConvention != null &&
|
||||
!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
|
||||
if (!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
|
||||
as = new AttributedString(callingConvention + " ", FunctionColors.RETURN_TYPE,
|
||||
getMetrics());
|
||||
textElements
|
||||
.add(new FunctionCallingConventionFieldElement(as, elementIndex, 0, startCol));
|
||||
.add(new FunctionCallingConventionFieldElement(as, elementIndex, 0, startCol));
|
||||
startCol += as.length();
|
||||
elementIndex++;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,14 @@ public class LanguageSortedTableModel extends AbstractSortedTableModel<LanguageC
|
|||
}
|
||||
++index;
|
||||
}
|
||||
// Try again using just LanguageID
|
||||
index = 0;
|
||||
for (LanguageCompilerSpecPair pair : languageList) {
|
||||
if (pair.getLanguageID().equals(toFind.getLanguageID())) {
|
||||
return index;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ import ghidra.framework.model.*;
|
|||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
|
@ -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 readOnly should file be opened read only
|
||||
* @return the data type manager
|
||||
|
@ -2494,8 +2505,7 @@ public class FlatProgramAPI {
|
|||
*/
|
||||
public final FileDataTypeManager openDataTypeArchive(File archiveFile, boolean readOnly)
|
||||
throws Exception {
|
||||
FileDataTypeManager dtfm = FileDataTypeManager.openFileArchive(archiveFile, !readOnly);
|
||||
return dtfm;
|
||||
return FileDataTypeManager.openFileArchive(archiveFile, !readOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.*;
|
|||
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.GenericCallingConvention;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.listing.*;
|
||||
|
@ -64,7 +63,7 @@ public class FunctionUtility {
|
|||
|
||||
Program sourceProgram = sourceFunction.getProgram();
|
||||
Program destinationProgram = destinationFunction.getProgram();
|
||||
boolean sameLanguage = isSameLanguage(destinationProgram, sourceProgram);
|
||||
boolean sameLanguage = isSameLanguageAndCompilerSpec(destinationProgram, sourceProgram);
|
||||
|
||||
String callingConventionName =
|
||||
determineCallingConventionName(destinationFunction, sourceFunction, sameLanguage);
|
||||
|
@ -274,7 +273,7 @@ public class FunctionUtility {
|
|||
* @param program2 the second program
|
||||
* @return true if the two programs have the same processor language and compiler spec.
|
||||
*/
|
||||
public static boolean isSameLanguage(Program program1, Program program2) {
|
||||
public static boolean isSameLanguageAndCompilerSpec(Program program1, Program program2) {
|
||||
Language language1 = program1.getLanguage();
|
||||
Language language2 = program2.getLanguage();
|
||||
if (language1.getLanguageID() != language2.getLanguageID()) {
|
||||
|
@ -289,17 +288,9 @@ public class FunctionUtility {
|
|||
}
|
||||
|
||||
private static String determineCallingConventionName(Function destinationFunction,
|
||||
Function sourceFunction, boolean sameLanguage) {
|
||||
String sourceCallingConventionName = sourceFunction.getCallingConventionName();
|
||||
if (sameLanguage) {
|
||||
return sourceCallingConventionName; // Same language, so set to source.
|
||||
}
|
||||
GenericCallingConvention guessedCallingConvention =
|
||||
GenericCallingConvention.guessFromName(sourceCallingConventionName);
|
||||
if (guessedCallingConvention == GenericCallingConvention.thiscall) {
|
||||
return GenericCallingConvention.thiscall.name(); // this call
|
||||
}
|
||||
return destinationFunction.getCallingConventionName(); // leave destination unchanged.
|
||||
Function sourceFunction, boolean sameLanguageAndCompilerSpec) {
|
||||
return sameLanguageAndCompilerSpec ? sourceFunction.getCallingConventionName()
|
||||
: destinationFunction.getCallingConventionName();
|
||||
}
|
||||
|
||||
private static boolean determineCustomStorageUse(Function destinationFunction,
|
||||
|
|
|
@ -44,6 +44,7 @@ import ghidra.program.database.ProgramDB;
|
|||
import ghidra.program.disassemble.DisassemblerContextImpl;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
||||
|
@ -971,6 +972,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
|
||||
ResourceFile emuTestingArchive = Application.getModuleDataFile("pcodetest/EmuTesting.gdt");
|
||||
archiveDtMgr = FileDataTypeManager.openFileArchive(emuTestingArchive, false);
|
||||
assertEquals(ArchiveWarning.NONE, archiveDtMgr.getWarning());
|
||||
DataType dt = archiveDtMgr.getDataType(CategoryPath.ROOT, TEST_INFO_STRUCT_NAME);
|
||||
if (dt == null || !(dt instanceof Structure)) {
|
||||
fail(TEST_INFO_STRUCT_NAME +
|
||||
|
|
|
@ -218,6 +218,11 @@ public class UndefinedFunction implements Function {
|
|||
return p.getCompilerSpec().getDefaultCallingConvention();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnknownCallingConventionName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCallingConventionName() {
|
||||
return Function.UNKNOWN_CALLING_CONVENTION_STRING;
|
||||
|
@ -233,11 +238,6 @@ public class UndefinedFunction implements Function {
|
|||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultCallingConventionName() {
|
||||
return p.getCompilerSpec().getDefaultCallingConvention().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getEntryPoint() {
|
||||
return entry;
|
||||
|
|
|
@ -622,11 +622,12 @@ public class CParser {
|
|||
* @param dec Declaration
|
||||
* @param funcDT function data type to qualify
|
||||
*/
|
||||
private void applyFunctionQualifiers(Declaration dec, FunctionDefinitionDataType funcDT) {
|
||||
private void applyFunctionQualifiers(Declaration dec, FunctionDefinition funcDT) {
|
||||
List<Integer> qualifierList = dec.getQualifiers();
|
||||
if (qualifierList.contains(NORETURN) ) {
|
||||
// TODO: set no return on function
|
||||
funcDT.setNoReturn(true);
|
||||
}
|
||||
// TODO: switch to setting calling convention by string identifier
|
||||
for (Integer qualifier : qualifierList) {
|
||||
switch (qualifier) {
|
||||
case CDECL:
|
||||
|
@ -1772,18 +1773,18 @@ Declaration TypeQualifier(Declaration dec) : {}
|
|||
<STATIC> |
|
||||
<PACKED> |
|
||||
<UNALIGNED> |
|
||||
( DeclSpec() )
|
||||
( DeclSpec(dec) )
|
||||
)
|
||||
{
|
||||
return dec;
|
||||
}
|
||||
}
|
||||
|
||||
void AttributeSpec() : {}
|
||||
void AttributeSpec(Declaration dec) : {}
|
||||
{
|
||||
( <ATTRIBUTE> ("(") SubIdent() (")") ) |
|
||||
( <ATTRIBUTE> ("(") SubIdent(dec) (")") ) |
|
||||
AsmStatement() |
|
||||
( "[" "[" AttributeList() "]" "]" ) |
|
||||
( "[" "[" AttributeList(dec) "]" "]" ) |
|
||||
AlignmentSpecifier()
|
||||
|
||||
}
|
||||
|
@ -1793,48 +1794,59 @@ void AlignmentSpecifier() : { Declaration dt = new Declaration(); }
|
|||
< ALIGNAS > "(" ( TypeQualifier(dt) | AssignmentExpression() ) ")"
|
||||
}
|
||||
|
||||
void AttributeList() : { }
|
||||
void AttributeList(Declaration dec) : { }
|
||||
{
|
||||
AttributeToken() [ ("," AttributeToken())+ ]
|
||||
AttributeToken(dec) [ ("," AttributeToken(dec))+ ]
|
||||
}
|
||||
|
||||
void AttributeToken() : { Declaration dt = new Declaration(); }
|
||||
void AttributeToken(Declaration dec) : { }
|
||||
{
|
||||
( < IDENTIFIER > | TypeQualifier(dt) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dt) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ]
|
||||
( < IDENTIFIER > | TypeQualifier(dec) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dec) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ]
|
||||
}
|
||||
|
||||
void AttributeSpecList() : {}
|
||||
void AttributeSpecList(Declaration dec) : {}
|
||||
{
|
||||
( AttributeSpec() )+
|
||||
( AttributeSpec(dec) )+
|
||||
}
|
||||
|
||||
void SubIdent() : { Declaration dt = new Declaration(); }
|
||||
void SubIdent(Declaration dec) : {
|
||||
Token id = null;
|
||||
Declaration dt = new Declaration();
|
||||
}
|
||||
{
|
||||
( ( "(" [SubIdent()] ")" ) |
|
||||
(<IDENTIFIER> | TypeQualifier(dt)) [ ( "(" [SubIdent()] ")") | ("=" SubIdent()) ]
|
||||
( ( "(" [SubIdent(dec)] ")" ) |
|
||||
(id=<IDENTIFIER> | TypeQualifier(dec)) [ ( "(" [SubIdent(dt)] ")") | ("=" SubIdent(dt)) ]
|
||||
[ ","
|
||||
SubIdent()
|
||||
SubIdent(dt)
|
||||
] |
|
||||
Constant() [ ","
|
||||
SubIdent()
|
||||
SubIdent(dt)
|
||||
]
|
||||
)
|
||||
{
|
||||
if (id != null && "noreturn".equals(id.image.replace("_", ""))) {
|
||||
dec.addQualifier(NORETURN);
|
||||
if (dec.getDataType() instanceof FunctionDefinition) {
|
||||
applyFunctionQualifiers(dec, (FunctionDefinition) dec.getDataType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclSpec() : {
|
||||
void DeclSpec(Declaration dec) : {
|
||||
}
|
||||
{
|
||||
( ( <DECLSPEC> | <READABLETO> ) "(" DeclSpecifier() ")" ) |
|
||||
AttributeSpecList()
|
||||
( ( <DECLSPEC> | <READABLETO> ) "(" DeclSpecifier(dec) ")" ) |
|
||||
AttributeSpecList(dec)
|
||||
}
|
||||
|
||||
void DeclSpecifier() : {
|
||||
void DeclSpecifier(Declaration dec) : {
|
||||
Token id = null;
|
||||
}
|
||||
{
|
||||
"(" DeclSpecifier() ")" |
|
||||
(<IDENTIFIER>)+ [ "("
|
||||
DeclConstant() ( DeclConstant() )*
|
||||
")" ]
|
||||
"(" DeclSpecifier(dec) ")" |
|
||||
(id=<IDENTIFIER> { if (id != null && "noreturn".equals(id.image)) dec.addQualifier(NORETURN); } )+
|
||||
[ "(" DeclConstant() ( DeclConstant() )* ")" ]
|
||||
}
|
||||
|
||||
void DeclConstant() : {}
|
||||
|
@ -1970,6 +1982,7 @@ DataType StructOrUnionSpecifier() : {
|
|||
Token parent;
|
||||
Token sname;
|
||||
Composite comp;
|
||||
Declaration dec = new Declaration();
|
||||
}
|
||||
{
|
||||
{
|
||||
|
@ -1982,7 +1995,7 @@ DataType StructOrUnionSpecifier() : {
|
|||
LOOKAHEAD(3)
|
||||
[ t= <IDENTIFIER> [ ":" parent=<IDENTIFIER>]
|
||||
{ comp=defineNamedComposite(t, null, comp); } // no parent yet, since there are no guts
|
||||
] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList() ]
|
||||
] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList(dec) ]
|
||||
|
|
||||
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);
|
||||
|
||||
|
@ -2014,7 +2030,7 @@ Composite StructOrUnion() : {Composite comp;}
|
|||
|
||||
}
|
||||
|
|
||||
<UNION> ( DeclSpec() )* {
|
||||
<UNION> ( DeclSpec(dec) )* {
|
||||
comp = new UnionDataType(getCurrentCategoryPath(), ANONYMOUS_UNION_PREFIX + cnt++, dtMgr);
|
||||
|
||||
// Always set the packing, because by default structures should be aligned
|
||||
|
@ -2067,6 +2083,7 @@ void InitDeclarator(Declaration dt) : { Declaration dec; }
|
|||
|
||||
void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
|
||||
Declaration dt = null;
|
||||
Declaration dec = new Declaration();
|
||||
}
|
||||
{
|
||||
LineDef() |
|
||||
|
@ -2077,7 +2094,7 @@ void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
|
|||
[
|
||||
StructDeclaratorList(dt, comp, compositeHandler) { dt= null; }
|
||||
]
|
||||
[ AttributeSpecList() ]
|
||||
[ AttributeSpecList(dec) ]
|
||||
";"
|
||||
)
|
||||
{
|
||||
|
@ -2173,12 +2190,13 @@ DataType EnumSpecifier() : {
|
|||
Token t= null;
|
||||
DataType dt;
|
||||
ArrayList<EnumMember> list;
|
||||
Declaration dec = new Declaration();
|
||||
}
|
||||
{
|
||||
<ENUM>
|
||||
(
|
||||
LOOKAHEAD(3)
|
||||
[AttributeSpecList()] [ t= <IDENTIFIER> ] "{" list= EnumeratorList() "}"
|
||||
[AttributeSpecList(dec)] [ t= <IDENTIFIER> ] "{" list= EnumeratorList() "}"
|
||||
{
|
||||
String enumName= (t != null ? t.image : ("enum_" + cnt++));
|
||||
EnumDataType enuum= new EnumDataType(getCurrentCategoryPath(), enumName, 4, dtMgr);
|
||||
|
@ -2247,7 +2265,7 @@ Declaration Declarator(Declaration dt, DataType container) : {
|
|||
}
|
||||
{
|
||||
(
|
||||
[ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList() ]
|
||||
[ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList(dec) ]
|
||||
)
|
||||
{
|
||||
return dec;
|
||||
|
|
|
@ -1172,6 +1172,16 @@ public class PreProcessor {
|
|||
public void addIncludePath(String path) {
|
||||
pathList.addElement(path);
|
||||
}
|
||||
|
||||
public void addIncludePaths(String[] paths) {
|
||||
if (paths == null || paths.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String path : paths) {
|
||||
addIncludePath(path);
|
||||
}
|
||||
}
|
||||
|
||||
public int getNumericType(String val) {
|
||||
try {
|
||||
|
@ -1246,7 +1256,7 @@ public class PreProcessor {
|
|||
outputStream = new PrintStream(fos);
|
||||
}
|
||||
|
||||
public void parse(String filename) throws ParseException {
|
||||
public boolean parse(String filename) throws ParseException {
|
||||
if (verboseLevel == 1) {
|
||||
addParseMessage(null,
|
||||
"PreProcessor: Reading from file " + filename + " . . .");
|
||||
|
@ -1269,7 +1279,7 @@ public class PreProcessor {
|
|||
}
|
||||
if (fis == null) {
|
||||
addParseMessage(null, "PreProcessor: File " + filename + " not found.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
fileStack.push(filename);
|
||||
alreadyDone = new HashMap<String, Integer>();
|
||||
|
@ -1290,6 +1300,7 @@ public class PreProcessor {
|
|||
addParseMessage(filename, "PreProcessor Token Error: " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PreProcessor(PreProcessor parent) {
|
||||
|
|
|
@ -45,17 +45,12 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testDataTypeEditedInMy() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// Make no changes to Latest.
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -99,9 +94,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testDataTypeEditedInBoth() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -126,9 +119,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -171,9 +161,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testDataTypeRenamedChanged() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -197,9 +185,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -235,9 +220,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testDataTypeRenamedChanged2() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -263,9 +246,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -309,9 +289,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testDataTypeRenamedChanged3() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -340,9 +318,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -383,9 +358,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testDataTypeRenamedChanged4() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -411,9 +384,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -458,9 +428,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testDataTypeRenamedInBoth() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -487,9 +455,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -532,9 +497,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testRenamedChanged() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -556,9 +519,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -602,9 +562,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
// in Latest move data type; in MY change the name;
|
||||
// should be a conflict
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -628,9 +586,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -666,9 +621,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testRenamedChangedMoved() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -699,9 +652,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -739,9 +689,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testRenamedChangedMovedNoConflict() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -772,9 +720,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -813,9 +758,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testRenamedChangedMovedNoConflict2() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -835,9 +778,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -889,9 +829,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
// edit DLL_Table in latest; edit DLL_Table in private
|
||||
// only DLL_Table should be in conflict; not the ones where it is used.
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -919,9 +857,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -963,9 +898,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
// edit DLL_Table in latest; edit DLL_Table in private
|
||||
// only DLL_Table should be in conflict; not the ones where it is used.
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -993,9 +926,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1037,9 +967,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
// edit ArrayStruct in latest; edit ArrayStruct in private
|
||||
// only ArrayStruct should be in conflict; not the ones where it is used.
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1067,9 +995,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1337,9 +1262,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testDeletedInLatest() throws Exception {
|
||||
|
||||
mtf.initialize("notepad2", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1356,9 +1279,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1429,9 +1349,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testAddedFuncSig() throws Exception {
|
||||
|
||||
mtf.initialize("notepad2", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1448,9 +1366,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1496,9 +1411,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testEditFuncSig() throws Exception {
|
||||
|
||||
mtf.initialize("notepad3", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1517,9 +1430,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1562,9 +1472,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testEditFuncSig2() throws Exception {
|
||||
|
||||
mtf.initialize("notepad3", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1585,9 +1493,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1629,9 +1534,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testEditFuncSig3() throws Exception {
|
||||
|
||||
mtf.initialize("notepad3", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1642,6 +1545,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
fd.setVarArgs(true);
|
||||
fd.setNoReturn(true);
|
||||
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
dtm.remove(foo, TaskMonitor.DUMMY);
|
||||
commit = true;
|
||||
|
@ -1651,9 +1555,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1689,16 +1590,15 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
assertEquals(DataType.DEFAULT, vars[0].getDataType());
|
||||
assertEquals("this is a comment", vars[0].getComment());
|
||||
assertEquals(DataType.DEFAULT, vars[1].getDataType());
|
||||
assertEquals(false, fd.hasVarArgs());
|
||||
assertFalse(fd.hasVarArgs());
|
||||
assertFalse(fd.hasNoReturn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditFuncSig4() throws Exception {
|
||||
|
||||
mtf.initialize("notepad3", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1709,6 +1609,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
fd.setVarArgs(true);
|
||||
fd.setNoReturn(true);
|
||||
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
dtm.remove(foo, TaskMonitor.DUMMY);
|
||||
commit = true;
|
||||
|
@ -1718,9 +1619,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1759,16 +1657,15 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
checkDataType(new CharDataType(), vars[1].getDataType());
|
||||
checkDataType(new Undefined4DataType(), vars[2].getDataType());
|
||||
checkDataType(new Undefined4DataType(), vars[3].getDataType());
|
||||
assertEquals(true, fd.hasVarArgs());
|
||||
assertTrue(fd.hasVarArgs());
|
||||
assertTrue(fd.hasNoReturn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditFuncSig5() throws Exception {
|
||||
|
||||
mtf.initialize("notepad3", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1788,9 +1685,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1808,6 +1702,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
"this is another comment");
|
||||
fd.setArguments(newVars);
|
||||
fd.setVarArgs(true);
|
||||
fd.setNoReturn(true);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1831,6 +1726,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
assertEquals("Bar", vars[4].getName());
|
||||
assertEquals("this is another comment", vars[4].getComment());
|
||||
assertTrue(fd.hasVarArgs());
|
||||
assertTrue(fd.hasNoReturn());
|
||||
}
|
||||
|
||||
private void checkDataType(DataType expectedDataType, DataType actualDataType) {
|
||||
|
@ -1842,9 +1738,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
public void testAddConflictFuncSig1() throws Exception {
|
||||
|
||||
mtf.initialize("notepad3", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1866,9 +1760,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
|
@ -1902,7 +1793,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
assertEquals("format", vars[0].getName());
|
||||
assertEquals(null, vars[0].getComment());
|
||||
checkDataType(new WordDataType(), fd1.getReturnType());
|
||||
assertEquals(false, fd1.hasVarArgs());
|
||||
assertFalse(fd1.hasVarArgs());
|
||||
|
||||
FunctionDefinition fd2 =
|
||||
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "printf.conflict");
|
||||
|
@ -1913,7 +1804,80 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
|
|||
assertEquals("format", vars2[0].getName());
|
||||
assertEquals(null, vars2[0].getComment());
|
||||
checkDataType(new WordDataType(), fd2.getReturnType());
|
||||
assertEquals(true, fd2.hasVarArgs());
|
||||
assertTrue(fd2.hasVarArgs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddConflictFuncSig2() throws Exception {
|
||||
|
||||
mtf.initialize("notepad3", new ProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
FunctionDefinition fd =
|
||||
new FunctionDefinitionDataType(new CategoryPath("/MISC"), "exit");
|
||||
fd.setReturnType(VoidDataType.dataType);
|
||||
fd.setNoReturn(false);
|
||||
fd.setArguments(
|
||||
new ParameterDefinition[] { new ParameterDefinitionImpl("rc",
|
||||
IntegerDataType.dataType, null) });
|
||||
dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
FunctionDefinition fd =
|
||||
new FunctionDefinitionDataType(new CategoryPath("/MISC"), "exit");
|
||||
fd.setReturnType(VoidDataType.dataType);
|
||||
fd.setNoReturn(true);
|
||||
fd.setArguments(
|
||||
new ParameterDefinition[] { new ParameterDefinitionImpl("rc",
|
||||
IntegerDataType.dataType, null) });
|
||||
dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
});
|
||||
executeMerge(DataTypeMergeManager.OPTION_MY);
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
FunctionDefinition fd1 =
|
||||
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "exit");
|
||||
assertNotNull(fd1);
|
||||
ParameterDefinition[] vars = fd1.getArguments();
|
||||
assertEquals(1, vars.length);
|
||||
checkDataType(IntegerDataType.dataType, vars[0].getDataType());
|
||||
assertEquals("rc", vars[0].getName());
|
||||
assertEquals(null, vars[0].getComment());
|
||||
checkDataType(VoidDataType.dataType, fd1.getReturnType());
|
||||
assertFalse(fd1.hasNoReturn());
|
||||
|
||||
FunctionDefinition fd2 =
|
||||
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "exit.conflict");
|
||||
assertNotNull(fd2);
|
||||
ParameterDefinition[] vars2 = fd2.getArguments();
|
||||
assertEquals(1, vars2.length);
|
||||
checkDataType(IntegerDataType.dataType, vars2[0].getDataType());
|
||||
assertEquals("rc", vars2[0].getName());
|
||||
assertEquals(null, vars2[0].getComment());
|
||||
checkDataType(VoidDataType.dataType, fd2.getReturnType());
|
||||
assertTrue(fd2.hasNoReturn());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -352,17 +352,21 @@ public class ParseDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(profileFile.getInputStream()));
|
||||
String line = null;
|
||||
while ((line = br.readLine()) != null) {
|
||||
|
||||
// read paths
|
||||
while ((line = br.readLine()) != null && line.trim().length() > 0) {
|
||||
line = line.trim();
|
||||
if (line.startsWith("-") || (line.length() == 0 && buffy.length() > 0)) {
|
||||
// this is a compiler directive
|
||||
buffy.append(line + "\n");
|
||||
}
|
||||
else if (line.length() > 0) {
|
||||
File f = new File(line);
|
||||
pathList.add(f.getPath());
|
||||
}
|
||||
|
||||
pathList.add(line);
|
||||
}
|
||||
|
||||
// read options
|
||||
while ((line = br.readLine()) != null && line.trim().length() > 0) {
|
||||
line = line.trim();
|
||||
|
||||
buffy.append(line + "\n");
|
||||
}
|
||||
|
||||
|
||||
paths = pathList;
|
||||
defaultPrfOptions = buffy.toString();
|
||||
|
|
|
@ -37,10 +37,13 @@ import ghidra.framework.plugintool.PluginTool;
|
|||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager.LanguageUpdateOption;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
|
@ -93,6 +96,45 @@ public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedInte
|
|||
waitForTree();
|
||||
}
|
||||
|
||||
protected DataType resolveDataType(StandAloneDataTypeManager archiveDtm, DataType dt)
|
||||
throws Exception {
|
||||
int id = archiveDtm.startTransaction("resolve datatype");
|
||||
try {
|
||||
return archiveDtm.resolve(dt, null);
|
||||
}
|
||||
finally {
|
||||
archiveDtm.endTransaction(id, true);
|
||||
waitForTree();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setArchitecture(StandAloneDataTypeManager archiveDtm, String languageId,
|
||||
String compilerSpecId) throws Exception {
|
||||
LanguageService languageService = getLanguageService();
|
||||
Language language = languageService.getLanguage(new LanguageID(languageId));
|
||||
|
||||
int id = archiveDtm.startTransaction("set architecture");
|
||||
try {
|
||||
archiveDtm.setProgramArchitecture(language, new CompilerSpecID(compilerSpecId),
|
||||
LanguageUpdateOption.CLEAR, TaskMonitor.DUMMY);
|
||||
}
|
||||
finally {
|
||||
archiveDtm.endTransaction(id, true);
|
||||
}
|
||||
waitForTree();
|
||||
}
|
||||
|
||||
protected void removeArchitecture(StandAloneDataTypeManager archiveDtm) throws Exception {
|
||||
int id = archiveDtm.startTransaction("remove architecture");
|
||||
try {
|
||||
archiveDtm.clearProgramArchitecture(TaskMonitor.DUMMY);
|
||||
}
|
||||
finally {
|
||||
archiveDtm.endTransaction(id, true);
|
||||
}
|
||||
waitForTree();
|
||||
}
|
||||
|
||||
protected void createNewArchive(String archiveName, boolean deleteExisting) throws Exception {
|
||||
File archiveFile = new File(getTestDirectoryPath(), archiveName);
|
||||
if (deleteExisting && archiveFile.exists()) {
|
||||
|
@ -190,10 +232,12 @@ public abstract class AbstractCreateArchiveTest extends AbstractGhidraHeadedInte
|
|||
@After
|
||||
public void tearDown() throws Exception {
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
ProgramManager pm = tool.getService(ProgramManager.class);
|
||||
pm.closeProgram();
|
||||
});
|
||||
if (tool != null) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
ProgramManager pm = tool.getService(ProgramManager.class);
|
||||
pm.closeProgram();
|
||||
});
|
||||
}
|
||||
waitForPostedSwingRunnables();
|
||||
|
||||
// this handles the save changes dialog and potential analysis dialogs
|
||||
|
|
|
@ -32,7 +32,9 @@ import ghidra.app.plugin.core.datamgr.archive.Archive;
|
|||
import ghidra.app.plugin.core.datamgr.archive.FileArchive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.framework.GenericRunInfo;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.ProgramArchitecture;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class CreateArchive1Test extends AbstractCreateArchiveTest {
|
||||
|
@ -62,6 +64,10 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
|
|||
createNewArchive(string + FileDataTypeManager.SUFFIX, true);
|
||||
|
||||
ArchiveNode archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
|
||||
StandAloneDataTypeManager dtm =
|
||||
(StandAloneDataTypeManager) archiveNode.getCategory().getDataTypeManager();
|
||||
assertNull(dtm.getProgramArchitecture());
|
||||
|
||||
createCategory(archiveNode.getCategory(), "bob");
|
||||
waitForTree();
|
||||
|
||||
|
@ -79,6 +85,9 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
|
|||
DataTypeTestUtils.performAction(action, tree);
|
||||
waitForTree();
|
||||
|
||||
archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
|
||||
assertNull(archiveNode);
|
||||
|
||||
archiveNode =
|
||||
DataTypeTestUtils.openArchive(getTestDirectoryPath(), "MyArchive.gdt", false, plugin);
|
||||
assertNotNull(archiveNode.getChild("bob"));
|
||||
|
@ -88,6 +97,65 @@ public class CreateArchive1Test extends AbstractCreateArchiveTest {
|
|||
f.deleteOnExit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndPopulateWithArchitecture() throws Exception {
|
||||
|
||||
String string = "MyArchive";
|
||||
createNewArchive(string + FileDataTypeManager.SUFFIX, true);
|
||||
|
||||
ArchiveNode archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
|
||||
StandAloneDataTypeManager dtm =
|
||||
(StandAloneDataTypeManager) archiveNode.getCategory().getDataTypeManager();
|
||||
assertNull(dtm.getProgramArchitecture());
|
||||
setArchitecture(dtm, ProgramBuilder._TOY64_LE, "default");
|
||||
|
||||
assertEquals(8, dtm.getPointer(DataType.DEFAULT).getLength());
|
||||
|
||||
createCategory(archiveNode.getCategory(), "bob");
|
||||
waitForTree();
|
||||
|
||||
DataType dt =
|
||||
resolveDataType(dtm, new StructureDataType(new CategoryPath("/bob"), "MyStruct", 0));
|
||||
dt = resolveDataType(dtm, new PointerDataType(dt));
|
||||
assertEquals(8, dtm.getPointer(DataType.DEFAULT).getLength());
|
||||
DataTypePath dataTypePath = dt.getDataTypePath();
|
||||
|
||||
tree.setSelectedNode(archiveNode);
|
||||
waitForTree();
|
||||
|
||||
createCategory(archiveNode.getCategory(), "joe");
|
||||
waitForTree();
|
||||
|
||||
DockingActionIf action = getAction(plugin, "Save");
|
||||
DataTypeTestUtils.performAction(action, tree);
|
||||
waitForTree();
|
||||
|
||||
action = getAction(plugin, "Close Archive");
|
||||
DataTypeTestUtils.performAction(action, tree);
|
||||
waitForTree();
|
||||
|
||||
archiveNode = (ArchiveNode) archiveRootNode.getChild("MyArchive");
|
||||
assertNull(archiveNode);
|
||||
|
||||
archiveNode =
|
||||
DataTypeTestUtils.openArchive(getTestDirectoryPath(), "MyArchive.gdt", false, plugin);
|
||||
assertNotNull(archiveNode.getChild("bob"));
|
||||
assertNotNull(archiveNode.getChild("joe"));
|
||||
|
||||
dtm = (StandAloneDataTypeManager) archiveNode.getCategory().getDataTypeManager();
|
||||
ProgramArchitecture arch = dtm.getProgramArchitecture();
|
||||
assertNotNull("Expected architecture to be set", arch);
|
||||
assertEquals(ProgramBuilder._TOY64_LE, arch.getLanguage().getLanguageID().toString());
|
||||
assertEquals("default", arch.getCompilerSpec().getCompilerSpecID().toString());
|
||||
|
||||
dt = dtm.getDataType(dataTypePath);
|
||||
assertNotNull(dt);
|
||||
assertEquals(8, dtm.getPointer(DataType.DEFAULT).getLength());
|
||||
|
||||
File f = new File(getTestDirectoryPath(), "MyArchive.gdt.bak");
|
||||
f.deleteOnExit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateArchiveNameCollision1() throws Exception {
|
||||
// create archive
|
||||
|
|
|
@ -27,6 +27,7 @@ import generic.jar.ResourceFile;
|
|||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
|
||||
|
||||
public class DataTypeArchiveIDTest extends AbstractGenericTest {
|
||||
|
||||
|
@ -68,6 +69,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
|
|||
notFound.remove(path);
|
||||
|
||||
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
|
||||
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
|
||||
try {
|
||||
assertEquals("Archive UniversalID mismatch: " + path, oldID,
|
||||
dtm.getUniversalID().toString());
|
||||
|
@ -101,6 +103,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
|
|||
public void spotCheckWindowsVS12_32() throws IOException {
|
||||
ResourceFile gdtFile = Application.getModuleDataFile(WIN_VS12_32_GDT_PATH);
|
||||
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
|
||||
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
|
||||
try {
|
||||
DataType dt = dtm.getDataType("/winsock.h/fd_set");
|
||||
assertNotNull(dt);
|
||||
|
@ -117,6 +120,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
|
|||
public void spotCheckWindowsVS12_64() throws IOException {
|
||||
ResourceFile gdtFile = Application.getModuleDataFile(WIN_VS12_64_GDT_PATH);
|
||||
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
|
||||
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
|
||||
try {
|
||||
DataType dt = dtm.getDataType("/winsock.h/fd_set");
|
||||
assertNotNull(dt);
|
||||
|
@ -132,6 +136,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
|
|||
public void spotCheckGenericCLib32() throws IOException {
|
||||
ResourceFile gdtFile = Application.getModuleDataFile(GENERIC_CLIB_32_GDT_PATH);
|
||||
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
|
||||
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
|
||||
try {
|
||||
DataType dt = dtm.getDataType("/select.h/fd_set");
|
||||
assertNotNull(dt);
|
||||
|
@ -147,6 +152,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
|
|||
public void spotCheckGenericCLib64() throws IOException {
|
||||
ResourceFile gdtFile = Application.getModuleDataFile(GENERIC_CLIB_64_GDT_PATH);
|
||||
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
|
||||
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
|
||||
try {
|
||||
DataType dt = dtm.getDataType("/select.h/fd_set");
|
||||
assertNotNull(dt);
|
||||
|
@ -162,6 +168,7 @@ public class DataTypeArchiveIDTest extends AbstractGenericTest {
|
|||
public void spotCheckMacOS10_9() throws IOException {
|
||||
ResourceFile gdtFile = Application.getModuleDataFile(MAC_OS_10_9_GDT_PATH);
|
||||
FileDataTypeManager dtm = FileDataTypeManager.openFileArchive(gdtFile, false);
|
||||
assertEquals(ArchiveWarning.NONE, dtm.getWarning());
|
||||
try {
|
||||
DataType dt = dtm.getDataType("/_fd_def.h/fd_set");
|
||||
assertNotNull(dt);
|
||||
|
|
|
@ -25,6 +25,7 @@ import ghidra.program.database.ProgramDB;
|
|||
import ghidra.program.model.FunctionTestDouble;
|
||||
import ghidra.program.model.TestDoubleFunctionSignature;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.*;
|
||||
|
@ -118,11 +119,9 @@ public class EditFunctionSignatureDialogTest extends AbstractGhidraHeadedIntegra
|
|||
//==================================================================================================
|
||||
|
||||
private class LocalFunctionStub extends FunctionTestDouble {
|
||||
private DataType returnType;
|
||||
|
||||
public LocalFunctionStub(String name, String signature) {
|
||||
super("Name", new LocalFunctionSignatureTestDouble(name, signature));
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -132,7 +131,7 @@ public class EditFunctionSignatureDialogTest extends AbstractGhidraHeadedIntegra
|
|||
|
||||
@Override
|
||||
public String getCallingConventionName() {
|
||||
return GenericCallingConvention.stdcall.toString();
|
||||
return CompilerSpec.CALLING_CONVENTION_stdcall;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1113,6 +1113,11 @@ public class DataTypeSelectionDialogTest extends AbstractGhidraHeadedIntegration
|
|||
SourceArchive sourceArchive) {
|
||||
// don't care for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
|
||||
// don't care for now
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomDataType extends StructureDataType {
|
||||
|
|
|
@ -908,5 +908,10 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
SourceArchive dataTypeSource) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programArchitectureChanged(DataTypeManager dataTypeManager) {
|
||||
// don't care
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -42,8 +42,8 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
private ProgramDB program;
|
||||
private ProgramBasedDataTypeManager dataMgr;
|
||||
private Listing listing;
|
||||
private ProgramBasedDataTypeManager dataMgr;
|
||||
private AddressSpace space;
|
||||
private int transactionID;
|
||||
|
||||
|
@ -62,11 +62,12 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Before
|
||||
public void setUp() throws Exception {
|
||||
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
|
||||
listing = program.getListing();
|
||||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
dataMgr = program.getDataTypeManager();
|
||||
listing = program.getListing();
|
||||
transactionID = program.startTransaction("Test");
|
||||
addBlock();
|
||||
|
||||
// pointer-typedef has the largest
|
||||
// System.out.println("Defined string settings:");
|
||||
// for (SettingsDefinition def : StringDataType.dataType.getSettingsDefinitions()) {
|
||||
|
@ -164,8 +165,8 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testIsEmpty() throws Exception {
|
||||
|
||||
Data data = listing.getDataAt(addr(10));
|
||||
Settings defaultSettings = data.getDataType().getDefaultSettings();
|
||||
DataType dt = dataMgr.resolve(StringDataType.dataType, null);
|
||||
Settings defaultSettings = dt.getDefaultSettings();
|
||||
defaultSettings.setString(STRING_SETTING_NAME, "red");
|
||||
defaultSettings.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
|
@ -390,7 +391,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultSettingsOnTypedef() throws Exception {
|
||||
DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
|
||||
DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
|
||||
SettingsDefinition[] settingsDefinitions = byteDT.getSettingsDefinitions();
|
||||
Settings settings = byteDT.getDefaultSettings();
|
||||
FormatSettingsDefinition.DEF.setChoice(settings, FormatSettingsDefinition.OCTAL);
|
||||
|
@ -418,7 +419,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultSettingsOnTypedef2() throws Exception {
|
||||
DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
|
||||
DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
|
||||
Settings settings = byteDT.getDefaultSettings();
|
||||
|
||||
TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT);
|
||||
|
@ -438,7 +439,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultSettingsOnTypedefUndoRedo() throws Exception {
|
||||
DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
|
||||
DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
|
||||
Settings settings = byteDT.getDefaultSettings();
|
||||
settings.setLong("format", FormatSettingsDefinition.OCTAL);
|
||||
endTransaction();
|
||||
|
@ -466,7 +467,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultSettingsOnDeletedTypdef() throws Exception {
|
||||
DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
|
||||
DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
|
||||
Settings settings = byteDT.getDefaultSettings();
|
||||
settings.setLong("format", FormatSettingsDefinition.OCTAL);
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ package ghidra.program.database.function;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
|
@ -453,25 +453,12 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(defaultModel, protoModel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCallingConventions() throws Exception {
|
||||
PrototypeModel[] protoModels = functionManager.getCallingConventions();
|
||||
assertTrue(protoModels.length >= 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCallingConventionNames() throws Exception {
|
||||
|
||||
List<String> names = functionManager.getCallingConventionNames();
|
||||
Collection<String> names = functionManager.getCallingConventionNames();
|
||||
assertTrue(names.size() >= 1);
|
||||
|
||||
for (String name : names) {
|
||||
if (Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(name)) {
|
||||
assertNull(functionManager.getCallingConvention(name));
|
||||
}
|
||||
else {
|
||||
assertNotNull(functionManager.getCallingConvention(name));
|
||||
}
|
||||
assertNotNull(functionManager.getCallingConvention(name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.util.cparser;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
|
@ -28,30 +25,9 @@ import org.junit.Test;
|
|||
|
||||
import ghidra.app.util.cparser.C.CParser;
|
||||
import ghidra.app.util.cparser.C.ParseException;
|
||||
import ghidra.program.model.data.Array;
|
||||
import ghidra.program.model.data.BuiltInDataType;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
import ghidra.program.model.data.CharDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeComponent;
|
||||
import ghidra.program.model.data.DataTypeConflictHandler;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.data.FunctionDefinition;
|
||||
import ghidra.program.model.data.GenericCallingConvention;
|
||||
import ghidra.program.model.data.LongLongDataType;
|
||||
import ghidra.program.model.data.ParameterDefinition;
|
||||
import ghidra.program.model.data.Pointer;
|
||||
import ghidra.program.model.data.ShortDataType;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.TypeDef;
|
||||
import ghidra.program.model.data.TypedefDataType;
|
||||
import ghidra.program.model.data.UnsignedLongDataType;
|
||||
import ghidra.program.model.data.UnsignedLongLongDataType;
|
||||
import ghidra.program.model.data.UnsignedShortDataType;
|
||||
import ghidra.program.model.data.WideCharDataType;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
|
||||
public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
|
@ -246,11 +222,11 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
String parseMessages = parser.getParseMessages();
|
||||
System.out.println(parseMessages);
|
||||
|
||||
assertTrue("Duplicate ENUM message", parseMessages.contains("duplicate enum value: options_enum : PLUS_SET : 16"));
|
||||
assertTrue("Duplicate ENUM message missing", parseMessages.contains("duplicate enum value: options_enum : PLUS_SET : 16"));
|
||||
|
||||
assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\""));
|
||||
assertTrue("Duplicate ENUM message missing", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\""));
|
||||
|
||||
assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\""));
|
||||
assertTrue("Duplicate ENUM message missing", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\""));
|
||||
|
||||
DataType dt;
|
||||
DataType pointedToDT;
|
||||
|
@ -285,14 +261,14 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
funcDef = (FunctionDefinition) dt;
|
||||
str = funcDef.getPrototypeString();
|
||||
assertEquals("signature not correct", "void _Once(_Once_t * , _func_anon_ * )", replaceAnonFuncName(str));
|
||||
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
|
||||
assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
|
||||
funcArgs = funcDef.getArguments();
|
||||
assertTrue("struct fstruct", funcArgs[0].getDataType() instanceof Pointer);
|
||||
assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer);
|
||||
pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType();
|
||||
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
|
||||
funcDef = (FunctionDefinition) pointedToDT;
|
||||
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
|
||||
assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
|
||||
str = funcDef.getPrototypeString();
|
||||
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
|
||||
|
||||
|
@ -301,12 +277,12 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
assertTrue("_Twice function definition", dt instanceof FunctionDefinition);
|
||||
funcDef = (FunctionDefinition) dt;
|
||||
str = funcDef.getPrototypeString();
|
||||
assertEquals("calling convention _Twice", "__stdcall", funcDef.getGenericCallingConvention().getDeclarationName());
|
||||
assertEquals("calling convention _Twice", "__stdcall", funcDef.getCallingConventionName());
|
||||
funcArgs = funcDef.getArguments();
|
||||
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
|
||||
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
|
||||
funcDef = (FunctionDefinition) pointedToDT;
|
||||
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
|
||||
assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
|
||||
str = funcDef.getPrototypeString();
|
||||
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
|
||||
|
||||
|
@ -315,12 +291,12 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
assertTrue("_Twice function definition", dt instanceof FunctionDefinition);
|
||||
funcDef = (FunctionDefinition) dt;
|
||||
str = funcDef.getPrototypeString();
|
||||
assertEquals("calling convention _Thrice", "", funcDef.getGenericCallingConvention().getDeclarationName());
|
||||
assertEquals("calling convention _Thrice", "unknown", funcDef.getCallingConventionName());
|
||||
funcArgs = funcDef.getArguments();
|
||||
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
|
||||
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
|
||||
funcDef = (FunctionDefinition) pointedToDT;
|
||||
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
|
||||
assertEquals("calling convention _Once", "__cdecl", funcDef.getCallingConventionName());
|
||||
str = funcDef.getPrototypeString();
|
||||
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
|
||||
|
||||
|
@ -368,22 +344,34 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
dt = dtMgr.getDataType(new CategoryPath("/functions"), "stdcall_func");
|
||||
assertTrue("not a function", dt instanceof FunctionDefinition);
|
||||
str = ((FunctionDefinition) dt).getPrototypeString();
|
||||
assertTrue("Callee should not purge", ((FunctionDefinition) dt)
|
||||
.getGenericCallingConvention() == GenericCallingConvention.stdcall);
|
||||
assertTrue("Callee should not purge", CompilerSpec.CALLING_CONVENTION_stdcall
|
||||
.equals(((FunctionDefinition) dt).getCallingConventionName()));
|
||||
assertTrue("signature not correct", str.equals("int stdcall_func(int b)"));
|
||||
|
||||
dt = dtMgr.getDataType(new CategoryPath("/functions"), "cdecl_func");
|
||||
assertTrue("not a function", dt instanceof FunctionDefinition);
|
||||
str = ((FunctionDefinition) dt).getPrototypeString();
|
||||
assertTrue("Caller should purge", ((FunctionDefinition) dt)
|
||||
.getGenericCallingConvention() != GenericCallingConvention.stdcall);
|
||||
assertTrue("Caller should purge", CompilerSpec.CALLING_CONVENTION_cdecl
|
||||
.equals(((FunctionDefinition) dt).getCallingConventionName()));
|
||||
assertTrue("signature not correct", str.equals("int cdecl_func(int a)"));
|
||||
|
||||
dt = dtMgr.getDataType(new CategoryPath("/functions"), "cdecl_func_after");
|
||||
assertTrue("not a function", dt instanceof FunctionDefinition);
|
||||
assertTrue("Caller should purge", ((FunctionDefinition) dt)
|
||||
.getGenericCallingConvention() != GenericCallingConvention.stdcall);
|
||||
assertTrue("Caller should purge", CompilerSpec.CALLING_CONVENTION_cdecl
|
||||
.equals(((FunctionDefinition) dt).getCallingConventionName()));
|
||||
|
||||
dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Noreturn_exit");
|
||||
assertTrue("not a function", dt instanceof FunctionDefinition);
|
||||
assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
|
||||
|
||||
dt = dtMgr.getDataType(new CategoryPath("/functions"), "win_exit");
|
||||
assertTrue("not a function", dt instanceof FunctionDefinition);
|
||||
assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
|
||||
|
||||
dt = dtMgr.getDataType(new CategoryPath("/functions"), "gcc_exit");
|
||||
assertTrue("not a function", dt instanceof FunctionDefinition);
|
||||
assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
|
||||
|
||||
dt = dtMgr.getDataType(new CategoryPath("/"), "UINT2");
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertEquals("ushort", ((TypeDef) dt).getBaseDataType().getName());
|
||||
|
|
|
@ -48,8 +48,11 @@ public class PreProcessorTest extends AbstractGenericTest {
|
|||
super();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
@Before
|
||||
public void init() {
|
||||
if (dtMgr != null) {
|
||||
return; // do only once - but not too soon
|
||||
}
|
||||
URL url = PreProcessorTest.class.getResource(resourceName);
|
||||
|
||||
String[] args = new String[] { "-I" + url.getPath() + "/..", "-DFROM_ARG_VALUE=300",
|
||||
|
|
|
@ -20,13 +20,13 @@ import static org.junit.Assert.*;
|
|||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.app.util.cparser.C.CParser;
|
||||
import ghidra.app.util.cparser.C.ParseException;
|
||||
import ghidra.util.Msg;
|
||||
import resources.ResourceManager;
|
||||
|
||||
abstract class AbstractCompositeTest extends AbstractGTest {
|
||||
abstract class AbstractCompositeTest extends AbstractGenericTest {
|
||||
|
||||
private HashMap<Long, DataType> copyMap = new HashMap<>();
|
||||
|
||||
|
|
|
@ -22,12 +22,12 @@ import java.util.List;
|
|||
import org.apache.commons.compress.utils.Sets;
|
||||
import org.junit.*;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import generic.test.AbstractGenericTest;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class StructureDataTypeTest extends AbstractGTest {
|
||||
public class StructureDataTypeTest extends AbstractGenericTest {
|
||||
|
||||
private Structure struct;
|
||||
|
||||
|
|
|
@ -21,12 +21,12 @@ import org.junit.*;
|
|||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import generic.test.AbstractGenericTest;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class UnionDataTypeTest extends AbstractGTest {
|
||||
public class UnionDataTypeTest extends AbstractGenericTest {
|
||||
|
||||
private Union union;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue