- 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:
JesusFreke@JesusFreke.com 2009-05-22 06:04:14 +00:00
parent 66a23e6ecc
commit f175e1d987
7 changed files with 181 additions and 72 deletions

View File

@ -457,11 +457,11 @@ CATCH_PHRASE
: CATCH_DIRECTIVE_EMIT : CATCH_DIRECTIVE_EMIT
WS WS
FIELD_TYPE_DESCRIPTOR_EMITCHILD FIELD_TYPE_DESCRIPTOR_EMITCHILD
WS 'from' WS WS? '{' WS?
(LABEL_EMIT | OFFSET_EMIT) (LABEL_EMIT | OFFSET_EMIT)
WS 'to' WS WS '..' WS
(LABEL_EMIT | OFFSET_EMIT) (LABEL_EMIT | OFFSET_EMIT)
WS 'using' WS WS? '}' WS?
(LABEL_EMIT | OFFSET_EMIT); (LABEL_EMIT | OFFSET_EMIT);
LINE_PHRASE LINE_PHRASE
@ -473,6 +473,15 @@ PARAMETER_PHRASE
: PARAMETER_DIRECTIVE_EMIT : PARAMETER_DIRECTIVE_EMIT
(WS STRING_LITERAL_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? //TODO: add support for both relative and absolute offsets?
fragment OFFSET_EMIT fragment OFFSET_EMIT
@ -570,6 +579,11 @@ fragment PARAMETER_DIRECTIVE_EMIT
fragment PARAMETER_DIRECTIVE fragment PARAMETER_DIRECTIVE
: '.parameter'; : '.parameter';
fragment LOCAL_DIRECTIVE_EMIT
: LOCAL_DIRECTIVE {emit($LOCAL_DIRECTIVE, LOCAL_DIRECTIVE);};
fragment LOCAL_DIRECTIVE
: '.local';
fragment REGISTER_EMIT fragment REGISTER_EMIT
: REGISTER {emit($REGISTER, REGISTER);}; : REGISTER {emit($REGISTER, REGISTER);};
fragment REGISTER fragment REGISTER
@ -720,6 +734,8 @@ fragment MEMBER_NAME_EMIT
fragment MEMBER_NAME fragment MEMBER_NAME
: '<'? SIMPLE_NAME '>'?; : '<'? SIMPLE_NAME '>'?;
fragment SIMPLE_NAME_EMIT
: SIMPLE_NAME {emit($SIMPLE_NAME, SIMPLE_NAME);};
fragment SIMPLE_NAME: fragment SIMPLE_NAME:
( 'A'..'Z' ( 'A'..'Z'

View File

@ -62,14 +62,15 @@ tokens {
I_SPARSE_SWITCH_KEYS; I_SPARSE_SWITCH_KEYS;
I_SPARSE_SWITCH_TARGET_COUNT; I_SPARSE_SWITCH_TARGET_COUNT;
I_SPARSE_SWITCH_TARGETS; I_SPARSE_SWITCH_TARGETS;
I_ADDRESS;
I_CATCH; I_CATCH;
I_CATCHES; I_CATCHES;
I_CATCH_ADDRESS;
I_LINE;
I_LINES;
I_PARAMETER; I_PARAMETER;
I_PARAMETERS; I_PARAMETERS;
I_PARAMETER_NOT_SPECIFIED; I_PARAMETER_NOT_SPECIFIED;
I_ORDERED_DEBUG_DIRECTIVES;
I_LINE;
I_LOCAL;
I_STATEMENTS; I_STATEMENTS;
I_STATEMENT_FORMAT10t; I_STATEMENT_FORMAT10t;
I_STATEMENT_FORMAT10x; I_STATEMENT_FORMAT10x;
@ -216,10 +217,11 @@ statements_and_directives
} }
( instruction {$method::currentAddress += $instruction.size/2;} ( instruction {$method::currentAddress += $instruction.size/2;}
| {!hasRegistersDirective}?=> registers_directive {hasRegistersDirective = true;} | {!hasRegistersDirective}?=> registers_directive {hasRegistersDirective = true;}
| label
| catch_directive | catch_directive
| line_directive
| parameter_directive | parameter_directive
| label)* | ordered_debug_directive
)*
{ {
if (!hasRegistersDirective) { if (!hasRegistersDirective) {
//TODO: throw correct exception type here //TODO: throw correct exception type here
@ -230,8 +232,8 @@ statements_and_directives
^(I_LABELS label*) ^(I_LABELS label*)
^(I_STATEMENTS instruction*) ^(I_STATEMENTS instruction*)
^(I_CATCHES catch_directive*) ^(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
: REGISTERS_DIRECTIVE integral_literal : REGISTERS_DIRECTIVE integral_literal
@ -239,19 +241,28 @@ registers_directive
catch_directive catch_directive
: CATCH_DIRECTIVE field_type_descriptor from=offset_or_label to=offset_or_label using=offset_or_label : 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
: PARAMETER_DIRECTIVE ( STRING_LITERAL -> ^(I_PARAMETER STRING_LITERAL?) : PARAMETER_DIRECTIVE ( STRING_LITERAL -> ^(I_PARAMETER STRING_LITERAL?)
| -> ^(I_PARAMETER I_PARAMETER_NOT_SPECIFIED) | -> ^(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
: 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] instruction returns [int size]
@init {boolean needsNop = false;} @init {boolean needsNop = false;}

View File

@ -301,8 +301,9 @@ method returns[ClassDataItem.EncodedMethod encodedMethod]
labels labels
statements statements
catches catches
lines parameters
parameters) ordered_debug_directives
)
{ {
MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem; MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem;
int registers = $registers_directive.registers; int registers = $registers_directive.registers;
@ -400,26 +401,39 @@ fully_qualified_field returns[FieldIdItem fieldIdItem]
registers_directive returns[int registers] registers_directive returns[int registers]
: ^(I_REGISTERS short_integral_literal) {$registers = $short_integral_literal.value;}; : ^(I_REGISTERS short_integral_literal) {$registers = $short_integral_literal.value;};
labels
: ^(I_LABELS label_def*);
label_def
: ^(I_LABEL label address)
{
String labelName = $label.labelName;
if ($method::labels.containsKey(labelName)) {
//TODO: use appropriate exception type
throw new RuntimeException("Label " + labelName + " has multiple defintions.");
}
$method::labels.put(labelName, $address.address);
};
catches : ^(I_CATCHES catch_directive*); catches : ^(I_CATCHES catch_directive*);
catch_directive catch_directive
: ^(I_CATCH I_CATCH_ADDRESS field_type_descriptor from=offset_or_label to=offset_or_label using=offset_or_label) : ^(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; TypeIdItem type = $field_type_descriptor.type;
int startAddress = $from.offsetValue + $method::currentAddress; int startAddress = $from.address;
int endAddress = $to.offsetValue + $method::currentAddress; int endAddress = $to.address;
int handlerAddress = $using.offsetValue + $method::currentAddress; int handlerAddress = $using.address;
$method::tryList.addHandler(type, startAddress, endAddress, handlerAddress); $method::tryList.addHandler(type, startAddress, endAddress, handlerAddress);
}; };
lines address returns[int address]
: ^(I_LINES line*); : I_ADDRESS
line
: ^(I_LINE integral_literal integer_literal)
{ {
$method::debugInfo.addLine($integer_literal.value, $integral_literal.value); $address = Integer.parseInt($I_ADDRESS.text);
}; };
parameters parameters
@ -431,22 +445,25 @@ parameter
| I_PARAMETER_NOT_SPECIFIED {$method::debugInfo.addParameterName(null);} | I_PARAMETER_NOT_SPECIFIED {$method::debugInfo.addParameterName(null);}
)); ));
labels ordered_debug_directives
: ^(I_LABELS label_def*); : ^(I_ORDERED_DEBUG_DIRECTIVES (line | local)*);
label_def line
: ^(I_LABEL label integer_literal) : ^(I_LINE integral_literal address)
{ {
String labelName = $label.labelName; $method::debugInfo.addLine($address.address, $integral_literal.value);
if ($method::labels.containsKey(labelName)) {
//TODO: use appropriate exception type
throw new RuntimeException("Label " + labelName + " has multiple defintions.");
}
$method::labels.put(labelName, $integer_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] statements returns[ArrayList<Instruction> instructions]
@init @init
{ {
@ -488,15 +505,13 @@ offset returns[int offsetValue]
$offsetValue = literalTools.parseInt(offsetText); $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_or_label returns[int offsetValue]
: offset {$offsetValue = $offset.offsetValue;} : offset {$offsetValue = $offset.offsetValue;}
| label_ref | label_ref {$offsetValue = $label_ref.labelAddress-$method::currentAddress;};
{
int labelAddress = $label_ref.labelAddress;
int currentAddress = $method::currentAddress;
$offsetValue = labelAddress-currentAddress;
};
instruction returns[Instruction instruction] instruction returns[Instruction instruction]
: //e.g. goto endloop: : //e.g. goto endloop:

View File

@ -47,7 +47,7 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
return item; return item;
} }
protected void setReference(T item) { public void setReference(T item) {
this.item = item; this.item = item;
} }

View File

@ -33,15 +33,28 @@ import org.JesusFreke.dexlib.*;
public class StartLocal extends CompositeField<StartLocal> implements DebugInstruction<StartLocal> { public class StartLocal extends CompositeField<StartLocal> implements DebugInstruction<StartLocal> {
private final Field[] fields; 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) { public StartLocal(DexFile dexFile) {
fields = new Field[] { fields = new Field[] {
new ByteField((byte)0x03), opcodeField = new ByteField((byte)0x03),
new SignedLeb128Field(), registerNumber = new SignedLeb128Field(),
new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()), localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()),
new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, 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() { protected Field[] getFields() {
return fields; return fields;
} }

View File

@ -32,6 +32,7 @@ import org.JesusFreke.dexlib.debug.*;
import org.JesusFreke.dexlib.DexFile; import org.JesusFreke.dexlib.DexFile;
import org.JesusFreke.dexlib.DebugInfoItem; import org.JesusFreke.dexlib.DebugInfoItem;
import org.JesusFreke.dexlib.StringIdItem; import org.JesusFreke.dexlib.StringIdItem;
import org.JesusFreke.dexlib.TypeIdItem;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -64,12 +65,22 @@ public class DebugInfoBuilder
public DebugInfoBuilder() { public DebugInfoBuilder() {
} }
public void addLine(int address, int line) { private void checkAddress(int address) {
hasData = true;
if (lastAddress > address) { if (lastAddress > address) {
throw new RuntimeException("Cannot add an event with an address before the address of the prior event"); 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) { if (lineStart == 0) {
lineStart = line; lineStart = line;
@ -78,10 +89,12 @@ public class DebugInfoBuilder
events.add(new LineEvent(address, line)); events.add(new LineEvent(address, line));
} }
public void addParameterName(String parameterName) { public void addLocal(int address, int registerNumber, String localName, String localType) {
hasData = true; hasData = true;
parameterNames.add(parameterName); checkAddress(address);
events.add(new StartLocalEvent(address, registerNumber, localName, localType));
} }
public int getParameterNameCount() { public int getParameterNameCount() {
@ -103,7 +116,7 @@ public class DebugInfoBuilder
currentLine = lineStart; currentLine = lineStart;
for (Event event: events) { for (Event event: events) {
event.emit(debugInstructions); event.emit(dexFile, debugInstructions);
} }
debugInstructions.add(new EndSequence()); debugInstructions.add(new EndSequence());
@ -121,7 +134,7 @@ public class DebugInfoBuilder
private interface Event private interface Event
{ {
int getAddress(); int getAddress();
void emit(List<DebugInstruction> debugInstructions); void emit(DexFile dexFile, List<DebugInstruction> debugInstructions);
} }
private class LineEvent implements Event private class LineEvent implements Event
@ -138,7 +151,7 @@ public class DebugInfoBuilder
return address; return address;
} }
public void emit(List<DebugInstruction> debugInstructions) { public void emit(DexFile dexFile, List<DebugInstruction> debugInstructions) {
int lineDelta = line - currentLine; int lineDelta = line - currentLine;
int addressDelta = address - currentAddress; int addressDelta = address - currentAddress;
@ -162,4 +175,37 @@ public class DebugInfoBuilder
return (byte)(FIRST_SPECIAL + (addressDelta * LINE_RANGE) + (lineDelta - LINE_BASE)); 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)));
}
}
} }

View File

@ -374,8 +374,15 @@ SparseSwitch:
.line 4 .line 4
;0 ;0
const-string v0, "This shouldn't be displayed!" const-string v0, "This shouldn't be displayed!"
.local v0, testVarName Ljava/lang/String;
;2 ;2
tryStart: tryStart:
@ -405,7 +412,8 @@ SparseSwitch:
;11 ;11
.catch Ljava/lang/Exception; from tryStart: to tryEnd: using handler:
.catch Ljava/lang/Exception; {tryStart: .. tryEnd:} handler:
handler: handler:
const-string v0, "In the exception handler." const-string v0, "In the exception handler."