Merge remote-tracking branch

'origin/GP-6073-dragonmacher-fid-plugin-delayed-loading-12.0' into
Ghidra_12.0 (Closes #8593)
This commit is contained in:
Ryan Kurtz
2025-10-28 12:12:51 -04:00
3 changed files with 105 additions and 31 deletions

View File

@@ -114,19 +114,25 @@ public class FidAnalyzer extends AbstractAnalyzer {
@Override @Override
public boolean getDefaultEnablement(Program program) { public boolean getDefaultEnablement(Program program) {
return service.canProcess(program.getLanguage()); // Loading Fid db files can be slow. For now, signal that we can analyze and check later.
return true;
//return service.canProcess(program.getLanguage());
} }
@Override @Override
public boolean canAnalyze(Program program) { public boolean canAnalyze(Program program) {
return service.canProcess(program.getLanguage()); // Loading Fid db files can be slow. For now, signal that we can analyze and check later.
return true;
//return service.canProcess(program.getLanguage());
} }
@Override @Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException { throws CancelledException {
if (!service.canProcess(program.getLanguage())) { if (!service.canProcess(program.getLanguage())) {
Msg.warn(this, "No FID Libraries apply for language " + program.getLanguageID()); // This can now happen, since we no longer check in canAnalyze()
Msg.debug(this, "No FID Libraries apply for language " + program.getLanguageID());
return false; return false;
} }

View File

@@ -27,14 +27,18 @@ import generic.util.Path;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.framework.preferences.Preferences; import ghidra.framework.preferences.Preferences;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.util.Msg;
import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet; import ghidra.util.datastruct.WeakSet;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskLauncher;
import ghidra.util.task.TaskMonitor;
/** /**
* Manages the set of FidFiles for the application. This uses the singleton pattern and * Manages the set of FidFiles for the application. This uses the singleton pattern and
* all users of Fid databases must use this to get open Fid databases. This ensures that * all users of Fid databases must use this to get open Fid databases. This ensures that
* there is only one updateable Fid database open for any given FidFile. * there is only one updatable Fid database open for any given FidFile.
*/ */
public class FidFileManager { public class FidFileManager {
@@ -48,7 +52,7 @@ public class FidFileManager {
private WeakSet<ChangeListener> listeners; private WeakSet<ChangeListener> listeners;
/** /**
* Returns the singleton instance of the FidFileManager. * {@return the singleton instance of the FidFileManager.}
*/ */
public static FidFileManager getInstance() { public static FidFileManager getInstance() {
if (THE_FID_FILE_MANAGER == null) { if (THE_FID_FILE_MANAGER == null) {
@@ -59,14 +63,23 @@ public class FidFileManager {
private FidFileManager() { private FidFileManager() {
listeners = WeakDataStructureFactory.createCopyOnWriteWeakSet(); listeners = WeakDataStructureFactory.createCopyOnWriteWeakSet();
// findDeliveredFidFiles(); - too slow
// restoreFromPreferences();
} }
private Set<FidFile> loadFidFiles() { private Set<FidFile> loadFidFiles() {
if (fidFiles == null) { if (fidFiles == null) {
findDeliveredFidFiles();
restoreFromPreferences(); TaskLauncher.launchModal("Loading Fid Files", monitor -> {
fidFiles = new CopyOnWriteArraySet<>();
try {
findDeliveredFidFiles(monitor);
restoreFromPreferences(monitor);
}
catch (CancelledException ce) {
Msg.showWarn(this, null, "Fid Loading Cancelled", "User cancelled Fid Db " +
"loading. To load all Fid Db files, the tool must be restarted.");
}
});
} }
return fidFiles; return fidFiles;
@@ -74,7 +87,7 @@ public class FidFileManager {
/** /**
* Add user FidDb file * Add user FidDb file
* @param file * @param file the file
* @return FidFile or null if invalid * @return FidFile or null if invalid
*/ */
public FidFile addUserFidFile(File file) { public FidFile addUserFidFile(File file) {
@@ -105,7 +118,7 @@ public class FidFileManager {
} }
/** /**
* Returns a list of all the FidFiles know to the application. * {@return a list of all the FidFiles know to the application.}
*/ */
public List<FidFile> getFidFiles() { public List<FidFile> getFidFiles() {
loadFidFiles(); loadFidFiles();
@@ -114,13 +127,30 @@ public class FidFileManager {
return files; return files;
} }
public boolean hasFidFiles() { /**
loadFidFiles(); * Triggers a load of the Fid db files, if not already loaded.
return !fidFiles.isEmpty(); */
public void load() {
if (fidFiles == null) {
loadFidFiles();
}
} }
/**
* {@return true if Fid db files have been loaded and files have been found.}
*/
public boolean hasFidFiles() {
return fidFiles != null && !fidFiles.isEmpty();
}
/**
* {@return true if Fid db files have been loaded and user Fid files have been found.}
*/
public boolean hasUserFidFiles() { public boolean hasUserFidFiles() {
loadFidFiles(); if (fidFiles == null) {
return false;
}
for (FidFile fidFile : fidFiles) { for (FidFile fidFile : fidFiles) {
if (!fidFile.isInstalled()) { if (!fidFile.isInstalled()) {
return true; return true;
@@ -130,8 +160,15 @@ public class FidFileManager {
} }
/** /**
* Returns a list of all the user added (non installation) Fid files. This will * {@return true if the Fid db files have been loaded.}
* be files containing packed databases. */
public boolean hasLoadedFidFiles() {
return fidFiles != null;
}
/**
* {@return a list of all the user added (non installation) Fid files. This will
* be files containing packed databases.}
*/ */
public List<FidFile> getUserAddedFiles() { public List<FidFile> getUserAddedFiles() {
loadFidFiles(); loadFidFiles();
@@ -251,17 +288,20 @@ public class FidFileManager {
return list; return list;
} }
private void restoreFromPreferences() { private void restoreFromPreferences(TaskMonitor monitor) throws CancelledException {
Set<File> userAddedFiles = getFilesFromPreference(USER_ADDED_FILES); Set<File> userAddedFiles = getFilesFromPreference(USER_ADDED_FILES);
addUserFidFiles(userAddedFiles); monitor.initialize(userAddedFiles.size(), "Adding user Fid files...");
doAddUserFidFiles(userAddedFiles, monitor);
Set<File> excludedFiles = getFilesFromPreference(INACTIVE_FID_FILES); Set<File> excludedFiles = getFilesFromPreference(INACTIVE_FID_FILES);
excludeFidFiles(excludedFiles); monitor.initialize(excludedFiles.size(), "Removing inactive user Fid files...");
doExcludeFidFiles(excludedFiles, monitor);
} }
private void addUserFidFiles(Set<File> userAddedFiles) { private void doAddUserFidFiles(Set<File> userAddedFiles, TaskMonitor monitor)
loadFidFiles(); throws CancelledException {
for (File file : userAddedFiles) { for (File file : userAddedFiles) {
monitor.increment();
FidFile fidFile = new FidFile(this, file, false); FidFile fidFile = new FidFile(this, file, false);
if (fidFile.isValidFile()) { if (fidFile.isValidFile()) {
fidFiles.add(fidFile); fidFiles.add(fidFile);
@@ -269,9 +309,10 @@ public class FidFileManager {
} }
} }
private void excludeFidFiles(Set<File> excludedFiles) { private void doExcludeFidFiles(Set<File> excludedFiles, TaskMonitor monitor)
loadFidFiles(); throws CancelledException {
for (FidFile fidFile : fidFiles) { for (FidFile fidFile : fidFiles) {
monitor.increment();
if (excludedFiles.contains(fidFile.getFile())) { if (excludedFiles.contains(fidFile.getFile())) {
fidFile.setActive(false); fidFile.setActive(false);
} }
@@ -296,11 +337,14 @@ public class FidFileManager {
return set; return set;
} }
private void findDeliveredFidFiles() { private void findDeliveredFidFiles(TaskMonitor monitor) throws CancelledException {
fidFiles = new CopyOnWriteArraySet<>();
List<ResourceFile> foundFiles = List<ResourceFile> foundFiles =
Application.findFilesByExtensionInApplication(FidFile.FID_RAW_DATABASE_FILE_EXTENSION); Application.findFilesByExtensionInApplication(FidFile.FID_RAW_DATABASE_FILE_EXTENSION);
monitor.initialize(foundFiles.size(), "Processing included Fid files...");
for (ResourceFile resourceFile : foundFiles) { for (ResourceFile resourceFile : foundFiles) {
monitor.increment();
File file = resourceFile.getFile(true); File file = resourceFile.getFile(true);
FidFile fidFile = new FidFile(this, file, true); FidFile fidFile = new FidFile(this, file, true);
if (fidFile.isValidFile()) { if (fidFile.isValidFile()) {

View File

@@ -94,7 +94,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
*/ */
private void createStandardActions() { private void createStandardActions() {
new ActionBuilder("Choose Active FidDbs", getName()) new ActionBuilder("Choose Active FidDbs", getName())
.enabledWhen(ac -> fidFileManager.hasFidFiles()) .enabledWhen(ac -> enabledForAnyFidFiles())
.onAction(ac -> chooseActiveFidDbs()) .onAction(ac -> chooseActiveFidDbs())
.menuPath(ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Choose active FidDbs...") .menuPath(ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Choose active FidDbs...")
.menuGroup(MENU_GROUP_1, "1") .menuGroup(MENU_GROUP_1, "1")
@@ -121,7 +121,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
.buildAndInstall(tool); .buildAndInstall(tool);
new ActionBuilder("Detach attached FidDb", getName()) new ActionBuilder("Detach attached FidDb", getName())
.enabledWhen(ac -> fidFileManager.hasUserFidFiles()) .enabledWhen(ac -> enabledForUserFidFiles())
.onAction(ac -> removeFidFile()) .onAction(ac -> removeFidFile())
.menuPath(ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Detach attached FidDb...") .menuPath(ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Detach attached FidDb...")
.menuGroup(MENU_GROUP_1, "4") .menuGroup(MENU_GROUP_1, "4")
@@ -130,8 +130,9 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
.buildAndInstall(tool); .buildAndInstall(tool);
new ActionBuilder("Populate FidDb from programs", getName()) new ActionBuilder("Populate FidDb from programs", getName())
.enabledWhen(ac -> fidFileManager.hasUserFidFiles()) .enabledWhen(ac -> enabledForUserFidFiles())
.onAction(ac -> { .onAction(ac -> {
fidFileManager.load();
PopulateFidDialog populateFidDialog = new PopulateFidDialog(tool, service); PopulateFidDialog populateFidDialog = new PopulateFidDialog(tool, service);
tool.showDialog(populateFidDialog); tool.showDialog(populateFidDialog);
}) })
@@ -143,11 +144,30 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
.buildAndInstall(tool); .buildAndInstall(tool);
} }
private boolean enabledForAnyFidFiles() {
if (!fidFileManager.hasLoadedFidFiles()) {
// We haven't loaded Fid files yet. Since we don't know if we can enable, return true
// so users can at least try to perform the action.
return true;
}
return fidFileManager.hasFidFiles();
}
private boolean enabledForUserFidFiles() {
if (!fidFileManager.hasLoadedFidFiles()) {
// We haven't loaded Fid files yet. Since we don't know if we can enable, return true
// so users can at least try to perform the action.
return true;
}
return fidFileManager.hasUserFidFiles();
}
/** /**
* Method to select which known FID databases are currently active * Method to select which known FID databases are currently active
* during search. * during search.
*/ */
private synchronized void chooseActiveFidDbs() { private synchronized void chooseActiveFidDbs() {
fidFileManager.load();
ActiveFidConfigureDialog dialog = ActiveFidConfigureDialog dialog =
new ActiveFidConfigureDialog(fidFileManager.getFidFiles()); new ActiveFidConfigureDialog(fidFileManager.getFidFiles());
tool.showDialog(dialog); tool.showDialog(dialog);
@@ -159,6 +179,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
* extension (.fidb). If they don't, we will add it for them. * extension (.fidb). If they don't, we will add it for them.
*/ */
private void createFidDb() { private void createFidDb() {
fidFileManager.load();
File dbFile = askFile("Create new FidDb file", "Create"); File dbFile = askFile("Create new FidDb file", "Create");
if (dbFile == null) { if (dbFile == null) {
return; return;
@@ -186,6 +207,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
* Method to attach an already-created (but heretofore unknown) database. * Method to attach an already-created (but heretofore unknown) database.
*/ */
private void attachFidDb() { private void attachFidDb() {
fidFileManager.load();
File dbFile = askFile("Attach existing FidDb file", "Attach"); File dbFile = askFile("Attach existing FidDb file", "Attach");
if (dbFile != null) { if (dbFile != null) {
fidFileManager.addUserFidFile(dbFile); fidFileManager.addUserFidFile(dbFile);
@@ -196,6 +218,8 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
* Method to "forget" about (close and stop trying to re-open next session) a FID database. * Method to "forget" about (close and stop trying to re-open next session) a FID database.
*/ */
private void removeFidFile() { private void removeFidFile() {
fidFileManager.load();
FidFile fidFile = askChoice("Choose FidDb to detach", "Please choose the FidDb to detach", FidFile fidFile = askChoice("Choose FidDb to detach", "Please choose the FidDb to detach",
fidFileManager.getUserAddedFiles(), null); fidFileManager.getUserAddedFiles(), null);
if (fidFile != null) { if (fidFile != null) {