mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Merge remote-tracking branch 'origin/GT-3350_ryanmkurtz_ExtensionPoints'
This commit is contained in:
commit
36a628ae97
52 changed files with 341 additions and 169 deletions
|
@ -22,6 +22,7 @@ import java.util.stream.Collectors;
|
|||
import generic.jar.ResourceFile;
|
||||
import ghidra.framework.GModule;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import utility.application.ApplicationLayout;
|
||||
import utility.module.ModuleUtilities;
|
||||
|
||||
/**
|
||||
|
@ -52,15 +53,17 @@ public class GhidraLauncher {
|
|||
|
||||
// Build the classpath
|
||||
List<String> classpathList = new ArrayList<String>();
|
||||
Map<String, GModule> modules = getOrderedModules(layout);
|
||||
|
||||
if (SystemUtilities.isInDevelopmentMode()) {
|
||||
addModuleBinPaths(classpathList, layout.getModules());
|
||||
addModuleBinPaths(classpathList, modules);
|
||||
addExternalJarPaths(classpathList, layout.getApplicationRootDirs());
|
||||
}
|
||||
else {
|
||||
addPatchPaths(classpathList, layout.getApplicationInstallationDir());
|
||||
addModuleJarPaths(classpathList, layout.getModules());
|
||||
addModuleJarPaths(classpathList, modules);
|
||||
}
|
||||
classpathList = orderClasspath(classpathList, layout.getModules());
|
||||
classpathList = orderClasspath(classpathList, modules);
|
||||
|
||||
// Add the classpath to the class loader
|
||||
GhidraClassLoader loader = (GhidraClassLoader) ClassLoader.getSystemClassLoader();
|
||||
|
@ -189,6 +192,63 @@ public class GhidraLauncher {
|
|||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the modules ordered by "class-loader priority". This ensures that core modules (things
|
||||
* in Framework/Features/Processors, etc) come before user modules (Extensions). It also
|
||||
* guarantees a consistent module order from run to run.
|
||||
*
|
||||
* @param layout The layout
|
||||
* @return the modules mapped by name, ordered by priority
|
||||
*/
|
||||
private static Map<String, GModule> getOrderedModules(ApplicationLayout layout) {
|
||||
|
||||
Comparator<GModule> comparator = (module1, module2) -> {
|
||||
int nameComparison = module1.getName().compareTo(module2.getName());
|
||||
|
||||
// First handle modules that are external to the Ghidra installation.
|
||||
// These should be put at the end of the list.
|
||||
boolean external1 = ModuleUtilities.isExternalModule(module1, layout);
|
||||
boolean external2 = ModuleUtilities.isExternalModule(module2, layout);
|
||||
if (external1 && external2) {
|
||||
return nameComparison;
|
||||
}
|
||||
if (external1) {
|
||||
return -1;
|
||||
}
|
||||
if (external2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Now handle modules that are internal to the Ghidra installation.
|
||||
// We will primarily order them by "type" and secondarily by name.
|
||||
Map<String, Integer> typePriorityMap = Map.of(
|
||||
"Framework", 0,
|
||||
"Configurations", 1,
|
||||
"Features", 2,
|
||||
"Processors", 3,
|
||||
"GPL", 4,
|
||||
"Extensions", 5,
|
||||
"Test", 6
|
||||
);
|
||||
String type1 = module1.getModuleRoot().getParentFile().getName();
|
||||
String type2 = module2.getModuleRoot().getParentFile().getName();
|
||||
int priority1 = typePriorityMap.getOrDefault(type1, typePriorityMap.size());
|
||||
int priority2 = typePriorityMap.getOrDefault(type2, typePriorityMap.size());
|
||||
if (priority1 != priority2) {
|
||||
return Integer.compare(priority1, priority2);
|
||||
}
|
||||
return nameComparison;
|
||||
};
|
||||
|
||||
List<GModule> moduleList = new ArrayList<>(layout.getModules().values());
|
||||
Collections.sort(moduleList, comparator);
|
||||
Map<String, GModule> moduleMap = new LinkedHashMap<>();
|
||||
for (GModule module : moduleList) {
|
||||
moduleMap.put(module.getName(), module);
|
||||
}
|
||||
return moduleMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of paths to make sure the order is correct for any class-loading dependencies.
|
||||
*
|
||||
|
@ -199,18 +259,16 @@ public class GhidraLauncher {
|
|||
private static List<String> orderClasspath(List<String> pathList,
|
||||
Map<String, GModule> modules) {
|
||||
|
||||
//@formatter:off
|
||||
Set<String> flatJars = modules
|
||||
Set<String> fatJars = modules
|
||||
.values()
|
||||
.stream()
|
||||
.flatMap(m -> m.getFatJars().stream())
|
||||
.collect(Collectors.toSet());
|
||||
//@formatter:on
|
||||
|
||||
List<String> orderedList = new ArrayList<String>(pathList);
|
||||
|
||||
for (String path : pathList) {
|
||||
if (flatJars.contains(new File(path).getName())) {
|
||||
if (fatJars.contains(new File(path).getName())) {
|
||||
orderedList.remove(path);
|
||||
orderedList.add(path);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import ghidra.util.Msg;
|
|||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import utilities.util.FileUtilities;
|
||||
import utility.application.ApplicationLayout;
|
||||
|
||||
/**
|
||||
* Utility methods for module related things.
|
||||
|
@ -334,4 +335,21 @@ public class ModuleUtilities {
|
|||
}
|
||||
return findRepo(f.getParentFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the given {@link GModule module} is external to the Ghidra installation
|
||||
* directory
|
||||
*
|
||||
* @param module the module to check
|
||||
* @param layout Ghidra's layout
|
||||
* @return true if the given {@link GModule module} is external to the Ghidra installation
|
||||
* directory
|
||||
*/
|
||||
public static boolean isExternalModule(GModule module, ApplicationLayout layout) {
|
||||
File moduleRootDir = module.getModuleRoot().getFile(false);
|
||||
return !layout.getApplicationRootDirs()
|
||||
.stream()
|
||||
.map(dir -> dir.getParentFile().getFile(false))
|
||||
.anyMatch(dir -> FileUtilities.isPathContainedWithin(dir, moduleRootDir));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue