mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-5138: GhidraDev/PyDev/PyGhidra integration
This commit is contained in:
parent
7c4d91f568
commit
31ee251a5c
35 changed files with 1300 additions and 315 deletions
|
@ -898,6 +898,7 @@ src/main/resources/images/pencil16.png||GHIDRA||||END|
|
||||||
src/main/resources/images/pin.png||GHIDRA||||END|
|
src/main/resources/images/pin.png||GHIDRA||||END|
|
||||||
src/main/resources/images/play_again.png||GHIDRA||||END|
|
src/main/resources/images/play_again.png||GHIDRA||||END|
|
||||||
src/main/resources/images/preferences-system.png||Tango Icons - Public Domain|||tango|END|
|
src/main/resources/images/preferences-system.png||Tango Icons - Public Domain|||tango|END|
|
||||||
|
src/main/resources/images/python.png||GHIDRA||||END|
|
||||||
src/main/resources/images/question_zero.png||GHIDRA||||END|
|
src/main/resources/images/question_zero.png||GHIDRA||||END|
|
||||||
src/main/resources/images/red-cross.png||GHIDRA||||END|
|
src/main/resources/images/red-cross.png||GHIDRA||||END|
|
||||||
src/main/resources/images/redQuestionMark.png||GHIDRA||||END|
|
src/main/resources/images/redQuestionMark.png||GHIDRA||||END|
|
||||||
|
|
BIN
Ghidra/Features/Base/src/main/resources/images/python.png
Normal file
BIN
Ghidra/Features/Base/src/main/resources/images/python.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 72 KiB |
|
@ -160,11 +160,14 @@ class PyGhidraLauncher:
|
||||||
install_dir = install_dir or os.getenv("GHIDRA_INSTALL_DIR")
|
install_dir = install_dir or os.getenv("GHIDRA_INSTALL_DIR")
|
||||||
self._install_dir = self._validate_install_dir(install_dir)
|
self._install_dir = self._validate_install_dir(install_dir)
|
||||||
|
|
||||||
|
java_home_override = os.getenv("JAVA_HOME_OVERRIDE")
|
||||||
|
if java_home_override:
|
||||||
|
self._java_home = java_home_override
|
||||||
|
|
||||||
# check if we are in the ghidra source tree
|
# check if we are in the ghidra source tree
|
||||||
support = Path(install_dir) / "support"
|
support = Path(install_dir) / "support"
|
||||||
if not support.exists():
|
if not support.exists():
|
||||||
self._dev_mode = True
|
self._dev_mode = True
|
||||||
self._java_home = os.getenv("JAVA_HOME_OVERRIDE")
|
|
||||||
|
|
||||||
self._plugins: List[Tuple[Path, ExtensionDetails]] = []
|
self._plugins: List[Tuple[Path, ExtensionDetails]] = []
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
|
@ -469,7 +472,7 @@ class PyGhidraLauncher:
|
||||||
self._pre_launch_init()
|
self._pre_launch_init()
|
||||||
self._launch()
|
self._launch()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._report_fatal_error("An error occured launching Ghidra", str(e), e)
|
self._report_fatal_error("An error occurred launching Ghidra", str(e), e)
|
||||||
|
|
||||||
def get_install_path(self, plugin_name: str) -> Path:
|
def get_install_path(self, plugin_name: str) -> Path:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<feature
|
<feature
|
||||||
id="ghidra.ghidradev"
|
id="ghidra.ghidradev"
|
||||||
label="GhidraDev"
|
label="GhidraDev"
|
||||||
version="4.0.1.qualifier"
|
version="5.0.0.qualifier"
|
||||||
provider-name="Ghidra">
|
provider-name="Ghidra">
|
||||||
|
|
||||||
<description>
|
<description>
|
||||||
|
|
|
@ -167,7 +167,9 @@
|
||||||
<setEntry value="com.google.guava.failureaccess@default:default"/>
|
<setEntry value="com.google.guava.failureaccess@default:default"/>
|
||||||
<setEntry value="com.google.guava@default:default"/>
|
<setEntry value="com.google.guava@default:default"/>
|
||||||
<setEntry value="com.ibm.icu@default:default"/>
|
<setEntry value="com.ibm.icu@default:default"/>
|
||||||
<setEntry value="com.python.pydev.analysis*6.3.1.201802272029@default:default"/>
|
<setEntry value="com.python.pydev.analysis*9.3.0.202203051235@default:default"/>
|
||||||
|
<setEntry value="com.python.pydev.debug*9.3.0.202203051235@default:default"/>
|
||||||
|
<setEntry value="com.python.pydev.refactoring*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="com.sun.el.javax.el@default:default"/>
|
<setEntry value="com.sun.el.javax.el@default:default"/>
|
||||||
<setEntry value="com.sun.jna.platform@default:default"/>
|
<setEntry value="com.sun.jna.platform@default:default"/>
|
||||||
<setEntry value="com.sun.jna@default:default"/>
|
<setEntry value="com.sun.jna@default:default"/>
|
||||||
|
@ -176,7 +178,6 @@
|
||||||
<setEntry value="jakarta.inject.jakarta.inject-api*1.0.5@default:default"/>
|
<setEntry value="jakarta.inject.jakarta.inject-api*1.0.5@default:default"/>
|
||||||
<setEntry value="jakarta.inject.jakarta.inject-api*2.0.1@default:default"/>
|
<setEntry value="jakarta.inject.jakarta.inject-api*2.0.1@default:default"/>
|
||||||
<setEntry value="jakarta.servlet-api@default:default"/>
|
<setEntry value="jakarta.servlet-api@default:default"/>
|
||||||
<setEntry value="javax.xml@default:default"/>
|
|
||||||
<setEntry value="jaxen@default:default"/>
|
<setEntry value="jaxen@default:default"/>
|
||||||
<setEntry value="org.apache.aries.spifly.dynamic.bundle@default:default"/>
|
<setEntry value="org.apache.aries.spifly.dynamic.bundle@default:default"/>
|
||||||
<setEntry value="org.apache.batik.constants@default:default"/>
|
<setEntry value="org.apache.batik.constants@default:default"/>
|
||||||
|
@ -202,6 +203,8 @@
|
||||||
<setEntry value="org.apache.xml.resolver@default:default"/>
|
<setEntry value="org.apache.xml.resolver@default:default"/>
|
||||||
<setEntry value="org.apache.xml.serializer@default:default"/>
|
<setEntry value="org.apache.xml.serializer@default:default"/>
|
||||||
<setEntry value="org.apache.xmlgraphics@default:default"/>
|
<setEntry value="org.apache.xmlgraphics@default:default"/>
|
||||||
|
<setEntry value="org.commonmark-gfm-tables@default:default"/>
|
||||||
|
<setEntry value="org.commonmark@default:default"/>
|
||||||
<setEntry value="org.eclipse.ant.core@default:default"/>
|
<setEntry value="org.eclipse.ant.core@default:default"/>
|
||||||
<setEntry value="org.eclipse.buildship.compat@default:default"/>
|
<setEntry value="org.eclipse.buildship.compat@default:default"/>
|
||||||
<setEntry value="org.eclipse.buildship.core@default:default"/>
|
<setEntry value="org.eclipse.buildship.core@default:default"/>
|
||||||
|
@ -296,7 +299,7 @@
|
||||||
<setEntry value="org.eclipse.help.base@default:default"/>
|
<setEntry value="org.eclipse.help.base@default:default"/>
|
||||||
<setEntry value="org.eclipse.help.ui@default:default"/>
|
<setEntry value="org.eclipse.help.ui@default:default"/>
|
||||||
<setEntry value="org.eclipse.help@default:default"/>
|
<setEntry value="org.eclipse.help@default:default"/>
|
||||||
<setEntry value="org.eclipse.jdt.annotation*2.3.0.v20240111-2306@default:default"/>
|
<setEntry value="org.eclipse.jdt.annotation@default:default"/>
|
||||||
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
|
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
|
||||||
<setEntry value="org.eclipse.jdt.core.manipulation@default:default"/>
|
<setEntry value="org.eclipse.jdt.core.manipulation@default:default"/>
|
||||||
<setEntry value="org.eclipse.jdt.core@default:default"/>
|
<setEntry value="org.eclipse.jdt.core@default:default"/>
|
||||||
|
@ -308,10 +311,11 @@
|
||||||
<setEntry value="org.eclipse.jdt.launching@default:default"/>
|
<setEntry value="org.eclipse.jdt.launching@default:default"/>
|
||||||
<setEntry value="org.eclipse.jdt.ui@default:default"/>
|
<setEntry value="org.eclipse.jdt.ui@default:default"/>
|
||||||
<setEntry value="org.eclipse.jem.util@default:default"/>
|
<setEntry value="org.eclipse.jem.util@default:default"/>
|
||||||
|
<setEntry value="org.eclipse.jetty.ee10.servlet@default:default"/>
|
||||||
|
<setEntry value="org.eclipse.jetty.ee10.webapp@default:default"/>
|
||||||
<setEntry value="org.eclipse.jetty.ee8.security@default:default"/>
|
<setEntry value="org.eclipse.jetty.ee8.security@default:default"/>
|
||||||
<setEntry value="org.eclipse.jetty.ee8.server@default:default"/>
|
<setEntry value="org.eclipse.jetty.ee8.server@default:default"/>
|
||||||
<setEntry value="org.eclipse.jetty.ee8.servlet@default:default"/>
|
<setEntry value="org.eclipse.jetty.ee8.servlet@default:default"/>
|
||||||
<setEntry value="org.eclipse.jetty.ee8.webapp@default:default"/>
|
|
||||||
<setEntry value="org.eclipse.jetty.ee@default:default"/>
|
<setEntry value="org.eclipse.jetty.ee@default:default"/>
|
||||||
<setEntry value="org.eclipse.jetty.http@default:default"/>
|
<setEntry value="org.eclipse.jetty.http@default:default"/>
|
||||||
<setEntry value="org.eclipse.jetty.io@default:default"/>
|
<setEntry value="org.eclipse.jetty.io@default:default"/>
|
||||||
|
@ -414,14 +418,19 @@
|
||||||
<setEntry value="org.osgi.util.position@default:default"/>
|
<setEntry value="org.osgi.util.position@default:default"/>
|
||||||
<setEntry value="org.osgi.util.promise@default:default"/>
|
<setEntry value="org.osgi.util.promise@default:default"/>
|
||||||
<setEntry value="org.osgi.util.xml@default:default"/>
|
<setEntry value="org.osgi.util.xml@default:default"/>
|
||||||
<setEntry value="org.python.pydev*6.3.1.201802272029@default:default"/>
|
<setEntry value="org.python.pydev*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="org.python.pydev.ast*6.3.1.201802272029@default:default"/>
|
<setEntry value="org.python.pydev.ast*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="org.python.pydev.core*6.3.1.201802272029@default:default"/>
|
<setEntry value="org.python.pydev.core*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="org.python.pydev.jython*6.3.1.201802272029@default:default"/>
|
<setEntry value="org.python.pydev.customizations*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="org.python.pydev.parser*6.3.1.201802272029@default:default"/>
|
<setEntry value="org.python.pydev.debug*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="org.python.pydev.shared_core*6.3.1.201802272029@default:default"/>
|
<setEntry value="org.python.pydev.django*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="org.python.pydev.shared_interactive_console*6.3.1.201802272029@default:default"/>
|
<setEntry value="org.python.pydev.help*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="org.python.pydev.shared_ui*6.3.1.201802272029@default:default"/>
|
<setEntry value="org.python.pydev.jython*9.3.0.202203051235@default:default"/>
|
||||||
|
<setEntry value="org.python.pydev.parser*9.3.0.202203051235@default:default"/>
|
||||||
|
<setEntry value="org.python.pydev.refactoring*9.3.0.202203051235@default:default"/>
|
||||||
|
<setEntry value="org.python.pydev.shared_core*9.3.0.202203051235@default:default"/>
|
||||||
|
<setEntry value="org.python.pydev.shared_interactive_console*9.3.0.202203051235@default:default"/>
|
||||||
|
<setEntry value="org.python.pydev.shared_ui*9.3.0.202203051235@default:default"/>
|
||||||
<setEntry value="org.sat4j.core@default:default"/>
|
<setEntry value="org.sat4j.core@default:default"/>
|
||||||
<setEntry value="org.sat4j.pb@default:default"/>
|
<setEntry value="org.sat4j.pb@default:default"/>
|
||||||
<setEntry value="org.tukaani.xz@default:default"/>
|
<setEntry value="org.tukaani.xz@default:default"/>
|
||||||
|
@ -430,7 +439,7 @@
|
||||||
<setAttribute key="selected_workspace_bundles">
|
<setAttribute key="selected_workspace_bundles">
|
||||||
<setEntry value="ghidra.ghidradev@default:default"/>
|
<setEntry value="ghidra.ghidradev@default:default"/>
|
||||||
</setAttribute>
|
</setAttribute>
|
||||||
<booleanAttribute key="show_selected_only" value="true"/>
|
<booleanAttribute key="show_selected_only" value="false"/>
|
||||||
<booleanAttribute key="tracing" value="false"/>
|
<booleanAttribute key="tracing" value="false"/>
|
||||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||||
<booleanAttribute key="useDefaultConfig" value="true"/>
|
<booleanAttribute key="useDefaultConfig" value="true"/>
|
||||||
|
|
|
@ -3,7 +3,7 @@ Manifest-Version: 1.0
|
||||||
Bundle-ManifestVersion: 2
|
Bundle-ManifestVersion: 2
|
||||||
Bundle-Name: GhidraDev
|
Bundle-Name: GhidraDev
|
||||||
Bundle-SymbolicName: ghidra.ghidradev;singleton:=true
|
Bundle-SymbolicName: ghidra.ghidradev;singleton:=true
|
||||||
Bundle-Version: 4.0.1.qualifier
|
Bundle-Version: 5.0.0.qualifier
|
||||||
Bundle-Activator: ghidradev.Activator
|
Bundle-Activator: ghidradev.Activator
|
||||||
Require-Bundle: org.eclipse.ant.core;bundle-version="3.7.200",
|
Require-Bundle: org.eclipse.ant.core;bundle-version="3.7.200",
|
||||||
org.eclipse.buildship.core;bundle-version="3.1.8",
|
org.eclipse.buildship.core;bundle-version="3.1.8",
|
||||||
|
@ -21,10 +21,11 @@ Require-Bundle: org.eclipse.ant.core;bundle-version="3.7.200",
|
||||||
org.eclipse.ltk.core.refactoring;bundle-version="3.14.200",
|
org.eclipse.ltk.core.refactoring;bundle-version="3.14.200",
|
||||||
org.eclipse.ui;bundle-version="3.205.0",
|
org.eclipse.ui;bundle-version="3.205.0",
|
||||||
org.eclipse.ui.ide;bundle-version="3.22.0",
|
org.eclipse.ui.ide;bundle-version="3.22.0",
|
||||||
com.python.pydev.debug;bundle-version="6.3.1";resolution:=optional,
|
com.python.pydev.debug;bundle-version="9.3.0";resolution:=optional,
|
||||||
org.python.pydev;bundle-version="[6.3.1,10.0.0)";resolution:=optional,
|
org.python.pydev;bundle-version="9.3.0";resolution:=optional,
|
||||||
org.python.pydev.core;bundle-version="[6.3.1,10.0.0)";resolution:=optional,
|
org.python.pydev.core;bundle-version="9.3.0";resolution:=optional,
|
||||||
org.python.pydev.ast;bundle-version="[6.3.1,10.0.0)";resolution:=optional,
|
org.python.pydev.ast;bundle-version="9.3.0";resolution:=optional,
|
||||||
|
org.python.pydev.debug;bundle-version="9.3.0";resolution:=optional,
|
||||||
org.eclipse.cdt.core;bundle-version="5.9.1";resolution:=optional,
|
org.eclipse.cdt.core;bundle-version="5.9.1";resolution:=optional,
|
||||||
org.eclipse.cdt.ui;bundle-version="5.9.0";resolution:=optional
|
org.eclipse.cdt.ui;bundle-version="5.9.0";resolution:=optional
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# GhidraDev Eclipse Plugin
|
# GhidraDev Eclipse Plugin
|
||||||
GhidraDev provides support for developing and debugging Ghidra scripts and modules in Eclipse.
|
GhidraDev provides support for developing and debugging Ghidra scripts and modules in Eclipse.
|
||||||
|
|
||||||
The information provided in this document is effective as of GhidraDev 4.0.0 and is subject to
|
The information provided in this document is effective as of GhidraDev 5.0.0 and is subject to
|
||||||
change with future releases.
|
change with future releases.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
@ -31,6 +31,9 @@ change with future releases.
|
||||||
12. [Building](#building)
|
12. [Building](#building)
|
||||||
|
|
||||||
## Change History
|
## Change History
|
||||||
|
__5.0.0:__
|
||||||
|
* Added support for PyGhidra.
|
||||||
|
|
||||||
__4.0.1:__
|
__4.0.1:__
|
||||||
* New Ghidra module projects now contain a default `README.md` file.
|
* New Ghidra module projects now contain a default `README.md` file.
|
||||||
* Fixed a bug that prevented an imported module source project from being discovered by Ghidra when
|
* Fixed a bug that prevented an imported module source project from being discovered by Ghidra when
|
||||||
|
@ -132,7 +135,7 @@ __1.0.1:__
|
||||||
* Ghidra 11.2 or later
|
* Ghidra 11.2 or later
|
||||||
|
|
||||||
## Optional Requirements
|
## Optional Requirements
|
||||||
* PyDev 6.3.1 - 9.3.0 ([more info](#pydev-support))
|
* PyDev 9.3.0 or later ([more info](#pydev-support))
|
||||||
* Gradle - required version(s) specified by linked Ghidra release
|
* Gradle - required version(s) specified by linked Ghidra release
|
||||||
([more info](#export-ghidra-module-extension))
|
([more info](#export-ghidra-module-extension))
|
||||||
|
|
||||||
|
@ -268,7 +271,10 @@ Ghidra from Eclipse independent of a project is not supported.
|
||||||
|
|
||||||
## PyDev Support
|
## PyDev Support
|
||||||
GhidraDev is able to integrate with PyDev to conveniently configure Python support into Ghidra
|
GhidraDev is able to integrate with PyDev to conveniently configure Python support into Ghidra
|
||||||
script and module projects.
|
script and module projects. GhidraDev supports both Jython and PyGhidra Python implementations.
|
||||||
|
|
||||||
|
__NOTE:__ PyDev discontinued Jython 2 support in version 10.0.0. If you want to use GhidraDev with
|
||||||
|
Jython, you must use __PyDev 9.3.0__. The latest vesions of PyDev support PyGhidra.
|
||||||
|
|
||||||
### Installing PyDev
|
### Installing PyDev
|
||||||
From Eclipse:
|
From Eclipse:
|
||||||
|
@ -293,13 +299,19 @@ GhidraDev can add Python support to a Ghidra project when:
|
||||||
* Creating a new Ghidra script project
|
* Creating a new Ghidra script project
|
||||||
* Linking a Ghidra installation to an existing Java project
|
* Linking a Ghidra installation to an existing Java project
|
||||||
|
|
||||||
In order for GhidraDev to add in Python support, PyDev must have a Jython interpreter configured.
|
In order for GhidraDev to add in Python support, PyDev must have a PyGhidra or Jython interpreter
|
||||||
GhidraDev will present a list of detected Jython interpreters that it found in PyDev's preferences.
|
configured. GhidraDev will present a list of detected PyGhidra/Jython interpreters that it found in
|
||||||
If no Jython interpreters were found, one can be added from GhidraDev by clicking the `+` icon.
|
PyDev's preferences. If no interpreters were found, one can be added from GhidraDev by clicking
|
||||||
When the `+` icon is clicked, GhidraDev will attempt to find the Jython interpreter bundled with the
|
the `+` icons.
|
||||||
selected Ghidra installation and automatically configure PyDev to use it. If for some reason
|
|
||||||
GhidraDev was unable to find a Jython interpreter in the Ghidra installation, one will have to be
|
When the Jython `+` icon is clicked, GhidraDev will attempt to find the Jython interpreter bundled
|
||||||
added manually in the PyDev preferences.
|
with the selected Ghidra installation and automatically configure PyDev to use it. If for some
|
||||||
|
reason GhidraDev was unable to find a Jython interpreter in the Ghidra installation, one will have
|
||||||
|
to be added manually in the PyDev preferences.
|
||||||
|
|
||||||
|
When the PyGhidra `+` icon is clicked, GhidraDev will attempt to find the PyGhidra interpreter
|
||||||
|
that was last used to launch PyGhidra. If it cannot find it, you will have to launch PyGhidra
|
||||||
|
and try again.
|
||||||
|
|
||||||
## Upgrading
|
## Upgrading
|
||||||
GhidraDev is upgraded differently depending on how it was installed. If GhidraDev was
|
GhidraDev is upgraded differently depending on how it was installed. If GhidraDev was
|
||||||
|
@ -347,9 +359,6 @@ installation directory.
|
||||||
to your Ghidra module project, which automatically happens when the project is created.
|
to your Ghidra module project, which automatically happens when the project is created.
|
||||||
Simply [relink](#link-ghidra) your Ghidra installation to the project, and your project will
|
Simply [relink](#link-ghidra) your Ghidra installation to the project, and your project will
|
||||||
pick up any newly discovered Ghidra extensions.
|
pick up any newly discovered Ghidra extensions.
|
||||||
* __Why doesn't GhidraDev support PyDev 10.0 or later?__
|
|
||||||
* PyDev dropped support for Python 2 in their 10.0 release. Ghidra currently does not support
|
|
||||||
Python 3.
|
|
||||||
|
|
||||||
## Additional Resources
|
## Additional Resources
|
||||||
For more information on the GhidraDev plugin and developing for Ghidra in an Eclipse environment,
|
For more information on the GhidraDev plugin and developing for Ghidra in an Eclipse environment,
|
||||||
|
@ -358,14 +367,14 @@ at `<GhidraInstallDir>/docs/GhidraClass/Intermediate/Scripting.html`.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
GhidraDev is currently built from Eclipse and distributed with Ghidra manually. Ideally we will use
|
GhidraDev is currently built from Eclipse and distributed with Ghidra manually. Ideally we will use
|
||||||
Gradle one day, but we aren't there yet. We do rely on `gradle prepDev` to generate the Eclipse
|
Gradle one day, but we aren't there yet. We do rely on Gradle to generate the Eclipse project and
|
||||||
project and build GhidraDev's dependencies though.
|
build GhidraDev's dependencies though.
|
||||||
|
|
||||||
__NOTE:__ Only "Eclipse for RCP and RAP Developers" has the ability to do the below instructions.
|
__NOTE:__ Only "Eclipse for RCP and RAP Developers" has the ability to do the below instructions.
|
||||||
The following instructions assume that you are using this version of Eclipse.
|
The following instructions assume that you are using this version of Eclipse.
|
||||||
|
|
||||||
#### Importing GhidraDev Eclipse projects (they are deactivated by default):
|
#### Importing GhidraDev Eclipse projects (they are deactivated by default):
|
||||||
1. Run `gradle eclipse -PeclipsePDE`
|
1. Run `gradle prepGhidraDev eclipse -PeclipsePDE`
|
||||||
2. From Eclipse, `File -> Import -> General -> Existing Projects into Workspace`
|
2. From Eclipse, `File -> Import -> General -> Existing Projects into Workspace`
|
||||||
3. From the ghidra repo, import `Eclipse GhidraDevFeature` and `Eclipse GhidraDevPlugin`
|
3. From the ghidra repo, import `Eclipse GhidraDevFeature` and `Eclipse GhidraDevPlugin`
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,8 @@ task pyDevUnpack(type:Copy) {
|
||||||
!pyDevDestDir.exists()
|
!pyDevDestDir.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
File depsFile = file("${DEPS_DIR}/GhidraDev/PyDev 6.3.1.zip")
|
File depsFile = file("${DEPS_DIR}/GhidraDev/PyDev 9.3.0.zip")
|
||||||
File binRepoFile = file("${BIN_REPO}/GhidraBuild/EclipsePlugins/GhidraDev/buildDependencies/PyDev 6.3.1.zip")
|
File binRepoFile = file("${BIN_REPO}/GhidraBuild/EclipsePlugins/GhidraDev/buildDependencies/PyDev 9.3.0.zip")
|
||||||
|
|
||||||
// First check if the file is in the dependencies repo. If not, check in the bin repo.
|
// First check if the file is in the dependencies repo. If not, check in the bin repo.
|
||||||
def pyDevZipTree = depsFile.exists() ? zipTree(depsFile) : zipTree(binRepoFile)
|
def pyDevZipTree = depsFile.exists() ? zipTree(depsFile) : zipTree(binRepoFile)
|
||||||
|
@ -115,6 +115,13 @@ task cdtUnpack(type:Copy) {
|
||||||
destinationDir cdtDestDir
|
destinationDir cdtDestDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task prepGhidraDev {
|
||||||
|
dependsOn("utilityJar")
|
||||||
|
dependsOn("launchSupportJar")
|
||||||
|
dependsOn("pyDevUnpack")
|
||||||
|
dependsOn("cdtUnpack")
|
||||||
|
}
|
||||||
|
|
||||||
// We do not currently build GhidraDev plugin at Ghidra build time so we must
|
// We do not currently build GhidraDev plugin at Ghidra build time so we must
|
||||||
// copy the prebuilt zip file from the BIN_REPO
|
// copy the prebuilt zip file from the BIN_REPO
|
||||||
rootProject.assembleDistribution {
|
rootProject.assembleDistribution {
|
||||||
|
@ -129,9 +136,3 @@ rootProject.assembleMarkdownToHtml {
|
||||||
into "Extensions/Eclipse/GhidraDev/"
|
into "Extensions/Eclipse/GhidraDev/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepDev dependencies
|
|
||||||
rootProject.prepDev.dependsOn utilityJar
|
|
||||||
rootProject.prepDev.dependsOn launchSupportJar
|
|
||||||
rootProject.prepDev.dependsOn pyDevUnpack
|
|
||||||
rootProject.prepDev.dependsOn cdtUnpack
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -378,6 +378,11 @@
|
||||||
id="GhidraHeadlessLaunchConfigurationType"
|
id="GhidraHeadlessLaunchConfigurationType"
|
||||||
name="Ghidra Headless">
|
name="Ghidra Headless">
|
||||||
</launchConfigurationType>
|
</launchConfigurationType>
|
||||||
|
<launchConfigurationType
|
||||||
|
delegate="ghidradev.ghidraprojectcreator.launchers.PyGhidraLaunchDelegate"
|
||||||
|
id="PyGhidraGuiLaunchConfigurationType"
|
||||||
|
name="PyGhidra">
|
||||||
|
</launchConfigurationType>
|
||||||
</extension>
|
</extension>
|
||||||
<extension
|
<extension
|
||||||
point="org.eclipse.debug.ui.launchConfigurationTypeImages">
|
point="org.eclipse.debug.ui.launchConfigurationTypeImages">
|
||||||
|
@ -391,6 +396,11 @@
|
||||||
icon="icons/GhidraIcon16_bw.png"
|
icon="icons/GhidraIcon16_bw.png"
|
||||||
id="GhidraHeadlessLaunchConfigurationTypeImage">
|
id="GhidraHeadlessLaunchConfigurationTypeImage">
|
||||||
</launchConfigurationTypeImage>
|
</launchConfigurationTypeImage>
|
||||||
|
<launchConfigurationTypeImage
|
||||||
|
configTypeID="PyGhidraGuiLaunchConfigurationType"
|
||||||
|
icon="icons/python.png"
|
||||||
|
id="PyGhidraGuiLaunchConfigurationTypeImage">
|
||||||
|
</launchConfigurationTypeImage>
|
||||||
</extension>
|
</extension>
|
||||||
<extension
|
<extension
|
||||||
point="org.eclipse.debug.core.launchDelegates">
|
point="org.eclipse.debug.core.launchDelegates">
|
||||||
|
@ -408,6 +418,13 @@
|
||||||
name="Ghidra Headless"
|
name="Ghidra Headless"
|
||||||
type="GhidraHeadlessLaunchConfigurationType">
|
type="GhidraHeadlessLaunchConfigurationType">
|
||||||
</launchDelegate>
|
</launchDelegate>
|
||||||
|
<launchDelegate
|
||||||
|
delegate="ghidradev.ghidraprojectcreator.launchers.PyGhidraLaunchDelegate"
|
||||||
|
id="PyGhidraGuiLaunchDelegate"
|
||||||
|
modes="run, debug"
|
||||||
|
name="PyGhidra GUI"
|
||||||
|
type="PyGhidraGuiLaunchConfigurationType">
|
||||||
|
</launchDelegate>
|
||||||
</extension>
|
</extension>
|
||||||
<extension
|
<extension
|
||||||
point="org.eclipse.debug.ui.launchConfigurationTabGroups">
|
point="org.eclipse.debug.ui.launchConfigurationTabGroups">
|
||||||
|
@ -423,6 +440,12 @@
|
||||||
id="GhidraHeadlessLaunchConfigurationTabGroup"
|
id="GhidraHeadlessLaunchConfigurationTabGroup"
|
||||||
type="GhidraHeadlessLaunchConfigurationType">
|
type="GhidraHeadlessLaunchConfigurationType">
|
||||||
</launchConfigurationTabGroup>
|
</launchConfigurationTabGroup>
|
||||||
|
<launchConfigurationTabGroup
|
||||||
|
class="org.python.pydev.debug.ui.PythonTabGroup"
|
||||||
|
description="Run and debug PyGhidra modules and scripts"
|
||||||
|
id="PyGhidraGuiLaunchConfigurationTabGroup"
|
||||||
|
type="PyGhidraGuiLaunchConfigurationType">
|
||||||
|
</launchConfigurationTabGroup>
|
||||||
</extension>
|
</extension>
|
||||||
<extension
|
<extension
|
||||||
point="org.eclipse.debug.ui.launchShortcuts">
|
point="org.eclipse.debug.ui.launchShortcuts">
|
||||||
|
@ -474,6 +497,30 @@
|
||||||
</enablement>
|
</enablement>
|
||||||
</contextualLaunch>
|
</contextualLaunch>
|
||||||
</shortcut>
|
</shortcut>
|
||||||
|
<shortcut
|
||||||
|
class="ghidradev.ghidraprojectcreator.launchers.PyGhidraGuiLaunchShortcut"
|
||||||
|
icon="icons/python.png"
|
||||||
|
id="PyGhidraGuiLaunchShortcut"
|
||||||
|
label="PyGhidra"
|
||||||
|
modes="run, debug">
|
||||||
|
<contextualLaunch>
|
||||||
|
<enablement>
|
||||||
|
<with
|
||||||
|
variable="selection">
|
||||||
|
<count
|
||||||
|
value="1">
|
||||||
|
</count>
|
||||||
|
<iterate
|
||||||
|
ifEmpty="false">
|
||||||
|
<test
|
||||||
|
property="ghidradev.ghidraprojectcreator.testers.isPyGhidraProject"
|
||||||
|
value="true">
|
||||||
|
</test>
|
||||||
|
</iterate>
|
||||||
|
</with>
|
||||||
|
</enablement>
|
||||||
|
</contextualLaunch>
|
||||||
|
</shortcut>
|
||||||
</extension>
|
</extension>
|
||||||
<extension
|
<extension
|
||||||
point="org.eclipse.core.expressions.propertyTesters">
|
point="org.eclipse.core.expressions.propertyTesters">
|
||||||
|
@ -505,6 +552,13 @@
|
||||||
properties="isGhidraModuleProject"
|
properties="isGhidraModuleProject"
|
||||||
type="java.lang.Object">
|
type="java.lang.Object">
|
||||||
</propertyTester>
|
</propertyTester>
|
||||||
|
<propertyTester
|
||||||
|
class="ghidradev.ghidraprojectcreator.testers.PyGhidraProjectPropertyTester"
|
||||||
|
id="PyGhidraProjectPropertyTester"
|
||||||
|
namespace="ghidradev.ghidraprojectcreator.testers"
|
||||||
|
properties="isPyGhidraProject"
|
||||||
|
type="java.lang.Object">
|
||||||
|
</propertyTester>
|
||||||
</extension>
|
</extension>
|
||||||
|
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/* ###
|
||||||
|
* 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 ghidradev.ghidraprojectcreator.launchers;
|
||||||
|
|
||||||
|
import javax.naming.OperationNotSupportedException;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.core.runtime.*;
|
||||||
|
import org.eclipse.debug.core.*;
|
||||||
|
import org.eclipse.debug.ui.ILaunchShortcut;
|
||||||
|
import org.eclipse.jface.viewers.ISelection;
|
||||||
|
import org.eclipse.ui.IEditorInput;
|
||||||
|
import org.eclipse.ui.IEditorPart;
|
||||||
|
|
||||||
|
import ghidradev.Activator;
|
||||||
|
import ghidradev.EclipseMessageUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.testers.GhidraProjectPropertyTester;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PyGhidra launch shortcut actions. These shortcuts appear when you right click on a
|
||||||
|
* PyGhidra project or file and select "Run As" or "Debug As".
|
||||||
|
* <p>
|
||||||
|
* The {@link GhidraProjectPropertyTester} is used to determine whether or not the shortcuts appear.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractPyGhidraLaunchShortcut implements ILaunchShortcut {
|
||||||
|
|
||||||
|
private String launchConfigTypeId;
|
||||||
|
private String launchConfigNameSuffix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new PyGhidra launch shortcut associated with the given launch configuration type ID.
|
||||||
|
*
|
||||||
|
* @param launchConfigTypeId The launch configuration type ID of this PyGhidra launch shortcut.
|
||||||
|
* @param launchConfigNameSuffix A string to append to the name of the launch configuration.
|
||||||
|
*/
|
||||||
|
protected AbstractPyGhidraLaunchShortcut(String launchConfigTypeId,
|
||||||
|
String launchConfigNameSuffix) {
|
||||||
|
this.launchConfigTypeId = launchConfigTypeId;
|
||||||
|
this.launchConfigNameSuffix = launchConfigNameSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void launch(ISelection selection, String mode) {
|
||||||
|
IProject project = GhidraProjectUtils.getSelectedProject(selection);
|
||||||
|
if (project != null) {
|
||||||
|
launch(project, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void launch(IEditorPart editor, String mode) {
|
||||||
|
IEditorInput input = editor.getEditorInput();
|
||||||
|
IResource resource = input.getAdapter(IResource.class);
|
||||||
|
if (resource != null) {
|
||||||
|
launch(resource.getProject(), mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launches the given Python nature in the given mode with a PyGhidra launcher.
|
||||||
|
*
|
||||||
|
* @param project The project to launch.
|
||||||
|
* @param mode The mode to launch in (run/debug).
|
||||||
|
*/
|
||||||
|
private void launch(IProject project, String mode) {
|
||||||
|
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
|
||||||
|
ILaunchConfigurationType launchType =
|
||||||
|
launchManager.getLaunchConfigurationType(launchConfigTypeId);
|
||||||
|
String launchConfigName = project.getName() + launchConfigNameSuffix;
|
||||||
|
try {
|
||||||
|
ILaunchConfiguration lc = GhidraLaunchUtils.getLaunchConfig(launchConfigName);
|
||||||
|
ILaunchConfigurationWorkingCopy wc = null;
|
||||||
|
if (lc == null) {
|
||||||
|
wc = launchType.newInstance(null, launchConfigName);
|
||||||
|
wc.setAttribute(PyDevUtils.getAttrProject(), project.getName());
|
||||||
|
}
|
||||||
|
else if (lc.getType().equals(launchType)) {
|
||||||
|
wc = lc.getWorkingCopy();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
|
||||||
|
IStatus.ERROR, "Failed to launch. Run configuration with name \"" +
|
||||||
|
launchConfigName + "\" already exists.",
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
wc.doSave().launch(mode, null);
|
||||||
|
}
|
||||||
|
catch (CoreException | OperationNotSupportedException e) {
|
||||||
|
EclipseMessageUtils.showErrorDialog(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ import org.eclipse.swt.widgets.Display;
|
||||||
import org.eclipse.ui.IPerspectiveDescriptor;
|
import org.eclipse.ui.IPerspectiveDescriptor;
|
||||||
import org.eclipse.ui.PlatformUI;
|
import org.eclipse.ui.PlatformUI;
|
||||||
|
|
||||||
import ghidra.launch.JavaConfig;
|
import ghidra.launch.AppConfig;
|
||||||
import ghidradev.EclipseMessageUtils;
|
import ghidradev.EclipseMessageUtils;
|
||||||
import ghidradev.ghidraprojectcreator.utils.*;
|
import ghidradev.ghidraprojectcreator.utils.*;
|
||||||
|
|
||||||
|
@ -62,10 +62,10 @@ public class GhidraLaunchDelegate extends JavaLaunchDelegate {
|
||||||
}
|
}
|
||||||
IFolder ghidraFolder =
|
IFolder ghidraFolder =
|
||||||
javaProject.getProject().getFolder(GhidraProjectUtils.GHIDRA_FOLDER_NAME);
|
javaProject.getProject().getFolder(GhidraProjectUtils.GHIDRA_FOLDER_NAME);
|
||||||
JavaConfig javaConfig;
|
AppConfig appConfig;
|
||||||
String ghidraInstallPath = ghidraFolder.getLocation().toOSString();
|
String ghidraInstallPath = ghidraFolder.getLocation().toOSString();
|
||||||
try {
|
try {
|
||||||
javaConfig = new JavaConfig(new File(ghidraInstallPath));
|
appConfig = new AppConfig(new File(ghidraInstallPath));
|
||||||
}
|
}
|
||||||
catch (ParseException | IOException e) {
|
catch (ParseException | IOException e) {
|
||||||
EclipseMessageUtils.showErrorDialog(
|
EclipseMessageUtils.showErrorDialog(
|
||||||
|
@ -98,7 +98,7 @@ public class GhidraLaunchDelegate extends JavaLaunchDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set VM arguments
|
// Set VM arguments
|
||||||
String vmArgs = javaConfig.getLaunchProperties().getVmArgs();
|
String vmArgs = appConfig.getLaunchProperties().getVmArgs();
|
||||||
vmArgs += " " + configuration.getAttribute(GhidraLaunchUtils.ATTR_VM_ARGUMENTS, "").trim();
|
vmArgs += " " + configuration.getAttribute(GhidraLaunchUtils.ATTR_VM_ARGUMENTS, "").trim();
|
||||||
vmArgs += " -Dghidra.external.modules=\"%s%s%s\"".formatted(
|
vmArgs += " -Dghidra.external.modules=\"%s%s%s\"".formatted(
|
||||||
javaProject.getProject().getLocation(), File.pathSeparator,
|
javaProject.getProject().getLocation(), File.pathSeparator,
|
||||||
|
@ -171,7 +171,7 @@ public class GhidraLaunchDelegate extends JavaLaunchDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start PyDev debugger
|
// Start PyDev debugger
|
||||||
if (PyDevUtils.isSupportedPyDevInstalled()) {
|
if (PyDevUtils.isSupportedJythonPyDevInstalled()) {
|
||||||
try {
|
try {
|
||||||
PyDevUtils.startPyDevRemoteDebugger();
|
PyDevUtils.startPyDevRemoteDebugger();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* ###
|
||||||
|
* 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 ghidradev.ghidraprojectcreator.launchers;
|
||||||
|
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.GhidraLaunchUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PyGhidra GUI launch shortcut actions.
|
||||||
|
*
|
||||||
|
* @see AbstractGhidraLaunchShortcut
|
||||||
|
*/
|
||||||
|
public class PyGhidraGuiLaunchShortcut extends AbstractPyGhidraLaunchShortcut {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new PyGhidra GUI launch shortcut.
|
||||||
|
*/
|
||||||
|
public PyGhidraGuiLaunchShortcut() {
|
||||||
|
super(GhidraLaunchUtils.PYGHIDRA_GUI_LAUNCH, " GUI");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
/* ###
|
||||||
|
* 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 ghidradev.ghidraprojectcreator.launchers;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.naming.OperationNotSupportedException;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IFolder;
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.debug.core.*;
|
||||||
|
import org.eclipse.debug.ui.IDebugUIConstants;
|
||||||
|
import org.eclipse.jdt.core.IJavaProject;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.ui.IPerspectiveDescriptor;
|
||||||
|
import org.eclipse.ui.PlatformUI;
|
||||||
|
import org.python.pydev.debug.ui.launching.RegularLaunchConfigurationDelegate;
|
||||||
|
|
||||||
|
import ghidra.launch.AppConfig;
|
||||||
|
import ghidradev.EclipseMessageUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.GhidraProjectUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PyGhidra Launch delegate handles the final launch of PyGhidra.
|
||||||
|
* We can do any extra custom launch behavior here.
|
||||||
|
*/
|
||||||
|
public class PyGhidraLaunchDelegate extends RegularLaunchConfigurationDelegate {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch,
|
||||||
|
IProgressMonitor monitor) throws CoreException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ILaunchConfigurationWorkingCopy wc = configuration.getWorkingCopy();
|
||||||
|
|
||||||
|
// Get project
|
||||||
|
String projectName = wc.getAttribute(PyDevUtils.getAttrProject(), "");
|
||||||
|
IJavaProject javaProject = GhidraProjectUtils.getGhidraProject(projectName);
|
||||||
|
if (javaProject == null) {
|
||||||
|
EclipseMessageUtils.showErrorDialog("Failed to launch project \"" + projectName +
|
||||||
|
"\".\nDoes not appear to be a Ghidra project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IProject project = javaProject.getProject();
|
||||||
|
|
||||||
|
// Get needed application.properties values
|
||||||
|
String javaComplianceLevel = null;
|
||||||
|
String ghidraVmErrorMsg = "";
|
||||||
|
try {
|
||||||
|
IFolder ghidraFolder = project.getFolder(GhidraProjectUtils.GHIDRA_FOLDER_NAME);
|
||||||
|
String ghidraInstallPath = ghidraFolder.getLocation().toOSString();
|
||||||
|
AppConfig appConfig = new AppConfig(new File(ghidraInstallPath));
|
||||||
|
javaComplianceLevel = appConfig.getCompilerComplianceLevel();
|
||||||
|
}
|
||||||
|
catch (ParseException | IOException e) {
|
||||||
|
ghidraVmErrorMsg = e.getMessage();
|
||||||
|
}
|
||||||
|
if (javaComplianceLevel == null) {
|
||||||
|
EclipseMessageUtils
|
||||||
|
.showErrorDialog("Failed to get JVM compliance level from project \"" +
|
||||||
|
projectName + "\".\n" + ghidraVmErrorMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set program location
|
||||||
|
wc.setAttribute(PyDevUtils.getAttrLocation(),
|
||||||
|
"${workspace_loc:%s/Ghidra/Ghidra/Features/PyGhidra/pypkg/src/pyghidra}"
|
||||||
|
.formatted(project.getName()));
|
||||||
|
|
||||||
|
// Set program arguments
|
||||||
|
wc.setAttribute(PyDevUtils.getAttrProgramArguments(), "-v -g");
|
||||||
|
|
||||||
|
// Set Python interpreter
|
||||||
|
String interpreterName = PyDevUtils.getInterpreterName(project);
|
||||||
|
wc.setAttribute(PyDevUtils.getAttrInterpreter(), interpreterName);
|
||||||
|
wc.setAttribute(PyDevUtils.getAttrInterpreterDefault(), interpreterName);
|
||||||
|
|
||||||
|
// Set environment variables
|
||||||
|
Map<String, String> env = new HashMap<>();
|
||||||
|
//env.put("GHIDRA_INSTALL_DIR", "${project_loc:/%s/Ghidra}".formatted(project.getName()));
|
||||||
|
env.put("GHIDRA_INSTALL_DIR",
|
||||||
|
"${resource_loc:/%s/Ghidra}".formatted(project.getName()));
|
||||||
|
env.put("JAVA_HOME_OVERRIDE", "${ee_home:JavaSE-%s}".formatted(javaComplianceLevel));
|
||||||
|
if (mode.equals("debug")) {
|
||||||
|
env.put("PYGHIDRA_DEBUG", "1");
|
||||||
|
handleDebugMode();
|
||||||
|
}
|
||||||
|
wc.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, env);
|
||||||
|
|
||||||
|
super.launch(wc.doSave(), mode, launch, monitor);
|
||||||
|
}
|
||||||
|
catch (OperationNotSupportedException e) {
|
||||||
|
EclipseMessageUtils.showErrorDialog("PyDev error",
|
||||||
|
"Failed to launch. PyDev version is not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles extra things that should happen when we are launching in debug mode.
|
||||||
|
*/
|
||||||
|
private static void handleDebugMode() {
|
||||||
|
Display.getDefault().asyncExec(() -> {
|
||||||
|
|
||||||
|
// Switch to debug perspective
|
||||||
|
if (PlatformUI.getWorkbench() != null) {
|
||||||
|
IPerspectiveDescriptor descriptor =
|
||||||
|
PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(
|
||||||
|
IDebugUIConstants.ID_DEBUG_PERSPECTIVE);
|
||||||
|
EclipseMessageUtils.getWorkbenchPage().setPerspective(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start PyDev debugger
|
||||||
|
try {
|
||||||
|
PyDevUtils.startPyDevRemoteDebugger();
|
||||||
|
}
|
||||||
|
catch (OperationNotSupportedException e) {
|
||||||
|
EclipseMessageUtils.error(
|
||||||
|
"Failed to start the PyDev remote debugger. PyDev version is not supported.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* ###
|
||||||
|
* 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 ghidradev.ghidraprojectcreator.testers;
|
||||||
|
|
||||||
|
import javax.naming.OperationNotSupportedException;
|
||||||
|
|
||||||
|
import org.eclipse.core.expressions.PropertyTester;
|
||||||
|
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.GhidraProjectUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link PropertyTester} used to determine if a given Eclipse resource is part
|
||||||
|
* of a PyGhidra project.
|
||||||
|
*/
|
||||||
|
public class PyGhidraProjectPropertyTester extends PropertyTester {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
|
||||||
|
try {
|
||||||
|
return PyDevUtils.isPyGhidraProject(GhidraProjectUtils.getEnclosingProject(receiver));
|
||||||
|
}
|
||||||
|
catch (OperationNotSupportedException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,6 +49,12 @@ public class GhidraLaunchUtils {
|
||||||
*/
|
*/
|
||||||
public static final String HEADLESS_LAUNCH = "GhidraHeadlessLaunchConfigurationType";
|
public static final String HEADLESS_LAUNCH = "GhidraHeadlessLaunchConfigurationType";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch configuration ID for a PyGhidra GUI launch. Must match corresponding value in
|
||||||
|
* plugin.xml.
|
||||||
|
*/
|
||||||
|
public static final String PYGHIDRA_GUI_LAUNCH = "PyGhidraGuiLaunchConfigurationType";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program arguments that will get passed to the launched Ghidra. These will be appended
|
* Program arguments that will get passed to the launched Ghidra. These will be appended
|
||||||
* to the required program arguments that are required to launch Ghidra, which are hidden
|
* to the required program arguments that are required to launch Ghidra, which are hidden
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.ltk.core.refactoring.*;
|
||||||
|
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +90,7 @@ public class GhidraModuleUtils {
|
||||||
*/
|
*/
|
||||||
public static IJavaProject createGhidraModuleProject(String projectName, File projectDir,
|
public static IJavaProject createGhidraModuleProject(String projectName, File projectDir,
|
||||||
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
||||||
String jythonInterpreterName, IProgressMonitor monitor)
|
ProjectPythonInterpreter jythonInterpreterName, IProgressMonitor monitor)
|
||||||
throws IOException, ParseException, CoreException {
|
throws IOException, ParseException, CoreException {
|
||||||
|
|
||||||
// Create empty Ghidra project
|
// Create empty Ghidra project
|
||||||
|
@ -227,8 +228,7 @@ public class GhidraModuleUtils {
|
||||||
* @param createRunConfig Whether or not to create a new run configuration for the project.
|
* @param createRunConfig Whether or not to create a new run configuration for the project.
|
||||||
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
||||||
* @param ghidraLayout The Ghidra layout to link the project to.
|
* @param ghidraLayout The Ghidra layout to link the project to.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* Could be null if Python support is not wanted.
|
|
||||||
* @param monitor The progress monitor to use during project creation.
|
* @param monitor The progress monitor to use during project creation.
|
||||||
* @return The imported project.
|
* @return The imported project.
|
||||||
* @throws IOException If there was a file-related problem with creating the project.
|
* @throws IOException If there was a file-related problem with creating the project.
|
||||||
|
@ -237,13 +237,13 @@ public class GhidraModuleUtils {
|
||||||
*/
|
*/
|
||||||
public static IJavaProject importGhidraModuleSource(String projectName, File moduleSourceDir,
|
public static IJavaProject importGhidraModuleSource(String projectName, File moduleSourceDir,
|
||||||
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
||||||
String jythonInterpreterName, IProgressMonitor monitor)
|
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||||
throws IOException, ParseException, CoreException {
|
throws IOException, ParseException, CoreException {
|
||||||
|
|
||||||
// Create empty Ghidra project
|
// Create empty Ghidra project
|
||||||
IJavaProject javaProject =
|
IJavaProject javaProject =
|
||||||
GhidraProjectUtils.createEmptyGhidraProject(projectName, moduleSourceDir,
|
GhidraProjectUtils.createEmptyGhidraProject(projectName, moduleSourceDir,
|
||||||
createRunConfig, runConfigMemory, ghidraLayout, jythonInterpreterName, monitor);
|
createRunConfig, runConfigMemory, ghidraLayout, pythonInterpreter, monitor);
|
||||||
IProject project = javaProject.getProject();
|
IProject project = javaProject.getProject();
|
||||||
|
|
||||||
// Set default output location
|
// Set default output location
|
||||||
|
|
|
@ -36,9 +36,10 @@ import org.eclipse.ui.part.FileEditorInput;
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidra.framework.GModule;
|
import ghidra.framework.GModule;
|
||||||
import ghidra.launch.JavaConfig;
|
import ghidra.launch.AppConfig;
|
||||||
import ghidradev.Activator;
|
import ghidradev.Activator;
|
||||||
import ghidradev.EclipseMessageUtils;
|
import ghidradev.EclipseMessageUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
import utility.module.ModuleUtilities;
|
import utility.module.ModuleUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -262,8 +263,7 @@ public class GhidraProjectUtils {
|
||||||
* @param createRunConfig Whether or not to create a new run configuration for the project.
|
* @param createRunConfig Whether or not to create a new run configuration for the project.
|
||||||
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
||||||
* @param ghidraLayout The Ghidra layout to link the project to.
|
* @param ghidraLayout The Ghidra layout to link the project to.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* Could be null if Python support is not wanted.
|
|
||||||
* @param monitor The progress monitor to use during project creation.
|
* @param monitor The progress monitor to use during project creation.
|
||||||
* @return The created project.
|
* @return The created project.
|
||||||
* @throws IOException If there was a file-related problem with creating the project.
|
* @throws IOException If there was a file-related problem with creating the project.
|
||||||
|
@ -272,12 +272,12 @@ public class GhidraProjectUtils {
|
||||||
*/
|
*/
|
||||||
public static IJavaProject createEmptyGhidraProject(String projectName, File projectDir,
|
public static IJavaProject createEmptyGhidraProject(String projectName, File projectDir,
|
||||||
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
||||||
String jythonInterpreterName, IProgressMonitor monitor)
|
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||||
throws IOException, ParseException, CoreException {
|
throws IOException, ParseException, CoreException {
|
||||||
|
|
||||||
// Get Ghidra's Java configuration
|
// Get Ghidra's Java configuration
|
||||||
JavaConfig javaConfig =
|
AppConfig appConfig =
|
||||||
new JavaConfig(ghidraLayout.getApplicationInstallationDir().getFile(false));
|
new AppConfig(ghidraLayout.getApplicationInstallationDir().getFile(false));
|
||||||
|
|
||||||
// Make new Java project
|
// Make new Java project
|
||||||
IWorkspace workspace = ResourcesPlugin.getWorkspace();
|
IWorkspace workspace = ResourcesPlugin.getWorkspace();
|
||||||
|
@ -299,7 +299,7 @@ public class GhidraProjectUtils {
|
||||||
javaProject.setRawClasspath(new IClasspathEntry[0], monitor);
|
javaProject.setRawClasspath(new IClasspathEntry[0], monitor);
|
||||||
|
|
||||||
// Configure Java compiler for the project
|
// Configure Java compiler for the project
|
||||||
configureJavaCompiler(javaProject, javaConfig);
|
configureJavaCompiler(javaProject, appConfig);
|
||||||
|
|
||||||
// Setup default bin folder
|
// Setup default bin folder
|
||||||
IFolder binFolder = project.getFolder("bin/default");
|
IFolder binFolder = project.getFolder("bin/default");
|
||||||
|
@ -310,7 +310,7 @@ public class GhidraProjectUtils {
|
||||||
monitor);
|
monitor);
|
||||||
|
|
||||||
// Link in Ghidra to the project
|
// Link in Ghidra to the project
|
||||||
linkGhidraToProject(javaProject, ghidraLayout, javaConfig, jythonInterpreterName, monitor);
|
linkGhidraToProject(javaProject, ghidraLayout, appConfig, pythonInterpreter, monitor);
|
||||||
|
|
||||||
// Create run configuration (if necessary)
|
// Create run configuration (if necessary)
|
||||||
if (createRunConfig) {
|
if (createRunConfig) {
|
||||||
|
@ -338,23 +338,22 @@ public class GhidraProjectUtils {
|
||||||
*
|
*
|
||||||
* @param javaProject The Java project to link.
|
* @param javaProject The Java project to link.
|
||||||
* @param ghidraLayout The Ghidra layout to link the project to.
|
* @param ghidraLayout The Ghidra layout to link the project to.
|
||||||
* @param javaConfig Ghidra's Java configuration.
|
* @param appConfig Ghidra's application configuration.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* Could be null if Python support is not wanted.
|
|
||||||
* @param monitor The progress monitor used during link.
|
* @param monitor The progress monitor used during link.
|
||||||
* @throws IOException If there was a file-related problem with linking in Ghidra.
|
* @throws IOException If there was a file-related problem with linking in Ghidra.
|
||||||
* @throws CoreException If there was an Eclipse-related problem with linking in Ghidra.
|
* @throws CoreException If there was an Eclipse-related problem with linking in Ghidra.
|
||||||
*/
|
*/
|
||||||
public static void linkGhidraToProject(IJavaProject javaProject,
|
public static void linkGhidraToProject(IJavaProject javaProject,
|
||||||
GhidraApplicationLayout ghidraLayout, JavaConfig javaConfig,
|
GhidraApplicationLayout ghidraLayout, AppConfig appConfig,
|
||||||
String jythonInterpreterName, IProgressMonitor monitor)
|
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||||
throws CoreException, IOException {
|
throws CoreException, IOException {
|
||||||
|
|
||||||
// Gets the Ghidra installation directory to link to from the Ghidra layout
|
// Gets the Ghidra installation directory to link to from the Ghidra layout
|
||||||
File ghidraInstallDir = ghidraLayout.getApplicationInstallationDir().getFile(false);
|
File ghidraInstallDir = ghidraLayout.getApplicationInstallationDir().getFile(false);
|
||||||
|
|
||||||
// Get the Java VM used to launch the Ghidra to link to
|
// Get the Java VM used to launch the Ghidra to link to
|
||||||
IVMInstall vm = getGhidraVm(javaConfig);
|
IVMInstall vm = getGhidraVm(appConfig);
|
||||||
IPath vmPath =
|
IPath vmPath =
|
||||||
new Path(JavaRuntime.JRE_CONTAINER).append(vm.getVMInstallType().getId()).append(
|
new Path(JavaRuntime.JRE_CONTAINER).append(vm.getVMInstallType().getId()).append(
|
||||||
vm.getName());
|
vm.getName());
|
||||||
|
@ -457,15 +456,13 @@ public class GhidraProjectUtils {
|
||||||
GhidraModuleUtils.writeAntProperties(javaProject.getProject(), ghidraLayout);
|
GhidraModuleUtils.writeAntProperties(javaProject.getProject(), ghidraLayout);
|
||||||
|
|
||||||
// Setup Python for the project
|
// Setup Python for the project
|
||||||
if (PyDevUtils.isSupportedPyDevInstalled()) {
|
try {
|
||||||
try {
|
PyDevUtils.setupPythonForProject(javaProject, libraryClasspathEntries,
|
||||||
PyDevUtils.setupPythonForProject(javaProject, libraryClasspathEntries,
|
pythonInterpreter, monitor);
|
||||||
jythonInterpreterName, monitor);
|
}
|
||||||
}
|
catch (OperationNotSupportedException e) {
|
||||||
catch (OperationNotSupportedException e) {
|
EclipseMessageUtils.showErrorDialog("PyDev error",
|
||||||
EclipseMessageUtils.showErrorDialog("PyDev error",
|
"Failed to setup Python for the project. PyDev version is not supported.");
|
||||||
"Failed to setup Python for the project. PyDev version is not supported.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,14 +556,14 @@ public class GhidraProjectUtils {
|
||||||
/**
|
/**
|
||||||
* Gets the required VM used to build and run the Ghidra defined by the given layout.
|
* Gets the required VM used to build and run the Ghidra defined by the given layout.
|
||||||
*
|
*
|
||||||
* @param javaConfig Ghidra's Java configuration.
|
* @param appConfig Ghidra's application configuration.
|
||||||
* @return The required VM used to build and run the Ghidra defined by the given layout.
|
* @return The required VM used to build and run the Ghidra defined by the given layout.
|
||||||
* @throws IOException If there was a file-related problem with getting the VM.
|
* @throws IOException If there was a file-related problem with getting the VM.
|
||||||
* @throws CoreException If there was an Eclipse-related problem with creating the project.
|
* @throws CoreException If there was an Eclipse-related problem with creating the project.
|
||||||
*/
|
*/
|
||||||
private static IVMInstall getGhidraVm(JavaConfig javaConfig) throws IOException, CoreException {
|
private static IVMInstall getGhidraVm(AppConfig appConfig) throws IOException, CoreException {
|
||||||
|
|
||||||
File requiredJavaHomeDir = javaConfig.getSavedJavaHome(); // safe to assume it's valid
|
File requiredJavaHomeDir = appConfig.getSavedJavaHome(); // safe to assume it's valid
|
||||||
|
|
||||||
// First look for a matching VM in Eclipse's existing list.
|
// First look for a matching VM in Eclipse's existing list.
|
||||||
// NOTE: Mac has its own VM type, so be sure to check it for VM matches too.
|
// NOTE: Mac has its own VM type, so be sure to check it for VM matches too.
|
||||||
|
@ -617,19 +614,19 @@ public class GhidraProjectUtils {
|
||||||
* Configures the default Java compiler behavior for the given java project.
|
* Configures the default Java compiler behavior for the given java project.
|
||||||
*
|
*
|
||||||
* @param jp The Java project to configure.
|
* @param jp The Java project to configure.
|
||||||
* @param javaConfig Ghidra's Java configuration.
|
* @param appConfig Ghidra's application configuration.
|
||||||
*/
|
*/
|
||||||
private static void configureJavaCompiler(IJavaProject jp, JavaConfig javaConfig) {
|
private static void configureJavaCompiler(IJavaProject jp, AppConfig appConfig) {
|
||||||
|
|
||||||
final String WARNING = JavaCore.WARNING;
|
final String WARNING = JavaCore.WARNING;
|
||||||
final String IGNORE = JavaCore.IGNORE;
|
final String IGNORE = JavaCore.IGNORE;
|
||||||
final String ERROR = JavaCore.ERROR;
|
final String ERROR = JavaCore.ERROR;
|
||||||
|
|
||||||
// Compliance
|
// Compliance
|
||||||
jp.setOption(JavaCore.COMPILER_SOURCE, javaConfig.getCompilerComplianceLevel());
|
jp.setOption(JavaCore.COMPILER_SOURCE, appConfig.getCompilerComplianceLevel());
|
||||||
jp.setOption(JavaCore.COMPILER_COMPLIANCE, javaConfig.getCompilerComplianceLevel());
|
jp.setOption(JavaCore.COMPILER_COMPLIANCE, appConfig.getCompilerComplianceLevel());
|
||||||
jp.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
|
jp.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
|
||||||
javaConfig.getCompilerComplianceLevel());
|
appConfig.getCompilerComplianceLevel());
|
||||||
|
|
||||||
// Code style
|
// Code style
|
||||||
jp.setOption(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER, WARNING);
|
jp.setOption(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER, WARNING);
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -26,6 +26,7 @@ import org.eclipse.jdt.core.*;
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidra.framework.GModule;
|
import ghidra.framework.GModule;
|
||||||
import ghidradev.Activator;
|
import ghidradev.Activator;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for working with Ghidra scripts in Eclipse.
|
* Utility methods for working with Ghidra scripts in Eclipse.
|
||||||
|
@ -45,8 +46,7 @@ public class GhidraScriptUtils {
|
||||||
* @param linkUserScripts Whether or not to link in the user scripts directory.
|
* @param linkUserScripts Whether or not to link in the user scripts directory.
|
||||||
* @param linkSystemScripts Whether or not to link in the system scripts directories.
|
* @param linkSystemScripts Whether or not to link in the system scripts directories.
|
||||||
* @param ghidraLayout The Ghidra layout to link the project to.
|
* @param ghidraLayout The Ghidra layout to link the project to.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* Could be null if Python support is not wanted.
|
|
||||||
* @param monitor The progress monitor to use during project creation.
|
* @param monitor The progress monitor to use during project creation.
|
||||||
* @return The created project.
|
* @return The created project.
|
||||||
* @throws IOException If there was a file-related problem with creating the project.
|
* @throws IOException If there was a file-related problem with creating the project.
|
||||||
|
@ -56,15 +56,14 @@ public class GhidraScriptUtils {
|
||||||
public static IJavaProject createGhidraScriptProject(String projectName, File projectDir,
|
public static IJavaProject createGhidraScriptProject(String projectName, File projectDir,
|
||||||
boolean createRunConfig, String runConfigMemory, boolean linkUserScripts,
|
boolean createRunConfig, String runConfigMemory, boolean linkUserScripts,
|
||||||
boolean linkSystemScripts, GhidraApplicationLayout ghidraLayout,
|
boolean linkSystemScripts, GhidraApplicationLayout ghidraLayout,
|
||||||
String jythonInterpreterName, IProgressMonitor monitor)
|
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||||
throws IOException, ParseException, CoreException {
|
throws IOException, ParseException, CoreException {
|
||||||
|
|
||||||
List<IClasspathEntry> classpathEntries = new ArrayList<>();
|
List<IClasspathEntry> classpathEntries = new ArrayList<>();
|
||||||
|
|
||||||
// Create empty Ghidra project
|
// Create empty Ghidra project
|
||||||
IJavaProject javaProject = GhidraProjectUtils.createEmptyGhidraProject(projectName,
|
IJavaProject javaProject = GhidraProjectUtils.createEmptyGhidraProject(projectName,
|
||||||
projectDir, createRunConfig, runConfigMemory, ghidraLayout, jythonInterpreterName,
|
projectDir, createRunConfig, runConfigMemory, ghidraLayout, pythonInterpreter, monitor);
|
||||||
monitor);
|
|
||||||
|
|
||||||
// Link each module's ghidra_scripts directory to the project
|
// Link each module's ghidra_scripts directory to the project
|
||||||
if (linkSystemScripts) {
|
if (linkSystemScripts) {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -26,6 +26,7 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.naming.OperationNotSupportedException;
|
import javax.naming.OperationNotSupportedException;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.runtime.*;
|
import org.eclipse.core.runtime.*;
|
||||||
import org.eclipse.jdt.core.IClasspathEntry;
|
import org.eclipse.jdt.core.IClasspathEntry;
|
||||||
import org.eclipse.jdt.core.IJavaProject;
|
import org.eclipse.jdt.core.IJavaProject;
|
||||||
|
@ -38,23 +39,58 @@ import ghidradev.Activator;
|
||||||
*/
|
*/
|
||||||
public class PyDevUtils {
|
public class PyDevUtils {
|
||||||
|
|
||||||
public final static String MIN_SUPPORTED_VERSION = "6.3.1";
|
public final static String MIN_SUPPORTED_VERSION = "9.3.0";
|
||||||
public final static String MAX_SUPPORTED_VERSION = "9.3.0";
|
public final static String MAX_JYTHON_SUPPORTED_VERSION = "9.3.0";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if a supported version of PyDev is installed.
|
* The various types of supported Python interpreters
|
||||||
*
|
|
||||||
* @return True if a supported version of PyDev is installed; otherwise, false.
|
|
||||||
*/
|
*/
|
||||||
public static boolean isSupportedPyDevInstalled() {
|
public static enum ProjectPythonInterpreterType {
|
||||||
|
NONE,
|
||||||
|
PYGHIDRA,
|
||||||
|
JYTHON
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The projects Python interpreter to use
|
||||||
|
*
|
||||||
|
* @param name The name of the interpreter
|
||||||
|
* @param type The {@link ProjectPythonInterpreterType type} of the interpreter
|
||||||
|
*/
|
||||||
|
public static record ProjectPythonInterpreter(String name, ProjectPythonInterpreterType type) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return true if a supported version of PyDev is installed for use with PyGhidra; otherwise,
|
||||||
|
* false}
|
||||||
|
*/
|
||||||
|
public static boolean isSupportedPyGhidraPyDevInstalled() {
|
||||||
Version min = Version.valueOf(MIN_SUPPORTED_VERSION);
|
Version min = Version.valueOf(MIN_SUPPORTED_VERSION);
|
||||||
Version max = Version.valueOf(MAX_SUPPORTED_VERSION);
|
try {
|
||||||
|
Version version = PyDevUtilsInternal.getPyDevVersion();
|
||||||
|
if (version != null) {
|
||||||
|
return version.compareTo(min) >= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError e) {
|
||||||
|
// Fall through to return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return true if a supported version of PyDev is installed for use with Jython; otherwise,
|
||||||
|
* false}
|
||||||
|
*/
|
||||||
|
public static boolean isSupportedJythonPyDevInstalled() {
|
||||||
|
Version min = Version.valueOf(MIN_SUPPORTED_VERSION);
|
||||||
|
Version max = Version.valueOf(MAX_JYTHON_SUPPORTED_VERSION);
|
||||||
try {
|
try {
|
||||||
Version version = PyDevUtilsInternal.getPyDevVersion();
|
Version version = PyDevUtilsInternal.getPyDevVersion();
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
// Make sure the installed version of PyDev is new enough to support the following
|
// Make sure the installed version of PyDev is new enough to support the following
|
||||||
// operation.
|
// operation.
|
||||||
getJython27InterpreterNames();
|
getJythonInterpreterNames();
|
||||||
return version.compareTo(min) >= 0 && version.compareTo(max) <= 0;
|
return version.compareTo(min) >= 0 && version.compareTo(max) <= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,15 +102,53 @@ public class PyDevUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of discovered Jython 2.7 interpreter names.
|
* Gets a list of discovered PyGhidra interpreter names.
|
||||||
*
|
* @param requiredFileMatch if not {@code null}, only interpreter names that correspond to the
|
||||||
* @return a list of discovered Jython 2.7 interpreter names.
|
* given interpreter file will be returned.
|
||||||
|
* @return a list of discovered PyGhidra interpreter names.
|
||||||
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
public static List<String> getJython27InterpreterNames() throws OperationNotSupportedException {
|
public static List<String> getPyGhidraInterpreterNames(File requiredFileMatch)
|
||||||
|
throws OperationNotSupportedException {
|
||||||
try {
|
try {
|
||||||
return PyDevUtilsInternal.getJython27InterpreterNames();
|
return PyDevUtilsInternal.getPyGhidraInterpreterNames(requiredFileMatch);
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of discovered Jython interpreter names.
|
||||||
|
*
|
||||||
|
* @return a list of discovered Jython interpreter names.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static List<String> getJythonInterpreterNames() throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.getJythonInterpreterNames();
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given PyGhidra interpreter to PyDev.
|
||||||
|
*
|
||||||
|
* @param interpreterName The name of the interpreter to add.
|
||||||
|
* @param interpreterFile The interpreter file to add.
|
||||||
|
* @param pypredefDir The pypredef directory to use (could be null if not supported)
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static void addPyGhidraInterpreter(String interpreterName, File interpreterFile,
|
||||||
|
File pypredefDir) throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
PyDevUtilsInternal.addPyGhidraInterpreter(interpreterName, interpreterFile,
|
||||||
|
pypredefDir);
|
||||||
}
|
}
|
||||||
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
||||||
throw new OperationNotSupportedException(e.getMessage());
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
@ -107,8 +181,7 @@ public class PyDevUtils {
|
||||||
*
|
*
|
||||||
* @param javaProject The Java project to enable Python for.
|
* @param javaProject The Java project to enable Python for.
|
||||||
* @param classpathEntries The classpath entries to add to the Python path.
|
* @param classpathEntries The classpath entries to add to the Python path.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* If this is null, Python support will be removed from the project.
|
|
||||||
* @param monitor The progress monitor used during link.
|
* @param monitor The progress monitor used during link.
|
||||||
* @throws CoreException if there was an Eclipse-related problem with enabling Python for the
|
* @throws CoreException if there was an Eclipse-related problem with enabling Python for the
|
||||||
* project.
|
* project.
|
||||||
|
@ -116,11 +189,11 @@ public class PyDevUtils {
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
public static void setupPythonForProject(IJavaProject javaProject,
|
public static void setupPythonForProject(IJavaProject javaProject,
|
||||||
List<IClasspathEntry> classpathEntries, String jythonInterpreterName,
|
List<IClasspathEntry> classpathEntries, ProjectPythonInterpreter pythonInterpreter,
|
||||||
IProgressMonitor monitor) throws CoreException, OperationNotSupportedException {
|
IProgressMonitor monitor) throws CoreException, OperationNotSupportedException {
|
||||||
try {
|
try {
|
||||||
PyDevUtilsInternal.setupPythonForProject(javaProject, classpathEntries,
|
PyDevUtilsInternal.setupPythonForProject(javaProject, classpathEntries,
|
||||||
jythonInterpreterName, monitor);
|
pythonInterpreter, monitor);
|
||||||
}
|
}
|
||||||
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
||||||
throw new OperationNotSupportedException(e.getMessage());
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
@ -151,6 +224,15 @@ public class PyDevUtils {
|
||||||
return "org.python.pydev.ui.pythonpathconf.interpreterPreferencesPageJython";
|
return "org.python.pydev.ui.pythonpathconf.interpreterPreferencesPageJython";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev Python preference page ID.
|
||||||
|
*
|
||||||
|
* @return the PyDev Python preference page ID.
|
||||||
|
*/
|
||||||
|
public static String getPythonPreferencePageId() {
|
||||||
|
return "org.python.pydev.ui.pythonpathconf.interpreterPreferencesPagePython";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets The PyDev source directory.
|
* Gets The PyDev source directory.
|
||||||
*
|
*
|
||||||
|
@ -184,4 +266,138 @@ public class PyDevUtils {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the given project is a Python project.
|
||||||
|
*
|
||||||
|
* @param project The project to check.
|
||||||
|
* @return True if the given project is a Python project; otherwise, false.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static boolean isPythonProject(IProject project) throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.isPythonProject(project);
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the given project is a PyGhidra project.
|
||||||
|
*
|
||||||
|
* @param project The project to check.
|
||||||
|
* @return True if the given project is a PyGhidra project; otherwise, false.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static boolean isPyGhidraProject(IProject project)
|
||||||
|
throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.isPyGhidraProject(project);
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the interpreter name of the given Python project.
|
||||||
|
*
|
||||||
|
* @param project The project to get the interpreter name from.
|
||||||
|
* @return The interpreter name of the given Python project, or null it it's not a Python
|
||||||
|
* project or doesn't have an interpreter.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static String getInterpreterName(IProject project)
|
||||||
|
throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.getInterpreterName(project);
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "project" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "project" attribute.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrProject() throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.getAttrProject();
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "location" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "location" attribute.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrLocation() throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.getAttrLocation();
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "program arguments" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "program arguments" attribute.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrProgramArguments() throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.getAttrProgramArguments();
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "interpreter" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "interpreter" attribute.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrInterpreter() throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.getAttrInterpreter();
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "interpreter default" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "interpreter default" attribute.
|
||||||
|
* @throws OperationNotSupportedException if PyDev is not installed or it does not support this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrInterpreterDefault() throws OperationNotSupportedException {
|
||||||
|
try {
|
||||||
|
return PyDevUtilsInternal.getAttrInterpreterDefault();
|
||||||
|
}
|
||||||
|
catch (NoClassDefFoundError e) {
|
||||||
|
throw new OperationNotSupportedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -19,6 +19,7 @@ import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.runtime.*;
|
import org.eclipse.core.runtime.*;
|
||||||
import org.eclipse.jdt.core.IClasspathEntry;
|
import org.eclipse.jdt.core.IClasspathEntry;
|
||||||
import org.eclipse.jdt.core.IJavaProject;
|
import org.eclipse.jdt.core.IJavaProject;
|
||||||
|
@ -26,11 +27,13 @@ import org.osgi.framework.*;
|
||||||
import org.python.pydev.ast.interpreter_managers.InterpreterInfo;
|
import org.python.pydev.ast.interpreter_managers.InterpreterInfo;
|
||||||
import org.python.pydev.ast.interpreter_managers.InterpreterManagersAPI;
|
import org.python.pydev.ast.interpreter_managers.InterpreterManagersAPI;
|
||||||
import org.python.pydev.core.*;
|
import org.python.pydev.core.*;
|
||||||
|
import org.python.pydev.debug.core.Constants;
|
||||||
import org.python.pydev.plugin.nature.PythonNature;
|
import org.python.pydev.plugin.nature.PythonNature;
|
||||||
|
|
||||||
import com.python.pydev.debug.remote.client_api.PydevRemoteDebuggerServer;
|
import com.python.pydev.debug.remote.client_api.PydevRemoteDebuggerServer;
|
||||||
|
|
||||||
import ghidradev.EclipseMessageUtils;
|
import ghidradev.EclipseMessageUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for interacting with PyDev.
|
* Utility methods for interacting with PyDev.
|
||||||
|
@ -62,20 +65,50 @@ class PyDevUtilsInternal {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of discovered Jython 2.7 interpreter names.
|
* Gets a list of discovered PyGhidra interpreter names.
|
||||||
*
|
*
|
||||||
* @return a list of discovered Jython 2.7 interpreter names.
|
* @param requiredFileMatch if not {@code null}, only interpreter names that correspond to the
|
||||||
|
* given interpreter file will be returned.
|
||||||
|
* @return a list of discovered PyGhidra interpreter names.
|
||||||
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
* @throws NoSuchMethodError if PyDev is not installed or it does not support this operation.
|
* @throws NoSuchMethodError if PyDev is not installed or it does not support this operation.
|
||||||
*/
|
*/
|
||||||
public static List<String> getJython27InterpreterNames()
|
public static List<String> getPyGhidraInterpreterNames(File requiredFileMatch)
|
||||||
|
throws NoClassDefFoundError, NoSuchMethodError {
|
||||||
|
|
||||||
|
List<String> interpreters = new ArrayList<>();
|
||||||
|
IInterpreterManager iMan = InterpreterManagersAPI.getPythonInterpreterManager(true);
|
||||||
|
|
||||||
|
for (IInterpreterInfo info : iMan.getInterpreterInfos()) {
|
||||||
|
ISystemModulesManager modulesManager = info.getModulesManager();
|
||||||
|
if (info.getInterpreterType() == IPythonNature.INTERPRETER_TYPE_PYTHON &&
|
||||||
|
!modulesManager.getAllModulesStartingWith("pyghidra.__main__").isEmpty()) {
|
||||||
|
if (requiredFileMatch == null ||
|
||||||
|
requiredFileMatch.getAbsolutePath().equals(info.getExecutableOrJar())) {
|
||||||
|
interpreters.add(info.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return interpreters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of discovered Jython interpreter names.
|
||||||
|
*
|
||||||
|
* @return a list of discovered Jython interpreter names.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
* @throws NoSuchMethodError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static List<String> getJythonInterpreterNames()
|
||||||
throws NoClassDefFoundError, NoSuchMethodError {
|
throws NoClassDefFoundError, NoSuchMethodError {
|
||||||
|
|
||||||
List<String> interpreters = new ArrayList<>();
|
List<String> interpreters = new ArrayList<>();
|
||||||
IInterpreterManager iMan = InterpreterManagersAPI.getJythonInterpreterManager(true);
|
IInterpreterManager iMan = InterpreterManagersAPI.getJythonInterpreterManager(true);
|
||||||
|
|
||||||
for (IInterpreterInfo info : iMan.getInterpreterInfos()) {
|
for (IInterpreterInfo info : iMan.getInterpreterInfos()) {
|
||||||
if (info.getInterpreterType() == IPythonNature.INTERPRETER_TYPE_JYTHON && info.getVersion().equals("2.7")) {
|
if (info.getInterpreterType() == IPythonNature.INTERPRETER_TYPE_JYTHON &&
|
||||||
|
info.getVersion().equals("2.7")) {
|
||||||
interpreters.add(info.getName());
|
interpreters.add(info.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,6 +116,38 @@ class PyDevUtilsInternal {
|
||||||
return interpreters;
|
return interpreters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given PyGhidra interpreter to PyDev.
|
||||||
|
*
|
||||||
|
* @param interpreterName The name of the interpreter to add.
|
||||||
|
* @param interpreterFile The interpreter to add.
|
||||||
|
* @param pypredefDir The pypredef directory to use (could be null if not supported)
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
* @throws NoSuchMethodError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static void addPyGhidraInterpreter(String interpreterName, File interpreterFile,
|
||||||
|
File pypredefDir) throws NoClassDefFoundError, NoSuchMethodError {
|
||||||
|
IProgressMonitor monitor = new NullProgressMonitor();
|
||||||
|
IInterpreterManager iMan = InterpreterManagersAPI.getPythonInterpreterManager(true);
|
||||||
|
IInterpreterInfo[] interpreterInfos = iMan.getInterpreterInfos();
|
||||||
|
for (IInterpreterInfo iInfo : interpreterInfos) {
|
||||||
|
if (iInfo.getName().equals(interpreterName) &&
|
||||||
|
iInfo.getExecutableOrJar().equals(interpreterFile.getAbsolutePath())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IInterpreterInfo iInfo =
|
||||||
|
iMan.createInterpreterInfo(interpreterFile.getAbsolutePath(), monitor, false);
|
||||||
|
iInfo.setName(interpreterName);
|
||||||
|
if (iInfo instanceof InterpreterInfo ii && pypredefDir != null) {
|
||||||
|
ii.addPredefinedCompletionsPath(pypredefDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
IInterpreterInfo[] newInterpreterInfos =
|
||||||
|
Arrays.copyOf(interpreterInfos, interpreterInfos.length + 1);
|
||||||
|
newInterpreterInfos[interpreterInfos.length] = iInfo;
|
||||||
|
iMan.setInfos(newInterpreterInfos, null, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given Jython interpreter to PyDev.
|
* Adds the given Jython interpreter to PyDev.
|
||||||
*
|
*
|
||||||
|
@ -119,26 +184,38 @@ class PyDevUtilsInternal {
|
||||||
*
|
*
|
||||||
* @param javaProject The Java project to setup Python for.
|
* @param javaProject The Java project to setup Python for.
|
||||||
* @param classpathEntries The classpath entries to add to the Python path.
|
* @param classpathEntries The classpath entries to add to the Python path.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* If this is null, Python support will be removed from the project.
|
|
||||||
* @param monitor The progress monitor used during link.
|
* @param monitor The progress monitor used during link.
|
||||||
* @throws CoreException If there was an Eclipse-related problem with enabling Python for the project.
|
* @throws CoreException If there was an Eclipse-related problem with enabling Python for the project.
|
||||||
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
* @throws NoSuchMethodError if PyDev is not installed or it does not support this operation.
|
* @throws NoSuchMethodError if PyDev is not installed or it does not support this operation.
|
||||||
*/
|
*/
|
||||||
public static void setupPythonForProject(IJavaProject javaProject,
|
public static void setupPythonForProject(IJavaProject javaProject,
|
||||||
List<IClasspathEntry> classpathEntries, String jythonInterpreterName,
|
List<IClasspathEntry> classpathEntries, ProjectPythonInterpreter pythonInterpreter,
|
||||||
IProgressMonitor monitor)
|
IProgressMonitor monitor)
|
||||||
throws CoreException, NoClassDefFoundError, NoSuchMethodError {
|
throws CoreException, NoClassDefFoundError, NoSuchMethodError {
|
||||||
|
|
||||||
PythonNature.removeNature(javaProject.getProject(), monitor);
|
PythonNature.removeNature(javaProject.getProject(), monitor);
|
||||||
|
|
||||||
if (jythonInterpreterName != null) {
|
String version;
|
||||||
String libs = classpathEntries.stream().map(e -> e.getPath().toOSString()).collect(
|
String libs;
|
||||||
Collectors.joining("|"));
|
switch (pythonInterpreter.type()) {
|
||||||
PythonNature.addNature(javaProject.getProject(), monitor,
|
case PYGHIDRA:
|
||||||
IPythonNature.JYTHON_VERSION_2_7, null, libs, jythonInterpreterName, null);
|
version = IPythonNature.PYTHON_VERSION_INTERPRETER;
|
||||||
|
libs = null;
|
||||||
|
break;
|
||||||
|
case JYTHON:
|
||||||
|
version = IPythonNature.JYTHON_VERSION_INTERPRETER;
|
||||||
|
libs = classpathEntries.stream()
|
||||||
|
.map(e -> e.getPath().toOSString())
|
||||||
|
.collect(Collectors.joining("|"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PythonNature.addNature(javaProject.getProject(), monitor, version, null, libs,
|
||||||
|
pythonInterpreter.name(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,6 +228,109 @@ class PyDevUtilsInternal {
|
||||||
PydevRemoteDebuggerServer.startServer();
|
PydevRemoteDebuggerServer.startServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the given project is a Python project.
|
||||||
|
*
|
||||||
|
* @param project The project to check.
|
||||||
|
* @return True if the given project is a Python project; otherwise, false.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static boolean isPythonProject(IProject project) throws NoClassDefFoundError {
|
||||||
|
try {
|
||||||
|
return project.hasNature(PythonNature.PYTHON_NATURE_ID);
|
||||||
|
}
|
||||||
|
catch (CoreException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the given project is a PyGhidra project.
|
||||||
|
*
|
||||||
|
* @param project The project to check.
|
||||||
|
* @return True if the given project is a PyGhidra project; otherwise, false.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static boolean isPyGhidraProject(IProject project) throws NoClassDefFoundError {
|
||||||
|
return isPythonProject(project) && GhidraProjectUtils.isGhidraProject(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the interpreter name of the given Python project.
|
||||||
|
*
|
||||||
|
* @param project The project to get the interpreter name from.
|
||||||
|
* @return The interpreter name of the given Python project, or null it it's not a Python
|
||||||
|
* project or doesn't have an interpreter.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
* @throws NoSuchMethodError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static String getInterpreterName(IProject project)
|
||||||
|
throws NoClassDefFoundError, NoSuchMethodError {
|
||||||
|
PythonNature nature = PythonNature.getPythonNature(project);
|
||||||
|
if (nature != null) {
|
||||||
|
try {
|
||||||
|
IInterpreterInfo info = nature.getProjectInterpreter();
|
||||||
|
if (info != null) {
|
||||||
|
return info.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (PythonNatureWithoutProjectException | MisconfigurationException e) {
|
||||||
|
// Fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "project" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "project" attribute.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrProject() throws NoClassDefFoundError {
|
||||||
|
return Constants.ATTR_PROJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "location" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "location" attribute.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrLocation() throws NoClassDefFoundError {
|
||||||
|
return Constants.ATTR_LOCATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "program arguments" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "program arguments" attribute.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrProgramArguments() throws NoClassDefFoundError {
|
||||||
|
return Constants.ATTR_PROGRAM_ARGUMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "interpreter" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "interpreter" attribute.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrInterpreter() throws NoClassDefFoundError {
|
||||||
|
return Constants.ATTR_INTERPRETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PyDev "interpreter default" attribute.
|
||||||
|
*
|
||||||
|
* @return The PyDev "interpreter default" attribute.
|
||||||
|
* @throws NoClassDefFoundError if PyDev is not installed or it does not support this operation.
|
||||||
|
*/
|
||||||
|
public static String getAttrInterpreterDefault() throws NoClassDefFoundError {
|
||||||
|
return Constants.ATTR_INTERPRETER_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
private PyDevUtilsInternal() throws NoClassDefFoundError {
|
private PyDevUtilsInternal() throws NoClassDefFoundError {
|
||||||
// Prevent instantiation
|
// Prevent instantiation
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -36,6 +36,7 @@ import ghidra.GhidraApplicationLayout;
|
||||||
import ghidradev.EclipseMessageUtils;
|
import ghidradev.EclipseMessageUtils;
|
||||||
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils;
|
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils;
|
||||||
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils.ModuleTemplateType;
|
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils.ModuleTemplateType;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
|
@ -87,12 +88,12 @@ public class CreateGhidraModuleProjectWizard extends Wizard implements INewWizar
|
||||||
boolean createRunConfig = projectPage.shouldCreateRunConfig();
|
boolean createRunConfig = projectPage.shouldCreateRunConfig();
|
||||||
String runConfigMemory = projectPage.getRunConfigMemory();
|
String runConfigMemory = projectPage.getRunConfigMemory();
|
||||||
File projectDir = projectPage.getProjectDir();
|
File projectDir = projectPage.getProjectDir();
|
||||||
String jythonInterpreterName = pythonPage.getJythonInterpreterName();
|
ProjectPythonInterpreter pythonInterpreter = pythonPage.getProjectPythonInterpreter();
|
||||||
Set<ModuleTemplateType> moduleTemplateTypes = projectConfigPage.getModuleTemplateTypes();
|
Set<ModuleTemplateType> moduleTemplateTypes = projectConfigPage.getModuleTemplateTypes();
|
||||||
try {
|
try {
|
||||||
getContainer().run(true, false,
|
getContainer().run(true, false,
|
||||||
monitor -> create(ghidraInstallDir, projectName, projectDir, createRunConfig,
|
monitor -> create(ghidraInstallDir, projectName, projectDir, createRunConfig,
|
||||||
runConfigMemory, moduleTemplateTypes, jythonInterpreterName, monitor));
|
runConfigMemory, moduleTemplateTypes, pythonInterpreter, monitor));
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
@ -115,14 +116,13 @@ public class CreateGhidraModuleProjectWizard extends Wizard implements INewWizar
|
||||||
* @param createRunConfig Whether or not to create a new run configuration for the project.
|
* @param createRunConfig Whether or not to create a new run configuration for the project.
|
||||||
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
||||||
* @param moduleTemplateTypes The desired module template types.
|
* @param moduleTemplateTypes The desired module template types.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* Could be null if Python support is not wanted.
|
|
||||||
* @param monitor The monitor to use during project creation.
|
* @param monitor The monitor to use during project creation.
|
||||||
* @throws InvocationTargetException if an error occurred during project creation.
|
* @throws InvocationTargetException if an error occurred during project creation.
|
||||||
*/
|
*/
|
||||||
private void create(File ghidraInstallDir, String projectName, File projectDir,
|
private void create(File ghidraInstallDir, String projectName, File projectDir,
|
||||||
boolean createRunConfig, String runConfigMemory,
|
boolean createRunConfig, String runConfigMemory,
|
||||||
Set<ModuleTemplateType> moduleTemplateTypes, String jythonInterpreterName,
|
Set<ModuleTemplateType> moduleTemplateTypes, ProjectPythonInterpreter pythonInterpreter,
|
||||||
IProgressMonitor monitor) throws InvocationTargetException {
|
IProgressMonitor monitor) throws InvocationTargetException {
|
||||||
try {
|
try {
|
||||||
info("Creating " + projectName + " at " + projectDir);
|
info("Creating " + projectName + " at " + projectDir);
|
||||||
|
@ -133,7 +133,7 @@ public class CreateGhidraModuleProjectWizard extends Wizard implements INewWizar
|
||||||
|
|
||||||
IJavaProject javaProject =
|
IJavaProject javaProject =
|
||||||
GhidraModuleUtils.createGhidraModuleProject(projectName, projectDir,
|
GhidraModuleUtils.createGhidraModuleProject(projectName, projectDir,
|
||||||
createRunConfig, runConfigMemory, ghidraLayout, jythonInterpreterName, monitor);
|
createRunConfig, runConfigMemory, ghidraLayout, pythonInterpreter, monitor);
|
||||||
monitor.worked(1);
|
monitor.worked(1);
|
||||||
|
|
||||||
IFile sourceFile = GhidraModuleUtils.configureModuleSource(javaProject,
|
IFile sourceFile = GhidraModuleUtils.configureModuleSource(javaProject,
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -32,6 +32,7 @@ import org.eclipse.ui.IWorkbench;
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidradev.EclipseMessageUtils;
|
import ghidradev.EclipseMessageUtils;
|
||||||
import ghidradev.ghidraprojectcreator.utils.GhidraScriptUtils;
|
import ghidradev.ghidraprojectcreator.utils.GhidraScriptUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
|
@ -81,11 +82,11 @@ public class CreateGhidraScriptProjectWizard extends Wizard implements INewWizar
|
||||||
String runConfigMemory = projectPage.getRunConfigMemory();
|
String runConfigMemory = projectPage.getRunConfigMemory();
|
||||||
boolean linkUserScripts = projectConfigPage.shouldLinkUsersScripts();
|
boolean linkUserScripts = projectConfigPage.shouldLinkUsersScripts();
|
||||||
boolean linkSystemScripts = projectConfigPage.shouldLinkSystemScripts();
|
boolean linkSystemScripts = projectConfigPage.shouldLinkSystemScripts();
|
||||||
String jythonInterpreterName = pythonPage.getJythonInterpreterName();
|
ProjectPythonInterpreter pythonInterpreter = pythonPage.getProjectPythonInterpreter();
|
||||||
try {
|
try {
|
||||||
getContainer().run(true, false,
|
getContainer().run(true, false,
|
||||||
monitor -> create(ghidraInstallDir, projectName, projectDir, createRunConfig,
|
monitor -> create(ghidraInstallDir, projectName, projectDir, createRunConfig,
|
||||||
runConfigMemory, linkUserScripts, linkSystemScripts, jythonInterpreterName,
|
runConfigMemory, linkUserScripts, linkSystemScripts, pythonInterpreter,
|
||||||
monitor));
|
monitor));
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
|
@ -110,15 +111,14 @@ public class CreateGhidraScriptProjectWizard extends Wizard implements INewWizar
|
||||||
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
||||||
* @param linkUserScripts Whether or not to link in the user scripts directory.
|
* @param linkUserScripts Whether or not to link in the user scripts directory.
|
||||||
* @param linkSystemScripts Whether or not to link in the system scripts directories.
|
* @param linkSystemScripts Whether or not to link in the system scripts directories.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* Could be null if Python support is not wanted.
|
|
||||||
* @param monitor The monitor to use during project creation.
|
* @param monitor The monitor to use during project creation.
|
||||||
* @throws InvocationTargetException if an error occurred during project creation.
|
* @throws InvocationTargetException if an error occurred during project creation.
|
||||||
*/
|
*/
|
||||||
private void create(File ghidraInstallDir, String projectName, File projectDir,
|
private void create(File ghidraInstallDir, String projectName, File projectDir,
|
||||||
boolean createRunConfig, String runConfigMemory, boolean linkUserScripts,
|
boolean createRunConfig, String runConfigMemory, boolean linkUserScripts,
|
||||||
boolean linkSystemScripts, String jythonInterpreterName, IProgressMonitor monitor)
|
boolean linkSystemScripts, ProjectPythonInterpreter pythonInterpreter,
|
||||||
throws InvocationTargetException {
|
IProgressMonitor monitor) throws InvocationTargetException {
|
||||||
try {
|
try {
|
||||||
info("Creating " + projectName + " at " + projectDir);
|
info("Creating " + projectName + " at " + projectDir);
|
||||||
monitor.beginTask("Creating " + projectName, 2);
|
monitor.beginTask("Creating " + projectName, 2);
|
||||||
|
@ -128,7 +128,7 @@ public class CreateGhidraScriptProjectWizard extends Wizard implements INewWizar
|
||||||
|
|
||||||
GhidraScriptUtils.createGhidraScriptProject(projectName, projectDir, createRunConfig,
|
GhidraScriptUtils.createGhidraScriptProject(projectName, projectDir, createRunConfig,
|
||||||
runConfigMemory, linkUserScripts, linkSystemScripts, ghidraLayout,
|
runConfigMemory, linkUserScripts, linkSystemScripts, ghidraLayout,
|
||||||
jythonInterpreterName, monitor);
|
pythonInterpreter, monitor);
|
||||||
monitor.worked(1);
|
monitor.worked(1);
|
||||||
|
|
||||||
info("Finished creating " + projectName);
|
info("Finished creating " + projectName);
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -40,7 +40,7 @@ import org.eclipse.ui.INewWizard;
|
||||||
import org.eclipse.ui.IWorkbench;
|
import org.eclipse.ui.IWorkbench;
|
||||||
|
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidra.launch.JavaConfig;
|
import ghidra.launch.AppConfig;
|
||||||
import ghidradev.EclipseMessageUtils;
|
import ghidradev.EclipseMessageUtils;
|
||||||
import ghidradev.ghidraprojectcreator.utils.GhidraProjectUtils;
|
import ghidradev.ghidraprojectcreator.utils.GhidraProjectUtils;
|
||||||
import ghidradev.ghidraprojectcreator.wizards.pages.ChooseGhidraModuleProjectWizardPage;
|
import ghidradev.ghidraprojectcreator.wizards.pages.ChooseGhidraModuleProjectWizardPage;
|
||||||
|
@ -123,7 +123,7 @@ public class ExportGhidraModuleWizard extends Wizard implements INewWizard {
|
||||||
// TODO: It's more correct to get this from the project's classpath, since Ghidra's
|
// TODO: It's more correct to get this from the project's classpath, since Ghidra's
|
||||||
// saved Java home can change from launch to launch.
|
// saved Java home can change from launch to launch.
|
||||||
GhidraApplicationLayout ghidraLayout = new GhidraApplicationLayout(new File(ghidraInstallDirPath));
|
GhidraApplicationLayout ghidraLayout = new GhidraApplicationLayout(new File(ghidraInstallDirPath));
|
||||||
File javaHomeDir = new JavaConfig(
|
File javaHomeDir = new AppConfig(
|
||||||
ghidraLayout.getApplicationInstallationDir().getFile(false)).getSavedJavaHome();
|
ghidraLayout.getApplicationInstallationDir().getFile(false)).getSavedJavaHome();
|
||||||
if(javaHomeDir == null) {
|
if(javaHomeDir == null) {
|
||||||
throw new IOException("Failed to get the Java home associated with the project. " +
|
throw new IOException("Failed to get the Java home associated with the project. " +
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -32,6 +32,7 @@ import org.eclipse.ui.IWorkbench;
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidradev.EclipseMessageUtils;
|
import ghidradev.EclipseMessageUtils;
|
||||||
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils;
|
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
|
@ -76,11 +77,11 @@ public class ImportGhidraModuleSourceWizard extends Wizard implements IImportWiz
|
||||||
String projectName = projectPage.getProjectName();
|
String projectName = projectPage.getProjectName();
|
||||||
boolean createRunConfig = projectPage.shouldCreateRunConfig();
|
boolean createRunConfig = projectPage.shouldCreateRunConfig();
|
||||||
String runConfigMemory = projectPage.getRunConfigMemory();
|
String runConfigMemory = projectPage.getRunConfigMemory();
|
||||||
String jythonInterpreterName = pythonPage.getJythonInterpreterName();
|
ProjectPythonInterpreter pythonInterpreter = pythonPage.getProjectPythonInterpreter();
|
||||||
try {
|
try {
|
||||||
getContainer().run(true, false,
|
getContainer().run(true, false,
|
||||||
monitor -> importModuleSource(ghidraInstallDir, projectName, moduleSourceDir,
|
monitor -> importModuleSource(ghidraInstallDir, projectName, moduleSourceDir,
|
||||||
createRunConfig, runConfigMemory, jythonInterpreterName, monitor));
|
createRunConfig, runConfigMemory, pythonInterpreter, monitor));
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
@ -102,14 +103,14 @@ public class ImportGhidraModuleSourceWizard extends Wizard implements IImportWiz
|
||||||
* @param moduleSourceDir The module source directory to import.
|
* @param moduleSourceDir The module source directory to import.
|
||||||
* @param createRunConfig Whether or not to create a new run configuration for the project.
|
* @param createRunConfig Whether or not to create a new run configuration for the project.
|
||||||
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
* @param runConfigMemory The run configuration's desired memory. Could be null.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* Could be null if Python support is not wanted.
|
|
||||||
* @param monitor The monitor to use during project creation.
|
* @param monitor The monitor to use during project creation.
|
||||||
* @throws InvocationTargetException if an error occurred during project creation.
|
* @throws InvocationTargetException if an error occurred during project creation.
|
||||||
*/
|
*/
|
||||||
private void importModuleSource(File ghidraInstallDir, String projectName, File moduleSourceDir,
|
private void importModuleSource(File ghidraInstallDir, String projectName, File moduleSourceDir,
|
||||||
boolean createRunConfig, String runConfigMemory, String jythonInterpreterName,
|
boolean createRunConfig, String runConfigMemory,
|
||||||
IProgressMonitor monitor) throws InvocationTargetException {
|
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||||
|
throws InvocationTargetException {
|
||||||
try {
|
try {
|
||||||
info("Importing " + projectName + " at " + moduleSourceDir);
|
info("Importing " + projectName + " at " + moduleSourceDir);
|
||||||
monitor.beginTask("Importing " + projectName, 2);
|
monitor.beginTask("Importing " + projectName, 2);
|
||||||
|
@ -118,7 +119,7 @@ public class ImportGhidraModuleSourceWizard extends Wizard implements IImportWiz
|
||||||
monitor.worked(1);
|
monitor.worked(1);
|
||||||
|
|
||||||
GhidraModuleUtils.importGhidraModuleSource(projectName, moduleSourceDir,
|
GhidraModuleUtils.importGhidraModuleSource(projectName, moduleSourceDir,
|
||||||
createRunConfig, runConfigMemory, ghidraLayout, jythonInterpreterName, monitor);
|
createRunConfig, runConfigMemory, ghidraLayout, pythonInterpreter, monitor);
|
||||||
monitor.worked(1);
|
monitor.worked(1);
|
||||||
|
|
||||||
info("Finished importing " + projectName);
|
info("Finished importing " + projectName);
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -31,8 +31,9 @@ import org.eclipse.jface.viewers.ISelection;
|
||||||
import org.eclipse.jface.wizard.Wizard;
|
import org.eclipse.jface.wizard.Wizard;
|
||||||
|
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidra.launch.JavaConfig;
|
import ghidra.launch.AppConfig;
|
||||||
import ghidradev.ghidraprojectcreator.utils.GhidraProjectUtils;
|
import ghidradev.ghidraprojectcreator.utils.GhidraProjectUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,10 +64,10 @@ public class LinkGhidraWizard extends Wizard {
|
||||||
public boolean performFinish() {
|
public boolean performFinish() {
|
||||||
File ghidraInstallDir = ghidraInstallationPage.getGhidraInstallDir();
|
File ghidraInstallDir = ghidraInstallationPage.getGhidraInstallDir();
|
||||||
IJavaProject javaProject = projectPage.getJavaProject();
|
IJavaProject javaProject = projectPage.getJavaProject();
|
||||||
String jythonInterpreterName = pythonPage.getJythonInterpreterName();
|
ProjectPythonInterpreter pythonInterpreter = pythonPage.getProjectPythonInterpreter();
|
||||||
try {
|
try {
|
||||||
getContainer().run(true, false,
|
getContainer().run(true, false,
|
||||||
monitor -> link(ghidraInstallDir, javaProject, jythonInterpreterName, monitor));
|
monitor -> link(ghidraInstallDir, javaProject, pythonInterpreter, monitor));
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
@ -85,23 +86,23 @@ public class LinkGhidraWizard extends Wizard {
|
||||||
*
|
*
|
||||||
* @param ghidraInstallDir The Ghidra installation directory to use.
|
* @param ghidraInstallDir The Ghidra installation directory to use.
|
||||||
* @param javaProject The Java project to link.
|
* @param javaProject The Java project to link.
|
||||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
* @param pythonInterpreter The Python interpreter to use.
|
||||||
* Could be null if Python support is not wanted.
|
|
||||||
* @param monitor The monitor to use during project link.
|
* @param monitor The monitor to use during project link.
|
||||||
* @throws InvocationTargetException if an error occurred during link.
|
* @throws InvocationTargetException if an error occurred during link.
|
||||||
*/
|
*/
|
||||||
private void link(File ghidraInstallDir, IJavaProject javaProject, String jythonInterpreterName,
|
private void link(File ghidraInstallDir, IJavaProject javaProject,
|
||||||
IProgressMonitor monitor) throws InvocationTargetException {
|
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||||
|
throws InvocationTargetException {
|
||||||
IProject project = javaProject.getProject();
|
IProject project = javaProject.getProject();
|
||||||
try {
|
try {
|
||||||
info("Linking " + project.getName());
|
info("Linking " + project.getName());
|
||||||
monitor.beginTask("Linking " + project.getName(), 2);
|
monitor.beginTask("Linking " + project.getName(), 2);
|
||||||
|
|
||||||
GhidraApplicationLayout ghidraLayout = new GhidraApplicationLayout(ghidraInstallDir);
|
GhidraApplicationLayout ghidraLayout = new GhidraApplicationLayout(ghidraInstallDir);
|
||||||
JavaConfig javaConfig =
|
AppConfig appConfig =
|
||||||
new JavaConfig(ghidraLayout.getApplicationInstallationDir().getFile(false));
|
new AppConfig(ghidraLayout.getApplicationInstallationDir().getFile(false));
|
||||||
GhidraProjectUtils.linkGhidraToProject(javaProject, ghidraLayout, javaConfig,
|
GhidraProjectUtils.linkGhidraToProject(javaProject, ghidraLayout, appConfig,
|
||||||
jythonInterpreterName, monitor);
|
pythonInterpreter, monitor);
|
||||||
monitor.worked(1);
|
monitor.worked(1);
|
||||||
|
|
||||||
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
|
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -27,7 +27,7 @@ import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.*;
|
import org.eclipse.swt.widgets.*;
|
||||||
import org.eclipse.ui.dialogs.PreferencesUtil;
|
import org.eclipse.ui.dialogs.PreferencesUtil;
|
||||||
|
|
||||||
import ghidra.launch.JavaConfig;
|
import ghidra.launch.AppConfig;
|
||||||
import ghidra.launch.JavaFinder.JavaFilter;
|
import ghidra.launch.JavaFinder.JavaFilter;
|
||||||
import ghidradev.ghidraprojectcreator.preferences.GhidraProjectCreatorPreferencePage;
|
import ghidradev.ghidraprojectcreator.preferences.GhidraProjectCreatorPreferencePage;
|
||||||
import ghidradev.ghidraprojectcreator.preferences.GhidraProjectCreatorPreferences;
|
import ghidradev.ghidraprojectcreator.preferences.GhidraProjectCreatorPreferences;
|
||||||
|
@ -108,8 +108,8 @@ public class ChooseGhidraInstallationWizardPage extends WizardPage {
|
||||||
File ghidraInstallDir = new File(ghidraInstallDirCombo.getText());
|
File ghidraInstallDir = new File(ghidraInstallDirCombo.getText());
|
||||||
GhidraProjectCreatorPreferencePage.validateGhidraInstallation(ghidraInstallDir);
|
GhidraProjectCreatorPreferencePage.validateGhidraInstallation(ghidraInstallDir);
|
||||||
try {
|
try {
|
||||||
JavaConfig javaConfig = new JavaConfig(ghidraInstallDir);
|
AppConfig appConfig = new AppConfig(ghidraInstallDir);
|
||||||
if (!javaConfig.isSupportedJavaHomeDir(javaConfig.getSavedJavaHome(),
|
if (!appConfig.isSupportedJavaHomeDir(appConfig.getSavedJavaHome(),
|
||||||
JavaFilter.JDK_ONLY)) {
|
JavaFilter.JDK_ONLY)) {
|
||||||
message = "A supported JDK is not associated with this Ghidra " +
|
message = "A supported JDK is not associated with this Ghidra " +
|
||||||
"installation. Please run this Ghidra and try again.";
|
"installation. Please run this Ghidra and try again.";
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidradev.ghidraprojectcreator.wizards.pages;
|
package ghidradev.ghidraprojectcreator.wizards.pages;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -27,13 +26,15 @@ import org.eclipse.jface.wizard.WizardPage;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.events.SelectionEvent;
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
import org.eclipse.swt.events.SelectionListener;
|
import org.eclipse.swt.events.SelectionListener;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.*;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
|
||||||
import org.eclipse.swt.widgets.*;
|
import org.eclipse.swt.widgets.*;
|
||||||
import org.eclipse.ui.dialogs.PreferencesUtil;
|
import org.eclipse.ui.dialogs.PreferencesUtil;
|
||||||
|
|
||||||
|
import ghidra.launch.AppConfig;
|
||||||
import ghidradev.EclipseMessageUtils;
|
import ghidradev.EclipseMessageUtils;
|
||||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils;
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||||
|
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreterType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wizard page that lets the user enable python for their project.
|
* A wizard page that lets the user enable python for their project.
|
||||||
|
@ -41,7 +42,11 @@ import ghidradev.ghidraprojectcreator.utils.PyDevUtils;
|
||||||
public class EnablePythonWizardPage extends WizardPage {
|
public class EnablePythonWizardPage extends WizardPage {
|
||||||
|
|
||||||
private ChooseGhidraInstallationWizardPage ghidraInstallationPage;
|
private ChooseGhidraInstallationWizardPage ghidraInstallationPage;
|
||||||
private Button enablePythonCheckboxButton;
|
private Button pyghidraButton;
|
||||||
|
private Button jythonButton;
|
||||||
|
private Button noneButton;
|
||||||
|
private Combo pyghidraCombo;
|
||||||
|
private Button addPyGhidraButton;
|
||||||
private Combo jythonCombo;
|
private Combo jythonCombo;
|
||||||
private Button addJythonButton;
|
private Button addJythonButton;
|
||||||
|
|
||||||
|
@ -61,46 +66,107 @@ public class EnablePythonWizardPage extends WizardPage {
|
||||||
public void createControl(Composite parent) {
|
public void createControl(Composite parent) {
|
||||||
|
|
||||||
Composite container = new Composite(parent, SWT.NULL);
|
Composite container = new Composite(parent, SWT.NULL);
|
||||||
container.setLayout(new GridLayout(3, false));
|
container.setLayout(new GridLayout(1, false));
|
||||||
|
|
||||||
// Enable Python checkbox.
|
// Project type selection
|
||||||
enablePythonCheckboxButton = new Button(container, SWT.CHECK);
|
SelectionListener projectTypeSelectionListener = new SelectionListener() {
|
||||||
enablePythonCheckboxButton.setText("Enable Python");
|
|
||||||
enablePythonCheckboxButton.setToolTipText("Enables Python support using the PyDev " +
|
|
||||||
"Eclipse plugin. Requires PyDev version " + PyDevUtils.MIN_SUPPORTED_VERSION +
|
|
||||||
" - " + PyDevUtils.MAX_SUPPORTED_VERSION);
|
|
||||||
enablePythonCheckboxButton.setSelection(PyDevUtils.isSupportedPyDevInstalled());
|
|
||||||
enablePythonCheckboxButton.addSelectionListener(new SelectionListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void widgetSelected(SelectionEvent evt) {
|
public void widgetSelected(SelectionEvent evt) {
|
||||||
validate();
|
validate(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void widgetDefaultSelected(SelectionEvent evt) {
|
public void widgetDefaultSelected(SelectionEvent evt) {
|
||||||
validate();
|
validate(null);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
Group projectTypeGroup = new Group(container, SWT.SHADOW_ETCHED_OUT);
|
||||||
|
projectTypeGroup.setLayout(new RowLayout(SWT.HORIZONTAL));
|
||||||
|
projectTypeGroup.setText("Project Type");
|
||||||
|
pyghidraButton = new Button(projectTypeGroup, SWT.RADIO);
|
||||||
|
pyghidraButton.setSelection(PyDevUtils.isSupportedPyGhidraPyDevInstalled());
|
||||||
|
pyghidraButton.setText("PyGhidra");
|
||||||
|
pyghidraButton.setToolTipText("Enables PyGhidra support using the PyDev " +
|
||||||
|
"Eclipse plugin. Requires PyDev version " + PyDevUtils.MIN_SUPPORTED_VERSION +
|
||||||
|
" or later.");
|
||||||
|
pyghidraButton.addSelectionListener(projectTypeSelectionListener);
|
||||||
|
jythonButton = new Button(projectTypeGroup, SWT.RADIO);
|
||||||
|
jythonButton.setSelection(false);
|
||||||
|
jythonButton.setText("Jython");
|
||||||
|
jythonButton.setToolTipText("Enables Jython support using the PyDev " +
|
||||||
|
"Eclipse plugin. Requires PyDev version " + PyDevUtils.MIN_SUPPORTED_VERSION +
|
||||||
|
" - " + PyDevUtils.MAX_JYTHON_SUPPORTED_VERSION);
|
||||||
|
jythonButton.addSelectionListener(projectTypeSelectionListener);
|
||||||
|
noneButton = new Button(projectTypeGroup, SWT.RADIO);
|
||||||
|
noneButton.setSelection(!PyDevUtils.isSupportedPyGhidraPyDevInstalled());
|
||||||
|
noneButton.setText("None");
|
||||||
|
noneButton.setToolTipText("Disables Python support for the project.");
|
||||||
|
noneButton.addSelectionListener(projectTypeSelectionListener);
|
||||||
|
|
||||||
|
Composite interpreterContainer = new Composite(container, SWT.NULL);
|
||||||
|
interpreterContainer.setLayout(new GridLayout(3, false));
|
||||||
|
interpreterContainer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
|
||||||
|
// PyGhidra interpreter combo box
|
||||||
|
Label pyGhidraLabel = new Label(interpreterContainer, SWT.NULL);
|
||||||
|
pyGhidraLabel.setText("PyGhidra interpreter:");
|
||||||
|
pyghidraCombo = new Combo(interpreterContainer, SWT.DROP_DOWN | SWT.READ_ONLY);
|
||||||
|
pyghidraCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
pyghidraCombo.setToolTipText("The wizard requires a Python interpreter to be " +
|
||||||
|
"selected. Click the + button to add or manage Python interpreters.");
|
||||||
|
File savedPyGhidraInterpreter = populatePyGhidraCombo(null);
|
||||||
|
pyghidraCombo.addModifyListener(evt -> validate(null));
|
||||||
|
|
||||||
|
// PyGhidra interpreter add button
|
||||||
|
addPyGhidraButton = new Button(interpreterContainer, SWT.BUTTON1);
|
||||||
|
addPyGhidraButton.setText("+");
|
||||||
|
addPyGhidraButton.setToolTipText("Adds/manages PyGhidra interpreters.");
|
||||||
|
addPyGhidraButton.addListener(SWT.Selection, evt -> {
|
||||||
|
try {
|
||||||
|
File ghidraDir = ghidraInstallationPage.getGhidraInstallDir();
|
||||||
|
File pyghidraInterpreter = findPyGhidraInterpreter();
|
||||||
|
File pypredefDir = new File(ghidraDir, "docs/ghidra_stubs/pypredef");
|
||||||
|
if (!pypredefDir.isDirectory()) {
|
||||||
|
pypredefDir = null;
|
||||||
|
}
|
||||||
|
if (EclipseMessageUtils.showQuestionDialog("Python Found",
|
||||||
|
"PyGhidra was previously launched with: \"" + pyghidraInterpreter +
|
||||||
|
"\". Would you like to use it as your interpreter?")) {
|
||||||
|
PyDevUtils.addPyGhidraInterpreter("pyghidra_" + ghidraDir.getName(),
|
||||||
|
pyghidraInterpreter, pypredefDir);
|
||||||
|
populatePyGhidraCombo(pyghidraInterpreter);
|
||||||
|
validate(pyghidraInterpreter);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// Fall through to show PyDev's Python preference page
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(null,
|
||||||
|
PyDevUtils.getPythonPreferencePageId(), null, null);
|
||||||
|
dialog.open();
|
||||||
|
populatePyGhidraCombo(savedPyGhidraInterpreter);
|
||||||
|
validate(null);
|
||||||
});
|
});
|
||||||
new Label(container, SWT.NONE).setText(""); // filler
|
|
||||||
new Label(container, SWT.NONE).setText(""); // filler
|
|
||||||
|
|
||||||
// Jython interpreter combo box
|
// Jython interpreter combo box
|
||||||
Label jythonLabel = new Label(container, SWT.NULL);
|
Label jythonLabel = new Label(interpreterContainer, SWT.NULL);
|
||||||
jythonLabel.setText("Jython interpreter:");
|
jythonLabel.setText("Jython interpreter:");
|
||||||
jythonCombo = new Combo(container, SWT.DROP_DOWN | SWT.READ_ONLY);
|
jythonCombo = new Combo(interpreterContainer, SWT.DROP_DOWN | SWT.READ_ONLY);
|
||||||
jythonCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
jythonCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
jythonCombo.setToolTipText("The wizard requires a Jython interpreter to be " +
|
jythonCombo.setToolTipText("The wizard requires a Jython interpreter to be " +
|
||||||
"selected. Click the + button to add or manage Jython interpreters.");
|
"selected. Click the + button to add or manage Jython interpreters.");
|
||||||
populateJythonCombo();
|
populateJythonCombo();
|
||||||
jythonCombo.addModifyListener(evt -> validate());
|
jythonCombo.addModifyListener(evt -> validate(null));
|
||||||
|
|
||||||
// Jython interpreter add button
|
// Jython interpreter add button
|
||||||
addJythonButton = new Button(container, SWT.BUTTON1);
|
addJythonButton = new Button(interpreterContainer, SWT.BUTTON1);
|
||||||
addJythonButton.setText("+");
|
addJythonButton.setText("+");
|
||||||
addJythonButton.setToolTipText("Adds/manages Jython interpreters.");
|
addJythonButton.setToolTipText("Adds/manages Jython interpreters.");
|
||||||
addJythonButton.addListener(SWT.Selection, evt -> {
|
addJythonButton.addListener(SWT.Selection, evt -> {
|
||||||
try {
|
try {
|
||||||
if (PyDevUtils.getJython27InterpreterNames().isEmpty()) {
|
if (PyDevUtils.getJythonInterpreterNames().isEmpty()) {
|
||||||
File ghidraDir = ghidraInstallationPage.getGhidraInstallDir();
|
File ghidraDir = ghidraInstallationPage.getGhidraInstallDir();
|
||||||
File jythonFile = findJythonInterpreter(ghidraDir);
|
File jythonFile = findJythonInterpreter(ghidraDir);
|
||||||
File jythonLib = findJythonLibrary(ghidraDir);
|
File jythonLib = findJythonLibrary(ghidraDir);
|
||||||
|
@ -111,7 +177,7 @@ public class EnablePythonWizardPage extends WizardPage {
|
||||||
PyDevUtils.addJythonInterpreter("jython_" + ghidraDir.getName(),
|
PyDevUtils.addJythonInterpreter("jython_" + ghidraDir.getName(),
|
||||||
jythonFile, jythonLib);
|
jythonFile, jythonLib);
|
||||||
populateJythonCombo();
|
populateJythonCombo();
|
||||||
validate();
|
validate(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,80 +190,142 @@ public class EnablePythonWizardPage extends WizardPage {
|
||||||
PyDevUtils.getJythonPreferencePageId(), null, null);
|
PyDevUtils.getJythonPreferencePageId(), null, null);
|
||||||
dialog.open();
|
dialog.open();
|
||||||
populateJythonCombo();
|
populateJythonCombo();
|
||||||
validate();
|
validate(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
validate();
|
validate(savedPyGhidraInterpreter);
|
||||||
setControl(container);
|
setControl(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Checks whether or not Python should be enabled.
|
public void setVisible(boolean visible) {
|
||||||
*
|
if (visible) {
|
||||||
* @return True if python should be enabled; otherwise, false.
|
validate(populatePyGhidraCombo(null));
|
||||||
*/
|
}
|
||||||
public boolean shouldEnablePython() {
|
super.setVisible(visible);
|
||||||
return enablePythonCheckboxButton.getSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of the Jython interpreter to use.
|
* {@return the project Python interpreter to use}
|
||||||
*
|
|
||||||
* @return The name of the Jython interpreter to use. Could be null of Python isn't
|
|
||||||
* enabled.
|
|
||||||
*/
|
*/
|
||||||
public String getJythonInterpreterName() {
|
public ProjectPythonInterpreter getProjectPythonInterpreter() {
|
||||||
if (enablePythonCheckboxButton.getSelection()) {
|
if (pyghidraButton.getSelection()) {
|
||||||
return jythonCombo.getText();
|
return new ProjectPythonInterpreter(pyghidraCombo.getText(),
|
||||||
|
ProjectPythonInterpreterType.PYGHIDRA);
|
||||||
}
|
}
|
||||||
return null;
|
if (jythonButton.getSelection()) {
|
||||||
|
return new ProjectPythonInterpreter(jythonCombo.getText(),
|
||||||
|
ProjectPythonInterpreterType.JYTHON);
|
||||||
|
}
|
||||||
|
return new ProjectPythonInterpreter(null, ProjectPythonInterpreterType.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the fields on the page and updates the page's status.
|
* Validates the fields on the page and updates the page's status.
|
||||||
* Should be called every time a field on the page changes.
|
* Should be called every time a field on the page changes.
|
||||||
|
*
|
||||||
|
* @param pyghidraInterpreter The Python interpreter used to launch PyGhidra (could be null if
|
||||||
|
* unknown).
|
||||||
*/
|
*/
|
||||||
private void validate() {
|
private void validate(File pyghidraInterpreter) {
|
||||||
String message = null;
|
String message = null;
|
||||||
boolean pyDevInstalled = PyDevUtils.isSupportedPyDevInstalled();
|
boolean pyghidraSupported = PyDevUtils.isSupportedPyGhidraPyDevInstalled();
|
||||||
boolean pyDevEnabled = enablePythonCheckboxButton.getSelection();
|
boolean jythonSupported = PyDevUtils.isSupportedJythonPyDevInstalled();
|
||||||
boolean comboEnabled = pyDevInstalled && pyDevEnabled;
|
|
||||||
|
|
||||||
if (pyDevEnabled) {
|
if (pyghidraButton.getSelection()) {
|
||||||
if (!pyDevInstalled) {
|
if (!pyghidraSupported) {
|
||||||
message = "PyDev version " + PyDevUtils.MIN_SUPPORTED_VERSION +
|
message = "PyDev version " + PyDevUtils.MIN_SUPPORTED_VERSION +
|
||||||
" - " + PyDevUtils.MAX_SUPPORTED_VERSION + " is not installed.";
|
" or later is not installed.";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
List<String> interpreters = PyDevUtils.getJython27InterpreterNames();
|
if (pyghidraInterpreter == null) {
|
||||||
if (interpreters.isEmpty()) {
|
pyghidraInterpreter = findPyGhidraInterpreter();
|
||||||
message = "No Jython interpreters found. Click the + button to add one.";
|
}
|
||||||
|
if (pyghidraInterpreter == null) {
|
||||||
|
message =
|
||||||
|
"Please first launch PyGhidra to associate the Ghidra installation with a supported version of Python.";
|
||||||
|
pyghidraSupported = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
List<String> interpreters =
|
||||||
|
PyDevUtils.getPyGhidraInterpreterNames(pyghidraInterpreter);
|
||||||
|
if (interpreters.isEmpty()) {
|
||||||
|
message ="No PyGhidra interpreters found. Click the + button or set project type to \"None\".";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OperationNotSupportedException e) {
|
catch (OperationNotSupportedException e) {
|
||||||
message = "PyDev version is not supported.";
|
message = "PyDev version is not supported for Jython.";
|
||||||
comboEnabled = false;
|
pyghidraSupported = false;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
message =
|
||||||
|
"Failed to lookup Python interpreter associated with the Ghidra installation.";
|
||||||
|
pyghidraSupported = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (jythonButton.getSelection()) {
|
||||||
|
if (!jythonSupported) {
|
||||||
|
message = "PyDev version " + PyDevUtils.MIN_SUPPORTED_VERSION +
|
||||||
|
" - " + PyDevUtils.MAX_JYTHON_SUPPORTED_VERSION + " is not installed.";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
List<String> interpreters = PyDevUtils.getJythonInterpreterNames();
|
||||||
|
if (interpreters.isEmpty()) {
|
||||||
|
message =
|
||||||
|
"No Jython interpreters found. Click the + button or set project type to \"None\".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationNotSupportedException e) {
|
||||||
|
message = "PyDev version is not supported for Jython.";
|
||||||
|
jythonSupported = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jythonCombo.setEnabled(comboEnabled);
|
pyghidraCombo.setEnabled(pyghidraButton.getSelection() && pyghidraSupported);
|
||||||
addJythonButton.setEnabled(comboEnabled);
|
addPyGhidraButton.setEnabled(pyghidraButton.getSelection() && pyghidraSupported);
|
||||||
|
jythonCombo.setEnabled(jythonButton.getSelection() && jythonSupported);
|
||||||
|
addJythonButton.setEnabled(jythonButton.getSelection() && jythonSupported);
|
||||||
|
|
||||||
setErrorMessage(message);
|
setErrorMessage(message);
|
||||||
setPageComplete(message == null);
|
setPageComplete(message == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates the Jython combo box with discovered Jython names.
|
* Populates the PyGhidra combo box with discovered PyGhidra interpreter names.
|
||||||
|
*
|
||||||
|
* @param pyghidraInterpreter The Python interpreter used to launch PyGhidra (could be null if
|
||||||
|
* unknown).
|
||||||
|
* @return The Python interpreter used to launch PyGhidra (could be null if unknown).
|
||||||
|
*/
|
||||||
|
private File populatePyGhidraCombo(File pyghidraInterpreter) {
|
||||||
|
pyghidraCombo.removeAll();
|
||||||
|
try {
|
||||||
|
if (pyghidraInterpreter == null) {
|
||||||
|
pyghidraInterpreter = findPyGhidraInterpreter();
|
||||||
|
}
|
||||||
|
PyDevUtils.getPyGhidraInterpreterNames(pyghidraInterpreter).forEach(pyghidraCombo::add);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// Nothing to do. Combo should and will be empty.
|
||||||
|
}
|
||||||
|
if (pyghidraCombo.getItemCount() > 0) {
|
||||||
|
pyghidraCombo.select(0);
|
||||||
|
}
|
||||||
|
return pyghidraInterpreter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the Jython combo box with discovered Jython interpreter names.
|
||||||
*/
|
*/
|
||||||
private void populateJythonCombo() {
|
private void populateJythonCombo() {
|
||||||
jythonCombo.removeAll();
|
jythonCombo.removeAll();
|
||||||
try {
|
try {
|
||||||
for (String jythonName : PyDevUtils.getJython27InterpreterNames()) {
|
PyDevUtils.getJythonInterpreterNames().forEach(jythonCombo::add);
|
||||||
jythonCombo.add(jythonName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (OperationNotSupportedException e) {
|
catch (OperationNotSupportedException e) {
|
||||||
// Nothing to do. Combo should and will be empty.
|
// Nothing to do. Combo should and will be empty.
|
||||||
|
@ -207,6 +335,32 @@ public class EnablePythonWizardPage extends WizardPage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find's the Python interpreter file that was used to launch PyGhidra.
|
||||||
|
*
|
||||||
|
* @return The Python interpreter file that was used to launch PyGhidra, or null if one could
|
||||||
|
* not be found.
|
||||||
|
* @throws Exception if there was a problem finding the Python interpreter.
|
||||||
|
*/
|
||||||
|
private File findPyGhidraInterpreter() throws Exception {
|
||||||
|
File ghidraDir = ghidraInstallationPage.getGhidraInstallDir();
|
||||||
|
AppConfig appConfig = new AppConfig(ghidraDir);
|
||||||
|
List<String> cmd = appConfig.getSavedPythonCommand();
|
||||||
|
if (cmd == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cmd.add("-c");
|
||||||
|
cmd.add("import sys; print(sys.executable)");
|
||||||
|
Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
|
||||||
|
BufferedReader reader =
|
||||||
|
new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
String pythonExecutable = reader.readLine();
|
||||||
|
if (p.waitFor() == 0) {
|
||||||
|
return new File(pythonExecutable);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find's a Jython interpreter file in the given Ghidra installation directory.
|
* Find's a Jython interpreter file in the given Ghidra installation directory.
|
||||||
*
|
*
|
||||||
|
|
|
@ -13,6 +13,7 @@ GhidraDevPlugin/icons/GhidraIcon16_bw.png||GHIDRA||||END|
|
||||||
GhidraDevPlugin/icons/brick_add.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
GhidraDevPlugin/icons/brick_add.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||||
GhidraDevPlugin/icons/brick_go.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
GhidraDevPlugin/icons/brick_go.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||||
GhidraDevPlugin/icons/folder_link.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
GhidraDevPlugin/icons/folder_link.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||||
|
GhidraDevPlugin/icons/python.png||GHIDRA||||END|
|
||||||
GhidraDevPlugin/icons/script_add.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
GhidraDevPlugin/icons/script_add.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||||
GhidraDevPlugin/icons/script_code_red.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
GhidraDevPlugin/icons/script_code_red.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||||
GhidraDevPlugin/plugin.xml||GHIDRA||||END|
|
GhidraDevPlugin/plugin.xml||GHIDRA||||END|
|
||||||
|
|
|
@ -78,20 +78,20 @@ public class LaunchSupport {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
File installDir = new File(installDirPath).getCanonicalFile(); // change relative path to absolute
|
File installDir = new File(installDirPath).getCanonicalFile(); // change relative path to absolute
|
||||||
JavaConfig javaConfig = new JavaConfig(installDir);
|
AppConfig appConfig = new AppConfig(installDir);
|
||||||
JavaFinder javaFinder = JavaFinder.create();
|
JavaFinder javaFinder = JavaFinder.create();
|
||||||
|
|
||||||
// Pass control to a mode-specific handler
|
// Pass control to a mode-specific handler
|
||||||
switch (mode.toLowerCase()) {
|
switch (mode.toLowerCase()) {
|
||||||
case "-java_home":
|
case "-java_home":
|
||||||
exitCode = handleJavaHome(javaConfig, javaFinder, JavaFilter.ANY, ask, save);
|
exitCode = handleJavaHome(appConfig, javaFinder, JavaFilter.ANY, ask, save);
|
||||||
break;
|
break;
|
||||||
case "-jdk_home":
|
case "-jdk_home":
|
||||||
exitCode =
|
exitCode =
|
||||||
handleJavaHome(javaConfig, javaFinder, JavaFilter.JDK_ONLY, ask, save);
|
handleJavaHome(appConfig, javaFinder, JavaFilter.JDK_ONLY, ask, save);
|
||||||
break;
|
break;
|
||||||
case "-vmargs":
|
case "-vmargs":
|
||||||
exitCode = handleVmArgs(javaConfig);
|
exitCode = handleVmArgs(appConfig);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.err.println("LaunchSupport received illegal argument: " + mode);
|
System.err.println("LaunchSupport received illegal argument: " + mode);
|
||||||
|
@ -109,7 +109,7 @@ public class LaunchSupport {
|
||||||
* Handles figuring out a Java home directory to use for the launch. If it is successfully
|
* Handles figuring out a Java home directory to use for the launch. If it is successfully
|
||||||
* determined, an exit code that indicates success is returned.
|
* determined, an exit code that indicates success is returned.
|
||||||
*
|
*
|
||||||
* @param javaConfig The Java configuration that defines what we support.
|
* @param appConfig The appConfig configuration that defines what we support.
|
||||||
* @param javaFinder The Java finder.
|
* @param javaFinder The Java finder.
|
||||||
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
||||||
* @param ask True to interact with the user to they can specify a Java home directory.
|
* @param ask True to interact with the user to they can specify a Java home directory.
|
||||||
|
@ -120,12 +120,12 @@ public class LaunchSupport {
|
||||||
* successfully determined.
|
* successfully determined.
|
||||||
* @throws IOException if there was a disk-related problem.
|
* @throws IOException if there was a disk-related problem.
|
||||||
*/
|
*/
|
||||||
private static int handleJavaHome(JavaConfig javaConfig, JavaFinder javaFinder,
|
private static int handleJavaHome(AppConfig appConfig, JavaFinder javaFinder,
|
||||||
JavaFilter javaFilter, boolean ask, boolean save) throws IOException {
|
JavaFilter javaFilter, boolean ask, boolean save) throws IOException {
|
||||||
if (ask) {
|
if (ask) {
|
||||||
return askJavaHome(javaConfig, javaFinder, javaFilter);
|
return askJavaHome(appConfig, javaFinder, javaFilter);
|
||||||
}
|
}
|
||||||
return findJavaHome(javaConfig, javaFinder, javaFilter, save);
|
return findJavaHome(appConfig, javaFinder, javaFilter, save);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,7 +133,7 @@ public class LaunchSupport {
|
||||||
* found, its path is printed to STDOUT and an exit code that indicates success is
|
* found, its path is printed to STDOUT and an exit code that indicates success is
|
||||||
* returned. Otherwise, nothing is printed to STDOUT and an error exit code is returned.
|
* returned. Otherwise, nothing is printed to STDOUT and an error exit code is returned.
|
||||||
*
|
*
|
||||||
* @param javaConfig The Java configuration that defines what we support.
|
* @param appConfig The application configuration that defines what we support.
|
||||||
* @param javaFinder The Java finder.
|
* @param javaFinder The Java finder.
|
||||||
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
||||||
* @param save True if the determined Java home directory should get saved to a file.
|
* @param save True if the determined Java home directory should get saved to a file.
|
||||||
|
@ -141,19 +141,19 @@ public class LaunchSupport {
|
||||||
* successfully determined.
|
* successfully determined.
|
||||||
* @throws IOException if there was a problem saving the java home to disk.
|
* @throws IOException if there was a problem saving the java home to disk.
|
||||||
*/
|
*/
|
||||||
private static int findJavaHome(JavaConfig javaConfig, JavaFinder javaFinder,
|
private static int findJavaHome(AppConfig appConfig, JavaFinder javaFinder,
|
||||||
JavaFilter javaFilter, boolean save) throws IOException {
|
JavaFilter javaFilter, boolean save) throws IOException {
|
||||||
|
|
||||||
File javaHomeDir;
|
File javaHomeDir;
|
||||||
LaunchProperties launchProperties = javaConfig.getLaunchProperties();
|
LaunchProperties launchProperties = appConfig.getLaunchProperties();
|
||||||
|
|
||||||
// PRIORITY 1: JAVA_HOME_OVERRIDE property
|
// PRIORITY 1: JAVA_HOME_OVERRIDE property
|
||||||
// If a valid java home override is specified in the launch properties, use that.
|
// If a valid java home override is specified in the launch properties, use that.
|
||||||
// Someone presumably wants to force that specific version.
|
// Someone presumably wants to force that specific version.
|
||||||
javaHomeDir = launchProperties.getJavaHomeOverride();
|
javaHomeDir = launchProperties.getJavaHomeOverride();
|
||||||
if (javaConfig.isSupportedJavaHomeDir(javaHomeDir, javaFilter)) {
|
if (appConfig.isSupportedJavaHomeDir(javaHomeDir, javaFilter)) {
|
||||||
if (save) {
|
if (save) {
|
||||||
javaConfig.saveJavaHome(javaHomeDir);
|
appConfig.saveJavaHome(javaHomeDir);
|
||||||
}
|
}
|
||||||
System.out.println(javaHomeDir);
|
System.out.println(javaHomeDir);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -162,10 +162,10 @@ public class LaunchSupport {
|
||||||
// PRIORITY 2: Java on PATH
|
// PRIORITY 2: Java on PATH
|
||||||
// This program (LaunchSupport) was started with the Java on the PATH. Try to use this one
|
// This program (LaunchSupport) was started with the Java on the PATH. Try to use this one
|
||||||
// next because it is most likely the one that is being upgraded on the user's system.
|
// next because it is most likely the one that is being upgraded on the user's system.
|
||||||
javaHomeDir = javaFinder.findSupportedJavaHomeFromCurrentJavaHome(javaConfig, javaFilter);
|
javaHomeDir = javaFinder.findSupportedJavaHomeFromCurrentJavaHome(appConfig, javaFilter);
|
||||||
if (javaHomeDir != null) {
|
if (javaHomeDir != null) {
|
||||||
if (save) {
|
if (save) {
|
||||||
javaConfig.saveJavaHome(javaHomeDir);
|
appConfig.saveJavaHome(javaHomeDir);
|
||||||
}
|
}
|
||||||
System.out.println(javaHomeDir);
|
System.out.println(javaHomeDir);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -173,19 +173,19 @@ public class LaunchSupport {
|
||||||
|
|
||||||
// PRIORITY 3: Last used Java
|
// PRIORITY 3: Last used Java
|
||||||
// Check to see if a prior launch resulted in that Java being saved. If so, try to use that.
|
// Check to see if a prior launch resulted in that Java being saved. If so, try to use that.
|
||||||
javaHomeDir = javaConfig.getSavedJavaHome();
|
javaHomeDir = appConfig.getSavedJavaHome();
|
||||||
if (javaConfig.isSupportedJavaHomeDir(javaHomeDir, javaFilter)) {
|
if (appConfig.isSupportedJavaHomeDir(javaHomeDir, javaFilter)) {
|
||||||
System.out.println(javaHomeDir);
|
System.out.println(javaHomeDir);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIORITY 4: Find all supported Java installations, and use the newest.
|
// PRIORITY 4: Find all supported Java installations, and use the newest.
|
||||||
List<File> javaHomeDirs =
|
List<File> javaHomeDirs =
|
||||||
javaFinder.findSupportedJavaHomeFromInstallations(javaConfig, javaFilter);
|
javaFinder.findSupportedJavaHomeFromInstallations(appConfig, javaFilter);
|
||||||
if (!javaHomeDirs.isEmpty()) {
|
if (!javaHomeDirs.isEmpty()) {
|
||||||
javaHomeDir = javaHomeDirs.iterator().next();
|
javaHomeDir = javaHomeDirs.iterator().next();
|
||||||
if (save) {
|
if (save) {
|
||||||
javaConfig.saveJavaHome(javaHomeDir);
|
appConfig.saveJavaHome(javaHomeDir);
|
||||||
}
|
}
|
||||||
System.out.println(javaHomeDir);
|
System.out.println(javaHomeDir);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -199,7 +199,7 @@ public class LaunchSupport {
|
||||||
* If a valid Java home directory was successfully determined, it is saved to the user's
|
* If a valid Java home directory was successfully determined, it is saved to the user's
|
||||||
* Java home save file, and an exit code that indicates success is returned.
|
* Java home save file, and an exit code that indicates success is returned.
|
||||||
*
|
*
|
||||||
* @param javaConfig The Java configuration that defines what we support.
|
* @param appConfig The application configuration that defines what we support.
|
||||||
* @param javaFinder The Java finder.
|
* @param javaFinder The Java finder.
|
||||||
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
||||||
* * @return A suggested exit code based on whether or not a valid Java home directory was
|
* * @return A suggested exit code based on whether or not a valid Java home directory was
|
||||||
|
@ -207,13 +207,13 @@ public class LaunchSupport {
|
||||||
* @throws IOException if there was a problem interacting with the user, or saving the java
|
* @throws IOException if there was a problem interacting with the user, or saving the java
|
||||||
* home location to disk.
|
* home location to disk.
|
||||||
*/
|
*/
|
||||||
private static int askJavaHome(JavaConfig javaConfig, JavaFinder javaFinder,
|
private static int askJavaHome(AppConfig appConfig, JavaFinder javaFinder,
|
||||||
JavaFilter javaFilter) throws IOException {
|
JavaFilter javaFilter) throws IOException {
|
||||||
|
|
||||||
String javaName = javaFilter.equals(JavaFilter.JDK_ONLY) ? "JDK" : "Java";
|
String javaName = javaFilter.equals(JavaFilter.JDK_ONLY) ? "JDK" : "Java";
|
||||||
String javaRange;
|
String javaRange;
|
||||||
int min = javaConfig.getMinSupportedJava();
|
int min = appConfig.getMinSupportedJava();
|
||||||
int max = javaConfig.getMaxSupportedJava();
|
int max = appConfig.getMaxSupportedJava();
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
javaRange = min + "";
|
javaRange = min + "";
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,7 @@ public class LaunchSupport {
|
||||||
|
|
||||||
System.out.println("******************************************************************");
|
System.out.println("******************************************************************");
|
||||||
System.out.println(
|
System.out.println(
|
||||||
javaName + " " + javaRange + " (" + javaConfig.getSupportedArchitecture() +
|
javaName + " " + javaRange + " (" + appConfig.getSupportedArchitecture() +
|
||||||
"-bit) could not be found and must be manually chosen!");
|
"-bit) could not be found and must be manually chosen!");
|
||||||
System.out.println("******************************************************************");
|
System.out.println("******************************************************************");
|
||||||
|
|
||||||
|
@ -254,13 +254,13 @@ public class LaunchSupport {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
JavaVersion javaVersion = javaConfig.getJavaVersion(javaHomeDir, javaFilter);
|
JavaVersion javaVersion = appConfig.getJavaVersion(javaHomeDir, javaFilter);
|
||||||
if (javaConfig.isJavaVersionSupported(javaVersion)) {
|
if (appConfig.isJavaVersionSupported(javaVersion)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
System.out.println(
|
System.out.println(
|
||||||
"Java version " + javaVersion + " is outside of supported range: [" +
|
"Java version " + javaVersion + " is outside of supported range: [" +
|
||||||
javaRange + " " + javaConfig.getSupportedArchitecture() + "-bit]");
|
javaRange + " " + appConfig.getSupportedArchitecture() + "-bit]");
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException e) {
|
catch (FileNotFoundException e) {
|
||||||
System.out.println(
|
System.out.println(
|
||||||
|
@ -271,7 +271,7 @@ public class LaunchSupport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File javaHomeSaveFile = javaConfig.saveJavaHome(javaHomeDir);
|
File javaHomeSaveFile = appConfig.saveJavaHome(javaHomeDir);
|
||||||
System.out.println("Saved changes to " + javaHomeSaveFile);
|
System.out.println("Saved changes to " + javaHomeSaveFile);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -281,18 +281,18 @@ public class LaunchSupport {
|
||||||
* to STDOUT as a new-line delimited string that can be parsed and added to the command line,
|
* to STDOUT as a new-line delimited string that can be parsed and added to the command line,
|
||||||
* and an exit code that indicates success is returned.
|
* and an exit code that indicates success is returned.
|
||||||
|
|
||||||
* @param javaConfig The Java configuration that defines what we support.
|
* @param appConfig The appConfig configuration that defines what we support.
|
||||||
* @return A suggested exit code based on whether or not the VM arguments were successfully
|
* @return A suggested exit code based on whether or not the VM arguments were successfully
|
||||||
* gotten.
|
* gotten.
|
||||||
*/
|
*/
|
||||||
private static int handleVmArgs(JavaConfig javaConfig) {
|
private static int handleVmArgs(AppConfig appConfig) {
|
||||||
if (javaConfig.getLaunchProperties() == null) {
|
if (appConfig.getLaunchProperties() == null) {
|
||||||
System.out.println("Launch properties file was not specified!");
|
System.out.println("Launch properties file was not specified!");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force newline style to make cross-platform parsing consistent
|
// Force newline style to make cross-platform parsing consistent
|
||||||
javaConfig.getLaunchProperties().getVmArgList().forEach(e -> System.out.print(e + "\r\n"));
|
appConfig.getLaunchProperties().getVmArgList().forEach(e -> System.out.print(e + "\r\n"));
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -17,21 +17,23 @@ package ghidra.launch;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Properties;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.launch.JavaFinder.JavaFilter;
|
import ghidra.launch.JavaFinder.JavaFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to determine and represent a required Java configuration, including minimum and maximum
|
* Class to determine and represent a required application configuration, including minimum and
|
||||||
* supported versions, compiler compliance level, etc.
|
* maximum supported Java versions, compiler compliance level, etc.
|
||||||
*/
|
*/
|
||||||
public class JavaConfig {
|
public class AppConfig {
|
||||||
|
|
||||||
private static final String LAUNCH_PROPERTIES_NAME = "launch.properties";
|
private static final String LAUNCH_PROPERTIES_NAME = "launch.properties";
|
||||||
private static final String JAVA_HOME_SAVE_NAME = "java_home.save";
|
private static final String JAVA_HOME_SAVE_NAME = "java_home.save";
|
||||||
|
private static final String PYTHON_COMMAND_SAVE_NAME = "python_command.save";
|
||||||
|
|
||||||
private LaunchProperties launchProperties;
|
private LaunchProperties launchProperties;
|
||||||
private File javaHomeSaveFile;
|
private File javaHomeSaveFile;
|
||||||
|
private File pythonCommandSaveFile;
|
||||||
|
|
||||||
private String applicationName; // example: Ghidra
|
private String applicationName; // example: Ghidra
|
||||||
private String applicationVersion; // example: 9.0.1
|
private String applicationVersion; // example: 9.0.1
|
||||||
|
@ -42,43 +44,43 @@ public class JavaConfig {
|
||||||
private String compilerComplianceLevel;
|
private String compilerComplianceLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Java configuration for the given installation.
|
* Creates a new application configuration for the given installation.
|
||||||
*
|
*
|
||||||
* @param installDir The installation directory.
|
* @param installDir The installation directory.
|
||||||
* @throws FileNotFoundException if a required file was not found.
|
* @throws FileNotFoundException if a required file was not found.
|
||||||
* @throws IOException if there was a problem reading a required file.
|
* @throws IOException if there was a problem reading a required file.
|
||||||
* @throws ParseException if there was a problem parsing a required file.
|
* @throws ParseException if there was a problem parsing a required file.
|
||||||
*/
|
*/
|
||||||
public JavaConfig(File installDir) throws FileNotFoundException, IOException, ParseException {
|
public AppConfig(File installDir) throws FileNotFoundException, IOException, ParseException {
|
||||||
initApplicationProperties(installDir);
|
initApplicationProperties(installDir);
|
||||||
initLaunchProperties(installDir);
|
initLaunchProperties(installDir);
|
||||||
initJavaHomeSaveFile(installDir);
|
javaHomeSaveFile = getSaveFile(installDir, JAVA_HOME_SAVE_NAME);
|
||||||
|
pythonCommandSaveFile = getSaveFile(installDir, PYTHON_COMMAND_SAVE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the launch properties associated with this Java configuration. Certain aspects of the
|
* Gets the launch properties associated with this application configuration.
|
||||||
* Java configuration are stored in the launch properties.
|
|
||||||
*
|
*
|
||||||
* @return The launch properties associated with this Java configuration. Could be null if
|
* @return The launch properties associated with this application configuration. Could be null
|
||||||
* this Java configuration does not use launch properties.
|
* if this application configuration does not use launch properties.
|
||||||
*/
|
*/
|
||||||
public LaunchProperties getLaunchProperties() {
|
public LaunchProperties getLaunchProperties() {
|
||||||
return launchProperties;
|
return launchProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Java configuration's minimum supported major Java version.
|
* Gets the application configuration's minimum supported major Java version.
|
||||||
*
|
*
|
||||||
* @return The Java configuration's minimum supported major Java version.
|
* @return The application configuration's minimum supported major Java version.
|
||||||
*/
|
*/
|
||||||
public int getMinSupportedJava() {
|
public int getMinSupportedJava() {
|
||||||
return minSupportedJava;
|
return minSupportedJava;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Java configuration's maximum supported major Java version.
|
* Gets the application configuration's maximum supported major Java version.
|
||||||
*
|
*
|
||||||
* @return The Java configuration's maximum supported major Java version. If there is no
|
* @return The application configuration's maximum supported major Java version. If there is no
|
||||||
* restriction, the value will be 0.
|
* restriction, the value will be 0.
|
||||||
*/
|
*/
|
||||||
public int getMaxSupportedJava() {
|
public int getMaxSupportedJava() {
|
||||||
|
@ -86,20 +88,20 @@ public class JavaConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Java configuration's supported Java architecture. All supported Java
|
* Gets the application configuration's supported Java architecture. All supported Java
|
||||||
* configurations must have an architecture of <code>64</code>.
|
* configurations must have an architecture of <code>64</code>.
|
||||||
*
|
*
|
||||||
* @return The Java configuration's supported Java architecture (64).
|
* @return The application configuration's supported Java architecture (64).
|
||||||
*/
|
*/
|
||||||
public int getSupportedArchitecture() {
|
public int getSupportedArchitecture() {
|
||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Java configuration's compiler compliance level that was used to build the
|
* Gets the application configuration's Java compiler compliance level that was used to build
|
||||||
* associated installation.
|
* the associated installation.
|
||||||
*
|
*
|
||||||
* @return The Java configuration's compiler compliance level.
|
* @return The application configuration's compiler compliance level.
|
||||||
*/
|
*/
|
||||||
public String getCompilerComplianceLevel() {
|
public String getCompilerComplianceLevel() {
|
||||||
return compilerComplianceLevel;
|
return compilerComplianceLevel;
|
||||||
|
@ -115,8 +117,11 @@ public class JavaConfig {
|
||||||
public File getSavedJavaHome() throws IOException {
|
public File getSavedJavaHome() throws IOException {
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(javaHomeSaveFile))) {
|
try (BufferedReader reader = new BufferedReader(new FileReader(javaHomeSaveFile))) {
|
||||||
String line = reader.readLine().trim();
|
String line = reader.readLine().trim();
|
||||||
if (line != null && !line.isEmpty()) {
|
if (line != null) {
|
||||||
return new File(line);
|
line = line.trim();
|
||||||
|
if (!line.isEmpty()) {
|
||||||
|
return new File(line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException e) {
|
catch (FileNotFoundException e) {
|
||||||
|
@ -148,12 +153,12 @@ public class JavaConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to see if the given directory is a supported Java home directory for this Java
|
* Tests to see if the given directory is a supported Java home directory for this application
|
||||||
* configuration.
|
* configuration.
|
||||||
*
|
*
|
||||||
* @param dir The directory to test.
|
* @param dir The directory to test.
|
||||||
* @param javaFilter A filter used to restrict what kind of Java installations we support.
|
* @param javaFilter A filter used to restrict what kind of Java installations we support.
|
||||||
* @return True if the given directory is a supported Java home directory for this Java
|
* @return True if the given directory is a supported Java home directory for this application
|
||||||
* configuration.
|
* configuration.
|
||||||
*/
|
*/
|
||||||
public boolean isSupportedJavaHomeDir(File dir, JavaFilter javaFilter) {
|
public boolean isSupportedJavaHomeDir(File dir, JavaFilter javaFilter) {
|
||||||
|
@ -166,10 +171,10 @@ public class JavaConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to see if the given Java version is supported by this Java launch configuration.
|
* Tests to see if the given Java version is supported by this application configuration.
|
||||||
*
|
*
|
||||||
* @param javaVersion The java version to check.
|
* @param javaVersion The java version to check.
|
||||||
* @return True if the given Java version is supported by this Java launch configuration.
|
* @return True if the given Java version is supported by this application configuration.
|
||||||
*/
|
*/
|
||||||
public boolean isJavaVersionSupported(JavaVersion javaVersion) {
|
public boolean isJavaVersionSupported(JavaVersion javaVersion) {
|
||||||
if (javaVersion.getArchitecture() != getSupportedArchitecture()) {
|
if (javaVersion.getArchitecture() != getSupportedArchitecture()) {
|
||||||
|
@ -233,6 +238,30 @@ public class JavaConfig {
|
||||||
return runAndGetJavaVersion(javaExecutable);
|
return runAndGetJavaVersion(javaExecutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Python command from the user's Python command save file.
|
||||||
|
*
|
||||||
|
* @return The Python command from the user's Python command save file, or null if the file
|
||||||
|
* does not exist or is empty.
|
||||||
|
* @throws IOException if there was a problem reading the Python command save file.
|
||||||
|
*/
|
||||||
|
public List<String> getSavedPythonCommand() throws IOException {
|
||||||
|
List<String> command = new ArrayList<>();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(pythonCommandSaveFile))) {
|
||||||
|
String line = null;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
line = line.trim();
|
||||||
|
if (!line.isEmpty()) {
|
||||||
|
command.add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the version of the given Java executable from the output of running "java -version".
|
* Gets the version of the given Java executable from the output of running "java -version".
|
||||||
*
|
*
|
||||||
|
@ -354,13 +383,13 @@ public class JavaConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the Java home save file.
|
* Gets the given "save file".
|
||||||
*
|
*
|
||||||
* @param installDir The Ghidra installation directory. This is the directory that has the
|
* @param installDir The Ghidra installation directory. This is the directory that has the
|
||||||
* "Ghidra" subdirectory in it.
|
* "Ghidra" subdirectory in it.
|
||||||
* @throws FileNotFoundException if the user's home directory was not found.
|
* @throws FileNotFoundException if the user's home directory was not found.
|
||||||
*/
|
*/
|
||||||
private void initJavaHomeSaveFile(File installDir) throws FileNotFoundException {
|
private File getSaveFile(File installDir, String saveFileName) throws FileNotFoundException {
|
||||||
boolean isDev = new File(installDir, "build.gradle").isFile();
|
boolean isDev = new File(installDir, "build.gradle").isFile();
|
||||||
String appName = applicationName.replaceAll("\\s", "").toLowerCase();
|
String appName = applicationName.replaceAll("\\s", "").toLowerCase();
|
||||||
|
|
||||||
|
@ -385,16 +414,14 @@ public class JavaConfig {
|
||||||
// Handle legacy application layout
|
// Handle legacy application layout
|
||||||
if (applicationLayoutVersion.equals("1")) {
|
if (applicationLayoutVersion.equals("1")) {
|
||||||
userSettingsDir = new File(userHomeDir, "." + appName + "/." + userSettingsDirName);
|
userSettingsDir = new File(userHomeDir, "." + appName + "/." + userSettingsDirName);
|
||||||
javaHomeSaveFile = new File(userSettingsDir, JAVA_HOME_SAVE_NAME);
|
return new File(userSettingsDir, saveFileName);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for XDG environment variable
|
// Look for XDG environment variable
|
||||||
String xdgConfigHomeDirStr = System.getenv("XDG_CONFIG_HOME");
|
String xdgConfigHomeDirStr = System.getenv("XDG_CONFIG_HOME");
|
||||||
if (xdgConfigHomeDirStr != null && !xdgConfigHomeDirStr.isEmpty()) {
|
if (xdgConfigHomeDirStr != null && !xdgConfigHomeDirStr.isEmpty()) {
|
||||||
userSettingsDir = new File(xdgConfigHomeDirStr, appName + "/" + userSettingsDirName);
|
userSettingsDir = new File(xdgConfigHomeDirStr, appName + "/" + userSettingsDirName);
|
||||||
javaHomeSaveFile = new File(userSettingsDir, JAVA_HOME_SAVE_NAME);
|
return new File(userSettingsDir, saveFileName);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look in current user settings directory
|
// Look in current user settings directory
|
||||||
|
@ -420,7 +447,7 @@ public class JavaConfig {
|
||||||
"Failed to find the user settings directory: Unsupported operating system.");
|
"Failed to find the user settings directory: Unsupported operating system.");
|
||||||
}
|
}
|
||||||
|
|
||||||
javaHomeSaveFile = new File(userSettingsDir, JAVA_HOME_SAVE_NAME);
|
return new File(userSettingsDir, saveFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -79,11 +79,11 @@ public abstract class JavaFinder {
|
||||||
* Returns a list of supported Java home directories from discovered Java installations.
|
* Returns a list of supported Java home directories from discovered Java installations.
|
||||||
* The list is sorted from newest Java version to oldest.
|
* The list is sorted from newest Java version to oldest.
|
||||||
*
|
*
|
||||||
* @param javaConfig The Java configuration that defines what we support.
|
* @param appConfig The appConfig configuration that defines what we support.
|
||||||
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
||||||
* @return A sorted list of supported Java home directories from discovered Java installations.
|
* @return A sorted list of supported Java home directories from discovered Java installations.
|
||||||
*/
|
*/
|
||||||
public List<File> findSupportedJavaHomeFromInstallations(JavaConfig javaConfig,
|
public List<File> findSupportedJavaHomeFromInstallations(AppConfig appConfig,
|
||||||
JavaFilter javaFilter) {
|
JavaFilter javaFilter) {
|
||||||
Set<File> potentialJavaHomeSet = new TreeSet<>();
|
Set<File> potentialJavaHomeSet = new TreeSet<>();
|
||||||
for (File javaRootInstallDir : getJavaRootInstallDirs()) {
|
for (File javaRootInstallDir : getJavaRootInstallDirs()) {
|
||||||
|
@ -107,8 +107,8 @@ public abstract class JavaFinder {
|
||||||
for (File potentialJavaHomeDir : potentialJavaHomeSet) {
|
for (File potentialJavaHomeDir : potentialJavaHomeSet) {
|
||||||
try {
|
try {
|
||||||
JavaVersion javaVersion =
|
JavaVersion javaVersion =
|
||||||
javaConfig.getJavaVersion(potentialJavaHomeDir, javaFilter);
|
appConfig.getJavaVersion(potentialJavaHomeDir, javaFilter);
|
||||||
if (javaConfig.isJavaVersionSupported(javaVersion)) {
|
if (appConfig.isJavaVersionSupported(javaVersion)) {
|
||||||
javaHomeToVersionMap.put(potentialJavaHomeDir, javaVersion);
|
javaHomeToVersionMap.put(potentialJavaHomeDir, javaVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,12 +130,12 @@ public abstract class JavaFinder {
|
||||||
* Returns the Java home directory corresponding to the current "java.home" system
|
* Returns the Java home directory corresponding to the current "java.home" system
|
||||||
* property (if it supported).
|
* property (if it supported).
|
||||||
*
|
*
|
||||||
* @param javaConfig The Java configuration that defines what we support.
|
* @param appConfig The appConfig configuration that defines what we support.
|
||||||
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
* @param javaFilter A filter used to restrict what kind of Java installations we search for.
|
||||||
* @return The Java home directory corresponding to the current "java.home" system property.
|
* @return The Java home directory corresponding to the current "java.home" system property.
|
||||||
* Could be null if the current "java.home" is not supported.
|
* Could be null if the current "java.home" is not supported.
|
||||||
*/
|
*/
|
||||||
public File findSupportedJavaHomeFromCurrentJavaHome(JavaConfig javaConfig,
|
public File findSupportedJavaHomeFromCurrentJavaHome(AppConfig appConfig,
|
||||||
JavaFilter javaFilter) {
|
JavaFilter javaFilter) {
|
||||||
Set<File> potentialJavaHomeSet = new HashSet<>();
|
Set<File> potentialJavaHomeSet = new HashSet<>();
|
||||||
String javaHomeProperty = System.getProperty("java.home");
|
String javaHomeProperty = System.getProperty("java.home");
|
||||||
|
@ -149,8 +149,8 @@ public abstract class JavaFinder {
|
||||||
}
|
}
|
||||||
for (File potentialJavaHomeDir : potentialJavaHomeSet) {
|
for (File potentialJavaHomeDir : potentialJavaHomeSet) {
|
||||||
try {
|
try {
|
||||||
if (javaConfig.isJavaVersionSupported(
|
if (appConfig.isJavaVersionSupported(
|
||||||
javaConfig.getJavaVersion(potentialJavaHomeDir, javaFilter))) {
|
appConfig.getJavaVersion(potentialJavaHomeDir, javaFilter))) {
|
||||||
return potentialJavaHomeDir;
|
return potentialJavaHomeDir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -432,6 +432,9 @@ task assembleDistribution (type: Copy) {
|
||||||
from ("${ROOT_PROJECT_DIR}/build/typestubs/src") {
|
from ("${ROOT_PROJECT_DIR}/build/typestubs/src") {
|
||||||
into 'docs/ghidra_stubs/typestubs'
|
into 'docs/ghidra_stubs/typestubs'
|
||||||
}
|
}
|
||||||
|
from ("${ROOT_PROJECT_DIR}/build/typestubs/pypredef") {
|
||||||
|
into 'docs/ghidra_stubs/pypredef'
|
||||||
|
}
|
||||||
from (createGhidraStubsWheel) {
|
from (createGhidraStubsWheel) {
|
||||||
into 'docs/ghidra_stubs'
|
into 'docs/ghidra_stubs'
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,9 +95,9 @@ ext.deps = [
|
||||||
destination: file("${DEPS_DIR}/BSim")
|
destination: file("${DEPS_DIR}/BSim")
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
name: "PyDev 6.3.1.zip",
|
name: "PyDev 9.3.0.zip",
|
||||||
url: "https://sourceforge.net/projects/pydev/files/pydev/PyDev%206.3.1/PyDev%206.3.1.zip",
|
url: "https://sourceforge.net/projects/pydev/files/pydev/PyDev%209.3.0/PyDev%209.3.0.zip",
|
||||||
sha256: "4d81fe9d8afe7665b8ea20844d3f5107f446742927c59973eade4f29809b0699",
|
sha256: "45398edf2adb56078a80bc88a919941578f0c0b363efbdd011bfd158a99b112e",
|
||||||
destination: file("${DEPS_DIR}/GhidraDev")
|
destination: file("${DEPS_DIR}/GhidraDev")
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue