1/* 2 * Copyright 2012, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32package org.jf.dexlib2.util; 33 34import org.jf.dexlib2.iface.instruction.Instruction; 35import org.jf.dexlib2.iface.instruction.OneRegisterInstruction; 36import org.jf.dexlib2.iface.instruction.WideLiteralInstruction; 37import org.jf.dexlib2.Opcodes; 38 39import java.util.List; 40 41public class SyntheticAccessorFSM { 42 %% machine SyntheticAccessorFSM; 43 %% write data; 44 45 // math type constants 46 public static final int ADD = SyntheticAccessorResolver.ADD_ASSIGNMENT; 47 public static final int SUB = SyntheticAccessorResolver.SUB_ASSIGNMENT; 48 public static final int MUL = SyntheticAccessorResolver.MUL_ASSIGNMENT; 49 public static final int DIV = SyntheticAccessorResolver.DIV_ASSIGNMENT; 50 public static final int REM = SyntheticAccessorResolver.REM_ASSIGNMENT; 51 public static final int AND = SyntheticAccessorResolver.AND_ASSIGNMENT; 52 public static final int OR = SyntheticAccessorResolver.OR_ASSIGNMENT; 53 public static final int XOR = SyntheticAccessorResolver.XOR_ASSIGNMENT; 54 public static final int SHL = SyntheticAccessorResolver.SHL_ASSIGNMENT; 55 public static final int SHR = SyntheticAccessorResolver.SHR_ASSIGNMENT; 56 public static final int USHR = SyntheticAccessorResolver.USHR_ASSIGNMENT; 57 58 public static final int INT = 0; 59 public static final int LONG = 1; 60 public static final int FLOAT = 2; 61 public static final int DOUBLE = 3; 62 63 public static final int POSITIVE_ONE = 1; 64 public static final int NEGATIVE_ONE = -1; 65 public static final int OTHER = 0; 66 67 @Nonnull private final Opcodes opcodes; 68 69 public SyntheticAccessorFSM(@Nonnull Opcodes opcodes) { 70 this.opcodes = opcodes; 71 } 72 73 public int test(List<? extends Instruction> instructions) { 74 int accessorType = -1; 75 int cs, p = 0; 76 int pe = instructions.size(); 77 78 // one of the math type constants representing the type of math operation being performed 79 int mathOp = -1; 80 81 // for increments an decrements, the type of value the math operation is on 82 int mathType = -1; 83 84 // for increments and decrements, the value of the constant that is used 85 long constantValue = 0; 86 87 // The source register for the put instruction 88 int putRegister = -1; 89 // The return register; 90 int returnRegister = -1; 91 92 %%{ 93 import "Opcodes.rl"; 94 alphtype short; 95 getkey opcodes.getOpcodeValue(instructions.get(p).getOpcode()); 96 97 get = (0x52 .. 0x58) | (0x60 .. 0x66); # all igets/sgets 98 99 # all iputs/sputs 100 put = ((0x59 .. 0x5f) | (0x67 .. 0x6d)) @ { 101 putRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA(); 102 }; 103 104 invoke = (0x6e .. 0x72) | (0x74 .. 0x78); # all invokes 105 106 # all numeric const instructions 107 const_literal = (0x12 .. 0x19) @ { 108 constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral(); 109 }; 110 111 add_const = (add_int_lit8 | add_int_lit16) @ { 112 mathType = INT; 113 mathOp = ADD; 114 constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral(); 115 }; 116 117 arbitrary_add = (((add_int | add_int_2addr) @ { mathType = INT; }) | 118 ((add_long | add_long_2addr) @ { mathType = LONG; }) | 119 ((add_float | add_float_2addr) @ { mathType = FLOAT; }) | 120 ((add_double | add_double_2addr) @ {mathType = DOUBLE; })) @ { 121 mathOp = ADD; 122 }; 123 arbitrary_sub = (((sub_int | sub_int_2addr) @ { mathType = INT; }) | 124 ((sub_long | sub_long_2addr) @ { mathType = LONG; }) | 125 ((sub_float | sub_float_2addr) @ { mathType = FLOAT; }) | 126 ((sub_double | sub_double_2addr) @ {mathType = DOUBLE; })) @ { 127 mathOp = SUB; 128 }; 129 arbitrary_mul = (mul_int | mul_int_2addr | mul_long | mul_long_2addr | 130 mul_float | mul_float_2addr | mul_double | mul_double_2addr) @ { 131 mathOp = MUL; 132 }; 133 arbitrary_div = (div_int | div_int_2addr | div_long | div_long_2addr | 134 div_float | div_float_2addr | div_double | div_double_2addr) @ { 135 mathOp = DIV; 136 }; 137 arbitrary_rem = (rem_int | rem_int_2addr | rem_long | rem_long_2addr | 138 rem_float | rem_float_2addr | rem_double | rem_double_2addr) @ { 139 mathOp = REM; 140 }; 141 arbitrary_and = (and_int | and_int_2addr | and_long | and_long_2addr) @ { 142 mathOp = AND; 143 }; 144 arbitrary_or = (or_int | or_int_2addr | or_long | or_long_2addr) @ { 145 mathOp = OR; 146 }; 147 arbitrary_xor = (xor_int | xor_int_2addr | xor_long | xor_long_2addr) @ { 148 mathOp = XOR; 149 }; 150 arbitrary_shl = (shl_int | shl_int_2addr | shl_long | shl_long_2addr) @ { 151 mathOp = SHL; 152 }; 153 arbitrary_shr = (shr_int | shr_int_2addr | shr_long | shr_long_2addr) @ { 154 mathOp = SHR; 155 }; 156 arbitrary_ushr = (ushr_int | ushr_int_2addr | ushr_long | ushr_long_2addr) @ { 157 mathOp = USHR; 158 }; 159 160 type_conversion = 0x81 .. 0x8f; # all type-conversion opcodes 161 162 return_something = (return | return_wide | return_object) @ { 163 returnRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA(); 164 }; 165 166 any_move_result = move_result | move_result_wide | move_result_object; 167 168 get_accessor = get return_something @ { 169 accessorType = SyntheticAccessorResolver.GETTER; fbreak; 170 }; 171 172 put_accessor = put return_something @ { 173 accessorType = SyntheticAccessorResolver.SETTER; fbreak; 174 }; 175 176 invoke_accessor = invoke (return_void | (any_move_result return_something)) @ { 177 accessorType = SyntheticAccessorResolver.METHOD; fbreak; 178 }; 179 180 increment_accessor = get add_const type_conversion? put return_something @ { 181 accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister); 182 }; 183 184 alt_increment_accessor = get const_literal (arbitrary_add | arbitrary_sub) put return_something @ { 185 accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister); 186 }; 187 188 math_assignment_accessor = get type_conversion? 189 (arbitrary_add | arbitrary_sub | arbitrary_mul | arbitrary_div | arbitrary_rem | 190 arbitrary_and | arbitrary_or | arbitrary_xor | arbitrary_shl | arbitrary_shr | 191 arbitrary_ushr) 192 type_conversion{0,2} put return_something @ { 193 accessorType = mathOp; fbreak; 194 }; 195 196 main := get_accessor | 197 put_accessor | 198 invoke_accessor | 199 increment_accessor | 200 alt_increment_accessor | 201 math_assignment_accessor; 202 203 write init; 204 write exec; 205 }%% 206 207 return accessorType; 208 } 209 210 private static int getIncrementType(int mathOp, int mathType, long constantValue, int putRegister, 211 int returnRegister) { 212 boolean isPrefix = putRegister == returnRegister; 213 214 boolean negativeConstant = false; 215 216 switch (mathType) { 217 case INT: 218 case LONG: { 219 if (constantValue == 1) { 220 negativeConstant = false; 221 } else if (constantValue == -1) { 222 negativeConstant = true; 223 } else { 224 return -1; 225 } 226 break; 227 } 228 case FLOAT: { 229 float val = Float.intBitsToFloat((int)constantValue); 230 if (val == 1) { 231 negativeConstant = false; 232 } else if (val == -1) { 233 negativeConstant = true; 234 } else { 235 return -1; 236 } 237 break; 238 } 239 case DOUBLE: { 240 double val = Double.longBitsToDouble(constantValue); 241 if (val == 1) { 242 negativeConstant = false; 243 } else if (val == -1) { 244 negativeConstant = true; 245 } else { 246 return -1; 247 } 248 break; 249 } 250 } 251 252 boolean isAdd = ((mathOp == ADD) && !negativeConstant) || 253 ((mathOp == SUB) && negativeConstant); 254 255 if (isPrefix) { 256 if (isAdd) { 257 return SyntheticAccessorResolver.PREFIX_INCREMENT; 258 } else { 259 return SyntheticAccessorResolver.PREFIX_DECREMENT; 260 } 261 } else { 262 if (isAdd) { 263 return SyntheticAccessorResolver.POSTFIX_INCREMENT; 264 } else { 265 return SyntheticAccessorResolver.POSTFIX_DECREMENT; 266 } 267 } 268 } 269}