1 /* 2 * Copyright 2013, 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 32 package org.jf.dexlib2.analysis; 33 34 import org.jf.dexlib2.Opcode; 35 36 import javax.annotation.Nonnull; 37 38 public class OdexedFieldInstructionMapper { 39 private static Opcode[][][][] opcodeMap = new Opcode[][][][] { 40 //get opcodes 41 new Opcode[][][] { 42 //iget quick 43 new Opcode[][] { 44 //odexed 45 new Opcode[] { 46 /*Z*/ Opcode.IGET_QUICK, 47 /*B*/ Opcode.IGET_QUICK, 48 /*S*/ Opcode.IGET_QUICK, 49 /*C*/ Opcode.IGET_QUICK, 50 /*I,F*/ Opcode.IGET_QUICK, 51 /*J,D*/ Opcode.IGET_WIDE_QUICK, 52 /*L,[*/ Opcode.IGET_OBJECT_QUICK 53 }, 54 //deodexed 55 new Opcode[] { 56 /*Z*/ Opcode.IGET_BOOLEAN, 57 /*B*/ Opcode.IGET_BYTE, 58 /*S*/ Opcode.IGET_SHORT, 59 /*C*/ Opcode.IGET_CHAR, 60 /*I,F*/ Opcode.IGET, 61 /*J,D*/ Opcode.IGET_WIDE, 62 /*L,[*/ Opcode.IGET_OBJECT 63 } 64 }, 65 //iget volatile 66 new Opcode[][] { 67 //odexed 68 new Opcode[] { 69 /*Z*/ Opcode.IGET_VOLATILE, 70 /*B*/ Opcode.IGET_VOLATILE, 71 /*S*/ Opcode.IGET_VOLATILE, 72 /*C*/ Opcode.IGET_VOLATILE, 73 /*I,F*/ Opcode.IGET_VOLATILE, 74 /*J,D*/ Opcode.IGET_WIDE_VOLATILE, 75 /*L,[*/ Opcode.IGET_OBJECT_VOLATILE 76 }, 77 //deodexed 78 new Opcode[] { 79 /*Z*/ Opcode.IGET_BOOLEAN, 80 /*B*/ Opcode.IGET_BYTE, 81 /*S*/ Opcode.IGET_SHORT, 82 /*C*/ Opcode.IGET_CHAR, 83 /*I,F*/ Opcode.IGET, 84 /*J,D*/ Opcode.IGET_WIDE, 85 /*L,[*/ Opcode.IGET_OBJECT 86 } 87 }, 88 //sget volatile 89 new Opcode[][] { 90 //odexed 91 new Opcode[] { 92 /*Z*/ Opcode.SGET_VOLATILE, 93 /*B*/ Opcode.SGET_VOLATILE, 94 /*S*/ Opcode.SGET_VOLATILE, 95 /*C*/ Opcode.SGET_VOLATILE, 96 /*I,F*/ Opcode.SGET_VOLATILE, 97 /*J,D*/ Opcode.SGET_WIDE_VOLATILE, 98 /*L,[*/ Opcode.SGET_OBJECT_VOLATILE 99 }, 100 //deodexed 101 new Opcode[] { 102 /*Z*/ Opcode.SGET_BOOLEAN, 103 /*B*/ Opcode.SGET_BYTE, 104 /*S*/ Opcode.SGET_SHORT, 105 /*C*/ Opcode.SGET_CHAR, 106 /*I,F*/ Opcode.SGET, 107 /*J,D*/ Opcode.SGET_WIDE, 108 /*L,[*/ Opcode.SGET_OBJECT 109 } 110 } 111 }, 112 //put opcodes 113 new Opcode[][][] { 114 //iput quick 115 new Opcode[][] { 116 //odexed 117 new Opcode[] { 118 /*Z*/ Opcode.IPUT_QUICK, 119 /*B*/ Opcode.IPUT_QUICK, 120 /*S*/ Opcode.IPUT_QUICK, 121 /*C*/ Opcode.IPUT_QUICK, 122 /*I,F*/ Opcode.IPUT_QUICK, 123 /*J,D*/ Opcode.IPUT_WIDE_QUICK, 124 /*L,[*/ Opcode.IPUT_OBJECT_QUICK 125 }, 126 //deodexed 127 new Opcode[] { 128 /*Z*/ Opcode.IPUT_BOOLEAN, 129 /*B*/ Opcode.IPUT_BYTE, 130 /*S*/ Opcode.IPUT_SHORT, 131 /*C*/ Opcode.IPUT_CHAR, 132 /*I,F*/ Opcode.IPUT, 133 /*J,D*/ Opcode.IPUT_WIDE, 134 /*L,[*/ Opcode.IPUT_OBJECT 135 } 136 }, 137 //iput volatile 138 new Opcode[][] { 139 //odexed 140 new Opcode[] { 141 /*Z*/ Opcode.IPUT_VOLATILE, 142 /*B*/ Opcode.IPUT_VOLATILE, 143 /*S*/ Opcode.IPUT_VOLATILE, 144 /*C*/ Opcode.IPUT_VOLATILE, 145 /*I,F*/ Opcode.IPUT_VOLATILE, 146 /*J,D*/ Opcode.IPUT_WIDE_VOLATILE, 147 /*L,[*/ Opcode.IPUT_OBJECT_VOLATILE 148 }, 149 //deodexed 150 new Opcode[] { 151 /*Z*/ Opcode.IPUT_BOOLEAN, 152 /*B*/ Opcode.IPUT_BYTE, 153 /*S*/ Opcode.IPUT_SHORT, 154 /*C*/ Opcode.IPUT_CHAR, 155 /*I,F*/ Opcode.IPUT, 156 /*J,D*/ Opcode.IPUT_WIDE, 157 /*L,[*/ Opcode.IPUT_OBJECT 158 } 159 }, 160 //sput volatile 161 new Opcode[][] { 162 //odexed 163 new Opcode[] { 164 /*Z*/ Opcode.SPUT_VOLATILE, 165 /*B*/ Opcode.SPUT_VOLATILE, 166 /*S*/ Opcode.SPUT_VOLATILE, 167 /*C*/ Opcode.SPUT_VOLATILE, 168 /*I,F*/ Opcode.SPUT_VOLATILE, 169 /*J,D*/ Opcode.SPUT_WIDE_VOLATILE, 170 /*L,[*/ Opcode.SPUT_OBJECT_VOLATILE 171 }, 172 //deodexed 173 new Opcode[] { 174 /*Z*/ Opcode.SPUT_BOOLEAN, 175 /*B*/ Opcode.SPUT_BYTE, 176 /*S*/ Opcode.SPUT_SHORT, 177 /*C*/ Opcode.SPUT_CHAR, 178 /*I,F*/ Opcode.SPUT, 179 /*J,D*/ Opcode.SPUT_WIDE, 180 /*L,[*/ Opcode.SPUT_OBJECT 181 } 182 } 183 } 184 }; 185 186 private static int getTypeIndex(char type) { 187 switch (type) { 188 case 'Z': 189 return 0; 190 case 'B': 191 return 1; 192 case 'S': 193 return 2; 194 case 'C': 195 return 3; 196 case 'I': 197 case 'F': 198 return 4; 199 case 'J': 200 case 'D': 201 return 5; 202 case 'L': 203 case '[': 204 return 6; 205 default: 206 } 207 throw new RuntimeException(String.format("Unknown type %s: ", type)); 208 } 209 210 private static int getOpcodeSubtype(@Nonnull Opcode opcode) { 211 if (opcode.isOdexedInstanceQuick()) { 212 return 0; 213 } else if (opcode.isOdexedInstanceVolatile()) { 214 return 1; 215 } else if (opcode.isOdexedStaticVolatile()) { 216 return 2; 217 } 218 throw new RuntimeException(String.format("Not an odexed field access opcode: %s", opcode.name)); 219 } 220 221 @Nonnull 222 static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(@Nonnull String fieldType, @Nonnull Opcode odexedOpcode) { 223 int opcodeType = odexedOpcode.setsRegister()?0:1; 224 int opcodeSubType = getOpcodeSubtype(odexedOpcode); 225 int typeIndex = getTypeIndex(fieldType.charAt(0)); 226 227 Opcode correctOdexedOpcode, deodexedOpcode; 228 229 correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex]; 230 deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex]; 231 232 if (correctOdexedOpcode != odexedOpcode) { 233 throw new AnalysisException(String.format("Incorrect field type \"%s\" for %s", fieldType, 234 odexedOpcode.name)); 235 } 236 237 return deodexedOpcode; 238 } 239 } 240 241 242