Implement implicit method/field references in smali

This commit is contained in:
Ben Gruver 2014-07-19 18:53:53 -07:00 committed by Connor Tumbleson
parent 4801482960
commit 2772be8e9d
4 changed files with 396 additions and 49 deletions

View File

@ -686,22 +686,21 @@ enum_literal
type_field_method_literal
: reference_type_descriptor
( ARROW
( member_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor member_name nonvoid_type_descriptor)
| member_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor member_name method_prototype)
| ( (reference_type_descriptor ARROW)?
( member_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor? member_name nonvoid_type_descriptor)
| member_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor? member_name method_prototype)
)
| -> reference_type_descriptor
)
| PRIMITIVE_TYPE
| VOID_TYPE;
fully_qualified_method
: reference_type_descriptor ARROW member_name method_prototype
-> reference_type_descriptor member_name method_prototype;
method_reference
: (reference_type_descriptor ARROW)? member_name method_prototype
-> reference_type_descriptor? member_name method_prototype;
fully_qualified_field
: reference_type_descriptor ARROW member_name COLON nonvoid_type_descriptor
-> reference_type_descriptor member_name nonvoid_type_descriptor;
field_reference
: (reference_type_descriptor ARROW)? member_name COLON nonvoid_type_descriptor
-> reference_type_descriptor? member_name nonvoid_type_descriptor;
label
: COLON simple_name -> ^(I_LABEL[$COLON, "I_LABEL"] simple_name);
@ -717,7 +716,7 @@ register_range
: (startreg=REGISTER (DOTDOT endreg=REGISTER)?)? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] $startreg? $endreg?);
verification_error_reference
: CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method;
: CLASS_DESCRIPTOR | field_reference | method_reference;
catch_directive
: CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref
@ -890,18 +889,18 @@ insn_format20t
insn_format21c_field
: //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field
-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field);
INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA field_reference
-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER field_reference);
insn_format21c_field_odex
: //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream;
INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA fully_qualified_field
INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA field_reference
{
if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_FIELD_ODEX.text) == null || apiLevel >= 14) {
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT21c_FIELD_ODEX.text);
}
}
-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER fully_qualified_field);
-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER field_reference);
insn_format21c_string
: //e.g. const-string v1, "Hello World!"
@ -940,18 +939,18 @@ insn_format22b
insn_format22c_field
: //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field
-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field);
INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA field_reference
-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER field_reference);
insn_format22c_field_odex
: //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field
INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA field_reference
{
if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_FIELD_ODEX.text) == null || apiLevel >= 14) {
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22c_FIELD_ODEX.text);
}
}
-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER REGISTER fully_qualified_field);
-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER REGISTER field_reference);
insn_format22c_type
: //e.g. instance-of v0, v1, Ljava/lang/String;
@ -1012,8 +1011,8 @@ insn_format32x
insn_format35c_method
: //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
-> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list fully_qualified_method);
INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA method_reference
-> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list method_reference);
insn_format35c_type
: //e.g. filled-new-array {v0,v1}, I
@ -1022,7 +1021,7 @@ insn_format35c_type
insn_format35c_method_odex
: //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
INSTRUCTION_FORMAT35c_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
INSTRUCTION_FORMAT35c_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA method_reference
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35c_METHOD_ODEX.text);
};
@ -1043,12 +1042,12 @@ insn_format35ms_method
insn_format3rc_method
: //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method
-> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method);
INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA method_reference
-> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range method_reference);
insn_format3rc_method_odex
: //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA method_reference
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rc_METHOD_ODEX.text);
};

View File

@ -501,17 +501,29 @@ method_type_list returns[List<String> types]
)*;
fully_qualified_method returns[ImmutableMethodReference methodReference]
: reference_type_descriptor SIMPLE_NAME method_prototype
method_reference returns[ImmutableMethodReference methodReference]
: reference_type_descriptor? SIMPLE_NAME method_prototype
{
$methodReference = new ImmutableMethodReference($reference_type_descriptor.type, $SIMPLE_NAME.text,
String type;
if ($reference_type_descriptor.type == null) {
type = classType;
} else {
type = $reference_type_descriptor.type;
}
$methodReference = new ImmutableMethodReference(type, $SIMPLE_NAME.text,
$method_prototype.parameters, $method_prototype.returnType);
};
fully_qualified_field returns[ImmutableFieldReference fieldReference]
: reference_type_descriptor SIMPLE_NAME nonvoid_type_descriptor
field_reference returns[ImmutableFieldReference fieldReference]
: reference_type_descriptor? SIMPLE_NAME nonvoid_type_descriptor
{
$fieldReference = new ImmutableFieldReference($reference_type_descriptor.type, $SIMPLE_NAME.text,
String type;
if ($reference_type_descriptor.type == null) {
type = classType;
} else {
type = $reference_type_descriptor.type;
}
$fieldReference = new ImmutableFieldReference(type, $SIMPLE_NAME.text,
$nonvoid_type_descriptor.type);
};
@ -688,13 +700,13 @@ verification_error_reference returns[ImmutableReference reference]
{
$reference = new ImmutableTypeReference($CLASS_DESCRIPTOR.text);
}
| fully_qualified_field
| field_reference
{
$reference = $fully_qualified_field.fieldReference;
$reference = $field_reference.fieldReference;
}
| fully_qualified_method
| method_reference
{
$reference = $fully_qualified_method.methodReference;
$reference = $method_reference.methodReference;
};
verification_error_type returns[int verificationError]
@ -816,12 +828,12 @@ insn_format20t
insn_format21c_field
: //e.g. sget_object v0, java/lang/System/out LJava/io/PrintStream;
^(I_STATEMENT_FORMAT21c_FIELD inst=(INSTRUCTION_FORMAT21c_FIELD | INSTRUCTION_FORMAT21c_FIELD_ODEX) REGISTER fully_qualified_field)
^(I_STATEMENT_FORMAT21c_FIELD inst=(INSTRUCTION_FORMAT21c_FIELD | INSTRUCTION_FORMAT21c_FIELD_ODEX) REGISTER field_reference)
{
Opcode opcode = opcodes.getOpcodeByName($inst.text);
short regA = parseRegister_byte($REGISTER.text);
ImmutableFieldReference fieldReference = $fully_qualified_field.fieldReference;
ImmutableFieldReference fieldReference = $field_reference.fieldReference;
$method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
dexBuilder.internFieldReference(fieldReference)));
@ -911,13 +923,13 @@ insn_format22b
insn_format22c_field
: //e.g. iput-object v1, v0, org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
^(I_STATEMENT_FORMAT22c_FIELD inst=(INSTRUCTION_FORMAT22c_FIELD | INSTRUCTION_FORMAT22c_FIELD_ODEX) registerA=REGISTER registerB=REGISTER fully_qualified_field)
^(I_STATEMENT_FORMAT22c_FIELD inst=(INSTRUCTION_FORMAT22c_FIELD | INSTRUCTION_FORMAT22c_FIELD_ODEX) registerA=REGISTER registerB=REGISTER field_reference)
{
Opcode opcode = opcodes.getOpcodeByName($inst.text);
byte regA = parseRegister_nibble($registerA.text);
byte regB = parseRegister_nibble($registerB.text);
ImmutableFieldReference fieldReference = $fully_qualified_field.fieldReference;
ImmutableFieldReference fieldReference = $field_reference.fieldReference;
$method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB,
dexBuilder.internFieldReference(fieldReference)));
@ -1038,7 +1050,7 @@ insn_format32x
insn_format35c_method
: //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
^(I_STATEMENT_FORMAT35c_METHOD INSTRUCTION_FORMAT35c_METHOD register_list fully_qualified_method)
^(I_STATEMENT_FORMAT35c_METHOD INSTRUCTION_FORMAT35c_METHOD register_list method_reference)
{
Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT35c_METHOD.text);
@ -1046,7 +1058,7 @@ insn_format35c_method
byte[] registers = $register_list.registers;
byte registerCount = $register_list.registerCount;
ImmutableMethodReference methodReference = $fully_qualified_method.methodReference;
ImmutableMethodReference methodReference = $method_reference.methodReference;
$method::methodBuilder.addInstruction(new BuilderInstruction35c(opcode, registerCount, registers[0], registers[1],
registers[2], registers[3], registers[4], dexBuilder.internMethodReference(methodReference)));
@ -1068,7 +1080,7 @@ insn_format35c_type
insn_format3rc_method
: //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
^(I_STATEMENT_FORMAT3rc_METHOD INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method)
^(I_STATEMENT_FORMAT3rc_METHOD INSTRUCTION_FORMAT3rc_METHOD register_range method_reference)
{
Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT3rc_METHOD.text);
int startRegister = $register_range.startRegister;
@ -1076,7 +1088,7 @@ insn_format3rc_method
int registerCount = endRegister-startRegister+1;
ImmutableMethodReference methodReference = $fully_qualified_method.methodReference;
ImmutableMethodReference methodReference = $method_reference.methodReference;
$method::methodBuilder.addInstruction(new BuilderInstruction3rc(opcode, startRegister, registerCount,
dexBuilder.internMethodReference(methodReference)));
@ -1259,19 +1271,19 @@ subannotation returns[String annotationType, List<AnnotationElement> elements]
};
field_literal returns[FieldReference value]
: ^(I_ENCODED_FIELD fully_qualified_field)
: ^(I_ENCODED_FIELD field_reference)
{
$value = $fully_qualified_field.fieldReference;
$value = $field_reference.fieldReference;
};
method_literal returns[MethodReference value]
: ^(I_ENCODED_METHOD fully_qualified_method)
: ^(I_ENCODED_METHOD method_reference)
{
$value = $fully_qualified_method.methodReference;
$value = $method_reference.methodReference;
};
enum_literal returns[FieldReference value]
: ^(I_ENCODED_ENUM fully_qualified_field)
: ^(I_ENCODED_ENUM field_reference)
{
$value = $fully_qualified_field.fieldReference;
$value = $field_reference.fieldReference;
};

View File

@ -0,0 +1,94 @@
/*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.smali;
import com.google.common.collect.Iterables;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.TokenSource;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.writer.builder.DexBuilder;
import org.jf.dexlib2.writer.io.MemoryDataStore;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class SmaliTestUtils {
public static ClassDef compileSmali(String smaliText) throws RecognitionException, IOException {
CommonTokenStream tokens;
LexerErrorInterface lexer;
DexBuilder dexBuilder = DexBuilder.makeDexBuilder(15);
Reader reader = new StringReader(smaliText);
lexer = new smaliFlexLexer(reader);
tokens = new CommonTokenStream((TokenSource)lexer);
smaliParser parser = new smaliParser(tokens);
parser.setVerboseErrors(true);
parser.setAllowOdex(false);
parser.setApiLevel(15);
smaliParser.smali_file_return result = parser.smali_file();
if(parser.getNumberOfSyntaxErrors() > 0 || lexer.getNumberOfSyntaxErrors() > 0) {
throw new RuntimeException("Error occured while compiling text");
}
CommonTree t = result.getTree();
CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
treeStream.setTokenStream(tokens);
smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
dexGen.setVerboseErrors(true);
dexGen.setDexBuilder(dexBuilder);
dexGen.smali_file();
if (dexGen.getNumberOfSyntaxErrors() > 0) {
throw new RuntimeException("Error occured while compiling text");
}
MemoryDataStore dataStore = new MemoryDataStore();
dexBuilder.writeTo(dataStore);
DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15), dataStore.getData());
return Iterables.getFirst(dexFile.getClasses(), null);
}
}

View File

@ -0,0 +1,242 @@
/*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import junit.framework.Assert;
import org.antlr.runtime.RecognitionException;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Field;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
import org.jf.dexlib2.iface.instruction.formats.Instruction35c;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.iface.value.FieldEncodedValue;
import org.jf.dexlib2.iface.value.MethodEncodedValue;
import org.jf.dexlib2.iface.value.TypeEncodedValue;
import org.jf.smali.SmaliTestUtils;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* Tests for method/field references that use an implicit type
*/
public class ImplicitReferenceTest extends SmaliTestUtils {
@Test
public void testImplicitMethodReference() throws RecognitionException, IOException {
ClassDef classDef = SmaliTestUtils.compileSmali("" +
".class public LHelloWorld;\n" +
".super Ljava/lang/Object;\n" +
".method public static main([Ljava/lang/String;)V\n" +
" .registers 1\n" +
" invoke-static {p0}, toString()V\n" +
" invoke-static {p0}, V()V\n" +
" invoke-static {p0}, I()V\n" +
" return-void\n" +
".end method");
Method mainMethod = null;
for (Method method: classDef.getMethods()) {
if (method.getName().equals("main")) {
mainMethod = method;
}
}
Assert.assertNotNull(mainMethod);
MethodImplementation methodImpl = mainMethod.getImplementation();
Assert.assertNotNull(methodImpl);
List<Instruction> instructions = Lists.newArrayList(methodImpl.getInstructions());
Instruction35c instruction = (Instruction35c)instructions.get(0);
Assert.assertNotNull(instruction);
Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode());
MethodReference method = (MethodReference)instruction.getReference();
Assert.assertEquals(classDef.getType(), method.getDefiningClass());
Assert.assertEquals("toString", method.getName());
instruction = (Instruction35c)instructions.get(1);
Assert.assertNotNull(instruction);
Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode());
method = (MethodReference)instruction.getReference();
Assert.assertEquals(classDef.getType(), method.getDefiningClass());
Assert.assertEquals("V", method.getName());
instruction = (Instruction35c)instructions.get(2);
Assert.assertNotNull(instruction);
Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode());
method = (MethodReference)instruction.getReference();
Assert.assertEquals(classDef.getType(), method.getDefiningClass());
Assert.assertEquals("I", method.getName());
}
@Test
public void testImplicitMethodLiteral() throws RecognitionException, IOException {
ClassDef classDef = SmaliTestUtils.compileSmali("" +
".class public LHelloWorld;\n" +
".super Ljava/lang/Object;\n" +
".field public static field1:Ljava/lang/reflect/Method; = toString()V\n" +
".field public static field2:Ljava/lang/reflect/Method; = V()V\n" +
".field public static field3:Ljava/lang/reflect/Method; = I()V\n" +
".field public static field4:Ljava/lang/Class; = I");
Map<String, Field> fields = Maps.newHashMap();
for (Field field: classDef.getFields()) {
fields.put(field.getName(), field);
}
Field field = fields.get("field1");
Assert.assertNotNull(field);
Assert.assertNotNull(field.getInitialValue());
Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType());
MethodEncodedValue methodEncodedValue = (MethodEncodedValue)field.getInitialValue();
Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass());
Assert.assertEquals("toString", methodEncodedValue.getValue().getName());
field = fields.get("field2");
Assert.assertNotNull(field);
Assert.assertNotNull(field.getInitialValue());
Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType());
methodEncodedValue = (MethodEncodedValue)field.getInitialValue();
Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass());
Assert.assertEquals("V", methodEncodedValue.getValue().getName());
field = fields.get("field3");
Assert.assertNotNull(field);
Assert.assertNotNull(field.getInitialValue());
Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType());
methodEncodedValue = (MethodEncodedValue)field.getInitialValue();
Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass());
Assert.assertEquals("I", methodEncodedValue.getValue().getName());
field = fields.get("field4");
Assert.assertNotNull(field);
Assert.assertNotNull(field.getInitialValue());
Assert.assertEquals(ValueType.TYPE, field.getInitialValue().getValueType());
TypeEncodedValue typeEncodedValue = (TypeEncodedValue)field.getInitialValue();
Assert.assertEquals("I", typeEncodedValue.getValue());
}
@Test
public void testImplicitFieldReference() throws RecognitionException, IOException {
ClassDef classDef = SmaliTestUtils.compileSmali("" +
".class public LHelloWorld;\n" +
".super Ljava/lang/Object;\n" +
".method public static main([Ljava/lang/String;)V\n" +
" .registers 1\n" +
" sget-object v0, someField:I\n" +
" sget-object v0, V:I\n" +
" sget-object v0, I:I\n" +
" return-void\n" +
".end method");
Method mainMethod = null;
for (Method method: classDef.getMethods()) {
if (method.getName().equals("main")) {
mainMethod = method;
}
}
Assert.assertNotNull(mainMethod);
MethodImplementation methodImpl = mainMethod.getImplementation();
Assert.assertNotNull(methodImpl);
List<Instruction> instructions = Lists.newArrayList(methodImpl.getInstructions());
Instruction21c instruction = (Instruction21c)instructions.get(0);
Assert.assertNotNull(instruction);
Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode());
FieldReference field = (FieldReference)instruction.getReference();
Assert.assertEquals(classDef.getType(), field.getDefiningClass());
Assert.assertEquals("someField", field.getName());
instruction = (Instruction21c)instructions.get(1);
Assert.assertNotNull(instruction);
Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode());
field = (FieldReference)instruction.getReference();
Assert.assertEquals(classDef.getType(), field.getDefiningClass());
Assert.assertEquals("V", field.getName());
instruction = (Instruction21c)instructions.get(2);
Assert.assertNotNull(instruction);
Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode());
field = (FieldReference)instruction.getReference();
Assert.assertEquals(classDef.getType(), field.getDefiningClass());
Assert.assertEquals("I", field.getName());
}
@Test
public void testImplicitFieldLiteral() throws RecognitionException, IOException {
ClassDef classDef = SmaliTestUtils.compileSmali("" +
".class public LHelloWorld;\n" +
".super Ljava/lang/Object;\n" +
".field public static field1:Ljava/lang/reflect/Field; = someField:I\n" +
".field public static field2:Ljava/lang/reflect/Field; = V:I\n" +
".field public static field3:Ljava/lang/reflect/Field; = I:I\n");
Map<String, Field> fields = Maps.newHashMap();
for (Field field: classDef.getFields()) {
fields.put(field.getName(), field);
}
Field field = fields.get("field1");
Assert.assertNotNull(field);
Assert.assertNotNull(field.getInitialValue());
Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType());
FieldEncodedValue fieldEncodedValue = (FieldEncodedValue)field.getInitialValue();
Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass());
Assert.assertEquals("someField", fieldEncodedValue.getValue().getName());
field = fields.get("field2");
Assert.assertNotNull(field);
Assert.assertNotNull(field.getInitialValue());
Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType());
fieldEncodedValue = (FieldEncodedValue)field.getInitialValue();
Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass());
Assert.assertEquals("V", fieldEncodedValue.getValue().getName());
field = fields.get("field3");
Assert.assertNotNull(field);
Assert.assertNotNull(field.getInitialValue());
Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType());
fieldEncodedValue = (FieldEncodedValue)field.getInitialValue();
Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass());
Assert.assertEquals("I", fieldEncodedValue.getValue().getName());
}
}