diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g b/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g index e51090fd..fb22f2de 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g @@ -122,31 +122,31 @@ import java.util.ArrayDeque; } public Token nextToken() { - while (true) { - if (tokens.size() > 0) { - Token token = tokens.poll(); - if (token == Token.SKIP_TOKEN) { - continue; - } - - System.out.println(token.toString()); - return token; - } + while (true) { + if (tokens.size() > 0) { + Token token = tokens.poll(); + if (token == Token.SKIP_TOKEN) { + continue; + } + + System.out.println(token.toString()); + return token; + } - state.channel = Token.DEFAULT_CHANNEL; - state.tokenStartCharIndex = input.index(); - state.tokenStartCharPositionInLine = input.getCharPositionInLine(); - state.tokenStartLine = input.getLine(); - state.text = null; - if ( input.LA(1)==CharStream.EOF ) { - return Token.EOF_TOKEN; - } - try { - mTokens(); + state.channel = Token.DEFAULT_CHANNEL; + state.tokenStartCharIndex = input.index(); + state.tokenStartCharPositionInLine = input.getCharPositionInLine(); + state.tokenStartLine = input.getLine(); + state.text = null; + if ( input.LA(1)==CharStream.EOF ) { + return Token.EOF_TOKEN; + } + try { + mTokens(); - if (tokens.size() == 0) { - emit(); - } + if (tokens.size() == 0) { + emit(); + } } catch (NoViableAltException nva) { reportError(nva); @@ -177,11 +177,6 @@ import java.util.ArrayDeque; token.setChannel(channel); tokens.add(token); } - - public void reportError(RecognitionException e) - { - throw new RuntimeException(e); - } } @@ -212,8 +207,8 @@ FIELD_PHRASE WS (FIELD_ACCESS_SPEC_EMIT WS)+ MEMBER_NAME_EMIT - WS - FIELD_TYPE_DESCRIPTOR_EMITCHILD + COLON_EMIT + NONVOID_TYPE_DESCRIPTOR_EMITCHILD WS? (EQUAL_EMIT WS? LITERAL_EMITCHILD)?; @@ -267,9 +262,7 @@ INSTRUCTION_FORMAT21c_FIELD_PHRASE WS REGISTER_EMIT WS? COMMA_EMIT WS? - FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN - WS - FIELD_TYPE_DESCRIPTOR_EMITCHILD; + FULLY_QUALIFIED_FIELD_EMITCHILDREN; INSTRUCTION_FORMAT21c_STRING_PHRASE : INSTRUCTION_FORMAT21c_STRING_EMIT @@ -283,7 +276,7 @@ INSTRUCTION_FORMAT21c_TYPE_PHRASE WS REGISTER_EMIT WS? COMMA_EMIT WS? - CLASS_OR_ARRAY_TYPE_DESCRIPTOR_EMITCHILD; + REFERENCE_TYPE_DESCRIPTOR_EMITCHILD; INSTRUCTION_FORMAT21h_PHRASE : INSTRUCTION_FORMAT21h_EMIT @@ -322,9 +315,7 @@ INSTRUCTION_FORMAT22c_FIELD_PHRASE WS? COMMA_EMIT WS? REGISTER_EMIT WS? COMMA_EMIT WS? - FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN - WS - FIELD_TYPE_DESCRIPTOR_EMITCHILD; + FULLY_QUALIFIED_FIELD_EMITCHILDREN; INSTRUCTION_FORMAT22c_TYPE_PHRASE : INSTRUCTION_FORMAT22c_TYPE_EMIT @@ -333,7 +324,7 @@ INSTRUCTION_FORMAT22c_TYPE_PHRASE WS? COMMA_EMIT WS? REGISTER_EMIT WS? COMMA_EMIT WS? - FIELD_TYPE_DESCRIPTOR_EMITCHILD; + NONVOID_TYPE_DESCRIPTOR_EMITCHILD; INSTRUCTION_FORMAT22s_PHRASE : INSTRUCTION_FORMAT22s_EMIT @@ -407,16 +398,14 @@ INSTRUCTION_FORMAT35c_METHOD_PHRASE WS REGISTER_LIST_EMITCHILDREN WS? COMMA_EMIT WS? - FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN - METHOD_PROTOTYPE_EMITCHILDREN; + FULLY_QUALIFIED_METHOD_EMITCHILDREN; INSTRUCTION_FORMAT3rc_METHOD_PHRASE : INSTRUCTION_FORMAT3rc_METHOD_EMIT WS REGISTER_RANGE_EMITCHILDREN WS? COMMA_EMIT WS? - FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN - METHOD_PROTOTYPE_EMITCHILDREN; + FULLY_QUALIFIED_METHOD_EMITCHILDREN; INSTRUCTION_FORMAT51l_PHRASE : INSTRUCTION_FORMAT51l_EMIT @@ -459,7 +448,7 @@ REGISTERS_PHRASE CATCH_PHRASE : CATCH_DIRECTIVE_EMIT WS - FIELD_TYPE_DESCRIPTOR_EMITCHILD + NONVOID_TYPE_DESCRIPTOR_EMITCHILD WS? '{' WS? (LABEL_EMIT | OFFSET_EMIT) WS '..' WS @@ -485,8 +474,8 @@ LOCAL_PHRASE REGISTER_EMIT WS? COMMA_EMIT WS? SIMPLE_NAME_EMIT - WS - FIELD_TYPE_DESCRIPTOR_EMITCHILD + COLON_EMIT + NONVOID_TYPE_DESCRIPTOR_EMITCHILD WS? ( COMMA_EMIT WS? STRING_LITERAL_EMIT)?; @@ -673,29 +662,35 @@ fragment REGISTER_RANGE_EMITCHILDREN fragment METHOD_PROTOTYPE_EMITCHILDREN : OPEN_PAREN_EMIT - (FIELD_TYPE_DESCRIPTOR_EMITCHILD+)? + (NONVOID_TYPE_DESCRIPTOR_EMITCHILD+)? CLOSE_PAREN_EMIT TYPE_DESCRIPTOR_EMITCHILD; -fragment FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN -@init {int startPos;} - : {startPos = getCharIndex();} (SIMPLE_NAME '/')* token=SIMPLE_NAME {((CommonToken)$token).setStartIndex(startPos); emit($token, CLASS_NAME);} - '/' - MEMBER_NAME_EMIT; +fragment FULLY_QUALIFIED_FIELD_EMITCHILDREN + : REFERENCE_TYPE_DESCRIPTOR_EMITCHILD + ARROW_EMIT + MEMBER_NAME_EMIT + COLON_EMIT + NONVOID_TYPE_DESCRIPTOR_EMITCHILD; +fragment FULLY_QUALIFIED_METHOD_EMITCHILDREN + : REFERENCE_TYPE_DESCRIPTOR_EMITCHILD + ARROW_EMIT + MEMBER_NAME_EMIT + METHOD_PROTOTYPE_EMITCHILDREN; + fragment TYPE_DESCRIPTOR_EMITCHILD : PRIMITIVE_TYPE_EMIT | VOID_TYPE_EMIT | CLASS_DESCRIPTOR_EMIT - | ARRAY_DESCRIPTOR_EMIT; + | ARRAY_DESCRIPTOR_EMIT; - -fragment FIELD_TYPE_DESCRIPTOR_EMITCHILD +fragment NONVOID_TYPE_DESCRIPTOR_EMITCHILD : PRIMITIVE_TYPE_EMIT | CLASS_DESCRIPTOR_EMIT | ARRAY_DESCRIPTOR_EMIT; -fragment CLASS_OR_ARRAY_TYPE_DESCRIPTOR_EMITCHILD +fragment REFERENCE_TYPE_DESCRIPTOR_EMITCHILD : CLASS_DESCRIPTOR_EMIT | ARRAY_DESCRIPTOR_EMIT; @@ -724,10 +719,7 @@ fragment CLASS_DESCRIPTOR_EMIT : CLASS_DESCRIPTOR {emit($CLASS_DESCRIPTOR, CLASS_DESCRIPTOR);}; fragment CLASS_DESCRIPTOR - : 'L' CLASS_NAME ';'; - -fragment CLASS_NAME - : (SIMPLE_NAME '/')* SIMPLE_NAME; + : 'L' (SIMPLE_NAME '/')* SIMPLE_NAME ';'; fragment ARRAY_DESCRIPTOR_EMIT @@ -848,9 +840,9 @@ fragment LITERAL_EMITCHILD | DOUBLE_LITERAL_EMIT | CHAR_LITERAL_EMIT | BOOL_LITERAL_EMIT - | TYPE_DESCRIPTOR_EMITCHILD | ARRAY_LITERAL_EMITCHILDREN - | SUBANNOTATION_EMITCHILDREN; + | SUBANNOTATION_EMITCHILDREN + | TYPE_FIELD_METHOD_LITERAL_EMITCHILDREN; fragment SUBANNOTATION_EMITCHILDREN : SUBANNOTATION_START_EMIT @@ -894,7 +886,17 @@ fragment ANNOTATION_ELEMENT_EMITCHILDREN EQUAL_EMIT WS? LITERAL_EMITCHILD; - + +fragment TYPE_FIELD_METHOD_LITERAL_EMITCHILDREN + : REFERENCE_TYPE_DESCRIPTOR_EMITCHILD + ( ARROW_EMIT + MEMBER_NAME_EMIT + ( METHOD_PROTOTYPE_EMITCHILDREN + | COLON_EMIT NONVOID_TYPE_DESCRIPTOR_EMITCHILD))? + //TODO: allow void and primitive type here? + | PRIMITIVE_TYPE_EMIT + | VOID_TYPE_EMIT; + fragment ARRAY_LITERAL_EMITCHILDREN : ARRAY_START_EMIT WS? @@ -1414,3 +1416,13 @@ fragment COMMA_EMIT : COMMA {emit($COMMA, COMMA, Token.HIDDEN_CHANNEL);}; fragment COMMA : ','; + +fragment COLON_EMIT + : COLON {emit($COLON, COLON, Token.HIDDEN_CHANNEL);}; +fragment COLON + : ':'; + +fragment ARROW_EMIT + : ARROW {emit($ARROW, ARROW);}; +fragment ARROW + : '->'; diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliParser.g b/src/main/antlr3/org/JesusFreke/smali/smaliParser.g index 02461114..c77a012f 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliParser.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliParser.g @@ -56,6 +56,8 @@ tokens { I_ANNOTATION; I_ANNOTATION_ELEMENT; I_SUBANNOTATION; + I_ENCODED_FIELD; + I_ENCODED_METHOD; I_ENCODED_ARRAY; I_ARRAY_ELEMENT_SIZE; I_ARRAY_ELEMENTS; @@ -113,9 +115,6 @@ tokens { I_STATEMENT_SPARSE_SWITCH; I_REGISTER_RANGE; I_REGISTER_LIST; - - CLASS_NAME; - MEMBER_NAME; } @header { @@ -200,11 +199,11 @@ access_list : ACCESS_SPEC+ -> ^(I_ACCESS_LIST[$start,"I_ACCESS_LIST"] ACCESS_SPEC+); -field : FIELD_DIRECTIVE access_list MEMBER_NAME field_type_descriptor literal? +field : FIELD_DIRECTIVE access_list MEMBER_NAME nonvoid_type_descriptor literal? ( (annotation+ END_FIELD_DIRECTIVE)=> annotation+ END_FIELD_DIRECTIVE | END_FIELD_DIRECTIVE? ) - -> ^(I_FIELD[$start, "I_FIELD"] MEMBER_NAME access_list ^(I_FIELD_TYPE field_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*)); method scope {int currentAddress;} @@ -215,15 +214,17 @@ method -> ^(I_METHOD[$start, "I_METHOD"] MEMBER_NAME method_prototype access_list statements_and_directives); method_prototype - : OPEN_PAREN field_type_descriptor* CLOSE_PAREN type_descriptor - -> ^(I_METHOD_PROTOTYPE[$start, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) field_type_descriptor*); + : OPEN_PAREN nonvoid_type_descriptor* CLOSE_PAREN type_descriptor + -> ^(I_METHOD_PROTOTYPE[$start, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) nonvoid_type_descriptor*); fully_qualified_method - : CLASS_NAME MEMBER_NAME method_prototype; + : reference_type_descriptor ARROW MEMBER_NAME method_prototype + -> reference_type_descriptor MEMBER_NAME method_prototype; fully_qualified_field - : CLASS_NAME MEMBER_NAME field_type_descriptor; + : reference_type_descriptor ARROW MEMBER_NAME nonvoid_type_descriptor + -> reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor; statements_and_directives scope {boolean hasRegistersDirective;} @@ -239,13 +240,7 @@ statements_and_directives | ordered_debug_directive | annotation )* - { - if (!$statements_and_directives::hasRegistersDirective) { - //TODO: throw correct exception type here - throw new RuntimeException("This method has no register directive"); - } - } - -> registers_directive + -> ^(I_REGISTERS registers_directive?) ^(I_LABELS label*) ^(I_STATEMENTS instruction*) ^(I_CATCHES catch_directive*) @@ -255,11 +250,11 @@ statements_and_directives registers_directive : REGISTERS_DIRECTIVE integral_literal - -> ^(I_REGISTERS[$start, "I_REGISTERS"] integral_literal); + -> integral_literal; catch_directive - : CATCH_DIRECTIVE field_type_descriptor from=offset_or_label to=offset_or_label using=offset_or_label - -> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] field_type_descriptor $from $to $using) + : CATCH_DIRECTIVE nonvoid_type_descriptor from=offset_or_label to=offset_or_label using=offset_or_label + -> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using) ; @@ -290,8 +285,8 @@ line_directive -> ^(I_LINE integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]); local_directive - : LOCAL_DIRECTIVE REGISTER SIMPLE_NAME field_type_descriptor STRING_LITERAL? - -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER SIMPLE_NAME field_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + : LOCAL_DIRECTIVE REGISTER SIMPLE_NAME nonvoid_type_descriptor STRING_LITERAL? + -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER SIMPLE_NAME nonvoid_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]); end_local_directive : END_LOCAL_DIRECTIVE REGISTER @@ -344,8 +339,8 @@ instruction returns [int size] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL {$size = Format21c.Format.getByteCount();} -> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL) | //e.g. const-class v2 org/JesusFreke/HelloWorld2/HelloWorld2 - INSTRUCTION_FORMAT21c_TYPE REGISTER class_or_array_type_descriptor {$size = Format21c.Format.getByteCount();} - -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER class_or_array_type_descriptor) + INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor {$size = Format21c.Format.getByteCount();} + -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor) | //e.g. const/high16 v1, 1234 INSTRUCTION_FORMAT21h REGISTER integral_literal {$size = Format21h.Format.getByteCount();} -> ^(I_STATEMENT_FORMAT21h[$start, "I_STATEMENT_FORMAT21h"] INSTRUCTION_FORMAT21h REGISTER integral_literal) @@ -362,8 +357,8 @@ instruction returns [int size] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field {$size = Format22c.Format.getByteCount();} -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field) | //e.g. instance-of v0, v1, Ljava/lang/String; - INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER field_type_descriptor {$size = Format22c.Format.getByteCount();} - -> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER field_type_descriptor) + INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor {$size = Format22c.Format.getByteCount();} + -> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor) | //e.g. add-int/lit16 v0, v1, 12345 INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal {$size = Format22s.Format.getByteCount();} -> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal) @@ -496,13 +491,13 @@ register_range : REGISTER REGISTER? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] REGISTER REGISTER?); -field_type_descriptor +nonvoid_type_descriptor : PRIMITIVE_TYPE | CLASS_DESCRIPTOR | ARRAY_DESCRIPTOR ; -class_or_array_type_descriptor +reference_type_descriptor : CLASS_DESCRIPTOR | ARRAY_DESCRIPTOR; @@ -541,16 +536,16 @@ fixed_literal returns[int size] literal : INTEGER_LITERAL | LONG_LITERAL - | SHORT_LITERAL_EMIT - | BYTE_LITERAL_EMIT + | SHORT_LITERAL + | BYTE_LITERAL | FLOAT_LITERAL | DOUBLE_LITERAL | CHAR_LITERAL | STRING_LITERAL | BOOL_LITERAL - | type_descriptor | array_literal - | subannotation; + | subannotation + | type_field_method; array_literal : ARRAY_START literal* ARRAY_END @@ -568,3 +563,14 @@ annotation_element subannotation : SUBANNOTATION_START CLASS_DESCRIPTOR annotation_element* SUBANNOTATION_END -> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*); + +type_field_method + : reference_type_descriptor + ( ARROW MEMBER_NAME + ( nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor) + | method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor MEMBER_NAME method_prototype) + ) + | -> reference_type_descriptor + ) + | PRIMITIVE_TYPE + | VOID_TYPE; diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g b/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g index 24b8f568..a901973c 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g @@ -197,11 +197,11 @@ methods returns[List methodAnnotationS })*); field returns[ClassDataItem.EncodedField encodedField, EncodedValue encodedValue, AnnotationDirectoryItem.FieldAnnotation fieldAnnotationSet] - :^(I_FIELD MEMBER_NAME access_list ^(I_FIELD_TYPE field_type_descriptor) field_initial_value annotations?) + :^(I_FIELD MEMBER_NAME access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) field_initial_value annotations?) { TypeIdItem classType = classDefItem.getClassType(); StringIdItem memberName = new StringIdItem(dexFile, $MEMBER_NAME.text); - TypeIdItem fieldType = $field_type_descriptor.type; + TypeIdItem fieldType = $nonvoid_type_descriptor.type; FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, memberName, fieldType); $encodedField = new ClassDataItem.EncodedField(dexFile, fieldIdItem, $access_list.value); @@ -239,7 +239,9 @@ literal returns[EncodedValue encodedValue] | bool_literal { $encodedValue = new EncodedValue(dexFile, new BoolEncodedValueSubField($bool_literal.value)); } | type_descriptor { $encodedValue = new EncodedValue(dexFile, new EncodedIndexedItemReference(dexFile, $type_descriptor.type)); } | array_literal { $encodedValue = new EncodedValue(dexFile, new ArrayEncodedValueSubField(dexFile, $array_literal.values)); } - | subannotation { $encodedValue = new EncodedValue(dexFile, $subannotation.value); }; + | subannotation { $encodedValue = new EncodedValue(dexFile, $subannotation.value); } + | field_literal { $encodedValue = new EncodedValue(dexFile, $field_literal.value); } + | method_literal { $encodedValue = new EncodedValue(dexFile, $method_literal.value); }; //everything but string @@ -355,46 +357,59 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod, parameters ordered_debug_directives annotations - ) + ) { MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem; - int registers = $registers_directive.registers; int access = $access_list.value; boolean isStatic = (access & AccessFlags.STATIC) != 0; + + int registers = $registers_directive.registers; ArrayList instructions = $statements.instructions; - - - int minRegisters = methodIdItem.getParameterRegisterCount((access & AccessFlags.STATIC) != 0); - - if (registers < minRegisters) { - //TODO: throw the correct exception type - throw new RuntimeException( "This method requires at least " + - Integer.toString(minRegisters) + - " registers, for the method parameters"); - } Pair, List> temp = $method::tryList.encodeTries(dexFile); List tries = temp.first; List handlers = temp.second; + + DebugInfoItem debugInfoItem = $method::debugInfo.encodeDebugInfo(dexFile); - int methodParameterCount = methodIdItem.getParameterCount(); - if ($method::debugInfo.getParameterNameCount() > methodParameterCount) { - //TODO: throw the correct exception type - throw new RuntimeException( "Too many parameter names specified. This method only has " + - Integer.toString(methodParameterCount) + - " parameters."); - } + CodeItem codeItem; - DebugInfoItem debugInfoItem = $method::debugInfo.encodeDebugInfo(dexFile); + if (registers == 0 && + instructions.size() == 0 && + $method::labels.size()== 0 && + (tries == null || tries.size() == 0) && + (handlers == null || handlers.size() == 0) && + debugInfoItem == null) { + + codeItem = null; + + } else { + int minRegisters = methodIdItem.getParameterRegisterCount((access & AccessFlags.STATIC) != 0); - CodeItem codeItem = new CodeItem(dexFile, + if (registers < minRegisters) { + //TODO: throw the correct exception type + throw new RuntimeException( "This method requires at least " + + Integer.toString(minRegisters) + + " registers, for the method parameters"); + } + + int methodParameterCount = methodIdItem.getParameterCount(); + if ($method::debugInfo.getParameterNameCount() > methodParameterCount) { + //TODO: throw the correct exception type + throw new RuntimeException( "Too many parameter names specified. This method only has " + + Integer.toString(methodParameterCount) + + " parameters."); + } + + codeItem = new CodeItem(dexFile, registers, methodIdItem.getParameterRegisterCount(isStatic), instructions, debugInfoItem, tries, handlers); + } $encodedMethod = new ClassDataItem.EncodedMethod(dexFile, methodIdItem, access, codeItem); @@ -433,33 +448,34 @@ field_type_list returns[ArrayList types] $types = new ArrayList(); } : ( - field_type_descriptor + nonvoid_type_descriptor { - $types.add($field_type_descriptor.type); + $types.add($nonvoid_type_descriptor.type); } )*; fully_qualified_method returns[MethodIdItem methodIdItem] - : CLASS_NAME MEMBER_NAME method_prototype + : reference_type_descriptor MEMBER_NAME method_prototype { - TypeIdItem classType = new TypeIdItem(dexFile, "L" + $CLASS_NAME.text + ";"); + TypeIdItem classType = $reference_type_descriptor.type; StringIdItem methodName = new StringIdItem(dexFile, $MEMBER_NAME.text); ProtoIdItem prototype = $method_prototype.protoIdItem; $methodIdItem = new MethodIdItem(dexFile, classType, methodName, prototype); }; fully_qualified_field returns[FieldIdItem fieldIdItem] - : CLASS_NAME MEMBER_NAME field_type_descriptor + : reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor { - TypeIdItem classType = new TypeIdItem(dexFile, "L" + $CLASS_NAME.text + ";"); + TypeIdItem classType = $reference_type_descriptor.type; StringIdItem fieldName = new StringIdItem(dexFile, $MEMBER_NAME.text); - TypeIdItem fieldType = $field_type_descriptor.type; + TypeIdItem fieldType = $nonvoid_type_descriptor.type; $fieldIdItem = new FieldIdItem(dexFile, classType, fieldName, fieldType); }; registers_directive returns[int registers] - : ^(I_REGISTERS short_integral_literal) {$registers = $short_integral_literal.value;}; + : {$registers = 0;} + ^(I_REGISTERS (short_integral_literal {$registers = $short_integral_literal.value;} )? ); labels : ^(I_LABELS label_def*); @@ -480,9 +496,9 @@ label_def catches : ^(I_CATCHES catch_directive*); catch_directive - : ^(I_CATCH address field_type_descriptor from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address] using=offset_or_label_absolute[$address.address]) + : ^(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]) { - TypeIdItem type = $field_type_descriptor.type; + TypeIdItem type = $nonvoid_type_descriptor.type; int startAddress = $from.address; int endAddress = $to.address; int handlerAddress = $using.address; @@ -547,14 +563,14 @@ line }; local - : ^(I_LOCAL REGISTER SIMPLE_NAME field_type_descriptor string_literal? address) + : ^(I_LOCAL REGISTER SIMPLE_NAME nonvoid_type_descriptor string_literal? address) { int registerNumber = parseRegister_short($REGISTER.text); if ($string_literal.value != null) { - $method::debugInfo.addLocalExtended($address.address, registerNumber, $SIMPLE_NAME.text, $field_type_descriptor.type.getTypeDescriptor(), $string_literal.value); + $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, $field_type_descriptor.type.getTypeDescriptor()); + $method::debugInfo.addLocal($address.address, registerNumber, $SIMPLE_NAME.text, $nonvoid_type_descriptor.type.getTypeDescriptor()); } }; @@ -725,12 +741,12 @@ instruction returns[Instruction instruction] $instruction = Format21c.Format.make(dexFile, opcode.value, regA, stringIdItem); } | //e.g. const-class v2 org/JesusFreke/HelloWorld2/HelloWorld2 - ^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER class_or_array_type_descriptor) + ^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor) { Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text); short regA = parseRegister_byte($REGISTER.text); - TypeIdItem typeIdItem = $class_or_array_type_descriptor.type; + TypeIdItem typeIdItem = $reference_type_descriptor.type; $instruction = Format21c.Format.make(dexFile, opcode.value, regA, typeIdItem); } @@ -793,13 +809,13 @@ instruction returns[Instruction instruction] $instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, fieldIdItem); } | //e.g. instance-of v0, v1, Ljava/lang/String; - ^(I_STATEMENT_FORMAT22c_TYPE INSTRUCTION_FORMAT22c_TYPE registerA=REGISTER registerB=REGISTER field_type_descriptor) + ^(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); byte regB = parseRegister_nibble($registerB.text); - TypeIdItem typeIdItem = $field_type_descriptor.type; + TypeIdItem typeIdItem = $nonvoid_type_descriptor.type; $instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, typeIdItem); } @@ -1002,7 +1018,7 @@ register_range returns[int startRegister, int endRegister] } ; -field_type_descriptor returns [TypeIdItem type] +nonvoid_type_descriptor returns [TypeIdItem type] : (PRIMITIVE_TYPE | CLASS_DESCRIPTOR | ARRAY_DESCRIPTOR) @@ -1010,7 +1026,7 @@ field_type_descriptor returns [TypeIdItem type] $type = new TypeIdItem(dexFile, $start.getText()); }; -class_or_array_type_descriptor returns [TypeIdItem type] +reference_type_descriptor returns [TypeIdItem type] : (CLASS_DESCRIPTOR | ARRAY_DESCRIPTOR) { @@ -1025,7 +1041,7 @@ class_type_descriptor returns [TypeIdItem type] type_descriptor returns [TypeIdItem type] : VOID_TYPE {$type = new TypeIdItem(dexFile, "V");} - | field_type_descriptor {$type = $field_type_descriptor.type;} + | nonvoid_type_descriptor {$type = $nonvoid_type_descriptor.type;} ; short_integral_literal returns[short value] @@ -1072,7 +1088,7 @@ double_literal returns[double value] : DOUBLE_LITERAL { $value = Double.parseDouble($DOUBLE_LITERAL.text); }; char_literal returns[char value] - : CHAR_LITERAL { $value = $CHAR_LITERAL.text.charAt(0); }; + : CHAR_LITERAL { $value = $CHAR_LITERAL.text.charAt(1); }; string_literal returns[String value] : STRING_LITERAL @@ -1120,4 +1136,15 @@ subannotation returns[AnnotationEncodedValueSubField value] { $value = new AnnotationEncodedValueSubField(dexFile, $class_type_descriptor.type, elements); }; - + +field_literal returns[EncodedIndexedItemReference value] + : ^(I_ENCODED_FIELD fully_qualified_field) + { + $value = new EncodedIndexedItemReference(dexFile, $fully_qualified_field.fieldIdItem); + }; + +method_literal returns[EncodedIndexedItemReference value] + : ^(I_ENCODED_METHOD fully_qualified_method) + { + $value = new EncodedIndexedItemReference(dexFile, $fully_qualified_method.methodIdItem); + };