diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g b/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g index edd15f16..2c0245c6 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g @@ -178,23 +178,13 @@ import java.util.ArrayDeque; tokens.add(token); } -/*protected void mismatch(IntStream input, int ttype, BitSet follow) throws RecognitionException -{ - throw new MismatchedTokenException(ttype, input); + public void reportError(RecognitionException e) + { + throw new RuntimeException(e); + } } -public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException -{ - throw e; -}*/ -} - -/*@rulecatch { -catch (RecognitionException e) { -throw e; -} -}*/ CLASS_PHRASE : CLASS_DIRECTIVE_EMIT @@ -207,6 +197,16 @@ SUPER_PHRASE WS CLASS_DESCRIPTOR_EMIT; +IMPLEMENTS_PHRASE + : IMPLEMENTS_DIRECTIVE_EMIT + WS + CLASS_DESCRIPTOR_EMIT; + +SOURCE_PHRASE + : SOURCE_DIRECTIVE_EMIT + WS + STRING_LITERAL_EMIT; + FIELD_PHRASE : FIELD_DIRECTIVE_EMIT WS @@ -461,7 +461,7 @@ CATCH_PHRASE (LABEL_EMIT | OFFSET_EMIT) WS 'to' WS (LABEL_EMIT | OFFSET_EMIT) - WS 'using' + WS 'using' WS (LABEL_EMIT | OFFSET_EMIT); @@ -485,6 +485,16 @@ fragment SUPER_DIRECTIVE_EMIT : SUPER_DIRECTIVE {emit($SUPER_DIRECTIVE, SUPER_DIRECTIVE);}; fragment SUPER_DIRECTIVE : '.super'; + +fragment IMPLEMENTS_DIRECTIVE_EMIT + : IMPLEMENTS_DIRECTIVE {emit($IMPLEMENTS_DIRECTIVE, IMPLEMENTS_DIRECTIVE);}; +fragment IMPLEMENTS_DIRECTIVE + : '.implements'; + +fragment SOURCE_DIRECTIVE_EMIT + : SOURCE_DIRECTIVE {emit($SOURCE_DIRECTIVE, SOURCE_DIRECTIVE);}; +fragment SOURCE_DIRECTIVE + : '.source'; fragment FIELD_DIRECTIVE_EMIT : FIELD_DIRECTIVE {emit($FIELD_DIRECTIVE, FIELD_DIRECTIVE);}; @@ -505,7 +515,7 @@ fragment REGISTERS_DIRECTIVE_EMIT : REGISTERS_DIRECTIVE {emit($REGISTERS_DIRECTIVE, REGISTERS_DIRECTIVE);}; fragment REGISTERS_DIRECTIVE : '.registers'; - + fragment ARRAY_DATA_DIRECTIVE_EMIT : ARRAY_DATA_DIRECTIVE {emit($ARRAY_DATA_DIRECTIVE, ARRAY_DATA_DIRECTIVE);}; fragment ARRAY_DATA_DIRECTIVE diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliParser.g b/src/main/antlr3/org/JesusFreke/smali/smaliParser.g index 00c816c6..aaa4329b 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliParser.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliParser.g @@ -38,6 +38,8 @@ tokens { //I_* tokens are imaginary tokens used as parent AST nodes I_CLASS_DEF; I_SUPER; + I_IMPLEMENTS; + I_SOURCE; I_ACCESS_LIST; I_METHODS; I_FIELDS; @@ -108,21 +110,81 @@ import org.JesusFreke.dexlib.code.Format.*; } -smali_file: header methods_and_fields -> ^(I_CLASS_DEF header methods_and_fields); +@members { + public String getErrorMessage(RecognitionException e, + String[] tokenNames) + { + List stack = getRuleInvocationStack(e, this.getClass().getName()); + String msg = null; + if ( e instanceof NoViableAltException ) { + NoViableAltException nvae = (NoViableAltException)e; + msg = " no viable alt; token="+e.token+ + " (decision="+nvae.decisionNumber+ + " state "+nvae.stateNumber+")"+ + " decision=<<"+nvae.grammarDecisionDescription+">>"; + } + else { + msg = super.getErrorMessage(e, tokenNames); + } + return stack+" "+msg; + } + + public String getTokenErrorDisplay(Token t) { + return t.toString(); + } +} -header : class_spec super_spec; +smali_file + scope + { + boolean hasClassSpec; + boolean hasSuperSpec; + } + : + { + $smali_file::hasClassSpec = false; + $smali_file::hasSuperSpec = false; + } + ( {!$smali_file::hasClassSpec}?=> class_spec {$smali_file::hasClassSpec = true;} + | {!$smali_file::hasSuperSpec}?=> super_spec {$smali_file::hasSuperSpec = true;} + | implements_spec + | source_spec + | method + | field)* + { + if (!$smali_file::hasClassSpec) { + //TODO: throw correct exception type + throw new RuntimeException("The file must contain a .class directive"); + } + + if (!$smali_file::hasSuperSpec) { + //TODO: throw correct exception type + throw new RuntimeException("The file must contain a .super directive"); + } + } + -> ^(I_CLASS_DEF + class_spec + super_spec + implements_spec* + source_spec + ^(I_METHODS method*) ^(I_FIELDS field*)); + class_spec : CLASS_DIRECTIVE access_list CLASS_DESCRIPTOR -> CLASS_DESCRIPTOR access_list; super_spec : SUPER_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_SUPER[$start, "I_SUPER"] CLASS_DESCRIPTOR); +implements_spec + : IMPLEMENTS_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_IMPLEMENTS[$start, "I_IMPLEMENTS"] CLASS_DESCRIPTOR); + +source_spec + : SOURCE_DIRECTIVE STRING_LITERAL -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL); + access_list : ACCESS_SPEC+ -> ^(I_ACCESS_LIST[$start,"I_ACCESS_LIST"] ACCESS_SPEC+); -methods_and_fields - : (method | field)* -> ^(I_METHODS method*) ^(I_FIELDS field*); field : FIELD_DIRECTIVE access_list MEMBER_NAME field_type_descriptor literal? -> ^(I_FIELD[$start, "I_FIELD"] MEMBER_NAME access_list ^(I_FIELD_TYPE field_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)?); diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g b/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g index 5ffaa987..d981bf2b 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g @@ -90,10 +90,10 @@ import org.JesusFreke.dexlib.code.Format.*; smali_file returns[ClassDefItem classDefItem] : ^(I_CLASS_DEF header methods fields); -header : class_spec super_spec +header : class_spec super_spec implements_list source_spec { classDataItem = new ClassDataItem(dexFile, 0); - classDefItem = new ClassDefItem(dexFile, $class_spec.type, $class_spec.accessFlags, $super_spec.type, classDataItem); + classDefItem = new ClassDefItem(dexFile, $class_spec.type, $class_spec.accessFlags, $super_spec.type, $implements_list.implementsList, $source_spec.source, classDataItem); }; class_spec returns[TypeIdItem type, int accessFlags] @@ -108,6 +108,27 @@ super_spec returns[TypeIdItem type] { $type = $class_type_descriptor.type; }; + + +implements_spec returns[TypeIdItem type] + : ^(I_IMPLEMENTS class_type_descriptor) + { + $type = $class_type_descriptor.type; + }; + +implements_list returns[TypeListItem implementsList] +@init { ArrayList typeList; } + : {typeList = new ArrayList();} + (implements_spec {typeList.add($implements_spec.type);} )* + {if (typeList.size() > 0) $implementsList = new TypeListItem(dexFile, typeList); + else $implementsList = null;}; + +source_spec returns[StringIdItem source] + : {$source = null;} + ^(I_SOURCE string_literal {$source = new StringIdItem(dexFile, $string_literal.value);}) + | ; + + access_list returns [int value] @init diff --git a/src/main/java/org/JesusFreke/dexlib/ClassDefItem.java b/src/main/java/org/JesusFreke/dexlib/ClassDefItem.java index 7bb5b2ec..3ef22945 100644 --- a/src/main/java/org/JesusFreke/dexlib/ClassDefItem.java +++ b/src/main/java/org/JesusFreke/dexlib/ClassDefItem.java @@ -69,7 +69,7 @@ public class ClassDefItem extends IndexedItem { }; } - public ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, ClassDataItem classDataItem) { + public ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementsList, StringIdItem source, ClassDataItem classDataItem) { super(-1); this.dexFile = dexFile; @@ -78,8 +78,8 @@ public class ClassDefItem extends IndexedItem { this.classType = new IndexedItemReference(dexFile, classType, new IntegerField()), this.accessFlags = new IntegerField(accessFlags), superclassType = new IndexedItemReference(dexFile, superType, new IntegerField()), - classInterfacesList = new OffsettedItemReference(dexFile.TypeListsSection, new IntegerField()), - sourceFile = new IndexedItemReference(dexFile.StringIdsSection, new IntegerField()), + classInterfacesList = new OffsettedItemReference(dexFile, implementsList, new IntegerField()), + sourceFile = new IndexedItemReference(dexFile, source, new IntegerField()), classAnnotations = new OffsettedItemReference(dexFile.AnnotationDirectoriesSection, new IntegerField()), classData = new OffsettedItemReference(dexFile, classDataItem, new IntegerField()), staticFieldInitialValues = new OffsettedItemReference(dexFile.EncodedArraysSection, new IntegerField()) diff --git a/src/test/resources/examples/HelloWorld2.smali b/src/test/resources/examples/HelloWorld2.smali index 447c552b..efb8ca49 100644 --- a/src/test/resources/examples/HelloWorld2.smali +++ b/src/test/resources/examples/HelloWorld2.smali @@ -1,6 +1,31 @@ .class public Lorg/JesusFreke/HelloWorld2/HelloWorld2; + .super Landroid/app/Activity; +.source "HelloWorld2.smali" + +;two random interfaces with only a single method to implement +.implements Landroid/util/Printer; +.implements Landroid/accounts/AccountMonitorListener; + + + +.method public println(Ljava/lang/String;)V + .registers 1 + + return-void +.end method + + + + +.method public onAccountsUpdated([Ljava/lang/String;)V + .registers 1 + + return-void +.end method + + .field private helloWorld Ljava/lang/String; .field private static helloWorldStatic Ljava/lang/String;