GP-5848: Enforce architecture matching when loading libraries from

project
This commit is contained in:
Ryan Kurtz
2025-10-01 06:59:39 -04:00
parent 79c5490042
commit 7c98b5cd52
2 changed files with 76 additions and 36 deletions

View File

@@ -38,7 +38,6 @@ import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Library; import ghidra.program.model.listing.Library;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.ExternalManager; import ghidra.program.model.symbol.ExternalManager;
import ghidra.util.Msg;
import ghidra.util.StringUtilities; import ghidra.util.StringUtilities;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException; import ghidra.util.exception.InvalidInputException;
@@ -632,12 +631,12 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
continue; continue;
} }
processed.add(library); processed.add(library);
if (findLibraryInProject(library, libraryDestFolder, searchPaths, if (findLibraryInProject(library, libraryDestFolder, searchPaths, true,
settings) != null) { settings) != null) {
log.appendMsg("Found %s in %s...".formatted(library, libraryDestFolder)); log.appendMsg("Found %s in %s...".formatted(library, libraryDestFolder));
log.appendMsg("------------------------------------------------\n"); log.appendMsg("------------------------------------------------\n");
} }
else if (findLibraryInProject(library, linkSearchFolder, searchPaths, else if (findLibraryInProject(library, linkSearchFolder, searchPaths, true,
settings) != null) { settings) != null) {
log.appendMsg("Found %s in %s...".formatted(library, linkSearchFolder)); log.appendMsg("Found %s in %s...".formatted(library, linkSearchFolder));
log.appendMsg("------------------------------------------------\n"); log.appendMsg("------------------------------------------------\n");
@@ -779,12 +778,14 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
* @param folder {@link DomainFolder root folder} within which imported libraries will * @param folder {@link DomainFolder root folder} within which imported libraries will
* be searched. If null this method will return null. * be searched. If null this method will return null.
* @param searchPaths A {@link List} of {@link LibrarySearchPath}s that will be searched * @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} * @param settings The {@link Loader.ImporterSettings}
* @return The found {@link DomainFile} or null if not found * @return The found {@link DomainFile} or null if not found
* @throws CancelledException if the user cancelled the load * @throws CancelledException if the user cancelled the load
*/ */
protected DomainFile findLibraryInProject(String library, DomainFolder folder, protected DomainFile findLibraryInProject(String library, DomainFolder folder,
List<LibrarySearchPath> searchPaths, ImporterSettings settings) List<LibrarySearchPath> searchPaths, boolean matchLoadSpec, ImporterSettings settings)
throws CancelledException { throws CancelledException {
if (folder == null) { if (folder == null) {
return null; return null;
@@ -809,7 +810,8 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
} }
DomainFile ret = DomainFile ret =
lookupLibraryInFolder(FilenameUtils.getName(library), parentFolder); lookupLibraryInFolder(FilenameUtils.getName(library), parentFolder);
if (ret != null) { if (ret != null &&
(!matchLoadSpec || matchSupportedLoadSpec(settings.loadSpec(), ret))) {
return 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); String libraryName = FilenameUtils.getName(library);
DomainFile file = folder.getFile(libraryName); DomainFile file = folder.getFile(libraryName);
if (file != null) { 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; continue;
} }
monitor.checkCancelled(); monitor.checkCancelled();
try { Loaded<Program> match = findLibraryInLoadedList(loadedPrograms, externalLibName);
Loaded<Program> match = findLibraryInLoadedList(loadedPrograms, externalLibName); if (match != null) {
if (match != null) { setExternalLibrary(externalLibName,
extManager.setExternalPath(externalLibName, FSUtilities FSUtilities.appendPath(match.getProjectFolderPath(), match.getName()), program,
.appendPath(match.getProjectFolderPath(), match.getName()), settings);
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");
}
}
} }
catch (InvalidInputException e) { else {
Msg.error(this, "Bad library name: " + externalLibName, e); 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"); 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 * A library that has not been processed by the loader yet
* *
@@ -1175,6 +1193,28 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
return null; return null;
} }
/**
* {@return whether or not the given {@link LoadSpec} matches the one associated with the given
* {@link DomainFile}}
* <p>
* 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 * Looks in the given {@link GFileSystem} for the given library using the loader's
* {@link #getLibraryNameComparator() library name comparator} * {@link #getLibraryNameComparator() library name comparator}

View File

@@ -627,7 +627,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
if (lib == null) { if (lib == null) {
for (DomainFolder searchFolder : searchFolders) { for (DomainFolder searchFolder : searchFolders) {
DomainFile df = DomainFile df =
findLibraryInProject(path, searchFolder, searchPaths, settings); findLibraryInProject(path, searchFolder, searchPaths, true, settings);
if (df != null) { if (df != null) {
DomainObject obj = df.getDomainObject(this, true, true, monitor); DomainObject obj = df.getDomainObject(this, true, true, monitor);
if (obj instanceof Program p) { if (obj instanceof Program p) {