Change .param and .local syntax, to be able to handle empty name/type/signature

This commit is contained in:
Ben Gruver 2013-04-18 00:17:34 -07:00
parent aa860984c0
commit 3e4e5ec7a4
10 changed files with 138 additions and 44 deletions

View File

@ -54,19 +54,12 @@ public class EndLocalMethodItem extends DebugMethodItem {
writer.write(".end local "); writer.write(".end local ");
registerFormatter.writeTo(writer, endLocal.getRegister()); registerFormatter.writeTo(writer, endLocal.getRegister());
//TODO: what if name is null, but there is a type?
String name = endLocal.getName(); 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(" # ");
writer.write(name); LocalFormatter.writeLocal(writer, name, type, signature);
writer.write(':');
writer.write(endLocal.getType());
String signature = endLocal.getSignature();
if (signature != null) {
writer.write(",\"");
writer.write(signature);
writer.write('"');
}
} }
return true; return true;
} }

View File

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

View File

@ -54,19 +54,12 @@ public class RestartLocalMethodItem extends DebugMethodItem {
writer.write(".restart local "); writer.write(".restart local ");
registerFormatter.writeTo(writer, restartLocal.getRegister()); registerFormatter.writeTo(writer, restartLocal.getRegister());
//TODO: what if name is null, but there is a type?
String name = restartLocal.getName(); 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(" # ");
writer.write(name); LocalFormatter.writeLocal(writer, name, type, signature);
writer.write(':');
writer.write(restartLocal.getType());
String signature = restartLocal.getSignature();
if (signature != null) {
writer.write(",\"");
writer.write(signature);
writer.write('"');
}
} }
return true; return true;
} }

View File

@ -53,17 +53,14 @@ public class StartLocalMethodItem extends DebugMethodItem {
public boolean writeTo(IndentingWriter writer) throws IOException { public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".local "); writer.write(".local ");
registerFormatter.writeTo(writer, startLocal.getRegister()); registerFormatter.writeTo(writer, startLocal.getRegister());
writer.write(", ");
//TODO: what about when name or type is null? Can the name contain a colon? String name = startLocal.getName();
writer.write(startLocal.getName()); String type = startLocal.getType();
writer.write(':');
writer.write(startLocal.getType());
String signature = startLocal.getSignature(); String signature = startLocal.getSignature();
if (signature != null) {
writer.write(",\""); if (name != null || type != null || signature != null) {
//TODO: does dalvik require this be in any format? Does it need to be escaped? writer.write(", ");
writer.write(signature); LocalFormatter.writeLocal(writer, name, type, signature);
writer.write('"');
} }
return true; return true;
} }

View File

@ -230,10 +230,10 @@ public class MethodDefinition {
if (parameterName != null || annotations.size() != 0) { if (parameterName != null || annotations.size() != 0) {
writer.write(".param p"); writer.write(".param p");
writer.printSignedIntAsDec(registerNumber); writer.printSignedIntAsDec(registerNumber);
if (parameterName != null) { if (parameterName != null) {
writer.write(", "); writer.write(", ");
// TODO: does dalvik allow non-identifier parameter and/or local names? ReferenceFormatter.writeStringReference(writer, parameterName);
writer.write(parameterName);
} }
writer.write(" # "); writer.write(" # ");
writer.write(parameterType); writer.write(parameterType);

View File

@ -76,6 +76,11 @@ public class AnalysisTest {
runTest("DuplicateTest", false); runTest("DuplicateTest", false);
} }
@Test
public void LocalTest() throws IOException, URISyntaxException {
runTest("LocalTest", false);
}
public void runTest(String test, boolean registerInfo) throws IOException, URISyntaxException { public void runTest(String test, boolean registerInfo) throws IOException, URISyntaxException {
String dexFilePath = String.format("%s%sclasses.dex", test, File.separatorChar); String dexFilePath = String.format("%s%sclasses.dex", test, File.separatorChar);

View File

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

Binary file not shown.

View File

@ -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*/ add them to the $statements_and_directives::methodAnnotations list*/
parameter_directive parameter_directive
@init {List<CommonTree> annotations = new ArrayList<CommonTree>();} @init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
: PARAMETER_DIRECTIVE REGISTER COMMA simple_name : PARAMETER_DIRECTIVE REGISTER (COMMA STRING_LITERAL)?
({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})* ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
( END_PARAMETER_DIRECTIVE ( 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);} | /*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 ordered_debug_directive
@ -785,8 +785,10 @@ line_directive
-> ^(I_LINE[$start, "I_LINE"] integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]); -> ^(I_LINE[$start, "I_LINE"] integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
local_directive local_directive
: LOCAL_DIRECTIVE REGISTER COMMA simple_name COLON nonvoid_type_descriptor (COMMA STRING_LITERAL)? : LOCAL_DIRECTIVE REGISTER (COMMA (NULL_LITERAL | name=STRING_LITERAL) COLON (VOID_TYPE | nonvoid_type_descriptor)
-> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER simple_name nonvoid_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]); (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
: END_LOCAL_DIRECTIVE REGISTER : END_LOCAL_DIRECTIVE REGISTER

View File

@ -612,7 +612,7 @@ parameters[List<SmaliMethodParameter> parameters]
: ^(I_PARAMETERS (parameter[parameters])*); : ^(I_PARAMETERS (parameter[parameters])*);
parameter[List<SmaliMethodParameter> parameters] parameter[List<SmaliMethodParameter> parameters]
: ^(I_PARAMETER REGISTER SIMPLE_NAME annotations) : ^(I_PARAMETER REGISTER string_literal? annotations)
{ {
final int registerNumber = parseRegister_short($REGISTER.text); final int registerNumber = parseRegister_short($REGISTER.text);
int totalMethodRegisters = $method::totalMethodRegisters; int totalMethodRegisters = $method::totalMethodRegisters;
@ -639,7 +639,7 @@ parameter[List<SmaliMethodParameter> parameters]
} }
SmaliMethodParameter methodParameter = parameters.get(parameterIndex); SmaliMethodParameter methodParameter = parameters.get(parameterIndex);
methodParameter.name = $SIMPLE_NAME.text; methodParameter.name = $string_literal.value;
if ($annotations.annotations != null && $annotations.annotations.size() > 0) { if ($annotations.annotations != null && $annotations.annotations.size() > 0) {
methodParameter.annotations = $annotations.annotations; methodParameter.annotations = $annotations.annotations;
} }
@ -665,12 +665,12 @@ line returns[DebugItem debugItem]
}; };
local 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); int registerNumber = parseRegister_short($REGISTER.text);
$debugItem = new ImmutableStartLocal($address.address, registerNumber, $SIMPLE_NAME.text, $debugItem = new ImmutableStartLocal($address.address, registerNumber, $name.value,
$nonvoid_type_descriptor.type, $string_literal.value); $nonvoid_type_descriptor.type, $signature.value);
}; };
end_local returns[DebugItem debugItem] end_local returns[DebugItem debugItem]