mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge remote-tracking branch 'origin/GP-6006_ghidra1_added_new_source_type' into Ghidra_12.0
This commit is contained in:
commit
5df99853af
15 changed files with 321 additions and 183 deletions
|
@ -52,7 +52,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
|
||||
implements TraceSymbol, DecodesAddresses {
|
||||
|
||||
private static final byte SOURCE_MASK = 0x0F;
|
||||
private static final byte SOURCE_MASK = 0x0F; // see SourceType
|
||||
private static final int SOURCE_SHIFT = 0;
|
||||
private static final byte SOURCE_CLEAR = ~(SOURCE_MASK << SOURCE_SHIFT);
|
||||
|
||||
|
@ -365,8 +365,8 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
|
|||
}
|
||||
|
||||
protected void doSetSource(SourceType newSource) {
|
||||
flags =
|
||||
(byte) ((flags & SOURCE_CLEAR) | (newSource.ordinal() & SOURCE_MASK) << SOURCE_SHIFT);
|
||||
flags = (byte) ((flags & SOURCE_CLEAR) |
|
||||
(newSource.getStorageId() & SOURCE_MASK) << SOURCE_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -502,7 +502,7 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
|
|||
@Override
|
||||
public SourceType getSource() {
|
||||
assertNotGlobal();
|
||||
return SourceType.values()[(flags >> SOURCE_SHIFT) & SOURCE_MASK];
|
||||
return SourceType.getSourceType((flags >> SOURCE_SHIFT) & SOURCE_MASK);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -103,14 +103,14 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
implements DecodesAddresses {
|
||||
private static final String TABLE_NAME = "References";
|
||||
|
||||
private static final byte SOURCE_MASK = 0x0F;
|
||||
private static final byte SOURCE_MASK = 0x0F; // see SourceType
|
||||
private static final byte SOURCE_SHIFT = 0;
|
||||
//private static final byte SOURCE_CLEAR = ~(SOURCE_MASK << SOURCE_SHIFT);
|
||||
|
||||
private static final byte PRIMARY_MASK = 0x10;
|
||||
private static final byte PRIMARY_CLEAR = ~PRIMARY_MASK;
|
||||
|
||||
private static final byte TYPE_MASK = 0x3;
|
||||
private static final byte TYPE_MASK = 0x3; // See DBTraceReferenceSpace.TypeEnum
|
||||
private static final byte TYPE_SHIFT = 5;
|
||||
//private static final byte TYPE_CLEAR = ~(TYPE_MASK << TYPE_SHIFT);
|
||||
|
||||
|
@ -142,15 +142,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
return DBTraceUtils.tableName(TABLE_NAME, space);
|
||||
}
|
||||
|
||||
@DBAnnotatedField(
|
||||
column = TO_ADDR_MIN_COLUMN_NAME,
|
||||
indexed = true,
|
||||
codec = AddressDBFieldCodec.class)
|
||||
@DBAnnotatedField(column = TO_ADDR_MIN_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class)
|
||||
protected Address toAddrMin = Address.NO_ADDRESS;
|
||||
@DBAnnotatedField(
|
||||
column = TO_ADDR_MAX_COLUMN_NAME,
|
||||
indexed = true,
|
||||
codec = AddressDBFieldCodec.class)
|
||||
@DBAnnotatedField(column = TO_ADDR_MAX_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class)
|
||||
protected Address toAddrMax = Address.NO_ADDRESS;
|
||||
@DBAnnotatedField(column = SYMBOL_ID_COLUMN_NAME, indexed = true)
|
||||
protected long symbolId; // TODO: Is this at the from or to address? I think TO...
|
||||
|
@ -201,8 +195,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
return this;
|
||||
}
|
||||
|
||||
protected void set(AddressRange toRange, long symbolId, RefType refType,
|
||||
int opIndex, long ext, boolean isPrimary, TypeEnum type, SourceType sourceType) {
|
||||
protected void set(AddressRange toRange, long symbolId, RefType refType, int opIndex,
|
||||
long ext, boolean isPrimary, TypeEnum type, SourceType sourceType) {
|
||||
this.toAddrMin = toRange.getMinAddress();
|
||||
this.toAddrMax = toRange.getMaxAddress();
|
||||
this.symbolId = symbolId;
|
||||
|
@ -210,7 +204,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
this.opIndex = (byte) opIndex;
|
||||
this.ext = ext;
|
||||
this.flags = (byte) ((isPrimary ? PRIMARY_MASK : 0) |
|
||||
(sourceType.ordinal() << SOURCE_SHIFT) | type.ordinal() << TYPE_SHIFT);
|
||||
(sourceType.getStorageId() << SOURCE_SHIFT) | type.ordinal() << TYPE_SHIFT);
|
||||
update(TO_ADDR_MIN_COLUMN, TO_ADDR_MAX_COLUMN, SYMBOL_ID_COLUMN, REF_TYPE_COLUMN,
|
||||
OP_INDEX_COLUMN, EXT_COLUMN, FLAGS_COLUMN);
|
||||
|
||||
|
@ -243,8 +237,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
TraceEvents.SYMBOL_ASSOCIATION_REMOVED, space.space, oldSymbol, ref));
|
||||
}
|
||||
if (newSymbol != null) {
|
||||
space.trace.setChanged(new TraceChangeRecord<>(
|
||||
TraceEvents.SYMBOL_ASSOCIATION_ADDED, space.space, newSymbol, ref));
|
||||
space.trace.setChanged(new TraceChangeRecord<>(TraceEvents.SYMBOL_ASSOCIATION_ADDED,
|
||||
space.space, newSymbol, ref));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,7 +270,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
}
|
||||
|
||||
public SourceType getSourceType() {
|
||||
return SourceType.values()[(flags >> SOURCE_SHIFT) & SOURCE_MASK];
|
||||
return SourceType.getSourceType((flags >> SOURCE_SHIFT) & SOURCE_MASK);
|
||||
}
|
||||
|
||||
protected void doDelete() {
|
||||
|
@ -375,16 +369,15 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
referenceMapSpace.getUserIndex(long.class, DBTraceReferenceEntry.SYMBOL_ID_COLUMN);
|
||||
|
||||
this.xrefMapSpace = new DBTraceAddressSnapRangePropertyMapSpace<>(
|
||||
DBTraceXRefEntry.tableName(space), trace, factory, lock, space,
|
||||
DBTraceXRefEntry.class, (t, s, r) -> new DBTraceXRefEntry(this, t, s, r));
|
||||
DBTraceXRefEntry.tableName(space), trace, factory, lock, space, DBTraceXRefEntry.class,
|
||||
(t, s, r) -> new DBTraceXRefEntry(this, t, s, r));
|
||||
this.xrefsByRefKey = xrefMapSpace.getUserIndex(long.class, DBTraceXRefEntry.REF_KEY_COLUMN);
|
||||
}
|
||||
|
||||
protected void doAddXRef(DBTraceReferenceEntry refEnt) {
|
||||
// Note: called from manager on relevant space
|
||||
DBTraceXRefEntry xrefEnt = xrefMapSpace.put(refEnt.toRange, refEnt.getLifespan(), null);
|
||||
xrefEnt.set((short) refEnt.getRange().getAddressSpace().getSpaceID(),
|
||||
refEnt.getKey());
|
||||
xrefEnt.set((short) refEnt.getRange().getAddressSpace().getSpaceID(), refEnt.getKey());
|
||||
}
|
||||
|
||||
protected void doDelXRef(DBTraceReferenceEntry refEnt) {
|
||||
|
@ -451,11 +444,11 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
int operandIndex) {
|
||||
// Do I consider "compatibility?" as in ReferenceDBManager?
|
||||
// NOTE: Always call with the write lock
|
||||
for (DBTraceReferenceEntry ent : referenceMapSpace.reduce(
|
||||
TraceAddressSnapRangeQuery.intersecting(new AddressRangeImpl(fromAddress, fromAddress),
|
||||
span)).values()) {
|
||||
if (!ent.toRange.equals(toRange) ||
|
||||
ent.opIndex != operandIndex) {
|
||||
for (DBTraceReferenceEntry ent : referenceMapSpace
|
||||
.reduce(TraceAddressSnapRangeQuery
|
||||
.intersecting(new AddressRangeImpl(fromAddress, fromAddress), span))
|
||||
.values()) {
|
||||
if (!ent.toRange.equals(toRange) || ent.opIndex != operandIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -585,10 +578,10 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
public DBTraceReference getReference(long snap, Address fromAddress, AddressRange toRange,
|
||||
int operandIndex) {
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
for (DBTraceReferenceEntry entry : referenceMapSpace.reduce(
|
||||
TraceAddressSnapRangeQuery.at(fromAddress, snap)).values()) {
|
||||
if (!entry.toRange.equals(toRange) ||
|
||||
entry.opIndex != operandIndex) {
|
||||
for (DBTraceReferenceEntry entry : referenceMapSpace
|
||||
.reduce(TraceAddressSnapRangeQuery.at(fromAddress, snap))
|
||||
.values()) {
|
||||
if (!entry.toRange.equals(toRange) || entry.opIndex != operandIndex) {
|
||||
continue;
|
||||
}
|
||||
return entry.ref;
|
||||
|
@ -641,8 +634,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
@Override
|
||||
public Collection<? extends DBTraceReference> getFlowReferencesFrom(long snap,
|
||||
Address fromAddress) {
|
||||
return streamReferencesFrom(snap, fromAddress)
|
||||
.filter(r -> r.getReferenceType().isFlow())
|
||||
return streamReferencesFrom(snap, fromAddress).filter(r -> r.getReferenceType().isFlow())
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
@ -650,8 +642,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
public void clearReferencesFrom(Lifespan span, AddressRange range) {
|
||||
try (LockHold hold = manager.getTrace().lockWrite()) {
|
||||
long startSnap = span.lmin();
|
||||
for (DBTraceReferenceEntry ref : referenceMapSpace.reduce(
|
||||
TraceAddressSnapRangeQuery.intersecting(range, span)).values()) {
|
||||
for (DBTraceReferenceEntry ref : referenceMapSpace
|
||||
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span))
|
||||
.values()) {
|
||||
truncateOrDeleteEntry(ref, startSnap);
|
||||
}
|
||||
// TODO: Coalesce events?
|
||||
|
@ -682,21 +675,19 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
@Override
|
||||
public Collection<? extends DBTraceReference> getReferencesToRange(Lifespan span,
|
||||
AddressRange range, Rectangle2DDirection order) {
|
||||
return new LazyCollection<>(
|
||||
() -> xrefMapSpace
|
||||
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span).starting(order))
|
||||
.values()
|
||||
.stream()
|
||||
.map(this::getRefForXRefEntry));
|
||||
return new LazyCollection<>(() -> xrefMapSpace
|
||||
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span).starting(order))
|
||||
.values()
|
||||
.stream()
|
||||
.map(this::getRefForXRefEntry));
|
||||
}
|
||||
|
||||
protected void truncateOrDeleteEntry(DBTraceReferenceEntry ref, long otherStartSnap) {
|
||||
if (ref.getLifespan().lmin() < otherStartSnap) {
|
||||
Lifespan oldSpan = ref.getLifespan();
|
||||
ref.setEndSnap(otherStartSnap - 1);
|
||||
trace.setChanged(new TraceChangeRecord<>(
|
||||
TraceEvents.REFERENCE_LIFESPAN_CHANGED, space, ref.ref, oldSpan,
|
||||
ref.getLifespan()));
|
||||
trace.setChanged(new TraceChangeRecord<>(TraceEvents.REFERENCE_LIFESPAN_CHANGED, space,
|
||||
ref.ref, oldSpan, ref.getLifespan()));
|
||||
}
|
||||
else {
|
||||
ref.ref.delete();
|
||||
|
@ -707,8 +698,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
|
|||
public void clearReferencesTo(Lifespan span, AddressRange range) {
|
||||
try (LockHold hold = manager.getTrace().lockWrite()) {
|
||||
long startSnap = span.lmin();
|
||||
for (DBTraceXRefEntry xref : xrefMapSpace.reduce(
|
||||
TraceAddressSnapRangeQuery.intersecting(range, span)).values()) {
|
||||
for (DBTraceXRefEntry xref : xrefMapSpace
|
||||
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span))
|
||||
.values()) {
|
||||
DBTraceReferenceEntry ref = getRefEntryForXRefEntry(xref);
|
||||
truncateOrDeleteEntry(ref, startSnap);
|
||||
}
|
||||
|
|
|
@ -448,7 +448,7 @@
|
|||
<TD align="left" height="21" width="22%">Function</TD>
|
||||
|
||||
<TD align="left" height="21" width="56%">Indicates the source-type associated with the
|
||||
function signature (i.e., DEFAULT, ANALYSIS, IMPORTED, USER_DEFINED).</TD>
|
||||
function signature (i.e., DEFAULT, AI_ASSIST, ANALYSIS, IMPORTED, USER_DEFINED).</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
|
|
|
@ -29,11 +29,12 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
|
||||
private static final String XML_NAME = "SYMBOL_TABLE_FILTER";
|
||||
|
||||
private Filter userDefinedFilter;
|
||||
private Filter analysisFilter;
|
||||
private Filter defaultFunctionFilter;
|
||||
private Filter defaultLabelFilter;
|
||||
private Filter importedFilter;
|
||||
private Filter defaultLabelSourceFilter;
|
||||
private Filter defaultFunctionSourceFilter;
|
||||
private Filter aiSourceFilter;
|
||||
private Filter analysisSourceFilter;
|
||||
private Filter importedSourceFilter;
|
||||
private Filter userDefinedSourceFilter;
|
||||
|
||||
private Filter[] labelFilters;
|
||||
private Filter[] nonLabelFilters;
|
||||
|
@ -67,19 +68,21 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
for (Filter advancedFilter : advancedFilters) {
|
||||
filterMap.put(advancedFilter.getName(), advancedFilter);
|
||||
}
|
||||
filterMap.put(userDefinedFilter.getName(), userDefinedFilter);
|
||||
filterMap.put(importedFilter.getName(), importedFilter);
|
||||
filterMap.put(analysisFilter.getName(), analysisFilter);
|
||||
filterMap.put(defaultLabelFilter.getName(), defaultLabelFilter);
|
||||
filterMap.put(defaultFunctionFilter.getName(), defaultFunctionFilter);
|
||||
filterMap.put(defaultLabelSourceFilter.getName(), defaultLabelSourceFilter);
|
||||
filterMap.put(defaultFunctionSourceFilter.getName(), defaultFunctionSourceFilter);
|
||||
filterMap.put(aiSourceFilter.getName(), aiSourceFilter);
|
||||
filterMap.put(analysisSourceFilter.getName(), analysisSourceFilter);
|
||||
filterMap.put(importedSourceFilter.getName(), importedSourceFilter);
|
||||
filterMap.put(userDefinedSourceFilter.getName(), userDefinedSourceFilter);
|
||||
|
||||
if (oldFilter instanceof NewSymbolFilter) {
|
||||
NewSymbolFilter filter = (NewSymbolFilter) oldFilter;
|
||||
userDefinedFilter.setActive(filter.userDefinedFilter.isActive());
|
||||
importedFilter.setActive(filter.importedFilter.isActive());
|
||||
analysisFilter.setActive(filter.analysisFilter.isActive());
|
||||
defaultLabelFilter.setActive(filter.defaultLabelFilter.isActive());
|
||||
defaultFunctionFilter.setActive(filter.defaultFunctionFilter.isActive());
|
||||
defaultLabelSourceFilter.setActive(filter.defaultLabelSourceFilter.isActive());
|
||||
defaultFunctionSourceFilter.setActive(filter.defaultFunctionSourceFilter.isActive());
|
||||
aiSourceFilter.setActive(filter.aiSourceFilter.isActive());
|
||||
analysisSourceFilter.setActive(filter.analysisSourceFilter.isActive());
|
||||
importedSourceFilter.setActive(filter.importedSourceFilter.isActive());
|
||||
userDefinedSourceFilter.setActive(filter.userDefinedSourceFilter.isActive());
|
||||
|
||||
for (int i = 0; i < labelFilters.length; i++) {
|
||||
labelFilters[i].setActive(filter.labelFilters[i].isActive());
|
||||
|
@ -156,8 +159,8 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
|
||||
@Override
|
||||
public boolean acceptsOnlyCodeSymbols() {
|
||||
for (int i = 0; i < activeTypeFilters.length; i++) {
|
||||
if (!activeTypeFilters[i].onlyCodeSymbols) {
|
||||
for (Filter activeTypeFilter : activeTypeFilters) {
|
||||
if (!activeTypeFilter.onlyCodeSymbols) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +169,7 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
|
||||
@Override
|
||||
public boolean acceptsDefaultLabelSymbols() {
|
||||
if (!defaultLabelFilter.isActive()) {
|
||||
if (!defaultLabelSourceFilter.isActive()) {
|
||||
return false;
|
||||
}
|
||||
for (Filter activeTypeFilter : activeTypeFilters) {
|
||||
|
@ -183,10 +186,10 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
}
|
||||
|
||||
String[] getSourceFilterNames() {
|
||||
return new String[] { userDefinedFilter.getName(), defaultFunctionFilter.getName(),
|
||||
importedFilter.getName(), defaultLabelFilter.getName(), analysisFilter.getName(),
|
||||
|
||||
};
|
||||
return new String[] { defaultLabelSourceFilter.getName(),
|
||||
defaultFunctionSourceFilter.getName(), aiSourceFilter.getName(),
|
||||
analysisSourceFilter.getName(), userDefinedSourceFilter.getName(),
|
||||
importedSourceFilter.getName() };
|
||||
}
|
||||
|
||||
String[] getLabelTypeFilterNames() {
|
||||
|
@ -283,31 +286,38 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
for (Filter advancedFilter : advancedFilters) {
|
||||
advancedFilter.setActive(false);
|
||||
}
|
||||
userDefinedFilter.setActive(true);
|
||||
importedFilter.setActive(true);
|
||||
analysisFilter.setActive(true);
|
||||
defaultFunctionFilter.setActive(true);
|
||||
defaultLabelFilter.setActive(false);
|
||||
defaultFunctionSourceFilter.setActive(true);
|
||||
defaultLabelSourceFilter.setActive(false);
|
||||
aiSourceFilter.setActive(true);
|
||||
analysisSourceFilter.setActive(true);
|
||||
importedSourceFilter.setActive(true);
|
||||
userDefinedSourceFilter.setActive(true);
|
||||
|
||||
rebuildActiveFilters();
|
||||
}
|
||||
|
||||
private void rebuildActiveFilters() {
|
||||
ArrayList<Filter> originList = new ArrayList<>(3);
|
||||
if (userDefinedFilter.isActive()) {
|
||||
originList.add(userDefinedFilter);
|
||||
|
||||
if (defaultLabelSourceFilter.isActive()) {
|
||||
originList.add(defaultLabelSourceFilter);
|
||||
}
|
||||
if (importedFilter.isActive()) {
|
||||
originList.add(importedFilter);
|
||||
if (defaultFunctionSourceFilter.isActive()) {
|
||||
originList.add(defaultFunctionSourceFilter);
|
||||
}
|
||||
if (analysisFilter.isActive()) {
|
||||
originList.add(analysisFilter);
|
||||
if (aiSourceFilter.isActive()) {
|
||||
originList.add(aiSourceFilter);
|
||||
}
|
||||
if (defaultLabelFilter.isActive()) {
|
||||
originList.add(defaultLabelFilter);
|
||||
if (analysisSourceFilter.isActive()) {
|
||||
originList.add(analysisSourceFilter);
|
||||
}
|
||||
if (defaultFunctionFilter.isActive()) {
|
||||
originList.add(defaultFunctionFilter);
|
||||
if (importedSourceFilter.isActive()) {
|
||||
originList.add(importedSourceFilter);
|
||||
}
|
||||
if (userDefinedSourceFilter.isActive()) {
|
||||
originList.add(userDefinedSourceFilter);
|
||||
}
|
||||
|
||||
activeOriginFilters = new Filter[originList.size()];
|
||||
originList.toArray(activeOriginFilters);
|
||||
|
||||
|
@ -339,49 +349,16 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
advancedList.toArray(activeAdvancedFilters);
|
||||
|
||||
acceptsAllTypes = activeTypeFilters.length == labelFilters.length + nonLabelFilters.length;
|
||||
acceptsAllSources = userDefinedFilter.isActive() && analysisFilter.isActive() &&
|
||||
defaultLabelFilter.isActive() && defaultFunctionFilter.isActive() &&
|
||||
importedFilter.isActive();
|
||||
|
||||
acceptsAllSources =
|
||||
defaultLabelSourceFilter.isActive() && defaultFunctionSourceFilter.isActive() &&
|
||||
importedSourceFilter.isActive() && aiSourceFilter.isActive() &&
|
||||
analysisSourceFilter.isActive() && userDefinedSourceFilter.isActive();
|
||||
acceptsAll = acceptsAllTypes && acceptsAllSources && activeAdvancedFilters.length == 0;
|
||||
|
||||
}
|
||||
|
||||
private void createFilters() {
|
||||
userDefinedFilter = new Filter("User Defined", false, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSource() == SourceType.USER_DEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getDescription() {
|
||||
return "Include Symbols named by the user.";
|
||||
}
|
||||
};
|
||||
importedFilter = new Filter("Imported", false, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSource() == SourceType.IMPORTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getDescription() {
|
||||
return "Include Symbols imported from external information.";
|
||||
}
|
||||
};
|
||||
analysisFilter = new Filter("Analysis", false, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSource() == SourceType.ANALYSIS;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getDescription() {
|
||||
return "Include Symbols named by auto-analysis.";
|
||||
}
|
||||
};
|
||||
defaultLabelFilter = new Filter("Default (Labels)", true, false) {
|
||||
defaultLabelSourceFilter = new Filter("Default (Labels)", true, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSymbolType() != SymbolType.FUNCTION &&
|
||||
|
@ -394,7 +371,7 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
}
|
||||
|
||||
};
|
||||
defaultFunctionFilter = new Filter("Default (Functions)", true, false) {
|
||||
defaultFunctionSourceFilter = new Filter("Default (Functions)", true, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSymbolType() == SymbolType.FUNCTION &&
|
||||
|
@ -405,8 +382,52 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
String getDescription() {
|
||||
return "Include Symbols that have default names.";
|
||||
}
|
||||
|
||||
};
|
||||
aiSourceFilter = new Filter(SourceType.AI.getDisplayString(), false, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSource() == SourceType.AI;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getDescription() {
|
||||
return "Include Symbols named by auto-analysis.";
|
||||
}
|
||||
};
|
||||
analysisSourceFilter = new Filter(SourceType.ANALYSIS.getDisplayString(), false, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSource() == SourceType.ANALYSIS;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getDescription() {
|
||||
return "Include Symbols named by auto-analysis.";
|
||||
}
|
||||
};
|
||||
importedSourceFilter = new Filter(SourceType.IMPORTED.getDisplayString(), false, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSource() == SourceType.IMPORTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getDescription() {
|
||||
return "Include Symbols imported from external information.";
|
||||
}
|
||||
};
|
||||
userDefinedSourceFilter =
|
||||
new Filter(SourceType.USER_DEFINED.getDisplayString(), false, false) {
|
||||
@Override
|
||||
boolean matches(Program program, Symbol symbol) {
|
||||
return symbol.getSource() == SourceType.USER_DEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getDescription() {
|
||||
return "Include Symbols named by the user.";
|
||||
}
|
||||
};
|
||||
|
||||
Filter instructionFilter = new Filter("Instruction Labels", true, true) {
|
||||
@Override
|
||||
|
@ -902,9 +923,7 @@ public class NewSymbolFilter implements SymbolFilter {
|
|||
|
||||
@Override
|
||||
boolean isEnabled() {
|
||||
Iterator<Filter> it = applicableFilters.iterator();
|
||||
while (it.hasNext()) {
|
||||
Filter filter = it.next();
|
||||
for (Filter filter : applicableFilters) {
|
||||
if (filter.isActive()) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1286,6 +1286,8 @@
|
|||
<li class="listitem" style="list-style-type: none">
|
||||
<span class="emphasis"><em>DEFAULT</em></span> - for basic or no information</li>
|
||||
<li class="listitem" style="list-style-type: none">
|
||||
<span class="emphasis"><em>AI</em></span> - for information that is produced with AI assistance</li>
|
||||
<li class="listitem" style="list-style-type: none">
|
||||
<span class="emphasis"><em>ANALYSIS</em></span> - for information derived by an Analyzer</li>
|
||||
<li class="listitem" style="list-style-type: none">
|
||||
<span class="emphasis"><em>IMPORTED</em></span> - for information imported from an external source</li>
|
||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.feature.vt.gui.provider.matchtable;
|
|||
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
|
||||
|
@ -48,6 +49,7 @@ public class SymbolTypeFilter extends CheckBoxBasedAncillaryFilter<VTMatch> {
|
|||
};
|
||||
|
||||
SourceType[] values = SourceType.values();
|
||||
Arrays.sort(values, (s1, s2) -> s1.getPriority() - s2.getPriority());
|
||||
for (SourceType type : values) {
|
||||
GCheckBox checkBox = new GCheckBox(type.getDisplayString(), true);
|
||||
checkBox.addItemListener(listener);
|
||||
|
|
|
@ -116,8 +116,10 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
* 13-Dec-2024 - version 29 Added source file manager.
|
||||
* 3-Jun-2025 - version 30 Symbol Table schema V4 with external symbol data indexing
|
||||
* 15-Sep-2025 - version 31 Code Mananger dropped Composites property map use
|
||||
* 19-Sep-2025 - version 32 Expanded number of SourceType values and record storage affecting
|
||||
* SymbolDB, FunctionDB and RefListFlagsV0
|
||||
*/
|
||||
static final int DB_VERSION = 31;
|
||||
static final int DB_VERSION = 32;
|
||||
|
||||
/**
|
||||
* UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the
|
||||
|
|
|
@ -46,10 +46,12 @@ abstract class FunctionAdapter {
|
|||
static final byte FUNCTION_INLINE_FLAG = (byte) 0x2; // Bit 1 is flag for "is inline".
|
||||
static final byte FUNCTION_NO_RETURN_FLAG = (byte) 0x4; // Bit 2 is flag for "has no return".
|
||||
static final byte FUNCTION_CUSTOM_PARAM_STORAGE_FLAG = (byte) 0x8; // Bit 3 is flag for "has custom storage"
|
||||
static final byte FUNCTION_SIGNATURE_SOURCE = (byte) 0x30; // Bits 4-5 are storage for "signature SourceType"
|
||||
static final byte FUNCTION_SIGNATURE_SOURCE = (byte) 0x70; // Bits 4-6 are storage for "signature SourceType"
|
||||
|
||||
static final int FUNCTION_SIGNATURE_SOURCE_SHIFT = 4; // bit shift for flag storage of "signature SourceType"
|
||||
|
||||
private static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
|
||||
|
||||
final static Schema FUNCTION_SCHEMA = new Schema(CURRENT_VERSION, "ID",
|
||||
new Field[] { LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE,
|
||||
ByteField.INSTANCE, ByteField.INSTANCE, StringField.INSTANCE },
|
||||
|
@ -94,8 +96,11 @@ abstract class FunctionAdapter {
|
|||
}
|
||||
|
||||
static byte getSignatureSourceFlagBits(SourceType signatureSource) {
|
||||
return (byte) (signatureSource
|
||||
.ordinal() << FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT);
|
||||
int sourceTypeId = signatureSource.getStorageId();
|
||||
if (sourceTypeId > MAX_SOURCE_VALUE) {
|
||||
throw new RuntimeException("Unsupported SourceType storage ID: " + sourceTypeId);
|
||||
}
|
||||
return (byte) (sourceTypeId << FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT);
|
||||
}
|
||||
|
||||
static FunctionAdapter findReadOnlyAdapter(DBHandle handle, AddressMap map)
|
||||
|
|
|
@ -2445,9 +2445,9 @@ public class FunctionDB extends DatabaseObject implements Function {
|
|||
|
||||
SourceType getStoredSignatureSource() {
|
||||
byte flags = rec.getByteValue(FunctionAdapter.FUNCTION_FLAGS_COL);
|
||||
int typeOrdinal = (flags &
|
||||
int sourceTypeId = (flags &
|
||||
FunctionAdapter.FUNCTION_SIGNATURE_SOURCE) >>> FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT;
|
||||
return SourceType.values()[typeOrdinal];
|
||||
return SourceType.getSourceType(sourceTypeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.
|
||||
|
@ -20,13 +19,23 @@ import ghidra.program.model.symbol.SourceType;
|
|||
|
||||
class RefListFlagsV0 {
|
||||
|
||||
private static final int SOURCE_LOBIT = 0x01;
|
||||
// NOTE: Storage for SourceType has been expanded into upper zero-initialized bits
|
||||
// with simple ProgramDB version change.
|
||||
|
||||
private static final int SOURCE_LOBIT = 0x01; // SourceType LO 1-bit
|
||||
private static final int IS_PRIMARY = 0x02;
|
||||
private static final int IS_OFFSET = 0x04;
|
||||
private static final int HAS_SYMBOL_ID = 0x08;
|
||||
private static final int IS_SHIFT = 0x10;
|
||||
private static final int SOURCE_HIBITS = 0x60; // SourceType HI 2-bits
|
||||
|
||||
private static final int SOURCE_HIBIT = 0x20;
|
||||
|
||||
private static final int SOURCE_LOBIT_SHIFT = 0;
|
||||
private static final int SOURCE_HIBITS_SHIFT = 5;
|
||||
|
||||
private static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
|
||||
|
||||
private int flags;
|
||||
|
||||
RefListFlagsV0(byte flags) {
|
||||
|
@ -36,12 +45,23 @@ class RefListFlagsV0 {
|
|||
public RefListFlagsV0(boolean isPrimary, boolean isOffsetRef, boolean hasSymbolID,
|
||||
boolean isShiftRef, SourceType source) {
|
||||
flags = 0;
|
||||
if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
|
||||
flags |= SOURCE_LOBIT;
|
||||
}
|
||||
if (source == SourceType.ANALYSIS || source == SourceType.IMPORTED) {
|
||||
flags |= SOURCE_HIBIT;
|
||||
|
||||
// Get the storage ID to be used to encode source type
|
||||
// NOTE: RefListV0 uses a storage ID in some cases that differs from SourceType storage ID
|
||||
int sourceId = switch (source) {
|
||||
case DEFAULT -> 0;
|
||||
case ANALYSIS -> 2;
|
||||
default -> source.getStorageId();
|
||||
};
|
||||
|
||||
// Encode SourceType value into split storage flags
|
||||
if (sourceId > MAX_SOURCE_VALUE) {
|
||||
throw new RuntimeException("Unsupported SourceType storage ID: " + sourceId);
|
||||
}
|
||||
int sourceTypeLoBit = (sourceId & 1) << SOURCE_LOBIT_SHIFT; // 1-bit
|
||||
int sourceTypeHiBits = (sourceId >>> 1) << SOURCE_HIBITS_SHIFT; // remaining hi-bits
|
||||
flags |= sourceTypeHiBits | sourceTypeLoBit;
|
||||
|
||||
if (isPrimary)
|
||||
flags |= IS_PRIMARY;
|
||||
if (isOffsetRef)
|
||||
|
@ -57,12 +77,18 @@ class RefListFlagsV0 {
|
|||
}
|
||||
|
||||
SourceType getSource() {
|
||||
boolean isLoBit = (flags & SOURCE_LOBIT) != 0;
|
||||
boolean isHiBit = (flags & SOURCE_HIBIT) != 0;
|
||||
if (isHiBit) {
|
||||
return isLoBit ? SourceType.IMPORTED : SourceType.ANALYSIS;
|
||||
}
|
||||
return isLoBit ? SourceType.USER_DEFINED : SourceType.DEFAULT;
|
||||
|
||||
// Decode storage ID from flags bits
|
||||
int sourceTypeLoBit = (flags & SOURCE_LOBIT) >>> SOURCE_LOBIT_SHIFT; // 1-bit
|
||||
int sourceTypeHiBits = (flags & SOURCE_HIBITS) >>> (SOURCE_HIBITS_SHIFT - 1); // remaining HI-bits
|
||||
int sourceTypeId = sourceTypeHiBits | sourceTypeLoBit;
|
||||
|
||||
// NOTE: RefListV0 uses a storage ID in some cases that differs from SourceType storage ID
|
||||
return switch (sourceTypeId) {
|
||||
case 0 -> SourceType.DEFAULT;
|
||||
case 2 -> SourceType.ANALYSIS;
|
||||
default -> SourceType.getSourceType(sourceTypeId);
|
||||
};
|
||||
}
|
||||
|
||||
public boolean hasSymbolID() {
|
||||
|
|
|
@ -169,7 +169,7 @@ public abstract class MemorySymbol extends SymbolDB {
|
|||
newNamespace.getID());
|
||||
}
|
||||
if (newSource != null) {
|
||||
setSourceFlagBit(newSource);
|
||||
setSourceFlagBits(newSource);
|
||||
}
|
||||
updatePinnedFlag(pinned);
|
||||
updateRecord();
|
||||
|
|
|
@ -253,7 +253,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
if (record != null) {
|
||||
setSourceFlagBit(newSource);
|
||||
setSourceFlagBits(newSource);
|
||||
updateRecord();
|
||||
symbolMgr.symbolSourceChanged(this);
|
||||
}
|
||||
|
@ -263,10 +263,10 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
protected void setSourceFlagBit(SourceType newSource) {
|
||||
protected void setSourceFlagBits(SourceType newSource) {
|
||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
||||
byte clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
|
||||
byte setBits = (byte) newSource.ordinal();
|
||||
byte clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_MASK;
|
||||
byte setBits = SymbolDatabaseAdapter.getSourceTypeFlagsBits(newSource);
|
||||
flags &= ~clearBits;
|
||||
flags |= setBits;
|
||||
record.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, flags);
|
||||
|
@ -280,10 +280,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
if (record == null) {
|
||||
return SourceType.DEFAULT;
|
||||
}
|
||||
byte sourceBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
|
||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
||||
byte adapterSource = (byte) (flags & sourceBits);
|
||||
return SourceType.values()[adapterSource];
|
||||
return SymbolDatabaseAdapter.decodeSourceTypeFromFlags(flags);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -448,8 +446,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
|
||||
private void updateSymbolSource(DBRecord symbolRecord, SourceType source) {
|
||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
||||
flags &= ~SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
|
||||
flags |= (byte) source.ordinal();
|
||||
flags &= ~SymbolDatabaseAdapter.SYMBOL_SOURCE_MASK; // clear source type bits
|
||||
flags |= SymbolDatabaseAdapter.getSourceTypeFlagsBits(source);
|
||||
symbolRecord.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, flags);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,9 +56,18 @@ abstract class SymbolDatabaseAdapter {
|
|||
|
||||
static final Schema SYMBOL_SCHEMA = SymbolDatabaseAdapterV4.V4_SYMBOL_SCHEMA;
|
||||
|
||||
// Bits 0 & 1 are used for the source of the symbol.
|
||||
static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
|
||||
// Bits 0, 1 and 3 are used for the source of the symbol.
|
||||
// NOTE: On the next V5 adapter revision the source type bits should be made contiguous
|
||||
static final byte SYMBOL_SOURCE_LO_BITS = (byte) 0x3; // bits 0-1 of SourceType storage ID
|
||||
static final byte SYMBOL_PINNED_FLAG = (byte) 0x4; // Bit 2 is flag for "anchored to address".
|
||||
static final byte SYMBOL_SOURCE_HI_BIT = (byte) 0x8; // bit-3 of SourceType storage ID
|
||||
|
||||
static final byte SYMBOL_SOURCE_MASK = (byte) 0xB; // (01011) Storage mask for SourceType storage ID
|
||||
|
||||
static final int SYMBOL_SOURCE_LO_BITS_SHIFT = 0;
|
||||
static final int SYMBOL_SOURCE_HI_BIT_SHIFT = 3;
|
||||
|
||||
static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
|
||||
|
||||
// Symbol type constants
|
||||
static final int SYMBOL_TYPE_LABEL = SymbolType.LABEL.getID();
|
||||
|
@ -219,6 +228,34 @@ abstract class SymbolDatabaseAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms source type storage ID to V4 flag bits.
|
||||
* @param sourceType source type
|
||||
* @return storage ID flag bits
|
||||
*/
|
||||
static byte getSourceTypeFlagsBits(SourceType sourceType) {
|
||||
// Encode SourceType value into split storage flags
|
||||
int sourceTypeId = sourceType.getStorageId();
|
||||
if (sourceTypeId > MAX_SOURCE_VALUE) {
|
||||
throw new RuntimeException("Unsupported SourceType storage ID: " + sourceTypeId);
|
||||
}
|
||||
int sourceTypeLoBits = (sourceTypeId & 0x3) << SYMBOL_SOURCE_LO_BITS_SHIFT; // bits 0-1
|
||||
int sourceTypeHiBit = (sourceTypeId >>> 2) << SYMBOL_SOURCE_HI_BIT_SHIFT; // remaining hi-bit
|
||||
return (byte) (sourceTypeHiBit | sourceTypeLoBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode V4 flags source type
|
||||
* @param flags symbol flags
|
||||
* @return source type
|
||||
*/
|
||||
static SourceType decodeSourceTypeFromFlags(byte flags) {
|
||||
int sourceTypeLoBits = (flags & SYMBOL_SOURCE_LO_BITS) >>> SYMBOL_SOURCE_LO_BITS_SHIFT; // bits 0-1
|
||||
int sourceTypeHiBit = (flags & SYMBOL_SOURCE_HI_BIT) >>> (SYMBOL_SOURCE_HI_BIT_SHIFT - 2); // remaining HI-bit
|
||||
int sourceTypeId = sourceTypeHiBit | sourceTypeLoBits;
|
||||
return SourceType.getSourceType(sourceTypeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a new basic symbol record. Caller is responsible for updating any related
|
||||
* optional record fields and then adding to the table via the
|
||||
|
|
|
@ -97,7 +97,7 @@ class SymbolDatabaseAdapterV4 extends SymbolDatabaseAdapter {
|
|||
// if (nextID == 0) {
|
||||
// nextID++;
|
||||
// }
|
||||
// return createSymbol(nextID, name, address, namespaceID, symbolType, (byte) source.ordinal(),
|
||||
// return createSymbol(nextID, name, address, namespaceID, symbolType, (byte) source.getStorageId(),
|
||||
// isPrimary);
|
||||
// }
|
||||
|
||||
|
@ -119,7 +119,7 @@ class SymbolDatabaseAdapterV4 extends SymbolDatabaseAdapter {
|
|||
rec.setLongValue(SYMBOL_ADDR_COL, addressKey);
|
||||
rec.setLongValue(SYMBOL_PARENT_ID_COL, namespaceID);
|
||||
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
|
||||
rec.setByteValue(SYMBOL_FLAGS_COL, (byte) source.ordinal());
|
||||
rec.setByteValue(SYMBOL_FLAGS_COL, getSourceTypeFlagsBits(source)); // assume non-pinned
|
||||
|
||||
// Sparse columns - these columns don't apply to all symbols.
|
||||
// they default to null unless specifically set. Null values don't consume space.
|
||||
|
|
|
@ -15,28 +15,83 @@
|
|||
*/
|
||||
package ghidra.program.model.symbol;
|
||||
|
||||
public enum SourceType {
|
||||
// WARNING WARNING: do not change the order of these enums as they are stored in the
|
||||
// database by their ordinal.
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public enum SourceType {
|
||||
// WARNING WARNING: the assigned storage IDs are used for persistent serialization.
|
||||
// Any change or re-use must consider data upgrade concerns.
|
||||
|
||||
// The SourceType's defined below are ordered based upon their priority values.
|
||||
// Priority values may be changed.
|
||||
|
||||
/** The object's source indicator for an auto analysis. */
|
||||
ANALYSIS("Analysis", 2),
|
||||
/** The object's source indicator for a user defined. */
|
||||
USER_DEFINED("User Defined", 4),
|
||||
/** The object's source indicator for a default. */
|
||||
DEFAULT("Default", 1),
|
||||
DEFAULT("Default", 1, 2),
|
||||
/** The object's source indicator for an auto analysis. */
|
||||
ANALYSIS("Analysis", 2, 0),
|
||||
/** The object's source indicator for something that was produced with AI assistance. */
|
||||
AI("AI", 2, 4),
|
||||
/** The object's source indicator for an imported. */
|
||||
IMPORTED("Imported", 3);
|
||||
IMPORTED("Imported", 3, 3),
|
||||
/** The object's source indicator for a user defined. */
|
||||
USER_DEFINED("User Defined", 4, 1);
|
||||
|
||||
// SourceType values indexed by storageID (use null for undefined IDs).
|
||||
private static SourceType[] SOURCE_BY_STORAGE_ID =
|
||||
new SourceType[] { ANALYSIS, USER_DEFINED, DEFAULT, IMPORTED, AI };
|
||||
|
||||
private final String displayString;
|
||||
private final int priority; // bigger numbers are higher priorty
|
||||
private final int storageId;
|
||||
private final int priority; // bigger numbers are higher priority
|
||||
|
||||
private SourceType(String displayString, int priority) {
|
||||
/**
|
||||
* {@link SourceType} constructor
|
||||
* @param displayString enum display name
|
||||
* @param priority unique priority among other defined enum values
|
||||
* @param storageId non-negative storage ID for persistent serialization. Once an ID is
|
||||
* assigned it may never be removed without serious consideration to DB upgrade transformation.
|
||||
*/
|
||||
private SourceType(String displayString, int priority, int storageId) {
|
||||
this.displayString = displayString;
|
||||
this.storageId = storageId;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
/** Returns a user-friendly string */
|
||||
/**
|
||||
* Get the SourceType which corresponds to the specified storage ID.
|
||||
* @param storageId storage ID
|
||||
* @return SourceType
|
||||
* @throws NoSuchElementException if specified storage ID is not defined.
|
||||
*/
|
||||
public static SourceType getSourceType(int storageId) {
|
||||
try {
|
||||
SourceType source = SOURCE_BY_STORAGE_ID[storageId];
|
||||
if (source != null) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
// throw error below
|
||||
}
|
||||
throw new NoSuchElementException("SourceType storgae ID not defined: " + storageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return numeric priority relative to other SourceType. Higher numbers are higher priority.}
|
||||
*/
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the storage ID which should be used for persistent serialization}
|
||||
*/
|
||||
public int getStorageId() {
|
||||
return storageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a user-friendly string}
|
||||
*/
|
||||
public String getDisplayString() {
|
||||
return displayString;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue