1959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/* 2959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Copyright (C) 2014 The Android Open Source Project 3959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 4959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Licensed under the Apache License, Version 2.0 (the "License"); 5959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * you may not use this file except in compliance with the License. 6959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * You may obtain a copy of the License at 7959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 8959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * http://www.apache.org/licenses/LICENSE-2.0 9959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 10959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Unless required by applicable law or agreed to in writing, software 11959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * distributed under the License is distributed on an "AS IS" BASIS, 12959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * See the License for the specific language governing permissions and 14959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * limitations under the License. 15959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 16959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 17959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepackage dexfuzz.program.mutators; 18959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 19959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.Log; 20959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.MutationStats; 21959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.program.MInsn; 22959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.program.MutatableCode; 23959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.program.Mutation; 24959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.Instruction; 25959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.Opcode; 26959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 27959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.ArrayList; 28959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.List; 29959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.Random; 30959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 31959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepublic class ConversionRepeater extends CodeMutator { 32959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 33959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Every CodeMutator has an AssociatedMutation, representing the 34959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * mutation that this CodeMutator can perform, to allow separate 35959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * generateMutation() and applyMutation() phases, allowing serialization. 36959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 37959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public static class AssociatedMutation extends Mutation { 38959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public int conversionInsnIdx; 39959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 40959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle @Override 41959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public String getString() { 42959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return Integer.toString(conversionInsnIdx); 43959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 44959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 45959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle @Override 46959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void parseString(String[] elements) { 47959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle conversionInsnIdx = Integer.parseInt(elements[2]); 48959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 49959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 50959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 51959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // The following two methods are here for the benefit of MutationSerializer, 52959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // so it can create a CodeMutator and get the correct associated Mutation, as it 53959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // reads in mutations from a dump of mutations. 54959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle @Override 55959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Mutation getNewMutation() { 56959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return new AssociatedMutation(); 57959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 58959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 59959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public ConversionRepeater() { } 60959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 61959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public ConversionRepeater(Random rng, MutationStats stats, List<Mutation> mutations) { 62959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle super(rng, stats, mutations); 63959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle likelihood = 50; 64959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 65959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 66959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // A cache that should only exist between generateMutation() and applyMutation(), 67959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // or be created at the start of applyMutation(), if we're reading in mutations from 68959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // a file. 69959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private List<MInsn> conversionInsns = null; 70959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 71959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void generateCachedConversionInsns(MutatableCode mutatableCode) { 72959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (conversionInsns != null) { 73959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return; 74959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 75959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 76959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle conversionInsns = new ArrayList<MInsn>(); 77959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 78959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MInsn mInsn : mutatableCode.getInstructions()) { 79959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (isConversionInstruction(mInsn)) { 80959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle conversionInsns.add(mInsn); 81959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 82959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 83959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 84959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 85959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle @Override 86959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle protected boolean canMutate(MutatableCode mutatableCode) { 87959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MInsn mInsn : mutatableCode.getInstructions()) { 88959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (isConversionInstruction(mInsn)) { 89959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return true; 90959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 91959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 92959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 93959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("No conversion operations in method, skipping..."); 94959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return false; 95959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 96959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 97959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle @Override 98959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle protected Mutation generateMutation(MutatableCode mutatableCode) { 99959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle generateCachedConversionInsns(mutatableCode); 100959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int conversionInsnIdx = rng.nextInt(conversionInsns.size()); 101959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle AssociatedMutation mutation = new AssociatedMutation(); 102959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutation.setup(this.getClass(), mutatableCode); 103959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutation.conversionInsnIdx = conversionInsnIdx; 104959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return mutation; 105959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 106959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 107959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle @Override 108959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle protected void applyMutation(Mutation uncastMutation) { 109959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Cast the Mutation to our AssociatedMutation, so we can access its fields. 110959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle AssociatedMutation mutation = (AssociatedMutation) uncastMutation; 111959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MutatableCode mutatableCode = mutation.mutatableCode; 112959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 113959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle generateCachedConversionInsns(mutatableCode); 114959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 115959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn originalInsn = conversionInsns.get(mutation.conversionInsnIdx); 116959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 117959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // We want to create two new instructions: 118959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // [original conversion] eg float-to-int 119959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // NEW: [there] eg int-to-float (with vregs of first inst swapped) 120959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // NEW: [back] eg float-to-int 121959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 122959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Create the "there" instruction. 123959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn newInsnThere = originalInsn.clone(); 124959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 125959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Flip the opcode. 126959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Opcode oppositeOpcode = null; 127959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle switch (newInsnThere.insn.info.opcode) { 128959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case INT_TO_LONG: 129959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.LONG_TO_INT; 130959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 131959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case INT_TO_FLOAT: 132959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.FLOAT_TO_INT; 133959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 134959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case INT_TO_DOUBLE: 135959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.DOUBLE_TO_INT; 136959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 137959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case LONG_TO_INT: 138959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.INT_TO_LONG; 139959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 140959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case LONG_TO_FLOAT: 141959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.FLOAT_TO_LONG; 142959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 143959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case LONG_TO_DOUBLE: 144959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.DOUBLE_TO_LONG; 145959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 146959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case FLOAT_TO_INT: 147959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.INT_TO_FLOAT; 148959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 149959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case FLOAT_TO_LONG: 150959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.LONG_TO_FLOAT; 151959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 152959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case FLOAT_TO_DOUBLE: 153959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.DOUBLE_TO_FLOAT; 154959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 155959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case DOUBLE_TO_INT: 156959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.INT_TO_DOUBLE; 157959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 158959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case DOUBLE_TO_LONG: 159959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.LONG_TO_DOUBLE; 160959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 161959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle case DOUBLE_TO_FLOAT: 162959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle oppositeOpcode = Opcode.FLOAT_TO_DOUBLE; 163959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 164959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle default: 165959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit( 166959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle "Trying to repeat the conversion in an insn that is not a conversion insn."); 167959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 168959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newInsnThere.insn.info = Instruction.getOpcodeInfo(oppositeOpcode); 169959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 170959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Swap the vregs. 171959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle long tempReg = newInsnThere.insn.vregA; 172959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newInsnThere.insn.vregA = newInsnThere.insn.vregB; 173959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newInsnThere.insn.vregB = tempReg; 174959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 175959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Create the "back" instruction. 176959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn newInsnBack = originalInsn.clone(); 177959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 178959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Get the index into the MutatableCode's mInsns list for this insn. 179959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int originalInsnIdx = mutatableCode.getInstructionIndex(originalInsn); 180959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 181959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Insert the new instructions. 182959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutatableCode.insertInstructionAfter(newInsnThere, originalInsnIdx); 183959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutatableCode.insertInstructionAfter(newInsnBack, originalInsnIdx + 1); 184959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 185959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.info("Performing conversion repetition for " + originalInsn); 186959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 187959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle stats.incrementStat("Repeating conversion"); 188959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 189959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Clear the cache. 190959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle conversionInsns = null; 191959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 192959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 193959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private boolean isConversionInstruction(MInsn mInsn) { 194959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Opcode opcode = mInsn.insn.info.opcode; 195959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (Opcode.isBetween(opcode, Opcode.INT_TO_LONG, Opcode.DOUBLE_TO_FLOAT)) { 196959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return true; 197959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 198959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return false; 199959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 200959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle} 201