Merge remote-tracking branch 'origin/GT-3376_ryanmkurtz_AutoImporter'

(Fixes #1311)
This commit is contained in:
ghidorahrex 2020-01-10 11:48:55 -05:00
commit decb362234
13 changed files with 224 additions and 372 deletions

View file

@ -17,7 +17,8 @@ package ghidra.app.util.importer;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import generic.stl.Pair;
@ -202,61 +203,17 @@ public final class AutoImporter {
private static LoadSpec getLoadSpec(Predicate<Loader> loaderFilter,
LoadSpecChooser loadSpecChooser, ByteProvider provider) {
Map<Loader, Collection<LoadSpec>> loadMap =
LoaderService.getSupportedLoadSpecs(provider, loaderFilter);
LoaderMap loaderMap = LoaderService.getSupportedLoadSpecs(provider, loaderFilter);
List<LoadSpec> allLoadSpecs = new ArrayList<>();
for (Collection<LoadSpec> loadSpecs : loadMap.values()) {
allLoadSpecs.addAll(loadSpecs);
LoadSpec loadSpec = loadSpecChooser.choose(loaderMap);
if (loadSpec != null) {
return loadSpec;
}
// "count" up our preferred (we really only care about 0, 1, and >1)
int preferredCount = 0;
LoadSpec preferred = null;
for (LoadSpec op : allLoadSpecs) {
if (op.isPreferred()) {
if (preferred == null) {
preferred = op;
preferredCount = 1;
continue;
}
preferredCount = 2;
break;
}
}
// if we had just one load spec, we forcefully consider it preferred
if (allLoadSpecs.size() == 1) {
preferredCount = 1;
preferred = allLoadSpecs.get(0);
}
// not just one preferred loadSpec? ask loadSpec chooser
LoadSpec loadSpec;
if (loadSpecChooser.usePreferred() && preferredCount == 1) {
loadSpec = preferred;
}
else {
loadSpec = loadSpecChooser.choose(allLoadSpecs);
}
// loadSpec chooser tell us it can't pick one? can't import
if (loadSpec == null) {
File f = provider.getFile();
String name = f != null ? f.getAbsolutePath() : provider.getName();
Msg.info(AutoImporter.class, "No load spec found for import file: " + name);
return null;
}
if (allLoadSpecs.size() > 1) {
for (LoadSpec unusedLoadSpec : allLoadSpecs) {
if (unusedLoadSpec.getLoader().getTier() != LoaderTier.UNTARGETED_LOADER &&
!unusedLoadSpec.equals(loadSpec)) {
Msg.trace(AutoImporter.class, "discarding load spec " + unusedLoadSpec);
}
}
}
return loadSpec;
File f = provider.getFile();
String name = f != null ? f.getAbsolutePath() : provider.getName();
Msg.info(AutoImporter.class, "No load spec found for import file: " + name);
return null;
}
private static List<Program> getPrograms(List<DomainObject> domainObjects) {
@ -269,84 +226,4 @@ public final class AutoImporter {
return programs;
}
public static boolean importAddToProgram(File file, Program program, MessageLog messageLog,
TaskMonitor monitor, Predicate<Loader> loaderFilter, LoadSpecChooser loadSpecChooser,
OptionChooser optionChooser) throws IOException, CancelledException {
if (file == null) {
return false;
}
LoadSpec loadSpec = null;
try (RandomAccessByteProvider provider = new RandomAccessByteProvider(file)) {
Map<Loader, Collection<LoadSpec>> loadMap =
LoaderService.getSupportedLoadSpecs(provider, loaderFilter);
List<LoadSpec> allLoadSpecs = new ArrayList<>();
for (Collection<LoadSpec> loadSpecs : loadMap.values()) {
allLoadSpecs.addAll(loadSpecs);
}
// "count" up our preferred (we really only care about 0, 1, and >1)
int preferredCount = 0;
LoadSpec preferred = null;
for (LoadSpec op : allLoadSpecs) {
if (op.isPreferred()) {
if (preferred == null) {
preferred = op;
preferredCount = 1;
continue;
}
preferredCount = 2;
break;
}
}
// if we had just one load spec, we forcefully consider it preferred
if (allLoadSpecs.size() == 1) {
preferredCount = 1;
preferred = allLoadSpecs.get(0);
}
// not just one preferred loadSpec? ask loadSpec chooser
if (loadSpecChooser.usePreferred() && preferredCount == 1) {
loadSpec = preferred;
}
else {
loadSpec = loadSpecChooser.choose(allLoadSpecs);
}
// loadSpec chooser tell us it can't pick one? can't import
if (loadSpec == null) {
File f = provider.getFile();
String name = f != null ? f.getAbsolutePath() : provider.getName();
Msg.info(AutoImporter.class, "No load spec found for import file: " + name);
return false;
}
LanguageCompilerSpecPair programPair = new LanguageCompilerSpecPair(
program.getLanguageID(), program.getCompilerSpec().getCompilerSpecID());
// loadSpec doesn't match current program
if (!loadSpec.getLanguageCompilerSpec().equals(programPair)) {
Msg.info(AutoImporter.class,
"Import file load spec does not match add-to program: " +
file.getAbsolutePath());
return false;
}
}
List<Option> options = null;
try (RandomAccessByteProvider provider = new RandomAccessByteProvider(file)) {
List<Option> optionChoices =
loadSpec.getLoader().getDefaultOptions(provider, loadSpec, program, true);
options = optionChooser.choose(optionChoices,
DefaultLanguageService.getLanguageService().getLanguage(
loadSpec.getLanguageCompilerSpec().languageID).getAddressFactory());
}
try (RandomAccessByteProvider provider = new RandomAccessByteProvider(file)) {
return loadSpec.getLoader().loadInto(provider, loadSpec, options, messageLog, program,
monitor);
}
}
}

View file

@ -0,0 +1,57 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.importer;
import ghidra.app.util.opinion.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.CompilerSpecID;
/**
* Chooses a {@link LoadSpec} for a {@link Loader} to use based on a provided {@link CompilerSpec}.
*/
public class CsHintLoadSpecChooser implements LoadSpecChooser {
private final CompilerSpecID compilerSpecID;
/**
* Creates a new {@link CsHintLoadSpecChooser}
*
* @param compilerSpecID The {@link CompilerSpecID} to use (should not be null)
*/
public CsHintLoadSpecChooser(CompilerSpecID compilerSpecID) {
this.compilerSpecID = compilerSpecID;
}
/**
* Creates a new {@link CsHintLoadSpecChooser}
*
* @param compilerSpecID The {@link CompilerSpecID} to use (should not be null)
*/
public CsHintLoadSpecChooser(String compilerSpecID) {
this(new CompilerSpecID(compilerSpecID));
}
@Override
public LoadSpec choose(LoaderMap loaderMap) {
return loaderMap.values()
.stream()
.flatMap(loadSpec -> loadSpec.stream())
.filter(loadSpec -> loadSpec.getLanguageCompilerSpec().compilerSpecID
.equals(compilerSpecID))
.findFirst()
.orElse(null);
}
}

View file

@ -15,64 +15,63 @@
*/
package ghidra.app.util.importer;
import java.util.List;
import java.util.Collection;
import ghidra.app.util.opinion.LoadSpec;
import ghidra.app.util.opinion.*;
import ghidra.program.model.lang.*;
import ghidra.util.Msg;
import util.CollectionUtils;
/**
* Chooses a {@link LoadSpec} for a {@link Loader} to use based on a provided {@link Language} and
* {@link CompilerSpec}.
*/
public class LcsHintLoadSpecChooser implements LoadSpecChooser {
private final LanguageID languageID;
private final CompilerSpecID compilerSpecID;
/**
* Creates a new {@link LcsHintLoadSpecChooser}.
* <p>
* NOTE: It is assumed that the given {@link Language} is valid and it supports the given
* {@link CompilerSpec}.
*
* @param language The {@link Language} to use (should not be null)
* @param compilerSpec The {@link CompilerSpec} to use (should not be null)
*/
public LcsHintLoadSpecChooser(Language language, CompilerSpec compilerSpec) {
this.languageID = language.getLanguageID();
this.compilerSpecID = compilerSpec == null ? null : compilerSpec.getCompilerSpecID();
this.compilerSpecID = compilerSpec.getCompilerSpecID();
}
@Override
public LoadSpec choose(List<LoadSpec> loadSpecs) {
for (LoadSpec loadSpec : loadSpecs) {
if (loadSpec == null) {
Msg.warn(this, "found null load spec whilst trying to choose");
}
else if (loadSpec.isPreferred()) {
LanguageCompilerSpecPair lcsPair = loadSpec.getLanguageCompilerSpec();
if (lcsPair == null) {
Msg.warn(this, "load spec " + loadSpec +
" proffered null LCS pair whilst trying to choose");
}
else {
if (lcsPair.languageID.equals(languageID) &&
(compilerSpecID == null || lcsPair.compilerSpecID.equals(compilerSpecID))) {
return loadSpec;
}
}
}
public LoadSpec choose(LoaderMap loaderMap) {
// Use the highest priority loader (it will be the first one)
Loader loader = loaderMap.keySet().stream().findFirst().orElse(null);
if (loader == null) {
return null;
}
for (LoadSpec loadSpec : loadSpecs) {
if (loadSpec == null) {
Msg.warn(this, "found null load spec whilst trying to choose");
}
else {
LanguageCompilerSpecPair lcsPair = loadSpec.getLanguageCompilerSpec();
if (lcsPair == null) {
Msg.warn(this, "load spec " + loadSpec +
" proffered null LCS pair whilst trying to choose");
}
else {
if (lcsPair.languageID.equals(languageID) &&
(compilerSpecID == null || lcsPair.compilerSpecID.equals(compilerSpecID))) {
return loadSpec;
}
}
}
}
return null;
}
@Override
public boolean usePreferred() {
return false;
// Try to use a known LoadSpec that matches the desired language/compiler spec
Collection<LoadSpec> loadSpecs = loaderMap.get(loader);
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsPair = loadSpec.getLanguageCompilerSpec();
if (lcsPair.languageID.equals(languageID) &&
(compilerSpecID == null || lcsPair.compilerSpecID.equals(compilerSpecID))) {
return loadSpec;
}
}
// The desired language/compiler spec is not a defined LoadSpec, so we'll create a custom
// one. This could result in crazy results/analysis, but the point of this chooser is to do
// what we are told.
LoadSpec anyLoadSpec = CollectionUtils.any(loadSpecs);
LanguageCompilerSpecPair customLcsPair =
new LanguageCompilerSpecPair(languageID, compilerSpecID);
LoadSpec customLoadSpec =
new LoadSpec(loader, anyLoadSpec.getDesiredImageBase(), customLcsPair, false);
Msg.warn(this, "Using unknown opinion: " + loader.getName() + ", " + customLcsPair);
return customLoadSpec;
}
}

View file

@ -15,33 +15,33 @@
*/
package ghidra.app.util.importer;
import java.util.List;
import ghidra.app.util.opinion.LoadSpec;
import ghidra.util.Msg;
import ghidra.app.util.opinion.*;
/**
* Chooses a {@link LoadSpec} for a {@link Loader} to use based on some criteria
*/
@FunctionalInterface
public interface LoadSpecChooser {
public static final LoadSpecChooser CHOOSE_THE_FIRST_PREFERRED = new LoadSpecChooser() {
@Override
public LoadSpec choose(List<LoadSpec> loadSpecs) {
for (LoadSpec loadSpec : loadSpecs) {
if (loadSpec == null) {
Msg.warn(this, "found null load spec whilst trying to choose");
}
else if (loadSpec.isPreferred()) {
return loadSpec;
}
}
return null;
}
@Override
public boolean usePreferred() {
return true;
}
/**
* Chooses a {@link LoadSpec} for a {@link Loader} to use based on some criteria
*
* @param loaderMap A {@link LoaderMap}
* @return The chosen {@link LoadSpec}, or null if one could not be found
*/
public LoadSpec choose(LoaderMap loaderMap);
/**
* Chooses the first "preferred" {@link LoadSpec}
*
* @see LoadSpec#isPreferred()
*/
public static final LoadSpecChooser CHOOSE_THE_FIRST_PREFERRED = loaderMap -> {
return loaderMap.values()
.stream()
.flatMap(loadSpecs -> loadSpecs.stream())
.filter(loadSpec -> loadSpec != null && loadSpec.isPreferred())
.findFirst()
.orElse(null);
};
public LoadSpec choose(List<LoadSpec> loadSpecs);
public boolean usePreferred();
}

View file

@ -0,0 +1,37 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.opinion;
import java.util.*;
/**
* A {@link Map} of {@link Loader}s to their respective {@link LoadSpec}s.
* <p>
* The {@link Loader} keys are sorted according to their {@link Loader#compareTo(Loader) natural
* ordering}.
*/
public class LoaderMap extends TreeMap<Loader, Collection<LoadSpec>> {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Loader loader : keySet()) {
Collection<LoadSpec> loadSpecs = get(loader);
sb.append(loader.getName() + " - " + loadSpecs.size() + " load specs\n");
}
return sb.toString();
}
}

View file

@ -36,19 +36,17 @@ public class LoaderService {
*
* @param provider The {@link ByteProvider} to load.
* @param loaderFilter A {@link Predicate} that will filter out undesired {@link Loader}s.
* @return A {@link Map} of {@link Loader}s to their respective {@link LoadSpec}s. It is safe
* to assume that every {@link Loader} in the {@link Map} will have at least one
* {@link LoadSpec}.
* @return All supported {@link LoadSpec}s in the form of a {@link LoaderMap}.
*/
public static Map<Loader, Collection<LoadSpec>> getSupportedLoadSpecs(ByteProvider provider,
public static LoaderMap getSupportedLoadSpecs(ByteProvider provider,
Predicate<Loader> loaderFilter) {
Map<Loader, Collection<LoadSpec>> loadMap = new LinkedHashMap<>(); // maintain loader order
LoaderMap loaderMap = new LoaderMap();
for (Loader loader : getAllLoaders()) {
if (loaderFilter.test(loader)) {
try {
Collection<LoadSpec> loadSpecs = loader.findSupportedLoadSpecs(provider);
if (loadSpecs != null && !loadSpecs.isEmpty()) { // shouldn't be null, but protect against rogue loaders
loadMap.put(loader, loadSpecs);
loaderMap.put(loader, loadSpecs);
}
}
catch (IOException e) {
@ -60,34 +58,32 @@ public class LoaderService {
}
}
}
return loadMap;
return loaderMap;
}
/**
* Gets all supported {@link LoadSpec}s for loading the given {@link ByteProvider}.
*
* @param provider The {@link ByteProvider} to load.
* @return A {@link Map} of {@link Loader}s to their respective {@link LoadSpec}s. It is safe
* to assume that every {@link Loader} in the {@link Map} will have at least one
* {@link LoadSpec}.
* @return All supported {@link LoadSpec}s in the form of a {@link LoaderMap}.
*/
public static Map<Loader, Collection<LoadSpec>> getAllSupportedLoadSpecs(
ByteProvider provider) {
public static LoaderMap getAllSupportedLoadSpecs(ByteProvider provider) {
return getSupportedLoadSpecs(provider, ACCEPT_ALL);
}
/**
* Gets all known {@link Loader}s' names.
*
* @return All known {@link Loader}s' names.
* @return All known {@link Loader}s' names. The {@link Loader} names are sorted
* according to their corresponding {@link Loader}s {@link Loader#compareTo(Loader) natural
* ordering}.
*/
public static Collection<String> getAllLoaderNames() {
//@formatter:off
return getAllLoaders()
.stream()
.sorted()
.map(loader -> loader.getName())
.collect(Collectors.toList());
//@formatter:on
}
/**
@ -99,20 +95,19 @@ public class LoaderService {
* name.
*/
public static Class<? extends Loader> getLoaderClassByName(String name) {
//@formatter:off
return getAllLoaders()
.stream()
.filter(loader -> loader.getClass().getSimpleName().equals(name))
.findFirst()
.map(loader -> loader.getClass())
.orElse(null);
//@formatter:on
}
/**
* Gets an instance of every known {@link Loader}.
*
* @return An instance of every known {@link Loader}.
* @return An instance of every known {@link Loader}. The {@link Loader} instances are sorted
* according to their {@link Loader#compareTo(Loader) natural ordering}.
*/
private synchronized static Collection<Loader> getAllLoaders() {
List<Loader> loaders = new ArrayList<>(ClassSearcher.getInstances(Loader.class));

View file

@ -15,12 +15,11 @@
*/
package ghidra.plugin.importer;
import java.util.*;
import java.util.List;
import ghidra.app.util.Option;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.opinion.LoadSpec;
import ghidra.app.util.opinion.Loader;
import ghidra.app.util.opinion.*;
import ghidra.formats.gfilesystem.FSRL;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
@ -43,14 +42,13 @@ public class AddToProgramDialog extends ImporterDialog {
* Construct a new AddToProgramDialog.
* @param tool the tool containing the currently open program.
* @param fsrl the FileSystemURL for where the imported data can be read.
* @param loadMap the loaders and their corresponding load specifications
* @param loaderMap the loaders and their corresponding load specifications
* @param byteProvider the ByteProvider from which the bytes from the source can be read.
* @param addToProgram the program to which the newly imported data will be added
*/
protected AddToProgramDialog(PluginTool tool, FSRL fsrl,
Map<Loader, Collection<LoadSpec>> loadMap, ByteProvider byteProvider,
Program addToProgram) {
super("Add To Program: " + fsrl.getPath(), tool, loadMap, byteProvider, null);
protected AddToProgramDialog(PluginTool tool, FSRL fsrl, LoaderMap loaderMap,
ByteProvider byteProvider, Program addToProgram) {
super("Add To Program: " + fsrl.getPath(), tool, loaderMap, byteProvider, null);
this.addToProgram = addToProgram;
folderNameTextField.setText(getFolderName(addToProgram));
filenameTextField.setText(addToProgram.getName());

View file

@ -68,7 +68,7 @@ public class ImporterDialog extends DialogComponentProvider {
private ProgramManager programManager;
protected FSRL fsrl;
protected List<Option> options;
private Map<Loader, Collection<LoadSpec>> loadMap;
private LoaderMap loaderMap;
protected LanguageCompilerSpecPair selectedLanguage;
private DomainFolder destinationFolder;
private boolean languageNeeded;
@ -88,7 +88,7 @@ public class ImporterDialog extends DialogComponentProvider {
* Construct a new dialog for importing a file as a new program into Ghidra.
* @param tool the active tool that spawned this dialog.
* @param programManager program manager to open imported file with or null
* @param loadMap the loaders and their corresponding load specifications
* @param loaderMap the loaders and their corresponding load specifications
* @param byteProvider the ByteProvider for getting the bytes from the file to be imported.
* @param suggestedDestinationPath optional string path that will be pre-pended to the destination
* filename. Any path specified in the destination filename field will be created when
@ -96,22 +96,20 @@ public class ImporterDialog extends DialogComponentProvider {
* option which requires the DomainFolder to already exist). The two destination paths work together
* to specify the final Ghidra project folder where the imported binary is placed.
*/
public ImporterDialog(PluginTool tool, ProgramManager programManager,
Map<Loader, Collection<LoadSpec>> loadMap, ByteProvider byteProvider,
String suggestedDestinationPath) {
this("Import " + byteProvider.getFSRL().getPath(), tool, loadMap, byteProvider,
public ImporterDialog(PluginTool tool, ProgramManager programManager, LoaderMap loaderMap,
ByteProvider byteProvider, String suggestedDestinationPath) {
this("Import " + byteProvider.getFSRL().getPath(), tool, loaderMap, byteProvider,
suggestedDestinationPath);
this.programManager = programManager;
}
protected ImporterDialog(String title, PluginTool tool,
Map<Loader, Collection<LoadSpec>> loadMap, ByteProvider byteProvider,
String suggestedDestinationPath) {
protected ImporterDialog(String title, PluginTool tool, LoaderMap loaderMap,
ByteProvider byteProvider, String suggestedDestinationPath) {
super(title);
this.tool = tool;
this.programManager = tool.getService(ProgramManager.class);
this.fsrl = byteProvider.getFSRL();
this.loadMap = loadMap;
this.loaderMap = loaderMap;
this.byteProvider = byteProvider;
this.suggestedDestinationPath = suggestedDestinationPath;
@ -231,7 +229,7 @@ public class ImporterDialog extends DialogComponentProvider {
if (selectedItem instanceof Loader) {
Loader loader = (Loader) selectedItem;
ImporterLanguageDialog dialog =
new ImporterLanguageDialog(loadMap.get(loader), tool, selectedLanguage);
new ImporterLanguageDialog(loaderMap.get(loader), tool, selectedLanguage);
dialog.show(getComponent());
LanguageCompilerSpecPair dialogResult = dialog.getSelectedLanguage();
if (dialogResult != null) {
@ -254,7 +252,7 @@ public class ImporterDialog extends DialogComponentProvider {
JPanel panel = new JPanel(new BorderLayout());
Set<Loader> set = new LinkedHashSet<>(); // maintain order
for (Loader loader : loadMap.keySet()) {
for (Loader loader : loaderMap.keySet()) {
if (isSupported(loader)) {
set.add(loader);
}
@ -321,7 +319,7 @@ public class ImporterDialog extends DialogComponentProvider {
}
private boolean isLanguageNeeded(Loader loader) {
return loadMap.get(loader).stream().anyMatch(spec -> spec.requiresLanguageCompilerSpec());
return loaderMap.get(loader).stream().anyMatch(spec -> spec.requiresLanguageCompilerSpec());
}
private Component buildButtonPanel() {
@ -434,7 +432,7 @@ public class ImporterDialog extends DialogComponentProvider {
}
protected LoadSpec getSelectedLoadSpec(Loader loader) {
Collection<LoadSpec> loadSpecs = loadMap.get(loader);
Collection<LoadSpec> loadSpecs = loaderMap.get(loader);
long imageBase = 0;
if (loadSpecs != null && !loadSpecs.isEmpty()) {
imageBase = loadSpecs.iterator().next().getDesiredImageBase();
@ -565,7 +563,7 @@ public class ImporterDialog extends DialogComponentProvider {
}
private LanguageCompilerSpecPair getPreferredLanguage(Loader loader) {
for (LoadSpec loadSpec : loadMap.get(loader)) {
for (LoadSpec loadSpec : loaderMap.get(loader)) {
if (loadSpec.isPreferred()) {
return loadSpec.getLanguageCompilerSpec();
}

View file

@ -271,12 +271,12 @@ public class ImporterUtilities {
return;
}
Map<Loader, Collection<LoadSpec>> loadMap = LoaderService.getSupportedLoadSpecs(
provider, loader -> loader.supportsLoadIntoProgram());
LoaderMap loaderMap = LoaderService.getSupportedLoadSpecs(provider,
loader -> loader.supportsLoadIntoProgram());
SystemUtilities.runSwingLater(() -> {
AddToProgramDialog dialog =
new AddToProgramDialog(tool, fsrl, loadMap, provider, program);
new AddToProgramDialog(tool, fsrl, loaderMap, provider, program);
tool.showDialog(dialog);
});
}
@ -309,12 +309,11 @@ public class ImporterUtilities {
try {
ByteProvider provider = FileSystemService.getInstance().getByteProvider(fsrl, monitor);
Map<Loader, Collection<LoadSpec>> loadMap =
LoaderService.getAllSupportedLoadSpecs(provider);
LoaderMap loaderMap = LoaderService.getAllSupportedLoadSpecs(provider);
SystemUtilities.runSwingLater(() -> {
ImporterDialog importerDialog =
new ImporterDialog(tool, programManager, loadMap, provider, suggestedPath);
new ImporterDialog(tool, programManager, loaderMap, provider, suggestedPath);
if (destinationFolder != null) {
importerDialog.setDestinationFolder(destinationFolder);
}

View file

@ -357,10 +357,9 @@ public class BatchInfo {
try (ByteProvider provider =
FileSystemService.getInstance().getByteProvider(fsrl, monitor)) {
Map<Loader, Collection<LoadSpec>> loadMap =
pollLoadersForLoadSpecs(provider, fsrl, monitor);
for (Loader loader : loadMap.keySet()) {
Collection<LoadSpec> loadSpecs = loadMap.get(loader);
LoaderMap loaderMap = pollLoadersForLoadSpecs(provider, fsrl, monitor);
for (Loader loader : loaderMap.keySet()) {
Collection<LoadSpec> loadSpecs = loaderMap.get(loader);
BatchSegregatingCriteria bsc =
new BatchSegregatingCriteria(loader, loadSpecs, provider);
BatchGroup batchGroup = groupsByCriteria.get(bsc);
@ -371,7 +370,7 @@ public class BatchInfo {
batchGroup.add(provider, loadSpecs, fsrl, currentUASI);
}
return loadMap.keySet().size() > 0;
return loaderMap.keySet().size() > 0;
}
catch (IOException ioe) {
Msg.warn(this, "Error while probing file " + fsrl + " for loader applications: " +
@ -380,8 +379,7 @@ public class BatchInfo {
}
}
private Map<Loader, Collection<LoadSpec>> pollLoadersForLoadSpecs(ByteProvider provider,
FSRL fsrl, TaskMonitor monitor) {
private LoaderMap pollLoadersForLoadSpecs(ByteProvider provider, FSRL fsrl, TaskMonitor monitor) {
monitor.setMessage(fsrl.getName());
return LoaderService.getSupportedLoadSpecs(provider,
loader -> !(loader instanceof BinaryLoader));

View file

@ -26,10 +26,11 @@ import ghidra.app.util.bin.format.coff.*;
import ghidra.app.util.bin.format.coff.archive.CoffArchiveHeader;
import ghidra.app.util.bin.format.coff.archive.CoffArchiveMemberHeader;
import ghidra.app.util.importer.*;
import ghidra.app.util.opinion.*;
import ghidra.app.util.opinion.Loader;
import ghidra.app.util.opinion.MSCoffLoader;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.store.local.LocalFileSystem;
import ghidra.program.model.lang.*;
import ghidra.program.model.lang.LanguageDescription;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
@ -38,46 +39,7 @@ import ghidra.util.task.TaskMonitor;
public class ImportMSLibs extends GhidraScript {
final static Predicate<Loader> LOADER_FILTER = new SingleLoaderFilter(MSCoffLoader.class);
final static LoadSpecChooser LOADSPEC_CHOOSER = new LoadSpecChooser() {
@Override
public LoadSpec choose(List<LoadSpec> loadSpecs) {
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
if (lcsp.compilerSpecID.getIdAsString().equals("windows")) {
return loadSpec;
}
}
// XXX short circuit; for now only process valid windows opinions, which means x86
if (Math.min(1, 2) == 1) {
return null;
}
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
try {
if (lcsp.getLanguageDescription().getProcessor() == Processor.toProcessor(
"ARM") && lcsp.getLanguageDescription().getEndian() == Endian.LITTLE &&
lcsp.getLanguageDescription().getVariant().contains("v7")) {
return loadSpec;
}
}
catch (LanguageNotFoundException e) {
// ignore...not sure why this happened
}
}
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
if (lcsp.compilerSpecID.getIdAsString().equals("gcc")) {
return loadSpec;
}
}
return null;
}
@Override
public boolean usePreferred() {
return true;
}
};
final static LoadSpecChooser LOADSPEC_CHOOSER = new CsHintLoadSpecChooser("windows");
@Override
protected void run() throws Exception {

View file

@ -64,11 +64,11 @@ import ghidra.app.util.bin.format.coff.*;
import ghidra.app.util.bin.format.coff.archive.CoffArchiveHeader;
import ghidra.app.util.bin.format.coff.archive.CoffArchiveMemberHeader;
import ghidra.app.util.importer.*;
import ghidra.app.util.opinion.*;
import ghidra.app.util.opinion.Loader;
import ghidra.app.util.opinion.MSCoffLoader;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.store.local.LocalFileSystem;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
@ -77,41 +77,7 @@ import utilities.util.FileUtilities;
public class MSLibBatchImportWorker extends GhidraScript {
final static Predicate<Loader> LOADER_FILTER = new SingleLoaderFilter(MSCoffLoader.class);
final static LoadSpecChooser LOADSPEC_CHOOSER = new LoadSpecChooser() {
@Override
public LoadSpec choose(List<LoadSpec> loadSpecs) {
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
if (lcsp.compilerSpecID.getIdAsString().equals("windows")) {
return loadSpec;
}
}
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
try {
if (lcsp.getLanguageDescription().getEndian() == Endian.LITTLE &&
lcsp.getLanguageDescription().getVariant().contains("v7")) {
return loadSpec;
}
}
catch (LanguageNotFoundException e) {
// ignore...not sure why this happened
}
}
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
if (lcsp.compilerSpecID.getIdAsString().equals("gcc")) {
return loadSpec;
}
}
return null;
}
@Override
public boolean usePreferred() {
return true;
}
};
final static LoadSpecChooser LOADSPEC_CHOOSER = new CsHintLoadSpecChooser("windows");
private static String getProcessId(String fallback) {
// something like '<pid>@<hostname>', at least in SUN / Oracle JVMs

View file

@ -25,10 +25,10 @@ import ghidra.app.util.bin.format.coff.*;
import ghidra.app.util.bin.format.coff.archive.CoffArchiveHeader;
import ghidra.app.util.bin.format.coff.archive.CoffArchiveMemberHeader;
import ghidra.app.util.importer.*;
import ghidra.app.util.opinion.*;
import ghidra.app.util.opinion.Loader;
import ghidra.app.util.opinion.MSCoffLoader;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.store.local.LocalFileSystem;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
@ -36,41 +36,7 @@ import ghidra.util.task.TaskMonitor;
public class RecursiveRecursiveMSLibImport extends GhidraScript {
final static Predicate<Loader> LOADER_FILTER = new SingleLoaderFilter(MSCoffLoader.class);
final static LoadSpecChooser LOADSPEC_CHOOSER = new LoadSpecChooser() {
@Override
public LoadSpec choose(List<LoadSpec> loadSpecs) {
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
if (lcsp.compilerSpecID.getIdAsString().equals("windows")) {
return loadSpec;
}
}
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
try {
if (lcsp.getLanguageDescription().getEndian() == Endian.LITTLE &&
lcsp.getLanguageDescription().getVariant().contains("v7")) {
return loadSpec;
}
}
catch (LanguageNotFoundException e) {
// ignore...not sure why this happened
}
}
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
if (lcsp.compilerSpecID.getIdAsString().equals("gcc")) {
return loadSpec;
}
}
return null;
}
@Override
public boolean usePreferred() {
return true;
}
};
final static LoadSpecChooser LOADSPEC_CHOOSER = new CsHintLoadSpecChooser("windows");
@Override
protected void run() throws Exception {