# HG changeset patch # User forax # Date 1301649349 -7200 # Node ID cf71c6ab82fcef13a35ffa9b8831939e6dfc887d # Parent 19915795c08c2bc34fca5570bb4b0e291355771e Add a flag daneel.verify to enable post verification of DEX to bytecode translation diff -r 19915795c08c -r cf71c6ab82fc src/main/java/org/icedrobot/daneel/loader/DaneelClassLoader.java --- a/src/main/java/org/icedrobot/daneel/loader/DaneelClassLoader.java Thu Mar 31 00:54:29 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/loader/DaneelClassLoader.java Fri Apr 01 11:15:49 2011 +0200 @@ -40,6 +40,7 @@ import java.io.File; import java.io.IOError; import java.io.IOException; +import java.io.PrintWriter; import java.net.URL; import java.util.ArrayList; import java.util.zip.ZipEntry; @@ -117,6 +118,9 @@ for (DexFile dexFile : dexFiles) { try { byte[] bytecode = DexRewriter.rewrite(name, dexFile); + if (VERIFY) { + Verifier.verify(this, dexFile, name, bytecode, new PrintWriter(System.err)); + } return defineClass(name, bytecode, 0, bytecode.length); } catch (ClassNotFoundException e) { // Ignore and skip to the next file. @@ -208,4 +212,9 @@ } return apks.toArray(new ApkFile[apks.size()]); } + + private static final boolean VERIFY; + static { + VERIFY = Boolean.getBoolean("daneel.verify"); + } } diff -r 19915795c08c -r cf71c6ab82fc src/main/java/org/icedrobot/daneel/loader/Verifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/icedrobot/daneel/loader/Verifier.java Fri Apr 01 11:15:49 2011 +0200 @@ -0,0 +1,478 @@ +/* + * Daneel - Dalvik to Java bytecode compiler + * Copyright (C) 2011 IcedRobot team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file is subject to the "Classpath" exception: + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under terms + * of your choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from or based on + * this library. If you modify this library, you may extend this exception + * to your version of the library, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. + */ + +/* + * A non negligible part of this code comes from a code + * that can be found in ASM's class file CheckClassAdapter.java. + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2007 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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.icedrobot.daneel.loader; + +import java.io.PrintWriter; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import org.icedrobot.daneel.dex.DexAnnotationVisitor; +import org.icedrobot.daneel.dex.DexClassVisitor; +import org.icedrobot.daneel.dex.DexFieldVisitor; +import org.icedrobot.daneel.dex.DexFile; +import org.icedrobot.daneel.dex.DexMethodVisitor; +import org.icedrobot.daneel.dex.DexReader; +import org.icedrobot.daneel.dex.Label; +import org.icedrobot.daneel.dex.Opcode; +import org.icedrobot.daneel.rewriter.DexRewriter.MethodRewriter; +import org.icedrobot.daneel.rewriter.Interpreter; +import org.icedrobot.daneel.util.TypeUtil; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.EmptyVisitor; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TryCatchBlockNode; +import org.objectweb.asm.tree.analysis.Analyzer; +import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.analysis.SimpleVerifier; +import org.objectweb.asm.util.CheckClassAdapter; +import org.objectweb.asm.util.TraceMethodVisitor; + +class Verifier { + public static void verify(ClassLoader classloader, DexFile dexFile, String className, byte[] bytecode, PrintWriter writer) { + ClassReader reader = new ClassReader(bytecode); + ClassNode node = new ClassNode(); + reader.accept(new CheckClassAdapter(node, false), + ClassReader.SKIP_DEBUG); + + Type superType = (node.superName == null) ? null : Type + .getObjectType(node.superName); + + @SuppressWarnings("unchecked") + List interfaces = node.interfaces; + Type[] interfazes = new Type[interfaces.size()]; + for (int i = 0; i < interfazes.length; i++) { + interfazes[i] = Type.getObjectType(interfaces.get(i)); + } + + @SuppressWarnings("unchecked") + List methods = node.methods; + String internalName = node.name; + for (int i = 0; i < methods.size(); i++) { + MethodNode method = methods.get(i); + SimpleVerifier verifier = new SimpleVerifier( + Type.getObjectType(internalName), + superType, + Arrays.asList(interfazes), + (node.access & ~Opcodes.ACC_INTERFACE) != 0); + Analyzer analyzer = new Analyzer(verifier); + verifier.setClassLoader(classloader); + + try { + analyzer.analyze(internalName, method); + } catch (Exception e) { + dump(dexFile, className, method, analyzer, writer); + e.printStackTrace(writer); + } + } + writer.flush(); + } + + private static void dump(DexFile dexFile, final String className, final MethodNode method, + Analyzer analyzer, final PrintWriter writer) { + writer.println("--- DEX bytecode"); + try { + dexFile.accept("L" + className.replace('.', '/') + ";", new DexClassVisitor() { + @Override + public void visit(int access, String name, String supername, + String[] interfaces) { + // nothing + } + + @Override + public void visitSource(String source) { + // nothing + } + + @Override + public DexAnnotationVisitor visitAnnotation(int visibility, String type) { + return null; + } + + @Override + public DexMethodVisitor visitMethod(int access, String name, String shorty, + String returnType, String[] parameterTypes) { + + String desc = TypeUtil.convertProtoToDesc(returnType, parameterTypes); + if (!name.equals(method.name) || !desc.equals(method.desc)) { + return null; + } + + final MethodRewriter mv = new MethodRewriter(new EmptyVisitor(), + (access & Opcodes.ACC_STATIC) != 0, + desc); + + writer.println(className+'.'+method.name + method.desc); + return new DexMethodVisitor() { + private final HashMap labelMap = + new HashMap(); + private final StringBuilder builder = new StringBuilder(); + + private String getLabel(Label label) { + String text = labelMap.get(label); + if (text != null) { + return text; + } + text = "L" + labelMap.size(); + labelMap.put(label, text); + return text; + } + + private void dumpRegisters() { + StringBuilder registerBuilder = new StringBuilder(); + Interpreter interpreter = mv.getInterpreter(); + for(int i=0; i joinPointMap = new HashMap(); private boolean isDead; @@ -57,7 +55,7 @@ * * @param registers The array of registers to handle. */ - Interpreter(Register[] registers) { + public Interpreter(Register[] registers) { this.registers = registers; } @@ -70,6 +68,15 @@ public Register getRegister(int vregister) { return registers[vregister]; } + + /** + * Returns the number of virtual registers. + * + * @return the number of virtual registers managed by the current interpreter. + */ + public int getRegisterCount() { + return registers.length; + } /** * Tracks a load operation on the given register. The expected type has to diff -r 19915795c08c -r cf71c6ab82fc src/main/java/org/icedrobot/daneel/rewriter/Main.java --- a/src/main/java/org/icedrobot/daneel/rewriter/Main.java Thu Mar 31 00:54:29 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Main.java Fri Apr 01 11:15:49 2011 +0200 @@ -39,16 +39,11 @@ import java.io.File; import java.io.IOException; -import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; -import org.icedrobot.daneel.dex.DexFile; -import org.icedrobot.daneel.dex.DexReader; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.util.CheckClassAdapter; +import org.icedrobot.daneel.loader.DaneelClassLoader; /** * Run: java -cp classes:lib/smali-1.2.6.jar:lib/asm-debug-all-4.0.jar @@ -58,23 +53,11 @@ public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException { - final DexReader dexReader = DexFile.parse(new File(args[0])); - ClassLoader classLoader = new ClassLoader() { - @Override - protected Class findClass(String name) - throws ClassNotFoundException { - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); - dexReader.accept('L'+name.replace('.', '/')+';', new DexRewriter(writer), 0); - byte[] array = writer.toByteArray(); - - CheckClassAdapter.verify(new ClassReader(array), true, - new PrintWriter(System.err)); - - return defineClass(name, array, 0, array.length); - } - }; - + // enable verification by default + System.setProperty("daneel.verify", "true"); + + ClassLoader classLoader = new DaneelClassLoader(Main.class.getClassLoader(), new File(args[0])); Class clazz = classLoader.loadClass(args[1]); Method method = clazz.getMethod("main", String[].class); try { diff -r 19915795c08c -r cf71c6ab82fc src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java --- a/src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java Thu Mar 31 00:54:29 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java Fri Apr 01 11:15:49 2011 +0200 @@ -118,6 +118,13 @@ } return methodNode.instructions.getLast(); } + + public void addNode(AbstractInsnNode node) { + if (methodNode == null) { + throw new IllegalStateException("patchMode is not activated"); + } + methodNode.instructions.add(node); + } public void patch(AbstractInsnNode node, AbstractInsnNode newNode) { if (methodNode == null) { diff -r 19915795c08c -r cf71c6ab82fc src/main/java/org/icedrobot/daneel/rewriter/Register.java --- a/src/main/java/org/icedrobot/daneel/rewriter/Register.java Thu Mar 31 00:54:29 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Register.java Fri Apr 01 11:15:49 2011 +0200 @@ -326,7 +326,7 @@ case U64_TYPE: return "u64"; case NO_TYPE: - return "uninitialized"; + return "uninit"; } if (!isArray(type)) { throw new AssertionError();