GT-3376: Headless now properly honors -processor flag, even if the

specified processor is not a valid opinion.
This commit is contained in:
Ryan Kurtz 2019-12-09 08:24:05 -05:00
parent 3ce8d3fa39
commit a46e788706
6 changed files with 167 additions and 287 deletions

View File

@ -205,58 +205,15 @@ public final class AutoImporter {
Map<Loader, Collection<LoadSpec>> loadMap =
LoaderService.getSupportedLoadSpecs(provider, loaderFilter);
List<LoadSpec> allLoadSpecs = new ArrayList<>();
for (Collection<LoadSpec> loadSpecs : loadMap.values()) {
allLoadSpecs.addAll(loadSpecs);
LoadSpec loadSpec = loadSpecChooser.choose(loadMap);
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

@ -15,64 +15,75 @@
*/
package ghidra.app.util.importer;
import java.util.List;
import java.util.Collection;
import java.util.Map;
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(Map<Loader, Collection<LoadSpec>> loadMap) {
// We need to reduce the set of matching loaders down to one. The only requirement is that
// if we do reduce, make sure we don't reduce it to the BinaryLoader.
Loader loader;
if (loadMap.size() > 1) {
loader = loadMap.keySet()
.stream()
.filter(e -> e.getTier() != LoaderTier.UNTARGETED_LOADER)
.findFirst()
.orElse(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;
}
}
}
else if (loadMap.size() == 1) {
loader = loadMap.keySet().iterator().next();
}
else {
return null;
}
return null;
}
@Override
public boolean usePreferred() {
return false;
// Try to use a known LoadSpec that matches the desired language/compiler spec
Collection<LoadSpec> loadSpecs = loadMap.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,37 @@
*/
package ghidra.app.util.importer;
import java.util.List;
import java.util.Collection;
import java.util.Map;
import ghidra.app.util.opinion.LoadSpec;
import ghidra.util.Msg;
import ghidra.app.util.opinion.Loader;
/**
* 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 loadMap A {@link Map} of {@link Loader}s to their respective {@link LoadSpec}s
* @return The chosen {@link LoadSpec}
*/
public LoadSpec choose(Map<Loader, Collection<LoadSpec>> loadMap);
/**
* Chooses the first "preferred" {@link LoadSpec}
*
* @see LoadSpec#isPreferred()
*/
public static final LoadSpecChooser CHOOSE_THE_FIRST_PREFERRED = loadMap -> {
return loadMap.values()
.stream()
.flatMap(e -> e.stream())
.filter(e -> e != null && e.isPreferred())
.findFirst()
.orElse(null);
};
public LoadSpec choose(List<LoadSpec> loadSpecs);
public boolean usePreferred();
}

View File

@ -19,6 +19,7 @@ import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.bin.*;
@ -35,48 +36,43 @@ import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
import ghidra.util.task.CancelOnlyWrappingTaskMonitor;
import ghidra.util.task.TaskMonitor;
import util.CollectionUtils;
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;
}
final static LoadSpecChooser LOADSPEC_CHOOSER = loadMap -> {
Stream<LoadSpec> loadSpecStream = loadMap.values().stream().flatMap(e -> e.stream());
Iterable<LoadSpec> loadSpecs = CollectionUtils.asIterable(loadSpecStream.iterator());
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;
}
@Override
public boolean usePreferred() {
return true;
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

View File

@ -54,6 +54,7 @@ import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.apache.commons.io.FileUtils;
@ -73,44 +74,39 @@ import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import util.CollectionUtils;
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")) {
final static LoadSpecChooser LOADSPEC_CHOOSER = loadMap -> {
Stream<LoadSpec> loadSpecStream = loadMap.values().stream().flatMap(e -> e.stream());
Iterable<LoadSpec> loadSpecs = CollectionUtils.asIterable(loadSpecStream.iterator());
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;
}
}
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
}
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;
}
}
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
if (lcsp.compilerSpecID.getIdAsString().equals("gcc")) {
return loadSpec;
}
return null;
}
@Override
public boolean usePreferred() {
return true;
}
return null;
};
private static String getProcessId(String fallback) {

View File

@ -17,6 +17,7 @@ import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
import generic.stl.Pair;
import ghidra.app.script.GhidraScript;
@ -33,43 +34,38 @@ import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import util.CollectionUtils;
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")) {
final static LoadSpecChooser LOADSPEC_CHOOSER = loadMap -> {
Stream<LoadSpec> loadSpecStream = loadMap.values().stream().flatMap(e -> e.stream());
Iterable<LoadSpec> loadSpecs = CollectionUtils.asIterable(loadSpecStream.iterator());
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;
}
}
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
}
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;
}
}
for (LoadSpec loadSpec : loadSpecs) {
LanguageCompilerSpecPair lcsp = loadSpec.getLanguageCompilerSpec();
if (lcsp.compilerSpecID.getIdAsString().equals("gcc")) {
return loadSpec;
}
return null;
}
@Override
public boolean usePreferred() {
return true;
}
return null;
};
@Override