Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz
2026-05-14 10:47:19 -04:00
7 changed files with 37 additions and 159 deletions
@@ -1,65 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.jython;
import java.io.IOException;
import org.python.util.jython;
import ghidra.GhidraApplicationLayout;
import ghidra.GhidraLaunchable;
import ghidra.framework.*;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
/**
* Launcher entry point for running Ghidra from within Jython.
*/
public class JythonRun implements GhidraLaunchable {
@Override
public void launch(GhidraApplicationLayout layout, String[] args) {
// Initialize the application
ApplicationConfiguration configuration = new HeadlessGhidraApplicationConfiguration();
Application.initializeApplication(layout, configuration);
// Setup jython home directory
try {
JythonUtils.setupJythonHomeDir();
}
catch (IOException e) {
Msg.showError(JythonRun.class, null, "Jython home directory", e.getMessage());
System.exit(1);
}
// Setup jython cache directory
try {
JythonUtils.setupJythonCacheDir(configuration.getTaskMonitor());
}
catch (IOException e) {
Msg.showError(JythonRun.class, null, "Jython cache directory", e.getMessage());
System.exit(1);
}
catch (CancelledException e) {
Msg.showError(JythonRun.class, null, "Operation cancelled", e.getMessage());
System.exit(1);
}
// Pass control to Jython
jython.main(args);
}
}
@@ -89,7 +89,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
public FindNoReturnFunctionsAnalyzer(String name, String description,
AnalyzerType analyzerType) {
super(name, description, analyzerType);
setPriority(AnalysisPriority.DISASSEMBLY.after());
setPriority(AnalysisPriority.DISASSEMBLY.after().after());
setSupportsOneTimeAnalysis();
}
@@ -373,6 +373,13 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
}
for (Address target : flows) {
// Skip targets that have a callfixup with fall-through semantics.
// A fall-through callfixup explicitly models the function's return
// behavior, so heuristic evidence should not override it.
if (hasCallFixupWithFallThrough(cp, target)) {
continue;
}
int count = 1;
ReferenceIterator refsTo = cp.getReferenceManager().getReferencesTo(target);
for (Reference reference : refsTo) {
@@ -421,6 +428,30 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
return hadSuspiciousFunctions;
}
/**
* Check if the function at the given address has a callfixup that falls through.
* A fall-through callfixup explicitly models the function's return behavior
* (e.g., Watcom's __CHK/__STK stack-check functions), so heuristic noreturn
* detection should not override it.
*
* @param cp current program
* @param target address of the potential noreturn function
* @return true if the function has a callfixup with fall-through semantics
*/
private boolean hasCallFixupWithFallThrough(Program cp, Address target) {
Function func = cp.getFunctionManager().getFunctionAt(target);
if (func == null) {
return false;
}
String callFixup = func.getCallFixup();
if (callFixup == null || callFixup.isEmpty()) {
return false;
}
PcodeInjectLibrary lib = cp.getCompilerSpec().getPcodeInjectLibrary();
InjectPayload payload = lib.getPayload(InjectPayload.CALLFIXUP_TYPE, callFixup);
return payload != null && payload.isFallThru();
}
private boolean targetOnlyCallsNoReturn(Program cp, Address target, AddressSet noReturnSet)
throws CancelledException {
@@ -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.
@@ -47,7 +47,7 @@ public class CallFixupAnalyzer extends AbstractAnalyzer {
public CallFixupAnalyzer(String name, AnalyzerType analyzerType,
boolean supportsOneTimeAnalysis) {
super(name, DESCRIPTION, analyzerType);
setPriority(AnalysisPriority.DISASSEMBLY.after().after());
setPriority(AnalysisPriority.DISASSEMBLY.after());
setDefaultEnablement(true);
if (supportsOneTimeAnalysis) {
setSupportsOneTimeAnalysis();
@@ -104,6 +104,8 @@ def find_supported_python_exe(install_dir: Path, dev: bool) -> List[str]:
return cmd
except FileNotFoundError:
pass
except NotADirectoryError:
pass
return None
@@ -1,41 +0,0 @@
#!/usr/bin/env bash
#----------------------------------------
# Ghidra Jython launch
#----------------------------------------
# Optionally override the default Java heap memory, which is typically 1/4 of system RAM.
# Supported values are of the regular expression form "\d+[gGmMkK]", allowing the value to be
# specified in gigabytes, megabytes, or kilobytes (for example: 8G, 4096m, etc).
MAXMEM_DEFAULT=
# Allow the above MAXMEM_DEFAULT to be overridden by externally set environment variables
# - GHIDRA_MAXMEM: Desired maximum heap memory for all Ghidra instances
# - GHIDRA_JYTHON_MAXMEM: Desired maximum heap memory only for Ghidra Jython instances
GHIDRA_MAXMEM=${GHIDRA_MAXMEM:=${MAXMEM_DEFAULT}}
GHIDRA_JYTHON_MAXMEM=${GHIDRA_JYTHON_MAXMEM:=${GHIDRA_MAXMEM}}
# Limit the # of garbage collection and JIT compiler threads in case many python
# instances are run in parallel. By default, Java will assign one thread per core
# which does not scale well on servers with many cores.
VMARG_LIST="-XX:ParallelGCThreads=2 -XX:CICompilerCount=2 -Djava.awt.headless=true"
# Apply Java options from externally set environment variables
VMARG_LIST="${VMARG_LIST} ${GHIDRA_JAVA_OPTIONS} ${GHIDRA_JYTHON_JAVA_OPTIONS}"
# Launch mode can be changed to one of the following: fg, debug, debug-suspend
LAUNCH_MODE=fg
# Set the debug address to listen on.
# NOTE: This variable is ignored if not launching in a debugging mode.
DEBUG_ADDRESS=127.0.0.1:13002
# Resolve symbolic link if present and get the directory this script lives in.
# NOTE: "readlink -f" is best but works on Linux only, "readlink" will only work if your PWD
# contains the link you are calling (which is the best we can do on macOS), and the "echo" is the
# fallback, which doesn't attempt to do anything with links.
SCRIPT_FILE="$(readlink -f "$0" 2>/dev/null || readlink "$0" 2>/dev/null || echo "$0")"
SCRIPT_DIR="$(dirname -- "$SCRIPT_FILE")"
# Launch Ghidra Jython
# DEBUG_ADDRESS set via environment for launch.sh
DEBUG_ADDRESS=${DEBUG_ADDRESS} "${SCRIPT_DIR}"/launch.sh "${LAUNCH_MODE}" jdk "Ghidra-Jython" "${GHIDRA_JYTHON_MAXMEM}" "${VMARG_LIST}" ghidra.jython.JythonRun "$@"
@@ -1,48 +0,0 @@
:: ###
:: IP: GHIDRA
::
:: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License.
:: You may obtain a copy of the License at
::
:: http://www.apache.org/licenses/LICENSE-2.0
::
:: Unless required by applicable law or agreed to in writing, software
:: distributed under the License is distributed on an "AS IS" BASIS,
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
:: See the License for the specific language governing permissions and
:: limitations under the License.
:: ##
:: Ghidra jython launch
@echo off
setlocal
:: Optionally override the default Java heap memory, which is typically 1/4 of system RAM.
:: Supported values are of the regular expression form "\d+[gGmMkK]", allowing the value to be
:: specified in gigabytes, megabytes, or kilobytes (for example: 8G, 4096m, etc).
set MAXMEM_DEFAULT=
:: Allow the above MAXMEM_DEFAULT to be overridden by externally set environment variables
:: - GHIDRA_MAXMEM: Desired maximum heap memory for all Ghidra instances
:: - GHIDRA_JYTHON_MAXMEM: Desired maximum heap memory only for Ghidra Jython instances
if not defined GHIDRA_MAXMEM set "GHIDRA_MAXMEM=%MAXMEM_DEFAULT%"
if not defined GHIDRA_JYTHON_MAXMEM set "GHIDRA_JYTHON_MAXMEM=%GHIDRA_MAXMEM%"
:: Limit the # of garbage collection and JIT compiler threads in case many headless
:: instances are run in parallel. By default, Java will assign one thread per core
:: which does not scale well on servers with many cores.
set VMARG_LIST=-XX:ParallelGCThreads=2 -XX:CICompilerCount=2
:: Apply Java options from externally set environment variables
set VMARG_LIST=%VMARG_LIST% %GHIDRA_JAVA_OPTIONS% %GHIDRA_JYTHON_JAVA_OPTIONS%
:: Launch mode can be changed to one of the following:
:: fg, debug, debug-suspend
set LAUNCH_MODE=fg
:: Set the debug address to listen on.
:: NOTE: This variable is ignored if not launching in a debugging mode.
set DEBUG_ADDRESS=127.0.0.1:13002
call "%~dp0launch.bat" %LAUNCH_MODE% jdk Ghidra-Jython "%GHIDRA_JYTHON_MAXMEM%" "%VMARG_LIST%" ghidra.jython.JythonRun %*
@@ -26,7 +26,6 @@ Linux/support/convertStorage||GHIDRA||||END|
Linux/support/ghidraClean||GHIDRA||||END|
Linux/support/ghidraDebug||GHIDRA||||END|
Linux/support/jshellRun||GHIDRA||||END|
Linux/support/jythonRun||GHIDRA||||END|
Linux/support/pyghidraRun||GHIDRA||||END|
Linux/support/sleigh||GHIDRA||||END|
Windows/support/README_createPdbXmlFiles.txt||GHIDRA||||END|