- 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
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'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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."