Compare commits

...

39 commits

Author SHA1 Message Date
Ryan Kurtz
96506554e7 Merge remote-tracking branch 'origin/Ghidra_12.0' 2025-09-26 12:57:42 -04:00
Ryan Kurtz
cde92ede12 Merge branch 'GP-6021_ryanmkurtz_pyghidra' into Ghidra_12.0
(Closes #8524)
2025-09-26 12:55:27 -04:00
Ryan Kurtz
951f5a5daa GP-6021: PyGhidra stdout/stderr scripting console fixes 2025-09-26 12:51:32 -04:00
ghidra1
c16396d235 Merge branch 'Ghidra_12.0' 2025-09-26 11:04:51 -04:00
ghidra1
2b5ba24327 GP-6008 Corrected regression bug for VT function stringable Imported
priority check
2025-09-26 11:02:35 -04:00
ghidra1
5ea1b04604 Merge remote-tracking branch 'origin/Ghidra_12.0' 2025-09-25 13:54:11 -04:00
ghidra1
531d53f8f8 Merge remote-tracking branch 'origin/patch' into Ghidra_12.0 2025-09-25 13:53:31 -04:00
ghidra1
9a20684330 GP-5526 Simplified fix for CreateThunkFunctionCmd 2025-09-25 13:52:42 -04:00
ghidra1
5ceb49b11f Merge remote-tracking branch 'origin/Ghidra_12.0' 2025-09-25 13:11:59 -04:00
ghidra1
fb66e26452 Merge remote-tracking branch 'origin/patch' into Ghidra_12.0 2025-09-25 13:10:48 -04:00
ghidra1
cae8caac14 GP-5526 Correct CreateThunkCmd NPE 2025-09-25 13:03:49 -04:00
Ryan Kurtz
1ded9bcb80 Merge remote-tracking branch 'origin/GP-6005_ryanmkurtz_vs' into
Ghidra_12.0 (#2305)
2025-09-25 09:58:05 -04:00
Ryan Kurtz
9ad9d0d3db Merge remote-tracking branch 'origin/Ghidra_12.0' 2025-09-25 05:26:54 -04:00
Ryan Kurtz
0fb3a8f8a9 Merge remote-tracking branch 'origin/patch' into Ghidra_12.0 2025-09-25 05:25:30 -04:00
emteere
136a28d603 GP-5526 bug fix for .plt.sec and pattern matching optimization 2025-09-25 05:22:34 -04:00
Ryan Kurtz
bcd9130aee Merge remote-tracking branch 'origin/GP-5989_ForceUnionException' into
Ghidra_12.0 (Closes #7466)
2025-09-25 05:04:27 -04:00
caheckman
72344ce13e GP-5989 Fix ForceUnionAction "Could not recover p-code op" 2025-09-24 19:06:45 +00:00
Ryan Kurtz
a51cfb7c09 Merge remote-tracking branch 'origin/Ghidra_12.0' 2025-09-24 14:33:50 -04:00
Ryan Kurtz
8802befa22 Merge remote-tracking branch 'origin/GP-5526_emteere_bugfix--SQUASHED' into Ghidra_12.0 2025-09-24 14:20:56 -04:00
Ryan Kurtz
961ab7b76e Merge remote-tracking branch
'origin/GP-5998_emteere_VS2022_stack_check_cookie_Issue--SQUASHED' into
Ghidra_12.0 (Closes #2743)
2025-09-24 14:18:25 -04:00
Ryan Kurtz
d1c6a1cd06 Merge remote-tracking branch
'origin/GP-5287_emteere_ENDBR_patterns--SQUASHED' into Ghidra_12.0
(#8516)
2025-09-24 14:13:50 -04:00
emteere
dc069a18c6 GP-5287 Added ENDBR jump target checking instructions as function start patterns for x86 gcc binaries 2025-09-24 18:06:03 +00:00
emteere
69ed84a069 GP-5526 bug fix for .plt.sec and pattern matching optimization 2025-09-24 18:03:10 +00:00
emteere
0815f463f5 GP-5998 Added security_check_cookie function patterns and callfixup for VS2022 based binaries. 2025-09-24 18:01:43 +00:00
Ryan Kurtz
48a86b945a GP-0: Finding dev mode extensions in all application root dirs 2025-09-24 13:04:54 -04:00
Ryan Kurtz
f41f7c9eab Merge remote-tracking branch 'origin/Ghidra_12.0' 2025-09-24 11:18:29 -04:00
Ryan Kurtz
14bdf2bbe5 Merge remote-tracking branch
'origin/GP-3139_James_add_apple_arm64_cspec' into Ghidra_12.0
(Closes #8032, Closes #2723)
2025-09-24 11:15:39 -04:00
ghidra1
4a1a373193 GP-0 SourceType javadoc update 2025-09-24 09:37:55 -04:00
ghidra1
5df99853af Merge remote-tracking branch 'origin/GP-6006_ghidra1_added_new_source_type' into Ghidra_12.0 2025-09-24 09:18:53 -04:00
ghidra1
ed4ad257f2 Merge remote-tracking branch 'origin/GP-6008_ghidra1_SourceTypePriorityUse--SQUASHED' into Ghidra_12.0 2025-09-24 09:18:36 -04:00
ghidra1
a3bd708160 GP-6008 Changed SourceType examination to base upon priorty instead of specific value equality when appropriate 2025-09-24 09:16:04 -04:00
Ryan Kurtz
350817be2d Merge remote-tracking branch 'origin/GP-5981_ryanmkurtz_jython' into Ghidra_12.0 2025-09-24 09:06:13 -04:00
Ryan Kurtz
03ee787325 GP-5981: Giving Jython scripts invoked via runScript() a fresh set of
locals
2025-09-24 08:54:11 -04:00
Ryan Kurtz
aacd763b25 Merge remote-tracking branch 'origin/Ghidra_12.0' 2025-09-24 05:57:55 -04:00
Ryan Kurtz
6c1a1b4600 Merge remote-tracking branch 'origin/GP-0-dragonmacher-test-fixes-9-23-25' into Ghidra_12.0 2025-09-24 05:55:44 -04:00
dragonmacher
9e9de7c4f5 Test fixes 2025-09-23 16:53:02 -04:00
ghidragon
e346c30205 GP-6006 Added a new source type called 'AI' 2025-09-23 15:18:03 -04:00
Ryan Kurtz
6bb33b0025 GP-6005: The Windows build can now use prerelease versions of Visual
Studio with the new -PvswherePrerelease arg
2025-09-18 12:50:13 -04:00
James
6e81a370ce GP-3139 added cspec for AARCH64 apple silicon 2025-09-11 17:36:37 +00:00
54 changed files with 1003 additions and 416 deletions

View file

@ -34,7 +34,7 @@ def configureVisualStudio() {
println " -> To manually specify the location of vswhere.exe, add \"-PvswherePath=<vswhere path>\" 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

View file

@ -52,7 +52,7 @@ import ghidra.util.task.TaskMonitor;
public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
implements TraceSymbol, DecodesAddresses {
private static final byte SOURCE_MASK = 0x0F;
private static final byte SOURCE_MASK = 0x0F; // see SourceType
private static final int SOURCE_SHIFT = 0;
private static final byte SOURCE_CLEAR = ~(SOURCE_MASK << SOURCE_SHIFT);
@ -365,8 +365,8 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
}
protected void doSetSource(SourceType newSource) {
flags =
(byte) ((flags & SOURCE_CLEAR) | (newSource.ordinal() & SOURCE_MASK) << SOURCE_SHIFT);
flags = (byte) ((flags & SOURCE_CLEAR) |
(newSource.getStorageId() & SOURCE_MASK) << SOURCE_SHIFT);
}
/**
@ -502,7 +502,7 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
@Override
public SourceType getSource() {
assertNotGlobal();
return SourceType.values()[(flags >> SOURCE_SHIFT) & SOURCE_MASK];
return SourceType.getSourceType((flags >> SOURCE_SHIFT) & SOURCE_MASK);
}
@Override

View file

@ -103,14 +103,14 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
implements DecodesAddresses {
private static final String TABLE_NAME = "References";
private static final byte SOURCE_MASK = 0x0F;
private static final byte SOURCE_MASK = 0x0F; // see SourceType
private static final byte SOURCE_SHIFT = 0;
//private static final byte SOURCE_CLEAR = ~(SOURCE_MASK << SOURCE_SHIFT);
private static final byte PRIMARY_MASK = 0x10;
private static final byte PRIMARY_CLEAR = ~PRIMARY_MASK;
private static final byte TYPE_MASK = 0x3;
private static final byte TYPE_MASK = 0x3; // See DBTraceReferenceSpace.TypeEnum
private static final byte TYPE_SHIFT = 5;
//private static final byte TYPE_CLEAR = ~(TYPE_MASK << TYPE_SHIFT);
@ -142,15 +142,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
return DBTraceUtils.tableName(TABLE_NAME, space);
}
@DBAnnotatedField(
column = TO_ADDR_MIN_COLUMN_NAME,
indexed = true,
codec = AddressDBFieldCodec.class)
@DBAnnotatedField(column = TO_ADDR_MIN_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class)
protected Address toAddrMin = Address.NO_ADDRESS;
@DBAnnotatedField(
column = TO_ADDR_MAX_COLUMN_NAME,
indexed = true,
codec = AddressDBFieldCodec.class)
@DBAnnotatedField(column = TO_ADDR_MAX_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class)
protected Address toAddrMax = Address.NO_ADDRESS;
@DBAnnotatedField(column = SYMBOL_ID_COLUMN_NAME, indexed = true)
protected long symbolId; // TODO: Is this at the from or to address? I think TO...
@ -201,8 +195,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
return this;
}
protected void set(AddressRange toRange, long symbolId, RefType refType,
int opIndex, long ext, boolean isPrimary, TypeEnum type, SourceType sourceType) {
protected void set(AddressRange toRange, long symbolId, RefType refType, int opIndex,
long ext, boolean isPrimary, TypeEnum type, SourceType sourceType) {
this.toAddrMin = toRange.getMinAddress();
this.toAddrMax = toRange.getMaxAddress();
this.symbolId = symbolId;
@ -210,7 +204,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
this.opIndex = (byte) opIndex;
this.ext = ext;
this.flags = (byte) ((isPrimary ? PRIMARY_MASK : 0) |
(sourceType.ordinal() << SOURCE_SHIFT) | type.ordinal() << TYPE_SHIFT);
(sourceType.getStorageId() << SOURCE_SHIFT) | type.ordinal() << TYPE_SHIFT);
update(TO_ADDR_MIN_COLUMN, TO_ADDR_MAX_COLUMN, SYMBOL_ID_COLUMN, REF_TYPE_COLUMN,
OP_INDEX_COLUMN, EXT_COLUMN, FLAGS_COLUMN);
@ -243,8 +237,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
TraceEvents.SYMBOL_ASSOCIATION_REMOVED, space.space, oldSymbol, ref));
}
if (newSymbol != null) {
space.trace.setChanged(new TraceChangeRecord<>(
TraceEvents.SYMBOL_ASSOCIATION_ADDED, space.space, newSymbol, ref));
space.trace.setChanged(new TraceChangeRecord<>(TraceEvents.SYMBOL_ASSOCIATION_ADDED,
space.space, newSymbol, ref));
}
}
@ -276,7 +270,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
}
public SourceType getSourceType() {
return SourceType.values()[(flags >> SOURCE_SHIFT) & SOURCE_MASK];
return SourceType.getSourceType((flags >> SOURCE_SHIFT) & SOURCE_MASK);
}
protected void doDelete() {
@ -375,16 +369,15 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
referenceMapSpace.getUserIndex(long.class, DBTraceReferenceEntry.SYMBOL_ID_COLUMN);
this.xrefMapSpace = new DBTraceAddressSnapRangePropertyMapSpace<>(
DBTraceXRefEntry.tableName(space), trace, factory, lock, space,
DBTraceXRefEntry.class, (t, s, r) -> new DBTraceXRefEntry(this, t, s, r));
DBTraceXRefEntry.tableName(space), trace, factory, lock, space, DBTraceXRefEntry.class,
(t, s, r) -> new DBTraceXRefEntry(this, t, s, r));
this.xrefsByRefKey = xrefMapSpace.getUserIndex(long.class, DBTraceXRefEntry.REF_KEY_COLUMN);
}
protected void doAddXRef(DBTraceReferenceEntry refEnt) {
// Note: called from manager on relevant space
DBTraceXRefEntry xrefEnt = xrefMapSpace.put(refEnt.toRange, refEnt.getLifespan(), null);
xrefEnt.set((short) refEnt.getRange().getAddressSpace().getSpaceID(),
refEnt.getKey());
xrefEnt.set((short) refEnt.getRange().getAddressSpace().getSpaceID(), refEnt.getKey());
}
protected void doDelXRef(DBTraceReferenceEntry refEnt) {
@ -451,11 +444,11 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
int operandIndex) {
// Do I consider "compatibility?" as in ReferenceDBManager?
// NOTE: Always call with the write lock
for (DBTraceReferenceEntry ent : referenceMapSpace.reduce(
TraceAddressSnapRangeQuery.intersecting(new AddressRangeImpl(fromAddress, fromAddress),
span)).values()) {
if (!ent.toRange.equals(toRange) ||
ent.opIndex != operandIndex) {
for (DBTraceReferenceEntry ent : referenceMapSpace
.reduce(TraceAddressSnapRangeQuery
.intersecting(new AddressRangeImpl(fromAddress, fromAddress), span))
.values()) {
if (!ent.toRange.equals(toRange) || ent.opIndex != operandIndex) {
continue;
}
@ -585,10 +578,10 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
public DBTraceReference getReference(long snap, Address fromAddress, AddressRange toRange,
int operandIndex) {
try (LockHold hold = LockHold.lock(lock.readLock())) {
for (DBTraceReferenceEntry entry : referenceMapSpace.reduce(
TraceAddressSnapRangeQuery.at(fromAddress, snap)).values()) {
if (!entry.toRange.equals(toRange) ||
entry.opIndex != operandIndex) {
for (DBTraceReferenceEntry entry : referenceMapSpace
.reduce(TraceAddressSnapRangeQuery.at(fromAddress, snap))
.values()) {
if (!entry.toRange.equals(toRange) || entry.opIndex != operandIndex) {
continue;
}
return entry.ref;
@ -641,8 +634,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
@Override
public Collection<? extends DBTraceReference> getFlowReferencesFrom(long snap,
Address fromAddress) {
return streamReferencesFrom(snap, fromAddress)
.filter(r -> r.getReferenceType().isFlow())
return streamReferencesFrom(snap, fromAddress).filter(r -> r.getReferenceType().isFlow())
.toList();
}
@ -650,8 +642,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
public void clearReferencesFrom(Lifespan span, AddressRange range) {
try (LockHold hold = manager.getTrace().lockWrite()) {
long startSnap = span.lmin();
for (DBTraceReferenceEntry ref : referenceMapSpace.reduce(
TraceAddressSnapRangeQuery.intersecting(range, span)).values()) {
for (DBTraceReferenceEntry ref : referenceMapSpace
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span))
.values()) {
truncateOrDeleteEntry(ref, startSnap);
}
// TODO: Coalesce events?
@ -682,21 +675,19 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
@Override
public Collection<? extends DBTraceReference> getReferencesToRange(Lifespan span,
AddressRange range, Rectangle2DDirection order) {
return new LazyCollection<>(
() -> xrefMapSpace
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span).starting(order))
.values()
.stream()
.map(this::getRefForXRefEntry));
return new LazyCollection<>(() -> xrefMapSpace
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span).starting(order))
.values()
.stream()
.map(this::getRefForXRefEntry));
}
protected void truncateOrDeleteEntry(DBTraceReferenceEntry ref, long otherStartSnap) {
if (ref.getLifespan().lmin() < otherStartSnap) {
Lifespan oldSpan = ref.getLifespan();
ref.setEndSnap(otherStartSnap - 1);
trace.setChanged(new TraceChangeRecord<>(
TraceEvents.REFERENCE_LIFESPAN_CHANGED, space, ref.ref, oldSpan,
ref.getLifespan()));
trace.setChanged(new TraceChangeRecord<>(TraceEvents.REFERENCE_LIFESPAN_CHANGED, space,
ref.ref, oldSpan, ref.getLifespan()));
}
else {
ref.ref.delete();
@ -707,8 +698,9 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
public void clearReferencesTo(Lifespan span, AddressRange range) {
try (LockHold hold = manager.getTrace().lockWrite()) {
long startSnap = span.lmin();
for (DBTraceXRefEntry xref : xrefMapSpace.reduce(
TraceAddressSnapRangeQuery.intersecting(range, span)).values()) {
for (DBTraceXRefEntry xref : xrefMapSpace
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span))
.values()) {
DBTraceReferenceEntry ref = getRefEntryForXRefEntry(xref);
truncateOrDeleteEntry(ref, startSnap);
}

View file

@ -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);

View file

@ -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);

View file

@ -448,7 +448,7 @@
<TD align="left" height="21" width="22%">Function</TD>
<TD align="left" height="21" width="56%">Indicates the source-type associated with the
function signature (i.e., DEFAULT, ANALYSIS, IMPORTED, USER_DEFINED).</TD>
function signature (i.e., DEFAULT, AI_ASSIST, ANALYSIS, IMPORTED, USER_DEFINED).</TD>
</TR>
<TR>

View file

@ -563,6 +563,13 @@ public class CreateThunkFunctionCmd extends BackgroundCommand<Program> {
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;
}

View file

@ -145,8 +145,10 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
}
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<Program> {
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<Program> {
return;
}
}
long extendedOffset = extendOffset(address.getOffset(), stackReg.getBitLength());
long extendedOffset =
extendOffset(address.getOffset(), stackReg.getBitLength());
defineFuncVariable(symEval, func, instr, opIndex, (int) extendedOffset, sortedVariables);
defineFuncVariable(symEval, func, instr, opIndex, (int) extendedOffset,
sortedVariables);
}
}
@ -634,8 +638,8 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
// return true;
// }
private void defineFuncVariable(SymbolicPropogator symEval, Function func, Instruction instr, int opIndex, int stackOffset,
List<Variable> sortedVariables) {
private void defineFuncVariable(SymbolicPropogator symEval, Function func, Instruction instr,
int opIndex, int stackOffset, List<Variable> sortedVariables) {
ReferenceManager refMgr = program.getReferenceManager();
int refSize = getRefSize(symEval, instr, opIndex);

View file

@ -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);

View file

@ -427,7 +427,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
}
SourceType mostTrusted = getMostTrustedParameterSource(func);
if (SourceType.ANALYSIS.isLowerPriorityThan(mostTrusted)) {
if (mostTrusted.isHigherOrEqualPriorityThan(SourceType.IMPORTED)) {
return;
}
}

View file

@ -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<GoType, DataType> returnTypeMapper) {
}
private GoRttiMapper goBinary;
private Program program;
private MarkupSession markupSession;

View file

@ -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);

View file

@ -717,11 +717,9 @@ public class ClearFlowAndRepairCmd extends BackgroundCommand<Program> {
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.

View file

@ -29,11 +29,12 @@ public class NewSymbolFilter implements SymbolFilter {
private static final String XML_NAME = "SYMBOL_TABLE_FILTER";
private Filter userDefinedFilter;
private Filter analysisFilter;
private Filter defaultFunctionFilter;
private Filter defaultLabelFilter;
private Filter importedFilter;
private Filter defaultLabelSourceFilter;
private Filter defaultFunctionSourceFilter;
private Filter aiSourceFilter;
private Filter analysisSourceFilter;
private Filter importedSourceFilter;
private Filter userDefinedSourceFilter;
private Filter[] labelFilters;
private Filter[] nonLabelFilters;
@ -67,19 +68,21 @@ public class NewSymbolFilter implements SymbolFilter {
for (Filter advancedFilter : advancedFilters) {
filterMap.put(advancedFilter.getName(), advancedFilter);
}
filterMap.put(userDefinedFilter.getName(), userDefinedFilter);
filterMap.put(importedFilter.getName(), importedFilter);
filterMap.put(analysisFilter.getName(), analysisFilter);
filterMap.put(defaultLabelFilter.getName(), defaultLabelFilter);
filterMap.put(defaultFunctionFilter.getName(), defaultFunctionFilter);
filterMap.put(defaultLabelSourceFilter.getName(), defaultLabelSourceFilter);
filterMap.put(defaultFunctionSourceFilter.getName(), defaultFunctionSourceFilter);
filterMap.put(aiSourceFilter.getName(), aiSourceFilter);
filterMap.put(analysisSourceFilter.getName(), analysisSourceFilter);
filterMap.put(importedSourceFilter.getName(), importedSourceFilter);
filterMap.put(userDefinedSourceFilter.getName(), userDefinedSourceFilter);
if (oldFilter instanceof NewSymbolFilter) {
NewSymbolFilter filter = (NewSymbolFilter) oldFilter;
userDefinedFilter.setActive(filter.userDefinedFilter.isActive());
importedFilter.setActive(filter.importedFilter.isActive());
analysisFilter.setActive(filter.analysisFilter.isActive());
defaultLabelFilter.setActive(filter.defaultLabelFilter.isActive());
defaultFunctionFilter.setActive(filter.defaultFunctionFilter.isActive());
defaultLabelSourceFilter.setActive(filter.defaultLabelSourceFilter.isActive());
defaultFunctionSourceFilter.setActive(filter.defaultFunctionSourceFilter.isActive());
aiSourceFilter.setActive(filter.aiSourceFilter.isActive());
analysisSourceFilter.setActive(filter.analysisSourceFilter.isActive());
importedSourceFilter.setActive(filter.importedSourceFilter.isActive());
userDefinedSourceFilter.setActive(filter.userDefinedSourceFilter.isActive());
for (int i = 0; i < labelFilters.length; i++) {
labelFilters[i].setActive(filter.labelFilters[i].isActive());
@ -156,8 +159,8 @@ public class NewSymbolFilter implements SymbolFilter {
@Override
public boolean acceptsOnlyCodeSymbols() {
for (int i = 0; i < activeTypeFilters.length; i++) {
if (!activeTypeFilters[i].onlyCodeSymbols) {
for (Filter activeTypeFilter : activeTypeFilters) {
if (!activeTypeFilter.onlyCodeSymbols) {
return false;
}
}
@ -166,7 +169,7 @@ public class NewSymbolFilter implements SymbolFilter {
@Override
public boolean acceptsDefaultLabelSymbols() {
if (!defaultLabelFilter.isActive()) {
if (!defaultLabelSourceFilter.isActive()) {
return false;
}
for (Filter activeTypeFilter : activeTypeFilters) {
@ -183,10 +186,10 @@ public class NewSymbolFilter implements SymbolFilter {
}
String[] getSourceFilterNames() {
return new String[] { userDefinedFilter.getName(), defaultFunctionFilter.getName(),
importedFilter.getName(), defaultLabelFilter.getName(), analysisFilter.getName(),
};
return new String[] { defaultLabelSourceFilter.getName(),
defaultFunctionSourceFilter.getName(), aiSourceFilter.getName(),
analysisSourceFilter.getName(), userDefinedSourceFilter.getName(),
importedSourceFilter.getName() };
}
String[] getLabelTypeFilterNames() {
@ -283,31 +286,38 @@ public class NewSymbolFilter implements SymbolFilter {
for (Filter advancedFilter : advancedFilters) {
advancedFilter.setActive(false);
}
userDefinedFilter.setActive(true);
importedFilter.setActive(true);
analysisFilter.setActive(true);
defaultFunctionFilter.setActive(true);
defaultLabelFilter.setActive(false);
defaultFunctionSourceFilter.setActive(true);
defaultLabelSourceFilter.setActive(false);
aiSourceFilter.setActive(true);
analysisSourceFilter.setActive(true);
importedSourceFilter.setActive(true);
userDefinedSourceFilter.setActive(true);
rebuildActiveFilters();
}
private void rebuildActiveFilters() {
ArrayList<Filter> originList = new ArrayList<>(3);
if (userDefinedFilter.isActive()) {
originList.add(userDefinedFilter);
if (defaultLabelSourceFilter.isActive()) {
originList.add(defaultLabelSourceFilter);
}
if (importedFilter.isActive()) {
originList.add(importedFilter);
if (defaultFunctionSourceFilter.isActive()) {
originList.add(defaultFunctionSourceFilter);
}
if (analysisFilter.isActive()) {
originList.add(analysisFilter);
if (aiSourceFilter.isActive()) {
originList.add(aiSourceFilter);
}
if (defaultLabelFilter.isActive()) {
originList.add(defaultLabelFilter);
if (analysisSourceFilter.isActive()) {
originList.add(analysisSourceFilter);
}
if (defaultFunctionFilter.isActive()) {
originList.add(defaultFunctionFilter);
if (importedSourceFilter.isActive()) {
originList.add(importedSourceFilter);
}
if (userDefinedSourceFilter.isActive()) {
originList.add(userDefinedSourceFilter);
}
activeOriginFilters = new Filter[originList.size()];
originList.toArray(activeOriginFilters);
@ -339,49 +349,16 @@ public class NewSymbolFilter implements SymbolFilter {
advancedList.toArray(activeAdvancedFilters);
acceptsAllTypes = activeTypeFilters.length == labelFilters.length + nonLabelFilters.length;
acceptsAllSources = userDefinedFilter.isActive() && analysisFilter.isActive() &&
defaultLabelFilter.isActive() && defaultFunctionFilter.isActive() &&
importedFilter.isActive();
acceptsAllSources =
defaultLabelSourceFilter.isActive() && defaultFunctionSourceFilter.isActive() &&
importedSourceFilter.isActive() && aiSourceFilter.isActive() &&
analysisSourceFilter.isActive() && userDefinedSourceFilter.isActive();
acceptsAll = acceptsAllTypes && acceptsAllSources && activeAdvancedFilters.length == 0;
}
private void createFilters() {
userDefinedFilter = new Filter("User Defined", false, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSource() == SourceType.USER_DEFINED;
}
@Override
String getDescription() {
return "Include Symbols named by the user.";
}
};
importedFilter = new Filter("Imported", false, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSource() == SourceType.IMPORTED;
}
@Override
String getDescription() {
return "Include Symbols imported from external information.";
}
};
analysisFilter = new Filter("Analysis", false, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSource() == SourceType.ANALYSIS;
}
@Override
String getDescription() {
return "Include Symbols named by auto-analysis.";
}
};
defaultLabelFilter = new Filter("Default (Labels)", true, false) {
defaultLabelSourceFilter = new Filter("Default (Labels)", true, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSymbolType() != SymbolType.FUNCTION &&
@ -394,7 +371,7 @@ public class NewSymbolFilter implements SymbolFilter {
}
};
defaultFunctionFilter = new Filter("Default (Functions)", true, false) {
defaultFunctionSourceFilter = new Filter("Default (Functions)", true, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSymbolType() == SymbolType.FUNCTION &&
@ -405,8 +382,52 @@ public class NewSymbolFilter implements SymbolFilter {
String getDescription() {
return "Include Symbols that have default names.";
}
};
aiSourceFilter = new Filter(SourceType.AI.getDisplayString(), false, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSource() == SourceType.AI;
}
@Override
String getDescription() {
return "Include Symbols named by auto-analysis.";
}
};
analysisSourceFilter = new Filter(SourceType.ANALYSIS.getDisplayString(), false, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSource() == SourceType.ANALYSIS;
}
@Override
String getDescription() {
return "Include Symbols named by auto-analysis.";
}
};
importedSourceFilter = new Filter(SourceType.IMPORTED.getDisplayString(), false, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSource() == SourceType.IMPORTED;
}
@Override
String getDescription() {
return "Include Symbols imported from external information.";
}
};
userDefinedSourceFilter =
new Filter(SourceType.USER_DEFINED.getDisplayString(), false, false) {
@Override
boolean matches(Program program, Symbol symbol) {
return symbol.getSource() == SourceType.USER_DEFINED;
}
@Override
String getDescription() {
return "Include Symbols named by the user.";
}
};
Filter instructionFilter = new Filter("Instruction Labels", true, true) {
@Override
@ -902,9 +923,7 @@ public class NewSymbolFilter implements SymbolFilter {
@Override
boolean isEnabled() {
Iterator<Filter> it = applicableFilters.iterator();
while (it.hasNext()) {
Filter filter = it.next();
for (Filter filter : applicableFilters) {
if (filter.isActive()) {
return true;
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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

View file

@ -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":

View file

@ -1286,6 +1286,8 @@
<li class="listitem" style="list-style-type: none">
<span class="emphasis"><em>DEFAULT</em></span> - for basic or no information</li>
<li class="listitem" style="list-style-type: none">
<span class="emphasis"><em>AI</em></span> - for information that is produced with AI assistance</li>
<li class="listitem" style="list-style-type: none">
<span class="emphasis"><em>ANALYSIS</em></span> - for information derived by an Analyzer</li>
<li class="listitem" style="list-style-type: none">
<span class="emphasis"><em>IMPORTED</em></span> - for information imported from an external source</li>

View file

@ -150,12 +150,12 @@ public class DecompilerParameterIdCmd extends BackgroundCommand<Program> {
// 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);
}
}

View file

@ -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
}
/**

View file

@ -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();

View file

@ -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;
}

View file

@ -273,9 +273,8 @@ public class ApplyFidEntriesCommand extends BackgroundCommand<Program> {
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;

View file

@ -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<PyObject> 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)) {

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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:

View file

@ -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;
}

View file

@ -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) {

View file

@ -17,6 +17,7 @@ package ghidra.feature.vt.gui.provider.matchtable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Arrays;
import javax.swing.JCheckBox;
@ -48,6 +49,7 @@ public class SymbolTypeFilter extends CheckBoxBasedAncillaryFilter<VTMatch> {
};
SourceType[] values = SourceType.values();
Arrays.sort(values, (s1, s2) -> s1.getPriority() - s2.getPriority());
for (SourceType type : values) {
GCheckBox checkBox = new GCheckBox(type.getDisplayString(), true);
checkBox.addItemListener(listener);

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,13 +19,23 @@ import ghidra.program.model.symbol.SourceType;
class RefListFlagsV0 {
private static final int SOURCE_LOBIT = 0x01;
// NOTE: Storage for SourceType has been expanded into upper zero-initialized bits
// with simple ProgramDB version change.
private static final int SOURCE_LOBIT = 0x01; // SourceType LO 1-bit
private static final int IS_PRIMARY = 0x02;
private static final int IS_OFFSET = 0x04;
private static final int HAS_SYMBOL_ID = 0x08;
private static final int IS_SHIFT = 0x10;
private static final int SOURCE_HIBITS = 0x60; // SourceType HI 2-bits
private static final int SOURCE_HIBIT = 0x20;
private static final int SOURCE_LOBIT_SHIFT = 0;
private static final int SOURCE_HIBITS_SHIFT = 5;
private static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
private int flags;
RefListFlagsV0(byte flags) {
@ -36,12 +45,23 @@ class RefListFlagsV0 {
public RefListFlagsV0(boolean isPrimary, boolean isOffsetRef, boolean hasSymbolID,
boolean isShiftRef, SourceType source) {
flags = 0;
if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
flags |= SOURCE_LOBIT;
}
if (source == SourceType.ANALYSIS || source == SourceType.IMPORTED) {
flags |= SOURCE_HIBIT;
// Get the storage ID to be used to encode source type
// NOTE: RefListV0 uses a storage ID in some cases that differs from SourceType storage ID
int sourceId = switch (source) {
case DEFAULT -> 0;
case ANALYSIS -> 2;
default -> source.getStorageId();
};
// Encode SourceType value into split storage flags
if (sourceId > MAX_SOURCE_VALUE) {
throw new RuntimeException("Unsupported SourceType storage ID: " + sourceId);
}
int sourceTypeLoBit = (sourceId & 1) << SOURCE_LOBIT_SHIFT; // 1-bit
int sourceTypeHiBits = (sourceId >>> 1) << SOURCE_HIBITS_SHIFT; // remaining hi-bits
flags |= sourceTypeHiBits | sourceTypeLoBit;
if (isPrimary)
flags |= IS_PRIMARY;
if (isOffsetRef)
@ -57,12 +77,18 @@ class RefListFlagsV0 {
}
SourceType getSource() {
boolean isLoBit = (flags & SOURCE_LOBIT) != 0;
boolean isHiBit = (flags & SOURCE_HIBIT) != 0;
if (isHiBit) {
return isLoBit ? SourceType.IMPORTED : SourceType.ANALYSIS;
}
return isLoBit ? SourceType.USER_DEFINED : SourceType.DEFAULT;
// Decode storage ID from flags bits
int sourceTypeLoBit = (flags & SOURCE_LOBIT) >>> SOURCE_LOBIT_SHIFT; // 1-bit
int sourceTypeHiBits = (flags & SOURCE_HIBITS) >>> (SOURCE_HIBITS_SHIFT - 1); // remaining HI-bits
int sourceTypeId = sourceTypeHiBits | sourceTypeLoBit;
// NOTE: RefListV0 uses a storage ID in some cases that differs from SourceType storage ID
return switch (sourceTypeId) {
case 0 -> SourceType.DEFAULT;
case 2 -> SourceType.ANALYSIS;
default -> SourceType.getSourceType(sourceTypeId);
};
}
public boolean hasSymbolID() {

View file

@ -169,7 +169,7 @@ public abstract class MemorySymbol extends SymbolDB {
newNamespace.getID());
}
if (newSource != null) {
setSourceFlagBit(newSource);
setSourceFlagBits(newSource);
}
updatePinnedFlag(pinned);
updateRecord();

View file

@ -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);
}

View file

@ -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

View file

@ -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.

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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|

View file

@ -0,0 +1,270 @@
<?xml version="1.0" encoding="UTF-8"?>
<compiler_spec>
<data_organization>
<absolute_max_alignment value="0" />
<machine_alignment value="4" />
<default_alignment value="1" />
<default_pointer_alignment value="8" />
<pointer_size value="8" />
<wchar_size value="4" />
<short_size value="2" />
<integer_size value="4" />
<long_size value="8" />
<long_long_size value="8" />
<float_size value="4" />
<double_size value="8" />
<long_double_size value="8" />
<size_alignment_map>
<entry size="1" alignment="1" />
<entry size="2" alignment="2" />
<entry size="4" alignment="4" />
<entry size="8" alignment="8" />
<entry size="16" alignment="16"/>
</size_alignment_map>
</data_organization>
<global>
<range space="ram"/>
</global>
<stackpointer register="sp" space="ram"/>
<funcptr align="4"/> <!-- Function pointers are word aligned and leastsig bit may encode otherstuff -->
<prefersplit style="inhalf">
<register name="q0"/>
<register name="q1"/>
<register name="q2"/>
<register name="q3"/>
<register name="q4"/>
<register name="q5"/>
<register name="q6"/>
<register name="q7"/>
<register name="q8"/>
<register name="q9"/>
<register name="q10"/>
<register name="q11"/>
<register name="q12"/>
<register name="q13"/>
<register name="q14"/>
<register name="q15"/>
<register name="q16"/>
<register name="q17"/>
<register name="q18"/>
<register name="q19"/>
<register name="q20"/>
<register name="q21"/>
<register name="q22"/>
<register name="q23"/>
<register name="q24"/>
<register name="q25"/>
<register name="q26"/>
<register name="q27"/>
<register name="q28"/>
<register name="q29"/>
<register name="q30"/>
</prefersplit>
<default_proto>
<prototype name="__cdecl" extrapop="0" stackshift="0">
<input>
<pentry minsize="8" maxsize="8" storage="hiddenret">
<register name="x8"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q0"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q1"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q2"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q3"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q4"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q5"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q6"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q7"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x0"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x1"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x2"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x3"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x4"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x5"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x6"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x7"/>
</pentry>
<pentry minsize="1" maxsize="500" align="8">
<addr offset="0" space="stack"/>
</pentry>
<rule>
<datatype name="homogeneous-float-aggregate"/>
<join_per_primitive storage="float"/>
</rule>
<rule>
<datatype name="homogeneous-float-aggregate"/>
<goto_stack/> <!-- Don't consume general purpose registers -->
<consume_extra storage="float"/> <!-- Once the stack has been used, don't go back to registers -->
</rule>
<rule>
<datatype name="struct" minsize="17"/>
<convert_to_ptr/>
</rule>
<rule>
<datatype name="union" minsize="17"/>
<convert_to_ptr/>
</rule>
<!-- Variadic arguments are passed differently than in the AARCH64 standard -->
<!-- See "Writing ARM64 Code for Apple Platforms" -->
<rule>
<datatype name="any"/>
<varargs first="0"/>
<goto_stack/>
</rule>
<rule>
<datatype name="float"/>
<consume storage="float"/>
</rule>
<rule>
<datatype name="float"/>
<goto_stack/> <!-- Don't consume general purpose registers -->
</rule>
<rule>
<datatype name="any"/>
<join align="true"/> <!-- Chunk from general purpose registers -->
</rule>
</input>
<output>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q0"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q1"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q2"/>
</pentry>
<pentry minsize="1" maxsize="16" storage="float">
<register name="q3"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x0"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x1"/>
</pentry>
<rule>
<datatype name="homogeneous-float-aggregate"/>
<join_per_primitive storage="float"/>
</rule>
<rule>
<datatype name="float"/>
<consume storage="float"/>
</rule>
<rule>
<datatype name="any" minsize="17"/>
<hidden_return voidlock="true"/>
</rule>
<rule>
<datatype name="any"/>
<join/>
</rule>
</output>
<unaffected>
<register name="x19"/>
<register name="x20"/>
<register name="x21"/>
<register name="x22"/>
<register name="x23"/>
<register name="x24"/>
<register name="x25"/>
<register name="x26"/>
<register name="x27"/>
<register name="x28"/>
<register name="x29"/>
<register name="x30"/>
<register name="sp"/>
<!-- vectors -->
<register name="d8"/>
<register name="d9"/>
<register name="d10"/>
<register name="d11"/>
<register name="d12"/>
<register name="d13"/>
<register name="d14"/>
<register name="d15"/>
</unaffected>
<killedbycall>
<register name="x0"/>
<register name="x1"/>
<register name="q0"/>
<!-- x8: indirect result location register, which is not
reflected in the pentry list -->
<register name="x8"/>
<register name="x9"/>
<register name="x10"/>
<register name="x11"/>
<register name="x12"/>
<register name="x13"/>
<register name="x14"/>
<register name="x15"/>
<register name="x16"/>
<register name="x17"/>
<register name="x18"/>
<!-- vectors -->
<register name="d16"/>
<register name="d17"/>
<register name="d18"/>
<register name="d19"/>
<register name="d20"/>
<register name="d21"/>
<register name="d22"/>
<register name="d23"/>
<register name="d24"/>
<register name="d25"/>
<register name="d26"/>
<register name="d27"/>
<register name="d28"/>
<register name="d29"/>
<register name="d30"/>
<register name="d31"/>
</killedbycall>
</prototype>
</default_proto>
<callfixup name="PlaceHolderCallFixup"> <!-- This is here just to force call fixup and NoReturn fixup. Will be fixed in Ghidra V6.0 -->
<target name="___NotARealFunctionName___"/>
<pcode>
<body><![CDATA[
tmpptr:4 = 0;
]]></body>
</pcode>
</callfixup>
</compiler_spec>

View file

@ -10,7 +10,7 @@
manualindexfile="../manuals/AARCH64.idx"
id="AARCH64:LE:64:AppleSilicon">
<description>AppleSilicon ARM v8.5-A LE instructions, LE data, AMX extensions</description>
<compiler name="default" spec="AARCH64.cspec" id="default"/>
<compiler name="default" spec="AARCH64_apple.cspec" id="default"/>
<compiler name="Swift" spec="AARCH64_swift.cspec" id="swift"/>
<compiler name="golang" spec="AARCH64_golang.cspec" id="golang"/>
<external_name tool="gnu" name="aarch64"/>

View file

@ -233,4 +233,13 @@
]]></body>
</pcode>
</callfixup>
<callfixup name="security_check_cookie">
<target name="__security_check_cookie"/>
<pcode>
<body><![CDATA[
tmpzero:4 = 0;
]]></body>
</pcode>
</callfixup>
</compiler_spec>

View file

@ -386,4 +386,13 @@
]]></body>
</pcode>
</callfixup>
<callfixup name="security_check_cookie">
<target name="__security_check_cookie"/>
<pcode>
<body><![CDATA[
tmpzero:4 = 0;
]]></body>
</pcode>
</callfixup>
</compiler_spec>

View file

@ -48,11 +48,70 @@
<data>0x41564155</data> <!-- PUSH R14; PUSH R13-->
<data>0x41554154</data> <!-- PUSH R13; PUSH R12-->
<data>0x41 010101.. 0100100. 0x89 11...... 0x55</data> <!-- PUSH R12/3/4/5; MOV(R12/3/4/5/xX,RxX); PUSH(RBP)-->
<data>0x41 010101.. 0x41 010101.. 0100100. 0x89 11...... </data> <!-- PUSH R12/3/4/5; PUSH R12/3/4/5; MOV(R12/3/4/5/xX,RxX); -->
<!-- These are copies of the patterns above with the ENDBR64 pattern pre-pended. If the above are modified, add here as well -->
<!-- ENDBR followed by two-instruction sequences -->
<data>0xf3 0x0f 0x1e 0xfa 0x48 0x89 0x5c 0x24 11...000 0x48 0x89 0x6c 0x24 11...000</data> <!-- MOV [RSP + C], RBX; MOV [RSP + C], RBP -->
<data>0xf3 0x0f 0x1e 0xfa 0x48 0x89 0x5c 0x24 11...000 0x4c 0x89 0x64 0x24 111..000</data> <!-- MOV [RSP + C], RBX; MOV [RSP + C], R12 -->
<data>0xf3 0x0f 0x1e 0xfa 0x48 0x89 0x6c 0x24 11...000 0x4c 0x89 0x64 0x24 111..000</data> <!-- MOV [RSP + C], RBP; MOV [RSP + C], R12 -->
<data>0xf3 0x0f 0x1e 0xfa 0x5589e5</data> <!-- PUSH RBP; MOV(EBP, ESP) (shared objects) -->
<data>0xf3 0x0f 0x1e 0xfa 0x554889e5</data> <!-- PUSH RBP; MOV(RBP, RSP) (shared objects) -->
<data>0xf3 0x0f 0x1e 0xfa 0x534889fb</data> <!-- PUSH RBX; MOV(RBX,RDI) (shared objects) -->
<data>0xf3 0x0f 0x1e 0xfa 0x554889fd</data> <!-- PUSH (RBP); MOV(RBP, RDI) (kernel objects) -->
<data>0xf3 0x0f 0x1e 0xfa 0x534889fb</data> <!-- PUSH RBX; MOV(RBX,RDI)-->
<data>0xf3 0x0f 0x1e 0xfa 0x53 0x48 0x83 0xec 0....000 </data> <!-- PUSH RBX; SUB RSP, C -->
<data>0xf3 0x0f 0x1e 0xfa 0x53 0x48 0x81 0xec .....000 00...... 0x00 </data> <!-- PUSH RBX; SUB RSP, C -->
<!-- ENDBR followed by three-instruction sequences -->
<data>0xf3 0x0f 0x1e 0xfa 0x55 0x48 0x89 0xe5 0x48 100000.1 0xec .....000</data> <!-- PUSH RBP; MOV RBP, RSP; SUB RSP, C -->
<data>0xf3 0x0f 0x1e 0xfa 0x554889e553</data> <!-- PUSH RBP; MOV RBP, RSP; PUSH RBX -->
<data>0xf3 0x0f 0x1e 0xfa 0x554889fd53</data> <!-- PUSH RBP; MOV RBP, RDI; PUSH RBX -->
<data>0xf3 0x0f 0x1e 0xfa 0x554889e548897df8</data> <!-- PUSH RBP; MOV RBP, RSP; MOV [RBP -0x8], RDI -->
<data>0xf3 0x0f 0x1e 0xfa 0x53 0x48 0x89 0xfb 0xe8 ........ ........ 0xff 0xff</data> <!-- PUSH RBX; MOV RBX,RDI; CALL -->
<data>0xf3 0x0f 0x1e 0xfa 0x4154 0x55 0100100. 0x89 11......</data> <!-- PUSH R12; PUSH RBP; MOV(R12/3/4/5/xX,RxX); -->
<data>0xf3 0x0f 0x1e 0xfa 0x4154 0x55 0x53 0100100. 0x89 11......</data> <!-- PUSH R12; PUSH RBP; PUSH RBX; MOV(R12/3/4/5/xX,RxX); -->
<!-- ENDBR followed by save registers start sequences -->
<data>0xf3 0x0f 0x1e 0xfa 0x415741564155</data> <!-- PUSH R15; PUSH R14; PUSH R13-->
<data>0xf3 0x0f 0x1e 0xfa 0x41564155</data> <!-- PUSH R14; PUSH R13-->
<data>0xf3 0x0f 0x1e 0xfa 0x41554154</data> <!-- PUSH R13; PUSH R12-->
<data>0xf3 0x0f 0x1e 0xfa 0x41 010101.. 0100100. 0x89 11...... 0x55</data> <!-- PUSH R12/3/4/5; MOV(R12/3/4/5/xX,RxX); PUSH(RBP)-->
<data>0xf3 0x0f 0x1e 0xfa 0x41 010101.. 0x41 010101.. 0100100. 0x89 11...... </data> <!-- PUSH R12/3/4/5; PUSH R12/3/4/5; MOV(R12/3/4/5/xX,RxX); -->
<funcstart/>
</postpatterns>
</patternpairs>
<!-- These are copies of the patterns above with the ENDBR64 pattern pre-pended. If the above are modified, add here as well
with the ENDBR64 specifying a code start.-->
<patternpairs totalbits="40" postbits="24">
<prepatterns>
<data>0x90 0x90</data> <!-- NOP NOP -->
<data>0xc3 0x90</data> <!-- RET NOP -->
<data>0x6690</data> <!-- two-byte nop -->
<data>0xc9 0xc3</data> <!-- LEAVE RET -->
<data>0xe9........</data> <!-- JMP xxx - after a shared jump target -->
<data>0xe9........90</data> <!-- JMP xxx, NOP - after a shared jump target -->
<data>0xeb..</data> <!-- JMP small -->
<data>0xeb..90</data> <!-- JMP small , NOP -->
<data>0x5d 0xc3</data> <!-- POP RBP, RET -->
<data>0x5b 0xc3</data> <!-- POP RBX, RET -->
<data>0x41 010111.. 0xc3</data> <!-- POP R12-15, RET -->
<data>0x31c0 0xc3</data> <!-- XOR(EAX,EAX), RET -->
<data>0x4883c4 ....1000 0xc3</data> <!-- ADD RSP, C; RET -->
<data>0x666690</data> <!-- three-byte NOP -->
<data>0x0f1f00</data> <!-- three-byte NOP -->
<data>0x0f1f4000</data> <!-- four-byte NOP -->
<data>0x0f1f440000</data> <!-- five-byte NOP -->
<data>0x660f1f440000</data> <!-- six-byte NOP -->
<data>0x0f1f8000000000</data> <!-- seven-byte NOP -->
<data>0x0f1f840000000000</data> <!-- eight-byte NOP -->
<data>0x660f1f840000000000</data> <!-- nine-byte NOP -->
</prepatterns>
<postpatterns>
<data>0xf3 0x0f 0x1e 0xfa </data> <!-- ENDBR64 -->
<!-- codestart, but could be an exception handler -->
<codeboundary/>
</postpatterns>
</patternpairs>
<pattern>
<data>0x5589e5</data> <!-- PUSH RBP; MOV(EBP, ESP) (shared objects) -->
<funcstart after="defined" /> <!-- must be something defined right before this, or no memory -->

View file

@ -89,4 +89,17 @@
<data>0xcccc * 0x4c8b 11...100 01001.01 0x89</data> <!-- CC filler : MOV -,RSP : MOV [- + #], -->
<funcstart/>
</pattern>
<pattern> <!-- This can most likely be removed when VS2022 FID files are added __security_check_cookie -->
<data> 01001... 0x3b 0x0d ........ ........ ........ ........
0x75 0x10
01001... 0xc1 0xc1 0x10
0x66 0xf7 0xc1 0xff 0xff
0x75 0x01
0xc3
01001... 0xc1 0xc9 0x10
0xe9 </data>
<align mark="0" bits="3"/>
<funcstart label="__security_check_cookie" validcode="function"/>
</pattern>
</patternlist>

View file

@ -108,9 +108,35 @@
<data>0x5589e5</data> <!-- PUSH EBP : MOV EBP,ESP -->
<data>0x8d 0x4c ..100100 0x04 0x83 0xe4 0xf. </data> <!-- LEA ECX [ESP+4] / AND ESP -->
<data>0x57 0x8d 0x7c ..100100 0x08 0x83 0xe4 0xf. </data> <!-- PUSH EDI / LEA EDI [ESP+8] / AND ESP -->
<!-- ENDBR32 followed by above patterns -->
<data>0xf3 0x0f 0x1e 0xfb 0x5589e5</data> <!-- PUSH EBP : MOV EBP,ESP -->
<data>0xf3 0x0f 0x1e 0xfb 0x8d 0x4c ..100100 0x04 0x83 0xe4 0xf. </data> <!-- LEA ECX [ESP+4] / AND ESP -->
<data>0xf3 0x0f 0x1e 0xfb 0x57 0x8d 0x7c ..100100 0x08 0x83 0xe4 0xf. </data> <!-- PUSH EDI / LEA EDI [ESP+8] / AND ESP -->
<codeboundary/>
<possiblefuncstart/>
</postpatterns>
</patternpairs>
<patternpairs totalbits="32" postbits="16">
<prepatterns>
<data>0x90</data> <!-- NOP filler -->
<data>0xc3</data> <!-- RET -->
<data>0xe9........</data> <!-- JMP big -->
<data>0xeb..</data> <!-- JMP small -->
<data>0x89f6</data> <!-- NOP (MOV ESI,ESI) -->
<data>0x8d7600</data> <!-- NOP (LEA ESI,[ESI]) -->
<data>0x8d742600</data> <!-- NOP (LEA ESI,[ESI]) -->
<data>0x8db600000000</data> <!-- NOP (LEA ESI,[ESI]) -->
<data>0x8dbf00000000</data> <!-- NOP (LEA EDI,[EDI]) -->
<data>0x8dbc2700000000</data> <!-- NOP (LEA EDI,[EDI]) -->
<data>0x8db42600000000</data> <!-- NOP (LEA ESI,[ESI]) -->
</prepatterns>
<postpatterns>
<data>0xf3 0x0f 0x1e 0xfb </data> <!-- ENDBR32 -->
<codeboundary/>
</postpatterns>
</patternpairs>
</patternlist>

View file

@ -6,15 +6,15 @@
0x68......00 <!-- push -->
0xe9......ff <!-- jmp -addr -->
</data> <!-- .plt thunk -->
<funcstart thunk="true" section=".plt"/>
<funcstart thunk="true" section="(?i)(\.plt)"/>
</pattern>
<pattern>
<data>
0xf3 0x0f 0x1e 0x1a <!-- ENDBR64 -->
0xf2 0xff 0x25 .. .. .. .. <!-- jmp -->
0xf3 0x0f 0x1e 0xfa <!-- ENDBR64 -->
0xf2 0xff 0x25 <!-- jmp qword ptr [0xxxx] -->
</data> <!-- .plt thunk -->
<funcstart thunk="true" section=".plt"/>
<funcstart thunk="true" section="(?i)(\.plt(\.sec)?)"/>
</pattern>
</patternlist>

View file

@ -144,4 +144,13 @@
<funcstart label="__break" validcode="function" noreturn="true"/> <!-- must be defined at an existing function -->
</pattern>
<pattern> <!-- This can most likely be removed when VS2022 FID files are added __security_check_cookie -->
<data> 0x3b 0x0d 0x.. 0x.. 0x.. 0x..
0x75 0x01
0xc3
0xe9
</data>
<funcstart label="__security_check_cookie" validcode="function"/>
</pattern>
</patternlist>