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 21824da9fc..5e21bb5642 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 @@ -38,7 +38,6 @@ import ghidra.program.model.lang.*; import ghidra.program.model.listing.Library; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.ExternalManager; -import ghidra.util.Msg; import ghidra.util.StringUtilities; import ghidra.util.exception.CancelledException; import ghidra.util.exception.InvalidInputException; @@ -632,12 +631,12 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader continue; } processed.add(library); - if (findLibraryInProject(library, libraryDestFolder, searchPaths, + if (findLibraryInProject(library, libraryDestFolder, searchPaths, true, settings) != null) { log.appendMsg("Found %s in %s...".formatted(library, libraryDestFolder)); log.appendMsg("------------------------------------------------\n"); } - else if (findLibraryInProject(library, linkSearchFolder, searchPaths, + else if (findLibraryInProject(library, linkSearchFolder, searchPaths, true, settings) != null) { log.appendMsg("Found %s in %s...".formatted(library, linkSearchFolder)); log.appendMsg("------------------------------------------------\n"); @@ -779,12 +778,14 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader * @param folder {@link DomainFolder root folder} within which imported libraries will * be searched. If null this method will return null. * @param searchPaths A {@link List} of {@link LibrarySearchPath}s that will be searched + * @param matchLoadSpec True if the returned library must match the desired load spec; false + * if a match is not required * @param settings The {@link Loader.ImporterSettings} * @return The found {@link DomainFile} or null if not found * @throws CancelledException if the user cancelled the load */ protected DomainFile findLibraryInProject(String library, DomainFolder folder, - List searchPaths, ImporterSettings settings) + List searchPaths, boolean matchLoadSpec, ImporterSettings settings) throws CancelledException { if (folder == null) { return null; @@ -809,7 +810,8 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader } DomainFile ret = lookupLibraryInFolder(FilenameUtils.getName(library), parentFolder); - if (ret != null) { + if (ret != null && + (!matchLoadSpec || matchSupportedLoadSpec(settings.loadSpec(), ret))) { return ret; } } @@ -825,13 +827,19 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader } } + // First perform a direct filename lookup in the folder (for efficiency) String libraryName = FilenameUtils.getName(library); DomainFile file = folder.getFile(libraryName); if (file != null) { - return file; + return !matchLoadSpec || matchSupportedLoadSpec(settings.loadSpec(), file) ? file + : null; } - return lookupLibraryInFolder(libraryName, folder); + // If necessary, perform a slower comparator-based lookup on every file in the folder + file = lookupLibraryInFolder(libraryName, folder); + return file != null && (!matchLoadSpec || matchSupportedLoadSpec(settings.loadSpec(), file)) + ? file + : null; } /** @@ -968,40 +976,50 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader continue; } monitor.checkCancelled(); - try { - Loaded match = findLibraryInLoadedList(loadedPrograms, externalLibName); - if (match != null) { - extManager.setExternalPath(externalLibName, FSUtilities - .appendPath(match.getProjectFolderPath(), match.getName()), - false); - log.appendMsg(" [" + externalLibName + "] -> [" + match.getName() + "]"); - } - else { - boolean found = false; - for (DomainFolder searchFolder : searchFolders) { - DomainFile alreadyImportedLib = findLibraryInProject(externalLibName, - searchFolder, fsSearchPaths, settings); - if (alreadyImportedLib != null) { - extManager.setExternalPath(externalLibName, - alreadyImportedLib.getPathname(), false); - log.appendMsg(" [" + externalLibName + "] -> [" + - alreadyImportedLib.getPathname() + "] (previously imported)"); - found = true; - break; - } - } - if (!found) { - log.appendMsg(" [" + externalLibName + "] -> not found in project"); - } - } + Loaded match = findLibraryInLoadedList(loadedPrograms, externalLibName); + if (match != null) { + setExternalLibrary(externalLibName, + FSUtilities.appendPath(match.getProjectFolderPath(), match.getName()), program, + settings); } - catch (InvalidInputException e) { - Msg.error(this, "Bad library name: " + externalLibName, e); + else { + boolean found = false; + for (DomainFolder searchFolder : searchFolders) { + DomainFile alreadyImportedLib = findLibraryInProject(externalLibName, + searchFolder, fsSearchPaths, false, settings); + if (alreadyImportedLib != null) { + if (matchSupportedLoadSpec(settings.loadSpec(), alreadyImportedLib)) { + setExternalLibrary(externalLibName, alreadyImportedLib.getPathname(), + program, settings); + } + else { + log.appendMsg( + " [%s] -> found wrong architecture".formatted(externalLibName)); + } + found = true; + break; + } + } + if (!found) { + log.appendMsg(" [%s] -> not found in project".formatted(externalLibName)); + } } } log.appendMsg("------------------------------------------------\n"); } + private void setExternalLibrary(String libraryName, String pathname, Program program, + ImporterSettings settings) { + MessageLog log = settings.log(); + try { + program.getExternalManager().setExternalPath(libraryName, pathname, false); + log.appendMsg(" [%s] -> [%s] (previously imported)".formatted(libraryName, pathname)); + } + catch (InvalidInputException e) { + log.appendMsg(" [%s] -> bad library name".formatted(libraryName)); + } + } + /** * A library that has not been processed by the loader yet * @@ -1175,6 +1193,28 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader return null; } + /** + * {@return whether or not the given {@link LoadSpec} matches the one associated with the given + * {@link DomainFile}} + *

+ * To avoid having to open each library which might require an upgrade, we just look at the + * "Language ID" metadata attached to the {@link DomainFile}. + * + * @param desiredLoadSpec The desired {@link LoadSpec} + * @param df The {@link DomainFile} + */ + protected boolean matchSupportedLoadSpec(LoadSpec desiredLoadSpec, DomainFile df) { + String fileLangId = df.getMetadata().getOrDefault("Language ID", ""); + String desiredLangId = + desiredLoadSpec.getLanguageCompilerSpec().getLanguageID().getIdAsString(); + + String[] fileParts = fileLangId.split(":"); + String[] desiredParts = desiredLangId.split(":"); + + return fileParts.length >= 3 && desiredParts.length >= 3 && + Arrays.equals(fileParts, 0, 3, desiredParts, 0, 3); + } + /** * Looks in the given {@link GFileSystem} for the given library using the loader's * {@link #getLibraryNameComparator() library name comparator} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java index e0dd3974da..24bf75734b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java @@ -627,7 +627,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader { if (lib == null) { for (DomainFolder searchFolder : searchFolders) { DomainFile df = - findLibraryInProject(path, searchFolder, searchPaths, settings); + findLibraryInProject(path, searchFolder, searchPaths, true, settings); if (df != null) { DomainObject obj = df.getDomainObject(this, true, true, monitor); if (obj instanceof Program p) {