From 88bec10e604d048d90e8085d5ad3928ad5ba3b47 Mon Sep 17 00:00:00 2001
From: Ryan Kurtz
Date: Fri, 26 Jul 2024 13:12:29 -0400
Subject: [PATCH] GP-3490: Fixing GhidraDev classpath issues
---
.../runtimeinfo/RuntimeInfoProvider.java | 11 ++-
.../util/classfinder/ClassSearcher.java | 22 ++----
.../java/ghidra/GhidraApplicationLayout.java | 35 +++-------
.../main/java/ghidra/GhidraClassLoader.java | 26 +++++--
.../src/main/java/ghidra/GhidraLauncher.java | 46 +++++++------
.../framework/ApplicationProperties.java | 12 ++--
Ghidra/application.properties | 2 +-
.../GhidraDevPlugin/.launch/GhidraDev.launch | 52 +++++++-------
.../GhidraDevPlugin/GhidraDev_README.html | 24 ++++++-
.../GhidraDevPlugin/META-INF/MANIFEST.MF | 4 +-
.../GhidraDev/GhidraDevPlugin/plugin.xml | 6 +-
.../launchers/GhidraLaunchDelegate.java | 19 ++++--
.../launchers/GhidraLaunchTabGroup.java | 53 +++++++++++++--
.../utils/GhidraLaunchUtils.java | 67 ++++++++++++++++++-
.../utils/GhidraModuleUtils.java | 39 +++++++----
.../utils/GhidraProjectUtils.java | 8 +--
16 files changed, 285 insertions(+), 141 deletions(-)
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoProvider.java
index 86040bb4fa..47ea398315 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoProvider.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,7 +16,6 @@
package ghidra.app.plugin.runtimeinfo;
import java.awt.*;
-import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
@@ -249,11 +248,9 @@ class RuntimeInfoProvider extends ReusableDialogComponentProvider {
*/
private Map getClasspathMap(String propertyName) {
Map map = new HashMap<>();
- StringTokenizer st =
- new StringTokenizer(System.getProperty(propertyName, ""), File.pathSeparator);
int i = 0;
- while (st.hasMoreTokens()) {
- map.put(i++, st.nextToken());
+ for (String entry : GhidraClassLoader.getClasspath(propertyName)) {
+ map.put(i++, entry);
}
return map;
}
diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java
index 011acf42d7..94630c1f26 100644
--- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java
+++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -30,7 +30,6 @@ import java.util.stream.Collectors;
import javax.swing.event.ChangeListener;
-import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -491,24 +490,11 @@ public class ClassSearcher {
// jar files will *not* be on the standard classpath, but instead will be on CP_EXT.
//
List rawPaths = new ArrayList<>();
- getPropertyPaths(GhidraClassLoader.CP, rawPaths);
- getPropertyPaths(GhidraClassLoader.CP_EXT, rawPaths);
+ rawPaths.addAll(GhidraClassLoader.getClasspath(GhidraClassLoader.CP));
+ rawPaths.addAll(GhidraClassLoader.getClasspath(GhidraClassLoader.CP_EXT));
return canonicalizePaths(rawPaths);
}
- private static void getPropertyPaths(String property, List results) {
- String paths = System.getProperty(property);
- log.trace("Paths in {}: {}", property, paths);
- if (StringUtils.isBlank(paths)) {
- return;
- }
-
- StringTokenizer st = new StringTokenizer(paths, File.pathSeparator);
- while (st.hasMoreTokens()) {
- results.add(st.nextToken());
- }
- }
-
private static List canonicalizePaths(Collection paths) {
//@formatter:off
diff --git a/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraApplicationLayout.java b/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraApplicationLayout.java
index 72974f853d..007f862d44 100644
--- a/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraApplicationLayout.java
+++ b/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraApplicationLayout.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -169,28 +169,15 @@ public class GhidraApplicationLayout extends ApplicationLayout {
});
}
- // Examine the classpath to look for modules outside of the application root directories.
- // These might exist if Ghidra was launched from an Eclipse project that resides
- // external to the Ghidra installation.
- for (String entry : System.getProperty("java.class.path", "").split(File.pathSeparator)) {
- ResourceFile classpathEntry = new ResourceFile(entry);
-
- // We only care about directories (skip jars)
- if (!classpathEntry.isDirectory()) {
- continue;
- }
-
- // Skip extensions in an application root directory... already found those.
- if (FileUtilities.isPathContainedWithin(applicationRootDirs, classpathEntry)) {
- continue;
- }
-
- // We are going to assume that the classpath entry is in a subdirectory of the module
- // directory (i.e., bin/), so only check parent directory for the module.
- ResourceFile classpathEntryParent = classpathEntry.getParentFile();
- if (classpathEntryParent != null &&
- ModuleUtilities.isModuleDirectory(classpathEntryParent)) {
- moduleRootDirectories.add(classpathEntryParent);
+ // Add external modules defined via a system property. This will typically be used by
+ // user's developing 3rd party modules from something like Eclipse.
+ String externalModules = System.getProperty("ghidra.external.modules", "");
+ if (!externalModules.isBlank()) {
+ for (String path : externalModules.split(File.pathSeparator)) {
+ ResourceFile eclipseProjectDir = new ResourceFile(path);
+ if (ModuleUtilities.isModuleDirectory(eclipseProjectDir)) {
+ moduleRootDirectories.add(eclipseProjectDir);
+ }
}
}
diff --git a/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraClassLoader.java b/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraClassLoader.java
index d781613067..d6564fae8d 100644
--- a/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraClassLoader.java
+++ b/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraClassLoader.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,8 +18,7 @@ package ghidra;
import java.io.File;
import java.lang.instrument.Instrumentation;
import java.net.*;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
import ghidra.util.Msg;
@@ -51,6 +50,25 @@ public class GhidraClassLoader extends URLClassLoader {
*/
public static final String CP_EXT = "java.class.path.ext";
+ /**
+ * Gets a {@link List} containing the current classpath referenced by the given property name
+ *
+ * @param propertyName The property name of the classpath to get
+ * @return A {@link List} containing the current classpath referenced by the given property name
+ */
+ public static List getClasspath(String propertyName) {
+ List result = new ArrayList<>();
+
+ // StringTokenizer is better than split() here because our result list will stay empty if
+ // the classpath is empty
+ StringTokenizer st =
+ new StringTokenizer(System.getProperty(propertyName, ""), File.pathSeparator);
+ while (st.hasMoreTokens()) {
+ result.add(st.nextToken());
+ }
+ return result;
+ }
+
/**
* Used to prevent duplicate URL's from being added to the classpath
*/
diff --git a/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraLauncher.java b/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraLauncher.java
index 8a0299d69f..d792b2c1ab 100644
--- a/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraLauncher.java
+++ b/Ghidra/Framework/Utility/src/main/java/ghidra/GhidraLauncher.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -150,11 +150,15 @@ public class GhidraLauncher {
List classpathList = new ArrayList<>();
Map modules = getOrderedModules(layout);
+ // First add any "bin" paths the module might have. These could come from external modules
+ // being developed and passed in via system property if we are in release mode, or they
+ // could be generated for each Ghidra module by Eclipse if we are in development mode.
+ addModuleBinPaths(classpathList, modules);
+
if (SystemUtilities.isInDevelopmentMode()) {
- // First add Eclipse's module "bin" paths. If we didn't find any, assume Ghidra was
+ // If we didn't find any "bin" paths and we are in development mode, assume Ghidra was
// compiled with Gradle, and add the module jars Gradle built.
- addModuleBinPaths(classpathList, modules);
boolean gradleDevMode = classpathList.isEmpty();
if (gradleDevMode) {
// Add the module jars Gradle built.
@@ -165,22 +169,16 @@ public class GhidraLauncher {
else { /* Eclipse dev mode */
// Support loading pre-built, jar-based, non-repo extensions in Eclipse dev mode
addExtensionJarPaths(classpathList, modules, layout);
-
- // Eclipse launches the Utility module, so it's already on the classpath. We don't
- // want to add it a second time, so remove the one we discovered.
- GModule utilityModule = modules.get("Utility");
- if (utilityModule == null) {
- throw new IOException("Failed to find the 'Utility' module!");
- }
- classpathList.removeIf(
- e -> e.startsWith(utilityModule.getModuleRoot().getAbsolutePath()));
}
- // In development mode, jars do not live in module directories. Instead, each jar lives
- // in an external, non-repo location, which is listed in build/libraryDependencies.txt.
+ // In development mode, 3rd party library jars do not live in module directories.
+ // Instead, each jar lives in an external, non-repo location, which is listed in
+ // build/libraryDependencies.txt.
addExternalJarPaths(classpathList, layout.getApplicationRootDirs());
}
else {
+
+ // Release mode is simple. We expect all of Ghidra's modules to be in pre-build jars.
addPatchPaths(classpathList, layout.getPatchDir());
addModuleJarPaths(classpathList, modules);
}
@@ -194,8 +192,16 @@ public class GhidraLauncher {
// the standard classpath.)
setExtensionJarPaths(modules, layout, classpathList);
- classpathList = orderClasspath(classpathList, modules);
- return classpathList;
+ // Ghidra launches from the Utility module, so it's already on the classpath. We don't
+ // want to add it a second time, so remove the one we discovered.
+ GModule utilityModule = modules.get("Utility");
+ if (utilityModule == null) {
+ throw new IOException("Failed to find the 'Utility' module!");
+ }
+ classpathList.removeIf(
+ e -> e.startsWith(utilityModule.getModuleRoot().getAbsolutePath()));
+
+ return orderClasspath(classpathList, modules);
}
/**
@@ -265,9 +271,9 @@ public class GhidraLauncher {
}
/**
- * Add extension module lib jars to the given path list. (This only needed in dev mode to find
- * any pre-built extensions that have been installed, since we already find extension module
- * jars in production mode.)
+ * Add extension module lib jars to the given path list. (This is only needed in dev mode to
+ * find any pre-built extensions that have been installed, since we already find extension
+ * module jars in production mode.)
*
* @param pathList The list of paths to add to.
* @param modules The modules to get the jars of.
diff --git a/Ghidra/Framework/Utility/src/main/java/ghidra/framework/ApplicationProperties.java b/Ghidra/Framework/Utility/src/main/java/ghidra/framework/ApplicationProperties.java
index 765b5025fa..0703b3ae44 100644
--- a/Ghidra/Framework/Utility/src/main/java/ghidra/framework/ApplicationProperties.java
+++ b/Ghidra/Framework/Utility/src/main/java/ghidra/framework/ApplicationProperties.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,6 +20,7 @@ import java.text.SimpleDateFormat;
import java.util.*;
import generic.jar.ResourceFile;
+import ghidra.GhidraApplicationLayout;
/**
* The application properties. Application properties may either be stored on disk, or created
@@ -52,8 +53,11 @@ public class ApplicationProperties extends Properties {
* Current application versions are:
*
* - 1: Layout used by Ghidra < 11.1
- * - 2: Introduced with Ghidra 11.1. Default user settings/cache/temp directories changed,
- * and XDG environment variables are supported.
+ *
- 2: Introduced with Ghidra 11.1. Default user settings/cache/temp directories changed,
+ * and XDG environment variables are supported.
+ * - 3: Introduced with Ghidra 11.2. Ghidra no longer finds external modules by examining
+ * the initial classpath. Instead, the "ghidra.external.modules" system property is used
+ * (see {@link GhidraApplicationLayout}).
*
*/
public static final String APPLICATION_LAYOUT_VERSION_PROPERTY = "application.layout.version";
diff --git a/Ghidra/application.properties b/Ghidra/application.properties
index 49cdcca99b..332f14284c 100644
--- a/Ghidra/application.properties
+++ b/Ghidra/application.properties
@@ -1,7 +1,7 @@
application.name=Ghidra
application.version=11.2
application.release.name=DEV
-application.layout.version=2
+application.layout.version=3
application.gradle.min=8.5
application.gradle.max=
application.java.min=21
diff --git a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/.launch/GhidraDev.launch b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/.launch/GhidraDev.launch
index 5ab9dc9fdf..219d1935e4 100644
--- a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/.launch/GhidraDev.launch
+++ b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/.launch/GhidraDev.launch
@@ -158,6 +158,7 @@
+
@@ -166,16 +167,14 @@
-
-
-
+
-
-
+
+
@@ -204,7 +203,7 @@
-
+
@@ -219,7 +218,7 @@
-
+
@@ -248,7 +247,7 @@
-
+
@@ -266,6 +265,7 @@
+
@@ -285,7 +285,7 @@
-
+
@@ -293,7 +293,7 @@
-
+
@@ -309,6 +309,7 @@
+
@@ -336,21 +337,20 @@
-
-
+
-
+
-
+
@@ -381,7 +381,7 @@
-
+
@@ -395,6 +395,7 @@
+
@@ -407,19 +408,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/GhidraDev_README.html b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/GhidraDev_README.html
index 80f1d798a6..50065d62a6 100644
--- a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/GhidraDev_README.html
+++ b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/GhidraDev_README.html
@@ -19,7 +19,7 @@
GhidraDev README
GhidraDev provides support for developing and debugging Ghidra scripts and modules in Eclipse.
-The information provided in this document is effective as of GhidraDev 3.1.0 and is subject to
+
The information provided in this document is effective as of GhidraDev 4.0.0 and is subject to
change with future releases.
@@ -54,6 +54,24 @@ change with future releases.
Change History
+4.0.0:
+
+ -
+ GhidraDev has been upgraded to be compatible with Ghidra 11.2 and later. Older versions of
+ GhidraDev will report an error when trying to link against Ghidra 11.2 or later.
+
+ -
+ GhidraDev now requires Eclipse 2023-12 4.30 or later.
+
+ -
+ GhidraDev now requires JDK 21.
+
+ -
+ Fixed an issue that could result in a GhidraHelpService exception when launching
+ Ghidra. GhidraDev now properly enforces that Ghidra is only launched with Utility.jar on
+ the initial classpath.
+
+
3.1.0:
-
@@ -176,8 +194,8 @@ that specify other projects on their build paths.
Minimum Requirements
- - Eclipse 2021-12 4.22 or later
- - Ghidra 9.1 or later
+ - Eclipse 2023-12 4.30 or later
+ - Ghidra 11.2 or later
(Back to Top)
diff --git a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/META-INF/MANIFEST.MF
index 591c26d03e..f043de2900 100644
--- a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/META-INF/MANIFEST.MF
+++ b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: GhidraDev
Bundle-SymbolicName: ghidra.ghidradev;singleton:=true
-Bundle-Version: 3.1.0.qualifier
+Bundle-Version: 4.0.0.qualifier
Bundle-Activator: ghidradev.Activator
Require-Bundle: org.eclipse.ant.core;bundle-version="3.6.200",
org.eclipse.buildship.core;bundle-version="3.1.5",
@@ -27,7 +27,7 @@ Require-Bundle: org.eclipse.ant.core;bundle-version="3.6.200",
org.python.pydev.ast;bundle-version="[6.3.1,10.0.0)";resolution:=optional,
org.eclipse.cdt.core;bundle-version="5.9.1";resolution:=optional,
org.eclipse.cdt.ui;bundle-version="5.9.0";resolution:=optional
-Bundle-RequiredExecutionEnvironment: JavaSE-17
+Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-Vendor: Ghidra
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .,
diff --git a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/plugin.xml b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/plugin.xml
index caaaaf2af3..d377ab0ca7 100644
--- a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/plugin.xml
+++ b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/plugin.xml
@@ -365,9 +365,13 @@
+ migrationDelegate="org.eclipse.jdt.internal.launching.JavaMigrationDelegate"
+ name="Ghidra"
+ sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
+ sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer">
tabs = new ArrayList<>();
tabs.add(getJavaMainTab());
tabs.add(getUserDefinedArgumentsTab());
- tabs.add(new JavaClasspathTab());
+ tabs.add(getJavaDependenciesTab());
+ tabs.add(getSourceLookupTab());
tabs.add(new EnvironmentTab());
tabs.add(getCommonTab());
@@ -169,6 +171,49 @@ public class GhidraLaunchTabGroup extends AbstractLaunchConfigurationTabGroup {
};
}
+ /**
+ * Gets the {@link JavaDependenciesTab} to use, with all Ghidra jars removed except Utility.jar.
+ *
+ * @return The {@link JavaDependenciesTab} to use, with all Ghidra jars removed except
+ * Utility.jar.
+ */
+ private JavaDependenciesTab getJavaDependenciesTab() {
+ return new JavaDependenciesTab() {
+ @Override
+ public void initializeFrom(ILaunchConfiguration config) {
+ try {
+ ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
+ GhidraLaunchUtils.setClasspath(wc);
+ super.initializeFrom(wc.doSave());
+ }
+ catch (CoreException e) {
+ EclipseMessageUtils.error("Failed to initialize the java dependencies tab.", e);
+ }
+ }
+ };
+ }
+
+ /**
+ * Gets the {@link SourceLookupTab} to use, with all Ghidra jars added.
+ *
+ * @return The {@link SourceLookupTab} to use, with all Ghidra jars added.
+ */
+ private SourceLookupTab getSourceLookupTab() {
+ return new SourceLookupTab() {
+ @Override
+ public void initializeFrom(ILaunchConfiguration config) {
+ try {
+ ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
+ GhidraLaunchUtils.setSource(wc);
+ super.initializeFrom(wc.doSave());
+ }
+ catch (CoreException e) {
+ EclipseMessageUtils.error("Failed to initialize the source lookup tab.", e);
+ }
+ }
+ };
+ }
+
/**
* Gets the {@link CommonTab} to use, with the new launch configuration added to the favorites.
*
diff --git a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraLaunchUtils.java b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraLaunchUtils.java
index c4e82f5d6b..e70f7c7a60 100644
--- a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraLaunchUtils.java
+++ b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraLaunchUtils.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,13 +19,15 @@ import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.debug.core.*;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationManager;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchHistory;
import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
+import org.eclipse.jdt.launching.*;
import ghidra.GhidraLauncher;
@@ -83,6 +85,8 @@ public class GhidraLaunchUtils {
javaProject.getProject().getName());
setMainTypeName(wc);
setMemory(wc, runConfigMemory);
+ setClasspath(wc);
+ setSource(wc);
setFavorites(wc);
return wc;
}
@@ -168,6 +172,63 @@ public class GhidraLaunchUtils {
return wc;
}
+ /**
+ * Removes all project jars from the classpath except Utility.jar.
+ *
+ * @param wc The launch configuration working copy to modify.
+ * @return The modified working copy.
+ * @throws CoreException if there was an Eclipse-related issue modifying the classpath.
+ */
+ public static ILaunchConfigurationWorkingCopy setClasspath(ILaunchConfigurationWorkingCopy wc)
+ throws CoreException {
+ List newList = new ArrayList<>();
+ for (IRuntimeClasspathEntry entry : JavaRuntime.computeUnresolvedRuntimeClasspath(wc)) {
+ switch (entry.getClasspathEntry().getEntryKind()) {
+ case IClasspathEntry.CPE_LIBRARY:
+ if (entry.getPath().toOSString().endsWith("Utility.jar")) {
+ newList.add(entry.getMemento());
+ }
+ break;
+ case IClasspathEntry.CPE_CONTAINER:
+ newList.add(entry.getMemento());
+ break;
+ case IClasspathEntry.CPE_PROJECT:
+ case IClasspathEntry.CPE_SOURCE:
+ case IClasspathEntry.CPE_VARIABLE:
+ default:
+ break;
+ }
+ }
+ wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH, newList);
+ wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);
+ return wc;
+ }
+
+ /**
+ * Adds all project jars that have associated source to the source path
+ *
+ * @param wc The launch configuration working copy to modify.
+ * @return The modified working copy.
+ * @throws CoreException if there was an Eclipse-related issue modifying the source path.
+ */
+ public static ILaunchConfigurationWorkingCopy setSource(ILaunchConfigurationWorkingCopy wc)
+ throws CoreException {
+ List newList = new ArrayList<>();
+ IJavaProject javaProject = JavaRuntime.getJavaProject(wc);
+ if (javaProject != null) {
+ for (IClasspathEntry entry : javaProject.getRawClasspath()) {
+ IPath sourcePath = entry.getSourceAttachmentPath();
+ if (sourcePath != null) {
+ newList.add(
+ JavaRuntime.newArchiveRuntimeClasspathEntry(sourcePath).getMemento());
+ }
+ }
+ }
+ wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH, newList);
+ wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_SOURCE_PATH, false);
+ return wc;
+ }
+
/**
* Sets the favorites attribute in the provided working copy to include the launcher in both
* the run and debug launch groups.
diff --git a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraModuleUtils.java b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraModuleUtils.java
index 98e65deab5..5a83376d9c 100644
--- a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraModuleUtils.java
+++ b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraModuleUtils.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -62,6 +62,14 @@ public class GhidraModuleUtils {
}
}
+ /**
+ * Stores a source folder and its corresponding output folder
+ *
+ * @param sourceFolder The source folder
+ * @param outputFolder The output folder
+ */
+ private record SourceFolderInfo(IFolder sourceFolder, IFolder outputFolder) {}
+
/**
* Creates a new Ghidra module project with the given name.
*
@@ -90,20 +98,27 @@ public class GhidraModuleUtils {
IProject project = javaProject.getProject();
// Create source directories
- List sourceFolders = new ArrayList<>();
- sourceFolders.add(project.getFolder("src/main/java"));
- sourceFolders.add(project.getFolder("src/main/help"));
- sourceFolders.add(project.getFolder("src/main/resources"));
- sourceFolders.add(project.getFolder("src/test/java"));
- sourceFolders.add(project.getFolder("ghidra_scripts"));
- for (IFolder sourceFolder : sourceFolders) {
- GhidraProjectUtils.createFolder(sourceFolder, monitor);
+ List sourceFolderInfos = new ArrayList<>();
+ sourceFolderInfos.add(new SourceFolderInfo(project.getFolder("src/main/java"),
+ project.getFolder("bin/main")));
+ sourceFolderInfos.add(new SourceFolderInfo(project.getFolder("src/main/help"),
+ project.getFolder("bin/main")));
+ sourceFolderInfos.add(new SourceFolderInfo(project.getFolder("src/main/resources"),
+ project.getFolder("bin/main")));
+ sourceFolderInfos.add(new SourceFolderInfo(project.getFolder("src/test/java"),
+ project.getFolder("bin/test")));
+ sourceFolderInfos.add(new SourceFolderInfo(project.getFolder("ghidra_scripts"),
+ project.getFolder("bin/scripts")));
+ for (SourceFolderInfo sourceFolderInfo : sourceFolderInfos) {
+ GhidraProjectUtils.createFolder(sourceFolderInfo.outputFolder(), monitor);
}
// Put the source directories in the project's classpath
List classpathEntries = new LinkedList<>();
- for (IFolder sourceFolder : sourceFolders) {
- classpathEntries.add(JavaCore.newSourceEntry(sourceFolder.getFullPath()));
+ for (SourceFolderInfo sourceFolderInfo : sourceFolderInfos) {
+ classpathEntries
+ .add(JavaCore.newSourceEntry(sourceFolderInfo.sourceFolder().getFullPath(),
+ new IPath[0], sourceFolderInfo.outputFolder().getFullPath()));
}
GhidraProjectUtils.addToClasspath(javaProject, classpathEntries, monitor);
diff --git a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraProjectUtils.java b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraProjectUtils.java
index f01a21fcee..059140616f 100644
--- a/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraProjectUtils.java
+++ b/GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/utils/GhidraProjectUtils.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -301,8 +301,8 @@ public class GhidraProjectUtils {
// Configure Java compiler for the project
configureJavaCompiler(javaProject, javaConfig);
- // Setup bin folder
- IFolder binFolder = project.getFolder("bin");
+ // Setup default bin folder
+ IFolder binFolder = project.getFolder("bin/default");
javaProject.setOutputLocation(binFolder.getFullPath(), monitor);
// Add Eclipse's built-in JUnit to classpath