Home | History | Annotate | Download | only in instruction
      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 }