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
|
@ -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.PlatformUI;
|
||||
|
||||
import ghidra.launch.JavaConfig;
|
||||
import ghidra.launch.AppConfig;
|
||||
import ghidradev.EclipseMessageUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.*;
|
||||
|
||||
|
@ -62,10 +62,10 @@ public class GhidraLaunchDelegate extends JavaLaunchDelegate {
|
|||
}
|
||||
IFolder ghidraFolder =
|
||||
javaProject.getProject().getFolder(GhidraProjectUtils.GHIDRA_FOLDER_NAME);
|
||||
JavaConfig javaConfig;
|
||||
AppConfig appConfig;
|
||||
String ghidraInstallPath = ghidraFolder.getLocation().toOSString();
|
||||
try {
|
||||
javaConfig = new JavaConfig(new File(ghidraInstallPath));
|
||||
appConfig = new AppConfig(new File(ghidraInstallPath));
|
||||
}
|
||||
catch (ParseException | IOException e) {
|
||||
EclipseMessageUtils.showErrorDialog(
|
||||
|
@ -98,7 +98,7 @@ public class GhidraLaunchDelegate extends JavaLaunchDelegate {
|
|||
}
|
||||
|
||||
// Set VM arguments
|
||||
String vmArgs = javaConfig.getLaunchProperties().getVmArgs();
|
||||
String vmArgs = appConfig.getLaunchProperties().getVmArgs();
|
||||
vmArgs += " " + configuration.getAttribute(GhidraLaunchUtils.ATTR_VM_ARGUMENTS, "").trim();
|
||||
vmArgs += " -Dghidra.external.modules=\"%s%s%s\"".formatted(
|
||||
javaProject.getProject().getLocation(), File.pathSeparator,
|
||||
|
@ -171,7 +171,7 @@ public class GhidraLaunchDelegate extends JavaLaunchDelegate {
|
|||
}
|
||||
|
||||
// Start PyDev debugger
|
||||
if (PyDevUtils.isSupportedPyDevInstalled()) {
|
||||
if (PyDevUtils.isSupportedJythonPyDevInstalled()) {
|
||||
try {
|
||||
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";
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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.util.exception.CancelledException;
|
||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
/**
|
||||
|
@ -89,7 +90,7 @@ public class GhidraModuleUtils {
|
|||
*/
|
||||
public static IJavaProject createGhidraModuleProject(String projectName, File projectDir,
|
||||
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
||||
String jythonInterpreterName, IProgressMonitor monitor)
|
||||
ProjectPythonInterpreter jythonInterpreterName, IProgressMonitor monitor)
|
||||
throws IOException, ParseException, CoreException {
|
||||
|
||||
// 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 runConfigMemory The run configuration's desired memory. Could be null.
|
||||
* @param ghidraLayout The Ghidra layout to link the project to.
|
||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* Could be null if Python support is not wanted.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The progress monitor to use during project creation.
|
||||
* @return The imported 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,
|
||||
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
||||
String jythonInterpreterName, IProgressMonitor monitor)
|
||||
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||
throws IOException, ParseException, CoreException {
|
||||
|
||||
// Create empty Ghidra project
|
||||
IJavaProject javaProject =
|
||||
GhidraProjectUtils.createEmptyGhidraProject(projectName, moduleSourceDir,
|
||||
createRunConfig, runConfigMemory, ghidraLayout, jythonInterpreterName, monitor);
|
||||
createRunConfig, runConfigMemory, ghidraLayout, pythonInterpreter, monitor);
|
||||
IProject project = javaProject.getProject();
|
||||
|
||||
// Set default output location
|
||||
|
|
|
@ -36,9 +36,10 @@ import org.eclipse.ui.part.FileEditorInput;
|
|||
import generic.jar.ResourceFile;
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.framework.GModule;
|
||||
import ghidra.launch.JavaConfig;
|
||||
import ghidra.launch.AppConfig;
|
||||
import ghidradev.Activator;
|
||||
import ghidradev.EclipseMessageUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||
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 runConfigMemory The run configuration's desired memory. Could be null.
|
||||
* @param ghidraLayout The Ghidra layout to link the project to.
|
||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* Could be null if Python support is not wanted.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The progress monitor to use during project creation.
|
||||
* @return The created 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,
|
||||
boolean createRunConfig, String runConfigMemory, GhidraApplicationLayout ghidraLayout,
|
||||
String jythonInterpreterName, IProgressMonitor monitor)
|
||||
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||
throws IOException, ParseException, CoreException {
|
||||
|
||||
// Get Ghidra's Java configuration
|
||||
JavaConfig javaConfig =
|
||||
new JavaConfig(ghidraLayout.getApplicationInstallationDir().getFile(false));
|
||||
AppConfig appConfig =
|
||||
new AppConfig(ghidraLayout.getApplicationInstallationDir().getFile(false));
|
||||
|
||||
// Make new Java project
|
||||
IWorkspace workspace = ResourcesPlugin.getWorkspace();
|
||||
|
@ -299,7 +299,7 @@ public class GhidraProjectUtils {
|
|||
javaProject.setRawClasspath(new IClasspathEntry[0], monitor);
|
||||
|
||||
// Configure Java compiler for the project
|
||||
configureJavaCompiler(javaProject, javaConfig);
|
||||
configureJavaCompiler(javaProject, appConfig);
|
||||
|
||||
// Setup default bin folder
|
||||
IFolder binFolder = project.getFolder("bin/default");
|
||||
|
@ -310,7 +310,7 @@ public class GhidraProjectUtils {
|
|||
monitor);
|
||||
|
||||
// Link in Ghidra to the project
|
||||
linkGhidraToProject(javaProject, ghidraLayout, javaConfig, jythonInterpreterName, monitor);
|
||||
linkGhidraToProject(javaProject, ghidraLayout, appConfig, pythonInterpreter, monitor);
|
||||
|
||||
// Create run configuration (if necessary)
|
||||
if (createRunConfig) {
|
||||
|
@ -338,23 +338,22 @@ public class GhidraProjectUtils {
|
|||
*
|
||||
* @param javaProject The Java project to link.
|
||||
* @param ghidraLayout The Ghidra layout to link the project to.
|
||||
* @param javaConfig Ghidra's Java configuration.
|
||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* Could be null if Python support is not wanted.
|
||||
* @param appConfig Ghidra's application configuration.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The progress monitor used during link.
|
||||
* @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.
|
||||
*/
|
||||
public static void linkGhidraToProject(IJavaProject javaProject,
|
||||
GhidraApplicationLayout ghidraLayout, JavaConfig javaConfig,
|
||||
String jythonInterpreterName, IProgressMonitor monitor)
|
||||
GhidraApplicationLayout ghidraLayout, AppConfig appConfig,
|
||||
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||
throws CoreException, IOException {
|
||||
|
||||
// Gets the Ghidra installation directory to link to from the Ghidra layout
|
||||
File ghidraInstallDir = ghidraLayout.getApplicationInstallationDir().getFile(false);
|
||||
|
||||
// Get the Java VM used to launch the Ghidra to link to
|
||||
IVMInstall vm = getGhidraVm(javaConfig);
|
||||
IVMInstall vm = getGhidraVm(appConfig);
|
||||
IPath vmPath =
|
||||
new Path(JavaRuntime.JRE_CONTAINER).append(vm.getVMInstallType().getId()).append(
|
||||
vm.getName());
|
||||
|
@ -457,15 +456,13 @@ public class GhidraProjectUtils {
|
|||
GhidraModuleUtils.writeAntProperties(javaProject.getProject(), ghidraLayout);
|
||||
|
||||
// Setup Python for the project
|
||||
if (PyDevUtils.isSupportedPyDevInstalled()) {
|
||||
try {
|
||||
PyDevUtils.setupPythonForProject(javaProject, libraryClasspathEntries,
|
||||
jythonInterpreterName, monitor);
|
||||
}
|
||||
catch (OperationNotSupportedException e) {
|
||||
EclipseMessageUtils.showErrorDialog("PyDev error",
|
||||
"Failed to setup Python for the project. PyDev version is not supported.");
|
||||
}
|
||||
try {
|
||||
PyDevUtils.setupPythonForProject(javaProject, libraryClasspathEntries,
|
||||
pythonInterpreter, monitor);
|
||||
}
|
||||
catch (OperationNotSupportedException e) {
|
||||
EclipseMessageUtils.showErrorDialog("PyDev error",
|
||||
"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.
|
||||
*
|
||||
* @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.
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
// 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.
|
||||
*
|
||||
* @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 IGNORE = JavaCore.IGNORE;
|
||||
final String ERROR = JavaCore.ERROR;
|
||||
|
||||
// Compliance
|
||||
jp.setOption(JavaCore.COMPILER_SOURCE, javaConfig.getCompilerComplianceLevel());
|
||||
jp.setOption(JavaCore.COMPILER_COMPLIANCE, javaConfig.getCompilerComplianceLevel());
|
||||
jp.setOption(JavaCore.COMPILER_SOURCE, appConfig.getCompilerComplianceLevel());
|
||||
jp.setOption(JavaCore.COMPILER_COMPLIANCE, appConfig.getCompilerComplianceLevel());
|
||||
jp.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
|
||||
javaConfig.getCompilerComplianceLevel());
|
||||
appConfig.getCompilerComplianceLevel());
|
||||
|
||||
// Code style
|
||||
jp.setOption(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER, WARNING);
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -26,6 +26,7 @@ import org.eclipse.jdt.core.*;
|
|||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.framework.GModule;
|
||||
import ghidradev.Activator;
|
||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||
|
||||
/**
|
||||
* 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 linkSystemScripts Whether or not to link in the system scripts directories.
|
||||
* @param ghidraLayout The Ghidra layout to link the project to.
|
||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* Could be null if Python support is not wanted.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The progress monitor to use during project creation.
|
||||
* @return The created 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,
|
||||
boolean createRunConfig, String runConfigMemory, boolean linkUserScripts,
|
||||
boolean linkSystemScripts, GhidraApplicationLayout ghidraLayout,
|
||||
String jythonInterpreterName, IProgressMonitor monitor)
|
||||
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||
throws IOException, ParseException, CoreException {
|
||||
|
||||
List<IClasspathEntry> classpathEntries = new ArrayList<>();
|
||||
|
||||
// Create empty Ghidra project
|
||||
IJavaProject javaProject = GhidraProjectUtils.createEmptyGhidraProject(projectName,
|
||||
projectDir, createRunConfig, runConfigMemory, ghidraLayout, jythonInterpreterName,
|
||||
monitor);
|
||||
projectDir, createRunConfig, runConfigMemory, ghidraLayout, pythonInterpreter, monitor);
|
||||
|
||||
// Link each module's ghidra_scripts directory to the project
|
||||
if (linkSystemScripts) {
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -26,6 +26,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import javax.naming.OperationNotSupportedException;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.*;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
|
@ -38,23 +39,58 @@ import ghidradev.Activator;
|
|||
*/
|
||||
public class PyDevUtils {
|
||||
|
||||
public final static String MIN_SUPPORTED_VERSION = "6.3.1";
|
||||
public final static String MAX_SUPPORTED_VERSION = "9.3.0";
|
||||
public final static String MIN_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.
|
||||
*
|
||||
* @return True if a supported version of PyDev is installed; otherwise, false.
|
||||
* The various types of supported Python interpreters
|
||||
*/
|
||||
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 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 {
|
||||
Version version = PyDevUtilsInternal.getPyDevVersion();
|
||||
if (version != null) {
|
||||
// Make sure the installed version of PyDev is new enough to support the following
|
||||
// operation.
|
||||
getJython27InterpreterNames();
|
||||
getJythonInterpreterNames();
|
||||
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.
|
||||
*
|
||||
* @return 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
|
||||
* 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
|
||||
* operation.
|
||||
*/
|
||||
public static List<String> getJython27InterpreterNames() throws OperationNotSupportedException {
|
||||
public static List<String> getPyGhidraInterpreterNames(File requiredFileMatch)
|
||||
throws OperationNotSupportedException {
|
||||
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) {
|
||||
throw new OperationNotSupportedException(e.getMessage());
|
||||
|
@ -107,8 +181,7 @@ public class PyDevUtils {
|
|||
*
|
||||
* @param javaProject The Java project to enable Python for.
|
||||
* @param classpathEntries The classpath entries to add to the Python path.
|
||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* If this is null, Python support will be removed from the project.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The progress monitor used during link.
|
||||
* @throws CoreException if there was an Eclipse-related problem with enabling Python for the
|
||||
* project.
|
||||
|
@ -116,11 +189,11 @@ public class PyDevUtils {
|
|||
* operation.
|
||||
*/
|
||||
public static void setupPythonForProject(IJavaProject javaProject,
|
||||
List<IClasspathEntry> classpathEntries, String jythonInterpreterName,
|
||||
List<IClasspathEntry> classpathEntries, ProjectPythonInterpreter pythonInterpreter,
|
||||
IProgressMonitor monitor) throws CoreException, OperationNotSupportedException {
|
||||
try {
|
||||
PyDevUtilsInternal.setupPythonForProject(javaProject, classpathEntries,
|
||||
jythonInterpreterName, monitor);
|
||||
pythonInterpreter, monitor);
|
||||
}
|
||||
catch (NoClassDefFoundError | NoSuchMethodError e) {
|
||||
throw new OperationNotSupportedException(e.getMessage());
|
||||
|
@ -151,6 +224,15 @@ public class PyDevUtils {
|
|||
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.
|
||||
*
|
||||
|
@ -184,4 +266,138 @@ public class PyDevUtils {
|
|||
|
||||
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");
|
||||
* 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.
|
||||
|
@ -19,6 +19,7 @@ import java.io.File;
|
|||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.*;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
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.InterpreterManagersAPI;
|
||||
import org.python.pydev.core.*;
|
||||
import org.python.pydev.debug.core.Constants;
|
||||
import org.python.pydev.plugin.nature.PythonNature;
|
||||
|
||||
import com.python.pydev.debug.remote.client_api.PydevRemoteDebuggerServer;
|
||||
|
||||
import ghidradev.EclipseMessageUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||
|
||||
/**
|
||||
* 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 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 {
|
||||
|
||||
List<String> interpreters = new ArrayList<>();
|
||||
IInterpreterManager iMan = InterpreterManagersAPI.getJythonInterpreterManager(true);
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +116,38 @@ class PyDevUtilsInternal {
|
|||
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.
|
||||
*
|
||||
|
@ -119,26 +184,38 @@ class PyDevUtilsInternal {
|
|||
*
|
||||
* @param javaProject The Java project to setup Python for.
|
||||
* @param classpathEntries The classpath entries to add to the Python path.
|
||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* If this is null, Python support will be removed from the project.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The progress monitor used during link.
|
||||
* @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 NoSuchMethodError if PyDev is not installed or it does not support this operation.
|
||||
*/
|
||||
public static void setupPythonForProject(IJavaProject javaProject,
|
||||
List<IClasspathEntry> classpathEntries, String jythonInterpreterName,
|
||||
List<IClasspathEntry> classpathEntries, ProjectPythonInterpreter pythonInterpreter,
|
||||
IProgressMonitor monitor)
|
||||
throws CoreException, NoClassDefFoundError, NoSuchMethodError {
|
||||
|
||||
PythonNature.removeNature(javaProject.getProject(), monitor);
|
||||
|
||||
if (jythonInterpreterName != null) {
|
||||
String libs = classpathEntries.stream().map(e -> e.getPath().toOSString()).collect(
|
||||
Collectors.joining("|"));
|
||||
PythonNature.addNature(javaProject.getProject(), monitor,
|
||||
IPythonNature.JYTHON_VERSION_2_7, null, libs, jythonInterpreterName, null);
|
||||
String version;
|
||||
String libs;
|
||||
switch (pythonInterpreter.type()) {
|
||||
case PYGHIDRA:
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
// Prevent instantiation
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -36,6 +36,7 @@ import ghidra.GhidraApplicationLayout;
|
|||
import ghidradev.EclipseMessageUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils.ModuleTemplateType;
|
||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
|
@ -87,12 +88,12 @@ public class CreateGhidraModuleProjectWizard extends Wizard implements INewWizar
|
|||
boolean createRunConfig = projectPage.shouldCreateRunConfig();
|
||||
String runConfigMemory = projectPage.getRunConfigMemory();
|
||||
File projectDir = projectPage.getProjectDir();
|
||||
String jythonInterpreterName = pythonPage.getJythonInterpreterName();
|
||||
ProjectPythonInterpreter pythonInterpreter = pythonPage.getProjectPythonInterpreter();
|
||||
Set<ModuleTemplateType> moduleTemplateTypes = projectConfigPage.getModuleTemplateTypes();
|
||||
try {
|
||||
getContainer().run(true, false,
|
||||
monitor -> create(ghidraInstallDir, projectName, projectDir, createRunConfig,
|
||||
runConfigMemory, moduleTemplateTypes, jythonInterpreterName, monitor));
|
||||
runConfigMemory, moduleTemplateTypes, pythonInterpreter, monitor));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
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 runConfigMemory The run configuration's desired memory. Could be null.
|
||||
* @param moduleTemplateTypes The desired module template types.
|
||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* Could be null if Python support is not wanted.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The monitor to use during project creation.
|
||||
* @throws InvocationTargetException if an error occurred during project creation.
|
||||
*/
|
||||
private void create(File ghidraInstallDir, String projectName, File projectDir,
|
||||
boolean createRunConfig, String runConfigMemory,
|
||||
Set<ModuleTemplateType> moduleTemplateTypes, String jythonInterpreterName,
|
||||
Set<ModuleTemplateType> moduleTemplateTypes, ProjectPythonInterpreter pythonInterpreter,
|
||||
IProgressMonitor monitor) throws InvocationTargetException {
|
||||
try {
|
||||
info("Creating " + projectName + " at " + projectDir);
|
||||
|
@ -133,7 +133,7 @@ public class CreateGhidraModuleProjectWizard extends Wizard implements INewWizar
|
|||
|
||||
IJavaProject javaProject =
|
||||
GhidraModuleUtils.createGhidraModuleProject(projectName, projectDir,
|
||||
createRunConfig, runConfigMemory, ghidraLayout, jythonInterpreterName, monitor);
|
||||
createRunConfig, runConfigMemory, ghidraLayout, pythonInterpreter, monitor);
|
||||
monitor.worked(1);
|
||||
|
||||
IFile sourceFile = GhidraModuleUtils.configureModuleSource(javaProject,
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -32,6 +32,7 @@ import org.eclipse.ui.IWorkbench;
|
|||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidradev.EclipseMessageUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.GhidraScriptUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
|
@ -81,11 +82,11 @@ public class CreateGhidraScriptProjectWizard extends Wizard implements INewWizar
|
|||
String runConfigMemory = projectPage.getRunConfigMemory();
|
||||
boolean linkUserScripts = projectConfigPage.shouldLinkUsersScripts();
|
||||
boolean linkSystemScripts = projectConfigPage.shouldLinkSystemScripts();
|
||||
String jythonInterpreterName = pythonPage.getJythonInterpreterName();
|
||||
ProjectPythonInterpreter pythonInterpreter = pythonPage.getProjectPythonInterpreter();
|
||||
try {
|
||||
getContainer().run(true, false,
|
||||
monitor -> create(ghidraInstallDir, projectName, projectDir, createRunConfig,
|
||||
runConfigMemory, linkUserScripts, linkSystemScripts, jythonInterpreterName,
|
||||
runConfigMemory, linkUserScripts, linkSystemScripts, pythonInterpreter,
|
||||
monitor));
|
||||
}
|
||||
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 linkUserScripts Whether or not to link in the user scripts directory.
|
||||
* @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.
|
||||
* Could be null if Python support is not wanted.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The monitor to use during project creation.
|
||||
* @throws InvocationTargetException if an error occurred during project creation.
|
||||
*/
|
||||
private void create(File ghidraInstallDir, String projectName, File projectDir,
|
||||
boolean createRunConfig, String runConfigMemory, boolean linkUserScripts,
|
||||
boolean linkSystemScripts, String jythonInterpreterName, IProgressMonitor monitor)
|
||||
throws InvocationTargetException {
|
||||
boolean linkSystemScripts, ProjectPythonInterpreter pythonInterpreter,
|
||||
IProgressMonitor monitor) throws InvocationTargetException {
|
||||
try {
|
||||
info("Creating " + projectName + " at " + projectDir);
|
||||
monitor.beginTask("Creating " + projectName, 2);
|
||||
|
@ -128,7 +128,7 @@ public class CreateGhidraScriptProjectWizard extends Wizard implements INewWizar
|
|||
|
||||
GhidraScriptUtils.createGhidraScriptProject(projectName, projectDir, createRunConfig,
|
||||
runConfigMemory, linkUserScripts, linkSystemScripts, ghidraLayout,
|
||||
jythonInterpreterName, monitor);
|
||||
pythonInterpreter, monitor);
|
||||
monitor.worked(1);
|
||||
|
||||
info("Finished creating " + projectName);
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -40,7 +40,7 @@ import org.eclipse.ui.INewWizard;
|
|||
import org.eclipse.ui.IWorkbench;
|
||||
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.launch.JavaConfig;
|
||||
import ghidra.launch.AppConfig;
|
||||
import ghidradev.EclipseMessageUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.GhidraProjectUtils;
|
||||
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
|
||||
// saved Java home can change from launch to launch.
|
||||
GhidraApplicationLayout ghidraLayout = new GhidraApplicationLayout(new File(ghidraInstallDirPath));
|
||||
File javaHomeDir = new JavaConfig(
|
||||
File javaHomeDir = new AppConfig(
|
||||
ghidraLayout.getApplicationInstallationDir().getFile(false)).getSavedJavaHome();
|
||||
if(javaHomeDir == null) {
|
||||
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");
|
||||
* 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.
|
||||
|
@ -32,6 +32,7 @@ import org.eclipse.ui.IWorkbench;
|
|||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidradev.EclipseMessageUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.GhidraModuleUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
|
@ -76,11 +77,11 @@ public class ImportGhidraModuleSourceWizard extends Wizard implements IImportWiz
|
|||
String projectName = projectPage.getProjectName();
|
||||
boolean createRunConfig = projectPage.shouldCreateRunConfig();
|
||||
String runConfigMemory = projectPage.getRunConfigMemory();
|
||||
String jythonInterpreterName = pythonPage.getJythonInterpreterName();
|
||||
ProjectPythonInterpreter pythonInterpreter = pythonPage.getProjectPythonInterpreter();
|
||||
try {
|
||||
getContainer().run(true, false,
|
||||
monitor -> importModuleSource(ghidraInstallDir, projectName, moduleSourceDir,
|
||||
createRunConfig, runConfigMemory, jythonInterpreterName, monitor));
|
||||
createRunConfig, runConfigMemory, pythonInterpreter, monitor));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
@ -102,14 +103,14 @@ public class ImportGhidraModuleSourceWizard extends Wizard implements IImportWiz
|
|||
* @param moduleSourceDir The module source directory to import.
|
||||
* @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 jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* Could be null if Python support is not wanted.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The monitor to use during project creation.
|
||||
* @throws InvocationTargetException if an error occurred during project creation.
|
||||
*/
|
||||
private void importModuleSource(File ghidraInstallDir, String projectName, File moduleSourceDir,
|
||||
boolean createRunConfig, String runConfigMemory, String jythonInterpreterName,
|
||||
IProgressMonitor monitor) throws InvocationTargetException {
|
||||
boolean createRunConfig, String runConfigMemory,
|
||||
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||
throws InvocationTargetException {
|
||||
try {
|
||||
info("Importing " + projectName + " at " + moduleSourceDir);
|
||||
monitor.beginTask("Importing " + projectName, 2);
|
||||
|
@ -118,7 +119,7 @@ public class ImportGhidraModuleSourceWizard extends Wizard implements IImportWiz
|
|||
monitor.worked(1);
|
||||
|
||||
GhidraModuleUtils.importGhidraModuleSource(projectName, moduleSourceDir,
|
||||
createRunConfig, runConfigMemory, ghidraLayout, jythonInterpreterName, monitor);
|
||||
createRunConfig, runConfigMemory, ghidraLayout, pythonInterpreter, monitor);
|
||||
monitor.worked(1);
|
||||
|
||||
info("Finished importing " + projectName);
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -31,8 +31,9 @@ import org.eclipse.jface.viewers.ISelection;
|
|||
import org.eclipse.jface.wizard.Wizard;
|
||||
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.launch.JavaConfig;
|
||||
import ghidra.launch.AppConfig;
|
||||
import ghidradev.ghidraprojectcreator.utils.GhidraProjectUtils;
|
||||
import ghidradev.ghidraprojectcreator.utils.PyDevUtils.ProjectPythonInterpreter;
|
||||
import ghidradev.ghidraprojectcreator.wizards.pages.*;
|
||||
|
||||
/**
|
||||
|
@ -63,10 +64,10 @@ public class LinkGhidraWizard extends Wizard {
|
|||
public boolean performFinish() {
|
||||
File ghidraInstallDir = ghidraInstallationPage.getGhidraInstallDir();
|
||||
IJavaProject javaProject = projectPage.getJavaProject();
|
||||
String jythonInterpreterName = pythonPage.getJythonInterpreterName();
|
||||
ProjectPythonInterpreter pythonInterpreter = pythonPage.getProjectPythonInterpreter();
|
||||
try {
|
||||
getContainer().run(true, false,
|
||||
monitor -> link(ghidraInstallDir, javaProject, jythonInterpreterName, monitor));
|
||||
monitor -> link(ghidraInstallDir, javaProject, pythonInterpreter, monitor));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
@ -85,23 +86,23 @@ public class LinkGhidraWizard extends Wizard {
|
|||
*
|
||||
* @param ghidraInstallDir The Ghidra installation directory to use.
|
||||
* @param javaProject The Java project to link.
|
||||
* @param jythonInterpreterName The name of the Jython interpreter to use for Python support.
|
||||
* Could be null if Python support is not wanted.
|
||||
* @param pythonInterpreter The Python interpreter to use.
|
||||
* @param monitor The monitor to use during project link.
|
||||
* @throws InvocationTargetException if an error occurred during link.
|
||||
*/
|
||||
private void link(File ghidraInstallDir, IJavaProject javaProject, String jythonInterpreterName,
|
||||
IProgressMonitor monitor) throws InvocationTargetException {
|
||||
private void link(File ghidraInstallDir, IJavaProject javaProject,
|
||||
ProjectPythonInterpreter pythonInterpreter, IProgressMonitor monitor)
|
||||
throws InvocationTargetException {
|
||||
IProject project = javaProject.getProject();
|
||||
try {
|
||||
info("Linking " + project.getName());
|
||||
monitor.beginTask("Linking " + project.getName(), 2);
|
||||
|
||||
GhidraApplicationLayout ghidraLayout = new GhidraApplicationLayout(ghidraInstallDir);
|
||||
JavaConfig javaConfig =
|
||||
new JavaConfig(ghidraLayout.getApplicationInstallationDir().getFile(false));
|
||||
GhidraProjectUtils.linkGhidraToProject(javaProject, ghidraLayout, javaConfig,
|
||||
jythonInterpreterName, monitor);
|
||||
AppConfig appConfig =
|
||||
new AppConfig(ghidraLayout.getApplicationInstallationDir().getFile(false));
|
||||
GhidraProjectUtils.linkGhidraToProject(javaProject, ghidraLayout, appConfig,
|
||||
pythonInterpreter, monitor);
|
||||
monitor.worked(1);
|
||||
|
||||
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -27,7 +27,7 @@ import org.eclipse.swt.layout.GridLayout;
|
|||
import org.eclipse.swt.widgets.*;
|
||||
import org.eclipse.ui.dialogs.PreferencesUtil;
|
||||
|
||||
import ghidra.launch.JavaConfig;
|
||||
import ghidra.launch.AppConfig;
|
||||
import ghidra.launch.JavaFinder.JavaFilter;
|
||||
import ghidradev.ghidraprojectcreator.preferences.GhidraProjectCreatorPreferencePage;
|
||||
import ghidradev.ghidraprojectcreator.preferences.GhidraProjectCreatorPreferences;
|
||||
|
@ -108,8 +108,8 @@ public class ChooseGhidraInstallationWizardPage extends WizardPage {
|
|||
File ghidraInstallDir = new File(ghidraInstallDirCombo.getText());
|
||||
GhidraProjectCreatorPreferencePage.validateGhidraInstallation(ghidraInstallDir);
|
||||
try {
|
||||
JavaConfig javaConfig = new JavaConfig(ghidraInstallDir);
|
||||
if (!javaConfig.isSupportedJavaHomeDir(javaConfig.getSavedJavaHome(),
|
||||
AppConfig appConfig = new AppConfig(ghidraInstallDir);
|
||||
if (!appConfig.isSupportedJavaHomeDir(appConfig.getSavedJavaHome(),
|
||||
JavaFilter.JDK_ONLY)) {
|
||||
message = "A supported JDK is not associated with this Ghidra " +
|
||||
"installation. Please run this Ghidra and try again.";
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidradev.ghidraprojectcreator.wizards.pages;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -27,13 +26,15 @@ import org.eclipse.jface.wizard.WizardPage;
|
|||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.events.SelectionListener;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.layout.*;
|
||||
import org.eclipse.swt.widgets.*;
|
||||
import org.eclipse.ui.dialogs.PreferencesUtil;
|
||||
|
||||
import ghidra.launch.AppConfig;
|
||||
import ghidradev.EclipseMessageUtils;
|
||||
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.
|
||||
|
@ -41,7 +42,11 @@ import ghidradev.ghidraprojectcreator.utils.PyDevUtils;
|
|||
public class EnablePythonWizardPage extends WizardPage {
|
||||
|
||||
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 Button addJythonButton;
|
||||
|
||||
|
@ -61,46 +66,107 @@ public class EnablePythonWizardPage extends WizardPage {
|
|||
public void createControl(Composite parent) {
|
||||
|
||||
Composite container = new Composite(parent, SWT.NULL);
|
||||
container.setLayout(new GridLayout(3, false));
|
||||
container.setLayout(new GridLayout(1, false));
|
||||
|
||||
// Enable Python checkbox.
|
||||
enablePythonCheckboxButton = new Button(container, SWT.CHECK);
|
||||
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() {
|
||||
// Project type selection
|
||||
SelectionListener projectTypeSelectionListener = new SelectionListener() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent evt) {
|
||||
validate();
|
||||
validate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
Label jythonLabel = new Label(container, SWT.NULL);
|
||||
Label jythonLabel = new Label(interpreterContainer, SWT.NULL);
|
||||
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.setToolTipText("The wizard requires a Jython interpreter to be " +
|
||||
"selected. Click the + button to add or manage Jython interpreters.");
|
||||
populateJythonCombo();
|
||||
jythonCombo.addModifyListener(evt -> validate());
|
||||
jythonCombo.addModifyListener(evt -> validate(null));
|
||||
|
||||
// Jython interpreter add button
|
||||
addJythonButton = new Button(container, SWT.BUTTON1);
|
||||
addJythonButton = new Button(interpreterContainer, SWT.BUTTON1);
|
||||
addJythonButton.setText("+");
|
||||
addJythonButton.setToolTipText("Adds/manages Jython interpreters.");
|
||||
addJythonButton.addListener(SWT.Selection, evt -> {
|
||||
try {
|
||||
if (PyDevUtils.getJython27InterpreterNames().isEmpty()) {
|
||||
if (PyDevUtils.getJythonInterpreterNames().isEmpty()) {
|
||||
File ghidraDir = ghidraInstallationPage.getGhidraInstallDir();
|
||||
File jythonFile = findJythonInterpreter(ghidraDir);
|
||||
File jythonLib = findJythonLibrary(ghidraDir);
|
||||
|
@ -111,7 +177,7 @@ public class EnablePythonWizardPage extends WizardPage {
|
|||
PyDevUtils.addJythonInterpreter("jython_" + ghidraDir.getName(),
|
||||
jythonFile, jythonLib);
|
||||
populateJythonCombo();
|
||||
validate();
|
||||
validate(null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -124,80 +190,142 @@ public class EnablePythonWizardPage extends WizardPage {
|
|||
PyDevUtils.getJythonPreferencePageId(), null, null);
|
||||
dialog.open();
|
||||
populateJythonCombo();
|
||||
validate();
|
||||
validate(null);
|
||||
});
|
||||
|
||||
validate();
|
||||
validate(savedPyGhidraInterpreter);
|
||||
setControl(container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not Python should be enabled.
|
||||
*
|
||||
* @return True if python should be enabled; otherwise, false.
|
||||
*/
|
||||
public boolean shouldEnablePython() {
|
||||
return enablePythonCheckboxButton.getSelection();
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
if (visible) {
|
||||
validate(populatePyGhidraCombo(null));
|
||||
}
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the Jython interpreter to use.
|
||||
*
|
||||
* @return The name of the Jython interpreter to use. Could be null of Python isn't
|
||||
* enabled.
|
||||
* {@return the project Python interpreter to use}
|
||||
*/
|
||||
public String getJythonInterpreterName() {
|
||||
if (enablePythonCheckboxButton.getSelection()) {
|
||||
return jythonCombo.getText();
|
||||
public ProjectPythonInterpreter getProjectPythonInterpreter() {
|
||||
if (pyghidraButton.getSelection()) {
|
||||
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.
|
||||
* 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;
|
||||
boolean pyDevInstalled = PyDevUtils.isSupportedPyDevInstalled();
|
||||
boolean pyDevEnabled = enablePythonCheckboxButton.getSelection();
|
||||
boolean comboEnabled = pyDevInstalled && pyDevEnabled;
|
||||
boolean pyghidraSupported = PyDevUtils.isSupportedPyGhidraPyDevInstalled();
|
||||
boolean jythonSupported = PyDevUtils.isSupportedJythonPyDevInstalled();
|
||||
|
||||
if (pyDevEnabled) {
|
||||
if (!pyDevInstalled) {
|
||||
if (pyghidraButton.getSelection()) {
|
||||
if (!pyghidraSupported) {
|
||||
message = "PyDev version " + PyDevUtils.MIN_SUPPORTED_VERSION +
|
||||
" - " + PyDevUtils.MAX_SUPPORTED_VERSION + " is not installed.";
|
||||
" or later is not installed.";
|
||||
}
|
||||
else {
|
||||
try {
|
||||
List<String> interpreters = PyDevUtils.getJython27InterpreterNames();
|
||||
if (interpreters.isEmpty()) {
|
||||
message = "No Jython interpreters found. Click the + button to add one.";
|
||||
if (pyghidraInterpreter == null) {
|
||||
pyghidraInterpreter = findPyGhidraInterpreter();
|
||||
}
|
||||
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) {
|
||||
message = "PyDev version is not supported.";
|
||||
comboEnabled = false;
|
||||
message = "PyDev version is not supported for Jython.";
|
||||
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);
|
||||
addJythonButton.setEnabled(comboEnabled);
|
||||
pyghidraCombo.setEnabled(pyghidraButton.getSelection() && pyghidraSupported);
|
||||
addPyGhidraButton.setEnabled(pyghidraButton.getSelection() && pyghidraSupported);
|
||||
jythonCombo.setEnabled(jythonButton.getSelection() && jythonSupported);
|
||||
addJythonButton.setEnabled(jythonButton.getSelection() && jythonSupported);
|
||||
|
||||
setErrorMessage(message);
|
||||
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() {
|
||||
jythonCombo.removeAll();
|
||||
try {
|
||||
for (String jythonName : PyDevUtils.getJython27InterpreterNames()) {
|
||||
jythonCombo.add(jythonName);
|
||||
}
|
||||
PyDevUtils.getJythonInterpreterNames().forEach(jythonCombo::add);
|
||||
}
|
||||
catch (OperationNotSupportedException e) {
|
||||
// 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.
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue