From 3e4e5ec7a4f2bcd82e21ba7caf93c60a981422ab Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Thu, 18 Apr 2013 00:17:34 -0700 Subject: [PATCH] Change .param and .local syntax, to be able to handle empty name/type/signature --- .../Adaptors/Debug/EndLocalMethodItem.java | 15 +--- .../Adaptors/Debug/LocalFormatter.java | 73 ++++++++++++++++++ .../Debug/RestartLocalMethodItem.java | 15 +--- .../Adaptors/Debug/StartLocalMethodItem.java | 17 ++-- .../baksmali/Adaptors/MethodDefinition.java | 4 +- .../java/org/jf/baksmali/AnalysisTest.java | 5 ++ .../test/resources/LocalTest/LocalTest.smali | 31 ++++++++ .../src/test/resources/LocalTest/classes.dex | Bin 0 -> 832 bytes smali/src/main/antlr3/smaliParser.g | 12 +-- smali/src/main/antlr3/smaliTreeWalker.g | 10 +-- 10 files changed, 138 insertions(+), 44 deletions(-) create mode 100644 baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LocalFormatter.java create mode 100644 baksmali/src/test/resources/LocalTest/LocalTest.smali create mode 100644 baksmali/src/test/resources/LocalTest/classes.dex diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndLocalMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndLocalMethodItem.java index e80ca35b..231e0498 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndLocalMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndLocalMethodItem.java @@ -54,19 +54,12 @@ public class EndLocalMethodItem extends DebugMethodItem { writer.write(".end local "); registerFormatter.writeTo(writer, endLocal.getRegister()); - //TODO: what if name is null, but there is a type? String name = endLocal.getName(); - if (name != null) { + String type = endLocal.getType(); + String signature = endLocal.getSignature(); + if (name != null || type != null || signature != null) { writer.write(" # "); - writer.write(name); - writer.write(':'); - writer.write(endLocal.getType()); - String signature = endLocal.getSignature(); - if (signature != null) { - writer.write(",\""); - writer.write(signature); - writer.write('"'); - } + LocalFormatter.writeLocal(writer, name, type, signature); } return true; } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LocalFormatter.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LocalFormatter.java new file mode 100644 index 00000000..62ed9958 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LocalFormatter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.baksmali.Adaptors.Debug; + +import org.jf.baksmali.Adaptors.ReferenceFormatter; +import org.jf.util.IndentingWriter; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; + +public class LocalFormatter { + /** + * Writes out the given local info + * + * The written string will be something like: + * + * "localVar":Ljava/lang/String;, "SomeSignature" + * "localVar":Ljava/lang/String; + * "localVar":V, "SomeSignature" + * null:Ljava/lang/String;, "SomeSignature" + * null:V, "SomeSignature" + * + * One of name, type or signature must be non-null + */ + public static void writeLocal(@Nonnull IndentingWriter writer, @Nullable String name, @Nullable String type, + @Nullable String signature) throws IOException { + if (name != null) { + ReferenceFormatter.writeStringReference(writer, name); + } else { + writer.write("null"); + } + writer.write(':'); + if (type != null) { + writer.write(type); + } else { + writer.write("V"); + } + if (signature != null) { + writer.write(", "); + ReferenceFormatter.writeStringReference(writer, signature); + } + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/RestartLocalMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/RestartLocalMethodItem.java index 45be903a..44617193 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/RestartLocalMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/RestartLocalMethodItem.java @@ -54,19 +54,12 @@ public class RestartLocalMethodItem extends DebugMethodItem { writer.write(".restart local "); registerFormatter.writeTo(writer, restartLocal.getRegister()); - //TODO: what if name is null, but there is a type? String name = restartLocal.getName(); - if (name != null) { + String type = restartLocal.getType(); + String signature = restartLocal.getSignature(); + if (name != null || type != null || signature != null) { writer.write(" # "); - writer.write(name); - writer.write(':'); - writer.write(restartLocal.getType()); - String signature = restartLocal.getSignature(); - if (signature != null) { - writer.write(",\""); - writer.write(signature); - writer.write('"'); - } + LocalFormatter.writeLocal(writer, name, type, signature); } return true; } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/StartLocalMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/StartLocalMethodItem.java index a994e130..0cd2d2b1 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/StartLocalMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/StartLocalMethodItem.java @@ -53,17 +53,14 @@ public class StartLocalMethodItem extends DebugMethodItem { public boolean writeTo(IndentingWriter writer) throws IOException { writer.write(".local "); registerFormatter.writeTo(writer, startLocal.getRegister()); - writer.write(", "); - //TODO: what about when name or type is null? Can the name contain a colon? - writer.write(startLocal.getName()); - writer.write(':'); - writer.write(startLocal.getType()); + + String name = startLocal.getName(); + String type = startLocal.getType(); String signature = startLocal.getSignature(); - if (signature != null) { - writer.write(",\""); - //TODO: does dalvik require this be in any format? Does it need to be escaped? - writer.write(signature); - writer.write('"'); + + if (name != null || type != null || signature != null) { + writer.write(", "); + LocalFormatter.writeLocal(writer, name, type, signature); } return true; } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java index 4fb1f871..b12328f8 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java @@ -230,10 +230,10 @@ public class MethodDefinition { if (parameterName != null || annotations.size() != 0) { writer.write(".param p"); writer.printSignedIntAsDec(registerNumber); + if (parameterName != null) { writer.write(", "); - // TODO: does dalvik allow non-identifier parameter and/or local names? - writer.write(parameterName); + ReferenceFormatter.writeStringReference(writer, parameterName); } writer.write(" # "); writer.write(parameterType); diff --git a/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java b/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java index 2cb1da2a..c511a37c 100644 --- a/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java +++ b/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java @@ -76,6 +76,11 @@ public class AnalysisTest { runTest("DuplicateTest", false); } + @Test + public void LocalTest() throws IOException, URISyntaxException { + runTest("LocalTest", false); + } + public void runTest(String test, boolean registerInfo) throws IOException, URISyntaxException { String dexFilePath = String.format("%s%sclasses.dex", test, File.separatorChar); diff --git a/baksmali/src/test/resources/LocalTest/LocalTest.smali b/baksmali/src/test/resources/LocalTest/LocalTest.smali new file mode 100644 index 00000000..fe6d1adf --- /dev/null +++ b/baksmali/src/test/resources/LocalTest/LocalTest.smali @@ -0,0 +1,31 @@ +.class public LLocalTest; +.super Ljava/lang/Object; + + +# direct methods +.method public static method1()V + .registers 10 + + .local v0, "blah! This local name has some spaces, a colon, even a \nnewline!":I, "some sig info:\nblah." + .local v1, "blah! This local name has some spaces, a colon, even a \nnewline!":V, "some sig info:\nblah." + .local v2, "blah! This local name has some spaces, a colon, even a \nnewline!":I + .local v3, "blah! This local name has some spaces, a colon, even a \nnewline!":V + .local v4, null:I, "some sig info:\nblah." + .local v5, null:V, "some sig info:\nblah." + .local v6, null:I + .local v7 + .local v8 + .local v9 + return-void +.end method + +.method public static method2(IJLjava/lang/String;)V + .registers 10 + .param p0, "blah! This local name has some spaces, a colon, even a \nnewline!" # I + .param p1 # J + .annotation runtime LAnnotationWithValues; + .end annotation + .end param + + return-void +.end method diff --git a/baksmali/src/test/resources/LocalTest/classes.dex b/baksmali/src/test/resources/LocalTest/classes.dex new file mode 100644 index 0000000000000000000000000000000000000000..5b6f026e2b07bb3bf629caaf04b81f27b25f53b9 GIT binary patch literal 832 zcmZ9Lv1=4T6vp4&Z0_9kFcL&8Cz3McqDB9U-gy#KuR>(1Mc z&z65**;pIC*m^mAezd%KU5iXbWH#7Z!BWYrCDMgPdk4G%Fv$ln7w*3T1%805Fa+3; z4v4^c&;z%?5Znh3z-#aZyaN<2%!jK;0G2>|flqMYJ!ty^oqi$Eh>WVW&cRsv{)PO( zI$=_X+7`7VXXBgR=cO&v+z-<-8QAQxEBbOWj`NYtc3n~SWhI{2L)*)&ANTI=P2A`| z+r9Ep>c@Ri0|^G(JF(o@%WSf0c9XO)8S@x#51dJCVTv3|F|{LCtQ%`ad6xTi;|`t2 zF7ob4mU_1;odZ`U`Tm8ua#7CIk?Gi^{$YMC;t?BlDOK&Pc1cuK9m@{OKTP;)1BWFt?F@4zQ0CxJYehoYI jV|-eT&YIhe59dKcXKYnRqu-_hI)1L_rHSQ#;3@bAY~yYL literal 0 HcmV?d00001 diff --git a/smali/src/main/antlr3/smaliParser.g b/smali/src/main/antlr3/smaliParser.g index 2f4c3085..bcb00bbd 100644 --- a/smali/src/main/antlr3/smaliParser.g +++ b/smali/src/main/antlr3/smaliParser.g @@ -762,13 +762,13 @@ the annotations. If it turns out that they are parameter annotations, we include add them to the $statements_and_directives::methodAnnotations list*/ parameter_directive @init {List annotations = new ArrayList();} - : PARAMETER_DIRECTIVE REGISTER COMMA simple_name + : PARAMETER_DIRECTIVE REGISTER (COMMA STRING_LITERAL)? ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})* ( END_PARAMETER_DIRECTIVE - -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER simple_name ^(I_ANNOTATIONS annotation*)) + -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER STRING_LITERAL? ^(I_ANNOTATIONS annotation*)) | /*epsilon*/ {$statements_and_directives::methodAnnotations.addAll(annotations);} - -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER simple_name ^(I_ANNOTATIONS)) + -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER STRING_LITERAL? ^(I_ANNOTATIONS)) ); ordered_debug_directive @@ -785,8 +785,10 @@ line_directive -> ^(I_LINE[$start, "I_LINE"] integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]); local_directive - : LOCAL_DIRECTIVE REGISTER COMMA simple_name COLON nonvoid_type_descriptor (COMMA STRING_LITERAL)? - -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER simple_name nonvoid_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + : LOCAL_DIRECTIVE REGISTER (COMMA (NULL_LITERAL | name=STRING_LITERAL) COLON (VOID_TYPE | nonvoid_type_descriptor) + (COMMA signature=STRING_LITERAL)? )? + -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER NULL_LITERAL? $name? nonvoid_type_descriptor? $signature? + I_ADDRESS[$start, Integer.toString($method::currentAddress)]); end_local_directive : END_LOCAL_DIRECTIVE REGISTER diff --git a/smali/src/main/antlr3/smaliTreeWalker.g b/smali/src/main/antlr3/smaliTreeWalker.g index 7c47090e..19fa05f7 100644 --- a/smali/src/main/antlr3/smaliTreeWalker.g +++ b/smali/src/main/antlr3/smaliTreeWalker.g @@ -612,7 +612,7 @@ parameters[List parameters] : ^(I_PARAMETERS (parameter[parameters])*); parameter[List parameters] - : ^(I_PARAMETER REGISTER SIMPLE_NAME annotations) + : ^(I_PARAMETER REGISTER string_literal? annotations) { final int registerNumber = parseRegister_short($REGISTER.text); int totalMethodRegisters = $method::totalMethodRegisters; @@ -639,7 +639,7 @@ parameter[List parameters] } SmaliMethodParameter methodParameter = parameters.get(parameterIndex); - methodParameter.name = $SIMPLE_NAME.text; + methodParameter.name = $string_literal.value; if ($annotations.annotations != null && $annotations.annotations.size() > 0) { methodParameter.annotations = $annotations.annotations; } @@ -665,12 +665,12 @@ line returns[DebugItem debugItem] }; local returns[DebugItem debugItem] - : ^(I_LOCAL REGISTER SIMPLE_NAME nonvoid_type_descriptor string_literal? address) + : ^(I_LOCAL REGISTER ((NULL_LITERAL | name=string_literal) nonvoid_type_descriptor? signature=string_literal?)? address) { int registerNumber = parseRegister_short($REGISTER.text); - $debugItem = new ImmutableStartLocal($address.address, registerNumber, $SIMPLE_NAME.text, - $nonvoid_type_descriptor.type, $string_literal.value); + $debugItem = new ImmutableStartLocal($address.address, registerNumber, $name.value, + $nonvoid_type_descriptor.type, $signature.value); }; end_local returns[DebugItem debugItem]