diff --git a/Ghidra/Extensions/Jython/src/main/java/ghidra/jython/JythonRun.java b/Ghidra/Extensions/Jython/src/main/java/ghidra/jython/JythonRun.java deleted file mode 100644 index ad2bd4fc2b..0000000000 --- a/Ghidra/Extensions/Jython/src/main/java/ghidra/jython/JythonRun.java +++ /dev/null @@ -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); - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/FindNoReturnFunctionsAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/FindNoReturnFunctionsAnalyzer.java index b2af9b487a..f0840399ca 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/FindNoReturnFunctionsAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/FindNoReturnFunctionsAnalyzer.java @@ -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 { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/CallFixupAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/CallFixupAnalyzer.java index 0d97c586ff..8dd9fbdb8e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/CallFixupAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/CallFixupAnalyzer.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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(); diff --git a/Ghidra/Features/PyGhidra/support/pyghidra_launcher.py b/Ghidra/Features/PyGhidra/support/pyghidra_launcher.py index 61e9706d98..a68bd4e800 100644 --- a/Ghidra/Features/PyGhidra/support/pyghidra_launcher.py +++ b/Ghidra/Features/PyGhidra/support/pyghidra_launcher.py @@ -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 diff --git a/Ghidra/RuntimeScripts/Linux/support/jythonRun b/Ghidra/RuntimeScripts/Linux/support/jythonRun deleted file mode 100755 index 5392a6ee54..0000000000 --- a/Ghidra/RuntimeScripts/Linux/support/jythonRun +++ /dev/null @@ -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 "$@" diff --git a/Ghidra/RuntimeScripts/Windows/support/jythonRun.bat b/Ghidra/RuntimeScripts/Windows/support/jythonRun.bat deleted file mode 100644 index f76fcbab0e..0000000000 --- a/Ghidra/RuntimeScripts/Windows/support/jythonRun.bat +++ /dev/null @@ -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 %* diff --git a/Ghidra/RuntimeScripts/certification.manifest b/Ghidra/RuntimeScripts/certification.manifest index ba6be5caef..fbac4ae1d8 100644 --- a/Ghidra/RuntimeScripts/certification.manifest +++ b/Ghidra/RuntimeScripts/certification.manifest @@ -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|