- made the .registers directive optional. it defaults to .registers 0 if not present

- added logic to avoid creating an empty code_item (i.e. for abstract methods)
- changed the field and parameter syntax so that there is a colon instead of a whitespace between the field/local name and the following type
- changed the member name syntax, so that the initial class is specified with the preceeding 'L' and folling ';', and changed the seperator between the class name and the member name to '->' instead of just another '/'
- added the ability to specify members and fields as constants for static fields or annotations (note: dalvik doesn't seem to like embedded field references)
- fixed the short and byte literals in the parser (they were mistakenly using the _EMIT token)
- fixed an issue with char literals where the value was always a single quote
- renamed the CLASS_OR_ARRAY_TYPE_DESCRIPTOR token and related rules to REFERENCE_TYPE_DESCRIPTOR
- renamed the FIELD_TYPE_DESCRIPTOR token and related rules to NONVOID_TYPE_DESCRIPTOR

git-svn-id: https://smali.googlecode.com/svn/trunk@64 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-06-03 04:58:54 +00:00
parent 5cf0028e73
commit 4250768620
3 changed files with 184 additions and 139 deletions

View File

@ -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
: '->';

View File

@ -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;

View File

@ -197,11 +197,11 @@ methods returns[List<AnnotationDirectoryItem.MethodAnnotation> 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<Instruction> 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<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> temp = $method::tryList.encodeTries(dexFile);
List<CodeItem.TryItem> tries = temp.first;
List<CodeItem.EncodedCatchHandler> 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<TypeIdItem> types]
$types = new ArrayList<TypeIdItem>();
}
: (
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<FieldIdItem> value]
: ^(I_ENCODED_FIELD fully_qualified_field)
{
$value = new EncodedIndexedItemReference<FieldIdItem>(dexFile, $fully_qualified_field.fieldIdItem);
};
method_literal returns[EncodedIndexedItemReference<MethodIdItem> value]
: ^(I_ENCODED_METHOD fully_qualified_method)
{
$value = new EncodedIndexedItemReference<MethodIdItem>(dexFile, $fully_qualified_method.methodIdItem);
};