mirror of
https://github.com/revanced/smali.git
synced 2025-05-16 14:17:04 +02:00
- changed the syntax for the .catch directive, to get rid of "from", "to" and "using" (too visual basicy)
- added support for the .local directive, which allows you to define a local variable in the debug info (no way to undefine it until ".end local" is implemented) git-svn-id: https://smali.googlecode.com/svn/trunk@46 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
66a23e6ecc
commit
f175e1d987
@ -457,11 +457,11 @@ CATCH_PHRASE
|
||||
: CATCH_DIRECTIVE_EMIT
|
||||
WS
|
||||
FIELD_TYPE_DESCRIPTOR_EMITCHILD
|
||||
WS 'from' WS
|
||||
WS? '{' WS?
|
||||
(LABEL_EMIT | OFFSET_EMIT)
|
||||
WS 'to' WS
|
||||
WS '..' WS
|
||||
(LABEL_EMIT | OFFSET_EMIT)
|
||||
WS 'using' WS
|
||||
WS? '}' WS?
|
||||
(LABEL_EMIT | OFFSET_EMIT);
|
||||
|
||||
LINE_PHRASE
|
||||
@ -472,6 +472,15 @@ LINE_PHRASE
|
||||
PARAMETER_PHRASE
|
||||
: PARAMETER_DIRECTIVE_EMIT
|
||||
(WS STRING_LITERAL_EMIT?)?;
|
||||
|
||||
LOCAL_PHRASE
|
||||
: LOCAL_DIRECTIVE_EMIT
|
||||
WS
|
||||
REGISTER_EMIT
|
||||
WS? ',' WS?
|
||||
SIMPLE_NAME_EMIT
|
||||
WS
|
||||
FIELD_TYPE_DESCRIPTOR_EMITCHILD;
|
||||
|
||||
|
||||
//TODO: add support for both relative and absolute offsets?
|
||||
@ -569,11 +578,16 @@ fragment PARAMETER_DIRECTIVE_EMIT
|
||||
: PARAMETER_DIRECTIVE {emit($PARAMETER_DIRECTIVE, PARAMETER_DIRECTIVE);};
|
||||
fragment PARAMETER_DIRECTIVE
|
||||
: '.parameter';
|
||||
|
||||
fragment LOCAL_DIRECTIVE_EMIT
|
||||
: LOCAL_DIRECTIVE {emit($LOCAL_DIRECTIVE, LOCAL_DIRECTIVE);};
|
||||
fragment LOCAL_DIRECTIVE
|
||||
: '.local';
|
||||
|
||||
fragment REGISTER_EMIT
|
||||
: REGISTER {emit($REGISTER, REGISTER);};
|
||||
fragment REGISTER
|
||||
: 'v' ('0'..'9')+;
|
||||
: 'v' ('0'..'9')+;
|
||||
|
||||
fragment REGISTER_LIST_EMITCHILDREN
|
||||
: OPEN_BRACKET_EMIT
|
||||
@ -720,6 +734,8 @@ fragment MEMBER_NAME_EMIT
|
||||
fragment MEMBER_NAME
|
||||
: '<'? SIMPLE_NAME '>'?;
|
||||
|
||||
fragment SIMPLE_NAME_EMIT
|
||||
: SIMPLE_NAME {emit($SIMPLE_NAME, SIMPLE_NAME);};
|
||||
|
||||
fragment SIMPLE_NAME:
|
||||
( 'A'..'Z'
|
||||
|
@ -62,14 +62,15 @@ tokens {
|
||||
I_SPARSE_SWITCH_KEYS;
|
||||
I_SPARSE_SWITCH_TARGET_COUNT;
|
||||
I_SPARSE_SWITCH_TARGETS;
|
||||
I_ADDRESS;
|
||||
I_CATCH;
|
||||
I_CATCHES;
|
||||
I_CATCH_ADDRESS;
|
||||
I_LINE;
|
||||
I_LINES;
|
||||
I_PARAMETER;
|
||||
I_PARAMETERS;
|
||||
I_PARAMETER_NOT_SPECIFIED;
|
||||
I_ORDERED_DEBUG_DIRECTIVES;
|
||||
I_LINE;
|
||||
I_LOCAL;
|
||||
I_STATEMENTS;
|
||||
I_STATEMENT_FORMAT10t;
|
||||
I_STATEMENT_FORMAT10x;
|
||||
@ -216,10 +217,11 @@ statements_and_directives
|
||||
}
|
||||
( instruction {$method::currentAddress += $instruction.size/2;}
|
||||
| {!hasRegistersDirective}?=> registers_directive {hasRegistersDirective = true;}
|
||||
| label
|
||||
| catch_directive
|
||||
| line_directive
|
||||
| parameter_directive
|
||||
| label)*
|
||||
| ordered_debug_directive
|
||||
)*
|
||||
{
|
||||
if (!hasRegistersDirective) {
|
||||
//TODO: throw correct exception type here
|
||||
@ -230,8 +232,8 @@ statements_and_directives
|
||||
^(I_LABELS label*)
|
||||
^(I_STATEMENTS instruction*)
|
||||
^(I_CATCHES catch_directive*)
|
||||
^(I_LINES line_directive*)
|
||||
^(I_PARAMETERS parameter_directive*);
|
||||
^(I_PARAMETERS parameter_directive*)
|
||||
^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*);
|
||||
|
||||
registers_directive
|
||||
: REGISTERS_DIRECTIVE integral_literal
|
||||
@ -239,19 +241,28 @@ registers_directive
|
||||
|
||||
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($method::currentAddress)] field_type_descriptor $from $to $using)
|
||||
-> ^(I_CATCH[$start, "I_CATCH"] I_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($method::currentAddress)))});
|
||||
|
||||
parameter_directive
|
||||
: PARAMETER_DIRECTIVE ( STRING_LITERAL -> ^(I_PARAMETER STRING_LITERAL?)
|
||||
| -> ^(I_PARAMETER I_PARAMETER_NOT_SPECIFIED)
|
||||
);
|
||||
|
||||
ordered_debug_directive
|
||||
: line_directive
|
||||
| local_directive;
|
||||
|
||||
line_directive
|
||||
: LINE_DIRECTIVE integral_literal -> ^(I_LINE integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
|
||||
|
||||
local_directive
|
||||
: LOCAL_DIRECTIVE REGISTER SIMPLE_NAME field_type_descriptor
|
||||
-> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER SIMPLE_NAME field_type_descriptor I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
|
||||
|
||||
label
|
||||
: LABEL -> ^(I_LABEL LABEL {new CommonTree(new CommonToken(INTEGER_LITERAL,Integer.toString($method::currentAddress)))});
|
||||
: LABEL -> ^(I_LABEL LABEL I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
|
||||
|
||||
instruction returns [int size]
|
||||
@init {boolean needsNop = false;}
|
||||
|
@ -82,7 +82,7 @@ import org.JesusFreke.dexlib.code.Format.*;
|
||||
}
|
||||
//the parser wouldn't accept a negative register, i.e. v-1, so we don't have to check for val<0;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -301,8 +301,9 @@ method returns[ClassDataItem.EncodedMethod encodedMethod]
|
||||
labels
|
||||
statements
|
||||
catches
|
||||
lines
|
||||
parameters)
|
||||
parameters
|
||||
ordered_debug_directives
|
||||
)
|
||||
{
|
||||
MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem;
|
||||
int registers = $registers_directive.registers;
|
||||
@ -400,42 +401,11 @@ fully_qualified_field returns[FieldIdItem fieldIdItem]
|
||||
registers_directive returns[int registers]
|
||||
: ^(I_REGISTERS short_integral_literal) {$registers = $short_integral_literal.value;};
|
||||
|
||||
catches : ^(I_CATCHES catch_directive*);
|
||||
|
||||
catch_directive
|
||||
: ^(I_CATCH I_CATCH_ADDRESS field_type_descriptor from=offset_or_label to=offset_or_label using=offset_or_label)
|
||||
{
|
||||
TypeIdItem type = $field_type_descriptor.type;
|
||||
int startAddress = $from.offsetValue + $method::currentAddress;
|
||||
int endAddress = $to.offsetValue + $method::currentAddress;
|
||||
int handlerAddress = $using.offsetValue + $method::currentAddress;
|
||||
|
||||
$method::tryList.addHandler(type, startAddress, endAddress, handlerAddress);
|
||||
};
|
||||
|
||||
lines
|
||||
: ^(I_LINES line*);
|
||||
|
||||
line
|
||||
: ^(I_LINE integral_literal integer_literal)
|
||||
{
|
||||
$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*);
|
||||
|
||||
label_def
|
||||
: ^(I_LABEL label integer_literal)
|
||||
: ^(I_LABEL label address)
|
||||
{
|
||||
String labelName = $label.labelName;
|
||||
if ($method::labels.containsKey(labelName)) {
|
||||
@ -444,8 +414,55 @@ label_def
|
||||
}
|
||||
|
||||
|
||||
$method::labels.put(labelName, $integer_literal.value);
|
||||
$method::labels.put(labelName, $address.address);
|
||||
};
|
||||
|
||||
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])
|
||||
{
|
||||
TypeIdItem type = $field_type_descriptor.type;
|
||||
int startAddress = $from.address;
|
||||
int endAddress = $to.address;
|
||||
int handlerAddress = $using.address;
|
||||
|
||||
$method::tryList.addHandler(type, startAddress, endAddress, handlerAddress);
|
||||
};
|
||||
|
||||
address returns[int address]
|
||||
: I_ADDRESS
|
||||
{
|
||||
$address = Integer.parseInt($I_ADDRESS.text);
|
||||
};
|
||||
|
||||
parameters
|
||||
: ^(I_PARAMETERS parameter*);
|
||||
|
||||
parameter
|
||||
: ^(I_PARAMETER (
|
||||
string_literal {$method::debugInfo.addParameterName($string_literal.value);}
|
||||
| I_PARAMETER_NOT_SPECIFIED {$method::debugInfo.addParameterName(null);}
|
||||
));
|
||||
|
||||
ordered_debug_directives
|
||||
: ^(I_ORDERED_DEBUG_DIRECTIVES (line | local)*);
|
||||
|
||||
line
|
||||
: ^(I_LINE integral_literal address)
|
||||
{
|
||||
$method::debugInfo.addLine($address.address, $integral_literal.value);
|
||||
};
|
||||
|
||||
local : ^(I_LOCAL REGISTER SIMPLE_NAME field_type_descriptor address)
|
||||
{
|
||||
|
||||
int registerNumber = parseRegister_short($REGISTER.text);
|
||||
|
||||
$method::debugInfo.addLocal($address.address, registerNumber, $SIMPLE_NAME.text, $field_type_descriptor.type.toString());
|
||||
|
||||
};
|
||||
|
||||
|
||||
statements returns[ArrayList<Instruction> instructions]
|
||||
@init
|
||||
@ -488,15 +505,13 @@ offset returns[int offsetValue]
|
||||
$offsetValue = literalTools.parseInt(offsetText);
|
||||
};
|
||||
|
||||
offset_or_label_absolute[int baseAddress] returns[int address]
|
||||
: offset {$address = $offset.offsetValue + $baseAddress;}
|
||||
| label_ref {$address = $label_ref.labelAddress;};
|
||||
|
||||
offset_or_label returns[int offsetValue]
|
||||
: offset {$offsetValue = $offset.offsetValue;}
|
||||
| label_ref
|
||||
{
|
||||
int labelAddress = $label_ref.labelAddress;
|
||||
int currentAddress = $method::currentAddress;
|
||||
|
||||
$offsetValue = labelAddress-currentAddress;
|
||||
};
|
||||
| label_ref {$offsetValue = $label_ref.labelAddress-$method::currentAddress;};
|
||||
|
||||
instruction returns[Instruction instruction]
|
||||
: //e.g. goto endloop:
|
||||
|
@ -47,7 +47,7 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
|
||||
return item;
|
||||
}
|
||||
|
||||
protected void setReference(T item) {
|
||||
public void setReference(T item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
|
@ -33,15 +33,28 @@ import org.JesusFreke.dexlib.*;
|
||||
public class StartLocal extends CompositeField<StartLocal> implements DebugInstruction<StartLocal> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField opcodeField;
|
||||
private final SignedLeb128Field registerNumber;
|
||||
private final IndexedItemReference<StringIdItem> localName;
|
||||
private final IndexedItemReference<TypeIdItem> localType;
|
||||
|
||||
public StartLocal(DexFile dexFile) {
|
||||
fields = new Field[] {
|
||||
new ByteField((byte)0x03),
|
||||
new SignedLeb128Field(),
|
||||
new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()),
|
||||
new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128p1Field()),
|
||||
opcodeField = new ByteField((byte)0x03),
|
||||
registerNumber = new SignedLeb128Field(),
|
||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()),
|
||||
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128p1Field()),
|
||||
};
|
||||
}
|
||||
|
||||
public StartLocal(DexFile dexFile, int registerNumber, StringIdItem localName, TypeIdItem localType) {
|
||||
this(dexFile);
|
||||
this.registerNumber.cacheValue(registerNumber);
|
||||
this.localName.setReference(localName);
|
||||
this.localType.setReference(localType);
|
||||
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import org.JesusFreke.dexlib.debug.*;
|
||||
import org.JesusFreke.dexlib.DexFile;
|
||||
import org.JesusFreke.dexlib.DebugInfoItem;
|
||||
import org.JesusFreke.dexlib.StringIdItem;
|
||||
import org.JesusFreke.dexlib.TypeIdItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -64,12 +65,22 @@ public class DebugInfoBuilder
|
||||
public DebugInfoBuilder() {
|
||||
}
|
||||
|
||||
public void addLine(int address, int line) {
|
||||
hasData = true;
|
||||
|
||||
private void checkAddress(int address) {
|
||||
if (lastAddress > address) {
|
||||
throw new RuntimeException("Cannot add an event with an address before the address of the prior event");
|
||||
}
|
||||
}
|
||||
|
||||
public void addParameterName(String parameterName) {
|
||||
hasData = true;
|
||||
|
||||
parameterNames.add(parameterName);
|
||||
}
|
||||
|
||||
public void addLine(int address, int line) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
if (lineStart == 0) {
|
||||
lineStart = line;
|
||||
@ -78,10 +89,12 @@ public class DebugInfoBuilder
|
||||
events.add(new LineEvent(address, line));
|
||||
}
|
||||
|
||||
public void addParameterName(String parameterName) {
|
||||
public void addLocal(int address, int registerNumber, String localName, String localType) {
|
||||
hasData = true;
|
||||
|
||||
parameterNames.add(parameterName);
|
||||
checkAddress(address);
|
||||
|
||||
events.add(new StartLocalEvent(address, registerNumber, localName, localType));
|
||||
}
|
||||
|
||||
public int getParameterNameCount() {
|
||||
@ -103,7 +116,7 @@ public class DebugInfoBuilder
|
||||
currentLine = lineStart;
|
||||
|
||||
for (Event event: events) {
|
||||
event.emit(debugInstructions);
|
||||
event.emit(dexFile, debugInstructions);
|
||||
}
|
||||
debugInstructions.add(new EndSequence());
|
||||
|
||||
@ -121,7 +134,7 @@ public class DebugInfoBuilder
|
||||
private interface Event
|
||||
{
|
||||
int getAddress();
|
||||
void emit(List<DebugInstruction> debugInstructions);
|
||||
void emit(DexFile dexFile, List<DebugInstruction> debugInstructions);
|
||||
}
|
||||
|
||||
private class LineEvent implements Event
|
||||
@ -138,7 +151,7 @@ public class DebugInfoBuilder
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(List<DebugInstruction> debugInstructions) {
|
||||
public void emit(DexFile dexFile, List<DebugInstruction> debugInstructions) {
|
||||
int lineDelta = line - currentLine;
|
||||
int addressDelta = address - currentAddress;
|
||||
|
||||
@ -162,4 +175,37 @@ public class DebugInfoBuilder
|
||||
return (byte)(FIRST_SPECIAL + (addressDelta * LINE_RANGE) + (lineDelta - LINE_BASE));
|
||||
}
|
||||
}
|
||||
|
||||
private class StartLocalEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
private final int registerNum;
|
||||
private final String localName;
|
||||
private final String localType;
|
||||
|
||||
public StartLocalEvent(int address, int registerNum, String localName, String localType) {
|
||||
this.address = address;
|
||||
this.registerNum = registerNum;
|
||||
this.localName = localName;
|
||||
this.localType = localType;
|
||||
}
|
||||
|
||||
public int getAddress()
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, List<DebugInstruction> debugInstructions)
|
||||
{
|
||||
int addressDelta = address-currentAddress;
|
||||
|
||||
if (addressDelta > 0) {
|
||||
debugInstructions.add(new AdvancePC(addressDelta));
|
||||
currentAddress = address;
|
||||
}
|
||||
|
||||
debugInstructions.add(new StartLocal(dexFile, registerNum, new StringIdItem(dexFile, localName),
|
||||
new TypeIdItem(dexFile, localType)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -374,8 +374,15 @@ SparseSwitch:
|
||||
.line 4
|
||||
|
||||
;0
|
||||
|
||||
|
||||
const-string v0, "This shouldn't be displayed!"
|
||||
|
||||
.local v0, testVarName Ljava/lang/String;
|
||||
|
||||
|
||||
|
||||
|
||||
;2
|
||||
|
||||
tryStart:
|
||||
@ -405,7 +412,8 @@ SparseSwitch:
|
||||
|
||||
;11
|
||||
|
||||
.catch Ljava/lang/Exception; from tryStart: to tryEnd: using handler:
|
||||
|
||||
.catch Ljava/lang/Exception; {tryStart: .. tryEnd:} handler:
|
||||
|
||||
handler:
|
||||
const-string v0, "In the exception handler."
|
||||
|
Loading…
x
Reference in New Issue
Block a user