aboutsummaryrefslogtreecommitdiff
path: root/smali
diff options
context:
space:
mode:
authorBen Gruver <bgruv@google.com>2014-02-13 11:36:59 -0800
committerBen Gruver <bgruv@google.com>2014-02-13 11:36:59 -0800
commit8f10b06b71c0ead4616b6ed98ea7be1f467b9098 (patch)
tree1049a11e2b37218facf4cf3ea33f88e67abd2e16 /smali
parentf3d921d1f8eb52f20440a0e43f604a7aae972e94 (diff)
parent7cf2b33cbdd81c1661e8b59356999cf98116595f (diff)
downloadsmali-8f10b06b71c0ead4616b6ed98ea7be1f467b9098.tar.gz
Merge tag 'v2.0.3' into master
Conflicts: scripts/smali Change-Id: Id26d343be87dc1fa6a09cc4b567cdbcb5970e211
Diffstat (limited to 'smali')
-rw-r--r--smali/build.gradle90
-rw-r--r--smali/src/main/antlr3/smaliParser.g584
-rw-r--r--smali/src/main/antlr3/smaliTreeWalker.g1509
-rw-r--r--smali/src/main/java/org/jf/smali/SmaliMethodParameter.java67
-rw-r--r--smali/src/main/java/org/jf/smali/WithRegister.java36
-rw-r--r--smali/src/main/java/org/jf/smali/main.java213
-rw-r--r--smali/src/main/jflex/smaliLexer.flex61
-rw-r--r--smali/src/test/java/LexerTest.java16
-rw-r--r--smali/src/test/resources/LexerTest/DirectiveTest.smali6
-rw-r--r--smali/src/test/resources/LexerTest/DirectiveTest.tokens8
-rw-r--r--smali/src/test/resources/LexerTest/InstructionTest.smali52
-rw-r--r--smali/src/test/resources/LexerTest/InstructionTest.tokens58
-rw-r--r--smali/src/test/resources/LexerTest/MiscTest.tokens14
-rw-r--r--smali/src/test/resources/LexerTest/RealSmaliFileTest.smali16
-rw-r--r--smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens60
-rw-r--r--smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali2
-rw-r--r--smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens8
17 files changed, 1134 insertions, 1666 deletions
diff --git a/smali/build.gradle b/smali/build.gradle
index d5f54ab1..9c16db77 100644
--- a/smali/build.gradle
+++ b/smali/build.gradle
@@ -28,7 +28,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
configurations {
antlr3
jflex
@@ -66,24 +66,36 @@ idea {
dependencies {
compile project(':util')
- compile project(':dexlib')
- compile 'org.antlr:antlr-runtime:3.2'
- compile 'commons-cli:commons-cli:1.2'
- compile 'com.google.guava:guava:13.0.1'
+ compile project(':dexlib2')
+ compile depends.antlr_runtime
+ compile depends.commons_cli
- testCompile 'junit:junit:4.6'
+ testCompile depends.junit
- antlr3 'org.antlr:antlr:3.2'
- jflex 'de.jflex:jflex:1.4.3'
- proguard 'net.sf.proguard:proguard-base:4.8'
+ antlr3 depends.antlr
+ jflex depends.jflex
+ proguard depends.proguard
}
-task generateAntlrSource(type: JavaExec) {
+task generateParserAntlrSource(type: JavaExec) {
inputs.dir file(antlrSource)
outputs.dir file(antlrOutput)
mkdir(antlrOutput)
- def grammars = fileTree(antlrSource).include('**/*.g')
+ def grammars = fileTree(antlrSource).include('**/smaliParser.g')
+
+ classpath = configurations.antlr3
+ main = 'org.antlr.Tool'
+ args '-fo', relativePath("${antlrOutput}/org/jf/smali")
+ args grammars.files
+}
+
+task generateTreeWalkerAntlrSource(type: JavaExec) {
+ inputs.dir file(antlrSource)
+ outputs.dir file(antlrOutput)
+
+ mkdir(antlrOutput)
+ def grammars = fileTree(antlrSource).include('**/smaliTreeWalker.g')
classpath = configurations.antlr3
main = 'org.antlr.Tool'
@@ -116,39 +128,73 @@ task generateJflexSource(type: JavaExec) {
args '-q'
args '-d', relativePath("${jflexOutput}/org/jf/smali")
args grammars.files.join(' ')
+ environment LC_ALL: "en_US"
}
-compileJava.dependsOn generateAntlrSource, generateJflexSource
+compileJava.dependsOn generateParserAntlrSource, generateTreeWalkerAntlrSource, generateJflexSource
compileTestJava.dependsOn generateTestAntlrSource
-// build a jar containing all dependencies
+processResources.inputs.property('version', version)
+processResources.expand('version': version)
+
+// This is the jar that gets uploaded to maven
jar {
+ baseName = 'maven'
+}
+
+// Build a separate jar that contains all dependencies
+task fatJar(type: Jar, dependsOn: jar) {
+ from sourceSets.main.output
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
manifest {
attributes("Main-Class": "org.jf.smali.main")
}
+
+ doLast {
+ if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
+ ant.symlink(link: file("${destinationDir}/smali.jar"), resource: archivePath, overwrite: true)
+ }
+ }
+}
+tasks.getByPath('build').dependsOn(fatJar)
+
+uploadArchives {
+ repositories.mavenDeployer {
+ pom.project {
+ description 'smali is an assembler for dalvik bytecode'
+ scm {
+ url 'https://github.com/JesusFreke/smali/tree/master/smali'
+ }
+ }
+ }
}
-processResources.inputs.property('version', version)
-processResources.expand('version': version)
+task sourcesJar(type: Jar) {
+ classifier = 'sources'
+ from sourceSets.main.allJava
+}
+
+artifacts {
+ archives sourcesJar
+}
-task proguard(type: JavaExec, dependsOn: jar) {
- def outFile = jar.destinationDir.getPath() + '/' + jar.baseName + '-' + jar.version + '-small' + '.' + jar.extension
- inputs.file jar.archivePath
+task proguard(type: JavaExec, dependsOn: fatJar) {
+ def outFile = fatJar.destinationDir.getPath() + '/' + fatJar.baseName + '-' + fatJar.version + '-small' + '.' + fatJar.extension
+ inputs.file fatJar.archivePath
outputs.file outFile
classpath = configurations.proguard
main = 'proguard.ProGuard'
- args "-injars ${jar.archivePath}(!**/TestStringTemplate*.class)"
+ args "-injars ${fatJar.archivePath}(!**/TestStringTemplate*.class)"
args "-outjars ${outFile}"
args "-libraryjars ${System.properties['java.home']}/lib/rt.jar"
args '-dontobfuscate'
args '-dontoptimize'
args '-keep public class org.jf.smali.main { public static void main(java.lang.String[]); }'
args '-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }'
- args '-dontwarn com.google.common.base.**'
- args '-dontnote com.google.common.base.**'
+ args '-dontwarn com.google.common.**'
+ args '-dontnote com.google.common.**'
}
-tasks.getByPath(':release').dependsOn(proguard) \ No newline at end of file
+tasks.getByPath(':release').dependsOn(proguard)
diff --git a/smali/src/main/antlr3/smaliParser.g b/smali/src/main/antlr3/smaliParser.g
index 34c5ddf0..563cda36 100644
--- a/smali/src/main/antlr3/smaliParser.g
+++ b/smali/src/main/antlr3/smaliParser.g
@@ -102,7 +102,8 @@ tokens {
INSTRUCTION_FORMAT21c_FIELD_ODEX;
INSTRUCTION_FORMAT21c_STRING;
INSTRUCTION_FORMAT21c_TYPE;
- INSTRUCTION_FORMAT21h;
+ INSTRUCTION_FORMAT21ih;
+ INSTRUCTION_FORMAT21lh;
INSTRUCTION_FORMAT21s;
INSTRUCTION_FORMAT21t;
INSTRUCTION_FORMAT22b;
@@ -139,10 +140,9 @@ tokens {
LOCALS_DIRECTIVE;
LONG_LITERAL;
METHOD_DIRECTIVE;
- METHOD_NAME;
+ MEMBER_NAME;
NEGATIVE_INTEGER_LITERAL;
NULL_LITERAL;
- OFFSET;
OPEN_BRACE;
OPEN_PAREN;
PACKED_SWITCH_DIRECTIVE;
@@ -187,7 +187,6 @@ tokens {
I_METHOD_RETURN_TYPE;
I_REGISTERS;
I_LOCALS;
- I_LABELS;
I_LABEL;
I_ANNOTATIONS;
I_ANNOTATION;
@@ -200,30 +199,21 @@ tokens {
I_ARRAY_ELEMENT_SIZE;
I_ARRAY_ELEMENTS;
I_PACKED_SWITCH_START_KEY;
- I_PACKED_SWITCH_TARGET_COUNT;
- I_PACKED_SWITCH_TARGETS;
- I_PACKED_SWITCH_DECLARATION;
- I_PACKED_SWITCH_DECLARATIONS;
- I_SPARSE_SWITCH_KEYS;
- I_SPARSE_SWITCH_TARGET_COUNT;
- I_SPARSE_SWITCH_TARGETS;
- I_SPARSE_SWITCH_DECLARATION;
- I_SPARSE_SWITCH_DECLARATIONS;
- I_ADDRESS;
+ I_PACKED_SWITCH_ELEMENTS;
+ I_SPARSE_SWITCH_ELEMENTS;
I_CATCH;
I_CATCHALL;
I_CATCHES;
I_PARAMETER;
I_PARAMETERS;
I_PARAMETER_NOT_SPECIFIED;
- I_ORDERED_DEBUG_DIRECTIVES;
I_LINE;
I_LOCAL;
I_END_LOCAL;
I_RESTART_LOCAL;
I_PROLOGUE;
I_EPILOGUE;
- I_STATEMENTS;
+ I_ORDERED_METHOD_ITEMS;
I_STATEMENT_FORMAT10t;
I_STATEMENT_FORMAT10x;
I_STATEMENT_FORMAT11n;
@@ -234,7 +224,8 @@ tokens {
I_STATEMENT_FORMAT21c_TYPE;
I_STATEMENT_FORMAT21c_FIELD;
I_STATEMENT_FORMAT21c_STRING;
- I_STATEMENT_FORMAT21h;
+ I_STATEMENT_FORMAT21ih;
+ I_STATEMENT_FORMAT21lh;
I_STATEMENT_FORMAT21s;
I_STATEMENT_FORMAT21t;
I_STATEMENT_FORMAT22b;
@@ -253,13 +244,7 @@ tokens {
I_STATEMENT_FORMAT35c_TYPE;
I_STATEMENT_FORMAT3rc_METHOD;
I_STATEMENT_FORMAT3rc_TYPE;
- I_STATEMENT_FORMAT41c_TYPE;
- I_STATEMENT_FORMAT41c_FIELD;
I_STATEMENT_FORMAT51l;
- I_STATEMENT_FORMAT52c_TYPE;
- I_STATEMENT_FORMAT52c_FIELD;
- I_STATEMENT_FORMAT5rc_METHOD;
- I_STATEMENT_FORMAT5rc_TYPE;
I_STATEMENT_ARRAY_DATA;
I_STATEMENT_PACKED_SWITCH;
I_STATEMENT_SPARSE_SWITCH;
@@ -270,8 +255,9 @@ tokens {
@header {
package org.jf.smali;
-import org.jf.dexlib.Code.Format.*;
-import org.jf.dexlib.Code.Opcode;
+import org.jf.dexlib2.Format;
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.Opcodes;
}
@@ -280,7 +266,8 @@ import org.jf.dexlib.Code.Opcode;
private boolean verboseErrors = false;
private boolean allowOdex = false;
- private int apiLevel;
+ private int apiLevel = 15;
+ private Opcodes opcodes = new Opcodes(apiLevel);
public void setVerboseErrors(boolean verboseErrors) {
this.verboseErrors = verboseErrors;
@@ -291,6 +278,7 @@ import org.jf.dexlib.Code.Opcode;
}
public void setApiLevel(int apiLevel) {
+ this.opcodes = new Opcodes(apiLevel);
this.apiLevel = apiLevel;
}
@@ -504,56 +492,49 @@ the annotations. If it turns out that they are field annotations, we include the
add them to the $smali_file::classAnnotations list*/
field
@init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
- : FIELD_DIRECTIVE access_list simple_name COLON nonvoid_type_descriptor (EQUAL literal)?
+ : FIELD_DIRECTIVE access_list member_name COLON nonvoid_type_descriptor (EQUAL literal)?
( ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
( END_FIELD_DIRECTIVE
- -> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*))
+ -> ^(I_FIELD[$start, "I_FIELD"] member_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*))
| /*epsilon*/ {$smali_file::classAnnotations.addAll(annotations);}
- -> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS))
+ -> ^(I_FIELD[$start, "I_FIELD"] member_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS))
)
);
method
- scope {int currentAddress;}
- : {$method::currentAddress = 0;}
- METHOD_DIRECTIVE access_list method_name method_prototype statements_and_directives
+ : METHOD_DIRECTIVE access_list member_name method_prototype statements_and_directives
END_METHOD_DIRECTIVE
- -> ^(I_METHOD[$start, "I_METHOD"] method_name method_prototype access_list statements_and_directives);
+ -> ^(I_METHOD[$start, "I_METHOD"] member_name method_prototype access_list statements_and_directives);
statements_and_directives
scope
{
boolean hasRegistersDirective;
- List<CommonTree> packedSwitchDeclarations;
- List<CommonTree> sparseSwitchDeclarations;
List<CommonTree> methodAnnotations;
}
: {
- $method::currentAddress = 0;
$statements_and_directives::hasRegistersDirective = false;
- $statements_and_directives::packedSwitchDeclarations = new ArrayList<CommonTree>();
- $statements_and_directives::sparseSwitchDeclarations = new ArrayList<CommonTree>();
$statements_and_directives::methodAnnotations = new ArrayList<CommonTree>();
}
- ( instruction {$method::currentAddress += $instruction.size/2;}
+ ( ordered_method_item
| registers_directive
- | label
| catch_directive
| catchall_directive
| parameter_directive
- | ordered_debug_directive
| annotation {$statements_and_directives::methodAnnotations.add($annotation.tree);}
)*
-> registers_directive?
- ^(I_LABELS label*)
- {buildTree(I_PACKED_SWITCH_DECLARATIONS, "I_PACKED_SWITCH_DECLARATIONS", $statements_and_directives::packedSwitchDeclarations)}
- {buildTree(I_SPARSE_SWITCH_DECLARATIONS, "I_SPARSE_SWITCH_DECLARATIONS", $statements_and_directives::sparseSwitchDeclarations)}
- ^(I_STATEMENTS instruction*)
+ ^(I_ORDERED_METHOD_ITEMS ordered_method_item*)
^(I_CATCHES catch_directive* catchall_directive*)
^(I_PARAMETERS parameter_directive*)
- ^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*)
{buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $statements_and_directives::methodAnnotations)};
+/* Method items whose order/location is important */
+ordered_method_item
+ : label
+ | instruction
+ | debug_directive;
+
registers_directive
: (
directive=REGISTERS_DIRECTIVE regCount=integral_literal -> ^(I_REGISTERS[$REGISTERS_DIRECTIVE, "I_REGISTERS"] $regCount)
@@ -609,9 +590,9 @@ simple_name
| INSTRUCTION_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD]
| INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l];
-method_name
+member_name
: simple_name
- | METHOD_NAME -> SIMPLE_NAME[$METHOD_NAME];
+ | MEMBER_NAME -> SIMPLE_NAME[$MEMBER_NAME];
method_prototype
: OPEN_PAREN param_list CLOSE_PAREN type_descriptor
@@ -665,6 +646,9 @@ literal
| type_field_method_literal
| enum_literal;
+parsed_integer_literal returns[int value]
+ : integer_literal { $value = LiteralTools.parseInt($integer_literal.text); };
+
integral_literal
: LONG_LITERAL
| integer_literal
@@ -681,15 +665,15 @@ fixed_32bit_literal
| CHAR_LITERAL
| BOOL_LITERAL;
-fixed_literal returns[int size]
- : integer_literal {$size = 4;}
- | LONG_LITERAL {$size = 8;}
- | SHORT_LITERAL {$size = 2;}
- | BYTE_LITERAL {$size = 1;}
- | float_literal {$size = 4;}
- | double_literal {$size = 8;}
- | CHAR_LITERAL {$size = 2;}
- | BOOL_LITERAL {$size = 1;};
+fixed_literal
+ : integer_literal
+ | LONG_LITERAL
+ | SHORT_LITERAL
+ | BYTE_LITERAL
+ | float_literal
+ | double_literal
+ | CHAR_LITERAL
+ | BOOL_LITERAL;
array_literal
: OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE
@@ -715,8 +699,8 @@ enum_literal
type_field_method_literal
: reference_type_descriptor
( ARROW
- ( simple_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor simple_name nonvoid_type_descriptor)
- | method_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor method_name method_prototype)
+ ( 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
)
@@ -724,20 +708,18 @@ type_field_method_literal
| VOID_TYPE;
fully_qualified_method
- : reference_type_descriptor ARROW method_name method_prototype
- -> reference_type_descriptor method_name method_prototype;
+ : reference_type_descriptor ARROW member_name method_prototype
+ -> reference_type_descriptor member_name method_prototype;
fully_qualified_field
- : reference_type_descriptor ARROW simple_name COLON nonvoid_type_descriptor
- -> reference_type_descriptor simple_name nonvoid_type_descriptor;
+ : 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 I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
+ : COLON simple_name -> ^(I_LABEL[$COLON, "I_LABEL"] simple_name);
-label_ref_or_offset
- : COLON simple_name -> simple_name
- | OFFSET
- | NEGATIVE_INTEGER_LITERAL -> OFFSET[$NEGATIVE_INTEGER_LITERAL];
+label_ref
+ : COLON simple_name -> simple_name;
register_list
: REGISTER (COMMA REGISTER)* -> ^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"] REGISTER*)
@@ -750,12 +732,12 @@ verification_error_reference
: CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method;
catch_directive
- : CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset
- -> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using);
+ : CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref
+ -> ^(I_CATCH[$start, "I_CATCH"] nonvoid_type_descriptor $from $to $using);
catchall_directive
- : CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset
- -> ^(I_CATCHALL[$start, "I_CATCHALL"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] $from $to $using);
+ : CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref
+ -> ^(I_CATCHALL[$start, "I_CATCHALL"] $from $to $using);
/*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations
or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse
@@ -763,17 +745,16 @@ the annotations. If it turns out that they are parameter annotations, we include
add them to the $statements_and_directives::methodAnnotations list*/
parameter_directive
@init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
- : PARAMETER_DIRECTIVE
- STRING_LITERAL?
+ : PARAMETER_DIRECTIVE REGISTER (COMMA STRING_LITERAL)?
({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
( END_PARAMETER_DIRECTIVE
- -> ^(I_PARAMETER[$start, "I_PARAMETER"] STRING_LITERAL? ^(I_ANNOTATIONS annotation*))
+ -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER STRING_LITERAL? ^(I_ANNOTATIONS annotation*))
| /*epsilon*/ {$statements_and_directives::methodAnnotations.addAll(annotations);}
- -> ^(I_PARAMETER[$start, "I_PARAMETER"] STRING_LITERAL? ^(I_ANNOTATIONS))
+ -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER STRING_LITERAL? ^(I_ANNOTATIONS))
);
-ordered_debug_directive
+debug_directive
: line_directive
| local_directive
| end_local_directive
@@ -784,31 +765,32 @@ ordered_debug_directive
line_directive
: LINE_DIRECTIVE integral_literal
- -> ^(I_LINE integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
+ -> ^(I_LINE[$start, "I_LINE"] integral_literal);
local_directive
- : LOCAL_DIRECTIVE REGISTER COMMA simple_name COLON nonvoid_type_descriptor (COMMA STRING_LITERAL)?
- -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER simple_name nonvoid_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
+ : LOCAL_DIRECTIVE REGISTER (COMMA (NULL_LITERAL | name=STRING_LITERAL) COLON (VOID_TYPE | nonvoid_type_descriptor)
+ (COMMA signature=STRING_LITERAL)? )?
+ -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER NULL_LITERAL? $name? nonvoid_type_descriptor? $signature?);
end_local_directive
: END_LOCAL_DIRECTIVE REGISTER
- -> ^(I_END_LOCAL[$start, "I_END_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
+ -> ^(I_END_LOCAL[$start, "I_END_LOCAL"] REGISTER);
restart_local_directive
: RESTART_LOCAL_DIRECTIVE REGISTER
- -> ^(I_RESTART_LOCAL[$start, "I_RESTART_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
+ -> ^(I_RESTART_LOCAL[$start, "I_RESTART_LOCAL"] REGISTER);
prologue_directive
: PROLOGUE_DIRECTIVE
- -> ^(I_PROLOGUE[$start, "I_PROLOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
+ -> ^(I_PROLOGUE[$start, "I_PROLOGUE"]);
epilogue_directive
: EPILOGUE_DIRECTIVE
- -> ^(I_EPILOGUE[$start, "I_EPILOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
+ -> ^(I_EPILOGUE[$start, "I_EPILOGUE"]);
source_directive
- : SOURCE_DIRECTIVE STRING_LITERAL
- -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
+ : SOURCE_DIRECTIVE STRING_LITERAL?
+ -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL?);
instruction_format12x
: INSTRUCTION_FORMAT12x
@@ -824,441 +806,317 @@ instruction_format31i
-instruction returns [int size]
- : insn_format10t { $size = $insn_format10t.size; }
- | insn_format10x { $size = $insn_format10x.size; }
- | insn_format10x_odex { $size = $insn_format10x_odex.size; }
- | insn_format11n { $size = $insn_format11n.size; }
- | insn_format11x { $size = $insn_format11x.size; }
- | insn_format12x { $size = $insn_format12x.size; }
- | insn_format20bc { $size = $insn_format20bc.size; }
- | insn_format20t { $size = $insn_format20t.size; }
- | insn_format21c_field { $size = $insn_format21c_field.size; }
- | insn_format21c_field_odex { $size = $insn_format21c_field_odex.size; }
- | insn_format21c_string { $size = $insn_format21c_string.size; }
- | insn_format21c_type { $size = $insn_format21c_type.size; }
- | insn_format21h { $size = $insn_format21h.size; }
- | insn_format21s { $size = $insn_format21s.size; }
- | insn_format21t { $size = $insn_format21t.size; }
- | insn_format22b { $size = $insn_format22b.size; }
- | insn_format22c_field { $size = $insn_format22c_field.size; }
- | insn_format22c_field_odex { $size = $insn_format22c_field_odex.size; }
- | insn_format22c_type { $size = $insn_format22c_type.size; }
- | insn_format22cs_field { $size = $insn_format22cs_field.size; }
- | insn_format22s { $size = $insn_format22s.size; }
- | insn_format22t { $size = $insn_format22t.size; }
- | insn_format22x { $size = $insn_format22x.size; }
- | insn_format23x { $size = $insn_format23x.size; }
- | insn_format30t { $size = $insn_format30t.size; }
- | insn_format31c { $size = $insn_format31c.size; }
- | insn_format31i { $size = $insn_format31i.size; }
- | insn_format31t { $size = $insn_format31t.size; }
- | insn_format32x { $size = $insn_format32x.size; }
- | insn_format35c_method { $size = $insn_format35c_method.size; }
- | insn_format35c_type { $size = $insn_format35c_type.size; }
- | insn_format35c_method_odex { $size = $insn_format35c_method_odex.size; }
- | insn_format35mi_method { $size = $insn_format35mi_method.size; }
- | insn_format35ms_method { $size = $insn_format35ms_method.size; }
- | insn_format3rc_method { $size = $insn_format3rc_method.size; }
- | insn_format3rc_method_odex { $size = $insn_format3rc_method_odex.size; }
- | insn_format3rc_type { $size = $insn_format3rc_type.size; }
- | insn_format3rmi_method { $size = $insn_format3rmi_method.size; }
- | insn_format3rms_method { $size = $insn_format3rms_method.size; }
- | insn_format41c_type { $size = $insn_format41c_type.size; }
- | insn_format41c_field { $size = $insn_format41c_field.size; }
- | insn_format41c_field_odex { $size = $insn_format41c_field_odex.size; }
- | insn_format51l { $size = $insn_format51l.size; }
- | insn_format52c_type { $size = $insn_format52c_type.size; }
- | insn_format52c_field { $size = $insn_format52c_field.size; }
- | insn_format52c_field_odex { $size = $insn_format52c_field_odex.size; }
- | insn_format5rc_method { $size = $insn_format5rc_method.size; }
- | insn_format5rc_method_odex { $size = $insn_format5rc_method_odex.size; }
- | insn_format5rc_type { $size = $insn_format5rc_type.size; }
- | insn_array_data_directive { $size = $insn_array_data_directive.size; }
- | insn_packed_switch_directive { $size = $insn_packed_switch_directive.size; }
- | insn_sparse_switch_directive { $size = $insn_sparse_switch_directive.size; };
-
-insn_format10t returns [int size]
+instruction
+ : insn_format10t
+ | insn_format10x
+ | insn_format10x_odex
+ | insn_format11n
+ | insn_format11x
+ | insn_format12x
+ | insn_format20bc
+ | insn_format20t
+ | insn_format21c_field
+ | insn_format21c_field_odex
+ | insn_format21c_string
+ | insn_format21c_type
+ | insn_format21ih
+ | insn_format21lh
+ | insn_format21s
+ | insn_format21t
+ | insn_format22b
+ | insn_format22c_field
+ | insn_format22c_field_odex
+ | insn_format22c_type
+ | insn_format22cs_field
+ | insn_format22s
+ | insn_format22t
+ | insn_format22x
+ | insn_format23x
+ | insn_format30t
+ | insn_format31c
+ | insn_format31i
+ | insn_format31t
+ | insn_format32x
+ | insn_format35c_method
+ | insn_format35c_type
+ | insn_format35c_method_odex
+ | insn_format35mi_method
+ | insn_format35ms_method
+ | insn_format3rc_method
+ | insn_format3rc_method_odex
+ | insn_format3rc_type
+ | insn_format3rmi_method
+ | insn_format3rms_method
+ | insn_format51l
+ | insn_array_data_directive
+ | insn_packed_switch_directive
+ | insn_sparse_switch_directive;
+
+insn_format10t
: //e.g. goto endloop:
//e.g. goto +3
- INSTRUCTION_FORMAT10t label_ref_or_offset {$size = Format.Format10t.size;}
- -> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref_or_offset);
+ INSTRUCTION_FORMAT10t label_ref
+ -> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref);
-insn_format10x returns [int size]
+insn_format10x
: //e.g. return-void
- INSTRUCTION_FORMAT10x {$size = Format.Format10x.size;}
+ INSTRUCTION_FORMAT10x
-> ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x);
-insn_format10x_odex returns [int size]
+insn_format10x_odex
: //e.g. return-void-barrier
- INSTRUCTION_FORMAT10x_ODEX {$size = Format.Format10x.size;}
+ INSTRUCTION_FORMAT10x_ODEX
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT10x_ODEX.text);
};
-insn_format11n returns [int size]
+insn_format11n
: //e.g. const/4 v0, 5
- INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal {$size = Format.Format11n.size;}
+ INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal
-> ^(I_STATEMENT_FORMAT11n[$start, "I_STATEMENT_FORMAT11n"] INSTRUCTION_FORMAT11n REGISTER integral_literal);
-insn_format11x returns [int size]
+insn_format11x
: //e.g. move-result-object v1
- INSTRUCTION_FORMAT11x REGISTER {$size = Format.Format11x.size;}
+ INSTRUCTION_FORMAT11x REGISTER
-> ^(I_STATEMENT_FORMAT11x[$start, "I_STATEMENT_FORMAT11x"] INSTRUCTION_FORMAT11x REGISTER);
-insn_format12x returns [int size]
+insn_format12x
: //e.g. move v1 v2
- instruction_format12x REGISTER COMMA REGISTER {$size = Format.Format12x.size;}
+ instruction_format12x REGISTER COMMA REGISTER
-> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] instruction_format12x REGISTER REGISTER);
-insn_format20bc returns [int size]
+insn_format20bc
: //e.g. throw-verification-error generic-error, Lsome/class;
- INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference {$size += Format.Format20bc.size;}
+ INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference
{
- if (!allowOdex || Opcode.getOpcodeByName($INSTRUCTION_FORMAT20bc.text) == null || apiLevel >= 14) {
+ if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT20bc.text) == null || apiLevel >= 14) {
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text);
}
}
-> ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE verification_error_reference);
- //TODO: check if dalvik has a jumbo version of throw-verification-error
-insn_format20t returns [int size]
+insn_format20t
: //e.g. goto/16 endloop:
- INSTRUCTION_FORMAT20t label_ref_or_offset {$size = Format.Format20t.size;}
- -> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref_or_offset);
+ INSTRUCTION_FORMAT20t label_ref
+ -> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref);
-insn_format21c_field returns [int size]
+insn_format21c_field
: //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
- INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;}
+ INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field
-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field);
-insn_format21c_field_odex returns [int size]
+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 {$size = Format.Format21c.size;}
+ INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA fully_qualified_field
{
- if (!allowOdex || Opcode.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);
}
}
-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER fully_qualified_field);
-insn_format21c_string returns [int size]
+insn_format21c_string
: //e.g. const-string v1, "Hello World!"
- INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL {$size = Format.Format21c.size;}
+ INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL
-> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL);
-insn_format21c_type returns [int size]
+insn_format21c_type
: //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
- INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor {$size = Format.Format21c.size;}
- -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor);
+ INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA nonvoid_type_descriptor
+ -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER nonvoid_type_descriptor);
-insn_format21h returns [int size]
+insn_format21ih
: //e.g. const/high16 v1, 1234
- INSTRUCTION_FORMAT21h REGISTER COMMA integral_literal {$size = Format.Format21h.size;}
- -> ^(I_STATEMENT_FORMAT21h[$start, "I_STATEMENT_FORMAT21h"] INSTRUCTION_FORMAT21h REGISTER integral_literal);
+ INSTRUCTION_FORMAT21ih REGISTER COMMA fixed_32bit_literal
+ -> ^(I_STATEMENT_FORMAT21ih[$start, "I_STATEMENT_FORMAT21ih"] INSTRUCTION_FORMAT21ih REGISTER fixed_32bit_literal);
+
+insn_format21lh
+ : //e.g. const-wide/high16 v1, 1234
+ INSTRUCTION_FORMAT21lh REGISTER COMMA fixed_32bit_literal
+ -> ^(I_STATEMENT_FORMAT21lh[$start, "I_STATEMENT_FORMAT21lh"] INSTRUCTION_FORMAT21lh REGISTER fixed_32bit_literal);
-insn_format21s returns [int size]
+insn_format21s
: //e.g. const/16 v1, 1234
- INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal {$size = Format.Format21s.size;}
+ INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal
-> ^(I_STATEMENT_FORMAT21s[$start, "I_STATEMENT_FORMAT21s"] INSTRUCTION_FORMAT21s REGISTER integral_literal);
-insn_format21t returns [int size]
+insn_format21t
: //e.g. if-eqz v0, endloop:
- INSTRUCTION_FORMAT21t REGISTER COMMA (label_ref_or_offset) {$size = Format.Format21t.size;}
- -> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER label_ref_or_offset);
+ INSTRUCTION_FORMAT21t REGISTER COMMA label_ref
+ -> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER label_ref);
-insn_format22b returns [int size]
+insn_format22b
: //e.g. add-int v0, v1, 123
- INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22b.size;}
+ INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal
-> ^(I_STATEMENT_FORMAT22b[$start, "I_STATEMENT_FORMAT22b"] INSTRUCTION_FORMAT22b REGISTER REGISTER integral_literal);
-insn_format22c_field returns [int size]
+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 {$size = Format.Format22c.size;}
+ 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);
-insn_format22c_field_odex returns [int size]
+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 {$size = Format.Format22c.size;}
+ INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field
{
- if (!allowOdex || Opcode.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);
}
}
-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER REGISTER fully_qualified_field);
-insn_format22c_type returns [int size]
+insn_format22c_type
: //e.g. instance-of v0, v1, Ljava/lang/String;
- INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor {$size = Format.Format22c.size;}
+ INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor
-> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor);
-insn_format22cs_field returns [int size]
+insn_format22cs_field
: //e.g. iget-quick v0, v1, field@0xc
INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22cs_FIELD.text);
};
-insn_format22s returns [int size]
+insn_format22s
: //e.g. add-int/lit16 v0, v1, 12345
- instruction_format22s REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22s.size;}
+ instruction_format22s REGISTER COMMA REGISTER COMMA integral_literal
-> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] instruction_format22s REGISTER REGISTER integral_literal);
-insn_format22t returns [int size]
+insn_format22t
: //e.g. if-eq v0, v1, endloop:
- INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref_or_offset {$size = Format.Format22t.size;}
- -> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER label_ref_or_offset);
+ INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref
+ -> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER label_ref);
-insn_format22x returns [int size]
+insn_format22x
: //e.g. move/from16 v1, v1234
- INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER {$size = Format.Format22x.size;}
+ INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER
-> ^(I_STATEMENT_FORMAT22x[$start, "I_STATEMENT_FORMAT22x"] INSTRUCTION_FORMAT22x REGISTER REGISTER);
-insn_format23x returns [int size]
+insn_format23x
: //e.g. add-int v1, v2, v3
- INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER {$size = Format.Format23x.size;}
+ INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER
-> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER);
-insn_format30t returns [int size]
+insn_format30t
: //e.g. goto/32 endloop:
- INSTRUCTION_FORMAT30t label_ref_or_offset {$size = Format.Format30t.size;}
- -> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t label_ref_or_offset);
+ INSTRUCTION_FORMAT30t label_ref
+ -> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t label_ref);
-insn_format31c returns [int size]
+insn_format31c
: //e.g. const-string/jumbo v1 "Hello World!"
- INSTRUCTION_FORMAT31c REGISTER COMMA STRING_LITERAL {$size = Format.Format31c.size;}
+ INSTRUCTION_FORMAT31c REGISTER COMMA STRING_LITERAL
->^(I_STATEMENT_FORMAT31c[$start, "I_STATEMENT_FORMAT31c"] INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL);
-insn_format31i returns [int size]
+insn_format31i
: //e.g. const v0, 123456
- instruction_format31i REGISTER COMMA fixed_32bit_literal {$size = Format.Format31i.size;}
+ instruction_format31i REGISTER COMMA fixed_32bit_literal
-> ^(I_STATEMENT_FORMAT31i[$start, "I_STATEMENT_FORMAT31i"] instruction_format31i REGISTER fixed_32bit_literal);
-insn_format31t returns [int size]
+insn_format31t
: //e.g. fill-array-data v0, ArrayData:
- INSTRUCTION_FORMAT31t REGISTER COMMA label_ref_or_offset {$size = Format.Format31t.size;}
- {
- if ($INSTRUCTION_FORMAT31t.text.equals("packed-switch")) {
- CommonTree root = new CommonTree(new CommonToken(I_PACKED_SWITCH_DECLARATION, "I_PACKED_SWITCH_DECLARATION"));
- CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress)));
- root.addChild(address);
- root.addChild($label_ref_or_offset.tree.dupNode());
- $statements_and_directives::packedSwitchDeclarations.add(root);
- } else if ($INSTRUCTION_FORMAT31t.text.equals("sparse-switch")) {
- CommonTree root = new CommonTree(new CommonToken(I_SPARSE_SWITCH_DECLARATION, "I_SPARSE_SWITCH_DECLARATION"));
- CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress)));
- root.addChild(address);
- root.addChild($label_ref_or_offset.tree.dupNode());
- $statements_and_directives::sparseSwitchDeclarations.add(root);
- }
- }
- -> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER label_ref_or_offset);
+ INSTRUCTION_FORMAT31t REGISTER COMMA label_ref
+ -> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER label_ref);
-insn_format32x returns [int size]
+insn_format32x
: //e.g. move/16 v4567, v1234
- INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER {$size = Format.Format32x.size;}
+ INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER
-> ^(I_STATEMENT_FORMAT32x[$start, "I_STATEMENT_FORMAT32x"] INSTRUCTION_FORMAT32x REGISTER REGISTER);
-insn_format35c_method returns [int size]
+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 {$size = Format.Format35c.size;}
+ 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);
-insn_format35c_type returns [int size]
+insn_format35c_type
: //e.g. filled-new-array {v0,v1}, I
- INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format35c.size;}
+ INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor
-> ^(I_STATEMENT_FORMAT35c_TYPE[$start, "I_STATEMENT_FORMAT35c_TYPE"] INSTRUCTION_FORMAT35c_TYPE register_list nonvoid_type_descriptor);
-insn_format35c_method_odex returns [int size]
+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
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35c_METHOD_ODEX.text);
};
-insn_format35mi_method returns [int size]
+insn_format35mi_method
: //e.g. execute-inline {v0, v1}, inline@0x4
INSTRUCTION_FORMAT35mi_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA INLINE_INDEX
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35mi_METHOD.text);
};
-insn_format35ms_method returns [int size]
+insn_format35ms_method
: //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4
INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_INDEX
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35ms_METHOD.text);
};
-insn_format3rc_method returns [int size]
+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 {$size = Format.Format3rc.size;}
+ 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);
-insn_format3rc_method_odex returns [int size]
+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
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rc_METHOD_ODEX.text);
};
-insn_format3rc_type returns [int size]
+insn_format3rc_type
: //e.g. filled-new-array/range {v0..v6}, I
- INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format3rc.size;}
+ INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor
-> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor);
-insn_format3rmi_method returns [int size]
+insn_format3rmi_method
: //e.g. execute-inline/range {v0 .. v10}, inline@0x14
INSTRUCTION_FORMAT3rmi_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA INLINE_INDEX
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rmi_METHOD.text);
};
-insn_format3rms_method returns [int size]
+insn_format3rms_method
: //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14
INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_INDEX
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text);
};
-insn_format41c_type returns [int size]
- : //e.g. const-class/jumbo v2, Lorg/jf/HelloWorld2/HelloWorld2;
- INSTRUCTION_FORMAT41c_TYPE REGISTER COMMA reference_type_descriptor {$size = Format.Format41c.size;}
- -> ^(I_STATEMENT_FORMAT41c_TYPE[$start, "I_STATEMENT_FORMAT41c"] INSTRUCTION_FORMAT41c_TYPE REGISTER reference_type_descriptor);
-
-insn_format41c_field returns [int size]
- : //e.g. sget-object/jumbo v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
- INSTRUCTION_FORMAT41c_FIELD REGISTER COMMA fully_qualified_field {$size = Format.Format41c.size;}
- -> ^(I_STATEMENT_FORMAT41c_FIELD[$start, "I_STATEMENT_FORMAT41c_FIELD"] INSTRUCTION_FORMAT41c_FIELD REGISTER fully_qualified_field);
-
-insn_format41c_field_odex returns [int size]
- : //e.g. sget-object-volatile/jumbo v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
- INSTRUCTION_FORMAT41c_FIELD_ODEX REGISTER COMMA fully_qualified_field {$size = Format.Format41c.size;}
- {
- throwOdexedInstructionException(input, $INSTRUCTION_FORMAT41c_FIELD_ODEX.text);
- };
-
-insn_format51l returns [int size]
+insn_format51l
: //e.g. const-wide v0, 5000000000L
- INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal {$size = Format.Format51l.size;}
+ INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal
-> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal);
-insn_format52c_type returns [int size]
- : //e.g. instance-of/jumbo v0, v1, Ljava/lang/String;
- INSTRUCTION_FORMAT52c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor {$size = Format.Format52c.size;}
- -> ^(I_STATEMENT_FORMAT52c_TYPE[$start, "I_STATEMENT_FORMAT52c_TYPE"] INSTRUCTION_FORMAT52c_TYPE REGISTER REGISTER nonvoid_type_descriptor);
-
-insn_format52c_field returns [int size]
- : //e.g. iput-object/jumbo v1, v0 Lorg/jf/HelloWorld2/HelloWorld2;->helloWorld:Ljava/lang/String;
- INSTRUCTION_FORMAT52c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format52c.size;}
- -> ^(I_STATEMENT_FORMAT52c_FIELD[$start, "I_STATEMENT_FORMAT52c_FIELD"] INSTRUCTION_FORMAT52c_FIELD REGISTER REGISTER fully_qualified_field);
-
-insn_format52c_field_odex returns [int size]
- : //e.g. iput-object-volatile/jumbo v1, v0 Lorg/jf/HelloWorld2/HelloWorld2;->helloWorld:Ljava/lang/String;
- INSTRUCTION_FORMAT52c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format52c.size;}
- {
- throwOdexedInstructionException(input, $INSTRUCTION_FORMAT52c_FIELD_ODEX.text);
- };
-
-insn_format5rc_method returns [int size]
- : //e.g. invoke-virtual/jumbo {v25..v26}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
- INSTRUCTION_FORMAT5rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format5rc.size;}
- -> ^(I_STATEMENT_FORMAT5rc_METHOD[$start, "I_STATEMENT_FORMAT5rc_METHOD"] INSTRUCTION_FORMAT5rc_METHOD register_range fully_qualified_method);
-
-insn_format5rc_method_odex returns [int size]
- : //e.g. invoke-object-init/jumbo {v25}, Ljava/lang/Object-><init>()V
- INSTRUCTION_FORMAT5rc_METHOD_ODEX OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format5rc.size;}
- {
- throwOdexedInstructionException(input, $INSTRUCTION_FORMAT5rc_METHOD_ODEX.text);
- };
-
-insn_format5rc_type returns [int size]
- : //e.g. filled-new-array/jumbo {v0..v6}, I
- INSTRUCTION_FORMAT5rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format5rc.size;}
- -> ^(I_STATEMENT_FORMAT5rc_TYPE[$start, "I_STATEMENT_FORMAT5rc_TYPE"] INSTRUCTION_FORMAT5rc_TYPE register_range nonvoid_type_descriptor);
-
-insn_array_data_directive returns [int size]
- @init {boolean needsNop = false;}
- : ARRAY_DATA_DIRECTIVE
+insn_array_data_directive
+ : ARRAY_DATA_DIRECTIVE
+ parsed_integer_literal
{
- if (($method::currentAddress \% 2) != 0) {
- needsNop = true;
- $size = 2;
- } else {
- $size = 0;
- }
+ int elementWidth = $parsed_integer_literal.value;
+ if (elementWidth != 4 && elementWidth != 8 && elementWidth != 1 && elementWidth != 2) {
+ throw new SemanticException(input, $start, "Invalid element width: \%d. Must be 1, 2, 4 or 8", elementWidth);
+ }
}
+ fixed_literal* END_ARRAY_DATA_DIRECTIVE
- integral_literal (fixed_literal {$size+=$fixed_literal.size;})* END_ARRAY_DATA_DIRECTIVE
- {$size = (($size + 1)/2)*2 + 8;}
-
- /*add a nop statement before this if needed to force the correct alignment*/
- -> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
- ^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE integral_literal) ^(I_ARRAY_ELEMENTS fixed_literal*))
-
- -> ^(I_STATEMENT_ARRAY_DATA[$start, "I_STATEMENT_ARRAY_DATA"] ^(I_ARRAY_ELEMENT_SIZE integral_literal)
+ -> ^(I_STATEMENT_ARRAY_DATA[$start, "I_STATEMENT_ARRAY_DATA"] ^(I_ARRAY_ELEMENT_SIZE parsed_integer_literal)
^(I_ARRAY_ELEMENTS fixed_literal*));
-insn_packed_switch_directive returns [int size]
- @init {boolean needsNop = false; int targetCount = 0;}
+insn_packed_switch_directive
: PACKED_SWITCH_DIRECTIVE
- {
- targetCount = 0;
- if (($method::currentAddress \% 2) != 0) {
- needsNop = true;
- $size = 2;
- } else {
- $size = 0;
- }
- }
-
fixed_32bit_literal
-
- (switch_target += label_ref_or_offset {$size+=4; targetCount++;})*
-
- END_PACKED_SWITCH_DIRECTIVE {$size = $size + 8;}
-
- /*add a nop statement before this if needed to force the correct alignment*/
- -> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
- ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
- ^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
- ^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"]
- I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*)
- )
-
+ label_ref*
+ END_PACKED_SWITCH_DIRECTIVE
-> ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
- ^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"]
- I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*)
+ ^(I_PACKED_SWITCH_ELEMENTS[$start, "I_PACKED_SWITCH_ELEMENTS"]
+ label_ref*)
);
-insn_sparse_switch_directive returns [int size]
- @init {boolean needsNop = false; int targetCount = 0;}
+insn_sparse_switch_directive
: SPARSE_SWITCH_DIRECTIVE
- {
- targetCount = 0;
- if (($method::currentAddress \% 2) != 0) {
- needsNop = true;
- $size = 2;
- } else {
- $size = 0;
- }
- }
-
- (fixed_32bit_literal ARROW switch_target += label_ref_or_offset {$size += 8; targetCount++;})*
-
- END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;}
-
- /*add a nop statement before this if needed to force the correct alignment*/
- -> {needsNop}?
- ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
- ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
- I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)]
- ^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*)
- ^(I_SPARSE_SWITCH_TARGETS $switch_target*)
- )
-
+ (fixed_32bit_literal ARROW label_ref)*
+ END_SPARSE_SWITCH_DIRECTIVE
-> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
- I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)]
- ^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*)
- ^(I_SPARSE_SWITCH_TARGETS $switch_target*)); \ No newline at end of file
+ ^(I_SPARSE_SWITCH_ELEMENTS[$start, "I_SPARSE_SWITCH_ELEMENTS"] (fixed_32bit_literal label_ref)*)); \ No newline at end of file
diff --git a/smali/src/main/antlr3/smaliTreeWalker.g b/smali/src/main/antlr3/smaliTreeWalker.g
index 2fdf715b..89eaf4a9 100644
--- a/smali/src/main/antlr3/smaliTreeWalker.g
+++ b/smali/src/main/antlr3/smaliTreeWalker.g
@@ -36,31 +36,68 @@ options {
@header {
package org.jf.smali;
-import com.google.common.collect.ImmutableSortedMap;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.regex.*;
-import java.lang.Float;
-import java.lang.Double;
-
-import org.jf.dexlib.*;
-import org.jf.dexlib.EncodedValue.*;
-import org.jf.dexlib.Util.*;
-import org.jf.dexlib.Code.*;
-import org.jf.dexlib.Code.Format.*;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.antlr.runtime.BitSet;
+import org.antlr.runtime.*;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.TreeNodeStream;
+import org.antlr.runtime.tree.TreeParser;
+import org.antlr.runtime.tree.TreeRuleReturnScope;
+import org.jf.dexlib2.*;
+import org.jf.dexlib2.builder.Label;
+import org.jf.dexlib2.builder.MethodImplementationBuilder;
+import org.jf.dexlib2.builder.SwitchLabelElement;
+import org.jf.dexlib2.builder.instruction.*;
+import org.jf.dexlib2.iface.Annotation;
+import org.jf.dexlib2.iface.AnnotationElement;
+import org.jf.dexlib2.iface.ClassDef;
+import org.jf.dexlib2.iface.MethodImplementation;
+import org.jf.dexlib2.iface.reference.FieldReference;
+import org.jf.dexlib2.iface.reference.MethodReference;
+import org.jf.dexlib2.iface.value.EncodedValue;
+import org.jf.dexlib2.immutable.ImmutableAnnotation;
+import org.jf.dexlib2.immutable.ImmutableAnnotationElement;
+import org.jf.dexlib2.immutable.reference.ImmutableFieldReference;
+import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
+import org.jf.dexlib2.immutable.reference.ImmutableReference;
+import org.jf.dexlib2.immutable.reference.ImmutableTypeReference;
+import org.jf.dexlib2.immutable.value.*;
+import org.jf.dexlib2.util.MethodUtil;
+import org.jf.dexlib2.writer.InstructionFactory;
+import org.jf.dexlib2.writer.builder.*;
+import org.jf.util.LinearSearch;
+
+import java.util.*;
}
@members {
- public DexFile dexFile;
- public TypeIdItem classType;
+ public String classType;
private boolean verboseErrors = false;
+ private int apiLevel = 15;
+ private Opcodes opcodes = new Opcodes(apiLevel);
+ private DexBuilder dexBuilder;
+
+ public void setDexBuilder(DexBuilder dexBuilder) {
+ this.dexBuilder = dexBuilder;
+ }
+
+ public void setApiLevel(int apiLevel) {
+ this.opcodes = new Opcodes(apiLevel);
+ this.apiLevel = apiLevel;
+ }
public void setVerboseErrors(boolean verboseErrors) {
this.verboseErrors = verboseErrors;
}
- private byte parseRegister_nibble(String register, int totalMethodRegisters, int methodParameterRegisters)
- throws SemanticException {
+ private byte parseRegister_nibble(String register)
+ throws SemanticException {
+ int totalMethodRegisters = method_stack.peek().totalMethodRegisters;
+ int methodParameterRegisters = method_stack.peek().methodParameterRegisters;
+
//register should be in the format "v12"
int val = Byte.parseByte(register.substring(1));
if (register.charAt(0) == 'p') {
@@ -74,8 +111,10 @@ import org.jf.dexlib.Code.Format.*;
}
//return a short, because java's byte is signed
- private short parseRegister_byte(String register, int totalMethodRegisters, int methodParameterRegisters)
- throws SemanticException {
+ private short parseRegister_byte(String register)
+ throws SemanticException {
+ int totalMethodRegisters = method_stack.peek().totalMethodRegisters;
+ int methodParameterRegisters = method_stack.peek().methodParameterRegisters;
//register should be in the format "v123"
int val = Short.parseShort(register.substring(1));
if (register.charAt(0) == 'p') {
@@ -88,8 +127,10 @@ import org.jf.dexlib.Code.Format.*;
}
//return an int because java's short is signed
- private int parseRegister_short(String register, int totalMethodRegisters, int methodParameterRegisters)
- throws SemanticException {
+ private int parseRegister_short(String register)
+ throws SemanticException {
+ int totalMethodRegisters = method_stack.peek().totalMethodRegisters;
+ int methodParameterRegisters = method_stack.peek().methodParameterRegisters;
//register should be in the format "v12345"
int val = Integer.parseInt(register.substring(1));
if (register.charAt(0) == 'p') {
@@ -115,36 +156,11 @@ import org.jf.dexlib.Code.Format.*;
}
}
-
-
-smali_file
+smali_file returns[ClassDef classDef]
: ^(I_CLASS_DEF header methods fields annotations)
{
- AnnotationDirectoryItem annotationDirectoryItem = null;
- ClassDefItem classDefItem = null;
- ClassDataItem classDataItem = null;
-
- if ($methods.methodAnnotations != null ||
- $methods.parameterAnnotations != null ||
- $fields.fieldAnnotations != null ||
- $annotations.annotationSetItem != null) {
- annotationDirectoryItem = AnnotationDirectoryItem.internAnnotationDirectoryItem(
- dexFile,
- $annotations.annotationSetItem,
- $fields.fieldAnnotations,
- $methods.methodAnnotations,
- $methods.parameterAnnotations);
- }
-
- if ($fields.staticFields.size() != 0 || $fields.instanceFields.size() != 0 ||
- $methods.directMethods.size() != 0 || $methods.virtualMethods.size()!= 0) {
- classDataItem = ClassDataItem.internClassDataItem(dexFile, $fields.staticFields, $fields.instanceFields,
- $methods.directMethods, $methods.virtualMethods);
- }
-
- classDefItem = ClassDefItem.internClassDefItem(dexFile, $header.classType, $header.accessFlags,
- $header.superType, $header.implementsList, $header.sourceSpec, annotationDirectoryItem,
- classDataItem, $fields.staticFieldInitialValues);
+ $classDef = dexBuilder.internClassDef($header.classType, $header.accessFlags, $header.superType,
+ $header.implementsList, $header.sourceSpec, $annotations.annotations, $fields.fields, $methods.methods);
};
catch [Exception ex] {
if (verboseErrors) {
@@ -154,7 +170,7 @@ smali_file
}
-header returns[TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementsList, StringIdItem sourceSpec]
+header returns[String classType, int accessFlags, String superType, List<String> implementsList, String sourceSpec]
: class_spec super_spec? implements_list source_spec
{
classType = $class_spec.type;
@@ -166,45 +182,43 @@ header returns[TypeIdItem classType, int accessFlags, TypeIdItem superType, Type
};
-class_spec returns[TypeIdItem type, int accessFlags]
- : class_type_descriptor access_list
+class_spec returns[String type, int accessFlags]
+ : CLASS_DESCRIPTOR access_list
{
- $type = $class_type_descriptor.type;
+ $type = $CLASS_DESCRIPTOR.text;
$accessFlags = $access_list.value;
};
-super_spec returns[TypeIdItem type]
- : ^(I_SUPER class_type_descriptor)
+super_spec returns[String type]
+ : ^(I_SUPER CLASS_DESCRIPTOR)
{
- $type = $class_type_descriptor.type;
+ $type = $CLASS_DESCRIPTOR.text;
};
-implements_spec returns[TypeIdItem type]
- : ^(I_IMPLEMENTS class_type_descriptor)
+implements_spec returns[String type]
+ : ^(I_IMPLEMENTS CLASS_DESCRIPTOR)
{
- $type = $class_type_descriptor.type;
+ $type = $CLASS_DESCRIPTOR.text;
};
-implements_list returns[TypeListItem implementsList]
-@init { List<TypeIdItem> typeList; }
- : {typeList = new LinkedList<TypeIdItem>();}
+implements_list returns[List<String> implementsList]
+@init { List<String> typeList; }
+ : {typeList = Lists.newArrayList();}
(implements_spec {typeList.add($implements_spec.type);} )*
{
if (typeList.size() > 0) {
- $implementsList = TypeListItem.internTypeListItem(dexFile, typeList);
+ $implementsList = typeList;
} else {
$implementsList = null;
}
};
-source_spec returns[StringIdItem source]
+source_spec returns[String source]
: {$source = null;}
- ^(I_SOURCE string_literal {$source = StringIdItem.internStringIdItem(dexFile, $string_literal.value);})
+ ^(I_SOURCE string_literal {$source = $string_literal.value;})
| /*epsilon*/;
-
-
access_list returns [int value]
@init
{
@@ -219,92 +233,34 @@ access_list returns [int value]
)*);
-fields returns[List<ClassDataItem.EncodedField> staticFields, List<ClassDataItem.EncodedField> instanceFields,
- List<ClassDefItem.StaticFieldInitializer> staticFieldInitialValues, List<AnnotationDirectoryItem.FieldAnnotation> fieldAnnotations]
- @init
- {
- $staticFields = new LinkedList<ClassDataItem.EncodedField>();
- $instanceFields = new LinkedList<ClassDataItem.EncodedField>();
- $staticFieldInitialValues = new ArrayList<ClassDefItem.StaticFieldInitializer>();
- }
+fields returns[List<BuilderField> fields]
+ @init {$fields = Lists.newArrayList();}
: ^(I_FIELDS
(field
{
- if ($field.encodedField.isStatic()) {
- $staticFields.add($field.encodedField);
- $staticFieldInitialValues.add(new ClassDefItem.StaticFieldInitializer(
- $field.encodedValue, $field.encodedField));
- } else {
- $instanceFields.add($field.encodedField);
- }
- if ($field.fieldAnnotationSet != null) {
- if ($fieldAnnotations == null) {
- $fieldAnnotations = new LinkedList<AnnotationDirectoryItem.FieldAnnotation>();
- }
- AnnotationDirectoryItem.FieldAnnotation fieldAnnotation = new AnnotationDirectoryItem.FieldAnnotation(
- $field.encodedField.field, $field.fieldAnnotationSet);
- $fieldAnnotations.add(fieldAnnotation);
- }
+ $fields.add($field.field);
})*);
-methods returns[List<ClassDataItem.EncodedMethod> directMethods,
- List<ClassDataItem.EncodedMethod> virtualMethods,
- List<AnnotationDirectoryItem.MethodAnnotation> methodAnnotations,
- List<AnnotationDirectoryItem.ParameterAnnotation> parameterAnnotations]
- @init
- {
- $directMethods = new LinkedList<ClassDataItem.EncodedMethod>();
- $virtualMethods = new LinkedList<ClassDataItem.EncodedMethod>();
- }
+methods returns[List<BuilderMethod> methods]
+ @init {$methods = Lists.newArrayList();}
: ^(I_METHODS
(method
{
- if ($method.encodedMethod.isDirect()) {
- $directMethods.add($method.encodedMethod);
- } else {
- $virtualMethods.add($method.encodedMethod);
- }
- if ($method.methodAnnotationSet != null) {
- if ($methodAnnotations == null) {
- $methodAnnotations = new LinkedList<AnnotationDirectoryItem.MethodAnnotation>();
- }
- AnnotationDirectoryItem.MethodAnnotation methodAnnotation =
- new AnnotationDirectoryItem.MethodAnnotation($method.encodedMethod.method, $method.methodAnnotationSet);
- $methodAnnotations.add(methodAnnotation);
- }
- if ($method.parameterAnnotationSets != null) {
- if ($parameterAnnotations == null) {
- $parameterAnnotations = new LinkedList<AnnotationDirectoryItem.ParameterAnnotation>();
- }
- AnnotationDirectoryItem.ParameterAnnotation parameterAnnotation =
- new AnnotationDirectoryItem.ParameterAnnotation($method.encodedMethod.method,
- $method.parameterAnnotationSets);
- $parameterAnnotations.add(parameterAnnotation);
- }
+ $methods.add($method.ret);
})*);
-field returns [ClassDataItem.EncodedField encodedField, EncodedValue encodedValue, AnnotationSetItem fieldAnnotationSet]
+field returns [BuilderField field]
:^(I_FIELD SIMPLE_NAME access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) field_initial_value annotations?)
{
- StringIdItem memberName = StringIdItem.internStringIdItem(dexFile, $SIMPLE_NAME.text);
- TypeIdItem fieldType = $nonvoid_type_descriptor.type;
+ int accessFlags = $access_list.value;
- FieldIdItem fieldIdItem = FieldIdItem.internFieldIdItem(dexFile, classType, fieldType, memberName);
- $encodedField = new ClassDataItem.EncodedField(fieldIdItem, $access_list.value);
- if ($field_initial_value.encodedValue != null) {
- if (!$encodedField.isStatic()) {
+ if (!AccessFlags.STATIC.isSet(accessFlags) && $field_initial_value.encodedValue != null) {
throw new SemanticException(input, "Initial field values can only be specified for static fields.");
- }
-
- $encodedValue = $field_initial_value.encodedValue;
- } else {
- $encodedValue = null;
}
- if ($annotations.annotationSetItem != null) {
- $fieldAnnotationSet = $annotations.annotationSetItem;
- }
+ $field = dexBuilder.internField(classType, $SIMPLE_NAME.text, $nonvoid_type_descriptor.type, $access_list.value,
+ $field_initial_value.encodedValue, $annotations.annotations);
};
@@ -313,36 +269,34 @@ field_initial_value returns[EncodedValue encodedValue]
| /*epsilon*/;
literal returns[EncodedValue encodedValue]
- : integer_literal { $encodedValue = new IntEncodedValue($integer_literal.value); }
- | long_literal { $encodedValue = new LongEncodedValue($long_literal.value); }
- | short_literal { $encodedValue = new ShortEncodedValue($short_literal.value); }
- | byte_literal { $encodedValue = new ByteEncodedValue($byte_literal.value); }
- | float_literal { $encodedValue = new FloatEncodedValue($float_literal.value); }
- | double_literal { $encodedValue = new DoubleEncodedValue($double_literal.value); }
- | char_literal { $encodedValue = new CharEncodedValue($char_literal.value); }
- | string_literal { $encodedValue = new StringEncodedValue(StringIdItem.internStringIdItem(dexFile, $string_literal.value)); }
- | bool_literal { $encodedValue = $bool_literal.value?BooleanEncodedValue.TrueValue:BooleanEncodedValue.FalseValue; }
- | NULL_LITERAL { $encodedValue = NullEncodedValue.NullValue; }
- | type_descriptor { $encodedValue = new TypeEncodedValue($type_descriptor.type); }
- | array_literal { $encodedValue = new ArrayEncodedValue($array_literal.values); }
- | subannotation { $encodedValue = new AnnotationEncodedValue($subannotation.annotationType, $subannotation.elementNames, $subannotation.elementValues); }
- | field_literal { $encodedValue = new FieldEncodedValue($field_literal.value); }
- | method_literal { $encodedValue = new MethodEncodedValue($method_literal.value); }
- | enum_literal { $encodedValue = new EnumEncodedValue($enum_literal.value); };
-
+ : integer_literal { $encodedValue = new ImmutableIntEncodedValue($integer_literal.value); }
+ | long_literal { $encodedValue = new ImmutableLongEncodedValue($long_literal.value); }
+ | short_literal { $encodedValue = new ImmutableShortEncodedValue($short_literal.value); }
+ | byte_literal { $encodedValue = new ImmutableByteEncodedValue($byte_literal.value); }
+ | float_literal { $encodedValue = new ImmutableFloatEncodedValue($float_literal.value); }
+ | double_literal { $encodedValue = new ImmutableDoubleEncodedValue($double_literal.value); }
+ | char_literal { $encodedValue = new ImmutableCharEncodedValue($char_literal.value); }
+ | string_literal { $encodedValue = new ImmutableStringEncodedValue($string_literal.value); }
+ | bool_literal { $encodedValue = ImmutableBooleanEncodedValue.forBoolean($bool_literal.value); }
+ | NULL_LITERAL { $encodedValue = ImmutableNullEncodedValue.INSTANCE; }
+ | type_descriptor { $encodedValue = new ImmutableTypeEncodedValue($type_descriptor.type); }
+ | array_literal { $encodedValue = new ImmutableArrayEncodedValue($array_literal.elements); }
+ | subannotation { $encodedValue = new ImmutableAnnotationEncodedValue($subannotation.annotationType, $subannotation.elements); }
+ | field_literal { $encodedValue = new ImmutableFieldEncodedValue($field_literal.value); }
+ | method_literal { $encodedValue = new ImmutableMethodEncodedValue($method_literal.value); }
+ | enum_literal { $encodedValue = new ImmutableEnumEncodedValue($enum_literal.value); };
//everything but string
-fixed_size_literal returns[byte[\] value]
- : integer_literal { $value = LiteralTools.intToBytes($integer_literal.value); }
- | long_literal { $value = LiteralTools.longToBytes($long_literal.value); }
- | short_literal { $value = LiteralTools.shortToBytes($short_literal.value); }
- | byte_literal { $value = new byte[] { $byte_literal.value }; }
- | float_literal { $value = LiteralTools.floatToBytes($float_literal.value); }
- | double_literal { $value = LiteralTools.doubleToBytes($double_literal.value); }
- | char_literal { $value = LiteralTools.charToBytes($char_literal.value); }
- | bool_literal { $value = LiteralTools.boolToBytes($bool_literal.value); };
+fixed_64bit_literal_number returns[Number value]
+ : integer_literal { $value = $integer_literal.value; }
+ | long_literal { $value = $long_literal.value; }
+ | short_literal { $value = $short_literal.value; }
+ | byte_literal { $value = $byte_literal.value; }
+ | float_literal { $value = Float.floatToRawIntBits($float_literal.value); }
+ | double_literal { $value = Double.doubleToRawLongBits($double_literal.value); }
+ | char_literal { $value = (int)$char_literal.value; }
+ | bool_literal { $value = $bool_literal.value?1:0; };
-//everything but string
fixed_64bit_literal returns[long value]
: integer_literal { $value = $integer_literal.value; }
| long_literal { $value = $long_literal.value; }
@@ -364,127 +318,82 @@ fixed_32bit_literal returns[int value]
| char_literal { $value = $char_literal.value; }
| bool_literal { $value = $bool_literal.value?1:0; };
-array_elements returns[List<byte[\]> values]
- : {$values = new ArrayList<byte[]>();}
+array_elements returns[List<Number> elements]
+ : {$elements = Lists.newArrayList();}
^(I_ARRAY_ELEMENTS
- (fixed_size_literal
+ (fixed_64bit_literal_number
{
- $values.add($fixed_size_literal.value);
+ $elements.add($fixed_64bit_literal_number.value);
})*);
-packed_switch_target_count returns[int targetCount]
- : I_PACKED_SWITCH_TARGET_COUNT {$targetCount = Integer.parseInt($I_PACKED_SWITCH_TARGET_COUNT.text);};
-
-packed_switch_targets[int baseAddress] returns[int[\] targets]
+packed_switch_elements returns[List<Label> elements]
+ @init {$elements = Lists.newArrayList();}
:
- ^(I_PACKED_SWITCH_TARGETS
- packed_switch_target_count
- {
- int targetCount = $packed_switch_target_count.targetCount;
- $targets = new int[targetCount];
- int targetsPosition = 0;
- }
-
- (offset_or_label
- {
- $targets[targetsPosition++] = ($method::currentAddress + $offset_or_label.offsetValue) - $baseAddress;
- })*
- );
-
-sparse_switch_target_count returns[int targetCount]
- : I_SPARSE_SWITCH_TARGET_COUNT {$targetCount = Integer.parseInt($I_SPARSE_SWITCH_TARGET_COUNT.text);};
-
-sparse_switch_keys[int targetCount] returns[int[\] keys]
- : {
- $keys = new int[$targetCount];
- int keysPosition = 0;
- }
- ^(I_SPARSE_SWITCH_KEYS
- (fixed_32bit_literal
- {
- $keys[keysPosition++] = $fixed_32bit_literal.value;
- })*
+ ^(I_PACKED_SWITCH_ELEMENTS
+ (label_ref { $elements.add($label_ref.label); })*
);
-
-sparse_switch_targets[int baseAddress, int targetCount] returns[int[\] targets]
- : {
- $targets = new int[$targetCount];
- int targetsPosition = 0;
- }
- ^(I_SPARSE_SWITCH_TARGETS
- (offset_or_label
- {
- $targets[targetsPosition++] = ($method::currentAddress + $offset_or_label.offsetValue) - $baseAddress;
- })*
+sparse_switch_elements returns[List<SwitchLabelElement> elements]
+ @init {$elements = Lists.newArrayList();}
+ :
+ ^(I_SPARSE_SWITCH_ELEMENTS
+ (fixed_32bit_literal label_ref
+ {
+ $elements.add(new SwitchLabelElement($fixed_32bit_literal.value, $label_ref.label));
+ })*
);
-method returns[ClassDataItem.EncodedMethod encodedMethod,
- AnnotationSetItem methodAnnotationSet,
- AnnotationSetRefList parameterAnnotationSets]
+method returns[BuilderMethod ret]
scope
{
- HashMap<String, Integer> labels;
- TryListBuilder tryList;
- int currentAddress;
- DebugInfoBuilder debugInfo;
- HashMap<Integer, Integer> packedSwitchDeclarations;
- HashMap<Integer, Integer> sparseSwitchDeclarations;
+ boolean isStatic;
+ int totalMethodRegisters;
+ int methodParameterRegisters;
+ MethodImplementationBuilder methodBuilder;
}
@init
{
- MethodIdItem methodIdItem = null;
- int totalMethodRegisters = 0;
- int methodParameterRegisters = 0;
+ $method::totalMethodRegisters = 0;
+ $method::methodParameterRegisters = 0;
int accessFlags = 0;
- boolean isStatic = false;
+ $method::isStatic = false;
}
- : {
- $method::labels = new HashMap<String, Integer>();
- $method::tryList = new TryListBuilder();
- $method::currentAddress = 0;
- $method::debugInfo = new DebugInfoBuilder();
- $method::packedSwitchDeclarations = new HashMap<Integer, Integer>();
- $method::sparseSwitchDeclarations = new HashMap<Integer, Integer>();
- }
+ :
^(I_METHOD
method_name_and_prototype
access_list
{
- methodIdItem = $method_name_and_prototype.methodIdItem;
accessFlags = $access_list.value;
- isStatic = (accessFlags & AccessFlags.STATIC.getValue()) != 0;
- methodParameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
- if (!isStatic) {
- methodParameterRegisters++;
- }
+ $method::isStatic = AccessFlags.STATIC.isSet(accessFlags);
+ $method::methodParameterRegisters =
+ MethodUtil.getParameterRegisterCount($method_name_and_prototype.parameters, $method::isStatic);
}
- (registers_directive
- {
- if ($registers_directive.isLocalsDirective) {
- totalMethodRegisters = $registers_directive.registers + methodParameterRegisters;
- } else {
- totalMethodRegisters = $registers_directive.registers;
- }
- }
- )?
- labels
- packed_switch_declarations
- sparse_switch_declarations
- statements[totalMethodRegisters, methodParameterRegisters]
+ (
+ (registers_directive
+ {
+ if ($registers_directive.isLocalsDirective) {
+ $method::totalMethodRegisters = $registers_directive.registers + $method::methodParameterRegisters;
+ } else {
+ $method::totalMethodRegisters = $registers_directive.registers;
+ }
+
+ $method::methodBuilder = new MethodImplementationBuilder($method::totalMethodRegisters);
+
+ })
+ |
+ /* epsilon */
+ {
+ $method::methodBuilder = new MethodImplementationBuilder(0);
+ }
+ )
+ ordered_method_items
catches
- parameters
- ordered_debug_directives[totalMethodRegisters, methodParameterRegisters]
+ parameters[$method_name_and_prototype.parameters]
annotations
)
{
- Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> temp = $method::tryList.encodeTries();
- List<CodeItem.TryItem> tries = temp.first;
- List<CodeItem.EncodedCatchHandler> handlers = temp.second;
-
- DebugInfoItem debugInfoItem = $method::debugInfo.encodeDebugInfo(dexFile);
-
- CodeItem codeItem;
+ MethodImplementation methodImplementation = null;
+ List<BuilderTryBlock> tryBlocks = $catches.tryBlocks;
boolean isAbstract = false;
boolean isNative = false;
@@ -495,7 +404,9 @@ method returns[ClassDataItem.EncodedMethod encodedMethod,
isNative = true;
}
- if ($statements.instructions.size() == 0) {
+ methodImplementation = $method::methodBuilder.getMethodImplementation();
+
+ if (Iterables.isEmpty(methodImplementation.getInstructions())) {
if (!isAbstract && !isNative) {
throw new SemanticException(input, $I_METHOD, "A non-abstract/non-native method must have at least 1 instruction");
}
@@ -507,27 +418,23 @@ method returns[ClassDataItem.EncodedMethod encodedMethod,
methodType = "a native";
}
- if ($registers_directive.start != null) {
- if ($registers_directive.isLocalsDirective) {
- throw new SemanticException(input, $registers_directive.start, "A .locals directive is not valid in \%s method", methodType);
- } else {
- throw new SemanticException(input, $registers_directive.start, "A .registers directive is not valid in \%s method", methodType);
- }
- }
-
- if ($method::labels.size() > 0) {
- throw new SemanticException(input, $I_METHOD, "Labels cannot be present in \%s method", methodType);
- }
+ if ($registers_directive.start != null) {
+ if ($registers_directive.isLocalsDirective) {
+ throw new SemanticException(input, $registers_directive.start, "A .locals directive is not valid in \%s method", methodType);
+ } else {
+ throw new SemanticException(input, $registers_directive.start, "A .registers directive is not valid in \%s method", methodType);
+ }
+ }
- if ((tries != null && tries.size() > 0) || (handlers != null && handlers.size() > 0)) {
- throw new SemanticException(input, $I_METHOD, "try/catch blocks cannot be present in \%s method", methodType);
- }
+ if (methodImplementation.getTryBlocks().size() > 0) {
+ throw new SemanticException(input, $I_METHOD, "try/catch blocks cannot be present in \%s method", methodType);
+ }
- if (debugInfoItem != null) {
- throw new SemanticException(input, $I_METHOD, "debug directives cannot be present in \%s method", methodType);
- }
+ if (!Iterables.isEmpty(methodImplementation.getDebugItems())) {
+ throw new SemanticException(input, $I_METHOD, "debug directives cannot be present in \%s method", methodType);
+ }
- codeItem = null;
+ methodImplementation = null;
} else {
if (isAbstract) {
throw new SemanticException(input, $I_METHOD, "An abstract method cannot have any instructions");
@@ -540,67 +447,51 @@ method returns[ClassDataItem.EncodedMethod encodedMethod,
throw new SemanticException(input, $I_METHOD, "A .registers or .locals directive must be present for a non-abstract/non-final method");
}
- if (totalMethodRegisters < methodParameterRegisters) {
+ if ($method::totalMethodRegisters < $method::methodParameterRegisters) {
throw new SemanticException(input, $registers_directive.start, "This method requires at least " +
- Integer.toString(methodParameterRegisters) +
+ Integer.toString($method::methodParameterRegisters) +
" registers, for the method parameters");
}
-
- int methodParameterCount = methodIdItem.getPrototype().getParameterRegisterCount();
- if ($method::debugInfo.getParameterNameCount() > methodParameterCount) {
- throw new SemanticException(input, $I_METHOD, "Too many parameter names specified. This method only has " +
- Integer.toString(methodParameterCount) +
- " parameters.");
- }
-
- codeItem = CodeItem.internCodeItem(dexFile,
- totalMethodRegisters,
- methodParameterRegisters,
- $statements.maxOutRegisters,
- debugInfoItem,
- $statements.instructions,
- tries,
- handlers);
}
- $encodedMethod = new ClassDataItem.EncodedMethod(methodIdItem, accessFlags, codeItem);
-
- if ($annotations.annotationSetItem != null) {
- $methodAnnotationSet = $annotations.annotationSetItem;
- }
-
- if ($parameters.parameterAnnotations != null) {
- $parameterAnnotationSets = $parameters.parameterAnnotations;
- }
+ $ret = dexBuilder.internMethod(
+ classType,
+ $method_name_and_prototype.name,
+ $method_name_and_prototype.parameters,
+ $method_name_and_prototype.returnType,
+ accessFlags,
+ $annotations.annotations,
+ methodImplementation);
};
-method_prototype returns[ProtoIdItem protoIdItem]
+method_prototype returns[List<String> parameters, String returnType]
: ^(I_METHOD_PROTOTYPE ^(I_METHOD_RETURN_TYPE type_descriptor) field_type_list)
{
- TypeIdItem returnType = $type_descriptor.type;
- List<TypeIdItem> parameterTypes = $field_type_list.types;
- TypeListItem parameterTypeListItem = null;
- if (parameterTypes != null && parameterTypes.size() > 0) {
- parameterTypeListItem = TypeListItem.internTypeListItem(dexFile, parameterTypes);
- }
-
- $protoIdItem = ProtoIdItem.internProtoIdItem(dexFile, returnType, parameterTypeListItem);
+ $returnType = $type_descriptor.type;
+ $parameters = $field_type_list.types;
};
-method_name_and_prototype returns[MethodIdItem methodIdItem]
+method_name_and_prototype returns[String name, List<SmaliMethodParameter> parameters, String returnType]
: SIMPLE_NAME method_prototype
{
- String methodNameString = $SIMPLE_NAME.text;
- StringIdItem methodName = StringIdItem.internStringIdItem(dexFile, methodNameString);
- ProtoIdItem protoIdItem = $method_prototype.protoIdItem;
-
- $methodIdItem = MethodIdItem.internMethodIdItem(dexFile, classType, protoIdItem, methodName);
+ $name = $SIMPLE_NAME.text;
+ $parameters = Lists.newArrayList();
+
+ int paramRegister = 0;
+ for (String type: $method_prototype.parameters) {
+ $parameters.add(new SmaliMethodParameter(paramRegister++, type));
+ char c = type.charAt(0);
+ if (c == 'D' || c == 'J') {
+ paramRegister++;
+ }
+ }
+ $returnType = $method_prototype.returnType;
};
-field_type_list returns[List<TypeIdItem> types]
+field_type_list returns[List<String> types]
@init
{
- $types = new LinkedList<TypeIdItem>();
+ $types = Lists.newArrayList();
}
: (
nonvoid_type_descriptor
@@ -610,22 +501,18 @@ field_type_list returns[List<TypeIdItem> types]
)*;
-fully_qualified_method returns[MethodIdItem methodIdItem]
+fully_qualified_method returns[ImmutableMethodReference methodReference]
: reference_type_descriptor SIMPLE_NAME method_prototype
{
- TypeIdItem classType = $reference_type_descriptor.type;
- StringIdItem methodName = StringIdItem.internStringIdItem(dexFile, $SIMPLE_NAME.text);
- ProtoIdItem prototype = $method_prototype.protoIdItem;
- $methodIdItem = MethodIdItem.internMethodIdItem(dexFile, classType, prototype, methodName);
+ $methodReference = new ImmutableMethodReference($reference_type_descriptor.type, $SIMPLE_NAME.text,
+ $method_prototype.parameters, $method_prototype.returnType);
};
-fully_qualified_field returns[FieldIdItem fieldIdItem]
+fully_qualified_field returns[ImmutableFieldReference fieldReference]
: reference_type_descriptor SIMPLE_NAME nonvoid_type_descriptor
{
- TypeIdItem classType = $reference_type_descriptor.type;
- StringIdItem fieldName = StringIdItem.internStringIdItem(dexFile, $SIMPLE_NAME.text);
- TypeIdItem fieldType = $nonvoid_type_descriptor.type;
- $fieldIdItem = FieldIdItem.internFieldIdItem(dexFile, classType, fieldType, fieldName);
+ $fieldReference = new ImmutableFieldReference($reference_type_descriptor.type, $SIMPLE_NAME.text,
+ $nonvoid_type_descriptor.type);
};
registers_directive returns[boolean isLocalsDirective, int registers]
@@ -636,223 +523,130 @@ registers_directive returns[boolean isLocalsDirective, int registers]
short_integral_literal {$registers = $short_integral_literal.value;}
);
-labels
- : ^(I_LABELS label_def*);
-
label_def
- : ^(I_LABEL SIMPLE_NAME address)
- {
- if ($method::labels.containsKey($SIMPLE_NAME.text)) {
- throw new SemanticException(input, $I_LABEL, "Label " + $SIMPLE_NAME.text + " has multiple defintions.");
- }
-
- $method::labels.put($SIMPLE_NAME.text, $address.address);
- };
+ : ^(I_LABEL SIMPLE_NAME)
+ {
+ $method::methodBuilder.addLabel($SIMPLE_NAME.text);
+ };
-packed_switch_declarations
- : ^(I_PACKED_SWITCH_DECLARATIONS packed_switch_declaration*);
-packed_switch_declaration
- : ^(I_PACKED_SWITCH_DECLARATION address offset_or_label_absolute[$address.address])
- {
- int switchDataAddress = $offset_or_label_absolute.address;
- if ((switchDataAddress \% 2) != 0) {
- switchDataAddress++;
- }
- if (!$method::packedSwitchDeclarations.containsKey(switchDataAddress)) {
- $method::packedSwitchDeclarations.put(switchDataAddress, $address.address);
- }
- };
+catches returns[List<BuilderTryBlock> tryBlocks]
+ @init {tryBlocks = Lists.newArrayList();}
+ : ^(I_CATCHES catch_directive* catchall_directive*);
-sparse_switch_declarations
- : ^(I_SPARSE_SWITCH_DECLARATIONS sparse_switch_declaration*);
-sparse_switch_declaration
- : ^(I_SPARSE_SWITCH_DECLARATION address offset_or_label_absolute[$address.address])
- {
- int switchDataAddress = $offset_or_label_absolute.address;
- if ((switchDataAddress \% 2) != 0) {
- switchDataAddress++;
- }
- if (!$method::sparseSwitchDeclarations.containsKey(switchDataAddress)) {
- $method::sparseSwitchDeclarations.put(switchDataAddress, $address.address);
- }
+catch_directive
+ : ^(I_CATCH nonvoid_type_descriptor from=label_ref to=label_ref using=label_ref)
+ {
+ $method::methodBuilder.addCatch(dexBuilder.internTypeReference($nonvoid_type_descriptor.type),
+ $from.label, $to.label, $using.label);
+ };
- };
+catchall_directive
+ : ^(I_CATCHALL from=label_ref to=label_ref using=label_ref)
+ {
+ $method::methodBuilder.addCatch($from.label, $to.label, $using.label);
+ };
-catches : ^(I_CATCHES catch_directive* catchall_directive*);
+parameters[List<SmaliMethodParameter> parameters]
+ : ^(I_PARAMETERS (parameter[parameters])*);
-catch_directive
- : ^(I_CATCH address nonvoid_type_descriptor from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address]
- using=offset_or_label_absolute[$address.address])
+parameter[List<SmaliMethodParameter> parameters]
+ : ^(I_PARAMETER REGISTER string_literal? annotations)
{
- TypeIdItem type = $nonvoid_type_descriptor.type;
- int startAddress = $from.address;
- int endAddress = $to.address;
- int handlerAddress = $using.address;
-
- $method::tryList.addHandler(type, startAddress, endAddress, handlerAddress);
- };
+ final int registerNumber = parseRegister_short($REGISTER.text);
+ int totalMethodRegisters = $method::totalMethodRegisters;
+ int methodParameterRegisters = $method::methodParameterRegisters;
-catchall_directive
- : ^(I_CATCHALL address from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address]
- using=offset_or_label_absolute[$address.address])
- {
- int startAddress = $from.address;
- int endAddress = $to.address;
- int handlerAddress = $using.address;
+ if (registerNumber >= totalMethodRegisters) {
+ throw new SemanticException(input, $I_PARAMETER, "Register \%s is larger than the maximum register v\%d " +
+ "for this method", $REGISTER.text, totalMethodRegisters-1);
+ }
+ final int indexGuess = registerNumber - (totalMethodRegisters - methodParameterRegisters) - ($method::isStatic?0:1);
- $method::tryList.addCatchAllHandler(startAddress, endAddress, handlerAddress);
- };
+ if (indexGuess < 0) {
+ throw new SemanticException(input, $I_PARAMETER, "Register \%s is not a parameter register.",
+ $REGISTER.text);
+ }
-address returns[int address]
- : I_ADDRESS
- {
- $address = Integer.parseInt($I_ADDRESS.text);
- };
+ int parameterIndex = LinearSearch.linearSearch(parameters, SmaliMethodParameter.COMPARATOR,
+ new WithRegister() { public int getRegister() { return indexGuess; } },
+ indexGuess);
-parameters returns[AnnotationSetRefList parameterAnnotations]
- @init
- {
- int parameterCount = 0;
- List<AnnotationSetItem> annotationSetItems = new ArrayList<AnnotationSetItem>();
- }
- : ^(I_PARAMETERS (parameter
- {
- if ($parameter.parameterAnnotationSet != null) {
- while (annotationSetItems.size() < parameterCount) {
- annotationSetItems.add(AnnotationSetItem.internAnnotationSetItem(dexFile, null));
- }
- annotationSetItems.add($parameter.parameterAnnotationSet);
- }
+ if (parameterIndex < 0) {
+ throw new SemanticException(input, $I_PARAMETER, "Register \%s is the second half of a wide parameter.",
+ $REGISTER.text);
+ }
- parameterCount++;
- })*
- )
- {
- if (annotationSetItems.size() > 0) {
- while (annotationSetItems.size() < parameterCount) {
- annotationSetItems.add(AnnotationSetItem.internAnnotationSetItem(dexFile, null));
+ SmaliMethodParameter methodParameter = parameters.get(parameterIndex);
+ methodParameter.name = $string_literal.value;
+ if ($annotations.annotations != null && $annotations.annotations.size() > 0) {
+ methodParameter.annotations = $annotations.annotations;
}
- $parameterAnnotations = AnnotationSetRefList.internAnnotationSetRefList(dexFile, annotationSetItems);
- }
};
-parameter returns[AnnotationSetItem parameterAnnotationSet]
- : ^(I_PARAMETER (string_literal {$method::debugInfo.addParameterName($string_literal.value);}
- | {$method::debugInfo.addParameterName(null);}
- )
- annotations {$parameterAnnotationSet = $annotations.annotationSetItem;}
- );
-
-ordered_debug_directives[int totalMethodRegisters, int methodParameterRegisters]
- : ^(I_ORDERED_DEBUG_DIRECTIVES
- ( line
- | local[$totalMethodRegisters, $methodParameterRegisters]
- | end_local[$totalMethodRegisters, $methodParameterRegisters]
- | restart_local[$totalMethodRegisters, $methodParameterRegisters]
- | prologue
- | epilogue
- | source
- )*
- );
+debug_directive
+ : line
+ | local
+ | end_local
+ | restart_local
+ | prologue
+ | epilogue
+ | source;
line
- : ^(I_LINE integral_literal address)
+ : ^(I_LINE integral_literal)
{
- $method::debugInfo.addLine($address.address, $integral_literal.value);
+ $method::methodBuilder.addLineNumber($integral_literal.value);
};
-local[int totalMethodRegisters, int methodParameterRegisters]
- : ^(I_LOCAL REGISTER SIMPLE_NAME nonvoid_type_descriptor string_literal? address)
+local
+ : ^(I_LOCAL REGISTER ((NULL_LITERAL | name=string_literal) nonvoid_type_descriptor? signature=string_literal?)?)
{
- int registerNumber = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- if ($string_literal.value != null) {
- $method::debugInfo.addLocalExtended($address.address, registerNumber, $SIMPLE_NAME.text, $nonvoid_type_descriptor.type.getTypeDescriptor(), $string_literal.value);
- } else {
- $method::debugInfo.addLocal($address.address, registerNumber, $SIMPLE_NAME.text, $nonvoid_type_descriptor.type.getTypeDescriptor());
- }
+ int registerNumber = parseRegister_short($REGISTER.text);
+ $method::methodBuilder.addStartLocal(registerNumber,
+ dexBuilder.internNullableStringReference($name.value),
+ dexBuilder.internNullableTypeReference($nonvoid_type_descriptor.type),
+ dexBuilder.internNullableStringReference($signature.value));
};
-end_local[int totalMethodRegisters, int methodParameterRegisters]
- : ^(I_END_LOCAL REGISTER address)
+end_local
+ : ^(I_END_LOCAL REGISTER)
{
- int registerNumber = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- $method::debugInfo.addEndLocal($address.address, registerNumber);
+ int registerNumber = parseRegister_short($REGISTER.text);
+ $method::methodBuilder.addEndLocal(registerNumber);
};
-restart_local[int totalMethodRegisters, int methodParameterRegisters]
- : ^(I_RESTART_LOCAL REGISTER address)
+restart_local
+ : ^(I_RESTART_LOCAL REGISTER)
{
- int registerNumber = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- $method::debugInfo.addRestartLocal($address.address, registerNumber);
+ int registerNumber = parseRegister_short($REGISTER.text);
+ $method::methodBuilder.addRestartLocal(registerNumber);
};
prologue
- : ^(I_PROLOGUE address)
+ : I_PROLOGUE
{
- $method::debugInfo.addPrologue($address.address);
+ $method::methodBuilder.addPrologue();
};
epilogue
- : ^(I_EPILOGUE address)
+ : I_EPILOGUE
{
- $method::debugInfo.addEpilogue($address.address);
+ $method::methodBuilder.addEpilogue();
};
source
- : ^(I_SOURCE string_literal address)
+ : ^(I_SOURCE string_literal?)
{
- $method::debugInfo.addSetFile($address.address, $string_literal.value);
+ $method::methodBuilder.addSetSourceFile(dexBuilder.internNullableStringReference($string_literal.value));
};
-statements[int totalMethodRegisters, int methodParameterRegisters] returns[List<Instruction> instructions, int maxOutRegisters]
- @init
- {
- $instructions = new LinkedList<Instruction>();
- $maxOutRegisters = 0;
- }
- : ^(I_STATEMENTS (instruction[$totalMethodRegisters, $methodParameterRegisters, $instructions]
- {
- $method::currentAddress += $instructions.get($instructions.size() - 1).getSize($method::currentAddress);
- if ($maxOutRegisters < $instruction.outRegisters) {
- $maxOutRegisters = $instruction.outRegisters;
- }
- })*);
-
-label_ref returns[int labelAddress]
- : SIMPLE_NAME
- {
- Integer labelAdd = $method::labels.get($SIMPLE_NAME.text);
-
- if (labelAdd == null) {
- throw new SemanticException(input, $SIMPLE_NAME, "Label \"" + $SIMPLE_NAME.text + "\" is not defined.");
- }
+ordered_method_items
+ : ^(I_ORDERED_METHOD_ITEMS (label_def | instruction | debug_directive)*);
- $labelAddress = labelAdd;
- };
+label_ref returns[Label label]
+ : SIMPLE_NAME { $label = $method::methodBuilder.getLabel($SIMPLE_NAME.text); };
-offset returns[int offsetValue]
- : OFFSET
- {
- String offsetText = $OFFSET.text;
- if (offsetText.charAt(0) == '+') {
- offsetText = offsetText.substring(1);
- }
- $offsetValue = LiteralTools.parseInt(offsetText);
- };
-
-offset_or_label_absolute[int baseAddress] returns[int address]
- : offset {$address = $offset.offsetValue + $baseAddress;}
- | label_ref {$address = $label_ref.labelAddress;};
-
-offset_or_label returns[int offsetValue]
- : offset {$offsetValue = $offset.offsetValue;}
- | label_ref {$offsetValue = $label_ref.labelAddress-$method::currentAddress;};
-
-
-register_list[int totalMethodRegisters, int methodParameterRegisters] returns[byte[\] registers, byte registerCount]
+register_list returns[byte[\] registers, byte registerCount]
@init
{
$registers = new byte[5];
@@ -862,23 +656,24 @@ register_list[int totalMethodRegisters, int methodParameterRegisters] returns[by
(REGISTER
{
if ($registerCount == 5) {
- throw new SemanticException(input, $I_REGISTER_LIST, "A list of registers can only have a maximum of 5 registers. Use the <op>/range alternate opcode instead.");
+ throw new SemanticException(input, $I_REGISTER_LIST, "A list of registers can only have a maximum of 5 " +
+ "registers. Use the <op>/range alternate opcode instead.");
}
- $registers[$registerCount++] = parseRegister_nibble($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
+ $registers[$registerCount++] = parseRegister_nibble($REGISTER.text);
})*);
-register_range[int totalMethodRegisters, int methodParameterRegisters] returns[int startRegister, int endRegister]
+register_range returns[int startRegister, int endRegister]
: ^(I_REGISTER_RANGE (startReg=REGISTER endReg=REGISTER?)?)
{
if ($startReg == null) {
$startRegister = 0;
$endRegister = -1;
} else {
- $startRegister = parseRegister_short($startReg.text, $totalMethodRegisters, $methodParameterRegisters);
+ $startRegister = parseRegister_short($startReg.text);
if ($endReg == null) {
$endRegister = $startRegister;
} else {
- $endRegister = parseRegister_short($endReg.text, $totalMethodRegisters, $methodParameterRegisters);
+ $endRegister = parseRegister_short($endReg.text);
}
int registerCount = $endRegister-$startRegister+1;
@@ -886,641 +681,476 @@ register_range[int totalMethodRegisters, int methodParameterRegisters] returns[i
throw new SemanticException(input, $I_REGISTER_RANGE, "A register range must have the lower register listed first");
}
}
- }
- ;
+ };
-verification_error_reference returns[Item item]
+verification_error_reference returns[ImmutableReference reference]
: CLASS_DESCRIPTOR
{
- $item = TypeIdItem.internTypeIdItem(dexFile, $start.getText());
+ $reference = new ImmutableTypeReference($CLASS_DESCRIPTOR.text);
}
| fully_qualified_field
{
- $item = $fully_qualified_field.fieldIdItem;
+ $reference = $fully_qualified_field.fieldReference;
}
| fully_qualified_method
{
- $item = $fully_qualified_method.methodIdItem;
+ $reference = $fully_qualified_method.methodReference;
};
-verification_error_type returns[VerificationErrorType verificationErrorType]
+verification_error_type returns[int verificationError]
: VERIFICATION_ERROR_TYPE
{
- $verificationErrorType = VerificationErrorType.fromString($VERIFICATION_ERROR_TYPE.text);
+ $verificationError = VerificationError.getVerificationError($VERIFICATION_ERROR_TYPE.text);
};
-instruction[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
- : insn_format10t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format10t.outRegisters; }
- | insn_format10x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format10x.outRegisters; }
- | insn_format11n[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format11n.outRegisters; }
- | insn_format11x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format11x.outRegisters; }
- | insn_format12x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format12x.outRegisters; }
- | insn_format20bc[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format20bc.outRegisters; }
- | insn_format20t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format20t.outRegisters; }
- | insn_format21c_field[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21c_field.outRegisters; }
- | insn_format21c_string[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21c_string.outRegisters; }
- | insn_format21c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21c_type.outRegisters; }
- | insn_format21h[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21h.outRegisters; }
- | insn_format21s[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21s.outRegisters; }
- | insn_format21t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21t.outRegisters; }
- | insn_format22b[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22b.outRegisters; }
- | insn_format22c_field[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22c_field.outRegisters; }
- | insn_format22c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22c_type.outRegisters; }
- | insn_format22s[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22s.outRegisters; }
- | insn_format22t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22t.outRegisters; }
- | insn_format22x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22x.outRegisters; }
- | insn_format23x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format23x.outRegisters; }
- | insn_format30t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format30t.outRegisters; }
- | insn_format31c[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format31c.outRegisters; }
- | insn_format31i[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format31i.outRegisters; }
- | insn_format31t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format31t.outRegisters; }
- | insn_format32x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format32x.outRegisters; }
- | insn_format35c_method[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format35c_method.outRegisters; }
- | insn_format35c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format35c_type.outRegisters; }
- | insn_format3rc_method[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format3rc_method.outRegisters; }
- | insn_format3rc_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format3rc_type.outRegisters; }
- | insn_format41c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format41c_type.outRegisters; }
- | insn_format41c_field[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format41c_field.outRegisters; }
- | insn_format51l_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format51l_type.outRegisters; }
- | insn_format52c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format52c_type.outRegisters; }
- | insn_format52c_field[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format52c_field.outRegisters; }
- | insn_format5rc_method[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format5rc_method.outRegisters; }
- | insn_format5rc_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format5rc_type.outRegisters; }
- | insn_array_data_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_array_data_directive.outRegisters; }
- | insn_packed_switch_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_packed_switch_directive.outRegisters; }
- | insn_sparse_switch_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_sparse_switch_directive.outRegisters; };
- catch [Exception ex] {
- reportError(new SemanticException(input, ex));
- recover(input, null);
- }
-
+instruction
+ : insn_format10t
+ | insn_format10x
+ | insn_format11n
+ | insn_format11x
+ | insn_format12x
+ | insn_format20bc
+ | insn_format20t
+ | insn_format21c_field
+ | insn_format21c_string
+ | insn_format21c_type
+ | insn_format21ih
+ | insn_format21lh
+ | insn_format21s
+ | insn_format21t
+ | insn_format22b
+ | insn_format22c_field
+ | insn_format22c_type
+ | insn_format22s
+ | insn_format22t
+ | insn_format22x
+ | insn_format23x
+ | insn_format30t
+ | insn_format31c
+ | insn_format31i
+ | insn_format31t
+ | insn_format32x
+ | insn_format35c_method
+ | insn_format35c_type
+ | insn_format3rc_method
+ | insn_format3rc_type
+ | insn_format51l_type
+ | insn_array_data_directive
+ | insn_packed_switch_directive
+ | insn_sparse_switch_directive;
+ catch [Exception ex] {
+ reportError(new SemanticException(input, $start, ex.getMessage()));
+ recover(input, null);
+ }
-insn_format10t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format10t
: //e.g. goto endloop:
- {$outRegisters = 0;}
- ^(I_STATEMENT_FORMAT10t INSTRUCTION_FORMAT10t offset_or_label)
+ ^(I_STATEMENT_FORMAT10t INSTRUCTION_FORMAT10t label_ref)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT10t.text);
-
- int addressOffset = $offset_or_label.offsetValue;
-
- $instructions.add(new Instruction10t(opcode, addressOffset));
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT10t.text);
+ $method::methodBuilder.addInstruction(new BuilderInstruction10t(opcode, $label_ref.label));
};
-insn_format10x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format10x
: //e.g. return
^(I_STATEMENT_FORMAT10x INSTRUCTION_FORMAT10x)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT10x.text);
- $instructions.add(new Instruction10x(opcode));
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT10x.text);
+ $method::methodBuilder.addInstruction(new BuilderInstruction10x(opcode));
};
-insn_format11n[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format11n
: //e.g. const/4 v0, 5
^(I_STATEMENT_FORMAT11n INSTRUCTION_FORMAT11n REGISTER short_integral_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT11n.text);
- byte regA = parseRegister_nibble($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT11n.text);
+ byte regA = parseRegister_nibble($REGISTER.text);
short litB = $short_integral_literal.value;
LiteralTools.checkNibble(litB);
- $instructions.add(new Instruction11n(opcode, regA, (byte)litB));
+ $method::methodBuilder.addInstruction(new BuilderInstruction11n(opcode, regA, litB));
};
-insn_format11x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format11x
: //e.g. move-result-object v1
^(I_STATEMENT_FORMAT11x INSTRUCTION_FORMAT11x REGISTER)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT11x.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT11x.text);
+ short regA = parseRegister_byte($REGISTER.text);
- $instructions.add(new Instruction11x(opcode, regA));
+ $method::methodBuilder.addInstruction(new BuilderInstruction11x(opcode, regA));
};
-insn_format12x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format12x
: //e.g. move v1 v2
^(I_STATEMENT_FORMAT12x INSTRUCTION_FORMAT12x registerA=REGISTER registerB=REGISTER)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT12x.text);
- byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT12x.text);
+ byte regA = parseRegister_nibble($registerA.text);
+ byte regB = parseRegister_nibble($registerB.text);
- $instructions.add(new Instruction12x(opcode, regA, regB));
+ $method::methodBuilder.addInstruction(new BuilderInstruction12x(opcode, regA, regB));
};
-insn_format20bc[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format20bc
: //e.g. throw-verification-error generic-error, Lsome/class;
^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc verification_error_type verification_error_reference)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT20bc.text);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT20bc.text);
- VerificationErrorType verificationErrorType = $verification_error_type.verificationErrorType;
- Item referencedItem = $verification_error_reference.item;
+ int verificationError = $verification_error_type.verificationError;
+ ImmutableReference referencedItem = $verification_error_reference.reference;
- $instructions.add(new Instruction20bc(opcode, verificationErrorType, referencedItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction20bc(opcode, verificationError,
+ dexBuilder.internReference(referencedItem)));
};
-insn_format20t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format20t
: //e.g. goto/16 endloop:
- ^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t offset_or_label)
+ ^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t label_ref)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT20t.text);
-
- int addressOffset = $offset_or_label.offsetValue;
-
- $instructions.add(new Instruction20t(opcode, addressOffset));
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT20t.text);
+ $method::methodBuilder.addInstruction(new BuilderInstruction20t(opcode, $label_ref.label));
};
-insn_format21c_field[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+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)
{
- Opcode opcode = Opcode.getOpcodeByName($inst.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($inst.text);
+ short regA = parseRegister_byte($REGISTER.text);
- FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem;
+ ImmutableFieldReference fieldReference = $fully_qualified_field.fieldReference;
- $instructions.add(new Instruction21c(opcode, regA, fieldIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
+ dexBuilder.internFieldReference(fieldReference)));
};
-insn_format21c_string[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format21c_string
: //e.g. const-string v1, "Hello World!"
^(I_STATEMENT_FORMAT21c_STRING INSTRUCTION_FORMAT21c_STRING REGISTER string_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21c_STRING.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- StringIdItem stringIdItem = StringIdItem.internStringIdItem(dexFile, $string_literal.value);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_STRING.text);
+ short regA = parseRegister_byte($REGISTER.text);
- instructions.add(new Instruction21c(opcode, regA, stringIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
+ dexBuilder.internStringReference($string_literal.value)));
};
-insn_format21c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format21c_type
: //e.g. const-class v2, org/jf/HelloWorld2/HelloWorld2
- ^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor)
+ ^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER nonvoid_type_descriptor)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- TypeIdItem typeIdItem = $reference_type_descriptor.type;
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text);
+ short regA = parseRegister_byte($REGISTER.text);
- $instructions.add(new Instruction21c(opcode, regA, typeIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
+ dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
};
-insn_format21h[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format21ih
: //e.g. const/high16 v1, 1234
- ^(I_STATEMENT_FORMAT21h INSTRUCTION_FORMAT21h REGISTER short_integral_literal)
+ ^(I_STATEMENT_FORMAT21ih INSTRUCTION_FORMAT21ih REGISTER fixed_32bit_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21h.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21ih.text);
+ short regA = parseRegister_byte($REGISTER.text);
- short litB = $short_integral_literal.value;
+ int litB = $fixed_32bit_literal.value;
- instructions.add(new Instruction21h(opcode, regA, litB));
+ $method::methodBuilder.addInstruction(new BuilderInstruction21ih(opcode, regA, litB));
};
-insn_format21s[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format21lh
+ : //e.g. const-wide/high16 v1, 1234
+ ^(I_STATEMENT_FORMAT21lh INSTRUCTION_FORMAT21lh REGISTER fixed_64bit_literal)
+ {
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21lh.text);
+ short regA = parseRegister_byte($REGISTER.text);
+
+ long litB = $fixed_64bit_literal.value;
+
+ $method::methodBuilder.addInstruction(new BuilderInstruction21lh(opcode, regA, litB));
+ };
+
+insn_format21s
: //e.g. const/16 v1, 1234
^(I_STATEMENT_FORMAT21s INSTRUCTION_FORMAT21s REGISTER short_integral_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21s.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21s.text);
+ short regA = parseRegister_byte($REGISTER.text);
short litB = $short_integral_literal.value;
- $instructions.add(new Instruction21s(opcode, regA, litB));
+ $method::methodBuilder.addInstruction(new BuilderInstruction21s(opcode, regA, litB));
};
-insn_format21t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format21t
: //e.g. if-eqz v0, endloop:
- ^(I_STATEMENT_FORMAT21t INSTRUCTION_FORMAT21t REGISTER offset_or_label)
+ ^(I_STATEMENT_FORMAT21t INSTRUCTION_FORMAT21t REGISTER label_ref)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21t.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- int addressOffset = $offset_or_label.offsetValue;
-
- if (addressOffset < Short.MIN_VALUE || addressOffset > Short.MAX_VALUE) {
- throw new SemanticException(input, $offset_or_label.start, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767].");
- }
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21t.text);
+ short regA = parseRegister_byte($REGISTER.text);
- $instructions.add(new Instruction21t(opcode, regA, (short)addressOffset));
+ $method::methodBuilder.addInstruction(new BuilderInstruction21t(opcode, regA, $label_ref.label));
};
-insn_format22b[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format22b
: //e.g. add-int v0, v1, 123
^(I_STATEMENT_FORMAT22b INSTRUCTION_FORMAT22b registerA=REGISTER registerB=REGISTER short_integral_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22b.text);
- short regA = parseRegister_byte($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- short regB = parseRegister_byte($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22b.text);
+ short regA = parseRegister_byte($registerA.text);
+ short regB = parseRegister_byte($registerB.text);
short litC = $short_integral_literal.value;
LiteralTools.checkByte(litC);
- $instructions.add(new Instruction22b(opcode, regA, regB, (byte)litC));
+ $method::methodBuilder.addInstruction(new BuilderInstruction22b(opcode, regA, regB, litC));
};
-insn_format22c_field[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+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)
{
- Opcode opcode = Opcode.getOpcodeByName($inst.text);
- byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($inst.text);
+ byte regA = parseRegister_nibble($registerA.text);
+ byte regB = parseRegister_nibble($registerB.text);
- FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem;
+ ImmutableFieldReference fieldReference = $fully_qualified_field.fieldReference;
- $instructions.add(new Instruction22c(opcode, regA, regB, fieldIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB,
+ dexBuilder.internFieldReference(fieldReference)));
};
-insn_format22c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format22c_type
: //e.g. instance-of v0, v1, Ljava/lang/String;
^(I_STATEMENT_FORMAT22c_TYPE INSTRUCTION_FORMAT22c_TYPE registerA=REGISTER registerB=REGISTER nonvoid_type_descriptor)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22c_TYPE.text);
- byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
-
- TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_TYPE.text);
+ byte regA = parseRegister_nibble($registerA.text);
+ byte regB = parseRegister_nibble($registerB.text);
- $instructions.add(new Instruction22c(opcode, regA, regB, typeIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB,
+ dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
};
-insn_format22s[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format22s
: //e.g. add-int/lit16 v0, v1, 12345
^(I_STATEMENT_FORMAT22s INSTRUCTION_FORMAT22s registerA=REGISTER registerB=REGISTER short_integral_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22s.text);
- byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22s.text);
+ byte regA = parseRegister_nibble($registerA.text);
+ byte regB = parseRegister_nibble($registerB.text);
short litC = $short_integral_literal.value;
- $instructions.add(new Instruction22s(opcode, regA, regB, litC));
+ $method::methodBuilder.addInstruction(new BuilderInstruction22s(opcode, regA, regB, litC));
};
-insn_format22t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format22t
: //e.g. if-eq v0, v1, endloop:
- ^(I_STATEMENT_FORMAT22t INSTRUCTION_FORMAT22t registerA=REGISTER registerB=REGISTER offset_or_label)
+ ^(I_STATEMENT_FORMAT22t INSTRUCTION_FORMAT22t registerA=REGISTER registerB=REGISTER label_ref)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22t.text);
- byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
-
- int addressOffset = $offset_or_label.offsetValue;
-
- if (addressOffset < Short.MIN_VALUE || addressOffset > Short.MAX_VALUE) {
- throw new SemanticException(input, $offset_or_label.start, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767].");
- }
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22t.text);
+ byte regA = parseRegister_nibble($registerA.text);
+ byte regB = parseRegister_nibble($registerB.text);
- $instructions.add(new Instruction22t(opcode, regA, regB, (short)addressOffset));
+ $method::methodBuilder.addInstruction(new BuilderInstruction22t(opcode, regA, regB, $label_ref.label));
};
-insn_format22x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format22x
: //e.g. move/from16 v1, v1234
^(I_STATEMENT_FORMAT22x INSTRUCTION_FORMAT22x registerA=REGISTER registerB=REGISTER)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22x.text);
- short regA = parseRegister_byte($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22x.text);
+ short regA = parseRegister_byte($registerA.text);
+ int regB = parseRegister_short($registerB.text);
- $instructions.add(new Instruction22x(opcode, regA, regB));
+ $method::methodBuilder.addInstruction(new BuilderInstruction22x(opcode, regA, regB));
};
-insn_format23x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format23x
: //e.g. add-int v1, v2, v3
^(I_STATEMENT_FORMAT23x INSTRUCTION_FORMAT23x registerA=REGISTER registerB=REGISTER registerC=REGISTER)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT23x.text);
- short regA = parseRegister_byte($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- short regB = parseRegister_byte($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
- short regC = parseRegister_byte($registerC.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT23x.text);
+ short regA = parseRegister_byte($registerA.text);
+ short regB = parseRegister_byte($registerB.text);
+ short regC = parseRegister_byte($registerC.text);
- $instructions.add(new Instruction23x(opcode, regA, regB, regC));
+ $method::methodBuilder.addInstruction(new BuilderInstruction23x(opcode, regA, regB, regC));
};
-insn_format30t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format30t
: //e.g. goto/32 endloop:
- ^(I_STATEMENT_FORMAT30t INSTRUCTION_FORMAT30t offset_or_label)
+ ^(I_STATEMENT_FORMAT30t INSTRUCTION_FORMAT30t label_ref)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT30t.text);
-
- int addressOffset = $offset_or_label.offsetValue;
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT30t.text);
- $instructions.add(new Instruction30t(opcode, addressOffset));
+ $method::methodBuilder.addInstruction(new BuilderInstruction30t(opcode, $label_ref.label));
};
-insn_format31c[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format31c
: //e.g. const-string/jumbo v1 "Hello World!"
^(I_STATEMENT_FORMAT31c INSTRUCTION_FORMAT31c REGISTER string_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT31c.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- StringIdItem stringIdItem = StringIdItem.internStringIdItem(dexFile, $string_literal.value);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT31c.text);
+ short regA = parseRegister_byte($REGISTER.text);
- $instructions.add(new Instruction31c(opcode, regA, stringIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction31c(opcode, regA,
+ dexBuilder.internStringReference($string_literal.value)));
};
-insn_format31i[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format31i
: //e.g. const v0, 123456
^(I_STATEMENT_FORMAT31i INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT31i.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT31i.text);
+ short regA = parseRegister_byte($REGISTER.text);
int litB = $fixed_32bit_literal.value;
- $instructions.add(new Instruction31i(opcode, regA, litB));
+ $method::methodBuilder.addInstruction(new BuilderInstruction31i(opcode, regA, litB));
};
-insn_format31t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format31t
: //e.g. fill-array-data v0, ArrayData:
- ^(I_STATEMENT_FORMAT31t INSTRUCTION_FORMAT31t REGISTER offset_or_label)
+ ^(I_STATEMENT_FORMAT31t INSTRUCTION_FORMAT31t REGISTER label_ref)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT31t.text);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT31t.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- int addressOffset = $offset_or_label.offsetValue;
- if (($method::currentAddress + addressOffset) \% 2 != 0) {
- addressOffset++;
- }
+ short regA = parseRegister_byte($REGISTER.text);
- $instructions.add(new Instruction31t(opcode, regA, addressOffset));
+ $method::methodBuilder.addInstruction(new BuilderInstruction31t(opcode, regA, $label_ref.label));
};
-insn_format32x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format32x
: //e.g. move/16 v5678, v1234
^(I_STATEMENT_FORMAT32x INSTRUCTION_FORMAT32x registerA=REGISTER registerB=REGISTER)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT32x.text);
- int regA = parseRegister_short($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT32x.text);
+ int regA = parseRegister_short($registerA.text);
+ int regB = parseRegister_short($registerB.text);
- $instructions.add(new Instruction32x(opcode, regA, regB));
+ $method::methodBuilder.addInstruction(new BuilderInstruction32x(opcode, regA, regB));
};
-insn_format35c_method[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+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[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method)
+ ^(I_STATEMENT_FORMAT35c_METHOD INSTRUCTION_FORMAT35c_METHOD register_list fully_qualified_method)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT35c_METHOD.text);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT35c_METHOD.text);
//this depends on the fact that register_list returns a byte[5]
byte[] registers = $register_list.registers;
byte registerCount = $register_list.registerCount;
- $outRegisters = registerCount;
- MethodIdItem methodIdItem = $fully_qualified_method.methodIdItem;
+ ImmutableMethodReference methodReference = $fully_qualified_method.methodReference;
- $instructions.add(new Instruction35c(opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], methodIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction35c(opcode, registerCount, registers[0], registers[1],
+ registers[2], registers[3], registers[4], dexBuilder.internMethodReference(methodReference)));
};
-insn_format35c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format35c_type
: //e.g. filled-new-array {v0,v1}, I
- ^(I_STATEMENT_FORMAT35c_TYPE INSTRUCTION_FORMAT35c_TYPE register_list[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor)
+ ^(I_STATEMENT_FORMAT35c_TYPE INSTRUCTION_FORMAT35c_TYPE register_list nonvoid_type_descriptor)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT35c_TYPE.text);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT35c_TYPE.text);
//this depends on the fact that register_list returns a byte[5]
byte[] registers = $register_list.registers;
byte registerCount = $register_list.registerCount;
- $outRegisters = registerCount;
- TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
-
- $instructions.add(new Instruction35c(opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], typeIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction35c(opcode, registerCount, registers[0], registers[1],
+ registers[2], registers[3], registers[4], dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
};
-insn_format3rc_method[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+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[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method)
+ ^(I_STATEMENT_FORMAT3rc_METHOD INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT3rc_METHOD.text);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT3rc_METHOD.text);
int startRegister = $register_range.startRegister;
int endRegister = $register_range.endRegister;
int registerCount = endRegister-startRegister+1;
- $outRegisters = registerCount;
- MethodIdItem methodIdItem = $fully_qualified_method.methodIdItem;
+ ImmutableMethodReference methodReference = $fully_qualified_method.methodReference;
- $instructions.add(new Instruction3rc(opcode, (short)registerCount, startRegister, methodIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction3rc(opcode, startRegister, registerCount,
+ dexBuilder.internMethodReference(methodReference)));
};
-insn_format3rc_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format3rc_type
: //e.g. filled-new-array/range {v0..v6} I
- ^(I_STATEMENT_FORMAT3rc_TYPE INSTRUCTION_FORMAT3rc_TYPE register_range[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor)
+ ^(I_STATEMENT_FORMAT3rc_TYPE INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT3rc_TYPE.text);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT3rc_TYPE.text);
int startRegister = $register_range.startRegister;
int endRegister = $register_range.endRegister;
int registerCount = endRegister-startRegister+1;
- $outRegisters = registerCount;
-
- TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
-
- $instructions.add(new Instruction3rc(opcode, (short)registerCount, startRegister, typeIdItem));
- };
-
-insn_format41c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
- : //e.g. const-class/jumbo v2, org/jf/HelloWorld2/HelloWorld2
- ^(I_STATEMENT_FORMAT41c_TYPE INSTRUCTION_FORMAT41c_TYPE REGISTER reference_type_descriptor)
- {
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT41c_TYPE.text);
- int regA = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- TypeIdItem typeIdItem = $reference_type_descriptor.type;
-
- $instructions.add(new Instruction41c(opcode, regA, typeIdItem));
- };
-
-insn_format41c_field[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
- : //e.g. sget-object/jumbo v0, Ljava/lang/System;->out:LJava/io/PrintStream;
- ^(I_STATEMENT_FORMAT41c_FIELD INSTRUCTION_FORMAT41c_FIELD REGISTER fully_qualified_field)
- {
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT41c_FIELD.text);
- int regA = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
-
- FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem;
- $instructions.add(new Instruction41c(opcode, regA, fieldIdItem));
+ $method::methodBuilder.addInstruction(new BuilderInstruction3rc(opcode, startRegister, registerCount,
+ dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
};
-insn_format51l_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_format51l_type
: //e.g. const-wide v0, 5000000000L
^(I_STATEMENT_FORMAT51l INSTRUCTION_FORMAT51l REGISTER fixed_64bit_literal)
{
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT51l.text);
- short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT51l.text);
+ short regA = parseRegister_byte($REGISTER.text);
long litB = $fixed_64bit_literal.value;
- $instructions.add(new Instruction51l(opcode, regA, litB));
+ $method::methodBuilder.addInstruction(new BuilderInstruction51l(opcode, regA, litB));
};
-insn_format52c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
- : //e.g. instance-of/jumbo v0, v1, Ljava/lang/String;
- ^(I_STATEMENT_FORMAT52c_TYPE INSTRUCTION_FORMAT52c_TYPE registerA=REGISTER registerB=REGISTER nonvoid_type_descriptor)
- {
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT52c_TYPE.text);
- int regA = parseRegister_short($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
-
- TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
-
- $instructions.add(new Instruction52c(opcode, regA, regB, typeIdItem));
- };
-
-insn_format52c_field[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
- : //e.g. iput-object/jumbo v1, v0, Lorg/jf/HelloWorld2/HelloWorld2;->helloWorld:Ljava/lang/String;
- ^(I_STATEMENT_FORMAT52c_FIELD INSTRUCTION_FORMAT52c_FIELD registerA=REGISTER registerB=REGISTER fully_qualified_field)
- {
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT52c_FIELD.text);
- int regA = parseRegister_short($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
- int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
-
- FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem;
-
- $instructions.add(new Instruction52c(opcode, regA, regB, fieldIdItem));
- };
-
-insn_format5rc_method[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
- : //e.g. invoke-virtual/jumbo {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
- ^(I_STATEMENT_FORMAT5rc_METHOD INSTRUCTION_FORMAT5rc_METHOD register_range[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method)
- {
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT5rc_METHOD.text);
- int startRegister = $register_range.startRegister;
- int endRegister = $register_range.endRegister;
-
- int registerCount = endRegister-startRegister+1;
- $outRegisters = registerCount;
-
- MethodIdItem methodIdItem = $fully_qualified_method.methodIdItem;
-
- $instructions.add(new Instruction5rc(opcode, registerCount, startRegister, methodIdItem));
- };
-
-insn_format5rc_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
- : //e.g. filled-new-array/jumbo {v0..v6} I
- ^(I_STATEMENT_FORMAT5rc_TYPE INSTRUCTION_FORMAT5rc_TYPE register_range[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor)
- {
- Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT5rc_TYPE.text);
- int startRegister = $register_range.startRegister;
- int endRegister = $register_range.endRegister;
-
- int registerCount = endRegister-startRegister+1;
- $outRegisters = registerCount;
-
- TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
-
- $instructions.add(new Instruction5rc(opcode, registerCount, startRegister, typeIdItem));
- };
-
-insn_array_data_directive[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_array_data_directive
: //e.g. .array-data 4 1000000 .end array-data
^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE short_integral_literal) array_elements)
{
- if (($method::currentAddress \% 2) != 0) {
- $instructions.add(new Instruction10x(Opcode.NOP));
- $method::currentAddress++;
- }
-
int elementWidth = $short_integral_literal.value;
- List<byte[]> byteValues = $array_elements.values;
-
- int length = 0;
- for (byte[] byteValue: byteValues) {
- length+=byteValue.length;
- }
-
- byte[] encodedValues = new byte[length];
- int index = 0;
- for (byte[] byteValue: byteValues) {
- System.arraycopy(byteValue, 0, encodedValues, index, byteValue.length);
- index+=byteValue.length;
- }
+ List<Number> elements = $array_elements.elements;
- $instructions.add(new ArrayDataPseudoInstruction(elementWidth, encodedValues));
+ $method::methodBuilder.addInstruction(new BuilderArrayPayload(elementWidth, $array_elements.elements));
};
-insn_packed_switch_directive[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_packed_switch_directive
:
- ^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal)
+ ^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal) packed_switch_elements)
{
- if (($method::currentAddress \% 2) != 0) {
- $instructions.add(new Instruction10x(Opcode.NOP));
- $method::currentAddress++;
- }
- Integer baseAddress = $method::packedSwitchDeclarations.get($method::currentAddress);
- if (baseAddress == null) {
- baseAddress = 0;
- }
- }
- packed_switch_targets[baseAddress])
- {
-
- int startKey = $fixed_32bit_literal.value;
- int[] targets = $packed_switch_targets.targets;
+ int startKey = $fixed_32bit_literal.value;
+ $method::methodBuilder.addInstruction(new BuilderPackedSwitchPayload(startKey,
+ $packed_switch_elements.elements));
+ };
- $instructions.add(new PackedSwitchDataPseudoInstruction(startKey, targets));
- };
-
-insn_sparse_switch_directive[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
+insn_sparse_switch_directive
:
- ^(I_STATEMENT_SPARSE_SWITCH sparse_switch_target_count sparse_switch_keys[$sparse_switch_target_count.targetCount]
- {
- if (($method::currentAddress \% 2) != 0) {
- $instructions.add(new Instruction10x(Opcode.NOP));
- $method::currentAddress++;
- }
- Integer baseAddress = $method::sparseSwitchDeclarations.get($method::currentAddress);
- if (baseAddress == null) {
- baseAddress = 0;
- }
- }
-
- sparse_switch_targets[baseAddress, $sparse_switch_target_count.targetCount])
+ ^(I_STATEMENT_SPARSE_SWITCH sparse_switch_elements)
{
- int[] keys = $sparse_switch_keys.keys;
- int[] targets = $sparse_switch_targets.targets;
-
- $instructions.add(new SparseSwitchDataPseudoInstruction(keys, targets));
+ $method::methodBuilder.addInstruction(new BuilderSparseSwitchPayload($sparse_switch_elements.elements));
};
-nonvoid_type_descriptor returns [TypeIdItem type]
+nonvoid_type_descriptor returns [String type]
: (PRIMITIVE_TYPE
| CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR)
{
- $type = TypeIdItem.internTypeIdItem(dexFile, $start.getText());
+ $type = $start.getText();
};
-
-reference_type_descriptor returns [TypeIdItem type]
+reference_type_descriptor returns [String type]
: (CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR)
{
- $type = TypeIdItem.internTypeIdItem(dexFile, $start.getText());
- };
-
-
-
-
-
-
-class_type_descriptor returns [TypeIdItem type]
- : CLASS_DESCRIPTOR
- {
- $type = TypeIdItem.internTypeIdItem(dexFile, $CLASS_DESCRIPTOR.text);
+ $type = $start.getText();
};
-type_descriptor returns [TypeIdItem type]
- : VOID_TYPE {$type = TypeIdItem.internTypeIdItem(dexFile, "V");}
+type_descriptor returns [String type]
+ : VOID_TYPE {$type = "V";}
| nonvoid_type_descriptor {$type = $nonvoid_type_descriptor.type;}
;
@@ -1581,78 +1211,67 @@ string_literal returns[String value]
bool_literal returns[boolean value]
: BOOL_LITERAL { $value = Boolean.parseBoolean($BOOL_LITERAL.text); };
-array_literal returns[EncodedValue[\] values]
- : {ArrayList<EncodedValue> valuesList = new ArrayList<EncodedValue>();}
- ^(I_ENCODED_ARRAY (literal {valuesList.add($literal.encodedValue);})*)
- {
- $values = new EncodedValue[valuesList.size()];
- valuesList.toArray($values);
- };
-
+array_literal returns[List<EncodedValue> elements]
+ : {$elements = Lists.newArrayList();}
+ ^(I_ENCODED_ARRAY (literal {$elements.add($literal.encodedValue);})*);
-annotations returns[AnnotationSetItem annotationSetItem]
- : {ArrayList<AnnotationItem> annotationList = new ArrayList<AnnotationItem>();}
- ^(I_ANNOTATIONS (annotation {annotationList.add($annotation.annotationItem);} )*)
+annotations returns[Set<Annotation> annotations]
+ : {HashMap<String, Annotation> annotationMap = Maps.newHashMap();}
+ ^(I_ANNOTATIONS (annotation
{
- if (annotationList.size() > 0) {
- $annotationSetItem = AnnotationSetItem.internAnnotationSetItem(dexFile, annotationList);
+ Annotation anno = $annotation.annotation;
+ Annotation old = annotationMap.put(anno.getType(), anno);
+ if (old != null) {
+ throw new SemanticException(input, "Multiple annotations of type \%s", anno.getType());
+ }
+ })*)
+ {
+ if (annotationMap.size() > 0) {
+ $annotations = ImmutableSet.copyOf(annotationMap.values());
}
};
-
-annotation returns[AnnotationItem annotationItem]
+annotation returns[Annotation annotation]
: ^(I_ANNOTATION ANNOTATION_VISIBILITY subannotation)
{
- AnnotationVisibility visibility = AnnotationVisibility.valueOf($ANNOTATION_VISIBILITY.text.toUpperCase());
- AnnotationEncodedSubValue encodedAnnotation = new AnnotationEncodedSubValue($subannotation.annotationType,
- $subannotation.elementNames, $subannotation.elementValues);
- $annotationItem = AnnotationItem.internAnnotationItem(dexFile, visibility, encodedAnnotation);
+ int visibility = AnnotationVisibility.getVisibility($ANNOTATION_VISIBILITY.text);
+ $annotation = new ImmutableAnnotation(visibility, $subannotation.annotationType, $subannotation.elements);
};
-annotation_element returns[StringIdItem elementName, EncodedValue elementValue]
+annotation_element returns[AnnotationElement element]
: ^(I_ANNOTATION_ELEMENT SIMPLE_NAME literal)
{
- $elementName = StringIdItem.internStringIdItem(dexFile, $SIMPLE_NAME.text);
- $elementValue = $literal.encodedValue;
+ $element = new ImmutableAnnotationElement($SIMPLE_NAME.text, $literal.encodedValue);
};
-subannotation returns[TypeIdItem annotationType, StringIdItem[\] elementNames, EncodedValue[\] elementValues]
- : {ImmutableSortedMap.Builder<StringIdItem, EncodedValue> elementBuilder =
- ImmutableSortedMap.<StringIdItem, EncodedValue>naturalOrder();}
+subannotation returns[String annotationType, List<AnnotationElement> elements]
+ : {ArrayList<AnnotationElement> elements = Lists.newArrayList();}
^(I_SUBANNOTATION
- class_type_descriptor
+ CLASS_DESCRIPTOR
(annotation_element
{
- elementBuilder.put($annotation_element.elementName, $annotation_element.elementValue);
- }
- )*
+ elements.add($annotation_element.element);
+ })*
)
{
- ImmutableSortedMap<StringIdItem, EncodedValue> elementMap = elementBuilder.build();
-
- $annotationType = $class_type_descriptor.type;
-
- $elementNames = new StringIdItem[elementMap.size()];
- $elementValues = new EncodedValue[elementMap.size()];
-
- elementMap.keySet().toArray($elementNames);
- elementMap.values().toArray($elementValues);
+ $annotationType = $CLASS_DESCRIPTOR.text;
+ $elements = elements;
};
-field_literal returns[FieldIdItem value]
+field_literal returns[FieldReference value]
: ^(I_ENCODED_FIELD fully_qualified_field)
{
- $value = $fully_qualified_field.fieldIdItem;
+ $value = $fully_qualified_field.fieldReference;
};
-method_literal returns[MethodIdItem value]
+method_literal returns[MethodReference value]
: ^(I_ENCODED_METHOD fully_qualified_method)
{
- $value = $fully_qualified_method.methodIdItem;
+ $value = $fully_qualified_method.methodReference;
};
-enum_literal returns[FieldIdItem value]
+enum_literal returns[FieldReference value]
: ^(I_ENCODED_ENUM fully_qualified_field)
{
- $value = $fully_qualified_field.fieldIdItem;
+ $value = $fully_qualified_field.fieldReference;
};
diff --git a/smali/src/main/java/org/jf/smali/SmaliMethodParameter.java b/smali/src/main/java/org/jf/smali/SmaliMethodParameter.java
new file mode 100644
index 00000000..f54c04e6
--- /dev/null
+++ b/smali/src/main/java/org/jf/smali/SmaliMethodParameter.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013, 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.ImmutableSet;
+import com.google.common.primitives.Ints;
+import org.jf.dexlib2.base.BaseMethodParameter;
+import org.jf.dexlib2.iface.Annotation;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Comparator;
+import java.util.Set;
+
+public class SmaliMethodParameter extends BaseMethodParameter implements WithRegister {
+ public final int register;
+ @Nonnull public final String type;
+ @Nonnull public Set<? extends Annotation> annotations;
+ @Nullable public String name;
+
+ public SmaliMethodParameter(int register, @Nonnull String type) {
+ this.register = register;
+ this.type = type;
+ this.annotations = ImmutableSet.of();
+ }
+
+ @Override public int getRegister() { return register; }
+ @Nonnull @Override public String getType() { return type; }
+ @Nonnull @Override public Set<? extends Annotation> getAnnotations() { return annotations; }
+ @Nullable @Override public String getName() { return name; }
+ @Nullable @Override public String getSignature() { return null; }
+
+ public static final Comparator<WithRegister> COMPARATOR = new Comparator<WithRegister>() {
+ @Override public int compare(WithRegister o1, WithRegister o2) {
+ return Ints.compare(o1.getRegister(), o2.getRegister());
+ }
+ };
+}
diff --git a/smali/src/main/java/org/jf/smali/WithRegister.java b/smali/src/main/java/org/jf/smali/WithRegister.java
new file mode 100644
index 00000000..cd9a48b0
--- /dev/null
+++ b/smali/src/main/java/org/jf/smali/WithRegister.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2013, 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;
+
+public interface WithRegister {
+ int getRegister();
+}
diff --git a/smali/src/main/java/org/jf/smali/main.java b/smali/src/main/java/org/jf/smali/main.java
index befa112c..c6095bf3 100644
--- a/smali/src/main/java/org/jf/smali/main.java
+++ b/smali/src/main/java/org/jf/smali/main.java
@@ -28,22 +28,25 @@
package org.jf.smali;
-import org.antlr.runtime.*;
+import com.google.common.collect.Lists;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenSource;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.apache.commons.cli.*;
-import org.jf.dexlib.Code.Opcode;
-import org.jf.dexlib.CodeItem;
-import org.jf.dexlib.DexFile;
-import org.jf.dexlib.Util.ByteArrayAnnotatedOutput;
+import org.jf.dexlib2.writer.builder.DexBuilder;
+import org.jf.dexlib2.writer.io.FileDataStore;
import org.jf.util.ConsoleUtil;
import org.jf.util.SmaliHelpFormatter;
+import javax.annotation.Nonnull;
import java.io.*;
-import java.util.LinkedHashSet;
-import java.util.Locale;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
/**
* Main class for smali. It recognizes enough options to be able to dispatch
@@ -64,14 +67,19 @@ public class main {
buildOptions();
InputStream templateStream = main.class.getClassLoader().getResourceAsStream("smali.properties");
- Properties properties = new Properties();
- String version = "(unknown)";
- try {
- properties.load(templateStream);
- version = properties.getProperty("application.version");
- } catch (IOException ex) {
+ if (templateStream != null) {
+ Properties properties = new Properties();
+ String version = "(unknown)";
+ try {
+ properties.load(templateStream);
+ version = properties.getProperty("application.version");
+ } catch (IOException ex) {
+ // just eat it
+ }
+ VERSION = version;
+ } else {
+ VERSION = "[unknown version]";
}
- VERSION = version;
}
@@ -98,18 +106,14 @@ public class main {
return;
}
+ int jobs = -1;
boolean allowOdex = false;
- boolean sort = false;
- boolean jumboInstructions = false;
- boolean fixGoto = true;
boolean verboseErrors = false;
boolean printTokens = false;
- boolean apiSet = false;
- int apiLevel = 14;
+ int apiLevel = 15;
String outputDexFile = "out.dex";
- String dumpFileName = null;
String[] remainingArgs = commandLine.getArgs();
@@ -140,19 +144,9 @@ public class main {
break;
case 'a':
apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
- apiSet = true;
- break;
- case 'D':
- dumpFileName = commandLine.getOptionValue("D", outputDexFile + ".dump");
break;
- case 'S':
- sort = true;
- break;
- case 'J':
- jumboInstructions = true;
- break;
- case 'G':
- fixGoto = false;
+ case 'j':
+ jobs = Integer.parseInt(commandLine.getOptionValue("j"));
break;
case 'V':
verboseErrors = true;
@@ -187,62 +181,52 @@ public class main {
}
}
- Opcode.updateMapsForApiLevel(apiLevel, jumboInstructions);
-
- DexFile dexFile = new DexFile();
-
- if (apiSet && apiLevel >= 14) {
- dexFile.HeaderItem.setVersion(36);
- }
-
- boolean errors = false;
-
- for (File file: filesToProcess) {
- if (!assembleSmaliFile(file, dexFile, verboseErrors, printTokens, allowOdex, apiLevel)) {
- errors = true;
+ if (jobs <= 0) {
+ jobs = Runtime.getRuntime().availableProcessors();
+ if (jobs > 6) {
+ jobs = 6;
}
}
- if (errors) {
- System.exit(1);
- }
-
-
- if (sort) {
- dexFile.setSortAllItems(true);
- }
+ boolean errors = false;
- if (fixGoto) {
- fixInstructions(dexFile, true, fixGoto);
+ final DexBuilder dexBuilder = DexBuilder.makeDexBuilder(apiLevel);
+ ExecutorService executor = Executors.newFixedThreadPool(jobs);
+ List<Future<Boolean>> tasks = Lists.newArrayList();
+
+ final boolean finalVerboseErrors = verboseErrors;
+ final boolean finalPrintTokens = printTokens;
+ final boolean finalAllowOdex = allowOdex;
+ final int finalApiLevel = apiLevel;
+ for (final File file: filesToProcess) {
+ tasks.add(executor.submit(new Callable<Boolean>() {
+ @Override public Boolean call() throws Exception {
+ return assembleSmaliFile(file, dexBuilder, finalVerboseErrors, finalPrintTokens,
+ finalAllowOdex, finalApiLevel);
+ }
+ }));
}
- dexFile.place();
-
- ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
-
- if (dumpFileName != null) {
- out.enableAnnotations(120, true);
+ for (Future<Boolean> task: tasks) {
+ while(true) {
+ try {
+ if (!task.get()) {
+ errors = true;
+ }
+ } catch (InterruptedException ex) {
+ continue;
+ }
+ break;
+ }
}
- dexFile.writeTo(out);
-
- byte[] bytes = out.toByteArray();
+ executor.shutdown();
- DexFile.calcSignature(bytes);
- DexFile.calcChecksum(bytes);
-
- if (dumpFileName != null) {
- out.finishAnnotating();
-
- FileWriter fileWriter = new FileWriter(dumpFileName);
- out.writeAnnotationsTo(fileWriter);
- fileWriter.close();
+ if (errors) {
+ System.exit(1);
}
- FileOutputStream fileOutputStream = new FileOutputStream(outputDexFile);
-
- fileOutputStream.write(bytes);
- fileOutputStream.close();
+ dexBuilder.writeTo(new FileDataStore(new File(outputDexFile)));
} catch (RuntimeException ex) {
System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
ex.printStackTrace();
@@ -254,31 +238,24 @@ public class main {
}
}
- private static void getSmaliFilesInDir(File dir, Set<File> smaliFiles) {
- for(File file: dir.listFiles()) {
- if (file.isDirectory()) {
- getSmaliFilesInDir(file, smaliFiles);
- } else if (file.getName().endsWith(".smali")) {
- smaliFiles.add(file);
+ private static void getSmaliFilesInDir(@Nonnull File dir, @Nonnull Set<File> smaliFiles) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for(File file: files) {
+ if (file.isDirectory()) {
+ getSmaliFilesInDir(file, smaliFiles);
+ } else if (file.getName().endsWith(".smali")) {
+ smaliFiles.add(file);
+ }
}
}
}
- private static void fixInstructions(DexFile dexFile, boolean fixJumbo, boolean fixGoto) {
- dexFile.place();
-
- for (CodeItem codeItem: dexFile.CodeItemsSection.getItems()) {
- codeItem.fixInstructions(fixJumbo, fixGoto);
- }
- }
-
- private static boolean assembleSmaliFile(File smaliFile, DexFile dexFile, boolean verboseErrors,
+ private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, boolean verboseErrors,
boolean printTokens, boolean allowOdex, int apiLevel)
throws Exception {
CommonTokenStream tokens;
-
- boolean lexerErrors = false;
LexerErrorInterface lexer;
FileInputStream fis = new FileInputStream(smaliFile.getAbsolutePath());
@@ -312,21 +289,17 @@ public class main {
return false;
}
- CommonTree t = (CommonTree) result.getTree();
+ CommonTree t = result.getTree();
CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
treeStream.setTokenStream(tokens);
smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
dexGen.setVerboseErrors(verboseErrors);
- dexGen.dexFile = dexFile;
+ dexGen.setDexBuilder(dexBuilder);
dexGen.smali_file();
- if (dexGen.getNumberOfSyntaxErrors() > 0) {
- return false;
- }
-
- return true;
+ return dexGen.getNumberOfSyntaxErrors() == 0;
}
@@ -361,6 +334,7 @@ public class main {
System.exit(0);
}
+ @SuppressWarnings("AccessStaticViaInstance")
private static void buildOptions() {
Option versionOption = OptionBuilder.withLongOpt("version")
.withDescription("prints the version then exits")
@@ -384,31 +358,17 @@ public class main {
Option apiLevelOption = OptionBuilder.withLongOpt("api-level")
.withDescription("The numeric api-level of the file to generate, e.g. 14 for ICS. If not " +
- "specified, it defaults to 14 (ICS).")
+ "specified, it defaults to 15 (ICS).")
.hasArg()
.withArgName("API_LEVEL")
.create("a");
- Option dumpOption = OptionBuilder.withLongOpt("dump-to")
- .withDescription("additionally writes a dump of written dex file to FILE (<dexfile>.dump by default)")
- .hasOptionalArg()
- .withArgName("FILE")
- .create("D");
-
- Option sortOption = OptionBuilder.withLongOpt("sort")
- .withDescription("sort the items in the dex file into a canonical order before writing")
- .create("S");
-
- Option jumboInstructionsOption = OptionBuilder.withLongOpt("jumbo-instructions")
- .withDescription("adds support for the jumbo opcodes that were temporarily available around the" +
- " ics timeframe. Note that support for these opcodes was removed from newer version of" +
- " dalvik. You shouldn't use this option unless you know the dex file will only be used on a" +
- " device that supports these opcodes.")
- .create("J");
-
- Option noFixGotoOption = OptionBuilder.withLongOpt("no-fix-goto")
- .withDescription("Don't replace goto type instructions with a larger version where appropriate")
- .create("G");
+ Option jobsOption = OptionBuilder.withLongOpt("jobs")
+ .withDescription("The number of threads to use. Defaults to the number of cores available, up to a " +
+ "maximum of 6")
+ .hasArg()
+ .withArgName("NUM_THREADS")
+ .create("j");
Option verboseErrorsOption = OptionBuilder.withLongOpt("verbose-errors")
.withDescription("Generate verbose error messages")
@@ -423,11 +383,8 @@ public class main {
basicOptions.addOption(outputOption);
basicOptions.addOption(allowOdexOption);
basicOptions.addOption(apiLevelOption);
+ basicOptions.addOption(jobsOption);
- debugOptions.addOption(dumpOption);
- debugOptions.addOption(sortOption);
- debugOptions.addOption(jumboInstructionsOption);
- debugOptions.addOption(noFixGotoOption);
debugOptions.addOption(verboseErrorsOption);
debugOptions.addOption(printTokensOption);
diff --git a/smali/src/main/jflex/smaliLexer.flex b/smali/src/main/jflex/smaliLexer.flex
index 81b9979b..1540bf8c 100644
--- a/smali/src/main/jflex/smaliLexer.flex
+++ b/smali/src/main/jflex/smaliLexer.flex
@@ -45,7 +45,7 @@ import static org.jf.smali.smaliParser.*;
}
catch (java.io.IOException e) {
System.err.println("shouldn't happen: " + e.getMessage());
- return Token.EOF_TOKEN;
+ return newToken(EOF);
}
}
@@ -254,8 +254,8 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
".catch" { return newToken(CATCH_DIRECTIVE); }
".catchall" { return newToken(CATCHALL_DIRECTIVE); }
".line" { return newToken(LINE_DIRECTIVE); }
- ".parameter" { return newToken(PARAMETER_DIRECTIVE); }
- ".end parameter" { return newToken(END_PARAMETER_DIRECTIVE); }
+ ".param" { return newToken(PARAMETER_DIRECTIVE); }
+ ".end param" { return newToken(END_PARAMETER_DIRECTIVE); }
".local" { return newToken(LOCAL_DIRECTIVE); }
".end local" { return newToken(END_LOCAL_DIRECTIVE); }
".restart local" { return newToken(RESTART_LOCAL_DIRECTIVE); }
@@ -377,8 +377,6 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
"vtable@0x" {HexDigit}+ { return newToken(VTABLE_INDEX); }
"field@0x" {HexDigit}+ { return newToken(FIELD_OFFSET); }
- "+" {Integer} { return newToken(OFFSET); }
-
# [^\r\n]* { return newToken(LINE_COMMENT, true); }
}
@@ -447,8 +445,12 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
return newToken(INSTRUCTION_FORMAT21c_TYPE);
}
- "const/high16" | "const-wide/high16" {
- return newToken(INSTRUCTION_FORMAT21h);
+ "const/high16" {
+ return newToken(INSTRUCTION_FORMAT21ih);
+ }
+
+ "const-wide/high16" {
+ return newToken(INSTRUCTION_FORMAT21lh);
}
"const/16" | "const-wide/16" {
@@ -574,52 +576,9 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
return newToken(INSTRUCTION_FORMAT3rms_METHOD);
}
- "check-cast/jumbo" | "new-instance/jumbo" | "const-class/jumbo" {
- return newToken(INSTRUCTION_FORMAT41c_TYPE);
- }
-
- "sget/jumbo" | "sget-wide/jumbo" | "sget-object/jumbo" | "sget-boolean/jumbo" | "sget-byte/jumbo" |
- "sget-char/jumbo" | "sget-short/jumbo" | "sput/jumbo" | "sput-wide/jumbo" | "sput-object/jumbo" |
- "sput-boolean/jumbo" | "sput-byte/jumbo" | "sput-char/jumbo" | "sput-short/jumbo" {
- return newToken(INSTRUCTION_FORMAT41c_FIELD);
- }
-
- "sget-volatile/jumbo" | "sget-wide-volatile/jumbo" | "sget-object-volatile/jumbo" | "sput-volatile/jumbo" |
- "sput-wide-volatile/jumbo" | "sput-object-volatile/jumbo" {
- return newToken(INSTRUCTION_FORMAT41c_FIELD_ODEX);
- }
-
"const-wide" {
return newToken(INSTRUCTION_FORMAT51l);
}
-
- "instance-of/jumbo" | "new-array/jumbo" {
- return newToken(INSTRUCTION_FORMAT52c_TYPE);
- }
-
- "iget/jumbo" | "iget-wide/jumbo" | "iget-object/jumbo" | "iget-boolean/jumbo" | "iget-byte/jumbo" |
- "iget-char/jumbo" | "iget-short/jumbo" | "iput/jumbo" | "iput-wide/jumbo" | "iput-object/jumbo" |
- "iput-boolean/jumbo" | "iput-byte/jumbo" | "iput-char/jumbo" | "iput-short/jumbo" {
- return newToken(INSTRUCTION_FORMAT52c_FIELD);
- }
-
- "iget-volatile/jumbo" | "iget-wide-volatile/jumbo" | "iget-object-volatile/jumbo" | "iput-volatile/jumbo" |
- "iput-wide-volatile/jumbo" | "iput-object-volatile/jumbo" {
- return newToken(INSTRUCTION_FORMAT52c_FIELD_ODEX);
- }
-
- "invoke-virtual/jumbo" | "invoke-super/jumbo" | "invoke-direct/jumbo" | "invoke-static/jumbo" |
- "invoke-interface/jumbo" {
- return newToken(INSTRUCTION_FORMAT5rc_METHOD);
- }
-
- "invoke-object-init/jumbo" {
- return newToken(INSTRUCTION_FORMAT5rc_METHOD_ODEX);
- }
-
- "filled-new-array/jumbo" {
- return newToken(INSTRUCTION_FORMAT5rc_TYPE);
- }
}
/*Types*/
@@ -631,7 +590,7 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
{PrimitiveType} {PrimitiveType}+ { return newToken(PARAM_LIST_OR_ID); }
{Type} {Type}+ { return newToken(PARAM_LIST); }
{SimpleName} { return newToken(SIMPLE_NAME); }
- "<init>" | "<clinit>" { return newToken(METHOD_NAME); }
+ "<" {SimpleName} ">" { return newToken(MEMBER_NAME); }
}
/*Symbols/Whitespace/EOF*/
diff --git a/smali/src/test/java/LexerTest.java b/smali/src/test/java/LexerTest.java
index 074b32ed..c1b70435 100644
--- a/smali/src/test/java/LexerTest.java
+++ b/smali/src/test/java/LexerTest.java
@@ -30,16 +30,21 @@ import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
-import org.jf.dexlib.Util.Utf8Utils;
-import org.jf.smali.*;
-import static org.jf.smali.expectedTokensTestGrammarParser.ExpectedToken;
+import org.jf.smali.expectedTokensTestGrammarLexer;
+import org.jf.smali.expectedTokensTestGrammarParser;
+import org.jf.smali.smaliFlexLexer;
+import org.jf.smali.smaliParser;
import org.junit.Assert;
import org.junit.Test;
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
+import static org.jf.smali.expectedTokensTestGrammarParser.ExpectedToken;
+
public class LexerTest {
private static final HashMap<String, Integer> tokenTypesByName;
@@ -158,11 +163,12 @@ public class LexerTest {
lexer.setSuppressErrors(true);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
+ tokenStream.fill();
List tokens = tokenStream.getTokens();
int expectedTokenIndex = 0;
CommonToken token;
- for (int i=0; i<tokens.size(); i++) {
+ for (int i=0; i<tokens.size()-1; i++) {
token = (CommonToken)tokens.get(i);
if (discardHiddenTokens && token.getChannel() == smaliParser.HIDDEN) {
diff --git a/smali/src/test/resources/LexerTest/DirectiveTest.smali b/smali/src/test/resources/LexerTest/DirectiveTest.smali
index 5ec54d8b..7ceec71a 100644
--- a/smali/src/test/resources/LexerTest/DirectiveTest.smali
+++ b/smali/src/test/resources/LexerTest/DirectiveTest.smali
@@ -23,8 +23,8 @@
.catch
.catchall
.line
-.parameter
-.end parameter
+.param
+.end param
.local
.end local
.restart local
@@ -52,5 +52,7 @@
.
.1234.1234
.
+.parameter
+.end parameter
diff --git a/smali/src/test/resources/LexerTest/DirectiveTest.tokens b/smali/src/test/resources/LexerTest/DirectiveTest.tokens
index 0579ad1b..06f4da73 100644
--- a/smali/src/test/resources/LexerTest/DirectiveTest.tokens
+++ b/smali/src/test/resources/LexerTest/DirectiveTest.tokens
@@ -22,8 +22,8 @@ END_SPARSE_SWITCH_DIRECTIVE(".end sparse-switch")
CATCH_DIRECTIVE(".catch")
CATCHALL_DIRECTIVE(".catchall")
LINE_DIRECTIVE(".line")
-PARAMETER_DIRECTIVE(".parameter")
-END_PARAMETER_DIRECTIVE(".end parameter")
+PARAMETER_DIRECTIVE(".param")
+END_PARAMETER_DIRECTIVE(".end param")
LOCAL_DIRECTIVE(".local")
END_LOCAL_DIRECTIVE(".end local")
RESTART_LOCAL_DIRECTIVE(".restart local")
@@ -61,4 +61,6 @@ INVALID_TOKEN(".end")
INVALID_TOKEN(".")
DOUBLE_LITERAL(".1234")
DOUBLE_LITERAL(".1234")
-INVALID_TOKEN(".") \ No newline at end of file
+INVALID_TOKEN(".")
+INVALID_TOKEN(".parameter")
+INVALID_TOKEN(".end parameter") \ No newline at end of file
diff --git a/smali/src/test/resources/LexerTest/InstructionTest.smali b/smali/src/test/resources/LexerTest/InstructionTest.smali
index 8b458342..2247adc0 100644
--- a/smali/src/test/resources/LexerTest/InstructionTest.smali
+++ b/smali/src/test/resources/LexerTest/InstructionTest.smali
@@ -225,56 +225,4 @@ filled-new-array/range
execute-inline/range
invoke-virtual-quick/range
invoke-super-quick/range
-check-cast/jumbo
-new-instance/jumbo
-const-class/jumbo
-sget/jumbo
-sget-wide/jumbo
-sget-object/jumbo
-sget-boolean/jumbo
-sget-byte/jumbo
-sget-char/jumbo
-sget-short/jumbo
-sput/jumbo
-sput-wide/jumbo
-sput-object/jumbo
-sput-boolean/jumbo
-sput-byte/jumbo
-sput-char/jumbo
-sput-short/jumbo
const-wide
-instance-of/jumbo
-new-array/jumbo
-iget/jumbo
-iget-wide/jumbo
-iget-object/jumbo
-iget-boolean/jumbo
-iget-byte/jumbo
-iget-char/jumbo
-iget-short/jumbo
-iput/jumbo
-iput-wide/jumbo
-iput-object/jumbo
-iput-boolean/jumbo
-iput-byte/jumbo
-iput-char/jumbo
-iput-short/jumbo
-invoke-virtual/jumbo
-invoke-super/jumbo
-invoke-direct/jumbo
-invoke-static/jumbo
-invoke-interface/jumbo
-filled-new-array/jumbo
-invoke-object-init/jumbo
-iget-volatile/jumbo
-iget-wide-volatile/jumbo
-iget-object-volatile/jumbo
-iput-volatile/jumbo
-iput-wide-volatile/jumbo
-iput-object-volatile/jumbo
-sget-volatile/jumbo
-sget-wide-volatile/jumbo
-sget-object-volatile/jumbo
-sput-volatile/jumbo
-sput-wide-volatile/jumbo
-sput-object-volatile/jumbo
diff --git a/smali/src/test/resources/LexerTest/InstructionTest.tokens b/smali/src/test/resources/LexerTest/InstructionTest.tokens
index 457ceebd..a5574ab4 100644
--- a/smali/src/test/resources/LexerTest/InstructionTest.tokens
+++ b/smali/src/test/resources/LexerTest/InstructionTest.tokens
@@ -84,8 +84,8 @@ INSTRUCTION_FORMAT21c_STRING("const-string")
INSTRUCTION_FORMAT21c_TYPE("check-cast")
INSTRUCTION_FORMAT21c_TYPE("new-instance")
INSTRUCTION_FORMAT21c_TYPE("const-class")
-INSTRUCTION_FORMAT21h("const/high16")
-INSTRUCTION_FORMAT21h("const-wide/high16")
+INSTRUCTION_FORMAT21ih("const/high16")
+INSTRUCTION_FORMAT21lh("const-wide/high16")
INSTRUCTION_FORMAT21s("const/16")
INSTRUCTION_FORMAT21s("const-wide/16")
INSTRUCTION_FORMAT21t("if-eqz")
@@ -225,56 +225,4 @@ INSTRUCTION_FORMAT3rc_TYPE("filled-new-array/range")
INSTRUCTION_FORMAT3rmi_METHOD("execute-inline/range")
INSTRUCTION_FORMAT3rms_METHOD("invoke-virtual-quick/range")
INSTRUCTION_FORMAT3rms_METHOD("invoke-super-quick/range")
-INSTRUCTION_FORMAT41c_TYPE("check-cast/jumbo")
-INSTRUCTION_FORMAT41c_TYPE("new-instance/jumbo")
-INSTRUCTION_FORMAT41c_TYPE("const-class/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sget/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sget-wide/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sget-object/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sget-boolean/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sget-byte/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sget-char/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sget-short/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sput/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sput-wide/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sput-object/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sput-boolean/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sput-byte/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sput-char/jumbo")
-INSTRUCTION_FORMAT41c_FIELD("sput-short/jumbo")
-INSTRUCTION_FORMAT51l("const-wide")
-INSTRUCTION_FORMAT52c_TYPE("instance-of/jumbo")
-INSTRUCTION_FORMAT52c_TYPE("new-array/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iget/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iget-wide/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iget-object/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iget-boolean/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iget-byte/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iget-char/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iget-short/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iput/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iput-wide/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iput-object/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iput-boolean/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iput-byte/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iput-char/jumbo")
-INSTRUCTION_FORMAT52c_FIELD("iput-short/jumbo")
-INSTRUCTION_FORMAT5rc_METHOD("invoke-virtual/jumbo")
-INSTRUCTION_FORMAT5rc_METHOD("invoke-super/jumbo")
-INSTRUCTION_FORMAT5rc_METHOD("invoke-direct/jumbo")
-INSTRUCTION_FORMAT5rc_METHOD("invoke-static/jumbo")
-INSTRUCTION_FORMAT5rc_METHOD("invoke-interface/jumbo")
-INSTRUCTION_FORMAT5rc_TYPE("filled-new-array/jumbo")
-INSTRUCTION_FORMAT5rc_METHOD_ODEX("invoke-object-init/jumbo")
-INSTRUCTION_FORMAT52c_FIELD_ODEX("iget-volatile/jumbo")
-INSTRUCTION_FORMAT52c_FIELD_ODEX("iget-wide-volatile/jumbo")
-INSTRUCTION_FORMAT52c_FIELD_ODEX("iget-object-volatile/jumbo")
-INSTRUCTION_FORMAT52c_FIELD_ODEX("iput-volatile/jumbo")
-INSTRUCTION_FORMAT52c_FIELD_ODEX("iput-wide-volatile/jumbo")
-INSTRUCTION_FORMAT52c_FIELD_ODEX("iput-object-volatile/jumbo")
-INSTRUCTION_FORMAT41c_FIELD_ODEX("sget-volatile/jumbo")
-INSTRUCTION_FORMAT41c_FIELD_ODEX("sget-wide-volatile/jumbo")
-INSTRUCTION_FORMAT41c_FIELD_ODEX("sget-object-volatile/jumbo")
-INSTRUCTION_FORMAT41c_FIELD_ODEX("sput-volatile/jumbo")
-INSTRUCTION_FORMAT41c_FIELD_ODEX("sput-wide-volatile/jumbo")
-INSTRUCTION_FORMAT41c_FIELD_ODEX("sput-object-volatile/jumbo")
+INSTRUCTION_FORMAT51l("const-wide") \ No newline at end of file
diff --git a/smali/src/test/resources/LexerTest/MiscTest.tokens b/smali/src/test/resources/LexerTest/MiscTest.tokens
index b42f2514..ed5142d8 100644
--- a/smali/src/test/resources/LexerTest/MiscTest.tokens
+++ b/smali/src/test/resources/LexerTest/MiscTest.tokens
@@ -67,12 +67,12 @@ SIMPLE_NAME("field") INVALID_TOKEN("@")
SIMPLE_NAME("field") INVALID_TOKEN("@") SIMPLE_NAME("zzz")
SIMPLE_NAME("field") INVALID_TOKEN("@") SIMPLE_NAME("abcd")
-OFFSET("+0")
-OFFSET("+10")
-OFFSET("+01")
-OFFSET("+0777")
-OFFSET("+0x1234ABC")
-OFFSET("+1234")
+INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("0")
+INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("10")
+INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("01")
+INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("0777")
+INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("0x1234ABC")
+INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("1234")
-OFFSET("+0") POSITIVE_INTEGER_LITERAL("8")
+INVALID_TOKEN("+") SIMPLE_NAME("08")
INVALID_TOKEN("+") \ No newline at end of file
diff --git a/smali/src/test/resources/LexerTest/RealSmaliFileTest.smali b/smali/src/test/resources/LexerTest/RealSmaliFileTest.smali
index 2062f75f..b1bbcbb6 100644
--- a/smali/src/test/resources/LexerTest/RealSmaliFileTest.smali
+++ b/smali/src/test/resources/LexerTest/RealSmaliFileTest.smali
@@ -100,7 +100,7 @@
# direct methods
.method constructor <init>(Lcom/android/internal/telephony/cdma/CDMAPhone;)V
.registers 2
- .parameter "phone"
+ .param p1, phone
.prologue
.line 42
@@ -112,7 +112,7 @@
.method protected getEFPath(I)Ljava/lang/String;
.registers 3
- .parameter "efid"
+ .param p1, efid
.prologue
.line 71
@@ -145,7 +145,7 @@
.method CardStateFromRILInt(I)Lcom/android/internal/telephony/IccCardStatus$CardState;
.registers 6
- .parameter "state"
+ .param p1, state
.prologue
.line 59
@@ -214,11 +214,11 @@
.method public setCallForwardingOption(IILjava/lang/String;ILandroid/os/Message;)V
.registers 13
- .parameter "commandInterfaceCFAction"
- .parameter "commandInterfaceCFReason"
- .parameter "dialingNumber"
- .parameter "timerSeconds"
- .parameter "onComplete"
+ .param p1, commandInterfaceCFAction
+ .param p2, commandInterfaceCFReason
+ .param p3, dialingNumber
+ .param p4, timerSeconds
+ .param p5, onComplete
.prologue
const/4 v3, 0x1
diff --git a/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens b/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens
index 562530df..a0f648a1 100644
--- a/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens
+++ b/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens
@@ -152,7 +152,7 @@ END_FIELD_DIRECTIVE(".end field")
METHOD_DIRECTIVE(".method")
ACCESS_SPEC("static")
ACCESS_SPEC("constructor")
-METHOD_NAME("<clinit>")
+MEMBER_NAME("<clinit>")
OPEN_PAREN("(")
CLOSE_PAREN(")")
VOID_TYPE("V")
@@ -211,7 +211,7 @@ CLOSE_BRACE("}")
COMMA(",")
CLASS_DESCRIPTOR("Lcom/android/internal/os/BatteryStatsImpl$1;")
ARROW("->")
-METHOD_NAME("<init>")
+MEMBER_NAME("<init>")
OPEN_PAREN("(")
CLOSE_PAREN(")")
VOID_TYPE("V")
@@ -259,15 +259,17 @@ END_ARRAY_DATA_DIRECTIVE(".end array-data")
END_METHOD_DIRECTIVE(".end method")
METHOD_DIRECTIVE(".method")
ACCESS_SPEC("constructor")
-METHOD_NAME("<init>")
+MEMBER_NAME("<init>")
OPEN_PAREN("(")
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/cdma/CDMAPhone;")
CLOSE_PAREN(")")
VOID_TYPE("V")
REGISTERS_DIRECTIVE(".registers")
POSITIVE_INTEGER_LITERAL("2")
-PARAMETER_DIRECTIVE(".parameter")
-STRING_LITERAL("\"phone\"")
+PARAMETER_DIRECTIVE(".param")
+REGISTER("p1")
+COMMA(",")
+SIMPLE_NAME("phone")
PROLOGUE_DIRECTIVE(".prologue")
LINE_DIRECTIVE(".line")
POSITIVE_INTEGER_LITERAL("42")
@@ -280,7 +282,7 @@ CLOSE_BRACE("}")
COMMA(",")
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/IccFileHandler;")
ARROW("->")
-METHOD_NAME("<init>")
+MEMBER_NAME("<init>")
OPEN_PAREN("(")
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/PhoneBase;")
CLOSE_PAREN(")")
@@ -298,8 +300,10 @@ CLOSE_PAREN(")")
CLASS_DESCRIPTOR("Ljava/lang/String;")
REGISTERS_DIRECTIVE(".registers")
POSITIVE_INTEGER_LITERAL("3")
-PARAMETER_DIRECTIVE(".parameter")
-STRING_LITERAL("\"efid\"")
+PARAMETER_DIRECTIVE(".param")
+REGISTER("p1")
+COMMA(",")
+SIMPLE_NAME("efid")
PROLOGUE_DIRECTIVE(".prologue")
LINE_DIRECTIVE(".line")
POSITIVE_INTEGER_LITERAL("71")
@@ -369,8 +373,10 @@ CLOSE_PAREN(")")
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/IccCardStatus$CardState;")
REGISTERS_DIRECTIVE(".registers")
POSITIVE_INTEGER_LITERAL("6")
-PARAMETER_DIRECTIVE(".parameter")
-STRING_LITERAL("\"state\"")
+PARAMETER_DIRECTIVE(".param")
+REGISTER("p1")
+COMMA(",")
+SIMPLE_NAME("state")
PROLOGUE_DIRECTIVE(".prologue")
LINE_DIRECTIVE(".line")
POSITIVE_INTEGER_LITERAL("59")
@@ -396,7 +402,7 @@ CLOSE_BRACE("}")
COMMA(",")
CLASS_DESCRIPTOR("Ljava/lang/StringBuilder;")
ARROW("->")
-METHOD_NAME("<init>")
+MEMBER_NAME("<init>")
OPEN_PAREN("(")
CLOSE_PAREN(")")
VOID_TYPE("V")
@@ -458,7 +464,7 @@ CLOSE_BRACE("}")
COMMA(",")
CLASS_DESCRIPTOR("Ljava/lang/RuntimeException;")
ARROW("->")
-METHOD_NAME("<init>")
+MEMBER_NAME("<init>")
OPEN_PAREN("(")
CLASS_DESCRIPTOR("Ljava/lang/String;")
CLOSE_PAREN(")")
@@ -551,16 +557,26 @@ CLOSE_PAREN(")")
VOID_TYPE("V")
REGISTERS_DIRECTIVE(".registers")
POSITIVE_INTEGER_LITERAL("13")
-PARAMETER_DIRECTIVE(".parameter")
-STRING_LITERAL("\"commandInterfaceCFAction\"")
-PARAMETER_DIRECTIVE(".parameter")
-STRING_LITERAL("\"commandInterfaceCFReason\"")
-PARAMETER_DIRECTIVE(".parameter")
-STRING_LITERAL("\"dialingNumber\"")
-PARAMETER_DIRECTIVE(".parameter")
-STRING_LITERAL("\"timerSeconds\"")
-PARAMETER_DIRECTIVE(".parameter")
-STRING_LITERAL("\"onComplete\"")
+PARAMETER_DIRECTIVE(".param")
+REGISTER("p1")
+COMMA(",")
+SIMPLE_NAME("commandInterfaceCFAction")
+PARAMETER_DIRECTIVE(".param")
+REGISTER("p2")
+COMMA(",")
+SIMPLE_NAME("commandInterfaceCFReason")
+PARAMETER_DIRECTIVE(".param")
+REGISTER("p3")
+COMMA(",")
+SIMPLE_NAME("dialingNumber")
+PARAMETER_DIRECTIVE(".param")
+REGISTER("p4")
+COMMA(",")
+SIMPLE_NAME("timerSeconds")
+PARAMETER_DIRECTIVE(".param")
+REGISTER("p5")
+COMMA(",")
+SIMPLE_NAME("onComplete")
PROLOGUE_DIRECTIVE(".prologue")
INSTRUCTION_FORMAT11n("const/4")
REGISTER("v3")
diff --git a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali
index 7fd9b65a..f001d19e 100644
--- a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali
+++ b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali
@@ -34,6 +34,8 @@ Ljava/lang/String;Ljava/lang/String;
<init>
<clinit>
+<blah>
+<init->
Ljava/lang/String
L;
diff --git a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens
index 531622e9..2bd781a5 100644
--- a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens
+++ b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens
@@ -32,8 +32,10 @@ PARAM_LIST("[I[I[I")
PARAM_LIST("[I[Z")
PARAM_LIST("[I[Ljava/lang/String;")
-METHOD_NAME("<init>")
-METHOD_NAME("<clinit>")
+MEMBER_NAME("<init>")
+MEMBER_NAME("<clinit>")
+MEMBER_NAME("<blah>")
+MEMBER_NAME("<init->")
SIMPLE_NAME("Ljava") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String")
SIMPLE_NAME("L") INVALID_TOKEN(";")
@@ -45,4 +47,4 @@ INVALID_TOKEN("[") VOID_TYPE("V")
INVALID_TOKEN("[") SIMPLE_NAME("java") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String") INVALID_TOKEN(";")
INVALID_TOKEN("[") INVALID_TOKEN(";")
-INVALID_TOKEN("<") SIMPLE_NAME("linit") INVALID_TOKEN(">") \ No newline at end of file
+MEMBER_NAME("<linit>") \ No newline at end of file