mirror of
https://github.com/revanced/Apktool.git
synced 2025-05-03 15:24:26 +02:00
Implement implicit method/field references in smali
This commit is contained in:
parent
4801482960
commit
2772be8e9d
@ -686,22 +686,21 @@ enum_literal
|
|||||||
|
|
||||||
type_field_method_literal
|
type_field_method_literal
|
||||||
: reference_type_descriptor
|
: reference_type_descriptor
|
||||||
( ARROW
|
| ( (reference_type_descriptor ARROW)?
|
||||||
( member_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor member_name nonvoid_type_descriptor)
|
( 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)
|
| member_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor? member_name method_prototype)
|
||||||
)
|
)
|
||||||
| -> reference_type_descriptor
|
|
||||||
)
|
)
|
||||||
| PRIMITIVE_TYPE
|
| PRIMITIVE_TYPE
|
||||||
| VOID_TYPE;
|
| VOID_TYPE;
|
||||||
|
|
||||||
fully_qualified_method
|
method_reference
|
||||||
: reference_type_descriptor ARROW member_name method_prototype
|
: (reference_type_descriptor ARROW)? member_name method_prototype
|
||||||
-> reference_type_descriptor member_name method_prototype;
|
-> reference_type_descriptor? member_name method_prototype;
|
||||||
|
|
||||||
fully_qualified_field
|
field_reference
|
||||||
: reference_type_descriptor ARROW member_name COLON nonvoid_type_descriptor
|
: (reference_type_descriptor ARROW)? member_name COLON nonvoid_type_descriptor
|
||||||
-> reference_type_descriptor member_name nonvoid_type_descriptor;
|
-> reference_type_descriptor? member_name nonvoid_type_descriptor;
|
||||||
|
|
||||||
label
|
label
|
||||||
: COLON simple_name -> ^(I_LABEL[$COLON, "I_LABEL"] simple_name);
|
: 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?);
|
: (startreg=REGISTER (DOTDOT endreg=REGISTER)?)? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] $startreg? $endreg?);
|
||||||
|
|
||||||
verification_error_reference
|
verification_error_reference
|
||||||
: CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method;
|
: CLASS_DESCRIPTOR | field_reference | method_reference;
|
||||||
|
|
||||||
catch_directive
|
catch_directive
|
||||||
: CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref
|
: 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
|
insn_format21c_field
|
||||||
: //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
|
: //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
|
||||||
INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field
|
INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA field_reference
|
||||||
-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field);
|
-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER field_reference);
|
||||||
|
|
||||||
insn_format21c_field_odex
|
insn_format21c_field_odex
|
||||||
: //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream;
|
: //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) {
|
if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_FIELD_ODEX.text) == null || apiLevel >= 14) {
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT21c_FIELD_ODEX.text);
|
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
|
insn_format21c_string
|
||||||
: //e.g. const-string v1, "Hello World!"
|
: //e.g. const-string v1, "Hello World!"
|
||||||
@ -940,18 +939,18 @@ insn_format22b
|
|||||||
|
|
||||||
insn_format22c_field
|
insn_format22c_field
|
||||||
: //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
|
: //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
|
||||||
INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA 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 fully_qualified_field);
|
-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER field_reference);
|
||||||
|
|
||||||
insn_format22c_field_odex
|
insn_format22c_field_odex
|
||||||
: //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
|
: //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) {
|
if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_FIELD_ODEX.text) == null || apiLevel >= 14) {
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22c_FIELD_ODEX.text);
|
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
|
insn_format22c_type
|
||||||
: //e.g. instance-of v0, v1, Ljava/lang/String;
|
: //e.g. instance-of v0, v1, Ljava/lang/String;
|
||||||
@ -1012,8 +1011,8 @@ insn_format32x
|
|||||||
|
|
||||||
insn_format35c_method
|
insn_format35c_method
|
||||||
: //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
|
: //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
|
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 fully_qualified_method);
|
-> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list method_reference);
|
||||||
|
|
||||||
insn_format35c_type
|
insn_format35c_type
|
||||||
: //e.g. filled-new-array {v0,v1}, I
|
: //e.g. filled-new-array {v0,v1}, I
|
||||||
@ -1022,7 +1021,7 @@ insn_format35c_type
|
|||||||
|
|
||||||
insn_format35c_method_odex
|
insn_format35c_method_odex
|
||||||
: //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
: //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);
|
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35c_METHOD_ODEX.text);
|
||||||
};
|
};
|
||||||
@ -1043,12 +1042,12 @@ insn_format35ms_method
|
|||||||
|
|
||||||
insn_format3rc_method
|
insn_format3rc_method
|
||||||
: //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
: //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
|
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 fully_qualified_method);
|
-> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range method_reference);
|
||||||
|
|
||||||
insn_format3rc_method_odex
|
insn_format3rc_method_odex
|
||||||
: //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
|
: //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);
|
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rc_METHOD_ODEX.text);
|
||||||
};
|
};
|
||||||
|
@ -501,17 +501,29 @@ method_type_list returns[List<String> types]
|
|||||||
)*;
|
)*;
|
||||||
|
|
||||||
|
|
||||||
fully_qualified_method returns[ImmutableMethodReference methodReference]
|
method_reference returns[ImmutableMethodReference methodReference]
|
||||||
: reference_type_descriptor SIMPLE_NAME method_prototype
|
: 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);
|
$method_prototype.parameters, $method_prototype.returnType);
|
||||||
};
|
};
|
||||||
|
|
||||||
fully_qualified_field returns[ImmutableFieldReference fieldReference]
|
field_reference returns[ImmutableFieldReference fieldReference]
|
||||||
: reference_type_descriptor SIMPLE_NAME nonvoid_type_descriptor
|
: 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);
|
$nonvoid_type_descriptor.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -688,13 +700,13 @@ verification_error_reference returns[ImmutableReference reference]
|
|||||||
{
|
{
|
||||||
$reference = new ImmutableTypeReference($CLASS_DESCRIPTOR.text);
|
$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]
|
verification_error_type returns[int verificationError]
|
||||||
@ -816,12 +828,12 @@ insn_format20t
|
|||||||
|
|
||||||
insn_format21c_field
|
insn_format21c_field
|
||||||
: //e.g. sget_object v0, java/lang/System/out LJava/io/PrintStream;
|
: //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);
|
Opcode opcode = opcodes.getOpcodeByName($inst.text);
|
||||||
short regA = parseRegister_byte($REGISTER.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,
|
$method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
|
||||||
dexBuilder.internFieldReference(fieldReference)));
|
dexBuilder.internFieldReference(fieldReference)));
|
||||||
@ -911,13 +923,13 @@ insn_format22b
|
|||||||
|
|
||||||
insn_format22c_field
|
insn_format22c_field
|
||||||
: //e.g. iput-object v1, v0, org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
|
: //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);
|
Opcode opcode = opcodes.getOpcodeByName($inst.text);
|
||||||
byte regA = parseRegister_nibble($registerA.text);
|
byte regA = parseRegister_nibble($registerA.text);
|
||||||
byte regB = parseRegister_nibble($registerB.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,
|
$method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB,
|
||||||
dexBuilder.internFieldReference(fieldReference)));
|
dexBuilder.internFieldReference(fieldReference)));
|
||||||
@ -1038,7 +1050,7 @@ insn_format32x
|
|||||||
|
|
||||||
insn_format35c_method
|
insn_format35c_method
|
||||||
: //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
|
: //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);
|
Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT35c_METHOD.text);
|
||||||
|
|
||||||
@ -1046,7 +1058,7 @@ insn_format35c_method
|
|||||||
byte[] registers = $register_list.registers;
|
byte[] registers = $register_list.registers;
|
||||||
byte registerCount = $register_list.registerCount;
|
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],
|
$method::methodBuilder.addInstruction(new BuilderInstruction35c(opcode, registerCount, registers[0], registers[1],
|
||||||
registers[2], registers[3], registers[4], dexBuilder.internMethodReference(methodReference)));
|
registers[2], registers[3], registers[4], dexBuilder.internMethodReference(methodReference)));
|
||||||
@ -1068,7 +1080,7 @@ insn_format35c_type
|
|||||||
|
|
||||||
insn_format3rc_method
|
insn_format3rc_method
|
||||||
: //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
: //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);
|
Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT3rc_METHOD.text);
|
||||||
int startRegister = $register_range.startRegister;
|
int startRegister = $register_range.startRegister;
|
||||||
@ -1076,7 +1088,7 @@ insn_format3rc_method
|
|||||||
|
|
||||||
int registerCount = endRegister-startRegister+1;
|
int registerCount = endRegister-startRegister+1;
|
||||||
|
|
||||||
ImmutableMethodReference methodReference = $fully_qualified_method.methodReference;
|
ImmutableMethodReference methodReference = $method_reference.methodReference;
|
||||||
|
|
||||||
$method::methodBuilder.addInstruction(new BuilderInstruction3rc(opcode, startRegister, registerCount,
|
$method::methodBuilder.addInstruction(new BuilderInstruction3rc(opcode, startRegister, registerCount,
|
||||||
dexBuilder.internMethodReference(methodReference)));
|
dexBuilder.internMethodReference(methodReference)));
|
||||||
@ -1259,19 +1271,19 @@ subannotation returns[String annotationType, List<AnnotationElement> elements]
|
|||||||
};
|
};
|
||||||
|
|
||||||
field_literal returns[FieldReference value]
|
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]
|
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]
|
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;
|
||||||
};
|
};
|
||||||
|
94
smali/src/main/java/org/jf/smali/SmaliTestUtils.java
Normal file
94
smali/src/main/java/org/jf/smali/SmaliTestUtils.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
242
smali/src/test/java/ImplicitReferenceTest.java
Normal file
242
smali/src/test/java/ImplicitReferenceTest.java
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user