Added support for annotations

git-svn-id: https://smali.googlecode.com/svn/trunk@48 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-05-28 00:44:20 +00:00
parent 0d16dfbfcc
commit 6cbfb8b875
11 changed files with 501 additions and 101 deletions

View File

@ -215,7 +215,10 @@ FIELD_PHRASE
WS
FIELD_TYPE_DESCRIPTOR_EMITCHILD
WS?
('=' WS? LITERAL_EMITCHILD)?;
(EQUAL_EMIT WS? LITERAL_EMITCHILD)?;
END_FIELD_PHRASE
: END_FIELD_DIRECTIVE_EMIT;
METHOD_PHRASE
: METHOD_DIRECTIVE_EMIT
@ -239,7 +242,7 @@ INSTRUCTION_FORMAT11n_PHRASE
: INSTRUCTION_FORMAT11n_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
INTEGRAL_LITERAL_EMITCHILD;
INSTRUCTION_FORMAT11x_PHRASE
@ -251,7 +254,7 @@ INSTRUCTION_FORMAT12x_PHRASE
: INSTRUCTION_FORMAT12x_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT;
INSTRUCTION_FORMAT20t_PHRASE
@ -263,7 +266,7 @@ INSTRUCTION_FORMAT21c_FIELD_PHRASE
: INSTRUCTION_FORMAT21c_FIELD_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN
WS
FIELD_TYPE_DESCRIPTOR_EMITCHILD;
@ -272,53 +275,53 @@ INSTRUCTION_FORMAT21c_STRING_PHRASE
: INSTRUCTION_FORMAT21c_STRING_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
STRING_LITERAL_EMIT;
INSTRUCTION_FORMAT21c_TYPE_PHRASE
: INSTRUCTION_FORMAT21c_TYPE_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
CLASS_OR_ARRAY_TYPE_DESCRIPTOR_EMITCHILD;
INSTRUCTION_FORMAT21h_PHRASE
: INSTRUCTION_FORMAT21h_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
INTEGRAL_LITERAL_EMITCHILD;
INSTRUCTION_FORMAT21s_PHRASE
: INSTRUCTION_FORMAT21s_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
INTEGRAL_LITERAL_EMITCHILD;
INSTRUCTION_FORMAT21t_PHRASE
: INSTRUCTION_FORMAT21t_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
(LABEL_EMIT | OFFSET_EMIT);
INSTRUCTION_FORMAT22b_PHRASE
: INSTRUCTION_FORMAT22b_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
INTEGRAL_LITERAL_EMITCHILD;
INSTRUCTION_FORMAT22c_FIELD_PHRASE
: INSTRUCTION_FORMAT22c_FIELD_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN
WS
FIELD_TYPE_DESCRIPTOR_EMITCHILD;
@ -327,43 +330,43 @@ INSTRUCTION_FORMAT22c_TYPE_PHRASE
: INSTRUCTION_FORMAT22c_TYPE_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
FIELD_TYPE_DESCRIPTOR_EMITCHILD;
INSTRUCTION_FORMAT22s_PHRASE
: INSTRUCTION_FORMAT22s_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
INTEGRAL_LITERAL_EMITCHILD;
INSTRUCTION_FORMAT22t_PHRASE
: INSTRUCTION_FORMAT22t_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
(LABEL_EMIT | OFFSET_EMIT);
INSTRUCTION_FORMAT22x_PHRASE
: INSTRUCTION_FORMAT22x_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT;
INSTRUCTION_FORMAT23x_PHRASE
: INSTRUCTION_FORMAT23x_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT;
INSTRUCTION_FORMAT30t_PHRASE
@ -375,35 +378,35 @@ INSTRUCTION_FORMAT31c_PHRASE
: INSTRUCTION_FORMAT31c_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
STRING_LITERAL_EMIT;
INSTRUCTION_FORMAT31i_PHRASE
: INSTRUCTION_FORMAT31i_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
(FIXED_32BIT_LITERAL_EMITCHILD);
INSTRUCTION_FORMAT31t_PHRASE
: INSTRUCTION_FORMAT31t_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
(LABEL_EMIT | OFFSET_EMIT);
INSTRUCTION_FORMAT32x_PHRASE
: INSTRUCTION_FORMAT32x_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
REGISTER_EMIT;
INSTRUCTION_FORMAT35c_METHOD_PHRASE
: INSTRUCTION_FORMAT35c_METHOD_EMIT
WS
REGISTER_LIST_EMITCHILDREN
WS? ',' WS?
WS? COMMA_EMIT WS?
FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN
METHOD_PROTOTYPE_EMITCHILDREN;
@ -411,7 +414,7 @@ INSTRUCTION_FORMAT3rc_METHOD_PHRASE
: INSTRUCTION_FORMAT3rc_METHOD_EMIT
WS
REGISTER_RANGE_EMITCHILDREN
WS? ',' WS?
WS? COMMA_EMIT WS?
FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN
METHOD_PROTOTYPE_EMITCHILDREN;
@ -419,7 +422,7 @@ INSTRUCTION_FORMAT51l_PHRASE
: INSTRUCTION_FORMAT51l_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
(FIXED_LITERAL_EMITCHILD);
ARRAY_DATA_PHRASE
@ -473,16 +476,19 @@ PARAMETER_PHRASE
: PARAMETER_DIRECTIVE_EMIT
(WS STRING_LITERAL_EMIT?)?;
END_PARAMETER_PHRASE
: END_PARAMETER_DIRECTIVE_EMIT;
LOCAL_PHRASE
: LOCAL_DIRECTIVE_EMIT
WS
REGISTER_EMIT
WS? ',' WS?
WS? COMMA_EMIT WS?
SIMPLE_NAME_EMIT
WS
FIELD_TYPE_DESCRIPTOR_EMITCHILD
WS?
( ',' WS? STRING_LITERAL_EMIT)?;
( COMMA_EMIT WS? STRING_LITERAL_EMIT)?;
END_LOCAL_PHRASE
: END_LOCAL_DIRECTIVE_EMIT
@ -500,6 +506,16 @@ PROLOGUE_PHRASE
EPILOGUE_PHRASE
: EPILOGUE_DIRECTIVE_EMIT;
ANNOTATION_PHRASE
: ANNOTATION_START_EMIT
WS
ANNOTATION_VISIBILITY_EMIT
WS
CLASS_DESCRIPTOR_EMIT
WS
(ANNOTATION_ELEMENT_EMITCHILDREN WS)*
ANNOTATION_END_EMIT;
//TODO: add support for both relative and absolute offsets?
fragment OFFSET_EMIT
: OFFSET {emit($OFFSET, OFFSET);};
@ -536,6 +552,11 @@ fragment FIELD_DIRECTIVE_EMIT
fragment FIELD_DIRECTIVE
: '.field';
fragment END_FIELD_DIRECTIVE_EMIT
: END_FIELD_DIRECTIVE {emit($END_FIELD_DIRECTIVE, END_FIELD_DIRECTIVE);};
fragment END_FIELD_DIRECTIVE
: '.end field';
fragment METHOD_DIRECTIVE_EMIT
: METHOD_DIRECTIVE {emit($METHOD_DIRECTIVE, METHOD_DIRECTIVE);};
fragment METHOD_DIRECTIVE
@ -596,6 +617,11 @@ fragment PARAMETER_DIRECTIVE_EMIT
fragment PARAMETER_DIRECTIVE
: '.parameter';
fragment END_PARAMETER_DIRECTIVE_EMIT
: END_PARAMETER_DIRECTIVE {emit($END_PARAMETER_DIRECTIVE, END_PARAMETER_DIRECTIVE);};
fragment END_PARAMETER_DIRECTIVE
: '.end parameter';
fragment LOCAL_DIRECTIVE_EMIT
: LOCAL_DIRECTIVE {emit($LOCAL_DIRECTIVE, LOCAL_DIRECTIVE);};
fragment LOCAL_DIRECTIVE
@ -629,7 +655,7 @@ fragment REGISTER
fragment REGISTER_LIST_EMITCHILDREN
: OPEN_BRACKET_EMIT
( WS?
REGISTER_EMIT (WS? ',' WS? REGISTER_EMIT)*
REGISTER_EMIT (WS? COMMA_EMIT WS? REGISTER_EMIT)*
WS?
| WS?)
CLOSE_BRACKET_EMIT;
@ -821,7 +847,69 @@ fragment LITERAL_EMITCHILD
| FLOAT_LITERAL_EMIT
| DOUBLE_LITERAL_EMIT
| CHAR_LITERAL_EMIT
| BOOL_LITERAL_EMIT;
| BOOL_LITERAL_EMIT
| TYPE_DESCRIPTOR_EMITCHILD
| ARRAY_LITERAL_EMITCHILDREN
| SUBANNOTATION_EMITCHILDREN;
fragment SUBANNOTATION_EMITCHILDREN
: SUBANNOTATION_START_EMIT
WS
CLASS_DESCRIPTOR_EMIT
WS
(ANNOTATION_ELEMENT_EMITCHILDREN WS)*
SUBANNOTATION_END_EMIT
;
fragment SUBANNOTATION_START_EMIT
: SUBANNOTATION_START {emit($SUBANNOTATION_START, SUBANNOTATION_START);};
fragment SUBANNOTATION_START
: '.subannotation';
fragment SUBANNOTATION_END_EMIT
: SUBANNOTATION_END {emit($SUBANNOTATION_END, SUBANNOTATION_END);};
fragment SUBANNOTATION_END
: '.end subannotation';
fragment ANNOTATION_START_EMIT
: ANNOTATION_START {emit($ANNOTATION_START, ANNOTATION_START);};
fragment ANNOTATION_START
: '.annotation';
fragment ANNOTATION_END_EMIT
: ANNOTATION_END {emit($ANNOTATION_END, ANNOTATION_END);};
fragment ANNOTATION_END
: '.end annotation';
fragment ANNOTATION_VISIBILITY_EMIT
: ANNOTATION_VISIBILITY {emit($ANNOTATION_VISIBILITY, ANNOTATION_VISIBILITY);};
fragment ANNOTATION_VISIBILITY
: 'build'
| 'runtime'
| 'system';
fragment ANNOTATION_ELEMENT_EMITCHILDREN
: MEMBER_NAME_EMIT
WS?
EQUAL_EMIT
WS?
LITERAL_EMITCHILD;
fragment ARRAY_LITERAL_EMITCHILDREN
: ARRAY_START_EMIT
WS?
(LITERAL_EMITCHILD WS? (COMMA_EMIT WS? LITERAL_EMITCHILD WS?)*)?
ARRAY_END_EMIT;
fragment ARRAY_START_EMIT
: ARRAY_START {emit($ARRAY_START, ARRAY_START);};
fragment ARRAY_START
: '{';
fragment ARRAY_END_EMIT
: ARRAY_END {emit($ARRAY_END, ARRAY_END);};
fragment ARRAY_END
: '}';
fragment STRING_LITERAL_EMIT
@ -1316,3 +1404,13 @@ LINE_COMMENT
: (';' ~('\n'|'\r')* ('\r\n' | '\r' | '\n')
| ';' ~('\n'|'\r')*)
{$channel = HIDDEN;};
fragment EQUAL_EMIT
: EQUAL {emit($EQUAL, EQUAL, Token.HIDDEN_CHANNEL);};
fragment EQUAL
: '=';
fragment COMMA_EMIT
: COMMA {emit($COMMA, COMMA, Token.HIDDEN_CHANNEL);};
fragment COMMA
: ',';

View File

@ -52,6 +52,11 @@ tokens {
I_REGISTERS;
I_LABELS;
I_LABEL;
I_ANNOTATIONS;
I_ANNOTATION;
I_ANNOTATION_ELEMENT;
I_SUBANNOTATION;
I_ENCODED_ARRAY;
I_ARRAY_ELEMENT_SIZE;
I_ARRAY_ELEMENTS;
I_PACKED_SWITCH_START_KEY;
@ -146,25 +151,28 @@ import org.JesusFreke.dexlib.code.Format.*;
smali_file
:
scope
{
boolean hasClassSpec = false;
boolean hasSuperSpec = false;
boolean hasSourceSpec = false;
boolean hasClassSpec;
boolean hasSuperSpec;
boolean hasSourceSpec;
}
( {!hasClassSpec}?=> class_spec {hasClassSpec = true;}
| {!hasSuperSpec}?=> super_spec {hasSuperSpec = true;}
@init { $smali_file::hasClassSpec = $smali_file::hasSuperSpec = $smali_file::hasSourceSpec = false; }
:
( {!$smali_file::hasClassSpec}?=> class_spec {$smali_file::hasClassSpec = true;}
| {!$smali_file::hasSuperSpec}?=> super_spec {$smali_file::hasSuperSpec = true;}
| implements_spec
| {!hasSourceSpec}?=> source_spec {hasSourceSpec = true;}
| {!$smali_file::hasSourceSpec}?=> source_spec {$smali_file::hasSourceSpec = true;}
| method
| field)*
| field
| annotation)*
{
if (!hasClassSpec) {
if (!$smali_file::hasClassSpec) {
//TODO: throw correct exception type
throw new RuntimeException("The file must contain a .class directive");
}
if (!hasSuperSpec) {
if (!$smali_file::hasSuperSpec) {
//TODO: throw correct exception type
throw new RuntimeException("The file must contain a .super directive");
}
@ -174,7 +182,7 @@ smali_file
super_spec
implements_spec*
source_spec
^(I_METHODS method*) ^(I_FIELDS field*));
^(I_METHODS method*) ^(I_FIELDS field*) ^(I_ANNOTATIONS annotation*));
class_spec
: CLASS_DIRECTIVE access_list CLASS_DESCRIPTOR -> CLASS_DESCRIPTOR access_list;
@ -192,8 +200,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?
-> ^(I_FIELD[$start, "I_FIELD"] MEMBER_NAME access_list ^(I_FIELD_TYPE field_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)?);
field : FIELD_DIRECTIVE access_list MEMBER_NAME field_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*));
method
scope {int currentAddress;}
@ -215,19 +226,21 @@ fully_qualified_field
: CLASS_NAME MEMBER_NAME field_type_descriptor;
statements_and_directives
scope {boolean hasRegistersDirective;}
: {
$method::currentAddress = 0;
boolean hasRegistersDirective = false;
$statements_and_directives::hasRegistersDirective = false;
}
( instruction {$method::currentAddress += $instruction.size/2;}
| {!hasRegistersDirective}?=> registers_directive {hasRegistersDirective = true;}
| {!$statements_and_directives::hasRegistersDirective}?=> registers_directive {$statements_and_directives::hasRegistersDirective = true;}
| label
| catch_directive
| parameter_directive
| ordered_debug_directive
| annotation
)*
{
if (!hasRegistersDirective) {
if (!$statements_and_directives::hasRegistersDirective) {
//TODO: throw correct exception type here
throw new RuntimeException("This method has no register directive");
}
@ -237,7 +250,8 @@ statements_and_directives
^(I_STATEMENTS instruction*)
^(I_CATCHES catch_directive*)
^(I_PARAMETERS parameter_directive*)
^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*);
^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*)
^(I_ANNOTATIONS annotation*);
registers_directive
: REGISTERS_DIRECTIVE integral_literal
@ -250,9 +264,17 @@ catch_directive
parameter_directive
: PARAMETER_DIRECTIVE ( STRING_LITERAL -> ^(I_PARAMETER STRING_LITERAL?)
| -> ^(I_PARAMETER I_PARAMETER_NOT_SPECIFIED)
);
: PARAMETER_DIRECTIVE
( STRING_LITERAL
( (annotation+ END_PARAMETER_DIRECTIVE)=> annotation+ END_PARAMETER_DIRECTIVE
| END_PARAMETER_DIRECTIVE?
)
-> ^(I_PARAMETER STRING_LITERAL ^(I_ANNOTATIONS annotation*))
| ( (annotation+ END_PARAMETER_DIRECTIVE)=> annotation+ END_PARAMETER_DIRECTIVE
| END_PARAMETER_DIRECTIVE?
)
-> ^(I_PARAMETER I_PARAMETER_NOT_SPECIFIED ^(I_ANNOTATIONS annotation*))
);
ordered_debug_directive
: line_directive
@ -295,7 +317,7 @@ label
: LABEL -> ^(I_LABEL LABEL I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
instruction returns [int size]
@init {boolean needsNop = false;}
@init {boolean needsNop = false; int targetCount = 0;}
: //e.g. goto endloop:
//e.g. goto +3
INSTRUCTION_FORMAT10t (LABEL | OFFSET) {$size = Format10t.Format.getByteCount();}
@ -400,7 +422,7 @@ instruction returns [int size]
|
PACKED_SWITCH_DIRECTIVE
{
int targetCount = 0;
targetCount = 0;
if (($method::currentAddress \% 2) != 0) {
needsNop = true;
$size = 2;
@ -434,7 +456,7 @@ instruction returns [int size]
|
SPARSE_SWITCH_DIRECTIVE
{
int targetCount = 0;
targetCount = 0;
if (($method::currentAddress \% 2) != 0) {
needsNop = true;
$size = 2;
@ -516,10 +538,33 @@ fixed_literal returns[int size]
| CHAR_LITERAL {$size = 2;}
| BOOL_LITERAL {$size = 1;};
literal : INTEGER_LITERAL
literal
: INTEGER_LITERAL
| LONG_LITERAL
| SHORT_LITERAL_EMIT
| BYTE_LITERAL_EMIT
| FLOAT_LITERAL
| DOUBLE_LITERAL
| CHAR_LITERAL
| STRING_LITERAL
| BOOL_LITERAL;
| BOOL_LITERAL
| type_descriptor
| array_literal
| subannotation;
array_literal
: ARRAY_START literal* ARRAY_END
-> ^(I_ENCODED_ARRAY[$start, "I_ENCODED_ARRAY"] literal*);
annotation
: ANNOTATION_START ANNOTATION_VISIBILITY CLASS_DESCRIPTOR
annotation_element* ANNOTATION_END
-> ^(I_ANNOTATION[$start, "I_ANNOTATION"] ANNOTATION_VISIBILITY ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*));
annotation_element
: MEMBER_NAME literal
-> ^(I_ANNOTATION_ELEMENT[$start, "I_ANNOTATION_ELEMENT"] MEMBER_NAME literal);
subannotation
: SUBANNOTATION_START CLASS_DESCRIPTOR annotation_element* SUBANNOTATION_END
-> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*);

View File

@ -87,13 +87,33 @@ import org.JesusFreke.dexlib.code.Format.*;
smali_file returns[ClassDefItem classDefItem]
: ^(I_CLASS_DEF header methods fields);
smali_file
: ^(I_CLASS_DEF header methods fields annotations)
{
AnnotationDirectoryItem annotationDirectoryItem = null;
if ( $methods.methodAnnotationSets != null ||
$methods.parameterAnnotationSets != null ||
$fields.fieldAnnotationSets != null ||
$annotations.annotationSetItem != null) {
annotationDirectoryItem = new AnnotationDirectoryItem(
dexFile,
$annotations.annotationSetItem,
$fields.fieldAnnotationSets,
$methods.methodAnnotationSets,
$methods.parameterAnnotationSets);
}
classDefItem.setAnnotations(annotationDirectoryItem);
};
header : class_spec super_spec implements_list source_spec
header returns[TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementsList, StringIdItem sourceSpec]
: 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, $implements_list.implementsList, $source_spec.source, 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]
@ -143,20 +163,41 @@ access_list returns [int value]
}
)+);
fields : ^(I_FIELDS
fields returns[List<AnnotationDirectoryItem.FieldAnnotation> fieldAnnotationSets]
: ^(I_FIELDS
(field
{
classDefItem.addField($field.encodedField, $field.encodedValue);
if ($field.fieldAnnotationSet != null) {
if ($fieldAnnotationSets == null) {
$fieldAnnotationSets = new ArrayList<AnnotationDirectoryItem.FieldAnnotation>();
}
fieldAnnotationSets.add($field.fieldAnnotationSet);
}
})*);
methods : ^(I_METHODS
methods returns[List<AnnotationDirectoryItem.MethodAnnotation> methodAnnotationSets,
List<AnnotationDirectoryItem.ParameterAnnotation> parameterAnnotationSets]
: ^(I_METHODS
(method
{
classDataItem.addMethod($method.encodedMethod);
if ($method.methodAnnotationSet != null) {
if ($methodAnnotationSets == null) {
$methodAnnotationSets = new ArrayList<AnnotationDirectoryItem.MethodAnnotation>();
}
$methodAnnotationSets.add($method.methodAnnotationSet);
}
if ($method.parameterAnnotationSets != null) {
if ($parameterAnnotationSets == null) {
$parameterAnnotationSets = new ArrayList<AnnotationDirectoryItem.ParameterAnnotation>();
}
$parameterAnnotationSets.add($method.parameterAnnotationSets);
}
})*);
field returns[ClassDataItem.EncodedField encodedField, EncodedValue encodedValue]
:^(I_FIELD MEMBER_NAME access_list ^(I_FIELD_TYPE field_type_descriptor) field_initial_value)
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?)
{
TypeIdItem classType = classDefItem.getClassType();
StringIdItem memberName = new StringIdItem(dexFile, $MEMBER_NAME.text);
@ -175,23 +216,31 @@ field returns[ClassDataItem.EncodedField encodedField, EncodedValue encodedValue
} else {
$encodedValue = null;
}
if ($annotations.annotationSetItem != null) {
$fieldAnnotationSet = new AnnotationDirectoryItem.FieldAnnotation(dexFile, fieldIdItem, $annotations.annotationSetItem);
}
};
//TODO: what about type or array encoded values?
field_initial_value returns[EncodedValue encodedValue]
: ^(I_FIELD_INITIAL_VALUE
( integer_literal { $encodedValue = new EncodedValue(dexFile, new IntEncodedValueSubField($integer_literal.value)); }
| long_literal { $encodedValue = new EncodedValue(dexFile, new LongEncodedValueSubField($long_literal.value)); }
| short_literal { $encodedValue = new EncodedValue(dexFile, new ShortEncodedValueSubField($short_literal.value)); }
| byte_literal { $encodedValue = new EncodedValue(dexFile, new ByteEncodedValueSubField($byte_literal.value)); }
| float_literal { $encodedValue = new EncodedValue(dexFile, new FloatEncodedValueSubField($float_literal.value)); }
| double_literal { $encodedValue = new EncodedValue(dexFile, new DoubleEncodedValueSubField($double_literal.value)); }
| char_literal { $encodedValue = new EncodedValue(dexFile, new CharEncodedValueSubField($char_literal.value)); }
| string_literal { $encodedValue = new EncodedValue(dexFile, new EncodedIndexedItemReference(dexFile, new StringIdItem(dexFile, $string_literal.value))); }
| bool_literal { $encodedValue = new EncodedValue(dexFile, new BoolEncodedValueSubField($bool_literal.value)); }
))
| ;
: ^(I_FIELD_INITIAL_VALUE literal) {$encodedValue = $literal.encodedValue;}
| ;
literal returns[EncodedValue encodedValue]
: integer_literal { $encodedValue = new EncodedValue(dexFile, new IntEncodedValueSubField($integer_literal.value)); }
| long_literal { $encodedValue = new EncodedValue(dexFile, new LongEncodedValueSubField($long_literal.value)); }
| short_literal { $encodedValue = new EncodedValue(dexFile, new ShortEncodedValueSubField($short_literal.value)); }
| byte_literal { $encodedValue = new EncodedValue(dexFile, new ByteEncodedValueSubField($byte_literal.value)); }
| float_literal { $encodedValue = new EncodedValue(dexFile, new FloatEncodedValueSubField($float_literal.value)); }
| double_literal { $encodedValue = new EncodedValue(dexFile, new DoubleEncodedValueSubField($double_literal.value)); }
| char_literal { $encodedValue = new EncodedValue(dexFile, new CharEncodedValueSubField($char_literal.value)); }
| string_literal { $encodedValue = new EncodedValue(dexFile, new EncodedIndexedItemReference(dexFile, new StringIdItem(dexFile, $string_literal.value))); }
| 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); };
//everything but string
fixed_size_literal returns[byte[\] value]
@ -280,7 +329,9 @@ sparse_switch_targets[int baseOffset, int targetCount] returns[int[\] targets]
})*
);
method returns[ClassDataItem.EncodedMethod encodedMethod]
method returns[ ClassDataItem.EncodedMethod encodedMethod,
AnnotationDirectoryItem.MethodAnnotation methodAnnotationSet,
AnnotationDirectoryItem.ParameterAnnotation parameterAnnotationSets]
scope
{
HashMap<String, Integer> labels;
@ -303,6 +354,7 @@ method returns[ClassDataItem.EncodedMethod encodedMethod]
catches
parameters
ordered_debug_directives
annotations
)
{
MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem;
@ -345,6 +397,14 @@ method returns[ClassDataItem.EncodedMethod encodedMethod]
handlers);
$encodedMethod = new ClassDataItem.EncodedMethod(dexFile, methodIdItem, access, codeItem);
if ($annotations.annotationSetItem != null) {
$methodAnnotationSet = new AnnotationDirectoryItem.MethodAnnotation(dexFile, methodIdItem, $annotations.annotationSetItem);
}
if ($parameters.parameterAnnotations != null) {
$parameterAnnotationSets = new AnnotationDirectoryItem.ParameterAnnotation(dexFile, methodIdItem, $parameters.parameterAnnotations);
}
};
method_prototype returns[ProtoIdItem protoIdItem]
@ -436,14 +496,39 @@ address returns[int address]
$address = Integer.parseInt($I_ADDRESS.text);
};
parameters
: ^(I_PARAMETERS parameter*);
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(new AnnotationSetItem(dexFile, -1));
}
annotationSetItems.add($parameter.parameterAnnotationSet);
}
parameterCount++;
})*
)
{
if (annotationSetItems.size() > 0) {
while (annotationSetItems.size() < parameterCount) {
annotationSetItems.add(new AnnotationSetItem(dexFile, -1));
}
$parameterAnnotations = new AnnotationSetRefList(dexFile, annotationSetItems);
}
};
parameter
: ^(I_PARAMETER (
string_literal {$method::debugInfo.addParameterName($string_literal.value);}
parameter returns[AnnotationSetItem parameterAnnotationSet]
: ^(I_PARAMETER ( string_literal {$method::debugInfo.addParameterName($string_literal.value);}
| I_PARAMETER_NOT_SPECIFIED {$method::debugInfo.addParameterName(null);}
));
)
annotations {$parameterAnnotationSet = $annotations.annotationSetItem;}
);
ordered_debug_directives
: ^(I_ORDERED_DEBUG_DIRECTIVES ( line
@ -998,3 +1083,41 @@ string_literal returns[String value]
bool_literal returns[boolean value]
: BOOL_LITERAL { $value = Boolean.parseBoolean($BOOL_LITERAL.text); };
array_literal returns[ArrayList<EncodedValue> values]
: {$values = new ArrayList<EncodedValue>();}
^(I_ENCODED_ARRAY (literal {$values.add($literal.encodedValue);})*);
annotations returns[AnnotationSetItem annotationSetItem]
: {ArrayList<AnnotationItem> annotationList = new ArrayList<AnnotationItem>();}
^(I_ANNOTATIONS (annotation {annotationList.add($annotation.annotationItem);} )*)
{
if (annotationList.size() > 0) {
$annotationSetItem = new AnnotationSetItem(dexFile, annotationList);
}
};
annotation returns[AnnotationItem annotationItem]
: ^(I_ANNOTATION ANNOTATION_VISIBILITY subannotation)
{
AnnotationVisibility visibility = AnnotationVisibility.fromName($ANNOTATION_VISIBILITY.text);
$annotationItem = new AnnotationItem(dexFile, visibility, $subannotation.value);
};
annotation_element returns[AnnotationElement element]
: ^(I_ANNOTATION_ELEMENT MEMBER_NAME literal)
{
$element = new AnnotationElement(dexFile, new StringIdItem(dexFile, $MEMBER_NAME.text), $literal.encodedValue);
};
subannotation returns[AnnotationEncodedValueSubField value]
: {ArrayList<AnnotationElement> elements = new ArrayList<AnnotationElement>();}
^( I_SUBANNOTATION
class_type_descriptor
(annotation_element {elements.add($annotation_element.element);} )* )
{
$value = new AnnotationEncodedValueSubField(dexFile, $class_type_descriptor.type, elements);
};

View File

@ -31,6 +31,8 @@ package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.ItemType;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
//TODO: fix field names in dex-format.html and submit
public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryItem> {
@ -74,6 +76,39 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
};
}
public AnnotationDirectoryItem(final DexFile dexFile,
AnnotationSetItem classAnnotations,
List<FieldAnnotation> fieldAnnotations,
List<MethodAnnotation> methodAnnotations,
List<ParameterAnnotation> parameterAnnotations) {
this(dexFile, -1);
this.classAnnotations.setReference(classAnnotations);
if (fieldAnnotations != null) {
this.fieldAnnotationList.addAll(fieldAnnotations);
}
if (methodAnnotations != null) {
this.methodAnnotationList.addAll(methodAnnotations);
}
if (parameterAnnotations != null) {
this.parameterAnnotationList.addAll(parameterAnnotations);
}
}
@Override
public int place(int index, int offset)
{
Collections.sort(fieldAnnotationList);
Collections.sort(methodAnnotationList);
Collections.sort(parameterAnnotationList);
return super.place(index, offset);
}
protected int getAlignment() {
return 4;
}
@ -86,48 +121,91 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
}
public class FieldAnnotation extends CompositeField<FieldAnnotation> {
public static class FieldAnnotation extends CompositeField<FieldAnnotation>
implements Comparable<FieldAnnotation> {
private final Field[] fields;
private final IndexedItemReference<FieldIdItem> field;
private final OffsettedItemReference<AnnotationSetItem> annotationSet;
public FieldAnnotation(DexFile dexFile) {
fields = new Field[] {
new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection, new IntegerField()),
new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection, new IntegerField()),
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
};
}
public FieldAnnotation(DexFile dexFile, FieldIdItem field, AnnotationSetItem annotationSet) {
this(dexFile);
this.field.setReference(field);
this.annotationSet.setReference(annotationSet);
}
protected Field[] getFields() {
return fields;
}
public int compareTo(FieldAnnotation o) {
return ((Integer)field.getReference().getIndex()).compareTo(o.field.getReference().getIndex());
}
}
public class MethodAnnotation extends CompositeField<MethodAnnotation> {
public static class MethodAnnotation extends CompositeField<MethodAnnotation>
implements Comparable<MethodAnnotation> {
private final Field[] fields;
private final IndexedItemReference<MethodIdItem> method;
private final OffsettedItemReference<AnnotationSetItem> annotationSet;
public MethodAnnotation(DexFile dexFile) {
fields = new Field[] {
new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()),
new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()),
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
};
}
public MethodAnnotation(DexFile dexFile, MethodIdItem method, AnnotationSetItem annotationSet) {
this(dexFile);
this.method.setReference(method);
this.annotationSet.setReference(annotationSet);
}
protected Field[] getFields() {
return fields;
}
public int compareTo(MethodAnnotation o) {
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
}
}
public class ParameterAnnotation extends CompositeField<ParameterAnnotation> {
public static class ParameterAnnotation extends CompositeField<ParameterAnnotation>
implements Comparable<ParameterAnnotation> {
private final Field[] fields;
private final IndexedItemReference<MethodIdItem> method;
private final OffsettedItemReference<AnnotationSetRefList> parameterAnnotations;
public ParameterAnnotation(DexFile dexFile) {
fields = new Field[] {
new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()),
new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()),
parameterAnnotations = new OffsettedItemReference<AnnotationSetRefList>(
dexFile.AnnotationSetRefListsSection, new IntegerField())
};
}
public ParameterAnnotation(DexFile dexFile, MethodIdItem method, AnnotationSetRefList parameterAnnotations) {
this(dexFile);
this.method.setReference(method);
this.parameterAnnotations.setReference(parameterAnnotations);
}
protected Field[] getFields() {
return fields;
}
public int compareTo(ParameterAnnotation o) {
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
}
}
}

View File

@ -46,6 +46,16 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
};
}
public AnnotationItem(DexFile dexFile, AnnotationVisibility visibility,
AnnotationEncodedValueSubField annotation) {
super(-1);
fields = new Field[] {
this.visibility = new ByteField(visibility.value),
this.annotation = annotation
};
}
protected int getAlignment() {
return 1;
}

View File

@ -31,6 +31,7 @@ package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.ItemType;
import java.util.ArrayList;
import java.util.List;
public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
private final Field[] fields;
@ -48,12 +49,22 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
annotationCount = new ListSizeField(annotationReferences, new IntegerField()),
annotations = new FieldListField<OffsettedItemReference<AnnotationItem>>(annotationReferences) {
protected OffsettedItemReference<AnnotationItem> make() {
return new OffsettedItemReference<AnnotationItem>(dexFile.AnnotationsSection, new IntegerField());
return new OffsettedItemReference<AnnotationItem>(dexFile.AnnotationsSection,
new IntegerField());
}
}
};
}
public AnnotationSetItem(final DexFile dexFile, List<AnnotationItem> annotations) {
this(dexFile, -1);
for (AnnotationItem annotationItem: annotations) {
this.annotationReferences.add(new OffsettedItemReference<AnnotationItem>(dexFile,
annotationItem, new IntegerField()));
}
}
protected int getAlignment() {
return 4;
}

View File

@ -31,6 +31,7 @@ package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.ItemType;
import java.util.ArrayList;
import java.util.List;
public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
private final Field[] fields;
@ -54,6 +55,14 @@ public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
};
}
public AnnotationSetRefList(final DexFile dexFile, List<AnnotationSetItem> annotationSets) {
this(dexFile, -1);
for (AnnotationSetItem annotation: annotationSets) {
this.annotationSetReferences.add(new OffsettedItemReference<AnnotationSetItem>(dexFile, annotation, new IntegerField()));
}
}
protected int getAlignment() {
return 4;
}

View File

@ -69,7 +69,13 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
};
}
public ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementsList, StringIdItem source, ClassDataItem classDataItem) {
public ClassDefItem(DexFile dexFile,
TypeIdItem classType,
int accessFlags,
TypeIdItem superType,
TypeListItem implementsList,
StringIdItem source,
ClassDataItem classDataItem) {
super(-1);
this.dexFile = dexFile;
@ -132,10 +138,9 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
return 0;
}
public void addMethod(ClassDataItem.EncodedMethod encodedMethod) {
}
public void addField(ClassDataItem.EncodedField encodedField, EncodedValue initialValue) {
//fields are added in ClassDefItem instead of ClassDataItem because we need to grab
//the static initializers for StaticFieldInitialValues
if (!encodedField.isStatic() && initialValue != null) {
throw new RuntimeException("Initial values are only allowed for static fields.");
}
@ -163,6 +168,10 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
}
}
public void setAnnotations(AnnotationDirectoryItem annotations) {
this.classAnnotations.setReference(annotations);
}
public static int placeClassDefItems(IndexedSection<ClassDefItem> section, int offset) {
ClassDefPlacer cdp = new ClassDefPlacer(section);
return cdp.placeSection(offset);

View File

@ -42,6 +42,13 @@ public class AnnotationElement extends CompositeField<AnnotationElement> {
encodedValue = new EncodedValue(dexFile)
};
}
public AnnotationElement(final DexFile dexFile, StringIdItem elementName, EncodedValue encodedValue) {
fields = new Field[] {
this.elementName = new IndexedItemReference<StringIdItem>(dexFile, elementName, new Leb128Field()),
this.encodedValue = encodedValue
};
}
protected Field[] getFields() {
return fields;

View File

@ -31,6 +31,7 @@ package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.*;
import java.util.ArrayList;
import java.util.List;
public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEncodedValueSubField>
implements EncodedValueSubField<AnnotationEncodedValueSubField> {
@ -54,6 +55,13 @@ public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEnc
};
}
public AnnotationEncodedValueSubField(final DexFile dexFile, TypeIdItem annotationType,
List<AnnotationElement> annotationElements) {
this(dexFile);
this.annotationType.setReference(annotationType);
this.annotationElementList.addAll(annotationElements);
}
protected Field[] getFields() {
return fields;
}

View File

@ -72,7 +72,9 @@ public class DebugInfoBuilder
}
public void addParameterName(String parameterName) {
hasData = true;
if (parameterName != null) {
hasData = true;
}
parameterNames.add(parameterName);
}