Merge remote-tracking branch 'origin/Ghidra_11.4'

This commit is contained in:
Ryan Kurtz 2025-05-27 13:06:32 -04:00
commit 3f8fe98862
4 changed files with 55 additions and 7 deletions

View file

@ -16,6 +16,8 @@
package ghidra;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import javax.swing.ToolTipManager;
@ -23,6 +25,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import docking.framework.SplashScreen;
import generic.jar.ResourceFile;
import ghidra.base.help.GhidraHelpService;
import ghidra.framework.Application;
import ghidra.framework.GhidraApplicationConfiguration;
@ -77,6 +80,8 @@ public class GhidraRun implements GhidraLaunchable {
log.info("User temp directory: " + Application.getUserTempDirectory());
log.info("User cache directory: " + Application.getUserCacheDirectory());
writeLastRun();
initializeTooltips();
updateSplashScreenStatusMessage("Populating Ghidra help...");
@ -99,6 +104,22 @@ public class GhidraRun implements GhidraLaunchable {
mainThread.start();
}
private void writeLastRun() {
// Write the Ghidra installation location to the "lastrun" file
File settingsDir = Application.getUserSettingsDirectory();
ResourceFile rootDir = Application.getApplicationRootDirectory();
if (settingsDir != null && rootDir != null) {
File lastRunFile = new File(settingsDir.getParentFile(), "lastrun");
try {
Files.writeString(lastRunFile.toPath(),
rootDir.getParentFile().getCanonicalPath() + "\n");
}
catch (IOException e) {
log.error("Failed to write 'lastrun' file", e);
}
}
}
private String processArguments(String[] args) {
//TODO remove this special handling when possible
if (args.length == 1 && (args[0].startsWith("-D") || args[0].indexOf(" -D") >= 0)) {

View file

@ -55,7 +55,7 @@ def start(verbose=False, *, install_dir: Path = None) -> "PyGhidraLauncher":
:param verbose: Enable verbose output during JVM startup (Defaults to False)
:param install_dir: The path to the Ghidra installation directory.
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
(Defaults to the GHIDRA_INSTALL_DIR environment variable or "lastrun" file)
:return: The PyGhidraLauncher used to start the JVM
"""
```
@ -222,7 +222,7 @@ def run_script(
This may be either a Java class or its path. (Defaults to None)
:param install_dir: The path to the Ghidra installation directory. This parameter is only
used if Ghidra has not been started yet.
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
(Defaults to the GHIDRA_INSTALL_DIR environment variable or "lastrun" file)
:param program_name: The name of the program to open in Ghidra.
(Defaults to None, which results in the name being derived from "binary_path")
:param nested_project_location: If True, assumes "project_location" contains an extra nested
@ -330,6 +330,10 @@ __2.2.0:__
[`pyghidra.run_script()`](#pyghidrarun_script) now accept a `nested_project_location` parameter
which can be set to `False` to open existing Ghidra projects that were created with the
Ghidra GUI.
* If a Ghidra installation directory is not specified by the `install_dir` parameter or
`GHIDRA_INSTALL_DIR` environment variable, PyGhidra will look for a `lastrun` file in the
Ghidra user settings parent directory, and use the installation directory it specifies. The
`lastrun` file is created by Ghidra 11.4 and later.
__2.1.0:__
* [`pyghidra.open_program()`](#pyghidraopen_program) now accepts a `program_name` parameter, which

View file

@ -33,7 +33,7 @@ def start(verbose=False, *, install_dir: Path = None) -> "PyGhidraLauncher":
:param verbose: Enable verbose output during JVM startup (Defaults to False)
:param install_dir: The path to the Ghidra installation directory.
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
(Defaults to the GHIDRA_INSTALL_DIR environment variable or "lastrun" file)
:return: The PyGhidraLauncher used to start the JVM
"""
from pyghidra.launcher import HeadlessPyGhidraLauncher
@ -302,7 +302,7 @@ def _flat_api(
This may be either a Java class or its path. (Defaults to None)
:param install_dir: The path to the Ghidra installation directory. This parameter is only
used if Ghidra has not been started yet.
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
(Defaults to the GHIDRA_INSTALL_DIR environment variable or "lastrun" file)
:raises ValueError: If the provided language, compiler or loader is invalid.
:raises TypeError: If the provided loader does not implement `ghidra.app.util.opinion.Loader`.
"""
@ -378,7 +378,7 @@ def run_script(
This may be either a Java class or its path. (Defaults to None)
:param install_dir: The path to the Ghidra installation directory. This parameter is only
used if Ghidra has not been started yet.
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
(Defaults to the GHIDRA_INSTALL_DIR environment variable or "lastrun" file)
:param program_name: The name of the program to open in Ghidra.
(Defaults to None, which results in the name being derived from "binary_path")
:param nested_project_location: If True, assumes "project_location" contains an extra nested

View file

@ -152,6 +152,29 @@ def _plugin_lock():
# it will be removed by said process when done
pass
def _lastrun() -> Path:
lastrun_file: Path = None
lastrun_rel: Path = Path('ghidra/lastrun')
# Check for XDG_CONFIG_HOME environment variable
xdg_config_home: str = os.environ.get('XDG_CONFIG_HOME')
if xdg_config_home:
lastrun_file = Path(xdg_config_home) / lastrun_rel
else:
# Default to platform-specific locations
if platform.system() == 'Windows':
lastrun_file = Path(os.environ['APPDATA']) / lastrun_rel
elif platform.system() == 'Darwin':
lastrun_file = Path.home() / 'Library' / lastrun_rel
else:
lastrun_file = Path.home() / '.config' / lastrun_rel
if lastrun_file is not None and lastrun_file.is_file():
with open(lastrun_file, "r") as file:
return Path(file.readline().strip())
return None
class PyGhidraLauncher:
"""
@ -164,7 +187,7 @@ class PyGhidraLauncher:
:param verbose: True to enable verbose output when starting Ghidra.
:param install_dir: Ghidra installation directory.
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
(Defaults to the GHIDRA_INSTALL_DIR environment variable or "lastrun" file)
:raises ValueError: If the Ghidra installation directory is invalid.
"""
self._layout = None
@ -173,7 +196,7 @@ class PyGhidraLauncher:
self._dev_mode = False
self._extension_path = None
install_dir = install_dir or os.getenv("GHIDRA_INSTALL_DIR")
install_dir = install_dir or os.getenv("GHIDRA_INSTALL_DIR") or _lastrun()
self._install_dir = self._validate_install_dir(install_dir)
java_home_override = os.getenv("JAVA_HOME_OVERRIDE")