diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java index e7ce1bd1e7..968a7cdfd5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java @@ -475,6 +475,8 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader createUnprocessedQueue(libraryNameList, getLibraryLoadDepth(options)); boolean loadLocalLibraries = isLoadLocalLibraries(options); boolean loadSystemLibraries = isLoadSystemLibraries(options); + List customSearchPaths = + getCustomLibrarySearchPaths(provider, options, log, monitor); List localSearchPaths = getLocalLibrarySearchPaths(provider, options, log, monitor); List systemSearchPaths = @@ -509,25 +511,34 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader // options turned off (if shouldSearchAllPaths() is overridden to return true). // In this case, we still want to process those libraries, but we // do not want to save them, so they can be released. - boolean loadedLocal = false; - if (!localSearchPaths.isEmpty()) { - Loaded loadedLibrary = loadLibraryFromSearchPaths( - libraryName, provider, localSearchPaths, libraryDestFolderPath, - unprocessed, depth, desiredLoadSpec, options, log, consumer, monitor); + boolean loaded = false; + if (!customSearchPaths.isEmpty()) { + Loaded loadedLibrary = loadLibraryFromSearchPaths(libraryName, + provider, customSearchPaths, libraryDestFolderPath, unprocessed, depth, + desiredLoadSpec, options, log, consumer, monitor); + if (loadedLibrary != null) { + loadedPrograms.add(loadedLibrary); + loaded = true; + } + } + if (!loaded && !localSearchPaths.isEmpty()) { + Loaded loadedLibrary = loadLibraryFromSearchPaths(libraryName, + provider, localSearchPaths, libraryDestFolderPath, unprocessed, depth, + desiredLoadSpec, options, log, consumer, monitor); if (loadedLibrary != null) { if (loadLocalLibraries) { loadedPrograms.add(loadedLibrary); - loadedLocal = true; + loaded = true; } else { loadedLibrary.release(consumer); } } } - if (!loadedLocal && !systemSearchPaths.isEmpty()) { - Loaded loadedLibrary = loadLibraryFromSearchPaths( - libraryName, provider, systemSearchPaths, libraryDestFolderPath, - unprocessed, depth, desiredLoadSpec, options, log, consumer, monitor); + if (!loaded && !systemSearchPaths.isEmpty()) { + Loaded loadedLibrary = loadLibraryFromSearchPaths(libraryName, + provider, systemSearchPaths, libraryDestFolderPath, unprocessed, depth, + desiredLoadSpec, options, log, consumer, monitor); if (loadedLibrary != null) { if (loadSystemLibraries) { loadedPrograms.add(loadedLibrary); @@ -1013,6 +1024,23 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader */ private record FileSystemSearchPath(FileSystemRef fsRef, Path fsPath) {} + /** + * Gets a {@link List} of priority-ordered custom {@link FileSystemSearchPath}s used to search + * for libraries. The default implementation of this method returns an empty {@link List}. + * Subclasses can override it as needed. + * + * @param provider The {@link ByteProvider} of the program being loaded + * @param options The options + * @param log The log + * @param monitor A cancelable task monitor + * @return A {@link List} of priority-ordered custom {@link FileSystemSearchPath}s used to + * search for libraries + */ + protected List getCustomLibrarySearchPaths(ByteProvider provider, + List