Re-implement SyntheticAccessorResolver

This commit is contained in:
Ben Gruver 2012-11-04 22:54:06 -08:00
parent db389aa3a1
commit 2b8845bb24
14 changed files with 1820 additions and 31 deletions

1
.gitignore vendored
View File

@ -2,5 +2,6 @@
/baksmali/build
/dexlib/build
/dexlib2/build
/dexlib2/accessorTestGenerator/build
/smali/build
/util/build

View File

@ -33,12 +33,16 @@ import org.jf.baksmali.Adaptors.Debug.DebugMethodItem;
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.util.InstructionOffsetMap;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.dexlib2.util.SyntheticAccessorResolver;
import org.jf.dexlib2.util.TypeUtils;
import org.jf.util.IndentingWriter;
import org.jf.baksmali.baksmali;
@ -314,22 +318,21 @@ public class MethodDefinition {
});
}
//TODO: uncomment
/*if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
if (!baksmali.noAccessorComments && (instruction instanceof ReferenceInstruction)) {
Opcode opcode = instruction.getOpcode();
if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
MethodIdItem methodIdItem =
(MethodIdItem)((InstructionWithReference) instruction).getReferencedItem();
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodIdItem)) {
if (opcode.referenceType == ReferenceType.METHOD) {
MethodReference methodReference = (MethodReference)((ReferenceInstruction)instruction).getReference();
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
SyntheticAccessorResolver.AccessedMember accessedMember =
baksmali.syntheticAccessorResolver.getAccessedMember(methodIdItem);
baksmali.syntheticAccessorResolver.getAccessedMember(methodReference);
if (accessedMember != null) {
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
}
}
}
}*/
}
currentCodeAddress += instruction.getCodeUnits();
}

View File

@ -28,17 +28,17 @@
package org.jf.baksmali.Adaptors;
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
import static org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver.AccessedMember;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.util.SyntheticAccessorResolver;
import org.jf.util.ExceptionWithContext;
import org.jf.util.IndentingWriter;
import java.io.IOException;
//TODO: uncomment
/*public class SyntheticAccessCommentMethodItem extends MethodItem {
private final AccessedMember accessedMember;
public class SyntheticAccessCommentMethodItem extends MethodItem {
private final SyntheticAccessorResolver.AccessedMember accessedMember;
public SyntheticAccessCommentMethodItem(AccessedMember accessedMember, int codeAddress) {
public SyntheticAccessCommentMethodItem(SyntheticAccessorResolver.AccessedMember accessedMember, int codeAddress) {
super(codeAddress);
this.accessedMember = accessedMember;
}
@ -49,15 +49,73 @@ import java.io.IOException;
}
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write('#');
if (accessedMember.accessedMemberType == SyntheticAccessorResolver.METHOD) {
writer.write("calls: ");
} else if (accessedMember.accessedMemberType == SyntheticAccessorResolver.GETTER) {
writer.write("getter for: ");
} else {
writer.write("setter for: ");
writer.write("# ");
switch (accessedMember.accessedMemberType) {
case SyntheticAccessorResolver.METHOD:
writer.write("invokes: ");
break;
case SyntheticAccessorResolver.GETTER:
writer.write("getter for: ");
break;
case SyntheticAccessorResolver.SETTER:
writer.write("setter for: ");
break;
case SyntheticAccessorResolver.PREFIX_INCREMENT:
writer.write("++operator for: ");
break;
case SyntheticAccessorResolver.POSTFIX_INCREMENT:
writer.write("operator++ for: ");
break;
case SyntheticAccessorResolver.PREFIX_DECREMENT:
writer.write("--operator for: ");
break;
case SyntheticAccessorResolver.POSTFIX_DECREMENT:
writer.write("operator-- for: ");
break;
case SyntheticAccessorResolver.ADD_ASSIGNMENT:
writer.write("+= operator for: ");
break;
case SyntheticAccessorResolver.SUB_ASSIGNMENT:
writer.write("-= operator for: ");
break;
case SyntheticAccessorResolver.MUL_ASSIGNMENT:
writer.write("*= operator for: ");
break;
case SyntheticAccessorResolver.DIV_ASSIGNMENT:
writer.write("/= operator for: ");
break;
case SyntheticAccessorResolver.REM_ASSIGNMENT:
writer.write("%= operator for: ");
break;
case SyntheticAccessorResolver.AND_ASSIGNMENT:
writer.write("&= operator for: ");
break;
case SyntheticAccessorResolver.OR_ASSIGNMENT:
writer.write("|= operator for: ");
break;
case SyntheticAccessorResolver.XOR_ASSIGNMENT:
writer.write("^= operator for: ");
break;
case SyntheticAccessorResolver.SHL_ASSIGNMENT:
writer.write("<<= operator for: ");
break;
case SyntheticAccessorResolver.SHR_ASSIGNMENT:
writer.write(">>= operator for: ");
break;
case SyntheticAccessorResolver.USHR_ASSIGNMENT:
writer.write(">>>= operator for: ");
break;
default:
throw new ExceptionWithContext("Unknown access type: %d", accessedMember.accessedMemberType);
}
ReferenceFormatter.writeReference(writer, accessedMember.accessedMember);
int referenceType;
if (accessedMember.accessedMemberType == SyntheticAccessorResolver.METHOD) {
referenceType = ReferenceType.METHOD;
} else {
referenceType = ReferenceType.FIELD;
}
ReferenceFormatter.writeReference(writer, referenceType, accessedMember.accessedMember);
return true;
}
}*/
}

View File

@ -29,9 +29,10 @@
package org.jf.baksmali;
import org.jf.baksmali.Adaptors.ClassDefinition;
import org.jf.dexlib.Code.Analysis.*;
import org.jf.dexlib.Code.Analysis.InlineMethodResolver;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.util.SyntheticAccessorResolver;
import org.jf.util.ClassFileNameHandler;
import org.jf.util.IndentingWriter;
@ -118,10 +119,9 @@ public class baksmali {
}
}
//TODO: uncomment
/*if (!noAccessorComments) {
syntheticAccessorResolver = new SyntheticAccessorResolver(dexFile);
}*/
if (!noAccessorComments) {
syntheticAccessorResolver = new SyntheticAccessorResolver(dexFile.getClasses());
}
//sort the classes, so that if we're on a case-insensitive file system and need to handle classes with file
//name collisions, then we'll use the same name for each class, if the dex file goes through multiple
@ -146,7 +146,7 @@ public class baksmali {
* package name are separated by '/'
*/
String classDescriptor = classDef.getName();
String classDescriptor = classDef.getType();
//validate that the descriptor is formatted like we expect
if (classDescriptor.charAt(0) != 'L' ||

View File

@ -0,0 +1,39 @@
/*
* Copyright 2012, 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.
*/
dependencies {
compile project(':util')
compile 'com.google.code.findbugs:jsr305:1.3.9'
compile 'com.google.guava:guava:13.0.1'
compile 'org.antlr:stringtemplate:4.0.2'
testCompile 'junit:junit:4.6'
}

View File

@ -0,0 +1,141 @@
/*
* Copyright 2012, 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.dexlib2;
import org.stringtemplate.v4.*;
import java.io.*;
import java.net.URL;
public class AccessorTestGenerator {
private static class UnaryOperation {
public final String name;
public UnaryOperation(String name) {
this.name = name;
}
}
private static class BinaryOperation {
public final String name;
public final String[] inputTypes;
public BinaryOperation(String name, String[] inputTypes) {
this.name = name;
this.inputTypes = inputTypes;
}
}
private static class TypeDef {
public final String name;
public final UnaryOperation[] unaryOperations;
public final BinaryOperation[] binaryOperations;
public TypeDef(String name, UnaryOperation[] unaryOperations, BinaryOperation[] binaryOperations) {
this.name = name;
this.unaryOperations = unaryOperations;
this.binaryOperations = binaryOperations;
}
}
private static final UnaryOperation[] unaryOperations = new UnaryOperation[] {
new UnaryOperation("preinc"),
new UnaryOperation("postinc"),
new UnaryOperation("predec"),
new UnaryOperation("postdec")
};
private static final String[] booleanInputs = new String[] {"boolean"};
private static final String[] integralInputs = new String[] {"int", "long"};
private static final String[] allInputs = new String[] {"int", "float", "long", "double"};
private static final BinaryOperation[] booleanOperations = new BinaryOperation[] {
new BinaryOperation("and", booleanInputs),
new BinaryOperation("or", booleanInputs),
new BinaryOperation("xor", booleanInputs),
};
private static final BinaryOperation[] floatOperations = new BinaryOperation[] {
new BinaryOperation("add", allInputs),
new BinaryOperation("sub", allInputs),
new BinaryOperation("mul", allInputs),
new BinaryOperation("div", allInputs),
new BinaryOperation("rem", allInputs),
};
private static final BinaryOperation[] integralOperations = new BinaryOperation[] {
new BinaryOperation("add", allInputs),
new BinaryOperation("sub", allInputs),
new BinaryOperation("mul", allInputs),
new BinaryOperation("div", allInputs),
new BinaryOperation("rem", allInputs),
new BinaryOperation("and", integralInputs),
new BinaryOperation("or", integralInputs),
new BinaryOperation("xor", integralInputs),
new BinaryOperation("shl", integralInputs),
new BinaryOperation("shr", integralInputs),
new BinaryOperation("ushr", integralInputs),
};
private static final TypeDef[] types = new TypeDef[] {
new TypeDef("boolean", new UnaryOperation[0], booleanOperations),
new TypeDef("byte", unaryOperations, integralOperations),
new TypeDef("char", unaryOperations, integralOperations),
new TypeDef("short", unaryOperations, integralOperations),
new TypeDef("int", unaryOperations, integralOperations),
new TypeDef("long", unaryOperations, integralOperations),
new TypeDef("float", unaryOperations, floatOperations),
new TypeDef("double", unaryOperations, floatOperations),
};
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.err.println("Usage: java org.jf.dexlib2.AccessorTestGenerator <output_file>");
}
URL stgUrl = AccessorTestGenerator.class.getClassLoader().getResource("AccessorTest.stg");
STGroupFile stg = new STGroupFile(stgUrl, "utf-8", '<', '>');
ST fileSt = stg.getInstanceOf("file");
fileSt.add("types", types);
PrintWriter w = null;
try {
w = new PrintWriter(new BufferedWriter(new FileWriter(args[0])));
w.print(fileSt.render());
} finally {
if (w != null) {
w.close();
}
}
}
}

View File

@ -0,0 +1,86 @@
decl(type, name, value) ::= "<type> <name><init(value)>;"
init(v) ::= "<if(v)> = <v><endif>"
field_decl(type) ::= "private <type.name> <type.name>_val;"
preinc_template(type) ::= "++<type.name>_val;"
postinc_template(type) ::= "<type.name>_val++;"
predec_template(type) ::= "--<type.name>_val;"
postdec_template(type) ::= "<type.name>_val--;"
add_template(type) ::= "<type.name>_val += val;"
sub_template(type) ::= "<type.name>_val -= val;"
mul_template(type) ::= "<type.name>_val *= val;"
div_template(type) ::= "<type.name>_val /= val;"
rem_template(type) ::= "<type.name>_val %= val;"
and_template(type) ::= "<type.name>_val &= val;"
or_template(type) ::= "<type.name>_val |= val;"
xor_template(type) ::= "<type.name>_val ^= val;"
shl_template(type) ::= "<type.name>_val \<\<= val;"
shr_template(type) ::= "<type.name>_val >>= val;"
ushr_template(type) ::= "<type.name>_val >>>= val;"
operation_template_name(operation) ::= "<operation.name>_template"
binary_method(input, type, binary_operation) ::= <<
public void <type.name>_<binary_operation.name>(<input> val) {
<(operation_template_name(binary_operation))(type)>
}
>>
binary_methods(binary_operation, type) ::= <<
<binary_operation.inputTypes:binary_method(type, binary_operation);separator="\n\n">
>>
unary_method(unary_operation, type) ::= <<
public void <type.name>_<unary_operation.name>() {
<(operation_template_name(unary_operation))(type)>
}
>>
type_methods(type) ::= <<
<[type.unaryOperations:unary_method(type), type.binaryOperations:binary_methods(type)];separator="\n\n">
>>
file(types) ::= <<
/*
* Copyright 2012, 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.dexlib2;
public class AccessorTypes {
<types:field_decl();separator="\n">
private class Accessors {
<types:type_methods();separator="\n\n">
}
}
>>

View File

@ -29,10 +29,91 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
configurations {
accessorTestGenerator
}
dependencies {
compile project(':util')
compile 'com.google.code.findbugs:jsr305:1.3.9'
compile 'com.google.guava:guava:13.0.1'
testCompile 'junit:junit:4.6'
}
accessorTestGenerator project('accessorTestGenerator')
}
ext.testAccessorOutputDir = file("${buildDir}/generated-accessor-test-sources")
ext.testAccessorOutputFile = file("${buildDir}/generated-accessor-test-sources/org/jf/dexlib2/AccessorTypes.java")
sourceSets {
// The sources for building the test dex file for the accessor test
accessorTestDex {
java {
srcDir testAccessorOutputDir
}
}
// The sources for the accessor test itself
accessorTest {
java {
compileClasspath += main.output
runtimeClasspath += main.output
}
}
}
configurations {
accessorTestDexCompile.extendsFrom compile
accessorTestDexRuntime.extendsFrom runtime
accessorTestCompile.extendsFrom testCompile
accessorTestRuntime.extendsFrom testRuntime
}
idea {
module {
testSourceDirs += sourceSets.accessorTest.java.srcDirs
}
}
// You must manually execute this task to regenerate SyntheticAccessorFSM.java, after modifying the ragel file
// e.g. ./gradlew ragel
task ragel(type:Exec) {
workingDir = 'src/main/ragel'
commandLine 'ragel', '-J', '-o', file('src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java'),
'SyntheticAccessorFSM.rl'
}
task generateAccessorTestSource(type: JavaExec) {
outputs.dir file(testAccessorOutputDir)
mkdir(file(testAccessorOutputFile).parent)
classpath = configurations.accessorTestGenerator
main = 'org.jf.dexlib2.AccessorTestGenerator'
args testAccessorOutputFile
}
compileAccessorTestDexJava.dependsOn(generateAccessorTestSource)
task generateAccessorTestDex(type: Exec, dependsOn: compileAccessorTestDexJava) {
def outputDex = file("${sourceSets.accessorTest.output.resourcesDir}/accessorTest.dex")
mkdir(outputDex.parent)
inputs.dir project.sourceSets.accessorTestDex.output.classesDir
outputs.file outputDex
sourceSets.accessorTest.resources
workingDir project.sourceSets.accessorTestDex.output.classesDir
executable 'dx'
args '--dex'
args "--output=${outputDex}"
args '.'
}
task accessorTest(type: Test, dependsOn: generateAccessorTestDex) {
testClassesDir = project.sourceSets.accessorTest.output.classesDir
classpath = project.sourceSets.accessorTest.runtimeClasspath
}

View File

@ -0,0 +1,133 @@
/*
* Copyright 2012, 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.dexlib2;
import com.google.common.collect.ImmutableMap;
import junit.framework.Assert;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.util.SyntheticAccessorResolver;
import org.junit.Test;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AccessorTest {
private Pattern accessorMethodPattern = Pattern.compile("([a-zA-Z]*)_([a-zA-Z]*)");
private static final Map<String, Integer> operationTypes;
static {
ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder();
builder.put("postinc", SyntheticAccessorResolver.POSTFIX_INCREMENT);
builder.put("preinc", SyntheticAccessorResolver.PREFIX_INCREMENT);
builder.put("postdec", SyntheticAccessorResolver.POSTFIX_DECREMENT);
builder.put("predec", SyntheticAccessorResolver.PREFIX_DECREMENT);
builder.put("add", SyntheticAccessorResolver.ADD_ASSIGNMENT);
builder.put("sub", SyntheticAccessorResolver.SUB_ASSIGNMENT);
builder.put("mul", SyntheticAccessorResolver.MUL_ASSIGNMENT);
builder.put("div", SyntheticAccessorResolver.DIV_ASSIGNMENT);
builder.put("rem", SyntheticAccessorResolver.REM_ASSIGNMENT);
builder.put("and", SyntheticAccessorResolver.AND_ASSIGNMENT);
builder.put("or", SyntheticAccessorResolver.OR_ASSIGNMENT);
builder.put("xor", SyntheticAccessorResolver.XOR_ASSIGNMENT);
builder.put("shl", SyntheticAccessorResolver.SHL_ASSIGNMENT);
builder.put("shr", SyntheticAccessorResolver.SHR_ASSIGNMENT);
builder.put("ushr", SyntheticAccessorResolver.USHR_ASSIGNMENT);
operationTypes = builder.build();
}
@Test
public void testAccessors() throws IOException {
URL url = AccessorTest.class.getClassLoader().getResource("accessorTest.dex");
Assert.assertNotNull(url);
DexFile f = DexFileFactory.loadDexFile(url.getFile());
SyntheticAccessorResolver sar = new SyntheticAccessorResolver(f.getClasses());
ClassDef accessorTypesClass = null;
ClassDef accessorsClass = null;
for (ClassDef classDef: f.getClasses()) {
String className = classDef.getType();
if (className.equals("Lorg/jf/dexlib2/AccessorTypes;")) {
accessorTypesClass = classDef;
} else if (className.equals("Lorg/jf/dexlib2/AccessorTypes$Accessors;")) {
accessorsClass = classDef;
}
}
Assert.assertNotNull(accessorTypesClass);
Assert.assertNotNull(accessorsClass);
for (Method method: accessorsClass.getMethods()) {
Matcher m = accessorMethodPattern.matcher(method.getName());
if (!m.matches()) {
continue;
}
String type = m.group(1);
String operation = m.group(2);
MethodImplementation methodImpl = method.getImplementation();
Assert.assertNotNull(methodImpl);
for (Instruction instruction: methodImpl.getInstructions()) {
Opcode opcode = instruction.getOpcode();
if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
MethodReference accessorMethod =
(MethodReference)((ReferenceInstruction) instruction).getReference();
SyntheticAccessorResolver.AccessedMember accessedMember = sar.getAccessedMember(accessorMethod);
Assert.assertNotNull(String.format("Could not resolve accessor for %s_%s", type, operation),
accessedMember);
int operationType = operationTypes.get(operation);
Assert.assertEquals(operationType, accessedMember.accessedMemberType);
Assert.assertEquals(String.format("%s_val", type),
((FieldReference)accessedMember.accessedMember).getName());
}
}
}
}
}

View File

@ -0,0 +1,565 @@
// line 1 "SyntheticAccessorFSM.rl"
/*
* Copyright 2012, 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.dexlib2.util;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.formats.Instruction22b;
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction;
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction;
import java.util.List;
public class SyntheticAccessorFSM {
// line 43 "SyntheticAccessorFSM.rl"
// line 48 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
private static byte[] init__SyntheticAccessorFSM_actions_0()
{
return new byte [] {
0, 1, 0, 1, 1, 1, 2, 1, 13, 1, 14, 1,
15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 20, 1,
21, 1, 25, 2, 3, 7, 2, 4, 7, 2, 5, 7,
2, 6, 7, 2, 8, 12, 2, 9, 12, 2, 10, 12,
2, 11, 12, 2, 22, 23, 2, 22, 24, 2, 22, 25,
2, 22, 26, 2, 22, 27, 2, 22, 28
};
}
private static final byte _SyntheticAccessorFSM_actions[] = init__SyntheticAccessorFSM_actions_0();
private static short[] init__SyntheticAccessorFSM_key_offsets_0()
{
return new short [] {
0, 0, 12, 82, 98, 102, 104, 166, 172, 174, 180, 184,
190, 192, 196, 198, 201, 203
};
}
private static final short _SyntheticAccessorFSM_key_offsets[] = init__SyntheticAccessorFSM_key_offsets_0();
private static short[] init__SyntheticAccessorFSM_trans_keys_0()
{
return new short [] {
82, 88, 89, 95, 96, 102, 103, 109, 110, 114, 116, 120,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
169, 170, 171, 172, 173, 174, 175, 177, 179, 180, 181, 182,
183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 195,
196, 197, 198, 199, 201, 202, 203, 204, 206, 207, 208, 216,
15, 17, 18, 25, 129, 143, 144, 176, 178, 205, 144, 145,
155, 156, 166, 167, 171, 172, 176, 177, 187, 188, 198, 199,
203, 204, 89, 95, 103, 109, 15, 17, 145, 146, 147, 148,
149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
173, 174, 175, 177, 179, 180, 181, 182, 183, 184, 185, 186,
187, 188, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
201, 202, 203, 204, 206, 207, 144, 176, 178, 205, 89, 95,
103, 109, 129, 143, 15, 17, 89, 95, 103, 109, 129, 143,
89, 95, 103, 109, 89, 95, 103, 109, 129, 143, 15, 17,
89, 95, 103, 109, 15, 17, 14, 10, 12, 15, 17, 0
};
}
private static final short _SyntheticAccessorFSM_trans_keys[] = init__SyntheticAccessorFSM_trans_keys_0();
private static byte[] init__SyntheticAccessorFSM_single_lengths_0()
{
return new byte [] {
0, 0, 60, 16, 0, 0, 58, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0
};
}
private static final byte _SyntheticAccessorFSM_single_lengths[] = init__SyntheticAccessorFSM_single_lengths_0();
private static byte[] init__SyntheticAccessorFSM_range_lengths_0()
{
return new byte [] {
0, 6, 5, 0, 2, 1, 2, 3, 1, 3, 2, 3,
1, 2, 1, 1, 1, 0
};
}
private static final byte _SyntheticAccessorFSM_range_lengths[] = init__SyntheticAccessorFSM_range_lengths_0();
private static short[] init__SyntheticAccessorFSM_index_offsets_0()
{
return new short [] {
0, 0, 7, 73, 90, 93, 95, 156, 160, 162, 166, 169,
173, 175, 178, 180, 183, 185
};
}
private static final short _SyntheticAccessorFSM_index_offsets[] = init__SyntheticAccessorFSM_index_offsets_0();
private static byte[] init__SyntheticAccessorFSM_indicies_0()
{
return new byte [] {
0, 2, 0, 2, 3, 3, 1, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 9, 10, 11, 12, 13,
14, 15, 16, 17, 20, 21, 9, 10, 11, 22, 23, 9,
10, 11, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 10,
11, 22, 23, 10, 11, 24, 24, 4, 5, 6, 7, 9,
1, 25, 26, 27, 28, 29, 30, 31, 32, 25, 26, 27,
28, 29, 30, 31, 32, 1, 33, 33, 1, 34, 1, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 9,
10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 9, 10,
11, 22, 23, 9, 10, 11, 8, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 10, 11, 12, 13, 14, 15, 16,
17, 20, 21, 10, 11, 22, 23, 10, 11, 7, 9, 1,
35, 35, 36, 1, 37, 1, 35, 35, 38, 1, 35, 35,
1, 39, 39, 40, 1, 41, 1, 39, 39, 1, 42, 1,
44, 43, 1, 45, 1, 1, 0
};
}
private static final byte _SyntheticAccessorFSM_indicies[] = init__SyntheticAccessorFSM_indicies_0();
private static byte[] init__SyntheticAccessorFSM_trans_targs_0()
{
return new byte [] {
2, 0, 14, 15, 17, 3, 6, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
11, 4, 4, 4, 4, 4, 4, 4, 4, 5, 17, 8,
9, 17, 10, 12, 13, 17, 17, 16, 17, 17
};
}
private static final byte _SyntheticAccessorFSM_trans_targs[] = init__SyntheticAccessorFSM_trans_targs_0();
private static byte[] init__SyntheticAccessorFSM_trans_actions_0()
{
return new byte [] {
0, 0, 1, 0, 51, 3, 0, 27, 39, 7, 9, 11,
13, 15, 17, 19, 21, 23, 30, 42, 33, 45, 36, 48,
5, 27, 39, 30, 42, 33, 45, 36, 48, 1, 63, 1,
0, 66, 0, 1, 0, 60, 54, 0, 25, 57
};
}
private static final byte _SyntheticAccessorFSM_trans_actions[] = init__SyntheticAccessorFSM_trans_actions_0();
static final int SyntheticAccessorFSM_start = 1;
static final int SyntheticAccessorFSM_first_final = 17;
static final int SyntheticAccessorFSM_error = 0;
static final int SyntheticAccessorFSM_en_main = 1;
// line 44 "SyntheticAccessorFSM.rl"
// math type constants
public static final int ADD = SyntheticAccessorResolver.ADD_ASSIGNMENT;
public static final int SUB = SyntheticAccessorResolver.SUB_ASSIGNMENT;
public static final int MUL = SyntheticAccessorResolver.MUL_ASSIGNMENT;
public static final int DIV = SyntheticAccessorResolver.DIV_ASSIGNMENT;
public static final int REM = SyntheticAccessorResolver.REM_ASSIGNMENT;
public static final int AND = SyntheticAccessorResolver.AND_ASSIGNMENT;
public static final int OR = SyntheticAccessorResolver.OR_ASSIGNMENT;
public static final int XOR = SyntheticAccessorResolver.XOR_ASSIGNMENT;
public static final int SHL = SyntheticAccessorResolver.SHL_ASSIGNMENT;
public static final int SHR = SyntheticAccessorResolver.SHR_ASSIGNMENT;
public static final int USHR = SyntheticAccessorResolver.USHR_ASSIGNMENT;
public static final int INT = 0;
public static final int LONG = 1;
public static final int FLOAT = 2;
public static final int DOUBLE = 3;
public static final int POSITIVE_ONE = 1;
public static final int NEGATIVE_ONE = -1;
public static final int OTHER = 0;
public static int test(List<? extends Instruction> instructions) {
int accessorType = -1;
int cs, p = 0;
int pe = instructions.size();
// one of the math type constants representing the type of math operation being performed
int mathOp = -1;
// for increments an decrements, the type of value the math operation is on
int mathType = -1;
// for increments and decrements, the value of the constant that is used
long constantValue = 0;
// The source register for the put instruction
int putRegister = -1;
// The return register;
int returnRegister = -1;
// line 236 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
{
cs = SyntheticAccessorFSM_start;
}
// line 241 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
{
int _klen;
int _trans = 0;
int _acts;
int _nacts;
int _keys;
int _goto_targ = 0;
_goto: while (true) {
switch ( _goto_targ ) {
case 0:
if ( p == pe ) {
_goto_targ = 4;
continue _goto;
}
if ( cs == 0 ) {
_goto_targ = 5;
continue _goto;
}
case 1:
_match: do {
_keys = _SyntheticAccessorFSM_key_offsets[cs];
_trans = _SyntheticAccessorFSM_index_offsets[cs];
_klen = _SyntheticAccessorFSM_single_lengths[cs];
if ( _klen > 0 ) {
int _lower = _keys;
int _mid;
int _upper = _keys + _klen - 1;
while (true) {
if ( _upper < _lower )
break;
_mid = _lower + ((_upper-_lower) >> 1);
if ( ( instructions.get(p).getOpcode().value) < _SyntheticAccessorFSM_trans_keys[_mid] )
_upper = _mid - 1;
else if ( ( instructions.get(p).getOpcode().value) > _SyntheticAccessorFSM_trans_keys[_mid] )
_lower = _mid + 1;
else {
_trans += (_mid - _keys);
break _match;
}
}
_keys += _klen;
_trans += _klen;
}
_klen = _SyntheticAccessorFSM_range_lengths[cs];
if ( _klen > 0 ) {
int _lower = _keys;
int _mid;
int _upper = _keys + (_klen<<1) - 2;
while (true) {
if ( _upper < _lower )
break;
_mid = _lower + (((_upper-_lower) >> 1) & ~1);
if ( ( instructions.get(p).getOpcode().value) < _SyntheticAccessorFSM_trans_keys[_mid] )
_upper = _mid - 2;
else if ( ( instructions.get(p).getOpcode().value) > _SyntheticAccessorFSM_trans_keys[_mid+1] )
_lower = _mid + 2;
else {
_trans += ((_mid - _keys)>>1);
break _match;
}
}
_trans += _klen;
}
} while (false);
_trans = _SyntheticAccessorFSM_indicies[_trans];
cs = _SyntheticAccessorFSM_trans_targs[_trans];
if ( _SyntheticAccessorFSM_trans_actions[_trans] != 0 ) {
_acts = _SyntheticAccessorFSM_trans_actions[_trans];
_nacts = (int) _SyntheticAccessorFSM_actions[_acts++];
while ( _nacts-- > 0 )
{
switch ( _SyntheticAccessorFSM_actions[_acts++] )
{
case 0:
// line 94 "SyntheticAccessorFSM.rl"
{
putRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
}
break;
case 1:
// line 101 "SyntheticAccessorFSM.rl"
{
constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
}
break;
case 2:
// line 105 "SyntheticAccessorFSM.rl"
{
mathType = INT;
mathOp = ADD;
constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
}
break;
case 3:
// line 111 "SyntheticAccessorFSM.rl"
{ mathType = INT; }
break;
case 4:
// line 112 "SyntheticAccessorFSM.rl"
{ mathType = LONG; }
break;
case 5:
// line 113 "SyntheticAccessorFSM.rl"
{ mathType = FLOAT; }
break;
case 6:
// line 114 "SyntheticAccessorFSM.rl"
{mathType = DOUBLE; }
break;
case 7:
// line 114 "SyntheticAccessorFSM.rl"
{
mathOp = ADD;
}
break;
case 8:
// line 117 "SyntheticAccessorFSM.rl"
{ mathType = INT; }
break;
case 9:
// line 118 "SyntheticAccessorFSM.rl"
{ mathType = LONG; }
break;
case 10:
// line 119 "SyntheticAccessorFSM.rl"
{ mathType = FLOAT; }
break;
case 11:
// line 120 "SyntheticAccessorFSM.rl"
{mathType = DOUBLE; }
break;
case 12:
// line 120 "SyntheticAccessorFSM.rl"
{
mathOp = SUB;
}
break;
case 13:
// line 124 "SyntheticAccessorFSM.rl"
{
mathOp = MUL;
}
break;
case 14:
// line 128 "SyntheticAccessorFSM.rl"
{
mathOp = DIV;
}
break;
case 15:
// line 132 "SyntheticAccessorFSM.rl"
{
mathOp = REM;
}
break;
case 16:
// line 135 "SyntheticAccessorFSM.rl"
{
mathOp = AND;
}
break;
case 17:
// line 138 "SyntheticAccessorFSM.rl"
{
mathOp = OR;
}
break;
case 18:
// line 141 "SyntheticAccessorFSM.rl"
{
mathOp = XOR;
}
break;
case 19:
// line 144 "SyntheticAccessorFSM.rl"
{
mathOp = SHL;
}
break;
case 20:
// line 147 "SyntheticAccessorFSM.rl"
{
mathOp = SHR;
}
break;
case 21:
// line 150 "SyntheticAccessorFSM.rl"
{
mathOp = USHR;
}
break;
case 22:
// line 156 "SyntheticAccessorFSM.rl"
{
returnRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
}
break;
case 23:
// line 162 "SyntheticAccessorFSM.rl"
{
accessorType = SyntheticAccessorResolver.GETTER; { p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
case 24:
// line 166 "SyntheticAccessorFSM.rl"
{
accessorType = SyntheticAccessorResolver.SETTER; { p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
case 25:
// line 170 "SyntheticAccessorFSM.rl"
{
accessorType = SyntheticAccessorResolver.METHOD; { p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
case 26:
// line 174 "SyntheticAccessorFSM.rl"
{
accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
}
break;
case 27:
// line 178 "SyntheticAccessorFSM.rl"
{
accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
}
break;
case 28:
// line 186 "SyntheticAccessorFSM.rl"
{
accessorType = mathOp; { p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
// line 481 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
}
}
}
case 2:
if ( cs == 0 ) {
_goto_targ = 5;
continue _goto;
}
if ( ++p != pe ) {
_goto_targ = 1;
continue _goto;
}
case 4:
case 5:
}
break; }
}
// line 199 "SyntheticAccessorFSM.rl"
return accessorType;
}
private static int getIncrementType(int mathOp, int mathType, long constantValue, int putRegister,
int returnRegister) {
boolean isPrefix = putRegister == returnRegister;
boolean negativeConstant = false;
switch (mathType) {
case INT:
case LONG: {
if (constantValue == 1) {
negativeConstant = false;
} else if (constantValue == -1) {
negativeConstant = true;
} else {
return -1;
}
break;
}
case FLOAT: {
float val = Float.intBitsToFloat((int)constantValue);
if (val == 1) {
negativeConstant = false;
} else if (val == -1) {
negativeConstant = true;
} else {
return -1;
}
break;
}
case DOUBLE: {
double val = Double.longBitsToDouble(constantValue);
if (val == 1) {
negativeConstant = false;
} else if (val == -1) {
negativeConstant = true;
} else {
return -1;
}
break;
}
}
boolean isAdd = ((mathOp == ADD) && !negativeConstant) ||
((mathOp == SUB) && negativeConstant);
if (isPrefix) {
if (isAdd) {
return SyntheticAccessorResolver.PREFIX_INCREMENT;
} else {
return SyntheticAccessorResolver.PREFIX_DECREMENT;
}
} else {
if (isAdd) {
return SyntheticAccessorResolver.POSTFIX_INCREMENT;
} else {
return SyntheticAccessorResolver.POSTFIX_DECREMENT;
}
}
}
}

View File

@ -0,0 +1,173 @@
/*
* Copyright 2012, 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.dexlib2.util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class SyntheticAccessorResolver {
public static final int METHOD = 0;
public static final int GETTER = 1;
public static final int SETTER = 2;
public static final int POSTFIX_INCREMENT = 3;
public static final int PREFIX_INCREMENT = 4;
public static final int POSTFIX_DECREMENT = 5;
public static final int PREFIX_DECREMENT = 6;
public static final int ADD_ASSIGNMENT = 7;
public static final int SUB_ASSIGNMENT = 8;
public static final int MUL_ASSIGNMENT = 9;
public static final int DIV_ASSIGNMENT = 10;
public static final int REM_ASSIGNMENT = 11;
public static final int AND_ASSIGNMENT = 12;
public static final int OR_ASSIGNMENT = 13;
public static final int XOR_ASSIGNMENT = 14;
public static final int SHL_ASSIGNMENT = 15;
public static final int SHR_ASSIGNMENT = 16;
public static final int USHR_ASSIGNMENT = 17;
//TODO: use a hashmap for the classes?
private final Map<String, ClassDef> classDefMap;
private final HashMap<String, AccessedMember> resolvedAccessors = new HashMap<String, AccessedMember>();
public SyntheticAccessorResolver(List<? extends ClassDef> classDefs) {
ImmutableMap.Builder<String, ClassDef> builder = ImmutableMap.builder();
for (ClassDef classDef: classDefs) {
builder.put(classDef.getType(), classDef);
}
this.classDefMap = builder.build();
}
public static boolean looksLikeSyntheticAccessor(String methodName) {
return methodName.startsWith("access$");
}
@Nullable
public AccessedMember getAccessedMember(@Nonnull MethodReference methodReference) {
String methodDescriptor = ReferenceUtil.getMethodDescriptor(methodReference);
AccessedMember accessedMember = resolvedAccessors.get(methodDescriptor);
if (accessedMember != null) {
return accessedMember;
}
String type = methodReference.getContainingClass();
ClassDef classDef = classDefMap.get(type);
if (classDef == null) {
return null;
}
Method matchedMethod = null;
MethodImplementation matchedMethodImpl = null;
for (Method method: classDef.getMethods()) {
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
if (methodReferenceEquals(method, methodReference)) {
matchedMethod = method;
matchedMethodImpl = methodImpl;
break;
}
}
}
if (matchedMethod == null) {
return null;
}
//A synthetic accessor will be marked synthetic
if (!AccessFlags.SYNTHETIC.isSet(matchedMethod.getAccessFlags())) {
return null;
}
List<Instruction> instructions = ImmutableList.copyOf(matchedMethodImpl.getInstructions());
int accessType = SyntheticAccessorFSM.test(instructions);
byte b = 0;
double l = 12341234.567;
b += l;
if (accessType >= 0) {
return new AccessedMember(accessType, ((ReferenceInstruction)instructions.get(0)).getReference());
}
return null;
}
public static class AccessedMember {
public final int accessedMemberType;
@Nonnull public final Reference accessedMember;
public AccessedMember(int accessedMemberType, @Nonnull Reference accessedMember) {
this.accessedMemberType = accessedMemberType;
this.accessedMember = accessedMember;
}
@Override
public int hashCode() {
switch (accessedMemberType) {
case METHOD:
}
return super.hashCode(); //To change body of overridden methods use File | Settings | File Templates.
}
}
private static boolean methodReferenceEquals(@Nonnull MethodReference ref1, @Nonnull MethodReference ref2) {
// we already know the containing class matches
if ((!ref1.getName().equals(ref2.getName())) ||
(!ref1.getReturnType().equals(ref2.getReturnType()))) {
return false;
}
Iterator<? extends BasicMethodParameter> params1 = ref1.getParameters().iterator();
Iterator<? extends BasicMethodParameter> params2 = ref2.getParameters().iterator();
while (params1.hasNext() && params2.hasNext()) {
if (!params1.next().getType().equals(params2.next().getType())) {
return false;
}
}
return (!params1.hasNext()) && (!params2.hasNext());
}
}

View File

@ -0,0 +1,246 @@
define nop 0
define move 1
define move_from16 2
define move_16 3
define move_wide 4
define move_wide_from16 5
define move_wide_16 6
define move_object 7
define move_object_from16 8
define move_object_16 9
define move_result 10
define move_result_wide 11
define move_result_object 12
define move_exception 13
define return_void 14
define return 15
define return_wide 16
define return_object 17
define const_4 18
define const_16 19
define const 20
define const_high16 21
define const_wide_16 22
define const_wide_32 23
define const_wide 24
define const_wide_high16 25
define const_string 26
define const_string_jumbo 27
define const_class 28
define monitor_enter 29
define monitor_exit 30
define check_cast 31
define instance_of 32
define array_length 33
define new_instance 34
define new_array 35
define filled_new_array 36
define filled_new_array_range 37
define fill_array_data 38
define throw 39
define goto 40
define goto_16 41
define goto_32 42
define packed_switch 43
define sparse_switch 44
define cmpl_float 45
define cmpg_float 46
define cmpl_double 47
define cmpg_double 48
define cmp_long 49
define if_eq 50
define if_ne 51
define if_lt 52
define if_ge 53
define if_gt 54
define if_le 55
define if_eqz 56
define if_nez 57
define if_ltz 58
define if_gez 59
define if_gtz 60
define if_lez 61
define aget 68
define aget_wide 69
define aget_object 70
define aget_boolean 71
define aget_byte 72
define aget_char 73
define aget_short 74
define aput 75
define aput_wide 76
define aput_object 77
define aput_boolean 78
define aput_byte 79
define aput_char 80
define aput_short 81
define iget 82
define iget_wide 83
define iget_object 84
define iget_boolean 85
define iget_byte 86
define iget_char 87
define iget_short 88
define iput 89
define iput_wide 90
define iput_object 91
define iput_boolean 92
define iput_byte 93
define iput_char 94
define iput_short 95
define sget 96
define sget_wide 97
define sget_object 98
define sget_boolean 99
define sget_byte 100
define sget_char 101
define sget_short 102
define sput 103
define sput_wide 104
define sput_object 105
define sput_boolean 106
define sput_byte 107
define sput_char 108
define sput_short 109
define invoke_virtual 110
define invoke_super 111
define invoke_direct 112
define invoke_static 113
define invoke_interface 114
define invoke_virtual_range 116
define invoke_super_range 117
define invoke_direct_range 118
define invoke_static_range 119
define invoke_interface_range 120
define neg_int 123
define not_int 124
define neg_long 125
define not_long 126
define neg_float 127
define neg_double 128
define int_to_long 129
define int_to_float 130
define int_to_double 131
define long_to_int 132
define long_to_float 133
define long_to_double 134
define float_to_int 135
define float_to_long 136
define float_to_double 137
define double_to_int 138
define double_to_long 139
define double_to_float 140
define int_to_byte 141
define int_to_char 142
define int_to_short 143
define add_int 144
define sub_int 145
define mul_int 146
define div_int 147
define rem_int 148
define and_int 149
define or_int 150
define xor_int 151
define shl_int 152
define shr_int 153
define ushr_int 154
define add_long 155
define sub_long 156
define mul_long 157
define div_long 158
define rem_long 159
define and_long 160
define or_long 161
define xor_long 162
define shl_long 163
define shr_long 164
define ushr_long 165
define add_float 166
define sub_float 167
define mul_float 168
define div_float 169
define rem_float 170
define add_double 171
define sub_double 172
define mul_double 173
define div_double 174
define rem_double 175
define add_int_2addr 176
define sub_int_2addr 177
define mul_int_2addr 178
define div_int_2addr 179
define rem_int_2addr 180
define and_int_2addr 181
define or_int_2addr 182
define xor_int_2addr 183
define shl_int_2addr 184
define shr_int_2addr 185
define ushr_int_2addr 186
define add_long_2addr 187
define sub_long_2addr 188
define mul_long_2addr 189
define div_long_2addr 190
define rem_long_2addr 191
define and_long_2addr 192
define or_long_2addr 193
define xor_long_2addr 194
define shl_long_2addr 195
define shr_long_2addr 196
define ushr_long_2addr 197
define add_float_2addr 198
define sub_float_2addr 199
define mul_float_2addr 200
define div_float_2addr 201
define rem_float_2addr 202
define add_double_2addr 203
define sub_double_2addr 204
define mul_double_2addr 205
define div_double_2addr 206
define rem_double_2addr 207
define add_int_lit16 208
define rsub_int 209
define mul_int_lit16 210
define div_int_lit16 211
define rem_int_lit16 212
define and_int_lit16 213
define or_int_lit16 214
define xor_int_lit16 215
define add_int_lit8 216
define rsub_int_lit8 217
define mul_int_lit8 218
define div_int_lit8 219
define rem_int_lit8 220
define and_int_lit8 221
define or_int_lit8 222
define xor_int_lit8 223
define shl_int_lit8 224
define shr_int_lit8 225
define ushr_int_lit8 226
define iget_volatile 227
define iput_volatile 228
define sget_volatile 229
define sput_volatile 230
define iget_object_volatile 231
define iget_wide_volatile 232
define iput_wide_volatile 233
define sget_wide_volatile 234
define sput_wide_volatile 235
define throw_verification_error 237
define execute_inline 238
define execute_inline_range 239
define invoke_direct_empty 240
define invoke_object_init_range 240
define return_void_barrier 241
define iget_quick 242
define iget_wide_quick 243
define iget_object_quick 244
define iput_quick 245
define iput_wide_quick 246
define iput_object_quick 247
define invoke_virtual_quick 248
define invoke_virtual_quick_range 249
define invoke_super_quick 250
define invoke_super_quick_range 251
define iput_object_volatile 252
define sget_object_volatile 253
define sput_object_volatile 254

View File

@ -0,0 +1,263 @@
/*
* Copyright 2012, 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.dexlib2.util;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.formats.Instruction22b;
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction;
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction;
import java.util.List;
public class SyntheticAccessorFSM {
%% machine SyntheticAccessorFSM;
%% write data;
// math type constants
public static final int ADD = SyntheticAccessorResolver.ADD_ASSIGNMENT;
public static final int SUB = SyntheticAccessorResolver.SUB_ASSIGNMENT;
public static final int MUL = SyntheticAccessorResolver.MUL_ASSIGNMENT;
public static final int DIV = SyntheticAccessorResolver.DIV_ASSIGNMENT;
public static final int REM = SyntheticAccessorResolver.REM_ASSIGNMENT;
public static final int AND = SyntheticAccessorResolver.AND_ASSIGNMENT;
public static final int OR = SyntheticAccessorResolver.OR_ASSIGNMENT;
public static final int XOR = SyntheticAccessorResolver.XOR_ASSIGNMENT;
public static final int SHL = SyntheticAccessorResolver.SHL_ASSIGNMENT;
public static final int SHR = SyntheticAccessorResolver.SHR_ASSIGNMENT;
public static final int USHR = SyntheticAccessorResolver.USHR_ASSIGNMENT;
public static final int INT = 0;
public static final int LONG = 1;
public static final int FLOAT = 2;
public static final int DOUBLE = 3;
public static final int POSITIVE_ONE = 1;
public static final int NEGATIVE_ONE = -1;
public static final int OTHER = 0;
public static int test(List<? extends Instruction> instructions) {
int accessorType = -1;
int cs, p = 0;
int pe = instructions.size();
// one of the math type constants representing the type of math operation being performed
int mathOp = -1;
// for increments an decrements, the type of value the math operation is on
int mathType = -1;
// for increments and decrements, the value of the constant that is used
long constantValue = 0;
// The source register for the put instruction
int putRegister = -1;
// The return register;
int returnRegister = -1;
%%{
import "Opcodes.rl";
alphtype short;
getkey instructions.get(p).getOpcode().value;
get = (0x52 .. 0x58) | (0x60 .. 0x66); # all igets/sgets
# all iputs/sputs
put = ((0x59 .. 0x5f) | (0x67 .. 0x6d)) @ {
putRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
};
invoke = (0x6e .. 0x72) | (0x74 .. 0x78); # all invokes
# all numeric const instructions
const_literal = (0x12 .. 0x19) @ {
constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
};
add_const = (add_int_lit8 | add_int_lit16) @ {
mathType = INT;
mathOp = ADD;
constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
};
arbitrary_add = (((add_int | add_int_2addr) @ { mathType = INT; }) |
((add_long | add_long_2addr) @ { mathType = LONG; }) |
((add_float | add_float_2addr) @ { mathType = FLOAT; }) |
((add_double | add_double_2addr) @ {mathType = DOUBLE; })) @ {
mathOp = ADD;
};
arbitrary_sub = (((sub_int | sub_int_2addr) @ { mathType = INT; }) |
((sub_long | sub_long_2addr) @ { mathType = LONG; }) |
((sub_float | sub_float_2addr) @ { mathType = FLOAT; }) |
((sub_double | sub_double_2addr) @ {mathType = DOUBLE; })) @ {
mathOp = SUB;
};
arbitrary_mul = (mul_int | mul_int_2addr | mul_long | mul_long_2addr |
mul_float | mul_float_2addr | mul_double | mul_double_2addr) @ {
mathOp = MUL;
};
arbitrary_div = (div_int | div_int_2addr | div_long | div_long_2addr |
div_float | div_float_2addr | div_double | div_double_2addr) @ {
mathOp = DIV;
};
arbitrary_rem = (rem_int | rem_int_2addr | rem_long | rem_long_2addr |
rem_float | rem_float_2addr | rem_double | rem_double_2addr) @ {
mathOp = REM;
};
arbitrary_and = (and_int | and_int_2addr | and_long | and_long_2addr) @ {
mathOp = AND;
};
arbitrary_or = (or_int | or_int_2addr | or_long | or_long_2addr) @ {
mathOp = OR;
};
arbitrary_xor = (xor_int | xor_int_2addr | xor_long | xor_long_2addr) @ {
mathOp = XOR;
};
arbitrary_shl = (shl_int | shl_int_2addr | shl_long | shl_long_2addr) @ {
mathOp = SHL;
};
arbitrary_shr = (shr_int | shr_int_2addr | shr_long | shr_long_2addr) @ {
mathOp = SHR;
};
arbitrary_ushr = (ushr_int | ushr_int_2addr | ushr_long | ushr_long_2addr) @ {
mathOp = USHR;
};
type_conversion = 0x81 .. 0x8f; # all type-conversion opcodes
return_something = (return | return_wide | return_object) @ {
returnRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
};
any_move_result = move_result | move_result_wide | move_result_object;
get_accessor = get return_something @ {
accessorType = SyntheticAccessorResolver.GETTER; fbreak;
};
put_accessor = put return_something @ {
accessorType = SyntheticAccessorResolver.SETTER; fbreak;
};
invoke_accessor = invoke (return_void | (any_move_result return_something)) @ {
accessorType = SyntheticAccessorResolver.METHOD; fbreak;
};
increment_accessor = get add_const type_conversion? put return_something @ {
accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
};
alt_increment_accessor = get const_literal (arbitrary_add | arbitrary_sub) put return_something @ {
accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
};
math_assignment_accessor = get type_conversion?
(arbitrary_add | arbitrary_sub | arbitrary_mul | arbitrary_div | arbitrary_rem |
arbitrary_and | arbitrary_or | arbitrary_xor | arbitrary_shl | arbitrary_shr |
arbitrary_ushr)
type_conversion{0,2} put return_something @ {
accessorType = mathOp; fbreak;
};
main := get_accessor |
put_accessor |
invoke_accessor |
increment_accessor |
alt_increment_accessor |
math_assignment_accessor;
write init;
write exec;
}%%
return accessorType;
}
private static int getIncrementType(int mathOp, int mathType, long constantValue, int putRegister,
int returnRegister) {
boolean isPrefix = putRegister == returnRegister;
boolean negativeConstant = false;
switch (mathType) {
case INT:
case LONG: {
if (constantValue == 1) {
negativeConstant = false;
} else if (constantValue == -1) {
negativeConstant = true;
} else {
return -1;
}
break;
}
case FLOAT: {
float val = Float.intBitsToFloat((int)constantValue);
if (val == 1) {
negativeConstant = false;
} else if (val == -1) {
negativeConstant = true;
} else {
return -1;
}
break;
}
case DOUBLE: {
double val = Double.longBitsToDouble(constantValue);
if (val == 1) {
negativeConstant = false;
} else if (val == -1) {
negativeConstant = true;
} else {
return -1;
}
break;
}
}
boolean isAdd = ((mathOp == ADD) && !negativeConstant) ||
((mathOp == SUB) && negativeConstant);
if (isPrefix) {
if (isAdd) {
return SyntheticAccessorResolver.PREFIX_INCREMENT;
} else {
return SyntheticAccessorResolver.PREFIX_DECREMENT;
}
} else {
if (isAdd) {
return SyntheticAccessorResolver.POSTFIX_INCREMENT;
} else {
return SyntheticAccessorResolver.POSTFIX_DECREMENT;
}
}
}
}

View File

@ -1 +1 @@
include 'util', 'dexlib', 'dexlib2', 'baksmali', 'smali'
include 'util', 'dexlib', 'dexlib2', 'baksmali', 'smali', 'dexlib2:accessorTestGenerator'