From f175e1d9877a313dd5e8cfc5307e508bf48db251 Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Fri, 22 May 2009 06:04:14 +0000 Subject: [PATCH] - 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 --- .../antlr3/org/JesusFreke/smali/smaliLexer.g | 24 ++++- .../antlr3/org/JesusFreke/smali/smaliParser.g | 33 ++++-- .../org/JesusFreke/smali/smaliTreeWalker.g | 101 ++++++++++-------- .../org/JesusFreke/dexlib/ItemReference.java | 2 +- .../JesusFreke/dexlib/debug/StartLocal.java | 21 +++- .../dexlib/util/DebugInfoBuilder.java | 62 +++++++++-- src/test/resources/examples/HelloWorld2.smali | 10 +- 7 files changed, 181 insertions(+), 72 deletions(-) diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g b/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g index e6e953f8..2e68c01a 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliLexer.g @@ -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' diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliParser.g b/src/main/antlr3/org/JesusFreke/smali/smaliParser.g index 5d57e291..9d33329b 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliParser.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliParser.g @@ -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;} diff --git a/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g b/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g index 2937046d..4bb45d15 100644 --- a/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g +++ b/src/main/antlr3/org/JesusFreke/smali/smaliTreeWalker.g @@ -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 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: diff --git a/src/main/java/org/JesusFreke/dexlib/ItemReference.java b/src/main/java/org/JesusFreke/dexlib/ItemReference.java index 8638fd08..9f6023e3 100644 --- a/src/main/java/org/JesusFreke/dexlib/ItemReference.java +++ b/src/main/java/org/JesusFreke/dexlib/ItemReference.java @@ -47,7 +47,7 @@ public abstract class ItemReference, S extends ItemReference implements DebugInstruction { private final Field[] fields; + private final ByteField opcodeField; + private final SignedLeb128Field registerNumber; + private final IndexedItemReference localName; + private final IndexedItemReference localType; + public StartLocal(DexFile dexFile) { fields = new Field[] { - new ByteField((byte)0x03), - new SignedLeb128Field(), - new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field()), - new IndexedItemReference(dexFile.TypeIdsSection, new Leb128p1Field()), + opcodeField = new ByteField((byte)0x03), + registerNumber = new SignedLeb128Field(), + localName = new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field()), + localType = new IndexedItemReference(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; } diff --git a/src/main/java/org/JesusFreke/dexlib/util/DebugInfoBuilder.java b/src/main/java/org/JesusFreke/dexlib/util/DebugInfoBuilder.java index cf318281..2a58f673 100644 --- a/src/main/java/org/JesusFreke/dexlib/util/DebugInfoBuilder.java +++ b/src/main/java/org/JesusFreke/dexlib/util/DebugInfoBuilder.java @@ -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 debugInstructions); + void emit(DexFile dexFile, List debugInstructions); } private class LineEvent implements Event @@ -138,7 +151,7 @@ public class DebugInfoBuilder return address; } - public void emit(List debugInstructions) { + public void emit(DexFile dexFile, List 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 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))); + } + } } diff --git a/src/test/resources/examples/HelloWorld2.smali b/src/test/resources/examples/HelloWorld2.smali index 244b4658..5cadead5 100644 --- a/src/test/resources/examples/HelloWorld2.smali +++ b/src/test/resources/examples/HelloWorld2.smali @@ -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."