mirror of
https://github.com/revanced/smali.git
synced 2025-05-12 04:14:27 +02:00
- Added support for parameter name debug info
- Changed the grammar so that the .registers directive can appear anywhere in the .method, instead of requiring it to be the first thing git-svn-id: https://smali.googlecode.com/svn/trunk@45 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
aa7e507bac
commit
66a23e6ecc
@ -227,11 +227,6 @@ METHOD_PHRASE
|
||||
END_METHOD_PHRASE
|
||||
: END_METHOD_DIRECTIVE_EMIT;
|
||||
|
||||
REGISTERS_PHRASE
|
||||
: REGISTERS_DIRECTIVE_EMIT
|
||||
WS
|
||||
INTEGRAL_LITERAL_EMITCHILD;
|
||||
|
||||
INSTRUCTION_FORMAT10t_PHRASE
|
||||
: INSTRUCTION_FORMAT10t_EMIT
|
||||
WS
|
||||
@ -453,6 +448,11 @@ SPARSE_SWITCH_PHRASE
|
||||
WSC
|
||||
END_SPARSE_SWITCH_DIRECTIVE_EMIT;
|
||||
|
||||
REGISTERS_PHRASE
|
||||
: REGISTERS_DIRECTIVE_EMIT
|
||||
WS
|
||||
INTEGRAL_LITERAL_EMITCHILD;
|
||||
|
||||
CATCH_PHRASE
|
||||
: CATCH_DIRECTIVE_EMIT
|
||||
WS
|
||||
@ -468,6 +468,10 @@ LINE_PHRASE
|
||||
: LINE_DIRECTIVE_EMIT
|
||||
WS
|
||||
INTEGRAL_LITERAL_EMITCHILD;
|
||||
|
||||
PARAMETER_PHRASE
|
||||
: PARAMETER_DIRECTIVE_EMIT
|
||||
(WS STRING_LITERAL_EMIT?)?;
|
||||
|
||||
|
||||
//TODO: add support for both relative and absolute offsets?
|
||||
@ -516,11 +520,6 @@ fragment END_METHOD_DIRECTIVE_EMIT
|
||||
fragment END_METHOD_DIRECTIVE
|
||||
: '.end method';
|
||||
|
||||
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
|
||||
@ -551,6 +550,11 @@ fragment END_SPARSE_SWITCH_DIRECTIVE_EMIT
|
||||
fragment END_SPARSE_SWITCH_DIRECTIVE
|
||||
: '.end sparse-switch';
|
||||
|
||||
fragment REGISTERS_DIRECTIVE_EMIT
|
||||
: REGISTERS_DIRECTIVE {emit($REGISTERS_DIRECTIVE, REGISTERS_DIRECTIVE);};
|
||||
fragment REGISTERS_DIRECTIVE
|
||||
: '.registers';
|
||||
|
||||
fragment CATCH_DIRECTIVE_EMIT
|
||||
: CATCH_DIRECTIVE {emit($CATCH_DIRECTIVE, CATCH_DIRECTIVE);};
|
||||
fragment CATCH_DIRECTIVE
|
||||
@ -561,6 +565,11 @@ fragment LINE_DIRECTIVE_EMIT
|
||||
fragment LINE_DIRECTIVE
|
||||
: '.line';
|
||||
|
||||
fragment PARAMETER_DIRECTIVE_EMIT
|
||||
: PARAMETER_DIRECTIVE {emit($PARAMETER_DIRECTIVE, PARAMETER_DIRECTIVE);};
|
||||
fragment PARAMETER_DIRECTIVE
|
||||
: '.parameter';
|
||||
|
||||
fragment REGISTER_EMIT
|
||||
: REGISTER {emit($REGISTER, REGISTER);};
|
||||
fragment REGISTER
|
||||
|
@ -67,6 +67,9 @@ tokens {
|
||||
I_CATCH_ADDRESS;
|
||||
I_LINE;
|
||||
I_LINES;
|
||||
I_PARAMETER;
|
||||
I_PARAMETERS;
|
||||
I_PARAMETER_NOT_SPECIFIED;
|
||||
I_STATEMENTS;
|
||||
I_STATEMENT_FORMAT10t;
|
||||
I_STATEMENT_FORMAT10x;
|
||||
@ -187,48 +190,68 @@ access_list
|
||||
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)?);
|
||||
|
||||
method : METHOD_DIRECTIVE access_list MEMBER_NAME method_prototype
|
||||
registers_directive
|
||||
statements
|
||||
method
|
||||
scope {int currentAddress;}
|
||||
: {$method::currentAddress = 0;}
|
||||
METHOD_DIRECTIVE access_list MEMBER_NAME method_prototype
|
||||
statements_and_directives
|
||||
END_METHOD_DIRECTIVE
|
||||
-> ^(I_METHOD[$start, "I_METHOD"] MEMBER_NAME method_prototype access_list registers_directive statements);
|
||||
-> ^(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*);
|
||||
|
||||
|
||||
|
||||
registers_directive
|
||||
: REGISTERS_DIRECTIVE integral_literal
|
||||
-> ^(I_REGISTERS[$start, "I_REGISTERS"] integral_literal);
|
||||
|
||||
|
||||
fully_qualified_method
|
||||
: CLASS_NAME MEMBER_NAME method_prototype;
|
||||
|
||||
fully_qualified_field
|
||||
: CLASS_NAME MEMBER_NAME field_type_descriptor;
|
||||
|
||||
statements
|
||||
scope {int currentAddress;}
|
||||
: {$statements::currentAddress = 0;}
|
||||
( instruction {$statements::currentAddress += $instruction.size/2;}
|
||||
statements_and_directives
|
||||
: {
|
||||
$method::currentAddress = 0;
|
||||
boolean hasRegistersDirective = false;
|
||||
}
|
||||
( instruction {$method::currentAddress += $instruction.size/2;}
|
||||
| {!hasRegistersDirective}?=> registers_directive {hasRegistersDirective = true;}
|
||||
| catch_directive
|
||||
| line_directive
|
||||
| parameter_directive
|
||||
| label)*
|
||||
-> ^(I_LABELS label*) ^(I_STATEMENTS instruction*) ^(I_CATCHES catch_directive*) ^(I_LINES line_directive*);
|
||||
{
|
||||
if (!hasRegistersDirective) {
|
||||
//TODO: throw correct exception type here
|
||||
throw new RuntimeException("This method has no register directive");
|
||||
}
|
||||
}
|
||||
-> registers_directive
|
||||
^(I_LABELS label*)
|
||||
^(I_STATEMENTS instruction*)
|
||||
^(I_CATCHES catch_directive*)
|
||||
^(I_LINES line_directive*)
|
||||
^(I_PARAMETERS parameter_directive*);
|
||||
|
||||
registers_directive
|
||||
: REGISTERS_DIRECTIVE integral_literal
|
||||
-> ^(I_REGISTERS[$start, "I_REGISTERS"] 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_CATCH_ADDRESS[$start, Integer.toString($statements::currentAddress)] field_type_descriptor $from $to $using)
|
||||
-> ^(I_CATCH[$start, "I_CATCH"] I_CATCH_ADDRESS[$start, Integer.toString($method::currentAddress)] field_type_descriptor $from $to $using)
|
||||
;
|
||||
|
||||
line_directive
|
||||
: LINE_DIRECTIVE integral_literal -> ^(I_LINE integral_literal {new CommonTree(new CommonToken(INTEGER_LITERAL,Integer.toString($statements::currentAddress)))});
|
||||
: LINE_DIRECTIVE integral_literal -> ^(I_LINE integral_literal {new CommonTree(new CommonToken(INTEGER_LITERAL,Integer.toString($method::currentAddress)))});
|
||||
|
||||
parameter_directive
|
||||
: PARAMETER_DIRECTIVE ( STRING_LITERAL -> ^(I_PARAMETER STRING_LITERAL?)
|
||||
| -> ^(I_PARAMETER I_PARAMETER_NOT_SPECIFIED)
|
||||
);
|
||||
|
||||
label
|
||||
: LABEL -> ^(I_LABEL LABEL {new CommonTree(new CommonToken(INTEGER_LITERAL,Integer.toString($statements::currentAddress)))});
|
||||
: LABEL -> ^(I_LABEL LABEL {new CommonTree(new CommonToken(INTEGER_LITERAL,Integer.toString($method::currentAddress)))});
|
||||
|
||||
instruction returns [int size]
|
||||
@init {boolean needsNop = false;}
|
||||
@ -317,7 +340,7 @@ instruction returns [int size]
|
||||
|
|
||||
ARRAY_DATA_DIRECTIVE
|
||||
{
|
||||
if (($statements::currentAddress \% 2) != 0) {
|
||||
if (($method::currentAddress \% 2) != 0) {
|
||||
needsNop = true;
|
||||
$size = 2;
|
||||
} else {
|
||||
@ -337,7 +360,7 @@ instruction returns [int size]
|
||||
PACKED_SWITCH_DIRECTIVE
|
||||
{
|
||||
int targetCount = 0;
|
||||
if (($statements::currentAddress \% 2) != 0) {
|
||||
if (($method::currentAddress \% 2) != 0) {
|
||||
needsNop = true;
|
||||
$size = 2;
|
||||
} else {
|
||||
@ -371,7 +394,7 @@ instruction returns [int size]
|
||||
SPARSE_SWITCH_DIRECTIVE
|
||||
{
|
||||
int targetCount = 0;
|
||||
if (($statements::currentAddress \% 2) != 0) {
|
||||
if (($method::currentAddress \% 2) != 0) {
|
||||
needsNop = true;
|
||||
$size = 2;
|
||||
} else {
|
||||
|
@ -294,17 +294,44 @@ method returns[ClassDataItem.EncodedMethod encodedMethod]
|
||||
$method::currentAddress = 0;
|
||||
$method::debugInfo = new DebugInfoBuilder();
|
||||
}
|
||||
^(I_METHOD method_name_and_prototype access_list registers_directive labels statements catches lines)
|
||||
^( I_METHOD
|
||||
method_name_and_prototype
|
||||
access_list
|
||||
registers_directive
|
||||
labels
|
||||
statements
|
||||
catches
|
||||
lines
|
||||
parameters)
|
||||
{
|
||||
MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem;
|
||||
int registers = $registers_directive.registers;
|
||||
int access = $access_list.value;
|
||||
boolean isStatic = (access & AccessFlags.STATIC) != 0;
|
||||
ArrayList<Instruction> instructions = $statements.instructions;
|
||||
|
||||
|
||||
int minRegisters = methodIdItem.getParameterWordCount((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;
|
||||
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
DebugInfoItem debugInfoItem = $method::debugInfo.encodeDebugInfo(dexFile);
|
||||
|
||||
@ -351,10 +378,6 @@ field_type_list returns[ArrayList<TypeIdItem> types]
|
||||
}
|
||||
)*;
|
||||
|
||||
registers_directive returns[int registers]
|
||||
: ^(I_REGISTERS short_integral_literal) {$registers = $short_integral_literal.value;};
|
||||
|
||||
|
||||
|
||||
fully_qualified_method returns[MethodIdItem methodIdItem]
|
||||
: CLASS_NAME MEMBER_NAME method_prototype
|
||||
@ -373,6 +396,9 @@ fully_qualified_field returns[FieldIdItem fieldIdItem]
|
||||
TypeIdItem fieldType = $field_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;};
|
||||
|
||||
catches : ^(I_CATCHES catch_directive*);
|
||||
|
||||
@ -395,6 +421,15 @@ line
|
||||
{
|
||||
$method::debugInfo.addLine($integer_literal.value, $integral_literal.value);
|
||||
};
|
||||
|
||||
parameters
|
||||
: ^(I_PARAMETERS parameter*);
|
||||
|
||||
parameter
|
||||
: ^(I_PARAMETER (
|
||||
string_literal {$method::debugInfo.addParameterName($string_literal.value);}
|
||||
| I_PARAMETER_NOT_SPECIFIED {$method::debugInfo.addParameterName(null);}
|
||||
));
|
||||
|
||||
labels
|
||||
: ^(I_LABELS label_def*);
|
||||
|
@ -90,6 +90,14 @@ public class MethodIdItem extends IndexedItem<MethodIdItem> {
|
||||
return prototype.getReference().getParameterWordCount() + (isStatic?0:1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of parameters, not including the "this" parameter, if any
|
||||
* @return The number of parameters, not including the "this" parameter, if any
|
||||
*/
|
||||
public int getParameterCount() {
|
||||
return prototype.getReference().getParameterCount();
|
||||
}
|
||||
|
||||
public int compareTo(MethodIdItem o) {
|
||||
int result = classType.compareTo(o.classType);
|
||||
if (result != 0) {
|
||||
|
@ -84,6 +84,16 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int getParameterCount() {
|
||||
TypeListItem typeList = parameters.getReference();
|
||||
if (typeList == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return typeList.getCount();
|
||||
}
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
@ -79,6 +79,10 @@ public class TypeListItem extends OffsettedItem<TypeListItem> implements Compara
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return typeList.size();
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
return 4;
|
||||
}
|
||||
|
@ -78,6 +78,16 @@ public class DebugInfoBuilder
|
||||
events.add(new LineEvent(address, line));
|
||||
}
|
||||
|
||||
public void addParameterName(String parameterName) {
|
||||
hasData = true;
|
||||
|
||||
parameterNames.add(parameterName);
|
||||
}
|
||||
|
||||
public int getParameterNameCount() {
|
||||
return parameterNames.size();
|
||||
}
|
||||
|
||||
public DebugInfoItem encodeDebugInfo(DexFile dexFile) {
|
||||
if (!hasData) {
|
||||
return null;
|
||||
@ -98,7 +108,11 @@ public class DebugInfoBuilder
|
||||
debugInstructions.add(new EndSequence());
|
||||
|
||||
for (String parameterName: parameterNames) {
|
||||
parameterNameReferences.add(new StringIdItem(dexFile, parameterName));
|
||||
if (parameterName == null) {
|
||||
parameterNameReferences.add(null);
|
||||
} else {
|
||||
parameterNameReferences.add(new StringIdItem(dexFile, parameterName));
|
||||
}
|
||||
}
|
||||
|
||||
return new DebugInfoItem(dexFile, lineStart, parameterNameReferences, debugInstructions);
|
||||
|
@ -20,7 +20,18 @@
|
||||
|
||||
|
||||
.method public onAccountsUpdated([Ljava/lang/String;)V
|
||||
.parameter "currentAccounts"
|
||||
|
||||
return-void
|
||||
.registers 2
|
||||
.end method
|
||||
|
||||
.method public static parameterNameTest(IIII)V
|
||||
.registers 4
|
||||
.parameter "test1"
|
||||
.parameter "test2"
|
||||
.parameter
|
||||
.parameter "test4"
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
Loading…
x
Reference in New Issue
Block a user