diff options
Diffstat (limited to 'tools/dexfuzz/src/dexfuzz')
24 files changed, 304 insertions, 416 deletions
diff --git a/tools/dexfuzz/src/dexfuzz/DexFuzz.java b/tools/dexfuzz/src/dexfuzz/DexFuzz.java index 2fb9663..04bbbf8 100644 --- a/tools/dexfuzz/src/dexfuzz/DexFuzz.java +++ b/tools/dexfuzz/src/dexfuzz/DexFuzz.java @@ -33,7 +33,7 @@ import dexfuzz.listeners.UpdatingConsoleListener; */ public class DexFuzz { private static int majorVersion = 1; - private static int minorVersion = 0; + private static int minorVersion = 1; private static int seedChangeVersion = 0; /** diff --git a/tools/dexfuzz/src/dexfuzz/Options.java b/tools/dexfuzz/src/dexfuzz/Options.java index 1ae7b5e..2e929c8 100644 --- a/tools/dexfuzz/src/dexfuzz/Options.java +++ b/tools/dexfuzz/src/dexfuzz/Options.java @@ -58,7 +58,7 @@ public class Options { // FLAG OPTIONS public static boolean execute; - public static boolean local; + public static boolean executeOnHost; public static boolean noBootImage; public static boolean useInterpreter; public static boolean useQuick; @@ -90,7 +90,7 @@ public class Options { Log.always(" --output=<file> : Output DEX file to be produced"); Log.always(""); Log.always(" --execute : Execute the resulting fuzzed program"); - Log.always(" --local : Execute on host (Not available yet.)"); + Log.always(" --host : Execute on host"); Log.always(" --device=<device> : Execute on an ADB-connected-device, where <device> is"); Log.always(" the argument given to adb -s. Default execution mode."); Log.always(" --execute-dir=<dir> : Push tests to this directory to execute them."); @@ -150,8 +150,8 @@ public class Options { private static void handleFlagOption(String flag) { if (flag.equals("execute")) { execute = true; - } else if (flag.equals("local")) { - local = true; + } else if (flag.equals("host")) { + executeOnHost = true; } else if (flag.equals("no-boot-image")) { noBootImage = true; } else if (flag.equals("skip-host-verify")) { @@ -383,19 +383,25 @@ public class Options { Log.error("Cannot use --max-methods that's smaller than --min-methods"); return false; } - if (local && usingSpecificDevice) { - Log.error("Cannot use --local and --device!"); + if (executeOnHost && usingSpecificDevice) { + Log.error("Cannot use --host and --device!"); return false; } if (execute) { - if (!(useArchArm - || useArchArm64 - || useArchX86 - || useArchX86_64 - || useArchMips - || useArchMips64)) { - Log.error("No architecture to execute on was specified!"); - return false; + // When host-execution mode is specified, we don't need to select an architecture. + if (!executeOnHost) { + if (!(useArchArm + || useArchArm64 + || useArchX86 + || useArchX86_64 + || useArchMips + || useArchMips64)) { + Log.error("No architecture to execute on was specified!"); + return false; + } + } else { + // TODO: Select the correct architecture. For now, just assume x86. + useArchX86 = true; } if ((useArchArm || useArchArm64) && (useArchX86 || useArchX86_64)) { Log.error("Did you mean to specify ARM and x86?"); diff --git a/tools/dexfuzz/src/dexfuzz/executors/Architecture.java b/tools/dexfuzz/src/dexfuzz/executors/Architecture.java index 5cdabc3..051d80e 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Architecture.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Architecture.java @@ -17,15 +17,23 @@ package dexfuzz.executors; /** - * Every Executor must specify an Architecture. It is important that when reduced - * to lower case, these match the ISA string that ART would produce. For example, - * the architecture directory used for /data/dalvik-cache/${ISA} + * Every Executor must specify an Architecture. */ public enum Architecture { - ARM, - ARM64, - X86, - X86_64, - MIPS, - MIPS64 + ARM("arm"), + ARM64("arm64"), + X86("x86"), + X86_64("x86_64"), + MIPS("mips"), + MIPS64("mips64"); + + private String archString = ""; + + private Architecture(String archString) { + this.archString = archString; + } + + public String asString() { + return archString; + } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64InterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64InterpreterExecutor.java index a945283..227c698 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Arm64InterpreterExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64InterpreterExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class Arm64InterpreterExecutor extends Executor { public Arm64InterpreterExecutor(BaseListener listener, Device device) { - super("ARM64 Interpreter", 30, listener, Architecture.ARM64, device); + super("ARM64 Interpreter", 30, listener, Architecture.ARM64, device, false); } @Override @@ -33,17 +33,6 @@ public class Arm64InterpreterExecutor extends Executor { } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/arm64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return false; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java index 2204ba8..bfa87b7 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class Arm64OptimizingBackendExecutor extends Executor { public Arm64OptimizingBackendExecutor(BaseListener listener, Device device) { - super("ARM64 Optimizing Backend", 5, listener, Architecture.ARM64, device); + super("ARM64 Optimizing Backend", 5, listener, Architecture.ARM64, device, true); } @Override @@ -33,17 +33,6 @@ public class Arm64OptimizingBackendExecutor extends Executor { } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/arm64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java index 55c9c7a..726a7a8 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class Arm64QuickBackendExecutor extends Executor { public Arm64QuickBackendExecutor(BaseListener listener, Device device) { - super("ARM64 Quick Backend", 5, listener, Architecture.ARM64, device); + super("ARM64 Quick Backend", 5, listener, Architecture.ARM64, device, true); } @Override @@ -33,17 +33,6 @@ public class Arm64QuickBackendExecutor extends Executor { } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/arm64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmInterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmInterpreterExecutor.java index 68ce2e0..d17ea87 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/ArmInterpreterExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/ArmInterpreterExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class ArmInterpreterExecutor extends Executor { public ArmInterpreterExecutor(BaseListener listener, Device device) { - super("ARM Interpreter", 30, listener, Architecture.ARM, device); + super("ARM Interpreter", 30, listener, Architecture.ARM, device, false); } @Override @@ -33,17 +33,6 @@ public class ArmInterpreterExecutor extends Executor { } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/arm/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return false; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java index 78cf652..947bb2f 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class ArmOptimizingBackendExecutor extends Executor { public ArmOptimizingBackendExecutor(BaseListener listener, Device device) { - super("ARM Optimizing Backend", 5, listener, Architecture.ARM, device); + super("ARM Optimizing Backend", 5, listener, Architecture.ARM, device, true); } @Override @@ -33,17 +33,6 @@ public class ArmOptimizingBackendExecutor extends Executor { } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/arm/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java index 8f026b2..611270b 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class ArmQuickBackendExecutor extends Executor { public ArmQuickBackendExecutor(BaseListener listener, Device device) { - super("ARM Quick Backend", 5, listener, Architecture.ARM, device); + super("ARM Quick Backend", 5, listener, Architecture.ARM, device, true); } @Override @@ -33,17 +33,6 @@ public class ArmQuickBackendExecutor extends Executor { } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/arm/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/Device.java b/tools/dexfuzz/src/dexfuzz/executors/Device.java index 8c03103..736aaad 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Device.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Device.java @@ -16,22 +16,36 @@ package dexfuzz.executors; +import java.io.IOException; +import java.util.Map; + +import dexfuzz.ExecutionResult; +import dexfuzz.Log; +import dexfuzz.Options; +import dexfuzz.StreamConsumer; + /** - * Handles execution either on a remote device, or locally. - * Currently only remote execution, on an ADB-connected device, is supported. + * Handles execution either on a remote target device, or on a local host computer. */ public class Device { - private boolean isLocal; + private boolean isHost; private String deviceName; private boolean usingSpecificDevice; private boolean noBootImage; + private String androidHostOut; + private String androidProductOut; + private String androidData; + + private boolean programPushed; + /** - * The constructor for a local "device". Not yet supported. + * The constructor for a host "device". */ public Device() { - this.isLocal = true; - throw new UnsupportedOperationException("Currently local execution is not supported."); + this.isHost = true; + this.deviceName = "[HostDevice]"; + setup(); } /** @@ -43,20 +57,68 @@ public class Device { this.usingSpecificDevice = true; } this.noBootImage = noBootImage; + setup(); + } + + private String checkForEnvVar(Map<String, String> envVars, String key) { + if (!envVars.containsKey(key)) { + Log.errorAndQuit("Cannot run a fuzzed program if $" + key + " is not set!"); + } + return envVars.get(key); + } + + private void setup() { + programPushed = false; + + Map<String, String> envVars = System.getenv(); + androidProductOut = checkForEnvVar(envVars, "ANDROID_PRODUCT_OUT"); + androidHostOut = checkForEnvVar(envVars, "ANDROID_HOST_OUT"); + + if (!isHost) { + // Create temporary consumers for the initial test. + StreamConsumer outputConsumer = new StreamConsumer(); + outputConsumer.start(); + StreamConsumer errorConsumer = new StreamConsumer(); + errorConsumer.start(); + + // Check for ADB. + try { + ProcessBuilder pb = new ProcessBuilder(); + pb.command("adb", "devices"); + Process process = pb.start(); + int exitValue = process.waitFor(); + if (exitValue != 0) { + Log.errorAndQuit("Problem executing ADB - is it in your $PATH?"); + } + } catch (IOException e) { + Log.errorAndQuit("IOException when executing ADB, is it working?"); + } catch (InterruptedException e) { + Log.errorAndQuit("InterruptedException when executing ADB, is it working?"); + } + + // Check we can run something on ADB. + ExecutionResult result = executeCommand("true", true, outputConsumer, errorConsumer); + if (result.getFlattenedAll().contains("device not found")) { + Log.errorAndQuit("Couldn't connect to specified ADB device: " + deviceName); + } + + outputConsumer.shutdown(); + errorConsumer.shutdown(); + } else { + androidData = checkForEnvVar(envVars, "ANDROID_DATA"); + } } /** * Get the name that would be provided to adb -s to communicate specifically with this device. */ public String getName() { - if (isLocal) { - return "LOCAL DEVICE"; - } + assert(!isHost); return deviceName; } - public boolean isLocal() { - return isLocal; + public boolean isHost() { + return isHost; } /** @@ -72,20 +134,81 @@ public class Device { * Get the command prefix for this device if we want to use adb shell. */ public String getExecutionShellPrefix() { - if (isLocal) { + if (isHost) { return ""; } return getExecutionPrefixWithAdb("shell"); } /** - * Get the command prefix for this device if we want to use adb push. + * Get any extra flags required to execute ART on the host. */ - public String getExecutionPushPrefix() { - if (isLocal) { - return ""; + public String getHostExecutionFlags() { + return String.format("-Xnorelocate -Ximage:%s/framework/core.art", androidHostOut); + } + + public String getAndroidHostOut() { + return androidHostOut; + } + + public String getAndroidProductOut() { + return androidProductOut; + } + + public ExecutionResult executeCommand(String command, boolean captureOutput) { + assert(!captureOutput); + return executeCommand(command, captureOutput, null, null); + } + + public ExecutionResult executeCommand(String command, boolean captureOutput, + StreamConsumer outputConsumer, StreamConsumer errorConsumer) { + + ExecutionResult result = new ExecutionResult(); + + Log.info("Executing: " + command); + + try { + ProcessBuilder processBuilder = new ProcessBuilder(command.split(" ")); + processBuilder.environment().put("ANDROID_ROOT", androidHostOut); + if (Options.executeOnHost) { + processBuilder.environment().put("ANDROID_DATA", androidData); + } + Process process = processBuilder.start(); + + if (captureOutput) { + // Give the streams to the StreamConsumers. + outputConsumer.giveStreamAndStartConsuming(process.getInputStream()); + errorConsumer.giveStreamAndStartConsuming(process.getErrorStream()); + } + + // Wait until the process is done - the StreamConsumers will keep the + // buffers drained, so this shouldn't block indefinitely. + // Get the return value as well. + result.returnValue = process.waitFor(); + + Log.info("Return value: " + result.returnValue); + + if (captureOutput) { + // Tell the StreamConsumers to stop consuming, and wait for them to finish + // so we know we have all of the output. + outputConsumer.processFinished(); + errorConsumer.processFinished(); + result.output = outputConsumer.getOutput(); + result.error = errorConsumer.getOutput(); + + // Always explicitly indicate the return code in the text output now. + // NB: adb shell doesn't actually return exit codes currently, but this will + // be useful if/when it does. + result.output.add("RETURN CODE: " + result.returnValue); + } + + } catch (IOException e) { + Log.errorAndQuit("ExecutionResult.execute() caught an IOException"); + } catch (InterruptedException e) { + Log.errorAndQuit("ExecutionResult.execute() caught an InterruptedException"); } - return getExecutionPrefixWithAdb("push"); + + return result; } private String getExecutionPrefixWithAdb(String command) { @@ -95,4 +218,37 @@ public class Device { return String.format("adb %s ", command); } } + + private String getCacheLocation(Architecture architecture) { + String cacheLocation = ""; + if (isHost) { + cacheLocation = androidData + "/dalvik-cache/" + architecture.asString() + "/"; + } else { + cacheLocation = "/data/dalvik-cache/" + architecture.asString() + "/"; + } + return cacheLocation; + } + + private String getOatFileName(String testLocation, String programName) { + // Converts e.g. /data/art-test/file.dex to data@art-test@file.dex + return (testLocation.replace("/", "@").substring(1) + "@" + programName); + } + + public void cleanCodeCache(Architecture architecture, String testLocation, String programName) { + String command = "rm -f " + getCacheLocation(architecture) + + getOatFileName(testLocation, programName); + executeCommand(command, false); + } + + public void pushProgramToDevice(String programName, String testLocation) { + assert(!isHost); + if (!programPushed) { + executeCommand(getExecutionPrefixWithAdb("push") + programName + " " + testLocation, false); + programPushed = true; + } + } + + public void resetProgramPushed() { + programPushed = false; + } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/Executor.java b/tools/dexfuzz/src/dexfuzz/executors/Executor.java index 7cc584d..1e5d4be 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Executor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Executor.java @@ -17,21 +17,14 @@ package dexfuzz.executors; import dexfuzz.ExecutionResult; -import dexfuzz.Log; import dexfuzz.Options; import dexfuzz.StreamConsumer; import dexfuzz.listeners.BaseListener; -import java.io.IOException; -import java.util.Map; - /** * Base class containing the common methods for executing a particular backend of ART. */ public abstract class Executor { - private String androidHostOut; - private String androidProductOut; - private StreamConsumer outputConsumer; private StreamConsumer errorConsumer; @@ -45,9 +38,10 @@ public abstract class Executor { protected String testLocation; protected Architecture architecture; protected Device device; + private boolean needsCleanCodeCache; protected Executor(String name, int timeout, BaseListener listener, Architecture architecture, - Device device) { + Device device, boolean needsCleanCodeCache) { executeClass = Options.executeClass; if (Options.shortTimeouts) { @@ -60,106 +54,27 @@ public abstract class Executor { this.listener = listener; this.architecture = architecture; this.device = device; + this.needsCleanCodeCache = needsCleanCodeCache; - this.testLocation = Options.executeDirectory; - - Map<String, String> envVars = System.getenv(); - androidProductOut = checkForEnvVar(envVars, "ANDROID_PRODUCT_OUT"); - androidHostOut = checkForEnvVar(envVars, "ANDROID_HOST_OUT"); + if (Options.executeOnHost) { + this.testLocation = System.getProperty("user.dir"); + } else { + this.testLocation = Options.executeDirectory; + } outputConsumer = new StreamConsumer(); outputConsumer.start(); errorConsumer = new StreamConsumer(); errorConsumer.start(); - - if (!device.isLocal()) { - // Check for ADB. - try { - ProcessBuilder pb = new ProcessBuilder(); - pb.command("adb", "devices"); - Process process = pb.start(); - int exitValue = process.waitFor(); - if (exitValue != 0) { - Log.errorAndQuit("Problem executing ADB - is it in your $PATH?"); - } - } catch (IOException e) { - Log.errorAndQuit("IOException when executing ADB, is it working?"); - } catch (InterruptedException e) { - Log.errorAndQuit("InterruptedException when executing ADB, is it working?"); - } - - // Check we can run something on ADB. - ExecutionResult result = executeOnDevice("true", true); - if (result.getFlattenedAll().contains("device not found")) { - Log.errorAndQuit("Couldn't connect to specified ADB device: " + device.getName()); - } - } - } - - private String checkForEnvVar(Map<String, String> envVars, String key) { - if (!envVars.containsKey(key)) { - Log.errorAndQuit("Cannot run a fuzzed program if $" + key + " is not set!"); - } - return envVars.get(key); - } - - private ExecutionResult executeCommand(String command, boolean captureOutput) { - ExecutionResult result = new ExecutionResult(); - - Log.info("Executing: " + command); - - try { - ProcessBuilder processBuilder = new ProcessBuilder(command.split(" ")); - processBuilder.environment().put("ANDROID_ROOT", androidHostOut); - Process process = processBuilder.start(); - - if (captureOutput) { - // Give the streams to the StreamConsumers. - outputConsumer.giveStreamAndStartConsuming(process.getInputStream()); - errorConsumer.giveStreamAndStartConsuming(process.getErrorStream()); - } - - // Wait until the process is done - the StreamConsumers will keep the - // buffers drained, so this shouldn't block indefinitely. - // Get the return value as well. - result.returnValue = process.waitFor(); - - Log.info("Return value: " + result.returnValue); - - if (captureOutput) { - // Tell the StreamConsumers to stop consuming, and wait for them to finish - // so we know we have all of the output. - outputConsumer.processFinished(); - errorConsumer.processFinished(); - result.output = outputConsumer.getOutput(); - result.error = errorConsumer.getOutput(); - - // Always explicitly indicate the return code in the text output now. - // NB: adb shell doesn't actually return exit codes currently, but this will - // be useful if/when it does. - result.output.add("RETURN CODE: " + result.returnValue); - } - - } catch (IOException e) { - Log.errorAndQuit("ExecutionResult.execute() caught an IOException"); - } catch (InterruptedException e) { - Log.errorAndQuit("ExecutionResult.execute() caught an InterruptedException"); - } - - return result; } /** * Called by subclass Executors in their execute() implementations. */ - protected ExecutionResult executeOnDevice(String command, boolean captureOutput) { + protected ExecutionResult executeCommandWithTimeout(String command, boolean captureOutput) { String timeoutString = "timeout " + timeout + " "; - return executeCommand(timeoutString + device.getExecutionShellPrefix() + command, - captureOutput); - } - - private ExecutionResult pushToDevice(String command) { - return executeCommand(device.getExecutionPushPrefix() + command, false); + return device.executeCommand(timeoutString + device.getExecutionShellPrefix() + command, + captureOutput, outputConsumer, errorConsumer); } /** @@ -184,13 +99,11 @@ public abstract class Executor { StringBuilder commandBuilder = new StringBuilder(); commandBuilder.append("dex2oat "); - // This assumes that the Architecture enum's name, when reduced to lower-case, - // matches what dex2oat would expect. - commandBuilder.append("--instruction-set=").append(architecture.toString().toLowerCase()); + commandBuilder.append("--instruction-set=").append(architecture.asString()); commandBuilder.append(" --instruction-set-features=default "); // Select the correct boot image. - commandBuilder.append("--boot-image=").append(androidProductOut); + commandBuilder.append("--boot-image=").append(device.getAndroidProductOut()); if (device.noBootImageAvailable()) { commandBuilder.append("/data/art-test/core.art "); } else { @@ -198,13 +111,14 @@ public abstract class Executor { } commandBuilder.append("--oat-file=output.oat "); - commandBuilder.append("--android-root=").append(androidHostOut).append(" "); + commandBuilder.append("--android-root=").append(device.getAndroidHostOut()).append(" "); commandBuilder.append("--runtime-arg -classpath "); commandBuilder.append("--runtime-arg ").append(programName).append(" "); commandBuilder.append("--dex-file=").append(programName).append(" "); commandBuilder.append("--compiler-filter=interpret-only --runtime-arg -Xnorelocate "); - ExecutionResult verificationResult = executeCommand(commandBuilder.toString(), true); + ExecutionResult verificationResult = device.executeCommand(commandBuilder.toString(), true, + outputConsumer, errorConsumer); boolean success = true; @@ -232,17 +146,23 @@ public abstract class Executor { listener.handleFailedHostVerification(verificationResult); } - executeCommand("rm output.oat", false); + device.executeCommand("rm output.oat", false); return success; } /** * Called by the Fuzzer to upload the program to the target device. - * TODO: Check if we're executing on a local device, and don't do this? */ - public void uploadToTarget(String programName) { - pushToDevice(programName + " " + testLocation); + public void prepareProgramForExecution(String programName) { + if (!Options.executeOnHost) { + device.pushProgramToDevice(programName, testLocation); + } + + if (needsCleanCodeCache) { + // Get the device to clean the code cache + device.cleanCodeCache(architecture, testLocation, programName); + } } /** @@ -252,16 +172,6 @@ public abstract class Executor { public abstract void execute(String programName); /** - * Executor subclasses need to override this, to delete their generated OAT file correctly. - */ - public abstract void deleteGeneratedOatFile(String programName); - - /** - * Executor subclasses need to override this, to report if they need a cleaned code cache. - */ - public abstract boolean needsCleanCodeCache(); - - /** * Fuzzer.checkForArchitectureSplit() will use this determine the architecture of the Executor. */ public Architecture getArchitecture() { @@ -269,14 +179,6 @@ public abstract class Executor { } /** - * Used in each subclass of Executor's deleteGeneratedOatFile() method, to know what to delete. - */ - protected String getOatFileName(String programName) { - // Converts e.g. /data/art-test/file.dex to data@art-test@file.dex - return (testLocation.replace("/", "@").substring(1) + "@" + programName); - } - - /** * Used by the Fuzzer to get result of execution. */ public ExecutionResult getResult() { @@ -289,9 +191,10 @@ public abstract class Executor { * a target verification failure, before doing anything else with the resulting output. * Used by the Fuzzer. */ - public boolean verifyOnTarget() { + public boolean didTargetVerify() { // TODO: Remove this once host-verification can be forced to always fail? - if (executionResult.getFlattenedOutput().contains("VerifyError")) { + String output = executionResult.getFlattenedAll(); + if (output.contains("VerifyError") || output.contains("Verification failed on class")) { return false; } return true; @@ -300,4 +203,8 @@ public abstract class Executor { public String getName() { return name; } + + public void finishedWithProgramOnDevice() { + device.resetProgramPushed(); + } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64InterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64InterpreterExecutor.java index 9f27b5e..f319201 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Mips64InterpreterExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64InterpreterExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class Mips64InterpreterExecutor extends Executor { public Mips64InterpreterExecutor(BaseListener listener, Device device) { - super("MIPS64 Interpreter", 30, listener, Architecture.MIPS64, device); + super("MIPS64 Interpreter", 30, listener, Architecture.MIPS64, device, false); } @Override @@ -30,18 +30,7 @@ public class Mips64InterpreterExecutor extends Executor { commandBuilder.append("dalvikvm64 -Xint "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/mips64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return false; - } }
\ No newline at end of file diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java index b30240d..a6784e6 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class Mips64OptimizingBackendExecutor extends Executor { public Mips64OptimizingBackendExecutor(BaseListener listener, Device device) { - super("MIPS64 Optimizing Backend", 5, listener, Architecture.MIPS64, device); + super("MIPS64 Optimizing Backend", 5, listener, Architecture.MIPS64, device, true); } @Override @@ -30,17 +30,6 @@ public class Mips64OptimizingBackendExecutor extends Executor { commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Optimizing "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/mips64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java index 42ccd1e..bebf27c 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class Mips64QuickBackendExecutor extends Executor { public Mips64QuickBackendExecutor(BaseListener listener, Device device) { - super("MIPS64 Quick Backend", 5, listener, Architecture.MIPS64, device); + super("MIPS64 Quick Backend", 5, listener, Architecture.MIPS64, device, true); } @Override @@ -30,17 +30,6 @@ public class Mips64QuickBackendExecutor extends Executor { commandBuilder.append("dalvikvm64 "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/mips64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsInterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsInterpreterExecutor.java index 524eaa9..4268c76 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/MipsInterpreterExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/MipsInterpreterExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class MipsInterpreterExecutor extends Executor { public MipsInterpreterExecutor(BaseListener listener, Device device) { - super("MIPS Interpreter", 30, listener, Architecture.MIPS, device); + super("MIPS Interpreter", 30, listener, Architecture.MIPS, device, false); } @Override @@ -30,17 +30,6 @@ public class MipsInterpreterExecutor extends Executor { commandBuilder.append("dalvikvm32 -Xint "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/mips/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return false; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java index fcc92c8..d64b1ce 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class MipsOptimizingBackendExecutor extends Executor { public MipsOptimizingBackendExecutor(BaseListener listener, Device device) { - super("MIPS Optimizing Backend", 5, listener, Architecture.MIPS, device); + super("MIPS Optimizing Backend", 5, listener, Architecture.MIPS, device, true); } @Override @@ -30,17 +30,6 @@ public class MipsOptimizingBackendExecutor extends Executor { commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Optimizing "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/mips/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java index cb442f9..a534866 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class MipsQuickBackendExecutor extends Executor { public MipsQuickBackendExecutor(BaseListener listener, Device device) { - super("MIPS Quick Backend", 5, listener, Architecture.MIPS, device); + super("MIPS Quick Backend", 5, listener, Architecture.MIPS, device, true); } @Override @@ -30,17 +30,6 @@ public class MipsQuickBackendExecutor extends Executor { commandBuilder.append("dalvikvm32 "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/mips/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86InterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86InterpreterExecutor.java index 93c14e9..510f0d0 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/X86InterpreterExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/X86InterpreterExecutor.java @@ -16,31 +16,24 @@ package dexfuzz.executors; +import dexfuzz.Options; import dexfuzz.listeners.BaseListener; public class X86InterpreterExecutor extends Executor { public X86InterpreterExecutor(BaseListener listener, Device device) { - super("x86 Interpreter", 30, listener, Architecture.X86, device); + super("x86 Interpreter", 30, listener, Architecture.X86, device, false); } @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); commandBuilder.append("dalvikvm32 -Xint "); + if (Options.executeOnHost) { + commandBuilder.append(device.getHostExecutionFlags()).append(" "); + } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/x86/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return false; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java index b27d5ca..81d7285 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java @@ -16,31 +16,24 @@ package dexfuzz.executors; +import dexfuzz.Options; import dexfuzz.listeners.BaseListener; public class X86OptimizingBackendExecutor extends Executor { public X86OptimizingBackendExecutor(BaseListener listener, Device device) { - super("x86 Optimizing Backend", 5, listener, Architecture.X86, device); + super("x86 Optimizing Backend", 5, listener, Architecture.X86, device, true); } @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Optimizing "); + if (Options.executeOnHost) { + commandBuilder.append(device.getHostExecutionFlags()).append(" "); + } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/x86/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java index d8ec217..4a68bde 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java @@ -16,31 +16,24 @@ package dexfuzz.executors; +import dexfuzz.Options; import dexfuzz.listeners.BaseListener; public class X86QuickBackendExecutor extends Executor { public X86QuickBackendExecutor(BaseListener listener, Device device) { - super("x86 Quick Backend", 5, listener, Architecture.X86, device); + super("x86 Quick Backend", 5, listener, Architecture.X86, device, true); } @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); commandBuilder.append("dalvikvm32 "); + if (Options.executeOnHost) { + commandBuilder.append(device.getHostExecutionFlags()).append(" "); + } commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/x86/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64InterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64InterpreterExecutor.java index 7497322..dc55a41 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/X86_64InterpreterExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64InterpreterExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class X86_64InterpreterExecutor extends Executor { public X86_64InterpreterExecutor(BaseListener listener, Device device) { - super("x86_64 Interpreter", 30, listener, Architecture.X86_64, device); + super("x86_64 Interpreter", 30, listener, Architecture.X86_64, device, false); } @Override @@ -30,17 +30,6 @@ public class X86_64InterpreterExecutor extends Executor { commandBuilder.append("dalvikvm64 -Xint "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/x86_64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return false; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java index a978f73..2a01c6c 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class X86_64OptimizingBackendExecutor extends Executor { public X86_64OptimizingBackendExecutor(BaseListener listener, Device device) { - super("x86_64 Optimizing Backend", 5, listener, Architecture.X86_64, device); + super("x86_64 Optimizing Backend", 5, listener, Architecture.X86_64, device, true); } @Override @@ -30,17 +30,6 @@ public class X86_64OptimizingBackendExecutor extends Executor { commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Optimizing "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/x86_64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java index 85532d8..9579b76 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java @@ -21,7 +21,7 @@ import dexfuzz.listeners.BaseListener; public class X86_64QuickBackendExecutor extends Executor { public X86_64QuickBackendExecutor(BaseListener listener, Device device) { - super("x86_64 Quick Backend", 5, listener, Architecture.X86_64, device); + super("x86_64 Quick Backend", 5, listener, Architecture.X86_64, device, true); } @Override @@ -30,17 +30,6 @@ public class X86_64QuickBackendExecutor extends Executor { commandBuilder.append("dalvikvm64 "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); - executionResult = executeOnDevice(commandBuilder.toString(), true); - } - - @Override - public void deleteGeneratedOatFile(String programName) { - String command = "rm -f /data/dalvik-cache/x86_64/" + getOatFileName(programName); - executeOnDevice(command, false); - } - - @Override - public boolean needsCleanCodeCache() { - return true; + executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); } } diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java b/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java index 4c1acdb..bc39d79 100644 --- a/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java +++ b/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java @@ -158,7 +158,7 @@ public abstract class Fuzzer { protected void addExecutors() { Device device = null; - if (Options.local) { + if (Options.executeOnHost) { device = new Device(); } else { device = new Device(Options.deviceName, Options.noBootImage); @@ -241,27 +241,22 @@ public abstract class Fuzzer { String programName = getNextOutputFilename(); boolean verified = true; - if (!Options.skipHostVerify) { + + if (!Options.skipHostVerify && !Options.executeOnHost) { verified = goldenExecutor.verifyOnHost(programName); + if (verified) { + listener.handleSuccessfulHostVerification(); + } } + if (verified) { boolean skipAnalysis = false; - boolean uploadedToTarget = false; - if (!Options.skipHostVerify) { - listener.handleSuccessfulHostVerification(); - } + for (Executor executor : executors) { executor.reset(); - if (!uploadedToTarget) { - executor.uploadToTarget(programName); - } else { - uploadedToTarget = true; - } - if (executor.needsCleanCodeCache()) { - executor.deleteGeneratedOatFile(programName); - } + executor.prepareProgramForExecution(programName); executor.execute(programName); - if (!executor.verifyOnTarget()) { + if (!executor.didTargetVerify()) { listener.handleFailedTargetVerification(); skipAnalysis = true; break; @@ -275,6 +270,8 @@ public abstract class Fuzzer { analyseResults(program, programName); } } + + goldenExecutor.finishedWithProgramOnDevice(); mutatedSuccessfully = false; savedSuccessfully = false; } |