Home | History | Annotate | Download | only in smali
      1 /*
      2  * Copyright 2016, 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.smali;import com.google.common.collect.Lists;
     33 import com.google.common.collect.Maps;
     34 import junit.framework.Assert;
     35 import org.antlr.runtime.RecognitionException;
     36 import org.jf.dexlib2.Opcode;
     37 import org.jf.dexlib2.ValueType;
     38 import org.jf.dexlib2.iface.ClassDef;
     39 import org.jf.dexlib2.iface.Field;
     40 import org.jf.dexlib2.iface.Method;
     41 import org.jf.dexlib2.iface.MethodImplementation;
     42 import org.jf.dexlib2.iface.instruction.Instruction;
     43 import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
     44 import org.jf.dexlib2.iface.instruction.formats.Instruction35c;
     45 import org.jf.dexlib2.iface.reference.FieldReference;
     46 import org.jf.dexlib2.iface.reference.MethodReference;
     47 import org.jf.dexlib2.iface.value.FieldEncodedValue;
     48 import org.jf.dexlib2.iface.value.MethodEncodedValue;
     49 import org.jf.dexlib2.iface.value.TypeEncodedValue;
     50 import org.jf.smali.SmaliTestUtils;
     51 import org.junit.Test;
     52 
     53 import java.io.IOException;
     54 import java.util.List;
     55 import java.util.Map;
     56 
     57 /**
     58  * Tests for method/field references that use an implicit type
     59  */
     60 public class ImplicitReferenceTest extends SmaliTestUtils {
     61     @Test
     62     public void testImplicitMethodReference() throws RecognitionException, IOException {
     63         ClassDef classDef = SmaliTestUtils.compileSmali("" +
     64                 ".class public LHelloWorld;\n" +
     65                 ".super Ljava/lang/Object;\n" +
     66                 ".method public static main([Ljava/lang/String;)V\n" +
     67                 "    .registers 1\n" +
     68                 "    invoke-static {p0}, toString()V\n" +
     69                 "    invoke-static {p0}, V()V\n" +
     70                 "    invoke-static {p0}, I()V\n" +
     71                 "    return-void\n" +
     72                 ".end method");
     73 
     74         Method mainMethod = null;
     75         for (Method method: classDef.getMethods()) {
     76             if (method.getName().equals("main")) {
     77                 mainMethod = method;
     78             }
     79         }
     80         Assert.assertNotNull(mainMethod);
     81 
     82         MethodImplementation methodImpl = mainMethod.getImplementation();
     83         Assert.assertNotNull(methodImpl);
     84 
     85         List<Instruction> instructions = Lists.newArrayList(methodImpl.getInstructions());
     86 
     87         Instruction35c instruction = (Instruction35c)instructions.get(0);
     88         Assert.assertNotNull(instruction);
     89         Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode());
     90         MethodReference method = (MethodReference)instruction.getReference();
     91         Assert.assertEquals(classDef.getType(), method.getDefiningClass());
     92         Assert.assertEquals("toString", method.getName());
     93 
     94         instruction = (Instruction35c)instructions.get(1);
     95         Assert.assertNotNull(instruction);
     96         Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode());
     97         method = (MethodReference)instruction.getReference();
     98         Assert.assertEquals(classDef.getType(), method.getDefiningClass());
     99         Assert.assertEquals("V", method.getName());
    100 
    101         instruction = (Instruction35c)instructions.get(2);
    102         Assert.assertNotNull(instruction);
    103         Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode());
    104         method = (MethodReference)instruction.getReference();
    105         Assert.assertEquals(classDef.getType(), method.getDefiningClass());
    106         Assert.assertEquals("I", method.getName());
    107     }
    108 
    109     @Test
    110     public void testImplicitMethodLiteral() throws RecognitionException, IOException {
    111         ClassDef classDef = SmaliTestUtils.compileSmali("" +
    112                 ".class public LHelloWorld;\n" +
    113                 ".super Ljava/lang/Object;\n" +
    114                 ".field public static field1:Ljava/lang/reflect/Method; = toString()V\n" +
    115                 ".field public static field2:Ljava/lang/reflect/Method; = V()V\n" +
    116                 ".field public static field3:Ljava/lang/reflect/Method; = I()V\n" +
    117                 ".field public static field4:Ljava/lang/Class; = I");
    118 
    119         Map<String, Field> fields = Maps.newHashMap();
    120         for (Field field: classDef.getFields()) {
    121             fields.put(field.getName(), field);
    122         }
    123 
    124         Field field = fields.get("field1");
    125         Assert.assertNotNull(field);
    126         Assert.assertNotNull(field.getInitialValue());
    127         Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType());
    128         MethodEncodedValue methodEncodedValue = (MethodEncodedValue)field.getInitialValue();
    129         Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass());
    130         Assert.assertEquals("toString", methodEncodedValue.getValue().getName());
    131 
    132         field = fields.get("field2");
    133         Assert.assertNotNull(field);
    134         Assert.assertNotNull(field.getInitialValue());
    135         Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType());
    136         methodEncodedValue = (MethodEncodedValue)field.getInitialValue();
    137         Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass());
    138         Assert.assertEquals("V", methodEncodedValue.getValue().getName());
    139 
    140         field = fields.get("field3");
    141         Assert.assertNotNull(field);
    142         Assert.assertNotNull(field.getInitialValue());
    143         Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType());
    144         methodEncodedValue = (MethodEncodedValue)field.getInitialValue();
    145         Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass());
    146         Assert.assertEquals("I", methodEncodedValue.getValue().getName());
    147 
    148         field = fields.get("field4");
    149         Assert.assertNotNull(field);
    150         Assert.assertNotNull(field.getInitialValue());
    151         Assert.assertEquals(ValueType.TYPE, field.getInitialValue().getValueType());
    152         TypeEncodedValue typeEncodedValue = (TypeEncodedValue)field.getInitialValue();
    153         Assert.assertEquals("I", typeEncodedValue.getValue());
    154     }
    155 
    156     @Test
    157     public void testImplicitFieldReference() throws RecognitionException, IOException {
    158         ClassDef classDef = SmaliTestUtils.compileSmali("" +
    159                 ".class public LHelloWorld;\n" +
    160                 ".super Ljava/lang/Object;\n" +
    161                 ".method public static main([Ljava/lang/String;)V\n" +
    162                 "    .registers 1\n" +
    163                 "    sget-object v0, someField:I\n" +
    164                 "    sget-object v0, V:I\n" +
    165                 "    sget-object v0, I:I\n" +
    166                 "    return-void\n" +
    167                 ".end method");
    168 
    169         Method mainMethod = null;
    170         for (Method method: classDef.getMethods()) {
    171             if (method.getName().equals("main")) {
    172                 mainMethod = method;
    173             }
    174         }
    175         Assert.assertNotNull(mainMethod);
    176 
    177         MethodImplementation methodImpl = mainMethod.getImplementation();
    178         Assert.assertNotNull(methodImpl);
    179 
    180         List<Instruction> instructions = Lists.newArrayList(methodImpl.getInstructions());
    181 
    182         Instruction21c instruction = (Instruction21c)instructions.get(0);
    183         Assert.assertNotNull(instruction);
    184         Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode());
    185         FieldReference field = (FieldReference)instruction.getReference();
    186         Assert.assertEquals(classDef.getType(), field.getDefiningClass());
    187         Assert.assertEquals("someField", field.getName());
    188 
    189         instruction = (Instruction21c)instructions.get(1);
    190         Assert.assertNotNull(instruction);
    191         Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode());
    192         field = (FieldReference)instruction.getReference();
    193         Assert.assertEquals(classDef.getType(), field.getDefiningClass());
    194         Assert.assertEquals("V", field.getName());
    195 
    196         instruction = (Instruction21c)instructions.get(2);
    197         Assert.assertNotNull(instruction);
    198         Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode());
    199         field = (FieldReference)instruction.getReference();
    200         Assert.assertEquals(classDef.getType(), field.getDefiningClass());
    201         Assert.assertEquals("I", field.getName());
    202     }
    203 
    204     @Test
    205     public void testImplicitFieldLiteral() throws RecognitionException, IOException {
    206         ClassDef classDef = SmaliTestUtils.compileSmali("" +
    207                 ".class public LHelloWorld;\n" +
    208                 ".super Ljava/lang/Object;\n" +
    209                 ".field public static field1:Ljava/lang/reflect/Field; = someField:I\n" +
    210                 ".field public static field2:Ljava/lang/reflect/Field; = V:I\n" +
    211                 ".field public static field3:Ljava/lang/reflect/Field; = I:I\n");
    212 
    213         Map<String, Field> fields = Maps.newHashMap();
    214         for (Field field: classDef.getFields()) {
    215             fields.put(field.getName(), field);
    216         }
    217 
    218         Field field = fields.get("field1");
    219         Assert.assertNotNull(field);
    220         Assert.assertNotNull(field.getInitialValue());
    221         Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType());
    222         FieldEncodedValue fieldEncodedValue = (FieldEncodedValue)field.getInitialValue();
    223         Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass());
    224         Assert.assertEquals("someField", fieldEncodedValue.getValue().getName());
    225 
    226         field = fields.get("field2");
    227         Assert.assertNotNull(field);
    228         Assert.assertNotNull(field.getInitialValue());
    229         Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType());
    230         fieldEncodedValue = (FieldEncodedValue)field.getInitialValue();
    231         Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass());
    232         Assert.assertEquals("V", fieldEncodedValue.getValue().getName());
    233 
    234         field = fields.get("field3");
    235         Assert.assertNotNull(field);
    236         Assert.assertNotNull(field.getInitialValue());
    237         Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType());
    238         fieldEncodedValue = (FieldEncodedValue)field.getInitialValue();
    239         Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass());
    240         Assert.assertEquals("I", fieldEncodedValue.getValue().getName());
    241     }
    242 }
    243