diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java index 32ad634f22..2479a0a84e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java @@ -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); @@ -311,7 +311,7 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject public DBTraceReference[] getReferences() { return getReferences(TaskMonitor.DUMMY); } - + @SuppressWarnings("hiding") void rawSet(String name, long parentID) { this.name = name; @@ -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 diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java index cdb57199de..9e25bbd199 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java @@ -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 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 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); } diff --git a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm index 1dc739a1da..50904aa6aa 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/Browser_Field_Formatter.htm @@ -448,7 +448,7 @@ Function Indicates the source-type associated with the - function signature (i.e., DEFAULT, ANALYSIS, IMPORTED, USER_DEFINED). + function signature (i.e., DEFAULT, AI_ASSIST, ANALYSIS, IMPORTED, USER_DEFINED). diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/NewSymbolFilter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/NewSymbolFilter.java index 10a72d096a..2cda64dea8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/NewSymbolFilter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/NewSymbolFilter.java @@ -4,9 +4,9 @@ * 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. @@ -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 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 it = applicableFilters.iterator(); - while (it.hasNext()) { - Filter filter = it.next(); + for (Filter filter : applicableFilters) { if (filter.isActive()) { return true; } diff --git a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html index c9475a6a53..59ff502054 100644 --- a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html +++ b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerAnnotations.html @@ -1286,6 +1286,8 @@
  • DEFAULT - for basic or no information
  • +AI - for information that is produced with AI assistance
  • +
  • ANALYSIS - for information derived by an Analyzer
  • IMPORTED - for information imported from an external source
  • diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/SymbolTypeFilter.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/SymbolTypeFilter.java index 8d84929394..eeafda3403 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/SymbolTypeFilter.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/SymbolTypeFilter.java @@ -4,9 +4,9 @@ * 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. @@ -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 { }; 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); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java index e66d387bb8..31b9a991de 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java @@ -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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapter.java index 0457ff2b25..983bad6685 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionAdapter.java @@ -4,9 +4,9 @@ * 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. @@ -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) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java index 9b83a39fba..df0580546f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java @@ -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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/RefListFlagsV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/RefListFlagsV0.java index b6a523ba8b..c5712590f8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/RefListFlagsV0.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/RefListFlagsV0.java @@ -1,13 +1,12 @@ /* ### * 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. * 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. @@ -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() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/MemorySymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/MemorySymbol.java index 84aae130a8..5e1601e091 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/MemorySymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/MemorySymbol.java @@ -169,7 +169,7 @@ public abstract class MemorySymbol extends SymbolDB { newNamespace.getID()); } if (newSource != null) { - setSourceFlagBit(newSource); + setSourceFlagBits(newSource); } updatePinnedFlag(pinned); updateRecord(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java index 5d1c10dbb8..e5a9c53b20 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java @@ -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); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java index b235019df5..b9e831da77 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java @@ -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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV4.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV4.java index 9a00e883c6..82276b74f1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV4.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV4.java @@ -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. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SourceType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SourceType.java index 186039e71b..0e6b4f12f4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SourceType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SourceType.java @@ -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; }