diff --git a/GPL/vsconfig.gradle b/GPL/vsconfig.gradle index 610aa08313..9821653a43 100644 --- a/GPL/vsconfig.gradle +++ b/GPL/vsconfig.gradle @@ -34,7 +34,7 @@ def configureVisualStudio() { println " -> To manually specify the location of vswhere.exe, add \"-PvswherePath=\" to the Gradle command line arguments" return } - def vswhereProcess = "\"${vswherePath}\" -products * -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -format json -utf8".execute() + def vswhereProcess = "\"${vswherePath}\" -products * -sort -prerelease -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -format json -utf8".execute() def vswhereOutput = vswhereProcess.text.trim() def vswhereExit = vswhereProcess.exitValue() if (vswhereExit != 0) { @@ -49,11 +49,27 @@ def configureVisualStudio() { return } def vswhereJson = new groovy.json.JsonSlurper().parseText(vswhereOutput); - if (vswhereJson.isEmpty()) { + def usePrerelease = project.hasProperty("vswherePrerelease") + def i = -1 + println " -> Searching for Visual Studio installations..." + vswhereJson.eachWithIndex { item, index -> + def isPrerelease = item.get("isPrerelease") + def name = item.get("displayName") + (isPrerelease ? " Prerelease" : "") + if (i == -1) { + if (usePrerelease || !isPrerelease) { + i = index + } + } + println " ${index + 1}: ${name}" + + (i == index ? " (selected)" : "") + + (isPrerelease && !usePrerelease ? " (enable with -PvswherePrerelease)" : "") + } + if (i == -1) { println " -> Visual Studio not found!" return } - def vsInstallDir = vswhereJson[0].installationPath + + def vsInstallDir = vswhereJson[i].installationPath println " -> Installation Directory: ${vsInstallDir}" // Use vcvarsall.bat to determine the latest Visual Studio's default SDK and tool versions 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/ghidra_scripts/AutoRenameSimpleLabels.java b/Ghidra/Features/Base/ghidra_scripts/AutoRenameSimpleLabels.java index 376453b6a4..09fd987e5f 100644 --- a/Ghidra/Features/Base/ghidra_scripts/AutoRenameSimpleLabels.java +++ b/Ghidra/Features/Base/ghidra_scripts/AutoRenameSimpleLabels.java @@ -43,8 +43,7 @@ import ghidra.program.model.symbol.*; public class AutoRenameSimpleLabels extends GhidraScript { boolean isDefaultName(Symbol symbol) { - return symbol.getSource() == SourceType.DEFAULT || - symbol.getSource() == SourceType.ANALYSIS; + return symbol.getSource().isLowerOrEqualPriorityThan(SourceType.ANALYSIS); } @Override @@ -61,6 +60,9 @@ public class AutoRenameSimpleLabels extends GhidraScript { //get this instruction's info Symbol s = iter.next(); Address startAddr = s.getAddress(); + if (!startAddr.isLoadedMemoryAddress()) { + continue; + } // read the instruction type and operand Instruction inst = getInstructionAt(startAddr); diff --git a/Ghidra/Features/Base/ghidra_scripts/LabelDataScript.java b/Ghidra/Features/Base/ghidra_scripts/LabelDataScript.java index 3be8fce559..a2bf9b8b8d 100644 --- a/Ghidra/Features/Base/ghidra_scripts/LabelDataScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/LabelDataScript.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. @@ -43,13 +43,12 @@ public class LabelDataScript extends GhidraScript { (!data.getBaseDataType().getName().toLowerCase().contains("string")) && (!data.getBaseDataType().getName().toLowerCase().contains("unicode"))) { Symbol sym = symbolTable.getPrimarySymbol(data.getMinAddress()); - if ((sym != null) && ((sym.getSource() == SourceType.DEFAULT) || - (sym.getSource() == SourceType.ANALYSIS))) { - String newLabel = - data.getDefaultLabelPrefix(null) + "_" + - SymbolUtilities.replaceInvalidChars( - data.getDefaultValueRepresentation(), false) + - "_" + data.getMinAddress().toString(); + if (sym != null && + sym.getSource().isLowerOrEqualPriorityThan(SourceType.ANALYSIS)) { + String newLabel = data.getDefaultLabelPrefix(null) + + "_" + SymbolUtilities + .replaceInvalidChars(data.getDefaultValueRepresentation(), false) + + "_" + data.getMinAddress().toString(); Symbol newSym = symbolTable.createLabel(data.getMinAddress(), newLabel, SourceType.ANALYSIS); println(data.getMinAddress().toString() + " " + newLabel); 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/cmd/function/CreateThunkFunctionCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java index 24eb186393..5d5c5f7d76 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java @@ -563,6 +563,13 @@ public class CreateThunkFunctionCmd extends BackgroundCommand { Listing listing = program.getListing(); Instruction instr = listing.getInstructionAt(entry); + + // if there is no pcode, go to the next instruction + // assume fallthrough (ie. x86 instruction ENDBR64) + // TODO: at some point, might need to do a NOP detection + if (instr != null && instr.getPcode().length == 0) { + instr = listing.getInstructionAfter(entry); + } if (instr == null) { return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java index dc6430d670..48923d0106 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java @@ -44,7 +44,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { private static final int MAX_LOCAL_OFFSET = -(64 * 1024); // max size of local reference space private final static String X86_NAME = "x86"; - + private boolean dontCreateNewVariables = false; private final boolean forceProcessing; @@ -55,7 +55,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { private Program program; private Register stackReg; private int purge = 0; - + private boolean isX86 = false; static String DEFAULT_FUNCTION_COMMENT = " FUNCTION"; @@ -105,7 +105,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { @Override public boolean applyTo(Program p, TaskMonitor monitor) { program = p; - + isX86 = checkForX86(p); int count = 0; @@ -145,8 +145,10 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { } private boolean checkForX86(Program p) { - return program.getLanguage().getProcessor().equals( - Processor.findOrPossiblyCreateProcessor(X86_NAME)) && program.getDefaultPointerSize() <= 32; + return program.getLanguage() + .getProcessor() + .equals(Processor.findOrPossiblyCreateProcessor(X86_NAME)) && + program.getDefaultPointerSize() <= 32; } /** @@ -221,7 +223,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { private boolean isProtectedVariable(Variable var) { return !var.isStackVariable() || !Undefined.isUndefined(var.getDataType()) || - var.getSource() == SourceType.IMPORTED || var.getSource() == SourceType.USER_DEFINED || + var.getSource().isHigherOrEqualPriorityThan(SourceType.IMPORTED) || var.isCompoundVariable(); } @@ -339,9 +341,11 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { return; } } - long extendedOffset = extendOffset(address.getOffset(), stackReg.getBitLength()); - - defineFuncVariable(symEval, func, instr, opIndex, (int) extendedOffset, sortedVariables); + long extendedOffset = + extendOffset(address.getOffset(), stackReg.getBitLength()); + + defineFuncVariable(symEval, func, instr, opIndex, (int) extendedOffset, + sortedVariables); } } @@ -634,8 +638,8 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { // return true; // } - private void defineFuncVariable(SymbolicPropogator symEval, Function func, Instruction instr, int opIndex, int stackOffset, - List sortedVariables) { + private void defineFuncVariable(SymbolicPropogator symEval, Function func, Instruction instr, + int opIndex, int stackOffset, List sortedVariables) { ReferenceManager refMgr = program.getReferenceManager(); int refSize = getRefSize(symEval, instr, opIndex); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java index 70d3dae2a5..59c76223d1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java @@ -224,7 +224,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer { if (symbol.getSymbolType() == SymbolType.FUNCTION) { Function function = (Function) symbol.getObject(); if (!function.isThunk() && - function.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) { + function.getSignatureSource().isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { return true; } } @@ -297,8 +297,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer { return; } String errorString = demangled.getErrorMessage(); - logApplyErrorMessage(log, demangled, mangledContext.getAddress(), null, - errorString); + logApplyErrorMessage(log, demangled, mangledContext.getAddress(), null, errorString); } catch (Exception e) { logApplyErrorMessage(log, demangled, mangledContext.getAddress(), e, null); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java index d3e345d530..b06d87ed6c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.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. @@ -427,7 +427,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter } SourceType mostTrusted = getMostTrustedParameterSource(func); - if (SourceType.ANALYSIS.isLowerPriorityThan(mostTrusted)) { + if (mostTrusted.isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { return; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java index 7d3ca7f001..2d31c9333e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java @@ -225,6 +225,8 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer { continue; } + // NOTE: DWARF may have applied function signature with IMPORTED source type but + // this analyzer must apply more details Function func = markupSession.createFunctionIfMissing(funcname, funcns, funcAddr); if (func == null || func.getSignatureSource().isHigherPriorityThan(SourceType.IMPORTED)) { @@ -503,8 +505,8 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer { Address mbStart = max.subtract(offset_from_eom + len - 1); MemoryBlock newMB = MemoryBlockUtils.createUninitializedBlock(program, false, "ARTIFICAL_GOLANG_CONTEXT", - mbStart, len, "Artifical memory block created to hold Go context data types", - null, true, true, false, null); + mbStart, len, "Artifical memory block created to hold Go context data types", null, + true, true, false, null); newMB.setArtificial(true); return newMB.getStart(); } @@ -1034,7 +1036,6 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer { Register register, java.util.function.Function returnTypeMapper) { } - private GoRttiMapper goBinary; private Program program; private MarkupSession markupSession; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/PefAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/PefAnalyzer.java index 82862fc757..125e13fd2a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/PefAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/PefAnalyzer.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. @@ -109,8 +109,9 @@ public class PefAnalyzer extends AbstractAnalyzer { } Function function = functions.next(); try { - program.getProgramContext().setRegisterValue(function.getEntryPoint(), - function.getEntryPoint(), regVal); + program.getProgramContext() + .setRegisterValue(function.getEntryPoint(), function.getEntryPoint(), + regVal); } catch (ContextChangeException e) { // should never happen when changing r2 register @@ -149,11 +150,8 @@ public class PefAnalyzer extends AbstractAnalyzer { return; } Function function = listing.getFunctionContaining(instruction.getMinAddress()); - if (function == null) { - return; - } - if (function.getSymbol().getSource() == SourceType.IMPORTED || - function.getSymbol().getSource() == SourceType.USER_DEFINED) { + if (function == null || + function.getSymbol().getSource().isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { return; } Symbol symbol = symbolTable.getPrimarySymbol(symbolAddress); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearFlowAndRepairCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearFlowAndRepairCmd.java index 8b0a1d3a29..eedb4721a8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearFlowAndRepairCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clear/ClearFlowAndRepairCmd.java @@ -717,11 +717,9 @@ public class ClearFlowAndRepairCmd extends BackgroundCommand { continue; // do not include data } Symbol s = symbolTable.getPrimarySymbol(blockAddr); - if (s != null && s.getSymbolType() == SymbolType.FUNCTION) { - SourceType source = s.getSource(); - if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) { - continue; // keep imported or user-defined function - } + if (s != null && s.getSymbolType() == SymbolType.FUNCTION && + s.getSource().isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { + continue; // TODO: GP-5872 Clearing thunks explicitly created by loader or pattern // generally have default SourceType and may not have references // to them. We need to prevent these thunks from getting cleared. 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/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java index b0826593fb..74827196a1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.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. @@ -378,8 +378,7 @@ public class DemangledFunction extends DemangledObject { if (f != null && f.getSymbol().getSource() == SourceType.USER_DEFINED) { return true; } - if (f == null || f.getSignatureSource() == SourceType.DEFAULT || - f.getSignatureSource() == SourceType.ANALYSIS) { + if (f == null || f.getSignatureSource().isLowerOrEqualPriorityThan(SourceType.ANALYSIS)) { return false; } return super.isAlreadyDemangled(program, address); @@ -809,7 +808,7 @@ public class DemangledFunction extends DemangledObject { continue; } // if the parameters source is higher than - if (parameter.getSource().isHigherPriorityThan(SourceType.ANALYSIS)) { + if (parameter.getSource().isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { return true; } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/ExpandCollapseDataActionsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/ExpandCollapseDataActionsTest.java index 92827c1fe8..41d4d20b3b 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/ExpandCollapseDataActionsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/ExpandCollapseDataActionsTest.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. @@ -15,13 +15,13 @@ */ package ghidra.app.plugin.core.codebrowser; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import org.junit.*; import docking.ActionContext; import docking.action.DockingActionIf; +import docking.action.MenuData; import ghidra.app.context.ProgramLocationActionContext; import ghidra.app.services.ProgramManager; import ghidra.app.util.viewer.listingpanel.ListingModel; @@ -217,13 +217,18 @@ public class ExpandCollapseDataActionsTest extends AbstractGhidraHeadedIntegrati public void testExpandAllInSelectionEnablement() { // Expand All In Selection is enabled whenever there is a selection ProgramSelection selection = new ProgramSelection(addr(0), addr(10)); - assertTrue(!expandAll.isEnabledForContext(getContext(addr(0x0), null))); - assertEquals("Expand All Data", expandAll.getPopupMenuData().getMenuPath()[0]); + ActionContext context = getContext(addr(0x0), null); + assertTrue(!expandAll.isEnabledForContext(context)); + MenuData menuData = expandAll.getPopupMenuData(); + String[] menuPath = menuData.getMenuPath(); + assertArrayEquals(menuPath, new String[] { "Data", "Expand All Data" }); - assertTrue( - expandAll.isEnabledForContext(getContextWithSelection(addr(STRUCT_1), selection))); + context = getContextWithSelection(addr(STRUCT_1), selection); + assertTrue(expandAll.isEnabledForContext(context)); // When there is a selection, the pop-up menu changes - assertEquals("Expand All Data In Selection", expandAll.getPopupMenuData().getMenuPath()[0]); + menuData = expandAll.getPopupMenuData(); + menuPath = menuData.getMenuPath(); + assertArrayEquals(menuPath, new String[] { "Data", "Expand All Data In Selection" }); } @Test diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingsTest.java index 409b94276d..93c89112ba 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/KeyBindingsTest.java @@ -224,10 +224,6 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest { assertKeyFieldText(ks); apply(); assertEquals(ks, getKeyStroke(action1)); - - // verify the additional binding for 'Alt Graph' - action = (Action) TestUtils.invokeInstanceMethod("getActionForKeyStroke", dwm, keyStroke); - assertNotNull(action); } @Test diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java index c02e18321e..a19668ff81 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java @@ -17,6 +17,7 @@ package ghidra.app.analyzers; import java.math.BigInteger; import java.util.*; +import java.util.regex.Matcher; import generic.jar.ResourceFile; import ghidra.app.cmd.function.CreateFunctionCmd; @@ -209,7 +210,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa private String label = null; private boolean isThunk = false; // true if this function should be turned into a thunk private boolean noreturn = false; // true to set function non-returning - private String sectionName = null; // required section name + private java.util.regex.Pattern sectionNamePattern = null; // required section name as a regex pattern boolean validFunction = false; // must be defined at a function private boolean contiguous = true; // require validcode instructions be contiguous @@ -227,9 +228,13 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa protected boolean checkPreRequisites(Program program, Address addr) { // check required section name - if (sectionName != null) { + if (sectionNamePattern != null) { MemoryBlock block = program.getMemory().getBlock(addr); - if (block == null || !block.getName().matches(sectionName)) { + if (block == null) { + return false; + } + Matcher m = sectionNamePattern.matcher(block.getName()); + if (!m.matches()) { return false; } } @@ -651,7 +656,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa break; case "section": - sectionName = attrValue; + sectionNamePattern = java.util.regex.Pattern.compile(attrValue); break; case "noreturn": 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/Decompiler/src/main/java/ghidra/app/cmd/function/DecompilerParameterIdCmd.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/cmd/function/DecompilerParameterIdCmd.java index f418edefc7..8c7119cbd0 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/cmd/function/DecompilerParameterIdCmd.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/cmd/function/DecompilerParameterIdCmd.java @@ -150,12 +150,12 @@ public class DecompilerParameterIdCmd extends BackgroundCommand { // since decompile could fail and leave the source types changed. Parameter retParam = func.getReturn(); if (retParam != null) { - if (!retParam.getSource().isHigherPriorityThan(sourceTypeClearLevel)) { + if (retParam.getSource().isLowerOrEqualPriorityThan(sourceTypeClearLevel)) { func.setReturn(retParam.getDataType(), retParam.getVariableStorage(), SourceType.DEFAULT); } } - if (!func.getSignatureSource().isHigherPriorityThan(sourceTypeClearLevel)) { + if (func.getSignatureSource().isLowerOrEqualPriorityThan(sourceTypeClearLevel)) { func.setSignatureSource(SourceType.DEFAULT); } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ForceUnionAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ForceUnionAction.java index ff6e359822..587097562c 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ForceUnionAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ForceUnionAction.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. @@ -128,28 +128,28 @@ public class ForceUnionAction extends AbstractDecompilerAction { int opcode = accessOp.getOpcode(); if (opcode == PcodeOp.PTRSUB) { parentDt = typeIsUnionRelated(accessOp.getInput(0)); - if (parentDt == null) { - accessOp = null; - return; - } - accessVn = accessOp.getInput(0); - accessSlot = 0; - if (accessOp.getInput(1).getOffset() == 0) { // Artificial op - do { - Varnode tmpVn = accessOp.getOutput(); - PcodeOp tmpOp = tmpVn.getLoneDescend(); - if (tmpOp == null) { - break; + if (parentDt != null) { + accessVn = accessOp.getInput(0); + accessSlot = 0; + if (accessOp.getInput(1).getOffset() == 0) { // Artificial op + do { + Varnode tmpVn = accessOp.getOutput(); + PcodeOp tmpOp = tmpVn.getLoneDescend(); + if (tmpOp == null) { + break; + } + accessOp = tmpOp; + accessVn = tmpVn; + accessSlot = accessOp.getSlot(accessVn); } - accessOp = tmpOp; - accessVn = tmpVn; - accessSlot = accessOp.getSlot(accessVn); + while (accessOp.getOpcode() == PcodeOp.PTRSUB && + accessOp.getInput(1).getOffset() == 0); } - while (accessOp.getOpcode() == PcodeOp.PTRSUB && - accessOp.getInput(1).getOffset() == 0); + return; } } else { + parentDt = null; for (accessSlot = 0; accessSlot < accessOp.getNumInputs(); ++accessSlot) { accessVn = accessOp.getInput(accessSlot); parentDt = typeIsUnionRelated(accessVn); @@ -157,22 +157,26 @@ public class ForceUnionAction extends AbstractDecompilerAction { break; } } - if (accessSlot >= accessOp.getNumInputs()) { - accessSlot = -1; - accessVn = accessOp.getOutput(); - parentDt = typeIsUnionRelated(accessVn); - if (parentDt == null) { - accessOp = null; - return; // Give up, could not find type associated with field + if (parentDt != null) { + if (opcode == PcodeOp.SUBPIECE && accessSlot == 0 && + !(parentDt instanceof Pointer)) { + // SUBPIECE acts directly as resolution operator + // Choose field based on output varnode, even though it isn't the union data-type + accessSlot = -1; + accessVn = accessOp.getOutput(); } - } - if (opcode == PcodeOp.SUBPIECE && accessSlot == 0 && !(parentDt instanceof Pointer)) { - // SUBPIECE acts directly as resolution operator - // Choose field based on output varnode, even though it isn't the union data-type - accessSlot = -1; - accessVn = accessOp.getOutput(); + return; } } + accessSlot = -1; + accessVn = accessOp.getOutput(); + if (accessVn != null) { + parentDt = typeIsUnionRelated(accessVn); + if (parentDt != null) { + return; + } + } + accessOp = null; // Give up, could not find type associated with field } /** diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java index 895e7f0b23..158125d867 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.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. @@ -36,7 +36,7 @@ import ghidra.util.exception.InvalidInputException; public class OverridePrototypeAction extends AbstractDecompilerAction { public OverridePrototypeAction() { - super("Override Signature"); + super("Override Signature"); setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ActionOverrideSignature")); setPopupMenuData(new MenuData(new String[] { "Override Signature" }, "Decompile")); } @@ -174,11 +174,9 @@ public class OverridePrototypeAction extends AbstractDecompilerAction { // for the initial signature. HighFunction does not make it easy to grab // existing override prototype - if (calledfunc != null) { - SourceType signatureSource = calledfunc.getSignatureSource(); - if (signatureSource == SourceType.DEFAULT || signatureSource == SourceType.ANALYSIS) { - calledfunc = null; // ignore - } + if (calledfunc != null && + calledfunc.getSignatureSource().isLowerOrEqualPriorityThan(SourceType.ANALYSIS)) { + calledfunc = null; // ignore } StringBuffer buf = new StringBuffer(); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompiler/validator/DecompilerParameterIDValidator.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompiler/validator/DecompilerParameterIDValidator.java index 2726f45207..98e44bfed8 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompiler/validator/DecompilerParameterIDValidator.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompiler/validator/DecompilerParameterIDValidator.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. @@ -63,6 +63,8 @@ public class DecompilerParameterIDValidator extends PostAnalysisValidator { if (inst != null) { final SourceType signatureSource = func.getSignatureSource(); + // TODO: There is a misconception that ANALYSIS source type can be used to + // determine if Param ID Analyzer has been used. This should be re-examined. if (signatureSource == SourceType.ANALYSIS) { ++numFuncsWithParameterID; } diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/cmd/ApplyFidEntriesCommand.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/cmd/ApplyFidEntriesCommand.java index bab3a95d2d..645f37be2d 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/cmd/ApplyFidEntriesCommand.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/cmd/ApplyFidEntriesCommand.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. @@ -273,9 +273,8 @@ public class ApplyFidEntriesCommand extends BackgroundCommand { SymbolTable symbolTable = program.getSymbolTable(); SymbolIterator symbols = symbolTable.getSymbolsAsIterator(function.getEntryPoint()); for (Symbol symbol : symbols) { - SourceType sourceType = symbol.getSource(); - if (sourceType == SourceType.USER_DEFINED || sourceType == SourceType.IMPORTED) { - return true; + if (symbol.getSource().isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { + return true; // symbol has trusted source } } return false; diff --git a/Ghidra/Features/Jython/src/main/java/ghidra/jython/GhidraJythonInterpreter.java b/Ghidra/Features/Jython/src/main/java/ghidra/jython/GhidraJythonInterpreter.java index 8a8428b315..c0f8254a72 100644 --- a/Ghidra/Features/Jython/src/main/java/ghidra/jython/GhidraJythonInterpreter.java +++ b/Ghidra/Features/Jython/src/main/java/ghidra/jython/GhidraJythonInterpreter.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. @@ -50,8 +50,8 @@ public class GhidraJythonInterpreter extends InteractiveInterpreter { private PyModule introspectModule; private PyModule builtinModule; private PyObject interrupt; - private boolean scriptMethodsInjected; private boolean cleanedUp; + private Stack localStack = new Stack<>(); /** * Gets a new GhidraPythonInterpreter instance. @@ -126,6 +126,7 @@ public class GhidraJythonInterpreter extends InteractiveInterpreter { /** * Initializes/resets the python path to include all known Ghidra script paths. */ + @SuppressWarnings("deprecation") private void initializePythonPath() { // Restore the python path back to default. @@ -359,24 +360,20 @@ public class GhidraJythonInterpreter extends InteractiveInterpreter { } } - // Add public methods (only once). Ignore inner classes. + // Add public methods. Ignore inner classes. // // NOTE: We currently do not have a way to safely add protected methods. Disabling // python.security.respectJavaAccessibility and adding in protected methods in the below // loop caused an InaccessibleObjectException for some users (relating to core Java // modules, not the GhidraScript class hierarchy). - if (!scriptMethodsInjected) { - for (Method method : scriptClass.getDeclaredMethods()) { - if (!method.getName().contains("$") && - Modifier.isPublic(method.getModifiers())) { - method.setAccessible(true); - setMethod(script, method); - } + for (Method method : scriptClass.getDeclaredMethods()) { + if (!method.getName().contains("$") && + Modifier.isPublic(method.getModifiers())) { + method.setAccessible(true); + setMethod(script, method); } } } - - scriptMethodsInjected = true; } /** @@ -395,6 +392,29 @@ public class GhidraJythonInterpreter extends InteractiveInterpreter { return false; } + /** + * Saves the interpreter's locals to a stack. These locals can be restored with the + * {@link #restoreLocals()} method. + */ + public void saveLocals() { + localStack.push(getLocals()); + } + + /** + * Clears the interpreter's locals + */ + public void clearLocals() { + setLocals(new PyStringMap()); + } + + /** + * Restores the locals that were last saved with the {@link #saveLocals()} method, and removes + * them from the stack. + */ + public void restoreLocals() { + setLocals(localStack.pop()); + } + /** * Sets a bound (callback/function pointer) method as a local variable in the interpreter. * @@ -427,6 +447,8 @@ public class GhidraJythonInterpreter extends InteractiveInterpreter { Msg.error(this, "Method " + methodName + " of " + obj + " attempting to shadow method " + pyMethod.__func__ + " of " + pyMethod.__self__); + set(methodName, new PyMethod(new PyReflectedFunction(method), Py.java2py(obj), + Py.java2py(obj.getClass()))); return false; } if (!(pyMethod.__func__ instanceof PyReflectedFunction)) { diff --git a/Ghidra/Features/Jython/src/main/java/ghidra/jython/JythonScript.java b/Ghidra/Features/Jython/src/main/java/ghidra/jython/JythonScript.java index b3509c1bef..7af8522874 100644 --- a/Ghidra/Features/Jython/src/main/java/ghidra/jython/JythonScript.java +++ b/Ghidra/Features/Jython/src/main/java/ghidra/jython/JythonScript.java @@ -71,13 +71,20 @@ public class JythonScript extends GhidraScript { updateStateFromVariables(); } - if (ghidraScript instanceof JythonScript) { - ghidraScript.set(scriptState); - JythonScript jythonScript = (JythonScript) ghidraScript; - interpreter.execFile(jythonScript.getSourceFile(), jythonScript); + try { + interpreter.saveLocals(); + interpreter.clearLocals(); + if (ghidraScript instanceof JythonScript) { + ghidraScript.set(scriptState); + JythonScript jythonScript = (JythonScript) ghidraScript; + interpreter.execFile(jythonScript.getSourceFile(), jythonScript); + } + else { + ghidraScript.execute(scriptState, getControls()); + } } - else { - ghidraScript.execute(scriptState, getControls()); + finally { + interpreter.restoreLocals(); } if (scriptState == state) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java index 0fe546c3b4..05b56bb98a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java @@ -2341,25 +2341,6 @@ public class DefaultPdbApplicator implements PdbApplicator { } } - //============================================================================================== - boolean shouldForcePrimarySymbol(Address address, boolean forceIfMangled) { - Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address); - if (primarySymbol != null) { - - if (primarySymbol.getName().startsWith("?") && forceIfMangled && - applicatorOptions.allowDemotePrimaryMangledSymbols()) { - return true; - } - - SourceType primarySymbolSource = primarySymbol.getSource(); - - if (!SourceType.ANALYSIS.isHigherPriorityThan(primarySymbolSource)) { - return true; - } - } - return false; - } - //============================================================================================== boolean addToPlateUnique(Address address, String comment) { if (StringUtils.isBlank(comment)) { @@ -2411,8 +2392,8 @@ public class DefaultPdbApplicator implements PdbApplicator { Function existingFunction = program.getListing().getFunctionAt(address); if (existingFunction != null) { // Maybe I should care if there is a data type there too. - if (existingFunction.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) { - // Existing is USER or IMPORTED + if (existingFunction.getSignatureSource() + .isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { return doCreateSymbol(address, symbolPath, false, plateAddition); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 7538dee4b0..3cf2e60d36 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -79,8 +79,7 @@ public class FunctionSymbolApplier extends AbstractBlockContextApplier return applicator.getAddress(symbol); } - private void processSymbol(MsSymbolIterator iter) - throws CancelledException, PdbException { + private void processSymbol(MsSymbolIterator iter) throws CancelledException, PdbException { Address address = applicator.getAddress(symbol); String name = symbol.getName(); @@ -186,8 +185,7 @@ public class FunctionSymbolApplier extends AbstractBlockContextApplier } // Remaining are non-thunks - if (function.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) { - // return if IMPORTED or USER_DEFINED + if (function.getSignatureSource().isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { return false; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ManagedProcedureSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ManagedProcedureSymbolApplier.java index 3ae8d81033..2a2db4658d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ManagedProcedureSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ManagedProcedureSymbolApplier.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. @@ -86,8 +86,7 @@ public class ManagedProcedureSymbolApplier extends AbstractBlockContextApplier // TODO. Investigate more. This is not working for at least one CLI dll in that we are // not getting correct addresses. There is no omap and the one section is unnamed. - private void processSymbol(MsSymbolIterator iter) - throws CancelledException, PdbException { + private void processSymbol(MsSymbolIterator iter) throws CancelledException, PdbException { Address address = applicator.getAddress(symbol); String name = symbol.getName(); @@ -124,8 +123,7 @@ public class ManagedProcedureSymbolApplier extends AbstractBlockContextApplier } @Override - public void deferredApply(MsSymbolIterator iter) - throws PdbException, CancelledException { + public void deferredApply(MsSymbolIterator iter) throws PdbException, CancelledException { // Pealing the symbol off again, as the iterator is coming in fresh, and we need the symbol getValidatedSymbol(iter, true); @@ -260,9 +258,8 @@ public class ManagedProcedureSymbolApplier extends AbstractBlockContextApplier return; // silently return. } // Currently just placing a comment. - String comment = - context.getIndent(symbolBlockNestingLevel + 1) + "static local (stored at " + - address + ") " + dataType.getName() + " " + name; + String comment = context.getIndent(symbolBlockNestingLevel + 1) + + "static local (stored at " + address + ") " + dataType.getName() + " " + name; context.getComments().addPreComment(currentBlockAddress, comment); } @@ -300,8 +297,7 @@ public class ManagedProcedureSymbolApplier extends AbstractBlockContextApplier private boolean setFunctionDefinition(Function function, Address address, AbstractManagedProcedureMsSymbol symbol) throws CancelledException, PdbException { - if (function.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) { - // return if IMPORTED or USER_DEFINED + if (function.getSignatureSource().isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { return false; } diff --git a/Ghidra/Features/PyGhidra/src/main/py/src/pyghidra/launcher.py b/Ghidra/Features/PyGhidra/src/main/py/src/pyghidra/launcher.py index fd5bc6ce8d..385b63bfbd 100644 --- a/Ghidra/Features/PyGhidra/src/main/py/src/pyghidra/launcher.py +++ b/Ghidra/Features/PyGhidra/src/main/py/src/pyghidra/launcher.py @@ -658,6 +658,7 @@ class _PyGhidraStdOut: def __init__(self, stream): self._stream = stream + self.is_error = stream == sys.stderr def _get_current_script(self) -> "PyGhidraScript": for entry in inspect.stack(): @@ -668,7 +669,7 @@ class _PyGhidraStdOut: def flush(self): script = self._get_current_script() if script is not None: - writer = script._script.writer + writer = script._script.errorWriter if self.is_error else script._script.writer if writer is not None: writer.flush() return @@ -678,7 +679,7 @@ class _PyGhidraStdOut: def write(self, s: str) -> int: script = self._get_current_script() if script is not None: - writer = script._script.writer + writer = script._script.errorWriter if self.is_error else script._script.writer if writer is not None: writer.write(s) return len(s) diff --git a/Ghidra/Features/PyGhidra/support/pyghidra_launcher.py b/Ghidra/Features/PyGhidra/support/pyghidra_launcher.py index 8f1c302020..acb9572601 100644 --- a/Ghidra/Features/PyGhidra/support/pyghidra_launcher.py +++ b/Ghidra/Features/PyGhidra/support/pyghidra_launcher.py @@ -279,11 +279,11 @@ def main() -> None: # Launch PyGhidra save_python_cmd(install_dir, python_cmd, args.dev) - py_args: List[str] = python_cmd + ['-m', 'pyghidra.ghidra_launch', '--install-dir', str(install_dir)] + py_args: List[str] = python_cmd + ['-m'] if args.headless: - py_args += ['ghidra.app.util.headless.AnalyzeHeadless'] + py_args += ['pyghidra.ghidra_launch', '--install-dir', str(install_dir), 'ghidra.app.util.headless.AnalyzeHeadless'] else: - py_args += ['-g', 'ghidra.GhidraRun'] + py_args += ['pyghidra', '-g', '--install-dir', str(install_dir)] if args.console: subprocess.call(py_args + remaining) else: diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/correlator/program/SimilarSymbolNameProgramCorrelator.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/correlator/program/SimilarSymbolNameProgramCorrelator.java index ffda750fff..48922bdac3 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/correlator/program/SimilarSymbolNameProgramCorrelator.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/correlator/program/SimilarSymbolNameProgramCorrelator.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. @@ -106,8 +106,7 @@ public class SimilarSymbolNameProgramCorrelator extends VTAbstractProgramCorrela if (!addressSet.contains(symbol.getAddress())) { continue; } - if (symbol.getSource() == SourceType.DEFAULT || - symbol.getSource() == SourceType.ANALYSIS) { + if (symbol.getSource().isLowerOrEqualPriorityThan(SourceType.ANALYSIS)) { continue; } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/stringable/FunctionSignatureStringable.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/stringable/FunctionSignatureStringable.java index 4f0ba0b416..4453fe85a3 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/stringable/FunctionSignatureStringable.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/stringable/FunctionSignatureStringable.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. @@ -979,38 +979,31 @@ public class FunctionSignatureStringable extends Stringable { private boolean isFirstHigherPriorityWhenUserPriority(SourceType first, SourceType second, boolean replaceSamePriorityNames) { - if (first == second && first != SourceType.DEFAULT) { + if (first == SourceType.DEFAULT) { + return false; + } + if (first == second) { return replaceSamePriorityNames; } - if (first == SourceType.USER_DEFINED) { - return (second == SourceType.IMPORTED || second == SourceType.ANALYSIS || - second == SourceType.DEFAULT); - } - if (first == SourceType.IMPORTED) { - return (second == SourceType.ANALYSIS || second == SourceType.DEFAULT); - } - if (first == SourceType.ANALYSIS) { - return (second == SourceType.DEFAULT); - } - return false; + return first.isHigherPriorityThan(second); } private boolean isFirstHigherPriorityWhenImportedPriority(SourceType first, SourceType second, boolean replaceSamePriorityNames) { - if (first == second && first != SourceType.DEFAULT) { + if (first == SourceType.DEFAULT) { + return false; + } + if (first == second) { return replaceSamePriorityNames; } + // Force IMPORTED to have highest priority if (first == SourceType.IMPORTED) { - return (second == SourceType.USER_DEFINED || second == SourceType.ANALYSIS || - second == SourceType.DEFAULT); + return true; } - if (first == SourceType.USER_DEFINED) { - return (second == SourceType.ANALYSIS || second == SourceType.DEFAULT); + else if (second == SourceType.IMPORTED) { + return false; } - if (first == SourceType.ANALYSIS) { - return (second == SourceType.DEFAULT); - } - return false; + return first.isHigherPriorityThan(second); } private void replaceParameterComments(Function toFunction, CommentChoices commentChoice) { 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 44421edeca..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 @@ -585,12 +585,9 @@ public class FunctionDB extends DatabaseObject implements Function { if (Undefined.isUndefined(variableDataType)) { return; } - SourceType type = SourceType.ANALYSIS; - if (variableSourceType != type && variableSourceType.isHigherPriorityThan(type)) { - type = variableSourceType; - } - if (type.isHigherPriorityThan(getStoredSignatureSource())) { - setSignatureSource(type); + // TODO: It seems that the lowest parameter priority should win out (see GP-6013) + if (variableSourceType.isHigherPriorityThan(getStoredSignatureSource())) { + setSignatureSource(variableSourceType); } } @@ -604,14 +601,14 @@ public class FunctionDB extends DatabaseObject implements Function { boolean isReturnUndefined = Undefined.isUndefined(returnType); SourceType type = isReturnUndefined ? SourceType.DEFAULT : SourceType.ANALYSIS; + // TODO: It seems that the lowest parameter priority should win out (see GP-6013) Parameter[] parameters = getParameters(); for (Parameter parameter : parameters) { if (Undefined.isUndefined(parameter.getDataType())) { continue; } SourceType paramSourceType = parameter.getSource(); - if (paramSourceType != SourceType.ANALYSIS && - paramSourceType.isHigherPriorityThan(SourceType.ANALYSIS)) { + if (paramSourceType.isHigherOrEqualPriorityThan(SourceType.IMPORTED)) { type = paramSourceType; } else { @@ -1458,7 +1455,7 @@ public class FunctionDB extends DatabaseObject implements Function { symbolMap.put(s, paramDb); } - if (source.isHigherPriorityThan(getStoredSignatureSource())) { + if (source != getStoredSignatureSource()) { setSignatureSource(source); } @@ -2448,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 a6f1cce566..c22b12603d 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 @@ -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. @@ -15,37 +15,98 @@ */ 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; + +import ghidra.program.model.listing.Program; + +/** + * {@link SourceType} provides a prioritized indication as to the general source of a specific + * markup made to a {@link Program}. The priority of each defined source type may be used to + * restrict impact or protect the related markup. Source types include: {@link #USER_DEFINED}, + * which is higher priority than {@link #IMPORTED}, which is higher priority than {@link #ANALYSIS}, + * which is higher priority than {@link #DEFAULT}. The {@link #AI} source type is primarliy + * intended to allow AI generated markup to be identified and currently has the same priority + * as {@link #ANALYSIS}. + */ +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 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; } /** - * Determines if this source type is a higher priority than the one being + * Determine if this source type has a higher priority than the one being * passed to this method as a parameter. - * USER_DEFINED objects are higher priority than IMPORTED objects which are higher - * priority than ANALYSIS objects which are higher priority than DEFAULT objects. * @param source the source type whose priority is to be compared with this one's. * @return true if this source type is a higher priority. * false if this source type is the same priority or lower priority. @@ -55,10 +116,19 @@ public enum SourceType { } /** - * Determines if this source type is a lower priority than the one being + * Determine if this source type has the same or higher priority than the one being + * passed to this method as a parameter. + * @param source the source type whose priority is to be compared with this one's. + * @return true if this source type is a higher priority. + * false if this source type is the same priority or lower priority. + */ + public boolean isHigherOrEqualPriorityThan(SourceType source) { + return this.priority >= source.priority; + } + + /** + * Determine if this source type has a lower priority than the one being * passed to this method as a parameter. - * DEFAULT objects are lower priority than ANALYSIS objects which are lower - * priority than IMPORTED objects which are lower priority than USER_DEFINED objects. * @param source the source type whose priority is to be compared with this one's. * @return true if this source type is a lower priority. * false if this source type is the same priority or higher priority. @@ -66,4 +136,15 @@ public enum SourceType { public boolean isLowerPriorityThan(SourceType source) { return this.priority < source.priority; } + + /** + * Determine if this source type has the same or lower priority than the one being + * passed to this method as a parameter. + * @param source the source type whose priority is to be compared with this one's. + * @return true if this source type is a lower priority. + * false if this source type is the same priority or higher priority. + */ + public boolean isLowerOrEqualPriorityThan(SourceType source) { + return this.priority <= source.priority; + } } diff --git a/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraApplicationLayout.java b/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraApplicationLayout.java index 802cc4b186..e0a9336ad3 100644 --- a/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraApplicationLayout.java +++ b/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraApplicationLayout.java @@ -240,10 +240,11 @@ public class GhidraApplicationLayout extends ApplicationLayout { dirs.add(new ResourceFile(new File(userSettingsDir, "Extensions"))); if (SystemUtilities.isInDevelopmentMode()) { - ResourceFile rootDir = getApplicationRootDirs().iterator().next(); - File temp = new File(rootDir.getFile(false), "Extensions"); - if (temp.exists()) { - dirs.add(new ResourceFile(temp)); // ghidra/Ghidra/Extensions + for (ResourceFile rootDir : getApplicationRootDirs()) { + File temp = new File(rootDir.getFile(false), "Extensions"); + if (temp.exists()) { + dirs.add(new ResourceFile(temp)); // i.e., ghidra/Ghidra/Extensions + } } } else { diff --git a/Ghidra/Processors/AARCH64/certification.manifest b/Ghidra/Processors/AARCH64/certification.manifest index 0ccc0b2789..d634991026 100644 --- a/Ghidra/Processors/AARCH64/certification.manifest +++ b/Ghidra/Processors/AARCH64/certification.manifest @@ -11,6 +11,7 @@ data/languages/AARCH64.slaspec||GHIDRA||||END| data/languages/AARCH64BE.slaspec||GHIDRA||||END| data/languages/AARCH64_AMXext.sinc||GHIDRA||||END| data/languages/AARCH64_AppleSilicon.slaspec||GHIDRA||||END| +data/languages/AARCH64_apple.cspec||GHIDRA||||END| data/languages/AARCH64_base_PACoptions.sinc||GHIDRA||||END| data/languages/AARCH64_golang.cspec||GHIDRA||||END| data/languages/AARCH64_golang.register.info||GHIDRA||||END| diff --git a/Ghidra/Processors/AARCH64/data/languages/AARCH64_apple.cspec b/Ghidra/Processors/AARCH64/data/languages/AARCH64_apple.cspec new file mode 100644 index 0000000000..2cc05f2b40 --- /dev/null +++ b/Ghidra/Processors/AARCH64/data/languages/AARCH64_apple.cspec @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/AARCH64/data/languages/AppleSilicon.ldefs b/Ghidra/Processors/AARCH64/data/languages/AppleSilicon.ldefs index 51fb914d96..438a3f92a5 100644 --- a/Ghidra/Processors/AARCH64/data/languages/AppleSilicon.ldefs +++ b/Ghidra/Processors/AARCH64/data/languages/AppleSilicon.ldefs @@ -10,7 +10,7 @@ manualindexfile="../manuals/AARCH64.idx" id="AARCH64:LE:64:AppleSilicon"> AppleSilicon ARM v8.5-A LE instructions, LE data, AMX extensions - + diff --git a/Ghidra/Processors/x86/data/languages/x86-64-win.cspec b/Ghidra/Processors/x86/data/languages/x86-64-win.cspec index 846134c13f..5310d4e1af 100644 --- a/Ghidra/Processors/x86/data/languages/x86-64-win.cspec +++ b/Ghidra/Processors/x86/data/languages/x86-64-win.cspec @@ -233,4 +233,13 @@ ]]> + + + + + + + diff --git a/Ghidra/Processors/x86/data/languages/x86win.cspec b/Ghidra/Processors/x86/data/languages/x86win.cspec index d759822606..19c6a28786 100644 --- a/Ghidra/Processors/x86/data/languages/x86win.cspec +++ b/Ghidra/Processors/x86/data/languages/x86win.cspec @@ -386,4 +386,13 @@ ]]> + + + + + + + diff --git a/Ghidra/Processors/x86/data/patterns/x86-64gcc_patterns.xml b/Ghidra/Processors/x86/data/patterns/x86-64gcc_patterns.xml index 2daa852e44..9c70076c5a 100644 --- a/Ghidra/Processors/x86/data/patterns/x86-64gcc_patterns.xml +++ b/Ghidra/Processors/x86/data/patterns/x86-64gcc_patterns.xml @@ -48,11 +48,70 @@ 0x41564155 0x41554154 0x41 010101.. 0100100. 0x89 11...... 0x55 - 0x41 010101.. 0x41 010101.. 0100100. 0x89 11...... + + + + 0xf3 0x0f 0x1e 0xfa 0x48 0x89 0x5c 0x24 11...000 0x48 0x89 0x6c 0x24 11...000 + 0xf3 0x0f 0x1e 0xfa 0x48 0x89 0x5c 0x24 11...000 0x4c 0x89 0x64 0x24 111..000 + 0xf3 0x0f 0x1e 0xfa 0x48 0x89 0x6c 0x24 11...000 0x4c 0x89 0x64 0x24 111..000 + 0xf3 0x0f 0x1e 0xfa 0x5589e5 + 0xf3 0x0f 0x1e 0xfa 0x554889e5 + 0xf3 0x0f 0x1e 0xfa 0x534889fb + 0xf3 0x0f 0x1e 0xfa 0x554889fd + 0xf3 0x0f 0x1e 0xfa 0x534889fb + 0xf3 0x0f 0x1e 0xfa 0x53 0x48 0x83 0xec 0....000 + 0xf3 0x0f 0x1e 0xfa 0x53 0x48 0x81 0xec .....000 00...... 0x00 + + 0xf3 0x0f 0x1e 0xfa 0x55 0x48 0x89 0xe5 0x48 100000.1 0xec .....000 + 0xf3 0x0f 0x1e 0xfa 0x554889e553 + 0xf3 0x0f 0x1e 0xfa 0x554889fd53 + 0xf3 0x0f 0x1e 0xfa 0x554889e548897df8 + 0xf3 0x0f 0x1e 0xfa 0x53 0x48 0x89 0xfb 0xe8 ........ ........ 0xff 0xff + 0xf3 0x0f 0x1e 0xfa 0x4154 0x55 0100100. 0x89 11...... + 0xf3 0x0f 0x1e 0xfa 0x4154 0x55 0x53 0100100. 0x89 11...... + + 0xf3 0x0f 0x1e 0xfa 0x415741564155 + 0xf3 0x0f 0x1e 0xfa 0x41564155 + 0xf3 0x0f 0x1e 0xfa 0x41554154 + 0xf3 0x0f 0x1e 0xfa 0x41 010101.. 0100100. 0x89 11...... 0x55 + 0xf3 0x0f 0x1e 0xfa 0x41 010101.. 0x41 010101.. 0100100. 0x89 11...... + + + + 0x90 0x90 + 0xc3 0x90 + 0x6690 + 0xc9 0xc3 + 0xe9........ + 0xe9........90 + 0xeb.. + 0xeb..90 + 0x5d 0xc3 + 0x5b 0xc3 + 0x41 010111.. 0xc3 + 0x31c0 0xc3 + 0x4883c4 ....1000 0xc3 + 0x666690 + 0x0f1f00 + 0x0f1f4000 + 0x0f1f440000 + 0x660f1f440000 + 0x0f1f8000000000 + 0x0f1f840000000000 + 0x660f1f840000000000 + + + 0xf3 0x0f 0x1e 0xfa + + + + + 0x5589e5 diff --git a/Ghidra/Processors/x86/data/patterns/x86-64win_patterns.xml b/Ghidra/Processors/x86/data/patterns/x86-64win_patterns.xml index 50b144afae..0b3d282905 100644 --- a/Ghidra/Processors/x86/data/patterns/x86-64win_patterns.xml +++ b/Ghidra/Processors/x86/data/patterns/x86-64win_patterns.xml @@ -89,4 +89,17 @@ 0xcccc * 0x4c8b 11...100 01001.01 0x89 + + + 01001... 0x3b 0x0d ........ ........ ........ ........ + 0x75 0x10 + 01001... 0xc1 0xc1 0x10 + 0x66 0xf7 0xc1 0xff 0xff + 0x75 0x01 + 0xc3 + 01001... 0xc1 0xc9 0x10 + 0xe9 + + + diff --git a/Ghidra/Processors/x86/data/patterns/x86gcc_patterns.xml b/Ghidra/Processors/x86/data/patterns/x86gcc_patterns.xml index 89885e5aea..fd06503cb3 100644 --- a/Ghidra/Processors/x86/data/patterns/x86gcc_patterns.xml +++ b/Ghidra/Processors/x86/data/patterns/x86gcc_patterns.xml @@ -108,9 +108,35 @@ 0x5589e5 0x8d 0x4c ..100100 0x04 0x83 0xe4 0xf. 0x57 0x8d 0x7c ..100100 0x08 0x83 0xe4 0xf. + + + 0xf3 0x0f 0x1e 0xfb 0x5589e5 + 0xf3 0x0f 0x1e 0xfb 0x8d 0x4c ..100100 0x04 0x83 0xe4 0xf. + 0xf3 0x0f 0x1e 0xfb 0x57 0x8d 0x7c ..100100 0x08 0x83 0xe4 0xf. + + + + 0x90 + 0xc3 + 0xe9........ + 0xeb.. + 0x89f6 + 0x8d7600 + 0x8d742600 + 0x8db600000000 + 0x8dbf00000000 + 0x8dbc2700000000 + 0x8db42600000000 + + + 0xf3 0x0f 0x1e 0xfb + + + + diff --git a/Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml b/Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml index 190acf223f..84b6d20dee 100644 --- a/Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml +++ b/Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml @@ -6,15 +6,15 @@ 0x68......00 0xe9......ff - + - 0xf3 0x0f 0x1e 0x1a - 0xf2 0xff 0x25 .. .. .. .. + 0xf3 0x0f 0x1e 0xfa + 0xf2 0xff 0x25 - + diff --git a/Ghidra/Processors/x86/data/patterns/x86win_patterns.xml b/Ghidra/Processors/x86/data/patterns/x86win_patterns.xml index 4c4b59e73c..c048c9f334 100644 --- a/Ghidra/Processors/x86/data/patterns/x86win_patterns.xml +++ b/Ghidra/Processors/x86/data/patterns/x86win_patterns.xml @@ -144,4 +144,13 @@ + + 0x3b 0x0d 0x.. 0x.. 0x.. 0x.. + 0x75 0x01 + 0xc3 + 0xe9 + + + +