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.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<LibrarySearchPath> searchPaths, ImporterSettings settings)
List<LibrarySearchPath> 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<Program> 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<Program> 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}}
* <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
* {@link #getLibraryNameComparator() library name comparator}

View File

@@ -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) {