mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 12:00:04 +02:00
Merge remote-tracking branch 'origin/GT-3376_ryanmkurtz_AutoImporter'
(Fixes #1311)
This commit is contained in:
commit
decb362234
13 changed files with 224 additions and 372 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue