Mercurial > hg > icedrobot > daneel
changeset 129:f07b2934d275
Code drop of DEX dumper tool.
* tools/DexDumper.java: Added new tooling class.
author | Michael Starzinger <michi@complang.tuwien.ac.at> |
---|---|
date | Tue, 12 Apr 2011 23:47:46 +0200 |
parents | ce0b5a00da7b |
children | b4e063a46401 |
files | src/main/java/org/icedrobot/daneel/tools/DexDumper.java |
diffstat | 1 files changed, 460 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/icedrobot/daneel/tools/DexDumper.java Tue Apr 12 23:47:46 2011 +0200 @@ -0,0 +1,460 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * 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. + */ + +package org.icedrobot.daneel.tools; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.ByteBuffer; +import java.util.Arrays; + +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.DexFileVisitor; +import org.icedrobot.daneel.dex.DexMethodVisitor; +import org.icedrobot.daneel.dex.Label; +import org.icedrobot.daneel.dex.Opcode; +import org.icedrobot.daneel.loader.ApkFile; +import org.objectweb.asm.Type; + +/** + * Simple tool which dumps the content of a DEX file. Mainly used to test the + * parser functionality by hand. + */ +public class DexDumper { + + /** + * Dumps all information contained in the given file (either a DEX or an APK + * file) to the given output stream in human-readable format. + * + * @param fileName The name of the file to be dumped. + * @param out The output stream to print to. + * @throws IOException In case of an error while accessing the file. + */ + public void execute(String fileName, PrintStream out) throws IOException { + DexFile dex; + long m1 = System.currentTimeMillis(); + if (fileName.endsWith(".apk")) { + ApkFile apk = new ApkFile(fileName); + dex = apk.getDexFile(); + } else { + dex = DexFile.parse(new File(fileName)); + } + long m2 = System.currentTimeMillis(); + System.err.printf("Construction took %4dms.\n", m2 - m1); + dex.accept(new FileDumper(out), 0); + long m3 = System.currentTimeMillis(); + System.err.printf("Dumping took %4dms.\n", m3 - m1); + } + + /** + * The dumper class taking care of printing file information. + */ + private static class FileDumper implements DexFileVisitor { + private final PrintStream out; + + public FileDumper(PrintStream out) { + this.out = out; + } + + @Override + public DexClassVisitor visitClass(String name) { + out.printf("class \"%s\":\n", convertDescToHuman(name)); + return new ClassDumper(out); + } + + @Override + public void visitEnd() { + // Nothing to do here. + } + }; + + /** + * The dumper class taking care of printing class information. + */ + private static class ClassDumper implements DexClassVisitor { + private final PrintStream out; + + public ClassDumper(PrintStream out) { + this.out = out; + } + + @Override + public void visit(int access, String name, String supername, + String[] interfaces) { + out.printf(" access: 0x%08x\n", access); + out.printf(" name: %s\n", name); + out.printf(" super: %s\n", supername); + out.printf(" interfaces: %s\n", Arrays.toString(interfaces)); + } + + @Override + public void visitEnd() { + out.printf("end of class.\n\n"); + } + + @Override + public DexAnnotationVisitor visitAnnotation(int visibility, String type) { + out.printf(" annotation-on-class:\n"); + out.printf(" visibility: 0x%02x\n", visibility); + out.printf(" type: %s\n", type); + return new AnnotationDumper(out, " "); + } + + @Override + public DexFieldVisitor visitField(int access, String name, String type, + Object value) { + out.printf(" field \"%s\":\n", name); + out.printf(" access: 0x%08x\n", access); + out.printf(" type: %s\n", type); + out.printf(" value: %s\n", value); + return new FieldDumper(out); + } + + @Override + public DexMethodVisitor visitMethod(int access, String name, + String shorty, String returnType, String[] parameterTypes) { + out.printf(" method \"%s\":\n", name); + out.printf(" access: 0x%08x\n", access); + out.printf(" shorty: %s\n", shorty); + out.printf(" return-type: %s\n", returnType); + out.printf(" parameter-types: %s\n", Arrays + .toString(parameterTypes)); + return new MethodDumper(out); + } + + @Override + public void visitSource(String source) { + out.printf(" source: %s\n", source); + } + }; + + /** + * The dumper class taking care of printing field information. + */ + private static class FieldDumper implements DexFieldVisitor { + private final PrintStream out; + + public FieldDumper(PrintStream out) { + this.out = out; + } + + @Override + public DexAnnotationVisitor visitAnnotation(int visibility, String type) { + out.printf(" annotation-on-field:\n"); + out.printf(" visibility: 0x%02x\n", visibility); + out.printf(" type: %s\n", type); + return new AnnotationDumper(out, " "); + } + + @Override + public void visitEnd() { + // Nothing to do here. + } + }; + + /** + * The dumper class taking care of printing method information. + */ + private static class MethodDumper implements DexMethodVisitor { + private final PrintStream out; + + public MethodDumper(PrintStream out) { + this.out = out; + } + + @Override + public DexAnnotationVisitor visitAnnotation(int visibility, String type) { + out.printf(" annotation-on-method:\n"); + out.printf(" visibility: 0x%02x\n", visibility); + out.printf(" type: %s\n", type); + return new AnnotationDumper(out, " "); + } + + @Override + public DexAnnotationVisitor visitParameterAnnotation(int parameter, + int visibility, String type) { + throw new RuntimeException("Implement me!"); + // return new DumpDexAnnotationVisitor() + } + + @Override + public void visitCode(int registers, int ins, int outs) { + out.printf(" code (r=%d, i=%d, o=%d):\n", registers, ins, outs); + } + + @Override + public void visitEnd() { + out.printf(" end of method.\n"); + } + + @Override + public void visitInstr(Opcode opcode) { + out.printf(" %s\n", opcode.name()); + } + + @Override + public void visitInstrArray(Opcode opcode, int vsrcOrDest, int varray, + int vindex) { + out.printf(" %s v%d v%d v%d\n", opcode.name(), vsrcOrDest, + varray, vindex); + } + + @Override + public void visitInstrBinOp(Opcode opcode, int vdest, int vsrc, + int vsrc2) { + out.printf(" %s v%d v%d v%d\n", opcode.name(), vdest, vsrc, + vsrc2); + } + + @Override + public void visitInstrBinOpAndLiteral(Opcode opcode, int vdest, + int vsrc, int value) { + out.printf(" %s v%d v%d #%d(0x%08x)\n", opcode.name(), vdest, + vsrc, value, value); + } + + @Override + public void visitInstrClass(Opcode opcode, int vdest, String type) { + String classRef = convertDescToHuman(type); + out.printf(" %s v%d [%s]\n", opcode.name(), vdest, classRef); + } + + @Override + public void visitInstrConstString(Opcode opcode, int vdest, String value) { + out.printf(" %s v%d \"%s\"\n", opcode.name(), vdest, value); + } + + @Override + public void visitInstrConstU32(Opcode opcode, int vdest, int value) { + out.printf(" %s v%d #%d(0x%08x)\n", opcode.name(), vdest, + value, value); + } + + @Override + public void visitInstrConstU64(Opcode opcode, int vdest, long value) { + out.printf(" %s v%d #%d(0x%016x)\n", opcode.name(), vdest, + value, value); + } + + @Override + public void visitInstrField(Opcode opcode, int vsrcOrDest, int vref, + String owner, String name, String desc) { + String fieldRef = convertDescToHuman(desc) + ' ' + + convertDescToHuman(owner) + '#' + name; + out.printf(" %s v%d v%d [%s]\n", opcode.name(), vsrcOrDest, + vref, fieldRef); + } + + @Override + public void visitInstrFillArrayData(Opcode opcode, int vsrc, + int elementWidth, int elementNumber, ByteBuffer data) { + out.printf(" %s v%d %s\n", opcode.name(), vsrc, data); + } + + @Override + public void visitInstrFilledNewArray(Opcode opcode, int num, int va, + int vpacked, String type) { + out.printf(" %s v%d+%d, %s\n", opcode.name(), va, num, type); + } + + @Override + public void visitInstrGoto(Opcode opcode, Label label) { + out.printf(" %s %s\n", opcode.name(), label); + } + + @Override + public void visitInstrIfTest(Opcode opcode, int vsrc1, int vsrc2, + Label label) { + out.printf(" %s v%d v%d %s\n", opcode.name(), vsrc1, vsrc2, + label); + } + + @Override + public void visitInstrIfTestZ(Opcode opcode, int vsrc, Label label) { + out.printf(" %s v%d %s\n", opcode.name(), vsrc, label); + } + + @Override + public void visitInstrInstanceof(Opcode opcode, int vdest, int vsrc, + String type) { + out.printf(" %s v%d v%d %s\n", opcode.name(), vdest, vsrc, + type); + } + + @Override + public void visitInstrMethod(Opcode opcode, int num, int va, + int vpacked, String owner, String name, String desc) { + String methodRef = convertDescToHuman(owner) + "#" + name + desc; + out.printf(" %s {%x%04x}+%d [%s]\n", opcode.name(), va, + vpacked, num, methodRef); + } + + @Override + public void visitInstrNewArray(Opcode opcode, int vdest, int vsize, + String type) { + out.printf(" %s v%d v%d %s\n", opcode.name(), vdest, vsize, + type); + } + + @Override + public void visitInstrOp(Opcode opcode, int srcOrDst) { + out.printf(" %s v%d\n", opcode.name(), srcOrDst); + } + + @Override + public void visitInstrPackedSwitch(Opcode opcode, int vsrc, + int firstKey, Label[] targets) { + out.printf(" %s v%d %s\n", opcode.name(), vsrc, Arrays + .toString(targets)); + } + + @Override + public void visitInstrSparseSwitch(Opcode opcode, int vsrc, int[] keys, + Label[] targets) { + out.printf(" %s v%d %s\n", opcode.name(), vsrc, Arrays + .toString(targets)); + } + + @Override + public void visitInstrUnaryOp(Opcode opcode, int vdest, int vsrc) { + out.printf(" %s v%d v%d\n", opcode.name(), vdest, vsrc); + } + + @Override + public void visitLabel(Label label) { + out.printf(" --- %s:\n", label); + } + + @Override + public void visitTryCatch(Label start, Label end, Label handler, + String type) { + out.printf(" try-catch: %s-%s -> %s, %s\n", start, end, handler, + type); + } + + @Override + public void visitLineNumber(String source, int line, Label start) { + out.printf(" line-number: %s -> %s:%d\n", start, source, line); + } + + @Override + public void visitLocalVariable(String name, String desc, Label start, + Label end, int reg) { + String varRef = convertDescToHuman(desc) + ' ' + name; + out.printf(" local-var: %s-%s, v%d -> [%s]\n", start, end, reg, + varRef); + } + }; + + /** + * The dumper class taking care of printing annotation information. + */ + private static class AnnotationDumper implements DexAnnotationVisitor { + private final PrintStream out; + private final String indent; + + public AnnotationDumper(PrintStream out, String indent) { + this.out = out; + this.indent = indent; + } + + @Override + public void visitPrimitive(String name, Object value) { + out.printf("%s primitive-value: %s = %s\n", indent, name, value); + } + + @Override + public DexAnnotationVisitor visitAnnotation(String name, String type) { + throw new UnsupportedOperationException(); + } + + @Override + public DexAnnotationVisitor visitArray(String name, int size) { + out.printf("%s array-value: %s = array[%d]\n", indent, name, size); + return null; + } + + @Override + public void visitEnum(String name, String enumOwner, String enumName) { + out.printf("%s enum-value: %s = %s %s\n", indent, name, enumOwner, + enumName); + } + + @Override + public void visitField(String name, String fieldOwner, + String fieldName, String fieldDesc) { + out.printf("%s field-value: %s = %s %s %s\n", indent, name, + fieldOwner, fieldName, fieldDesc); + } + + @Override + public void visitMethod(String name, String methodOwner, + String methodName, String methodDesc) { + out.printf("%s method-value: %s = %s %s %s\n", indent, name, + methodOwner, methodName, methodDesc); + } + + @Override + public void visitType(String name, String typeDesc) { + out.printf("%s type-value: %s = %s\n", indent, name, typeDesc); + } + + @Override + public void visitEnd() { + out.printf("%send of annotation.\n", indent); + } + }; + + /** + * Converts a type descriptor into a human-readable representation. + * + * @param desc The given type descriptor. + * @return The human-readable representation. + */ + static String convertDescToHuman(String desc) { + return Type.getType(desc).getClassName(); + } + + public static void main(String[] args) throws Exception { + DexDumper dumper = new DexDumper(); + dumper.execute(args[0], System.out); + } +}