mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 05:10:16 +00:00
Merge remote-tracking branch
'origin/GP-2277_ryanmkurtz_lib-fs--SQUASHED' (Closes #4162)
This commit is contained in:
commit
e4e6a28caf
@ -24,8 +24,6 @@ import ghidra.framework.Platform;
|
||||
* and avoiding duplicate directories.
|
||||
*/
|
||||
public class LibrarySearchPathManager {
|
||||
public final static String CURRENT_DIRECTORY = ".";
|
||||
|
||||
private static List<String> pathList = createPathList();
|
||||
|
||||
private static boolean hasBeenRestored;
|
||||
@ -37,8 +35,6 @@ public class LibrarySearchPathManager {
|
||||
}
|
||||
|
||||
private static void loadJavaLibraryPath() {
|
||||
addPath(CURRENT_DIRECTORY);//add current directory
|
||||
|
||||
List<String> paths = Platform.CURRENT_PLATFORM.getAdditionalLibraryPaths();
|
||||
for (String path : paths) {
|
||||
addPath(path);
|
||||
@ -79,7 +75,6 @@ public class LibrarySearchPathManager {
|
||||
public static void setLibraryPaths(String[] paths) {
|
||||
|
||||
pathList.clear();
|
||||
addPath(CURRENT_DIRECTORY);//add current directory
|
||||
for (String path : paths) {
|
||||
addPath(path);
|
||||
}
|
||||
@ -120,6 +115,7 @@ public class LibrarySearchPathManager {
|
||||
|
||||
/**
|
||||
* Adds the path at the specified index in path search list.
|
||||
* @param index The index
|
||||
* @param path the path to add
|
||||
* @return true if the path was appended, false if the path was a duplicate
|
||||
*/
|
||||
@ -137,9 +133,6 @@ public class LibrarySearchPathManager {
|
||||
* @return true if the path was removed, false if the path did not exist
|
||||
*/
|
||||
public static boolean removePath(String path) {
|
||||
if (path.equals(CURRENT_DIRECTORY)) {
|
||||
return false;
|
||||
}
|
||||
return pathList.remove(path);
|
||||
}
|
||||
|
||||
|
@ -15,22 +15,21 @@
|
||||
*/
|
||||
package ghidra.app.util.opinion;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.AccessMode;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.OptionUtils;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.FileByteProvider;
|
||||
import ghidra.app.util.importer.LibrarySearchPathManager;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.formats.gfilesystem.FSRL;
|
||||
import ghidra.formats.gfilesystem.FileSystemService;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.*;
|
||||
@ -41,7 +40,6 @@ import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
/**
|
||||
* An abstract {@link Loader} that provides a framework to conveniently load {@link Program}s with
|
||||
@ -389,19 +387,20 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ByteProvider} for the given library file
|
||||
* Creates a {@link ByteProvider} for the given library {@link FSRL}
|
||||
*
|
||||
* @param libFile The library file to get a {@link ByteProvider} for
|
||||
* @param libFsrl The library {@link FSRL} to get a {@link ByteProvider} for
|
||||
* @param loadSpec An optional {@link LoadSpec} the {@link ByteProvider} should conform to
|
||||
* @param log The log
|
||||
* @return A {@link ByteProvider} for the given library file, or null if one could not be
|
||||
* created that matches the given {@link LoadSpec}
|
||||
* @param monitor A cancellable monitor
|
||||
* @return A {@link ByteProvider} for the given library {@link FSRL}, or null if one could not
|
||||
* be created that matches the given {@link LoadSpec}
|
||||
* @throws IOException If there was an IO-related issue
|
||||
* @throws CancelledException If the user cancelled the operation
|
||||
*/
|
||||
protected ByteProvider createLibraryByteProvider(File libFile, LoadSpec loadSpec,
|
||||
MessageLog log) throws IOException {
|
||||
return new FileByteProvider(libFile, FileSystemService.getInstance().getLocalFSRL(libFile),
|
||||
AccessMode.READ);
|
||||
protected ByteProvider createLibraryByteProvider(FSRL libFsrl, LoadSpec loadSpec,
|
||||
MessageLog log, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
return FileSystemService.getInstance().getByteProvider(libFsrl, true, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -410,17 +409,17 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
* It may be appropriate to not load a specific library after examining its bytes.
|
||||
*
|
||||
* @param libraryName The name of the library
|
||||
* @param libraryFile The library {@link File}
|
||||
* @param libraryFsrl The library {@link FSRL}
|
||||
* @param provider The library bytes
|
||||
* @param desiredLoadSpec The desired {@link LoadSpec}
|
||||
* @param log The log
|
||||
* @return True if the given library should be loaded; otherwise, false
|
||||
* @throws IOException If an IO-related error occurred
|
||||
*/
|
||||
protected boolean shouldLoadLibrary(String libraryName, File libraryFile, ByteProvider provider,
|
||||
LoadSpec desiredLoadSpec, MessageLog log) throws IOException {
|
||||
protected boolean shouldLoadLibrary(String libraryName, FSRL libraryFsrl,
|
||||
ByteProvider provider, LoadSpec desiredLoadSpec, MessageLog log) throws IOException {
|
||||
if (matchSupportedLoadSpec(desiredLoadSpec, provider) == null) {
|
||||
log.appendMsg("Skipping library which is the wrong architecture: " + libraryFile);
|
||||
log.appendMsg("Skipping library which is the wrong architecture: " + libraryFsrl);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -431,7 +430,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
*
|
||||
* @param library The loaded library {@link Program}
|
||||
* @param libraryName The name of the library
|
||||
* @param libraryFile The library {@link File}
|
||||
* @param libraryFsrl The library {@link FSRL}
|
||||
* @param provider The library bytes
|
||||
* @param loadSpec The {@link LoadSpec} used for the load
|
||||
* @param options The options
|
||||
@ -440,7 +439,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
* @throws IOException If an IO-related error occurred
|
||||
* @throws CancelledException If the user cancelled the action
|
||||
*/
|
||||
protected void processLibrary(Program library, String libraryName, File libraryFile,
|
||||
protected void processLibrary(Program library, String libraryName, FSRL libraryFsrl,
|
||||
ByteProvider provider, LoadSpec loadSpec, List<Option> options, MessageLog log,
|
||||
TaskMonitor monitor) throws IOException, CancelledException {
|
||||
// Default behavior is to do nothing
|
||||
@ -475,8 +474,10 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
createUnprocessedQueue(libraryNameList, getLibraryLoadDepth(options));
|
||||
boolean loadLocalLibraries = isLoadLocalLibraries(options);
|
||||
boolean loadSystemLibraries = isLoadSystemLibraries(options);
|
||||
List<String> localSearchPaths = getLocalLibrarySearchPaths(provider, options);
|
||||
List<String> systemSearchPaths = getSystemLibrarySearchPaths(provider, options);
|
||||
List<FileSystemSearchPath> localSearchPaths =
|
||||
getLocalLibrarySearchPaths(provider, options, log, monitor);
|
||||
List<FileSystemSearchPath> systemSearchPaths =
|
||||
getSystemLibrarySearchPaths(options, log, monitor);
|
||||
DomainFolder linkSearchFolder = getLinkSearchFolder(project, projectFolderPath, options);
|
||||
String libraryDestFolderPath =
|
||||
getLibraryDestinationFolderPath(project, projectFolderPath, options);
|
||||
@ -544,6 +545,16 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
if (!success) {
|
||||
release(loadedPrograms, consumer);
|
||||
}
|
||||
for (FileSystemSearchPath fsSearchPath : localSearchPaths) {
|
||||
if (!fsSearchPath.fsRef().isClosed()) {
|
||||
fsSearchPath.fsRef().close();
|
||||
}
|
||||
}
|
||||
for (FileSystemSearchPath fsSearchPath : systemSearchPaths) {
|
||||
if (!fsSearchPath.fsRef().isClosed()) {
|
||||
fsSearchPath.fsRef().close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -553,7 +564,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
*
|
||||
* @param libraryName The name of the library to load
|
||||
* @param provider The {@link ByteProvider} of the program being loaded
|
||||
* @param searchPaths The {@link List} of search paths
|
||||
* @param fsSearchPaths A {@link List} of {@link FileSystemSearchPath}s that will be searched
|
||||
* @param libraryDestFolderPath The path of the project folder to load the libraries into.
|
||||
* Could be null if the specified project is null or a destination folder path could not be
|
||||
* determined.
|
||||
@ -570,22 +581,22 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
* @throws CancelledException if the user cancelled the load
|
||||
*/
|
||||
private Loaded<Program> loadLibraryFromSearchPaths(String libraryName,
|
||||
ByteProvider provider, List<String> searchPaths, String libraryDestFolderPath,
|
||||
Queue<UnprocessedLibrary> unprocessed, int depth, LoadSpec desiredLoadSpec,
|
||||
List<Option> options, MessageLog log, Object consumer, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
ByteProvider provider, List<FileSystemSearchPath> fsSearchPaths,
|
||||
String libraryDestFolderPath, Queue<UnprocessedLibrary> unprocessed, int depth,
|
||||
LoadSpec desiredLoadSpec, List<Option> options, MessageLog log, Object consumer,
|
||||
TaskMonitor monitor) throws CancelledException, IOException {
|
||||
|
||||
Program library = null;
|
||||
String simpleLibraryName = FilenameUtils.getName(libraryName);
|
||||
List<File> candidateLibraryFiles =
|
||||
findLibrary(FilenameUtils.separatorsToUnix(libraryName), searchPaths);
|
||||
List<FSRL> candidateLibraryFsrls =
|
||||
findLibrary(Path.of(libraryName), fsSearchPaths, log, monitor);
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
for (File candidateLibraryFile : candidateLibraryFiles) {
|
||||
for (FSRL candidateLibraryFsrl : candidateLibraryFsrls) {
|
||||
monitor.checkCancelled();
|
||||
List<String> newLibraryList = new ArrayList<>();
|
||||
library = loadLibrary(simpleLibraryName, candidateLibraryFile,
|
||||
library = loadLibrary(simpleLibraryName, candidateLibraryFsrl,
|
||||
desiredLoadSpec, newLibraryList, options, consumer, log, monitor);
|
||||
for (String newLibraryName : newLibraryList) {
|
||||
unprocessed.add(new UnprocessedLibrary(newLibraryName, depth - 1));
|
||||
@ -593,8 +604,8 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
if (library == null) {
|
||||
continue;
|
||||
}
|
||||
log.appendMsg("Library " + libraryName + ": Examining " + candidateLibraryFile);
|
||||
processLibrary(library, libraryName, candidateLibraryFile, provider,
|
||||
log.appendMsg("Library " + libraryName + ": Examining " + candidateLibraryFsrl);
|
||||
processLibrary(library, libraryName, candidateLibraryFsrl, provider,
|
||||
desiredLoadSpec, options, log, monitor);
|
||||
success = true;
|
||||
return new Loaded<Program>(library, simpleLibraryName, libraryDestFolderPath);
|
||||
@ -667,7 +678,8 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the library on the filesystem, returning a {@link List} of possible candidate files.
|
||||
* Find the library in a {@link GFileSystem}, returning a {@link List} of possible candidate
|
||||
* {@link GFile files}.
|
||||
* <p>
|
||||
* Each search path directory will be searched for the library file in order.
|
||||
* <p>
|
||||
@ -678,50 +690,70 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
* If the library specifies an absolute path, its native path is searched on the local
|
||||
* filesystem.
|
||||
* <p>
|
||||
* @param libraryPath Either a path_and_filename, or just a filename of a library
|
||||
* that should be searched for
|
||||
* @param searchPaths A {@link List} of filesystem paths on the local filesystem that will be
|
||||
* searched
|
||||
* @return A {@link List} of files that match the requested library path
|
||||
* @param libraryPath The library {@link Path}. This will be either an absolute path, a
|
||||
* relative path, or just a filename.
|
||||
* @param fsSearchPaths A {@link List} of {@link FileSystemSearchPath}s that will be searched
|
||||
* @param log The log
|
||||
* @param monitor A cancelable task monitor
|
||||
* @return A {@link List} of {@link GFile files} that match the requested library path
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
private List<File> findLibrary(String libraryPath, List<String> searchPaths) {
|
||||
private List<FSRL> findLibrary(Path libraryPath, List<FileSystemSearchPath> fsSearchPaths,
|
||||
MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
List<FSRL> results = new ArrayList<>();
|
||||
FileSystemService fsService = FileSystemService.getInstance();
|
||||
|
||||
String libraryName = FilenameUtils.getName(libraryPath);
|
||||
List<File> results = new ArrayList<>();
|
||||
Path libraryParentPath = libraryPath.getParent();
|
||||
String libraryName = libraryPath.getFileName().toString();
|
||||
|
||||
for (String searchPath : searchPaths) {
|
||||
for (FileSystemSearchPath fsSearchPath : fsSearchPaths) {
|
||||
monitor.checkCancelled();
|
||||
|
||||
// ignore garbage entries: relative, non-existent, not directory
|
||||
searchPath = FilenameUtils.normalizeNoEndSeparator(searchPath);
|
||||
if (searchPath == null || searchPath.isEmpty()) {
|
||||
try {
|
||||
// Handle 3 different library-lookup cases:
|
||||
|
||||
// 1) libraryPath is library name, relative path, or absolute path from the root
|
||||
// of the searchPath. We need to join our fsSearchPath with our
|
||||
// libraryParentPath
|
||||
Path combinedParentPath =
|
||||
ObjectUtils.allNotNull(fsSearchPath.fsPath(), libraryParentPath)
|
||||
? fsSearchPath.fsPath().resolve(libraryParentPath)
|
||||
: ObjectUtils.firstNonNull(fsSearchPath.fsPath(), libraryParentPath);
|
||||
FSRL resolvedFsrl = resolveLibraryFile(fsSearchPath.fsRef().getFilesystem(),
|
||||
combinedParentPath, libraryName);
|
||||
if (resolvedFsrl != null) {
|
||||
results.add(resolvedFsrl);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2) libraryPath is an absolute path and should be looked up as-is on the
|
||||
// LocalFileSystem. Note that the root of the LocalFileSystem should not be
|
||||
// assumed to be in searchPaths for this case (otherwise case 1 would find it)
|
||||
if (libraryParentPath != null && libraryParentPath.isAbsolute()) {
|
||||
resolvedFsrl = resolveLibraryFile(fsService.getLocalFS(), libraryParentPath,
|
||||
libraryName);
|
||||
if (resolvedFsrl != null) {
|
||||
results.add(resolvedFsrl);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) libraryPath is some kind of path that we haven't found yet, so handle a
|
||||
// flat-directory structure by just appending filename part of the path to the
|
||||
// searchPath. Not sure if this case is still necessary but supporting for
|
||||
// legacy support.
|
||||
resolvedFsrl = resolveLibraryFile(fsSearchPath.fsRef().getFilesystem(),
|
||||
fsSearchPath.fsPath(), libraryName);
|
||||
if (resolvedFsrl != null) {
|
||||
results.add(resolvedFsrl);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendException(e);
|
||||
continue;
|
||||
}
|
||||
File searchDir = new File(searchPath);
|
||||
if (!searchDir.isAbsolute() || !searchDir.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1) Try as possible subpath under the search path
|
||||
String candidatePath =
|
||||
FilenameUtils.separatorsToSystem(concatenatePaths(searchPath, libraryPath));
|
||||
File f = resolveLibraryFile(new File(candidatePath));
|
||||
if (f == null || !f.isFile()) {
|
||||
// 2) Fall back to looking for the library in the user specified search path, sans
|
||||
// any subpath built into the library string
|
||||
f = resolveLibraryFile(new File(searchDir, libraryName));
|
||||
}
|
||||
if (f != null && f.isFile() && !results.contains(f)) {
|
||||
results.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (FilenameUtils.getPrefixLength(libraryPath) > 0) {
|
||||
// 3) Search the local filesystem (as if the importPath list contained "/")
|
||||
// if the specified library string specifies an absolute path
|
||||
File f = resolveLibraryFile(new File(libraryPath));
|
||||
if (f != null && f.isAbsolute() && f.isFile() && !results.contains(f)) {
|
||||
results.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
@ -732,7 +764,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
* a {@link ByteProvider} available.
|
||||
*
|
||||
* @param libraryName The name of the library to load
|
||||
* @param libraryFile The library file to load
|
||||
* @param libraryFsrl The library {@link FSRL} to load
|
||||
* @param desiredLoadSpec The desired {@link LoadSpec}
|
||||
* @param libraryNameList A {@link List} to be populated with the given library's dependent
|
||||
* library names
|
||||
@ -744,18 +776,19 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
* @throws CancelledException if the user cancelled the load operation
|
||||
* @throws IOException if there was an IO-related error during the load
|
||||
*/
|
||||
private Program loadLibrary(String libraryName, File libraryFile, LoadSpec desiredLoadSpec,
|
||||
private Program loadLibrary(String libraryName, FSRL libraryFsrl, LoadSpec desiredLoadSpec,
|
||||
List<String> libraryNameList, List<Option> options, Object consumer, MessageLog log,
|
||||
TaskMonitor monitor) throws CancelledException, IOException {
|
||||
|
||||
try (ByteProvider provider = createLibraryByteProvider(libraryFile, desiredLoadSpec, log)) {
|
||||
if (!shouldLoadLibrary(libraryName, libraryFile, provider, desiredLoadSpec, log)) {
|
||||
try (ByteProvider provider =
|
||||
createLibraryByteProvider(libraryFsrl, desiredLoadSpec, log, monitor)) {
|
||||
if (!shouldLoadLibrary(libraryName, libraryFsrl, provider, desiredLoadSpec, log)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LoadSpec libLoadSpec = matchSupportedLoadSpec(desiredLoadSpec, provider);
|
||||
if (libLoadSpec == null) {
|
||||
log.appendMsg("Skipping library which is the wrong architecture: " + libraryFile);
|
||||
log.appendMsg("Skipping library which is the wrong architecture: " + libraryFsrl);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -763,7 +796,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
consumer, log, monitor);
|
||||
|
||||
if (library == null) {
|
||||
log.appendMsg("Library " + libraryFile + " failed to load for some reason");
|
||||
log.appendMsg("Library " + libraryFsrl + " failed to load for some reason");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -972,36 +1005,81 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link List} of priority-ordered local paths used to search for libraries
|
||||
* A file system search path
|
||||
*
|
||||
* @param fsRef A {@link FileSystemRef}
|
||||
* @param fsPath A {@link Path} relative to the root of the file system, or null for the root
|
||||
*/
|
||||
private record FileSystemSearchPath(FileSystemRef fsRef, Path fsPath) {}
|
||||
|
||||
/**
|
||||
* Gets a {@link List} of priority-ordered local {@link FileSystemSearchPath}s used to search
|
||||
* for libraries
|
||||
*
|
||||
* @param provider The {@link ByteProvider} of the program being loaded
|
||||
* @param options The options
|
||||
* @return A {@link List} of priority-ordered local paths used to search for libraries
|
||||
* @param log The log
|
||||
* @param monitor A cancelable task monitor
|
||||
* @return A {@link List} of priority-ordered local {@link FileSystemSearchPath}s used to s
|
||||
* search for libraries
|
||||
*/
|
||||
private List<String> getLocalLibrarySearchPaths(ByteProvider provider, List<Option> options) {
|
||||
List<String> paths = new ArrayList<>();
|
||||
private List<FileSystemSearchPath> getLocalLibrarySearchPaths(ByteProvider provider,
|
||||
List<Option> options, MessageLog log, TaskMonitor monitor) {
|
||||
List<FileSystemSearchPath> result = new ArrayList<>();
|
||||
FileSystemService fsService = FileSystemService.getInstance();
|
||||
if (isLoadLocalLibraries(options) || shouldSearchAllPaths(options)) {
|
||||
String parent = getProviderFilePath(provider);
|
||||
if (parent != null) {
|
||||
paths.add(parent);
|
||||
FSRL providerFsrl = provider.getFSRL();
|
||||
if (providerFsrl != null) {
|
||||
try (RefdFile fileRef = fsService.getRefdFile(providerFsrl, monitor)) {
|
||||
GFile parentFile = fileRef.file.getParentFile();
|
||||
result.add(
|
||||
new FileSystemSearchPath(fileRef.fsRef, Path.of(parentFile.getPath())));
|
||||
}
|
||||
catch (IOException | CancelledException e) {
|
||||
log.appendException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link List} of priority-ordered system paths used to search for libraries
|
||||
* Gets a {@link List} of priority-ordered system {@link FileSystemSearchPath}s used to search
|
||||
* for libraries
|
||||
*
|
||||
* @param provider The {@link ByteProvider} of the program being loaded
|
||||
* @param options The options
|
||||
* @return A {@link List} of priority-ordered system paths used to search for libraries
|
||||
* @param log The log
|
||||
* @param monitor A cancelable task monitor
|
||||
* @return A {@link List} of priority-ordered system {@link FileSystemSearchPath}s used to
|
||||
* search for libraries
|
||||
*/
|
||||
private List<String> getSystemLibrarySearchPaths(ByteProvider provider, List<Option> options) {
|
||||
List<String> paths = new ArrayList<>();
|
||||
private List<FileSystemSearchPath> getSystemLibrarySearchPaths(List<Option> options,
|
||||
MessageLog log, TaskMonitor monitor) {
|
||||
List<FileSystemSearchPath> result = new ArrayList<>();
|
||||
FileSystemService fsService = FileSystemService.getInstance();
|
||||
if (isLoadSystemLibraries(options) || shouldSearchAllPaths(options)) {
|
||||
paths.addAll(LibrarySearchPathManager.getLibraryPathsList());
|
||||
List<Path> searchPaths = LibrarySearchPathManager.getLibraryPathsList()
|
||||
.stream()
|
||||
.map(s -> Path.of(s).normalize())
|
||||
.filter(Path::isAbsolute)
|
||||
.filter(Files::exists)
|
||||
.toList();
|
||||
|
||||
for (Path searchPath : searchPaths) {
|
||||
try {
|
||||
FSRL searchFSRL = fsService.getLocalFSRL(searchPath.toFile());
|
||||
FileSystemRef fsRef =
|
||||
fsService.probeFileForFilesystem(searchFSRL, monitor, null);
|
||||
if (fsRef != null) {
|
||||
result.add(new FileSystemSearchPath(fsRef, null));
|
||||
}
|
||||
}
|
||||
catch (IOException | CancelledException e) {
|
||||
log.appendException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1050,56 +1128,41 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given library path to an existing {@link File} on disk. Some {@link Loader}s
|
||||
* Resolves the given library path to an existing {@link FSRL}. Some {@link Loader}s
|
||||
* have relaxed requirements on what counts as a valid library filename match. For example,
|
||||
* case-insensitive lookup may be allowed, and filename extensions may be optional.
|
||||
*
|
||||
* @param libraryFile The library file to resolve
|
||||
* @return The library file resolved to an existing {@link File} on disk, or null if it did not
|
||||
* resolve
|
||||
* @param fs The {@link GFileSystem file system} to resolve in
|
||||
* @param libraryParentPath The {@link Path} of the libraries parent directory, relative to the
|
||||
* given file system (could be null)
|
||||
* @param libraryName The library name
|
||||
* @return The library resolved to an existing {@link FSRL}, or null if it did not resolve
|
||||
* @throws IOException If an IO-related problem occurred
|
||||
*/
|
||||
private File resolveLibraryFile(File libraryFile) {
|
||||
File ret = libraryFile;
|
||||
if (isCaseInsensitiveLibraryFilenames()) {
|
||||
ret = FileUtilities.resolveFileCaseInsensitive(libraryFile);
|
||||
}
|
||||
if (ret.exists()) {
|
||||
return ret;
|
||||
}
|
||||
if (isOptionalLibraryFilenameExtensions() &&
|
||||
FilenameUtils.getExtension(libraryFile.toString()).equals("")) {
|
||||
File[] files = libraryFile.getParentFile().listFiles();
|
||||
if (files != null) {
|
||||
Comparator<String> libNameComparator = getLibraryNameComparator();
|
||||
for (File file : files) {
|
||||
String baseName = FilenameUtils.getBaseName(file.toString());
|
||||
if (libNameComparator.compare(libraryFile.getName(), baseName) == 0) {
|
||||
return file;
|
||||
}
|
||||
protected FSRL resolveLibraryFile(GFileSystem fs, Path libraryParentPath, String libraryName)
|
||||
throws IOException {
|
||||
GFile libraryParentDir =
|
||||
fs.lookup(libraryParentPath != null ? libraryParentPath.toString() : null);
|
||||
boolean compareWithoutExtension = isOptionalLibraryFilenameExtensions() &&
|
||||
FilenameUtils.getExtension(libraryName).equals("");
|
||||
if (libraryParentDir != null) {
|
||||
Comparator<String> libNameComparator = getLibraryNameComparator();
|
||||
for (GFile file : fs.getListing(libraryParentDir)) {
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
String compareName = file.getName();
|
||||
if (compareWithoutExtension) {
|
||||
compareName = FilenameUtils.getBaseName(compareName);
|
||||
}
|
||||
if (libNameComparator.compare(libraryName, compareName) == 0) {
|
||||
return file.getFSRL();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path the loaded {@link ByteProvider} is located in.
|
||||
* <p>
|
||||
* Special case when the ByteProvider specifies a {@link FSRL}, try to get the 'real'
|
||||
* path on the local filesystem, otherwise return null.
|
||||
*
|
||||
* @param provider The {@link ByteProvider}.
|
||||
* @return The path the loaded {@link ByteProvider} is located in.
|
||||
*/
|
||||
private String getProviderFilePath(ByteProvider provider) {
|
||||
FSRL fsrl = provider.getFSRL();
|
||||
if ((fsrl != null) && !fsrl.getFS().hasContainer()) {
|
||||
return FilenameUtils.getFullPathNoEndSeparator(fsrl.getPath());
|
||||
}
|
||||
File f = provider.getFile();
|
||||
return (f != null) ? f.getParent() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link Comparator} for comparing library filenames
|
||||
*
|
||||
|
@ -24,6 +24,7 @@ import ghidra.app.util.Option;
|
||||
import ghidra.app.util.OptionUtils;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.options.Options;
|
||||
@ -75,17 +76,19 @@ public abstract class AbstractOrdinalSupportLoader extends AbstractLibrarySuppor
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldLoadLibrary(String libName, File libFile,
|
||||
ByteProvider provider, LoadSpec loadSpec, MessageLog log) throws IOException {
|
||||
protected boolean shouldLoadLibrary(String libName, FSRL libFsrl, ByteProvider provider,
|
||||
LoadSpec loadSpec, MessageLog log) throws IOException {
|
||||
|
||||
if (!super.shouldLoadLibrary(libName, libFile, provider, loadSpec, log)) {
|
||||
if (!super.shouldLoadLibrary(libName, libFsrl, provider, loadSpec, log)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int size = loadSpec.getLanguageCompilerSpec().getLanguageDescription().getSize();
|
||||
File localLibFile = getLocalFile(libFsrl);
|
||||
|
||||
if (!LibraryLookupTable.hasFileAndPathAndTimeStampMatch(libFile, size) &&
|
||||
LibraryLookupTable.libraryLookupTableFileExists(libName, size)) {
|
||||
if (localLibFile == null ||
|
||||
!LibraryLookupTable.hasFileAndPathAndTimeStampMatch(localLibFile, size) &&
|
||||
LibraryLookupTable.libraryLookupTableFileExists(libName, size)) {
|
||||
log.appendMsg("WARNING! Using existing exports file for " + libName +
|
||||
" which may not be an exact match");
|
||||
}
|
||||
@ -94,26 +97,46 @@ public abstract class AbstractOrdinalSupportLoader extends AbstractLibrarySuppor
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processLibrary(Program lib, String libName, File libFile,
|
||||
ByteProvider provider, LoadSpec loadSpec, List<Option> options, MessageLog log,
|
||||
TaskMonitor monitor) throws IOException, CancelledException {
|
||||
protected void processLibrary(Program lib, String libName, FSRL libFsrl, ByteProvider provider,
|
||||
LoadSpec loadSpec, List<Option> options, MessageLog log, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
int size = loadSpec.getLanguageCompilerSpec().getLanguageDescription().getSize();
|
||||
File localLibFile = getLocalFile(libFsrl);
|
||||
|
||||
// Create exports file
|
||||
if (!LibraryLookupTable.libraryLookupTableFileExists(libName, size) ||
|
||||
!LibraryLookupTable.hasFileAndPathAndTimeStampMatch(libFile, size)) {
|
||||
if (localLibFile == null ||
|
||||
!LibraryLookupTable.libraryLookupTableFileExists(libName, size) ||
|
||||
!LibraryLookupTable.hasFileAndPathAndTimeStampMatch(localLibFile, size)) {
|
||||
try {
|
||||
// Need to write correct library exports file (LibrarySymbolTable)
|
||||
// for use with related imports
|
||||
LibraryLookupTable.createFile(lib, true, monitor);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg("Unable to create exports file for " + libFile);
|
||||
Msg.error(this, "Unable to create exports file for " + libFile, e);
|
||||
log.appendMsg("Unable to create exports file for " + libFsrl);
|
||||
Msg.error(this, "Unable to create exports file for " + libFsrl, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given {@link FSRL} is from a {@link LocalFileSystem}, its corresponding local
|
||||
* {@link File} is returned
|
||||
*
|
||||
* @param fsrl A {@link FSRL}
|
||||
* @return The given {@link FSRL}'s corresponding local {@link File}, or null if it doesn't
|
||||
* have one
|
||||
*/
|
||||
private File getLocalFile(FSRL fsrl) {
|
||||
try {
|
||||
return FileSystemService.getInstance().getLocalFS().getLocalFile(fsrl);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// fall thru
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postLoadProgramFixups(List<Loaded<Program>> loadedPrograms, Project project,
|
||||
List<Option> options, MessageLog messageLog, TaskMonitor monitor)
|
||||
|
@ -44,8 +44,8 @@ public class LibraryPathsDialog extends DialogComponentProvider {
|
||||
tablePanel = new PathnameTablePanel(libraryPaths, false, true, () -> reset());
|
||||
// false=> not editable, true=> add new paths to top of the table
|
||||
|
||||
tablePanel.setFileChooserProperties("Select Directory", "LibrarySearchDirectory",
|
||||
GhidraFileChooserMode.DIRECTORIES_ONLY, false, null);
|
||||
tablePanel.setFileChooserProperties("Select Directory or Filesystem",
|
||||
"LibrarySearchDirectory", GhidraFileChooserMode.FILES_AND_DIRECTORIES, false, null);
|
||||
|
||||
return tablePanel;
|
||||
}
|
||||
|
@ -15,18 +15,18 @@
|
||||
*/
|
||||
package ghidra.app.util.opinion;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.AccessMode;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.MemoryBlockUtils;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.ByteProviderWrapper;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.app.util.bin.format.ubi.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.formats.gfilesystem.FileSystemService;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.LittleEndianDataConverter;
|
||||
@ -115,24 +115,22 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
||||
* found that is successful (meaning it matches the correct architecture). Only one file
|
||||
* in the UBI will ever be imported. If the provided file is NOT a UBI, default
|
||||
* import method will be invoked.
|
||||
* <hr>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected ByteProvider createLibraryByteProvider(File libFile, LoadSpec loadSpec, MessageLog log)
|
||||
throws IOException {
|
||||
protected ByteProvider createLibraryByteProvider(FSRL libFsrl, LoadSpec loadSpec,
|
||||
MessageLog log, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
|
||||
if (!libFile.isFile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteProvider provider = new FileByteProvider(libFile,
|
||||
FileSystemService.getInstance().getLocalFSRL(libFile), AccessMode.READ);
|
||||
ByteProvider provider = super.createLibraryByteProvider(libFsrl, loadSpec, log, monitor);
|
||||
|
||||
try {
|
||||
FatHeader header = new FatHeader(provider);
|
||||
List<FatArch> architectures = header.getArchitectures();
|
||||
|
||||
if (architectures.isEmpty()) {
|
||||
log.appendMsg("WARNING! No archives found in the UBI: " + libFile);
|
||||
log.appendMsg("WARNING! No archives found in the UBI: " + libFsrl);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -158,4 +156,45 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Special Mach-O library file resolver to account for a "Versions" subdirectory being inserted
|
||||
* in the library lookup path. For example, a reference to:
|
||||
* <p>
|
||||
* {@code /System/Library/Frameworks/Foundation.framework/Foundation}
|
||||
* <p>
|
||||
* might be found at:
|
||||
* <p>
|
||||
* {@code /System/Library/Frameworks/Foundation.framework//Versions/C/Foundation}
|
||||
* <hr>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected FSRL resolveLibraryFile(GFileSystem fs, Path libraryParentPath, String libraryName)
|
||||
throws IOException {
|
||||
GFile libraryParentDir =
|
||||
fs.lookup(libraryParentPath != null ? libraryParentPath.toString() : null);
|
||||
if (libraryParentDir != null) {
|
||||
for (GFile file : fs.getListing(libraryParentDir)) {
|
||||
if (file.isDirectory() && file.getName().equals("Versions")) {
|
||||
Path versionsPath = libraryParentPath.resolve(file.getName());
|
||||
List<GFile> versionListion = fs.getListing(file);
|
||||
if (!versionListion.isEmpty()) {
|
||||
GFile specificVersionDir = versionListion.get(0);
|
||||
if (specificVersionDir.isDirectory()) {
|
||||
return resolveLibraryFile(fs,
|
||||
versionsPath.resolve(specificVersionDir.getName()), libraryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
if (file.getName().equals(libraryName)) {
|
||||
return file.getFSRL();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1136,16 +1136,13 @@ public class MachoProgramBuilder {
|
||||
}
|
||||
|
||||
if (libraryPath != null) {
|
||||
// For now, strip off the full path and just the use the filename. We will utilize
|
||||
// the full path one day when we started looking in dyld_shared_cache files for
|
||||
// libraries.
|
||||
int index = libraryPath.lastIndexOf("/");
|
||||
String libraryName = index != -1 ? libraryPath.substring(index + 1) : libraryPath;
|
||||
if (!libraryName.equals(program.getName())) {
|
||||
addLibrary(libraryName);
|
||||
addLibrary(libraryPath);
|
||||
props.setString(
|
||||
ExternalSymbolResolver.getRequiredLibraryProperty(libraryIndex++),
|
||||
libraryName);
|
||||
libraryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,8 @@
|
||||
*/
|
||||
package ghidra.formats.gfilesystem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.formats.gfilesystem.FileCache.FileCacheEntry;
|
||||
@ -211,11 +210,11 @@ public class FileSystemService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a direct reference to a filesystem that represents the local filesystem.
|
||||
* Returns a direct reference to the {@link LocalFileSystem local filesystem}.
|
||||
*
|
||||
* @return {@link GFileSystem} that represents the local filesystem.
|
||||
* @return A direct reference to the {@link LocalFileSystem local filesystem}.
|
||||
*/
|
||||
public GFileSystem getLocalFS() {
|
||||
public LocalFileSystem getLocalFS() {
|
||||
return localFS;
|
||||
}
|
||||
|
||||
|
@ -67,9 +67,9 @@ public class ExternalSymbolResolver {
|
||||
public static void fixUnresolvedExternalSymbols(List<Loaded<Program>> loadedPrograms,
|
||||
boolean fixAll, MessageLog messageLog, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
Map<String, Loaded<Program>> loadedByName = loadedPrograms.stream()
|
||||
.collect(
|
||||
Collectors.toMap(loaded -> loaded.getName(), loaded -> loaded));
|
||||
Map<String, Loaded<Program>> loadedByPath = loadedPrograms.stream()
|
||||
.collect(Collectors.toMap(
|
||||
loaded -> loaded.getProjectFolderPath() + loaded.getName(), loaded -> loaded));
|
||||
|
||||
List<Loaded<Program>> fixupList =
|
||||
loadedPrograms.subList(0, fixAll ? loadedPrograms.size() : 1);
|
||||
@ -101,8 +101,8 @@ public class ExternalSymbolResolver {
|
||||
if (libPath == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Loaded<Program> loadedLib = loadedByName.get(libName);
|
||||
|
||||
Loaded<Program> loadedLib = loadedByPath.get(libPath);
|
||||
if (loadedLib == null) {
|
||||
messageLog.appendMsg("Referenced external program not found: " + libName);
|
||||
continue;
|
||||
|
@ -210,6 +210,11 @@ public enum Platform {
|
||||
paths.add("/usr/X11R6/bin");
|
||||
paths.add("/usr/X11R6/lib");
|
||||
}
|
||||
else if (operatingSystem == OperatingSystem.MAC_OS_X) {
|
||||
paths.add("/System/Library/dyld/dyld_shared_cache_arm64e");
|
||||
paths.add(
|
||||
"/System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e");
|
||||
}
|
||||
else if (CURRENT_PLATFORM == WIN_X86_64) {
|
||||
String windir = System.getenv("SystemRoot");
|
||||
if (windir != null) {
|
||||
|
Loading…
Reference in New Issue
Block a user