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