1 /* 2 * Copyright 2014, 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.smalidea.dexlib.instruction; 33 34 import com.google.common.base.Function; 35 import com.google.common.collect.Lists; 36 import com.intellij.psi.PsiType; 37 import org.jf.dexlib2.Opcode; 38 import org.jf.dexlib2.ReferenceType; 39 import org.jf.dexlib2.iface.instruction.Instruction; 40 import org.jf.dexlib2.iface.reference.Reference; 41 import org.jf.dexlib2.immutable.reference.ImmutableFieldReference; 42 import org.jf.dexlib2.immutable.reference.ImmutableMethodReference; 43 import org.jf.dexlib2.immutable.reference.ImmutableStringReference; 44 import org.jf.dexlib2.immutable.reference.ImmutableTypeReference; 45 import org.jf.smalidea.psi.impl.*; 46 import org.jf.smalidea.util.NameUtils; 47 import org.jf.smalidea.util.StringUtils; 48 49 import javax.annotation.Nonnull; 50 import javax.annotation.Nullable; 51 import java.util.List; 52 53 public abstract class SmalideaInstruction implements Instruction { 54 @Nonnull protected final SmaliInstruction psiInstruction; 55 56 protected SmalideaInstruction(@Nonnull SmaliInstruction instruction) { 57 this.psiInstruction = instruction; 58 } 59 60 @Nonnull 61 public static SmalideaInstruction of(SmaliInstruction instruction) { 62 switch (instruction.getOpcode().format) { 63 case Format10t: 64 return new SmalideaInstruction10t(instruction); 65 case Format10x: 66 return new SmalideaInstruction10x(instruction); 67 case Format11n: 68 return new SmalideaInstruction11n(instruction); 69 case Format11x: 70 return new SmalideaInstruction11x(instruction); 71 case Format12x: 72 return new SmalideaInstruction12x(instruction); 73 case Format20t: 74 return new SmalideaInstruction20t(instruction); 75 case Format21c: 76 return new SmalideaInstruction21c(instruction); 77 case Format21ih: 78 return new SmalideaInstruction21ih(instruction); 79 case Format21lh: 80 return new SmalideaInstruction21lh(instruction); 81 case Format21s: 82 return new SmalideaInstruction21s(instruction); 83 case Format21t: 84 return new SmalideaInstruction21t(instruction); 85 case Format22b: 86 return new SmalideaInstruction22b(instruction); 87 case Format22c: 88 return new SmalideaInstruction22c(instruction); 89 case Format22s: 90 return new SmalideaInstruction22s(instruction); 91 case Format22t: 92 return new SmalideaInstruction22t(instruction); 93 case Format22x: 94 return new SmalideaInstruction22x(instruction); 95 case Format23x: 96 return new SmalideaInstruction23x(instruction); 97 case Format30t: 98 return new SmalideaInstruction30t(instruction); 99 case Format31c: 100 return new SmalideaInstruction31c(instruction); 101 case Format31i: 102 return new SmalideaInstruction31i(instruction); 103 case Format31t: 104 return new SmalideaInstruction31t(instruction); 105 case Format32x: 106 return new SmalideaInstruction32x(instruction); 107 case Format35c: 108 return new SmalideaInstruction35c(instruction); 109 case Format3rc: 110 return new SmalideaInstruction3rc(instruction); 111 case Format51l: 112 return new SmalideaInstruction51l(instruction); 113 case PackedSwitchPayload: 114 return new SmalideaPackedSwitchPayload(instruction); 115 case SparseSwitchPayload: 116 return new SmalideaSparseSwitchPayload(instruction); 117 case ArrayPayload: 118 return new SmalideaArrayPayload(instruction); 119 default: 120 throw new RuntimeException("Unexpected instruction type"); 121 } 122 } 123 124 @Nonnull public Opcode getOpcode() { 125 return psiInstruction.getOpcode(); 126 } 127 128 public int getCodeUnits() { 129 return getOpcode().format.size / 2; 130 } 131 132 public int getCodeOffset() { 133 SmaliLabelReference labelReference = psiInstruction.getTarget(); 134 if (labelReference == null) { 135 return -1; 136 } 137 138 SmaliLabel label = labelReference.resolve(); 139 if (label == null) { 140 return -1; 141 } 142 return (label.getOffset() - psiInstruction.getOffset())/2; 143 } 144 145 public int getRegisterCount() { 146 return psiInstruction.getRegisterCount(); 147 } 148 149 public int getRegisterA() { 150 return psiInstruction.getRegister(0); 151 } 152 153 public int getRegisterB() { 154 return psiInstruction.getRegister(1); 155 } 156 157 public int getRegisterC() { 158 return psiInstruction.getRegister(2); 159 } 160 161 public int getNarrowLiteral() { 162 SmaliLiteral literal = psiInstruction.getLiteral(); 163 if (literal == null) { 164 return 0; 165 } 166 return (int)literal.getIntegralValue(); 167 } 168 169 public long getWideLiteral() { 170 SmaliLiteral literal = psiInstruction.getLiteral(); 171 if (literal == null) { 172 return 0; 173 } 174 return literal.getIntegralValue(); 175 } 176 177 @Nonnull public Reference getReference() { 178 switch (getReferenceType()) { 179 case ReferenceType.STRING: 180 return new ImmutableStringReference(StringUtils.parseQuotedString( 181 psiInstruction.getLiteral().getText())); 182 case ReferenceType.TYPE: 183 SmaliTypeElement typeReference = psiInstruction.getTypeReference(); 184 assert typeReference != null; 185 return new ImmutableTypeReference(typeReference.getText()); 186 case ReferenceType.METHOD: 187 SmaliMethodReference methodReference = psiInstruction.getMethodReference(); 188 assert methodReference != null; 189 String containingClass = methodReference.getContainingType().getText(); 190 List<String> paramTypes = 191 Lists.transform(methodReference.getParameterTypes(), new Function<PsiType, String>() { 192 @Nullable @Override public String apply(@Nullable PsiType psiType) { 193 if (psiType == null) { 194 return null; 195 } 196 return NameUtils.javaToSmaliType(psiType); 197 } 198 }); 199 200 return new ImmutableMethodReference(containingClass, 201 methodReference.getName(), 202 paramTypes, 203 methodReference.getReturnType().getText()); 204 case ReferenceType.FIELD: 205 SmaliFieldReference fieldReference = psiInstruction.getFieldReference(); 206 assert fieldReference != null; 207 containingClass = fieldReference.getContainingType().getText(); 208 return new ImmutableFieldReference(containingClass, 209 fieldReference.getName(), 210 fieldReference.getFieldType().getText()); 211 } 212 assert false; 213 return null; 214 } 215 216 public int getReferenceType() { 217 return psiInstruction.getOpcode().referenceType; 218 } 219 220 }