Mercurial > hg > icedrobot > daneel
changeset 17:fe828e968662
Reformatted code and removed author tags.
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/ClassTransformer.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/ClassTransformer.java Tue Mar 15 23:25:43 2011 +0100 @@ -29,14 +29,15 @@ /** * Transforms a given class from Dalvik representation into its equivalent * Java bytecode representation. + * * @param classDef The given class definition as Dalvik representation. * @return The generated Java bytecode representation. */ public static byte[] transformClass(ClassDef classDef) { - ClassTransformer transformer = new ClassTransformer(classDef); - transformer.visitClass(); - transformer.visitFields(); - return transformer.visitEnd(); + ClassTransformer transformer = new ClassTransformer(classDef); + transformer.visitClass(); + transformer.visitFields(); + return transformer.visitEnd(); } private ClassWriter writer; @@ -61,7 +62,8 @@ for (int i = 0; i < classData.getStaticFieldsSize(); i++) { int access = classData.getStaticFieldsFlag(i); FieldId field = classData.getStaticFieldsId(i); - writer.visitField(access, field.getName(), field.getTypeDescriptor(), null, null); + writer.visitField(access, field.getName(), + field.getTypeDescriptor(), null, null); } } @@ -72,8 +74,9 @@ /** * Converts a type descriptor for a class type into an internal class name - * as the ASM library expects it. For details about those type names see - * the "ASM 3.0 User Guide, Section 2.1.2 and 2.1.3". + * as the ASM library expects it. For details about those type names see the + * "ASM 3.0 User Guide, Section 2.1.2 and 2.1.3". + * * @param desc The given type descriptor. * @return The internal class name. */
--- a/src/main/java/org/icedrobot/daneel/dex/ClassData.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/ClassData.java Tue Mar 15 23:25:43 2011 +0100 @@ -27,10 +27,12 @@ /** * Parses a {@code class_data_item} structure in a DEX file at the buffer's * current position. + * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. * @param staticValuesOff Offset to the list of initial values for static - * fields as stored in {@code class_def_item}, or 0 in case there are none. + * fields as stored in {@code class_def_item}, or 0 in case there + * are none. * @return An object representing the parsed data. */ public static ClassData parse(ByteBuffer buffer, DexFile dex, @@ -101,7 +103,8 @@ directMethodsFlags[i] = BufferUtil.getULEB128(buffer); int codeOff = BufferUtil.getULEB128(buffer); if (codeOff != 0) - directMethodsCode[i] = Code.parse(dex.getDataBuffer(codeOff), dex); + directMethodsCode[i] = Code.parse(dex.getDataBuffer(codeOff), + dex); } // Parse encoded_method structures in virtual_methods array. @@ -115,7 +118,8 @@ virtualMethodsFlags[i] = BufferUtil.getULEB128(buffer); int codeOff = BufferUtil.getULEB128(buffer); if (codeOff != 0) - virtualMethodsCode[i] = Code.parse(dex.getDataBuffer(codeOff), dex); + virtualMethodsCode[i] = Code.parse(dex.getDataBuffer(codeOff), + dex); } // Parse encoded_array_item and contained encoded_value structures. @@ -171,6 +175,7 @@ /** * Allows the given visitor to visit this class data object. + * * @param visitor The given DEX class visitor object. */ public void accept(DexClassVisitor visitor) { @@ -224,9 +229,9 @@ private static void acceptMethod(DexClassVisitor visitor, int access, MethodId method, Code code) { ProtoId proto = method.getProtoId(); - DexMethodVisitor dmv = visitor.visitMethod(access, - method.getName(), proto.getShorty(), proto.getReturnType(), - proto.getParameters()); + DexMethodVisitor dmv = visitor + .visitMethod(access, method.getName(), proto.getShorty(), + proto.getReturnType(), proto.getParameters()); if (dmv == null) return; if (code != null)
--- a/src/main/java/org/icedrobot/daneel/dex/ClassDef.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/ClassDef.java Tue Mar 15 23:25:43 2011 +0100 @@ -25,6 +25,7 @@ /** * Parses a {@code class_def_item} structure in a DEX file at the buffer's * current position. + * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. * @return An object representing the parsed data. @@ -102,6 +103,7 @@ /** * Allows the given visitor to visit this class definition. + * * @param visitor The given DEX class visitor object. */ public void accept(DexClassVisitor visitor) {
--- a/src/main/java/org/icedrobot/daneel/dex/Code.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/Code.java Tue Mar 15 23:25:43 2011 +0100 @@ -28,15 +28,15 @@ import org.icedrobot.daneel.util.BufferUtil; /** - * A parser class capable of parsing {@code code_item} structures as part - * of DEX files. Keep package-private to hide internal API. - * @author Michael Starzinger <michi@complang.tuwien.ac.at> + * A parser class capable of parsing {@code code_item} structures as part of DEX + * files. Keep package-private to hide internal API. */ class Code { /** * Parses a {@code code_item} structure in a DEX file at the buffer's * current position. + * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. * @return An object representing the parsed data. @@ -67,7 +67,7 @@ insSize = buffer.getShort(); outsSize = buffer.getShort(); triesSize = buffer.getShort(); - /*debugInfoOff =*/ buffer.getInt(); + /* debugInfoOff = */buffer.getInt(); insnsSize = buffer.getInt(); // Keep a separate buffer for the instructions array. @@ -121,6 +121,7 @@ /** * Allows the given visitor to visit this code object. + * * @param visitor The given DEX method visitor object. */ public void accept(DexMethodVisitor visitor) { @@ -134,6 +135,7 @@ /** * Allows the given visitor to visit all instructions and labels contained * within this code object. + * * @param v The given DEX method visitor object. * @throws DexParseException In case any instruction cannot be decoded. */ @@ -142,19 +144,19 @@ // Iterate over all 16-bit code units. while (insns.hasRemaining()) { - int pos = insns.position(); // bytecode address - int s1 = insns.get(); // signed 1st short + int pos = insns.position(); // bytecode address + int s1 = insns.get(); // signed 1st short // Read and decode further code units. - Opcode op = Opcode.getOpcode(s1 & 0xff); // current opcode + Opcode op = Opcode.getOpcode(s1 & 0xff); // current opcode int codeLength = OP_LENGTH[op.ordinal()]; int s2 = (codeLength >= 2) ? insns.get() : 0; // signed 2nd short int s3 = (codeLength >= 3) ? insns.get() : 0; // signed 3rd short - int b1 = ((s1 >> 8) & 0xff); // unsig. 1st byte - int n1 = ((s1 >> 12) & 0x0f); // unsig. 1st nibble - int n2 = ((s1 >> 8) & 0x0f); // unsig. 2nd nibble - int u2 = (s2 & 0xffff); // unsig. 2nd short - int u3 = (s3 & 0xffff); // unsig. 3rd short + int b1 = ((s1 >> 8) & 0xff); // unsig. 1st byte + int n1 = ((s1 >> 12) & 0x0f); // unsig. 1st nibble + int n2 = ((s1 >> 8) & 0x0f); // unsig. 2nd nibble + int u2 = (s2 & 0xffff); // unsig. 2nd short + int u3 = (s3 & 0xffff); // unsig. 3rd short int b3, b4; // Local variables used within the big switch. @@ -356,7 +358,7 @@ if (!(label instanceof FillArrayDataLabel)) throw new DexParseException("Mistyped branch target."); // XXX Use fill-array-data structure once the interface - // specifies how to do that. + // specifies how to do that. v.visitInstrFillArrayData(op, b1, null); break; @@ -461,8 +463,8 @@ // Format 22c: B|A|op CCCC // Syntax: op vA, vB, field@CCCC field = dex.getFieldId(u2); - v.visitInstrField(op, n2, n1, field.getClassName(), field - .getName(), field.getTypeDescriptor()); + v.visitInstrField(op, n2, n1, field.getClassName(), + field.getName(), field.getTypeDescriptor()); break; case SGET: @@ -482,8 +484,8 @@ // Format 21c: AA|op BBBB // Syntax: op vAA, field@BBBB field = dex.getFieldId(u2); - v.visitInstrField(op, b1, 0, field.getClassName(), field - .getName(), field.getTypeDescriptor()); + v.visitInstrField(op, b1, 0, field.getClassName(), + field.getName(), field.getTypeDescriptor()); break; case INVOKE_VIRTUAL: @@ -508,8 +510,8 @@ // Syntax: op {vCCCC .. vNNNN}, meth@BBBB method = dex.getMethodId(u2); // XXX Don't use the shorty as type descriptor. - v.visitInstrMethod(op, b1, u3, 0, method.getClassName(), method - .getName(), method.getProtoId().getShorty()); + v.visitInstrMethod(op, b1, u3, 0, method.getClassName(), + method.getName(), method.getProtoId().getShorty()); break; case CMPL_FLOAT: @@ -631,28 +633,29 @@ } /** The array associating bytecode instructions to their lengths. */ - private static final int[] OP_LENGTH = new int[] { - 1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 3, - 5, 2, 2, 3, 2, 1, 1, 2, 2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - }; + private static final int[] OP_LENGTH = new int[] { 1, 1, 2, 3, 1, 2, 3, 1, + 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 3, 5, 2, 2, 3, 2, 1, + 1, 2, 2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 1, 3, 3, + 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1 }; /** * Adds a new try-catch-block information structure to our internal list. + * * @param startLabel The start of the try block. * @param endLabel The end (exclusive) of the try block. - * @param type The type descriptor of the exception to catch or - * {@code null} for a catch-all handler. + * @param type The type descriptor of the exception to catch or {@code null} + * for a catch-all handler. * @param handlerAddr The bytecode address of the associated exception - * handler, a label will be added for this address. + * handler, a label will be added for this address. */ private void addTryCatch(Label startLabel, Label endLabel, String type, int handlerAddr) { @@ -667,6 +670,7 @@ /** * Returns the label associated with the given bytecode position. + * * @param pos The given bytecode position in 16-bit code units. * @return The associated label, never returns {@code null}. * @throws DexParseException In case no label can be found. @@ -684,6 +688,7 @@ * Adds a new label to the given bytecode position. Keep this method * package-private in favor of private as long as there are inner classes * which call it, to avoid trampoline code. + * * @param pos The given bytecode position in 16-bit code units. * @return The associated label, never returns {@code null}. */ @@ -700,6 +705,7 @@ /** * Adds a given label to the given bytecode position. + * * @param pos The given bytecode position in 16-bit code units. * @param label The label to be associated with that position. * @throws DexParseException In case there already is a label. @@ -716,8 +722,9 @@ /** * Finds all branch targets by iterating over the bytecode instructions. * This method also parses all encountered in-code data structures. + * * @param buffer The original buffer needed for decoding of in-code data - * structures. + * structures. */ private void findLabels(ByteBuffer buffer) { ShortBuffer insns = this.insns.duplicate(); @@ -815,8 +822,9 @@ } /** - * Skips possible in-code data structures inside the instructions array. - * The given buffer will be positioned after the in-code data. + * Skips possible in-code data structures inside the instructions array. The + * given buffer will be positioned after the in-code data. + * * @param insns The buffer for the instructions array. * @param pos The position at which in-code data is suspeced. * @return True if skipping was sucessfull, false otherwise. @@ -832,7 +840,7 @@ return true; } if (label instanceof FillArrayDataLabel) { - insns.position(pos + ((FillArrayDataLabel)label).length()); + insns.position(pos + ((FillArrayDataLabel) label).length()); return true; } return false; @@ -849,6 +857,7 @@ protected final Label endLabel; protected final Label handlerLabel; protected final String type; + public TryCatchInfo(Label startLabel, Label endLabel, Label handlerLabel, String type) { this.startLabel = startLabel; @@ -864,6 +873,7 @@ private class PackedSwitchLabel extends Label { private final int size; protected final Map<Integer, Label> map; + public PackedSwitchLabel(ByteBuffer buffer, int pos) { if (buffer.getShort() != 0x0100) throw new DexParseException("Unidentified in-code data."); @@ -874,6 +884,7 @@ for (int i = 0; i < size; i++) map.put(firstKey + i, putLabel(pos + targets[i])); } + public int length() { return (size * 2) + 4; } @@ -885,6 +896,7 @@ private class SparseSwitchLabel extends Label { private final int size; protected final Map<Integer, Label> map; + public SparseSwitchLabel(ByteBuffer buffer, int pos) { if (buffer.getShort() != 0x0200) throw new DexParseException("Unidentified in-code data."); @@ -895,6 +907,7 @@ for (int i = 0; i < size; i++) map.put(keys[i], putLabel(pos + targets[i])); } + public int length() { return (size * 4) + 2; } @@ -907,6 +920,7 @@ private final int elementWidth; private final int size; private final byte[] data; + public FillArrayDataLabel(ByteBuffer buffer) { if (buffer.getShort() != 0x0300) throw new DexParseException("Unidentified in-code data."); @@ -915,6 +929,7 @@ data = new byte[size]; buffer.get(data, 0, size); } + public int length() { return (size * elementWidth + 1) / 2 + 4; } @@ -926,9 +941,11 @@ */ private static class DebugLabel extends Label { private final int pos; + public DebugLabel(int pos) { this.pos = pos; } + public String toString() { return String.format("L%03d", pos); }
--- a/src/main/java/org/icedrobot/daneel/dex/DexClassVisitor.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexClassVisitor.java Tue Mar 15 23:25:43 2011 +0100 @@ -20,43 +20,44 @@ /** * A visitor for classes contained in DEX files. - * @author RĂ©mi Forax - * @author Michael Starzinger <michi@complang.tuwien.ac.at> */ public interface DexClassVisitor { /** * Visits the header of the class. + * * @param access The access flags of the class. * @param name The name of the class as a type descriptor. * @param supername The name of the superclass as a type descriptor or - * {@code null} if the class has no superclass (i.e. only for definition of - * {@code java.lang.Object}). + * {@code null} if the class has no superclass (i.e. only for + * definition of {@code java.lang.Object}). * @param interfaces The names of implemented interfaces as type - * descriptors. + * descriptors. */ void visit(int access, String name, String supername, String[] interfaces); /** * Visits the source of the class. - * @param source The name of the file containing the original source for - * (at least most of) this class. + * + * @param source The name of the file containing the original source for (at + * least most of) this class. */ void visitSource(String source); /** * Visits a field of the class. In case this visitor is interested in - * further details about the field (i.e. annotations) it should return a - * new visitor object, otherwise it should return {@code null}. + * further details about the field (i.e. annotations) it should return a new + * visitor object, otherwise it should return {@code null}. + * * @param access The field's access flags. * @param name The field's name. * @param type The field's type as a type descriptor. * @param value The field's initial value. This parameter can be a boxed - * primitive value, a {@code String} object or {@code null} if the field - * does not have an initial value. Is always {@code null} for instance - * fields. - * @return A visitor object for the field or {@code null} if this visitor - * is not interested in details about the field. + * primitive value, a {@code String} object or {@code null} if + * the field does not have an initial value. Is always + * {@code null} for instance fields. + * @return A visitor object for the field or {@code null} if this visitor is + * not interested in details about the field. */ DexFieldVisitor visitField(int access, String name, String type, Object value); @@ -65,13 +66,14 @@ * Visits a method of the class. In case this visitor is interested in * further details about the method it should return a new visitor object, * otherwise it should return {@code null}. + * * @param access The method's access flags. * @param name The method's name. * @param shorty The method's prototype as a short form descriptor. * @param returnType The method's return type as a type descriptor. * @param parameterTypes The method's parameter types as type descriptors. * @return A visitor object for the method or {@code null} if this visitor - * is not interested in details about the method. + * is not interested in details about the method. */ DexMethodVisitor visitMethod(int access, String name, String shorty, String returnType, String[] parameterTypes);
--- a/src/main/java/org/icedrobot/daneel/dex/DexFieldVisitor.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexFieldVisitor.java Tue Mar 15 23:25:43 2011 +0100 @@ -20,8 +20,6 @@ /** * A visitor for fields contained in DEX files. - * @author RĂ©mi Forax - * @author Michael Starzinger <michi@complang.tuwien.ac.at> */ public interface DexFieldVisitor {
--- a/src/main/java/org/icedrobot/daneel/dex/DexFile.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexFile.java Tue Mar 15 23:25:43 2011 +0100 @@ -101,6 +101,7 @@ /** * Resolves the given index value to a prototype id object. The index is * implicitly range-checked. Keep package-private to hide internal API. + * * @param idx The index referring to a prototype id inside this DEX file. * @return The resolved prototype id object. */ @@ -115,6 +116,7 @@ /** * Resolves the given index value to a method id object. The index is * implicitly range-checked. Keep package-private to hide internal API. + * * @param idx The index referring to a method id inside this DEX file. * @return The resolved method id object. */ @@ -128,9 +130,10 @@ /** * Provides a buffer for the data area of this DEX file. The buffer is - * positioned at the given offset and limited to the data area, all - * attempts to read outside that area will fail. Keep package-private to - * hide internal API. + * positioned at the given offset and limited to the data area, all attempts + * to read outside that area will fail. Keep package-private to hide + * internal API. + * * @param off The offset from the start of the file into the data area. * @return The positioned and limited byte buffer. * @throws DexParseException In case the offset is outside of data area. @@ -150,6 +153,7 @@ /** * Allows the given visitor to visit this DEX file. + * * @param visitor The given DEX file visitor object. */ public void accept(DexFileVisitor visitor) {
--- a/src/main/java/org/icedrobot/daneel/dex/DexFileVisitor.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexFileVisitor.java Tue Mar 15 23:25:43 2011 +0100 @@ -20,8 +20,6 @@ /** * A visitor for DEX files. - * @author RĂ©mi Forax - * @author Michael Starzinger <michi@complang.tuwien.ac.at> */ public interface DexFileVisitor { @@ -29,9 +27,10 @@ * Visits a class of the DEX file. In case this visitor is interested in * further details about the class it should return a new visitor object, * otherwise it should return {@code null}. + * * @param name The name of the class as a type descriptor. - * @return A visitor object for the class or {@code null} if this visitor - * is not interested in details about the class. + * @return A visitor object for the class or {@code null} if this visitor is + * not interested in details about the class. */ DexClassVisitor visitClass(String name);
--- a/src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java Tue Mar 15 23:25:43 2011 +0100 @@ -22,17 +22,16 @@ /** * A visitor for methods contained in DEX files. - * @author RĂ©mi Forax - * @author Michael Starzinger <michi@complang.tuwien.ac.at> */ public interface DexMethodVisitor { /** * Starts visiting the method's code. The code is visited by subsequent * calls to {@code visitLabel()} and {@code visitInstr*()} methods. + * * @param registers The number of registers used by the code. * @param ins The number of words of incoming arguments to the code. * @param outs The number of words of outgoing argument space required by - * the code for method invocation. + * the code for method invocation. */ void visitCode(int registers, int ins, int outs); @@ -40,34 +39,39 @@ * Visits a label. The given label refers to the instruction immediately * following it. Labels can be used as branch targets or in try-catch * blocks. + * * @param label The target of a branch. */ void visitLabel(Label label); /** * Visits an instruction with a {@code 10x} format id. + * * @param opcode An opcode among NOP, RETURN_VOID. */ void visitInstr(Opcode opcode); /** * Visits an instruction with a {@code 11x} format id. + * * @param opcode An opcode among MOVE_RESULT, MOVE_RESULT_WIDE, - * MOVE_RESULT_OBJECT, MOVE_EXCEPTION, RETURN, MONITOR_ENTER, MONITOR_EXIT, - * RETURN_WIDE, RETURN_OBJECT, THROW. + * MOVE_RESULT_OBJECT, MOVE_EXCEPTION, RETURN, MONITOR_ENTER, + * MONITOR_EXIT, RETURN_WIDE, RETURN_OBJECT, THROW. * @param srcOrDst Source or destination register or register pair. */ void visitInstrOp(Opcode opcode, int srcOrDst); /** * Visits an instruction with a {@code 12x|22x|32x} format id. + * * @param opcode An opcode among MOVE, MOVE_FROM16, MOVE_16, MOVE_WIDE, - * MOVE_WIDE_FROM16, MOVE_WIDE_16, MOVE_OBJECT, MOVE_OBJECT_FROM16, - * MOVE_OBJECT_16, NEG_INT, NOT_INT, NEG_LONG, NOT_LONG, NEG_FLOAT, - * NEG_DOUBLE, INT_TO_LONG, INT_TO_FLOAT, INT_TO_DOUBLE, LONG_TO_INT, - * LONG_TO_FLOAT, LONG_TO_DOUBLE, FLOAT_TO_INT, FLOAT_TO_LONG, - * DOUBLE_TO_INT, DOUBLE_TO_LONG, DOUBLE_TO_FLOAT, INT_TO_BYTE, INT_TO_CHAR, - * INT_TO_SHORT, ARRAY_LENGTH. + * MOVE_WIDE_FROM16, MOVE_WIDE_16, MOVE_OBJECT, + * MOVE_OBJECT_FROM16, MOVE_OBJECT_16, NEG_INT, NOT_INT, + * NEG_LONG, NOT_LONG, NEG_FLOAT, NEG_DOUBLE, INT_TO_LONG, + * INT_TO_FLOAT, INT_TO_DOUBLE, LONG_TO_INT, LONG_TO_FLOAT, + * LONG_TO_DOUBLE, FLOAT_TO_INT, FLOAT_TO_LONG, DOUBLE_TO_INT, + * DOUBLE_TO_LONG, DOUBLE_TO_FLOAT, INT_TO_BYTE, INT_TO_CHAR, + * INT_TO_SHORT, ARRAY_LENGTH. * @param vdest Destination register or register pair. * @param vsrc Source register or register pair. */ @@ -75,20 +79,23 @@ /** * Visits an instruction with a {@code 23x} format id. + * * @param opcode An opcode among CMPL_FLOAT, CMPG_FLOAT, CMPL_DOUBLE, - * CMPG_DOUBLE, CMP_LONG, ADD_INT, SUB_INT, MUL_INT, DIV_INT, REM_INT, - * AND_INT, OR_INT, XOR_INT, SHL_INT, SHR_INT, USHR_INT, ADD_LONG, SUB_LONG, - * MUL_LONG, DIV_LONG, REM_LONG, AND_LONG, OR_LONG, XOR_LONG, SHL_LONG, - * SHR_LONG, USHR_LONG, ADD_FLOAT, SUB_FLOAT, MUL_FLOAT, DIV_FLOAT, - * REM_FLOAT, ADD_DOUBLE, SUB_DOUBLE, MUL_DOUBLE, DIV_DOUBLE, REM_DOUBLE, - * ADD_INT_2ADDR, SUB_INT_2ADDR, MUL_INT_2ADDR, DIV_INT_2ADDR, - * REM_INT_2ADDR, AND_INT_2ADDR, OR_INT_2ADDR, XOR_INT_2ADDR, SHL_INT_2ADDR, - * SHR_INT_2ADDR, USHR_INT_2ADDR, ADD_LONG_2ADDR, SUB_LONG_2ADDR, - * MUL_LONG_2ADDR, DIV_LONG_2ADDR, REM_LONG_2ADDR, AND_LONG_2ADDR, - * OR_LONG_2ADDR, XOR_LONG_2ADDR, SHL_LONG_2ADDR, SHR_LONG_2ADDR, - * USHR_LONG_2ADDR, ADD_FLOAT_2ADDR, SUB_FLOAT_2ADDR, MUL_FLOAT_2ADDR, - * DIV_FLOAT_2ADDR, REM_FLOAT_2ADDR, ADD_DOUBLE_2ADDR, SUB_DOUBLE_2ADDR, - * MUL_DOUBLE_2ADDR, DIV_DOUBLE_2ADDR, REM_DOUBLE_2ADDR. + * CMPG_DOUBLE, CMP_LONG, ADD_INT, SUB_INT, MUL_INT, DIV_INT, + * REM_INT, AND_INT, OR_INT, XOR_INT, SHL_INT, SHR_INT, USHR_INT, + * ADD_LONG, SUB_LONG, MUL_LONG, DIV_LONG, REM_LONG, AND_LONG, + * OR_LONG, XOR_LONG, SHL_LONG, SHR_LONG, USHR_LONG, ADD_FLOAT, + * SUB_FLOAT, MUL_FLOAT, DIV_FLOAT, REM_FLOAT, ADD_DOUBLE, + * SUB_DOUBLE, MUL_DOUBLE, DIV_DOUBLE, REM_DOUBLE, ADD_INT_2ADDR, + * SUB_INT_2ADDR, MUL_INT_2ADDR, DIV_INT_2ADDR, REM_INT_2ADDR, + * AND_INT_2ADDR, OR_INT_2ADDR, XOR_INT_2ADDR, SHL_INT_2ADDR, + * SHR_INT_2ADDR, USHR_INT_2ADDR, ADD_LONG_2ADDR, SUB_LONG_2ADDR, + * MUL_LONG_2ADDR, DIV_LONG_2ADDR, REM_LONG_2ADDR, + * AND_LONG_2ADDR, OR_LONG_2ADDR, XOR_LONG_2ADDR, SHL_LONG_2ADDR, + * SHR_LONG_2ADDR, USHR_LONG_2ADDR, ADD_FLOAT_2ADDR, + * SUB_FLOAT_2ADDR, MUL_FLOAT_2ADDR, DIV_FLOAT_2ADDR, + * REM_FLOAT_2ADDR, ADD_DOUBLE_2ADDR, SUB_DOUBLE_2ADDR, + * MUL_DOUBLE_2ADDR, DIV_DOUBLE_2ADDR, REM_DOUBLE_2ADDR. * @param vdest Destination register or register pair. * @param vsrc1 First source register or register pair. * @param vsrc2 Second source register or register pair. @@ -97,11 +104,13 @@ /** * Visits an instruction with a {@code 22b|22s} format id. + * * @param opcode An opcode among ADD_INT_LIT16, RSUB_INT_LIT16, - * MUL_INT_LIT16, DIV_INT_LIT16, REM_INT_LIT16, AND_INT_LIT16, OR_INT_LIT16, - * XOR_INT_LIT16, ADD_INT_LIT8, RSUB_INT_LIT8, MUL_INT_LIT8, DIV_INT_LIT8, - * REM_INT_LIT8, AND_INT_LIT8, OR_INT_LIT8, XOR_INT_LIT8, SHL_INT_LIT8, - * SHR_INT_LIT8, USHR_INT_LIT8. + * MUL_INT_LIT16, DIV_INT_LIT16, REM_INT_LIT16, AND_INT_LIT16, + * OR_INT_LIT16, XOR_INT_LIT16, ADD_INT_LIT8, RSUB_INT_LIT8, + * MUL_INT_LIT8, DIV_INT_LIT8, REM_INT_LIT8, AND_INT_LIT8, + * OR_INT_LIT8, XOR_INT_LIT8, SHL_INT_LIT8, SHR_INT_LIT8, + * USHR_INT_LIT8. * @param vdest Destination register or register pair. * @param vsrc Source register or register pair. * @param value Constant literal value. @@ -110,6 +119,7 @@ /** * Visits an instruction with a {@code 21c|31c} format id. + * * @param opcode An opcode among CONST_STRING, CONST_STRING_JUMBO. * @param vdest Destination register (no register pair). * @param value Constant string literal value. @@ -118,6 +128,7 @@ /** * Visits an instruction with a {@code 11n|21h|21s|31i} format id. + * * @param opcode An opcode among CONST_4, CONST_16, CONST, CONST_HIGH16. * @param vdest Destination register (no register pair). * @param value Constant literal value. @@ -126,8 +137,9 @@ /** * Visits an instruction with a {@code 21h|21s|31i|51l} format id. + * * @param opcode An opcode among CONST_WIDE_16, CONST_WIDE_32, CONST_WIDE, - * CONST_WIDE_HIGH16. + * CONST_WIDE_HIGH16. * @param vdest Destination register pair (no single register). * @param value Constant literal value. */ @@ -135,6 +147,7 @@ /** * Visits an instruction with a {@code 21c} format id. + * * @param opcode An opcode among CONST_CLASS, CHECK_CAST, NEW_INSTANCE. * @param vdest Destination register (no register pair). * @param type Constant type descriptor value. @@ -143,6 +156,7 @@ /** * Visits an instruction with a {@code 22c} format id. + * * @param opcode The opcode INSTANCE_OF. * @param vdest Destination register (no register pair). * @param vsrc Source register (no register pair). @@ -152,6 +166,7 @@ /** * Visits an instruction with a {@code 10t|20t|30t} format id. + * * @param opcode An opcode among GOTO_32, GOTO, GOTO_16. * @param label The target of the branch. */ @@ -159,8 +174,9 @@ /** * Visits an instruction with a {@code 21t} format id. + * * @param opcode An opcode among IF_EQZ, IF_NEZ, IF_LTZ, IF_GEZ, IF_GTZ, - * IF_LEZ. + * IF_LEZ. * @param vsrc Source register (no register pair). * @param label The target of the branch. */ @@ -168,6 +184,7 @@ /** * Visits an instruction with a {@code 22t} format id. + * * @param opcode An opcode among IF_EQ, IF_NE, IF_LT, IF_GE, IF_GT, IF_LE. * @param vsrc1 First source register (no register pair). * @param vsrc2 Second source register (no register pair). @@ -177,6 +194,7 @@ /** * Visits an instruction with a {@code 31t} format id. + * * @param opcode An opcode among PACKED_SWITCH, SPARSE_SWITCH. * @param vsrc Source register (no register pair). * @param labels The target of the branch. @@ -185,9 +203,10 @@ /** * Visits an instruction with a {@code 23x} format id. + * * @param opcode An opcode among APUT, APUT_WIDE, APUT_OBJECT, APUT_BOOLEAN, - * APUT_BYTE, APUT_CHAR, APUT_SHORT, AGET, AGET_WIDE, AGET_OBJECT, - * AGET_BOOLEAN, AGET_BYTE, AGET_CHAR, AGET_SHORT. + * APUT_BYTE, APUT_CHAR, APUT_SHORT, AGET, AGET_WIDE, + * AGET_OBJECT, AGET_BOOLEAN, AGET_BYTE, AGET_CHAR, AGET_SHORT. * @param vsrcOrDest Source or destination register or register pair. * @param varray The array register. * @param vindex The index register. @@ -196,11 +215,13 @@ /** * Visits an instruction with a {@code 21c|22c} format id. + * * @param opcode opcode among IGET, IGET_WIDE, IGET_OBJECT, IGET_BOOLEAN, - * IGET_BYTE, IGET_CHAR, IGET_SHORT, IPUT, IPUT_WIDE, IPUT_OBJECT, - * IPUT_BOOLEAN, IPUT_BYTE, IPUT_CHAR, IPUT_SHORT, SGET, SGET_WIDE, - * SGET_OBJECT, SGET_BOOLEAN, SGET_BYTE, SGET_CHAR, SGET_SHORT, SPUT, - * SPUT_WIDE, SPUT_OBJECT, SPUT_BOOLEAN, SPUT_BYTE, SPUT_CHAR, SPUT_SHORT. + * IGET_BYTE, IGET_CHAR, IGET_SHORT, IPUT, IPUT_WIDE, + * IPUT_OBJECT, IPUT_BOOLEAN, IPUT_BYTE, IPUT_CHAR, IPUT_SHORT, + * SGET, SGET_WIDE, SGET_OBJECT, SGET_BOOLEAN, SGET_BYTE, + * SGET_CHAR, SGET_SHORT, SPUT, SPUT_WIDE, SPUT_OBJECT, + * SPUT_BOOLEAN, SPUT_BYTE, SPUT_CHAR, SPUT_SHORT. * @param vsrcOrDest Source or destination register or register pair. * @param vref The object register in instance mode or 0 in static mode. * @param owner The field's owner as type descriptor. @@ -212,14 +233,15 @@ /** * Visits an instruction with a {@code 35c|3rc} format id. + * * @param opcode An opcode among INVOKE_VIRTUAL, INVOKE_SUPER, - * INVOKE_DIRECT, INVOKE_STATIC, INVOKE_INTERFACE, INVOKE_VIRTUAL_RANGE, - * INVOKE_SUPER_RANGE, INVOKE_DIRECT_RANGE, INVOKE_STATIC_RANGE, - * INVOKE_INTERFACE_RANGE. + * INVOKE_DIRECT, INVOKE_STATIC, INVOKE_INTERFACE, + * INVOKE_VIRTUAL_RANGE, INVOKE_SUPER_RANGE, INVOKE_DIRECT_RANGE, + * INVOKE_STATIC_RANGE, INVOKE_INTERFACE_RANGE. * @param num The number of registers involved. * @param va Register A in normal mode or first register in range mode. * @param vpacked Register D,E,F,G (4 bits each) in normal mode or 0 in - * range mode. + * range mode. * @param owner The method's owner as type descriptor. * @param name The method's name. * @param desc The method's type descriptor. @@ -229,11 +251,12 @@ /** * Visits an instruction with a {@code 35c|3rc} format id. + * * @param opcode An opcode among FILLED_NEW_ARRAY, FILLED_NEW_ARRAY_RANGE. * @param num The number of registers involved. * @param va Register A in normal mode or first register in range mode. * @param vpacked Register D,E,F,G (4 bits each) in normal mode or 0 in - * range mode. + * range mode. * @param type Constant type descriptor value. */ void visitInstrFilledNewArray(Opcode opcode, int num, int va, int vpacked, @@ -241,6 +264,7 @@ /** * Visits an instruction with a {@code 22c} format id. + * * @param opcode The opcode NEW_ARRAY. * @param vdest Destination register (no register pair). * @param vsize The size register. @@ -250,6 +274,7 @@ /** * Visits an instruction with a {@code 31t} format id. + * * @param opcode The opcode FILL_ARRAY_DATA. * @param vsrc The array register. * @param arrayData XXX Specify me! @@ -258,11 +283,12 @@ /** * Visits a try-catch block for the method's code. + * * @param start The label of the handler's scope start. * @param end The label of the handler's scope end (exclusive). * @param handler The label for the actual handler code. * @param type The type descriptor of the exceptions this block handles or - * {@code null} in case it is a catch-all handler. + * {@code null} in case it is a catch-all handler. */ void visitTryCatch(Label start, Label end, Label handler, String type);
--- a/src/main/java/org/icedrobot/daneel/dex/DexReader.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexReader.java Tue Mar 15 23:25:43 2011 +0100 @@ -1,13 +1,11 @@ package org.icedrobot.daneel.dex; -/** +/** * Common interface of DEX file reader. - * - * @author Remi Forax */ public interface DexReader { - public void accept(DexFileVisitor dv); + public void accept(DexFileVisitor dv); - public void accept(String className, DexClassVisitor cv) - throws ClassNotFoundException; + public void accept(String className, DexClassVisitor cv) + throws ClassNotFoundException; } \ No newline at end of file
--- a/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java Tue Mar 15 23:25:43 2011 +0100 @@ -21,32 +21,32 @@ import java.nio.ByteBuffer; /** - * A parser class capable of parsing {@code encoded_value} structures as part - * of DEX files. Keep package-private to hide internal API. - * @author Michael Starzinger <michi@complang.tuwien.ac.at> + * A parser class capable of parsing {@code encoded_value} structures as part of + * DEX files. Keep package-private to hide internal API. */ class EncodedValue { - public static final int VALUE_BYTE = 0x00; - public static final int VALUE_SHORT = 0x02; - public static final int VALUE_CHAR = 0x03; - public static final int VALUE_INT = 0x04; - public static final int VALUE_LONG = 0x06; - public static final int VALUE_FLOAT = 0x10; - public static final int VALUE_DOUBLE = 0x11; - public static final int VALUE_STRING = 0x17; - public static final int VALUE_TYPE = 0x18; - public static final int VALUE_FIELD = 0x19; - public static final int VALUE_METHOD = 0x1a; - public static final int VALUE_ENUM = 0x1b; - public static final int VALUE_ARRAY = 0x1c; + public static final int VALUE_BYTE = 0x00; + public static final int VALUE_SHORT = 0x02; + public static final int VALUE_CHAR = 0x03; + public static final int VALUE_INT = 0x04; + public static final int VALUE_LONG = 0x06; + public static final int VALUE_FLOAT = 0x10; + public static final int VALUE_DOUBLE = 0x11; + public static final int VALUE_STRING = 0x17; + public static final int VALUE_TYPE = 0x18; + public static final int VALUE_FIELD = 0x19; + public static final int VALUE_METHOD = 0x1a; + public static final int VALUE_ENUM = 0x1b; + public static final int VALUE_ARRAY = 0x1c; public static final int VALUE_ANNOTATION = 0x1d; - public static final int VALUE_NULL = 0x1e; - public static final int VALUE_BOOLEAN = 0x1f; + public static final int VALUE_NULL = 0x1e; + public static final int VALUE_BOOLEAN = 0x1f; /** * Parses a {@code encoded_value} structure in a DEX file at the buffer's * current position. + * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. * @return An object representing the parsed data. @@ -90,6 +90,7 @@ /** * Helper method for sanity checking the {@code value_arg} value. + * * @param arg The given {@code value_arg} value. * @param max The maximum value allowed in this instance. * @throws DexParseException In case the value exceeds its boundaries. @@ -102,6 +103,7 @@ /** * Helper method decoding a signed (sign-extended) {@code value} array. + * * @param buffer The buffer positioned at the array. * @param size The number of bytes in the array minus 1. * @return The decoded value. @@ -116,6 +118,7 @@ /** * Helper method decoding an unsigned (zero-extended) {@code value} array. + * * @param buffer The buffer positioned at the {@code value} array. * @param size The number of bytes in the array minus 1. * @return The decoded value.
--- a/src/main/java/org/icedrobot/daneel/dex/FieldId.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/FieldId.java Tue Mar 15 23:25:43 2011 +0100 @@ -25,6 +25,7 @@ /** * Parses a {@code field_id_item} structure in a DEX file at the buffer's * current position. + * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. * @return An object representing the parsed data.
--- a/src/main/java/org/icedrobot/daneel/dex/Header.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/Header.java Tue Mar 15 23:25:43 2011 +0100 @@ -247,8 +247,8 @@ string.append(getChecksum()); string.append("\n signature: "); for (byte sigByte : getSignature()) { - string.append(Integer.toHexString(sigByte)); - string.append(' '); + string.append(Integer.toHexString(sigByte)); + string.append(' '); } string.append("\n file size: "); string.append(getFileLength());
--- a/src/main/java/org/icedrobot/daneel/dex/Label.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/Label.java Tue Mar 15 23:25:43 2011 +0100 @@ -20,7 +20,6 @@ /** * A label referencing a certain position in Dalvik VM bytecode. - * @author RĂ©mi Forax */ public class Label {
--- a/src/main/java/org/icedrobot/daneel/dex/Main.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/Main.java Tue Mar 15 23:25:43 2011 +0100 @@ -12,7 +12,8 @@ File dexFile = new File(dexFileName); RandomAccessFile dexFileAccess = new RandomAccessFile(dexFile, "r"); FileChannel dexFileChannel = dexFileAccess.getChannel(); - ByteBuffer dexFileBuffer = dexFileChannel.map(FileChannel.MapMode.READ_ONLY, 0, dexFile.length()); + ByteBuffer dexFileBuffer = dexFileChannel.map( + FileChannel.MapMode.READ_ONLY, 0, dexFile.length()); DexFile parsedDexFile = DexFile.parse(dexFileBuffer); System.out.println(parsedDexFile); }
--- a/src/main/java/org/icedrobot/daneel/dex/MethodId.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/MethodId.java Tue Mar 15 23:25:43 2011 +0100 @@ -23,13 +23,13 @@ /** * A parser class capable of parsing {@code method_id_item} structures as part * of DEX files. Keep package-private to hide internal API. - * @author Michael Starzinger <michi@complang.tuwien.ac.at> */ class MethodId { /** * Parses a {@code method_id_item} structure in a DEX file at the buffer's * current position. + * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. * @return An object representing the parsed data.
--- a/src/main/java/org/icedrobot/daneel/dex/Opcode.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/Opcode.java Tue Mar 15 23:25:43 2011 +0100 @@ -20,264 +20,77 @@ /** * Enumeration of all opcodes available in Dalvik VM bytecode. - * @author RĂ©mi Forax */ public enum Opcode { - NOP(0x00), - MOVE(0x01), - MOVE_FROM16(0x02), - MOVE_16(0x03), - MOVE_WIDE(0x04), - MOVE_WIDE_FROM16(0x05), - MOVE_WIDE_16(0x06), - MOVE_OBJECT(0x07), - MOVE_OBJECT_FROM16(0x08), - MOVE_OBJECT_16(0x09), - MOVE_RESULT(0x0a), - MOVE_RESULT_WIDE(0x0b), - MOVE_RESULT_OBJECT(0x0c), - MOVE_EXCEPTION(0x0d), - RETURN_VOID(0x0e), - RETURN(0x0f), - RETURN_WIDE(0x10), - RETURN_OBJECT(0x11), - CONST_4(0x12), - CONST_16(0x13), - CONST(0x14), - CONST_HIGH16(0x15), - CONST_WIDE_16(0x16), - CONST_WIDE_32(0x17), - CONST_WIDE(0x18), - CONST_WIDE_HIGH16(0x19), - CONST_STRING(0x1a), - CONST_STRING_JUMBO(0x1b), - CONST_CLASS(0x1c), - MONITOR_ENTER(0x1d), - MONITOR_EXIT(0x1e), - CHECK_CAST(0x1f), - INSTANCE_OF(0x20), - ARRAY_LENGTH(0x21), - NEW_INSTANCE(0x22), - NEW_ARRAY(0x23), - FILLED_NEW_ARRAY(0x24), - FILLED_NEW_ARRAY_RANGE(0x25), - FILL_ARRAY_DATA(0x26), - THROW(0x27), - GOTO(0x28), - GOTO_16(0x29), - GOTO_32(0x2a), - PACKED_SWITCH(0x2b), - SPARSE_SWITCH(0x2c), - CMPL_FLOAT(0x2d), - CMPG_FLOAT(0x2e), - CMPL_DOUBLE(0x2f), - CMPG_DOUBLE(0x30), - CMP_LONG(0x31), - IF_EQ(0x32), - IF_NE(0x33), - IF_LT(0x34), - IF_GE(0x35), - IF_GT(0x36), - IF_LE(0x37), - IF_EQZ(0x38), - IF_NEZ(0x39), - IF_LTZ(0x3a), - IF_GEZ(0x3b), - IF_GTZ(0x3c), - IF_LEZ(0x3d), - UNUSED_3E(0x3e), - UNUSED_3F(0x3f), - UNUSED_40(0x40), - UNUSED_41(0x41), - UNUSED_42(0x42), - UNUSED_43(0x43), - AGET(0x44), - AGET_WIDE(0x45), - AGET_OBJECT(0x46), - AGET_BOOLEAN(0x47), - AGET_BYTE(0x48), - AGET_CHAR(0x49), - AGET_SHORT(0x4a), - APUT(0x4b), - APUT_WIDE(0x4c), - APUT_OBJECT(0x4d), - APUT_BOOLEAN(0x4e), - APUT_BYTE(0x4f), - APUT_CHAR(0x50), - APUT_SHORT(0x51), - IGET(0x52), - IGET_WIDE(0x53), - IGET_OBJECT(0x54), - IGET_BOOLEAN(0x55), - IGET_BYTE(0x56), - IGET_CHAR(0x57), - IGET_SHORT(0x58), - IPUT(0x59), - IPUT_WIDE(0x5a), - IPUT_OBJECT(0x5b), - IPUT_BOOLEAN(0x5c), - IPUT_BYTE(0x5d), - IPUT_CHAR(0x5e), - IPUT_SHORT(0x5f), - SGET(0x60), - SGET_WIDE(0x61), - SGET_OBJECT(0x62), - SGET_BOOLEAN(0x63), - SGET_BYTE(0x64), - SGET_CHAR(0x65), - SGET_SHORT(0x66), - SPUT(0x67), - SPUT_WIDE(0x68), - SPUT_OBJECT(0x69), - SPUT_BOOLEAN(0x6a), - SPUT_BYTE(0x6b), - SPUT_CHAR(0x6c), - SPUT_SHORT(0x6d), - INVOKE_VIRTUAL(0x6e), - INVOKE_SUPER(0x6f), - INVOKE_DIRECT(0x70), - INVOKE_STATIC(0x71), - INVOKE_INTERFACE(0x72), - UNUSED_73(0x73), - INVOKE_VIRTUAL_RANGE(0x74), - INVOKE_SUPER_RANGE(0x75), - INVOKE_DIRECT_RANGE(0x76), - INVOKE_STATIC_RANGE(0x77), - INVOKE_INTERFACE_RANGE(0x78), - UNUSED_79(0x79), - UNUSED_7A(0x7a), - NEG_INT(0x7b), - NOT_INT(0x7c), - NEG_LONG(0x7d), - NOT_LONG(0x7e), - NEG_FLOAT(0x7f), - NEG_DOUBLE(0x80), - INT_TO_LONG(0x81), - INT_TO_FLOAT(0x82), - INT_TO_DOUBLE(0x83), - LONG_TO_INT(0x84), - LONG_TO_FLOAT(0x85), - LONG_TO_DOUBLE(0x86), - FLOAT_TO_INT(0x87), - FLOAT_TO_LONG(0x88), - FLOAT_TO_DOUBLE(0x89), - DOUBLE_TO_INT(0x8a), - DOUBLE_TO_LONG(0x8b), - DOUBLE_TO_FLOAT(0x8c), - INT_TO_BYTE(0x8d), - INT_TO_CHAR(0x8e), - INT_TO_SHORT(0x8f), - ADD_INT(0x90), - SUB_INT(0x91), - MUL_INT(0x92), - DIV_INT(0x93), - REM_INT(0x94), - AND_INT(0x95), - OR_INT(0x96), - XOR_INT(0x97), - SHL_INT(0x98), - SHR_INT(0x99), - USHR_INT(0x9a), - ADD_LONG(0x9b), - SUB_LONG(0x9c), - MUL_LONG(0x9d), - DIV_LONG(0x9e), - REM_LONG(0x9f), - AND_LONG(0xa0), - OR_LONG(0xa1), - XOR_LONG(0xa2), - SHL_LONG(0xa3), - SHR_LONG(0xa4), - USHR_LONG(0xa5), - ADD_FLOAT(0xa6), - SUB_FLOAT(0xa7), - MUL_FLOAT(0xa8), - DIV_FLOAT(0xa9), - REM_FLOAT(0xaa), - ADD_DOUBLE(0xab), - SUB_DOUBLE(0xac), - MUL_DOUBLE(0xad), - DIV_DOUBLE(0xae), - REM_DOUBLE(0xaf), - ADD_INT_2ADDR(0xb0), - SUB_INT_2ADDR(0xb1), - MUL_INT_2ADDR(0xb2), - DIV_INT_2ADDR(0xb3), - REM_INT_2ADDR(0xb4), - AND_INT_2ADDR(0xb5), - OR_INT_2ADDR(0xb6), - XOR_INT_2ADDR(0xb7), - SHL_INT_2ADDR(0xb8), - SHR_INT_2ADDR(0xb9), - USHR_INT_2ADDR(0xba), - ADD_LONG_2ADDR(0xbb), - SUB_LONG_2ADDR(0xbc), - MUL_LONG_2ADDR(0xbd), - DIV_LONG_2ADDR(0xbe), - REM_LONG_2ADDR(0xbf), - AND_LONG_2ADDR(0xc0), - OR_LONG_2ADDR(0xc1), - XOR_LONG_2ADDR(0xc2), - SHL_LONG_2ADDR(0xc3), - SHR_LONG_2ADDR(0xc4), - USHR_LONG_2ADDR(0xc5), - ADD_FLOAT_2ADDR(0xc6), - SUB_FLOAT_2ADDR(0xc7), - MUL_FLOAT_2ADDR(0xc8), - DIV_FLOAT_2ADDR(0xc9), - REM_FLOAT_2ADDR(0xca), - ADD_DOUBLE_2ADDR(0xcb), - SUB_DOUBLE_2ADDR(0xcc), - MUL_DOUBLE_2ADDR(0xcd), - DIV_DOUBLE_2ADDR(0xce), - REM_DOUBLE_2ADDR(0xcf), - ADD_INT_LIT16(0xd0), - RSUB_INT_LIT16(0xd1), - MUL_INT_LIT16(0xd2), - DIV_INT_LIT16(0xd3), - REM_INT_LIT16(0xd4), - AND_INT_LIT16(0xd5), - OR_INT_LIT16(0xd6), - XOR_INT_LIT16(0xd7), - ADD_INT_LIT8(0xd8), - RSUB_INT_LIT8(0xd9), - MUL_INT_LIT8(0xda), - DIV_INT_LIT8(0xdb), - REM_INT_LIT8(0xdc), - AND_INT_LIT8(0xdd), - OR_INT_LIT8(0xde), - XOR_INT_LIT8(0xdf), - SHL_INT_LIT8(0xe0), - SHR_INT_LIT8(0xe1), - USHR_INT_LIT8(0xe2), - IGET_VOLATILE(0xe3), - IPUT_VOLATILE(0xe4), - SGET_VOLATILE(0xe5), - SPUT_VOLATILE(0xe6), - IGET_OBJECT_VOLATILE(0xe7), - IGET_WIDE_VOLATILE(0xe8), - IPUT_WIDE_VOLATILE(0xe9), - SGET_WIDE_VOLATILE(0xea), - SPUT_WIDE_VOLATILE(0xeb), - UNUSED_EC(0xec), - UNUSED_ED(0xed), - EXECUTE_INLINE(0xee), - EXECUTE_INLINE_RANGE(0xef), - INVOKE_DIRECT_EMPTY(0xf0), - IGET_QUICK(0xf2), - IGET_WIDE_QUICK(0xf3), - IGET_OBJECT_QUICK(0xf4), - IPUT_QUICK(0xf5), - IPUT_WIDE_QUICK(0xf6), - IPUT_OBJECT_QUICK(0xf7), - INVOKE_VIRTUAL_QUICK(0xf8), - INVOKE_VIRTUAL_QUICK_RANGE(0xf9), - INVOKE_SUPER_QUICK(0xfa), - INVOKE_SUPER_QUICK_RANGE(0xfb), - IPUT_OBJECT_VOLATILE(0xfc), - SGET_OBJECT_VOLATILE(0xfd), - SPUT_OBJECT_VOLATILE(0xfe), - UNUSED_FF(0xff); + NOP(0x00), MOVE(0x01), MOVE_FROM16(0x02), MOVE_16(0x03), MOVE_WIDE(0x04), MOVE_WIDE_FROM16( + 0x05), MOVE_WIDE_16(0x06), MOVE_OBJECT(0x07), MOVE_OBJECT_FROM16( + 0x08), MOVE_OBJECT_16(0x09), MOVE_RESULT(0x0a), MOVE_RESULT_WIDE( + 0x0b), MOVE_RESULT_OBJECT(0x0c), MOVE_EXCEPTION(0x0d), RETURN_VOID( + 0x0e), RETURN(0x0f), RETURN_WIDE(0x10), RETURN_OBJECT(0x11), CONST_4( + 0x12), CONST_16(0x13), CONST(0x14), CONST_HIGH16(0x15), CONST_WIDE_16( + 0x16), CONST_WIDE_32(0x17), CONST_WIDE(0x18), CONST_WIDE_HIGH16( + 0x19), CONST_STRING(0x1a), CONST_STRING_JUMBO(0x1b), CONST_CLASS( + 0x1c), MONITOR_ENTER(0x1d), MONITOR_EXIT(0x1e), CHECK_CAST(0x1f), INSTANCE_OF( + 0x20), ARRAY_LENGTH(0x21), NEW_INSTANCE(0x22), NEW_ARRAY(0x23), FILLED_NEW_ARRAY( + 0x24), FILLED_NEW_ARRAY_RANGE(0x25), FILL_ARRAY_DATA(0x26), THROW( + 0x27), GOTO(0x28), GOTO_16(0x29), GOTO_32(0x2a), PACKED_SWITCH(0x2b), SPARSE_SWITCH( + 0x2c), CMPL_FLOAT(0x2d), CMPG_FLOAT(0x2e), CMPL_DOUBLE(0x2f), CMPG_DOUBLE( + 0x30), CMP_LONG(0x31), IF_EQ(0x32), IF_NE(0x33), IF_LT(0x34), IF_GE( + 0x35), IF_GT(0x36), IF_LE(0x37), IF_EQZ(0x38), IF_NEZ(0x39), IF_LTZ( + 0x3a), IF_GEZ(0x3b), IF_GTZ(0x3c), IF_LEZ(0x3d), UNUSED_3E(0x3e), UNUSED_3F( + 0x3f), UNUSED_40(0x40), UNUSED_41(0x41), UNUSED_42(0x42), UNUSED_43( + 0x43), AGET(0x44), AGET_WIDE(0x45), AGET_OBJECT(0x46), AGET_BOOLEAN( + 0x47), AGET_BYTE(0x48), AGET_CHAR(0x49), AGET_SHORT(0x4a), APUT( + 0x4b), APUT_WIDE(0x4c), APUT_OBJECT(0x4d), APUT_BOOLEAN(0x4e), APUT_BYTE( + 0x4f), APUT_CHAR(0x50), APUT_SHORT(0x51), IGET(0x52), IGET_WIDE( + 0x53), IGET_OBJECT(0x54), IGET_BOOLEAN(0x55), IGET_BYTE(0x56), IGET_CHAR( + 0x57), IGET_SHORT(0x58), IPUT(0x59), IPUT_WIDE(0x5a), IPUT_OBJECT( + 0x5b), IPUT_BOOLEAN(0x5c), IPUT_BYTE(0x5d), IPUT_CHAR(0x5e), IPUT_SHORT( + 0x5f), SGET(0x60), SGET_WIDE(0x61), SGET_OBJECT(0x62), SGET_BOOLEAN( + 0x63), SGET_BYTE(0x64), SGET_CHAR(0x65), SGET_SHORT(0x66), SPUT( + 0x67), SPUT_WIDE(0x68), SPUT_OBJECT(0x69), SPUT_BOOLEAN(0x6a), SPUT_BYTE( + 0x6b), SPUT_CHAR(0x6c), SPUT_SHORT(0x6d), INVOKE_VIRTUAL(0x6e), INVOKE_SUPER( + 0x6f), INVOKE_DIRECT(0x70), INVOKE_STATIC(0x71), INVOKE_INTERFACE( + 0x72), UNUSED_73(0x73), INVOKE_VIRTUAL_RANGE(0x74), INVOKE_SUPER_RANGE( + 0x75), INVOKE_DIRECT_RANGE(0x76), INVOKE_STATIC_RANGE(0x77), INVOKE_INTERFACE_RANGE( + 0x78), UNUSED_79(0x79), UNUSED_7A(0x7a), NEG_INT(0x7b), NOT_INT( + 0x7c), NEG_LONG(0x7d), NOT_LONG(0x7e), NEG_FLOAT(0x7f), NEG_DOUBLE( + 0x80), INT_TO_LONG(0x81), INT_TO_FLOAT(0x82), INT_TO_DOUBLE(0x83), LONG_TO_INT( + 0x84), LONG_TO_FLOAT(0x85), LONG_TO_DOUBLE(0x86), FLOAT_TO_INT(0x87), FLOAT_TO_LONG( + 0x88), FLOAT_TO_DOUBLE(0x89), DOUBLE_TO_INT(0x8a), DOUBLE_TO_LONG( + 0x8b), DOUBLE_TO_FLOAT(0x8c), INT_TO_BYTE(0x8d), INT_TO_CHAR(0x8e), INT_TO_SHORT( + 0x8f), ADD_INT(0x90), SUB_INT(0x91), MUL_INT(0x92), DIV_INT(0x93), REM_INT( + 0x94), AND_INT(0x95), OR_INT(0x96), XOR_INT(0x97), SHL_INT(0x98), SHR_INT( + 0x99), USHR_INT(0x9a), ADD_LONG(0x9b), SUB_LONG(0x9c), MUL_LONG( + 0x9d), DIV_LONG(0x9e), REM_LONG(0x9f), AND_LONG(0xa0), OR_LONG(0xa1), XOR_LONG( + 0xa2), SHL_LONG(0xa3), SHR_LONG(0xa4), USHR_LONG(0xa5), ADD_FLOAT( + 0xa6), SUB_FLOAT(0xa7), MUL_FLOAT(0xa8), DIV_FLOAT(0xa9), REM_FLOAT( + 0xaa), ADD_DOUBLE(0xab), SUB_DOUBLE(0xac), MUL_DOUBLE(0xad), DIV_DOUBLE( + 0xae), REM_DOUBLE(0xaf), ADD_INT_2ADDR(0xb0), SUB_INT_2ADDR(0xb1), MUL_INT_2ADDR( + 0xb2), DIV_INT_2ADDR(0xb3), REM_INT_2ADDR(0xb4), AND_INT_2ADDR(0xb5), OR_INT_2ADDR( + 0xb6), XOR_INT_2ADDR(0xb7), SHL_INT_2ADDR(0xb8), SHR_INT_2ADDR(0xb9), USHR_INT_2ADDR( + 0xba), ADD_LONG_2ADDR(0xbb), SUB_LONG_2ADDR(0xbc), MUL_LONG_2ADDR( + 0xbd), DIV_LONG_2ADDR(0xbe), REM_LONG_2ADDR(0xbf), AND_LONG_2ADDR( + 0xc0), OR_LONG_2ADDR(0xc1), XOR_LONG_2ADDR(0xc2), SHL_LONG_2ADDR( + 0xc3), SHR_LONG_2ADDR(0xc4), USHR_LONG_2ADDR(0xc5), ADD_FLOAT_2ADDR( + 0xc6), SUB_FLOAT_2ADDR(0xc7), MUL_FLOAT_2ADDR(0xc8), DIV_FLOAT_2ADDR( + 0xc9), REM_FLOAT_2ADDR(0xca), ADD_DOUBLE_2ADDR(0xcb), SUB_DOUBLE_2ADDR( + 0xcc), MUL_DOUBLE_2ADDR(0xcd), DIV_DOUBLE_2ADDR(0xce), REM_DOUBLE_2ADDR( + 0xcf), ADD_INT_LIT16(0xd0), RSUB_INT_LIT16(0xd1), MUL_INT_LIT16( + 0xd2), DIV_INT_LIT16(0xd3), REM_INT_LIT16(0xd4), AND_INT_LIT16(0xd5), OR_INT_LIT16( + 0xd6), XOR_INT_LIT16(0xd7), ADD_INT_LIT8(0xd8), RSUB_INT_LIT8(0xd9), MUL_INT_LIT8( + 0xda), DIV_INT_LIT8(0xdb), REM_INT_LIT8(0xdc), AND_INT_LIT8(0xdd), OR_INT_LIT8( + 0xde), XOR_INT_LIT8(0xdf), SHL_INT_LIT8(0xe0), SHR_INT_LIT8(0xe1), USHR_INT_LIT8( + 0xe2), IGET_VOLATILE(0xe3), IPUT_VOLATILE(0xe4), SGET_VOLATILE(0xe5), SPUT_VOLATILE( + 0xe6), IGET_OBJECT_VOLATILE(0xe7), IGET_WIDE_VOLATILE(0xe8), IPUT_WIDE_VOLATILE( + 0xe9), SGET_WIDE_VOLATILE(0xea), SPUT_WIDE_VOLATILE(0xeb), UNUSED_EC( + 0xec), UNUSED_ED(0xed), EXECUTE_INLINE(0xee), EXECUTE_INLINE_RANGE( + 0xef), INVOKE_DIRECT_EMPTY(0xf0), IGET_QUICK(0xf2), IGET_WIDE_QUICK( + 0xf3), IGET_OBJECT_QUICK(0xf4), IPUT_QUICK(0xf5), IPUT_WIDE_QUICK( + 0xf6), IPUT_OBJECT_QUICK(0xf7), INVOKE_VIRTUAL_QUICK(0xf8), INVOKE_VIRTUAL_QUICK_RANGE( + 0xf9), INVOKE_SUPER_QUICK(0xfa), INVOKE_SUPER_QUICK_RANGE(0xfb), IPUT_OBJECT_VOLATILE( + 0xfc), SGET_OBJECT_VOLATILE(0xfd), SPUT_OBJECT_VOLATILE(0xfe), UNUSED_FF( + 0xff); private final static Opcode[] OPCODES = Opcode.values();
--- a/src/main/java/org/icedrobot/daneel/dex/ProtoId.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/ProtoId.java Tue Mar 15 23:25:43 2011 +0100 @@ -21,15 +21,15 @@ import java.nio.ByteBuffer; /** - * A parser class capable of parsing {@code proto_id_item} structures as part - * of DEX files. Keep package-private to hide internal API. - * @author Michael Starzinger <michi@complang.tuwien.ac.at> + * A parser class capable of parsing {@code proto_id_item} structures as part of + * DEX files. Keep package-private to hide internal API. */ class ProtoId { /** * Parses a {@code proto_id_item} structure in a DEX file at the buffer's * current position. + * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. * @return An object representing the parsed data.
--- a/src/main/java/org/icedrobot/daneel/dex/dexlib/DexLibDexReader.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/dexlib/DexLibDexReader.java Tue Mar 15 23:25:43 2011 +0100 @@ -49,284 +49,288 @@ import org.objectweb.asm.Type; public class DexLibDexReader implements DexReader { - private final DexFile dex; - private HashMap<String,Integer> classIndexMap; - - public DexLibDexReader(File file) throws IOException { - dex = new DexFile(file); - } - - @Override - public void accept(DexFileVisitor dv) { - List<ClassDefItem> classItems = dex.ClassDefsSection.getItems(); - for(ClassDefItem classItem: classItems) { - DexClassVisitor cv = dv.visitClass(asInternalName(classItem.getClassType())); - if (cv != null) { - accept(classItem, cv); - } + private final DexFile dex; + private HashMap<String, Integer> classIndexMap; + + public DexLibDexReader(File file) throws IOException { + dex = new DexFile(file); + } + + @Override + public void accept(DexFileVisitor dv) { + List<ClassDefItem> classItems = dex.ClassDefsSection.getItems(); + for (ClassDefItem classItem : classItems) { + DexClassVisitor cv = dv.visitClass(asInternalName(classItem + .getClassType())); + if (cv != null) { + accept(classItem, cv); + } + } + dv.visitEnd(); } - dv.visitEnd(); - } - - @Override - public void accept(String className, DexClassVisitor cv) throws ClassNotFoundException { - if (classIndexMap == null) { - HashMap<String, Integer> map = new HashMap<String,Integer>(); - int index = 0; - List<ClassDefItem> classItems = dex.ClassDefsSection.getItems(); - for(ClassDefItem classItem: classItems) { - map.put(asInternalName(classItem.getClassType()).replace('/', '.'), index++); - } - classIndexMap = map; - } - - Integer index = classIndexMap.get(className); - if (index == null) { - throw new ClassNotFoundException(className); - } - accept(dex.ClassDefsSection.getItemByIndex(index), cv); - } - private static void accept(ClassDefItem classItem, DexClassVisitor cv) { - TypeListItem interfaceListItem = classItem.getInterfaces(); - String[] interfaces = null; - if (interfaceListItem != null) { - interfaces = new String[interfaceListItem.getTypeCount()]; - for(int i=0; i<interfaces.length; i++) { - interfaces[i] = asInternalName(interfaceListItem.getTypeIdItem(i)); - } - } - - cv.visit(classItem.getAccessFlags(), - asInternalName(classItem.getClassType()), - asInternalName(classItem.getSuperclass()), - interfaces); - - StringIdItem sourceFile = classItem.getSourceFile(); - if (sourceFile != null) { - cv.visitSource(sourceFile.getStringValue()); + @Override + public void accept(String className, DexClassVisitor cv) + throws ClassNotFoundException { + if (classIndexMap == null) { + HashMap<String, Integer> map = new HashMap<String, Integer>(); + int index = 0; + List<ClassDefItem> classItems = dex.ClassDefsSection.getItems(); + for (ClassDefItem classItem : classItems) { + map.put(asInternalName(classItem.getClassType()).replace('/', + '.'), index++); + } + classIndexMap = map; + } + + Integer index = classIndexMap.get(className); + if (index == null) { + throw new ClassNotFoundException(className); + } + accept(dex.ClassDefsSection.getItemByIndex(index), cv); } - - // outer-class - - // annotations - - // attributes - - // inner classes - - // fields - ClassDataItem classData = classItem.getClassData(); - acceptField(classData.getStaticFields(), classItem.getStaticFieldInitializers(), cv); - acceptField(classData.getInstanceFields(), null, cv); - - // methods - acceptMethod(classData.getDirectMethods(), cv); - acceptMethod(classData.getVirtualMethods(), cv); - - cv.visitEnd(); - } + + private static void accept(ClassDefItem classItem, DexClassVisitor cv) { + TypeListItem interfaceListItem = classItem.getInterfaces(); + String[] interfaces = null; + if (interfaceListItem != null) { + interfaces = new String[interfaceListItem.getTypeCount()]; + for (int i = 0; i < interfaces.length; i++) { + interfaces[i] = asInternalName(interfaceListItem + .getTypeIdItem(i)); + } + } + + cv.visit(classItem.getAccessFlags(), + asInternalName(classItem.getClassType()), + asInternalName(classItem.getSuperclass()), interfaces); + + StringIdItem sourceFile = classItem.getSourceFile(); + if (sourceFile != null) { + cv.visitSource(sourceFile.getStringValue()); + } + + // outer-class + + // annotations + + // attributes + + // inner classes + + // fields + ClassDataItem classData = classItem.getClassData(); + acceptField(classData.getStaticFields(), + classItem.getStaticFieldInitializers(), cv); + acceptField(classData.getInstanceFields(), null, cv); + + // methods + acceptMethod(classData.getDirectMethods(), cv); + acceptMethod(classData.getVirtualMethods(), cv); + + cv.visitEnd(); + } + + private static String asInternalName(TypeIdItem typeIdItem) { + return Type.getType(typeIdItem.getTypeDescriptor()).getInternalName(); + } - private static String asInternalName(TypeIdItem typeIdItem) { - return Type.getType(typeIdItem.getTypeDescriptor()).getInternalName(); - } - - private static void acceptField(EncodedField[] fields, EncodedArrayItem staticInitItem, DexClassVisitor cv) { - EncodedValue[] constants = (staticInitItem == null)? null: staticInitItem.getEncodedArray().values; - - for(int i=0; i<fields.length; i++) { - EncodedField field = fields[i]; - FieldIdItem fieldIdItem = field.field; - - DexFieldVisitor fv = cv.visitField(field.accessFlags, fieldIdItem.getFieldName().getStringValue(), - asInternalName(fieldIdItem.getFieldType()), - (constants == null? null: getConstant(constants[i]))); - if (fv != null) { - // visit annotation - - // visit attribute - - fv.visitEnd(); - } + private static void acceptField(EncodedField[] fields, + EncodedArrayItem staticInitItem, DexClassVisitor cv) { + EncodedValue[] constants = (staticInitItem == null) ? null + : staticInitItem.getEncodedArray().values; + + for (int i = 0; i < fields.length; i++) { + EncodedField field = fields[i]; + FieldIdItem fieldIdItem = field.field; + + DexFieldVisitor fv = cv.visitField(field.accessFlags, fieldIdItem + .getFieldName().getStringValue(), + asInternalName(fieldIdItem.getFieldType()), + (constants == null ? null : getConstant(constants[i]))); + if (fv != null) { + // visit annotation + + // visit attribute + + fv.visitEnd(); + } + } } - } - - private static Object getConstant(EncodedValue value) { - switch(value.getValueType()) { - case VALUE_BOOLEAN: - return ((BooleanEncodedValue)value).value; - case VALUE_BYTE: - return ((ByteEncodedValue)value).value; - case VALUE_SHORT: - return ((ShortEncodedValue)value).value; - case VALUE_CHAR: - return ((CharEncodedValue)value).value; - case VALUE_INT: - return ((IntEncodedValue)value).value; - case VALUE_LONG: - return ((LongEncodedValue)value).value; - case VALUE_FLOAT: - return ((FloatEncodedValue)value).value; - case VALUE_DOUBLE: - return ((DoubleEncodedValue)value).value; - default: - throw new AssertionError("invalid type "+value.getValueType()); + + private static Object getConstant(EncodedValue value) { + switch (value.getValueType()) { + case VALUE_BOOLEAN: + return ((BooleanEncodedValue) value).value; + case VALUE_BYTE: + return ((ByteEncodedValue) value).value; + case VALUE_SHORT: + return ((ShortEncodedValue) value).value; + case VALUE_CHAR: + return ((CharEncodedValue) value).value; + case VALUE_INT: + return ((IntEncodedValue) value).value; + case VALUE_LONG: + return ((LongEncodedValue) value).value; + case VALUE_FLOAT: + return ((FloatEncodedValue) value).value; + case VALUE_DOUBLE: + return ((DoubleEncodedValue) value).value; + default: + throw new AssertionError("invalid type " + value.getValueType()); + } } - } + + private static void acceptMethod(EncodedMethod[] methods, DexClassVisitor cv) { + for (EncodedMethod method : methods) { + MethodIdItem methodIdItem = method.method; + ProtoIdItem protoIdItem = methodIdItem.getPrototype(); - private static void acceptMethod(EncodedMethod[] methods, DexClassVisitor cv) { - for(EncodedMethod method: methods) { - MethodIdItem methodIdItem = method.method; - ProtoIdItem protoIdItem = methodIdItem.getPrototype(); - - DexMethodVisitor mv = cv.visitMethod(method.accessFlags, methodIdItem.getMethodName().getStringValue(), - protoIdItem.getConciseIdentity(), - protoIdItem.getReturnType().getTypeDescriptor(), - asDescriptorArray(protoIdItem)); - if (mv != null) { - CodeItem codeItem = method.codeItem; - - // visit annotation default - - // visit annotation - - // visit parameter annotation - - // visit attribute - - mv.visitCode(codeItem.getRegisterCount(), -1, -1); //FIXME insSize/outSize - acceptCode(codeItem, mv); - mv.visitEnd(); - } - } - } + DexMethodVisitor mv = cv.visitMethod(method.accessFlags, + methodIdItem.getMethodName().getStringValue(), protoIdItem + .getConciseIdentity(), protoIdItem.getReturnType() + .getTypeDescriptor(), + asDescriptorArray(protoIdItem)); + if (mv != null) { + CodeItem codeItem = method.codeItem; + + // visit annotation default - private static String[] asDescriptorArray(ProtoIdItem protoIdItem) { - TypeListItem parameters = protoIdItem.getParameters(); - if (parameters == null) { - return new String[0]; - } - int length = parameters.getTypeCount(); - String[] types = new String[length]; - for(int i=0; i<length; i++) { - types[i] = parameters.getTypeIdItem(i).getTypeDescriptor(); + // visit annotation + + // visit parameter annotation + + // visit attribute + + mv.visitCode(codeItem.getRegisterCount(), -1, -1); // FIXME + // insSize/outSize + acceptCode(codeItem, mv); + mv.visitEnd(); + } + } } - return types; - } - // opcode categories - private static final int INSTR = 0; - private static final int INSTR_OP = 1; - private static final int INSTR_UNARY_OP = 2; - private static final int INSTR_BIN_OP = 3; - private static final int INSTR_BIN_AND_LITERAL = 4; - private static final int INSTR_CONST_STRING = 5; - private static final int INSTR_CONST_U32 = 6; - private static final int INSTR_CONST_U64 = 7; - private static final int INSTR_CLASS = 8; - private static final int INSTR_INSTANCEOF = 9; - private static final int INSTR_GOTO = 10; - private static final int INSTR_IF_TESTZ = 11; - private static final int INSTR_IF_TEST = 12; - private static final int INSTR_SWITCH = 13; - private static final int INSTR_ARRAY = 14; - private static final int INSTR_FIELD = 15; - private static final int INSTR_METHOD = 16; - private static final int INSTR_FILLED_NEW_ARRAY = 17; - private static final int INSTR_NEW_ARRAY = 18; - private static final int INSTR_FILL_ARRAY_DATA = 19; - - private static final int[] OPCODE_CATEGORY; - static { // see OpcodesEncoder - int[] categories = new int[256]; - String text = "ACCCCCCCCCBBBBABBBGGGGHHHHFFIBBI"+ - "JCISRRTBKKKNNDDDDDMMMMMMLLLLLL@@"+ - "@@@@OOOOOOOOOOOOOOPPPPPPPPPPPPPP"+ - "PPPPPPPPPPPPPPQQQQQ@QQQQQ@@CCCCC"+ - "CCCCCCCCC@CCCCCCDDDDDDDDDDDDDDDD"+ - "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"+ - "DDDDDDDDDDDDDDDDEEEEEEEEEEEEEEEE"+ - "EEE@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; - for(int i=0; i<text.length(); i++) { - categories[i] = text.charAt(i) - 'A'; + private static String[] asDescriptorArray(ProtoIdItem protoIdItem) { + TypeListItem parameters = protoIdItem.getParameters(); + if (parameters == null) { + return new String[0]; + } + int length = parameters.getTypeCount(); + String[] types = new String[length]; + for (int i = 0; i < length; i++) { + types[i] = parameters.getTypeIdItem(i).getTypeDescriptor(); + } + return types; } - OPCODE_CATEGORY = categories; - } - - private static void acceptCode(CodeItem codeItem, DexMethodVisitor mv) { - Instruction[] instrs = codeItem.getInstructions(); - for(int i=0; i<instrs.length; i++) { - Instruction instr = instrs[i]; - acceptInstr(instr, mv); - } - } + + // opcode categories + private static final int INSTR = 0; + private static final int INSTR_OP = 1; + private static final int INSTR_UNARY_OP = 2; + private static final int INSTR_BIN_OP = 3; + private static final int INSTR_BIN_AND_LITERAL = 4; + private static final int INSTR_CONST_STRING = 5; + private static final int INSTR_CONST_U32 = 6; + private static final int INSTR_CONST_U64 = 7; + private static final int INSTR_CLASS = 8; + private static final int INSTR_INSTANCEOF = 9; + private static final int INSTR_GOTO = 10; + private static final int INSTR_IF_TESTZ = 11; + private static final int INSTR_IF_TEST = 12; + private static final int INSTR_SWITCH = 13; + private static final int INSTR_ARRAY = 14; + private static final int INSTR_FIELD = 15; + private static final int INSTR_METHOD = 16; + private static final int INSTR_FILLED_NEW_ARRAY = 17; + private static final int INSTR_NEW_ARRAY = 18; + private static final int INSTR_FILL_ARRAY_DATA = 19; - private static void acceptInstr(Instruction instr, DexMethodVisitor mv) { - org.jf.dexlib.Code.Opcode dexOpcode = instr.opcode; - Opcode opcode = Opcode.getOpcode(dexOpcode.value); - switch(OPCODE_CATEGORY[dexOpcode.value]) { - - case INSTR: - mv.visitInstr(opcode); - break; - - case INSTR_FIELD: { - FieldIdItem field; - int vsrcOrDest; - int vref; - if (instr instanceof Instruction21c) { - Instruction21c i21c = (Instruction21c)instr; - field = (FieldIdItem)i21c.getReferencedItem(); - vsrcOrDest = i21c.getRegisterA(); - vref = 0; // no instance - } else { - Instruction22c i22c = (Instruction22c)instr; - field = (FieldIdItem)i22c.getReferencedItem(); - vsrcOrDest = i22c.getRegisterA(); - vref = i22c.getRegisterB(); + private static final int[] OPCODE_CATEGORY; + static { // see OpcodesEncoder + int[] categories = new int[256]; + String text = "ACCCCCCCCCBBBBABBBGGGGHHHHFFIBBI" + + "JCISRRTBKKKNNDDDDDMMMMMMLLLLLL@@" + + "@@@@OOOOOOOOOOOOOOPPPPPPPPPPPPPP" + + "PPPPPPPPPPPPPPQQQQQ@QQQQQ@@CCCCC" + + "CCCCCCCCC@CCCCCCDDDDDDDDDDDDDDDD" + + "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" + + "DDDDDDDDDDDDDDDDEEEEEEEEEEEEEEEE" + + "EEE@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; + for (int i = 0; i < text.length(); i++) { + categories[i] = text.charAt(i) - 'A'; + } + OPCODE_CATEGORY = categories; + } + + private static void acceptCode(CodeItem codeItem, DexMethodVisitor mv) { + Instruction[] instrs = codeItem.getInstructions(); + for (int i = 0; i < instrs.length; i++) { + Instruction instr = instrs[i]; + acceptInstr(instr, mv); } - mv.visitInstrField(opcode, vsrcOrDest, - vref, - asInternalName(field.getContainingClass()), - field.getFieldName().getStringValue(), - field.getFieldType().getTypeDescriptor()); - break; - } - - case INSTR_CONST_U64: { - int vdest = ((SingleRegisterInstruction)instr).getRegisterA(); - long value = ((LiteralInstruction)instr).getLiteral(); - mv.visitInstrConstU64(opcode, vdest, value); - break; } - - case INSTR_CONST_STRING: { - Item<?> item = ((InstructionWithReference)instr).getReferencedItem(); - int registerA = ((SingleRegisterInstruction)instr).getRegisterA(); - mv.visitInstrConstString(opcode, registerA, ((StringIdItem)item).getStringValue()); - break; - } - - case INSTR_METHOD: { //TODO implement range !!! - Instruction35c i35c = (Instruction35c)instr; - MethodIdItem methodIdItem = (MethodIdItem)i35c.getReferencedItem(); - String desc = methodIdItem.getPrototype().getPrototypeString(); - int vpacked = i35c.getRegisterG() << 12 | - i35c.getRegisterF() << 8 | - i35c.getRegisterE() << 4 | - i35c.getRegisterD(); - mv.visitInstrMethod(opcode, - i35c.getRegCount(), - i35c.getRegisterA(), - vpacked, - asInternalName(methodIdItem.getContainingClass()), - methodIdItem.getMethodName().getStringValue(), - desc); - break; - } - - default: - throw new AssertionError("unknown category for "+dexOpcode); + + private static void acceptInstr(Instruction instr, DexMethodVisitor mv) { + org.jf.dexlib.Code.Opcode dexOpcode = instr.opcode; + Opcode opcode = Opcode.getOpcode(dexOpcode.value); + switch (OPCODE_CATEGORY[dexOpcode.value]) { + + case INSTR: + mv.visitInstr(opcode); + break; + + case INSTR_FIELD: { + FieldIdItem field; + int vsrcOrDest; + int vref; + if (instr instanceof Instruction21c) { + Instruction21c i21c = (Instruction21c) instr; + field = (FieldIdItem) i21c.getReferencedItem(); + vsrcOrDest = i21c.getRegisterA(); + vref = 0; // no instance + } else { + Instruction22c i22c = (Instruction22c) instr; + field = (FieldIdItem) i22c.getReferencedItem(); + vsrcOrDest = i22c.getRegisterA(); + vref = i22c.getRegisterB(); + } + mv.visitInstrField(opcode, vsrcOrDest, vref, asInternalName(field + .getContainingClass()), field.getFieldName() + .getStringValue(), field.getFieldType().getTypeDescriptor()); + break; + } + + case INSTR_CONST_U64: { + int vdest = ((SingleRegisterInstruction) instr).getRegisterA(); + long value = ((LiteralInstruction) instr).getLiteral(); + mv.visitInstrConstU64(opcode, vdest, value); + break; + } + + case INSTR_CONST_STRING: { + Item<?> item = ((InstructionWithReference) instr) + .getReferencedItem(); + int registerA = ((SingleRegisterInstruction) instr).getRegisterA(); + mv.visitInstrConstString(opcode, registerA, + ((StringIdItem) item).getStringValue()); + break; + } + + case INSTR_METHOD: { // TODO implement range !!! + Instruction35c i35c = (Instruction35c) instr; + MethodIdItem methodIdItem = (MethodIdItem) i35c.getReferencedItem(); + String desc = methodIdItem.getPrototype().getPrototypeString(); + int vpacked = i35c.getRegisterG() << 12 | i35c.getRegisterF() << 8 + | i35c.getRegisterE() << 4 | i35c.getRegisterD(); + mv.visitInstrMethod(opcode, i35c.getRegCount(), + i35c.getRegisterA(), vpacked, + asInternalName(methodIdItem.getContainingClass()), + methodIdItem.getMethodName().getStringValue(), desc); + break; + } + + default: + throw new AssertionError("unknown category for " + dexOpcode); + } } - } }
--- a/src/main/java/org/icedrobot/daneel/dex/dexlib/OpcodesEncoder.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/dexlib/OpcodesEncoder.java Tue Mar 15 23:25:43 2011 +0100 @@ -7,135 +7,125 @@ import static org.icedrobot.daneel.dex.Opcode.*; class OpcodesEncoder { - //opcode categories - private static final int INSTR = 0; - private static final int INSTR_OP = 1; - private static final int INSTR_UNARY_OP = 2; - private static final int INSTR_BIN_OP = 3; - private static final int INSTR_BIN_AND_LITERAL = 4; - private static final int INSTR_CONST_STRING = 5; - private static final int INSTR_CONST_U32 = 6; - private static final int INSTR_CONST_U64 = 7; - private static final int INSTR_CLASS = 8; - private static final int INSTR_INSTANCEOF = 9; - private static final int INSTR_GOTO = 10; - private static final int INSTR_IF_TESTZ = 11; - private static final int INSTR_IF_TEST = 12; - private static final int INSTR_SWITCH = 13; - private static final int INSTR_ARRAY = 14; - private static final int INSTR_FIELD = 15; - private static final int INSTR_METHOD = 16; - private static final int INSTR_FILLED_NEW_ARRAY = 17; - private static final int INSTR_NEW_ARRAY = 18; - private static final int INSTR_FILL_ARRAY_DATA = 19; - - public static void main(String[] args) { - Object[] assoc = { - INSTR, new Opcode[] { - NOP, RETURN_VOID - }, - INSTR_OP, new Opcode[] { - MOVE_RESULT, MOVE_RESULT_WIDE, - MOVE_RESULT_OBJECT, MOVE_EXCEPTION, RETURN, MONITOR_ENTER, MONITOR_EXIT, - RETURN_WIDE, RETURN_OBJECT, THROW - }, - INSTR_UNARY_OP, new Opcode[] { - MOVE, MOVE_FROM16, MOVE_16, MOVE_WIDE, - MOVE_WIDE_FROM16, MOVE_WIDE_16, MOVE_OBJECT, MOVE_OBJECT_FROM16, - MOVE_OBJECT_16, NEG_INT, NOT_INT, NEG_LONG, NOT_LONG, NEG_FLOAT, - NEG_DOUBLE, INT_TO_LONG, INT_TO_FLOAT, INT_TO_DOUBLE, LONG_TO_INT, - LONG_TO_FLOAT, LONG_TO_DOUBLE, FLOAT_TO_INT, FLOAT_TO_LONG, - DOUBLE_TO_INT, DOUBLE_TO_LONG, DOUBLE_TO_FLOAT, INT_TO_BYTE, INT_TO_CHAR, - INT_TO_SHORT, ARRAY_LENGTH - }, - INSTR_BIN_OP, new Opcode[] { - CMPL_FLOAT, CMPG_FLOAT, CMPL_DOUBLE, - CMPG_DOUBLE, CMP_LONG, ADD_INT, SUB_INT, MUL_INT, DIV_INT, REM_INT, - AND_INT, OR_INT, XOR_INT, SHL_INT, SHR_INT, USHR_INT, ADD_LONG, SUB_LONG, - MUL_LONG, DIV_LONG, REM_LONG, AND_LONG, OR_LONG, XOR_LONG, SHL_LONG, - SHR_LONG, USHR_LONG, ADD_FLOAT, SUB_FLOAT, MUL_FLOAT, DIV_FLOAT, - REM_FLOAT, ADD_DOUBLE, SUB_DOUBLE, MUL_DOUBLE, DIV_DOUBLE, REM_DOUBLE, - ADD_INT_2ADDR, SUB_INT_2ADDR, MUL_INT_2ADDR, DIV_INT_2ADDR, - REM_INT_2ADDR, AND_INT_2ADDR, OR_INT_2ADDR, XOR_INT_2ADDR, SHL_INT_2ADDR, - SHR_INT_2ADDR, USHR_INT_2ADDR, ADD_LONG_2ADDR, SUB_LONG_2ADDR, - MUL_LONG_2ADDR, DIV_LONG_2ADDR, REM_LONG_2ADDR, AND_LONG_2ADDR, - OR_LONG_2ADDR, XOR_LONG_2ADDR, SHL_LONG_2ADDR, SHR_LONG_2ADDR, - USHR_LONG_2ADDR, ADD_FLOAT_2ADDR, SUB_FLOAT_2ADDR, MUL_FLOAT_2ADDR, - DIV_FLOAT_2ADDR, REM_FLOAT_2ADDR, ADD_DOUBLE_2ADDR, SUB_DOUBLE_2ADDR, - MUL_DOUBLE_2ADDR, DIV_DOUBLE_2ADDR, REM_DOUBLE_2ADDR - }, - INSTR_BIN_AND_LITERAL, new Opcode[] { - ADD_INT_LIT16, RSUB_INT_LIT16, - MUL_INT_LIT16, DIV_INT_LIT16, REM_INT_LIT16, AND_INT_LIT16, OR_INT_LIT16, - XOR_INT_LIT16, ADD_INT_LIT8, RSUB_INT_LIT8, MUL_INT_LIT8, DIV_INT_LIT8, - REM_INT_LIT8, AND_INT_LIT8, OR_INT_LIT8, XOR_INT_LIT8, SHL_INT_LIT8, - SHR_INT_LIT8, USHR_INT_LIT8 - }, - INSTR_CONST_STRING, new Opcode[] { - CONST_STRING, CONST_STRING_JUMBO - }, - INSTR_CONST_U32, new Opcode[] { - CONST_4, CONST_16, CONST, CONST_HIGH16 - }, - INSTR_CONST_U64, new Opcode[] { - CONST_WIDE_16, CONST_WIDE_32, CONST_WIDE, CONST_WIDE_HIGH16 - }, - INSTR_CLASS, new Opcode[] { - CONST_CLASS, CHECK_CAST, NEW_INSTANCE - }, - INSTR_INSTANCEOF, new Opcode[] { - INSTANCE_OF - }, - INSTR_GOTO, new Opcode[] { - GOTO_32, GOTO, GOTO_16 - }, - INSTR_IF_TESTZ, new Opcode[] { - IF_EQZ, IF_NEZ, IF_LTZ, IF_GEZ, IF_GTZ, IF_LEZ - }, - INSTR_IF_TEST, new Opcode[] { - IF_EQ, IF_NE, IF_LT, IF_GE, IF_GT, IF_LE - }, - INSTR_SWITCH, new Opcode[] { - PACKED_SWITCH, SPARSE_SWITCH - }, - INSTR_ARRAY, new Opcode[] { - APUT, APUT_WIDE, APUT_OBJECT, APUT_BOOLEAN, - APUT_BYTE, APUT_CHAR, APUT_SHORT, AGET, AGET_WIDE, AGET_OBJECT, - AGET_BOOLEAN, AGET_BYTE, AGET_CHAR, AGET_SHORT - }, - INSTR_FIELD, new Opcode[] { - IGET, IGET_WIDE, IGET_OBJECT, IGET_BOOLEAN, - IGET_BYTE, IGET_CHAR, IGET_SHORT, IPUT, IPUT_WIDE, IPUT_OBJECT, - IPUT_BOOLEAN, IPUT_BYTE, IPUT_CHAR, IPUT_SHORT, SGET, SGET_WIDE, - SGET_OBJECT, SGET_BOOLEAN, SGET_BYTE, SGET_CHAR, SGET_SHORT, SPUT, - SPUT_WIDE, SPUT_OBJECT, SPUT_BOOLEAN, SPUT_BYTE, SPUT_CHAR, SPUT_SHORT - }, - INSTR_METHOD, new Opcode[] { - INVOKE_VIRTUAL, INVOKE_SUPER, - INVOKE_DIRECT, INVOKE_STATIC, INVOKE_INTERFACE, INVOKE_VIRTUAL_RANGE, - INVOKE_SUPER_RANGE, INVOKE_DIRECT_RANGE, INVOKE_STATIC_RANGE, - INVOKE_INTERFACE_RANGE - }, - INSTR_FILLED_NEW_ARRAY, new Opcode[] { - FILLED_NEW_ARRAY, FILLED_NEW_ARRAY_RANGE - }, - INSTR_NEW_ARRAY, new Opcode[] { - NEW_ARRAY - }, - INSTR_FILL_ARRAY_DATA, new Opcode[] { - FILL_ARRAY_DATA - }, - }; - - char[] text = new char[256]; - Arrays.fill(text, '@'); - for(int i=0; i<assoc.length; i+=2) { - int category = (Integer)assoc[i]; - Opcode[] opcodes = (Opcode[])assoc[i+1]; - for(Opcode opcode: opcodes) { - text[opcode.ordinal()] = (char)('A' + category); - } + // opcode categories + private static final int INSTR = 0; + private static final int INSTR_OP = 1; + private static final int INSTR_UNARY_OP = 2; + private static final int INSTR_BIN_OP = 3; + private static final int INSTR_BIN_AND_LITERAL = 4; + private static final int INSTR_CONST_STRING = 5; + private static final int INSTR_CONST_U32 = 6; + private static final int INSTR_CONST_U64 = 7; + private static final int INSTR_CLASS = 8; + private static final int INSTR_INSTANCEOF = 9; + private static final int INSTR_GOTO = 10; + private static final int INSTR_IF_TESTZ = 11; + private static final int INSTR_IF_TEST = 12; + private static final int INSTR_SWITCH = 13; + private static final int INSTR_ARRAY = 14; + private static final int INSTR_FIELD = 15; + private static final int INSTR_METHOD = 16; + private static final int INSTR_FILLED_NEW_ARRAY = 17; + private static final int INSTR_NEW_ARRAY = 18; + private static final int INSTR_FILL_ARRAY_DATA = 19; + + public static void main(String[] args) { + Object[] assoc = { + INSTR, + new Opcode[] { NOP, RETURN_VOID }, + INSTR_OP, + new Opcode[] { MOVE_RESULT, MOVE_RESULT_WIDE, + MOVE_RESULT_OBJECT, MOVE_EXCEPTION, RETURN, + MONITOR_ENTER, MONITOR_EXIT, RETURN_WIDE, + RETURN_OBJECT, THROW }, + INSTR_UNARY_OP, + new Opcode[] { MOVE, MOVE_FROM16, MOVE_16, MOVE_WIDE, + MOVE_WIDE_FROM16, MOVE_WIDE_16, MOVE_OBJECT, + MOVE_OBJECT_FROM16, MOVE_OBJECT_16, NEG_INT, NOT_INT, + NEG_LONG, NOT_LONG, NEG_FLOAT, NEG_DOUBLE, INT_TO_LONG, + INT_TO_FLOAT, INT_TO_DOUBLE, LONG_TO_INT, + LONG_TO_FLOAT, LONG_TO_DOUBLE, FLOAT_TO_INT, + FLOAT_TO_LONG, DOUBLE_TO_INT, DOUBLE_TO_LONG, + DOUBLE_TO_FLOAT, INT_TO_BYTE, INT_TO_CHAR, + INT_TO_SHORT, ARRAY_LENGTH }, + INSTR_BIN_OP, + new Opcode[] { CMPL_FLOAT, CMPG_FLOAT, CMPL_DOUBLE, + CMPG_DOUBLE, CMP_LONG, ADD_INT, SUB_INT, MUL_INT, + DIV_INT, REM_INT, AND_INT, OR_INT, XOR_INT, SHL_INT, + SHR_INT, USHR_INT, ADD_LONG, SUB_LONG, MUL_LONG, + DIV_LONG, REM_LONG, AND_LONG, OR_LONG, XOR_LONG, + SHL_LONG, SHR_LONG, USHR_LONG, ADD_FLOAT, SUB_FLOAT, + MUL_FLOAT, DIV_FLOAT, REM_FLOAT, ADD_DOUBLE, + SUB_DOUBLE, MUL_DOUBLE, DIV_DOUBLE, REM_DOUBLE, + ADD_INT_2ADDR, SUB_INT_2ADDR, MUL_INT_2ADDR, + DIV_INT_2ADDR, REM_INT_2ADDR, AND_INT_2ADDR, + OR_INT_2ADDR, XOR_INT_2ADDR, SHL_INT_2ADDR, + SHR_INT_2ADDR, USHR_INT_2ADDR, ADD_LONG_2ADDR, + SUB_LONG_2ADDR, MUL_LONG_2ADDR, DIV_LONG_2ADDR, + REM_LONG_2ADDR, AND_LONG_2ADDR, OR_LONG_2ADDR, + XOR_LONG_2ADDR, SHL_LONG_2ADDR, SHR_LONG_2ADDR, + USHR_LONG_2ADDR, ADD_FLOAT_2ADDR, SUB_FLOAT_2ADDR, + MUL_FLOAT_2ADDR, DIV_FLOAT_2ADDR, REM_FLOAT_2ADDR, + ADD_DOUBLE_2ADDR, SUB_DOUBLE_2ADDR, MUL_DOUBLE_2ADDR, + DIV_DOUBLE_2ADDR, REM_DOUBLE_2ADDR }, + INSTR_BIN_AND_LITERAL, + new Opcode[] { ADD_INT_LIT16, RSUB_INT_LIT16, MUL_INT_LIT16, + DIV_INT_LIT16, REM_INT_LIT16, AND_INT_LIT16, + OR_INT_LIT16, XOR_INT_LIT16, ADD_INT_LIT8, + RSUB_INT_LIT8, MUL_INT_LIT8, DIV_INT_LIT8, + REM_INT_LIT8, AND_INT_LIT8, OR_INT_LIT8, XOR_INT_LIT8, + SHL_INT_LIT8, SHR_INT_LIT8, USHR_INT_LIT8 }, + INSTR_CONST_STRING, + new Opcode[] { CONST_STRING, CONST_STRING_JUMBO }, + INSTR_CONST_U32, + new Opcode[] { CONST_4, CONST_16, CONST, CONST_HIGH16 }, + INSTR_CONST_U64, + new Opcode[] { CONST_WIDE_16, CONST_WIDE_32, CONST_WIDE, + CONST_WIDE_HIGH16 }, + INSTR_CLASS, + new Opcode[] { CONST_CLASS, CHECK_CAST, NEW_INSTANCE }, + INSTR_INSTANCEOF, + new Opcode[] { INSTANCE_OF }, + INSTR_GOTO, + new Opcode[] { GOTO_32, GOTO, GOTO_16 }, + INSTR_IF_TESTZ, + new Opcode[] { IF_EQZ, IF_NEZ, IF_LTZ, IF_GEZ, IF_GTZ, IF_LEZ }, + INSTR_IF_TEST, + new Opcode[] { IF_EQ, IF_NE, IF_LT, IF_GE, IF_GT, IF_LE }, + INSTR_SWITCH, + new Opcode[] { PACKED_SWITCH, SPARSE_SWITCH }, + INSTR_ARRAY, + new Opcode[] { APUT, APUT_WIDE, APUT_OBJECT, APUT_BOOLEAN, + APUT_BYTE, APUT_CHAR, APUT_SHORT, AGET, AGET_WIDE, + AGET_OBJECT, AGET_BOOLEAN, AGET_BYTE, AGET_CHAR, + AGET_SHORT }, + INSTR_FIELD, + new Opcode[] { IGET, IGET_WIDE, IGET_OBJECT, IGET_BOOLEAN, + IGET_BYTE, IGET_CHAR, IGET_SHORT, IPUT, IPUT_WIDE, + IPUT_OBJECT, IPUT_BOOLEAN, IPUT_BYTE, IPUT_CHAR, + IPUT_SHORT, SGET, SGET_WIDE, SGET_OBJECT, SGET_BOOLEAN, + SGET_BYTE, SGET_CHAR, SGET_SHORT, SPUT, SPUT_WIDE, + SPUT_OBJECT, SPUT_BOOLEAN, SPUT_BYTE, SPUT_CHAR, + SPUT_SHORT }, + INSTR_METHOD, + new Opcode[] { INVOKE_VIRTUAL, INVOKE_SUPER, INVOKE_DIRECT, + INVOKE_STATIC, INVOKE_INTERFACE, INVOKE_VIRTUAL_RANGE, + INVOKE_SUPER_RANGE, INVOKE_DIRECT_RANGE, + INVOKE_STATIC_RANGE, INVOKE_INTERFACE_RANGE }, + INSTR_FILLED_NEW_ARRAY, + new Opcode[] { FILLED_NEW_ARRAY, FILLED_NEW_ARRAY_RANGE }, + INSTR_NEW_ARRAY, new Opcode[] { NEW_ARRAY }, + INSTR_FILL_ARRAY_DATA, new Opcode[] { FILL_ARRAY_DATA }, }; + + char[] text = new char[256]; + Arrays.fill(text, '@'); + for (int i = 0; i < assoc.length; i += 2) { + int category = (Integer) assoc[i]; + Opcode[] opcodes = (Opcode[]) assoc[i + 1]; + for (Opcode opcode : opcodes) { + text[opcode.ordinal()] = (char) ('A' + category); + } + } + System.out.println(new String(text)); } - System.out.println(new String(text)); - } }
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Tue Mar 15 23:25:43 2011 +0100 @@ -21,308 +21,341 @@ import org.objectweb.asm.tree.VarInsnNode; public class DexRewriter implements DexClassVisitor { - private final ClassVisitor cv; - - public DexRewriter(ClassVisitor cv) { - this.cv = cv; - } + private final ClassVisitor cv; - @Override - public void visit(int access, String name, String supername, String[] interfaces) { - cv.visit(V1_6, access, - name, - null, - supername, - interfaces); - } - - @Override - public void visitSource(String source) { - cv.visitSource(source, null); - } - - @Override - public DexFieldVisitor visitField(int access, String name, String type, Object value) { - final FieldVisitor fv = cv.visitField(access, name, type, null, value); - if (fv == null) { - return null; - } - - return new DexFieldVisitor() { - @Override - public void visitEnd() { - fv.visitEnd(); - } - }; - } - - @Override - public DexMethodVisitor visitMethod(int access, String name, String shorty, String returnType, String[] parameterTypes) { - StringBuilder desc = new StringBuilder(); - desc.append('('); - for(String parameterType: parameterTypes) { - desc.append(parameterType); + public DexRewriter(ClassVisitor cv) { + this.cv = cv; } - desc.append(')'); - desc.append(returnType); - - MethodVisitor mv = cv.visitMethod(access, name, - desc.toString(), - null, - null); - if (mv == null) { - return null; - } - - return new MethodRewriter(mv); - } - - @Override - public void visitEnd() { - cv.visitEnd(); - } - static class MethodRewriter implements DexMethodVisitor { - final PatchMethodVisitor mv; - - private Interpreter interpreter; - private int returnRegisterType; // type of the register used to stored the return value - - public MethodRewriter(MethodVisitor mv) { - this.mv = new PatchMethodVisitor(mv); + @Override + public void visit(int access, String name, String supername, + String[] interfaces) { + cv.visit(V1_6, access, name, null, supername, interfaces); } - - private static int getTypeFromASMType(Type type) { - switch(type.getSort()) { - case Type.BOOLEAN: - return BOOLEAN_TYPE; - case Type.BYTE: - return BYTE_TYPE; - case Type.CHAR: - return CHAR_TYPE; - case Type.SHORT: - return SHORT_TYPE; - case Type.INT: - return INT_TYPE; - case Type.LONG: - return LONG_TYPE; - case Type.FLOAT: - return FLOAT_TYPE; - case Type.DOUBLE: - return DOUBLE_TYPE; - case Type.VOID: - return VOID_TYPE; - default: - return OBJECT_TYPE; - } - } - - private static int getTypeFromFieldDescriptor(String descriptor) { - return getTypeFromASMType(Type.getType(descriptor)); - } - - private static int getReturnTypeFromMethodDescriptor(String descriptor) { - return getTypeFromASMType(Type.getReturnType(descriptor)); + + @Override + public void visitSource(String source) { + cv.visitSource(source, null); } - - private static void throwNewAssertionError(Opcode opcode) { - throw new AssertionError("invalid opcode "+opcode); - } - - @Override - public void visitCode(int registerSize, int insSize, int outSize) { - mv.visitCode(); - interpreter = new Interpreter(registerSize); - } - + @Override - public void visitInstr(Opcode opcode) { - if (opcode == Opcode.RETURN_VOID) { - mv.visitInsn(RETURN); - interpreter.setDead(); - return; - } - if (opcode == Opcode.NOP) { - mv.visitInsn(NOP); - return; - } - throwNewAssertionError(opcode); + public DexFieldVisitor visitField(int access, String name, String type, + Object value) { + final FieldVisitor fv = cv.visitField(access, name, type, null, value); + if (fv == null) { + return null; + } + + return new DexFieldVisitor() { + @Override + public void visitEnd() { + fv.visitEnd(); + } + }; } - + @Override - public void visitInstrField(Opcode opcode, int vsrcOrDest, int vref, String owner, String name, String desc) { - if (opcode.compareTo(Opcode.IGET)>=0 && opcode.compareTo(Opcode.IGET_SHORT)<=0) { - mv.visitVarInsn(ALOAD, vref); - mv.visitFieldInsn(GETFIELD, owner, name, desc); - int type = getTypeFromFieldDescriptor(desc); - interpreter.store(vsrcOrDest, type); - mv.visitVarInsn(Register.getJavaOpcode(type, ISTORE), vsrcOrDest); - } else - if (opcode.compareTo(Opcode.SGET)>=0 && opcode.compareTo(Opcode.SGET_SHORT)<=0) { - mv.visitFieldInsn(GETSTATIC, owner, name, desc); - int type = getTypeFromFieldDescriptor(desc); - interpreter.store(vsrcOrDest, type); - mv.visitVarInsn(Register.getJavaOpcode(type, ISTORE), vsrcOrDest); - } else - if (opcode.compareTo(Opcode.IPUT)>=0 && opcode.compareTo(Opcode.IPUT_SHORT)<=0) { - mv.visitVarInsn(ALOAD, vref); - int type = getTypeFromFieldDescriptor(desc); - mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrcOrDest); - mv.visitFieldInsn(PUTFIELD, owner, name, desc); - interpreter.load(vsrcOrDest, type); - } else - if (opcode.compareTo(Opcode.SPUT)>=0 && opcode.compareTo(Opcode.SPUT_SHORT)<=0) { - int type = getTypeFromFieldDescriptor(desc); - mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrcOrDest); - mv.visitFieldInsn(PUTSTATIC, owner, name, desc); - interpreter.load(vsrcOrDest, type); - } else { - throwNewAssertionError(opcode); - } - } - - @Override - public void visitInstrConstString(Opcode opcode, int vdest, String value) { - mv.visitLdcInsn(value); - mv.visitVarInsn(ASTORE, vdest); - interpreter.store(vdest, OBJECT_TYPE); - } - - - @Override - public void visitInstrMethod(Opcode opcode, int num, int va, int vpacked, String owner, String name, String desc) { - switch(opcode) { - case INVOKE_VIRTUAL: - case INVOKE_STATIC: - case INVOKE_SUPER: - case INVOKE_DIRECT: - int javaOpcode; - int[] registers = { getRegisterD(vpacked), getRegisterE(vpacked), getRegisterF(vpacked), getRegisterG(vpacked), va}; - int r; - if (opcode == Opcode.INVOKE_STATIC) { - r = 0; - javaOpcode = INVOKESTATIC; - } else { - r = 1; - javaOpcode = (opcode == Opcode.INVOKE_SUPER)? INVOKESPECIAL: - (opcode == Opcode.INVOKE_DIRECT && "<init>".equals(name))? INVOKESPECIAL: INVOKEVIRTUAL; - int register = registers[0]; - mv.visitVarInsn(ALOAD, register); - interpreter.load(register, OBJECT_TYPE); + public DexMethodVisitor visitMethod(int access, String name, String shorty, + String returnType, String[] parameterTypes) { + StringBuilder desc = new StringBuilder(); + desc.append('('); + for (String parameterType : parameterTypes) { + desc.append(parameterType); } - - Type[] types = Type.getArgumentTypes(desc); - for(int i=0; i<types.length; i++) { - Type asmType = types[i]; - int type = getTypeFromASMType(asmType); - int register = registers[r]; - mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), register); - interpreter.load(register, type); - r += asmType.getSize(); + desc.append(')'); + desc.append(returnType); + + MethodVisitor mv = cv.visitMethod(access, name, desc.toString(), null, + null); + if (mv == null) { + return null; } - mv.visitMethodInsn(javaOpcode, owner, name, desc); - returnRegisterType = getReturnTypeFromMethodDescriptor(desc); - return; - default: - throwNewAssertionError(opcode); - } + + return new MethodRewriter(mv); } @Override - public void visitInstrConstU64(Opcode opcode, final int vdest, final long value) { - mv.setPatchMode(); - mv.visitLdcInsn(value); - final AbstractInsnNode ldc = mv.getLastInsnNode(); - mv.visitVarInsn(LSTORE, vdest); - final AbstractInsnNode lstore = mv.getLastInsnNode(); - interpreter.storeArbitraryType(vdest, U64_TYPE, new Patchable() { - @Override - protected void patch(int registerType) { - if (registerType == DOUBLE_TYPE) { - mv.patch(ldc, new LdcInsnNode(Double.longBitsToDouble(value))); - mv.patch(lstore, new VarInsnNode(DSTORE, vdest)); - } - } - }); - } - - // unimplemented - @Override - public void visitLabel(Label label) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrArray(Opcode opcode, int vsrcOrDest, int varray, int vindex) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrBinOp(Opcode opcode, int vdest, int vsrc, int vsrc2) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrBinOpAndLiteral(Opcode opcode, int vdest, int vsrc, int value) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrClass(Opcode opcode, int vdest, String type) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrConstU32(Opcode opcode, int vdest, int value) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrFillArrayData(Opcode opcode, int vsrc, Object arrayData) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrFilledNewArray(Opcode opcode, int num, int va, int vpacked, String type) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrGoto(Opcode opcode, Label label) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrIfTest(Opcode opcode, int vsrc1, int vsrc2, Label label) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrIfTestZ(Opcode opcode, int vsrc, Label label) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrInstanceof(Opcode opcode, int vdest, int vsrc, String type) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrNewArray(Opcode opcode, int vdest, int vsize, String type) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrOp(Opcode opcode, int srcOrDst) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrSwitch(Opcode opcode, int vsrc, Map<Integer, Label> labels) { - throw new UnsupportedOperationException("NYI"); - } - @Override - public void visitInstrUnaryOp(Opcode opcode, int vdest, int vsrc) { - throw new UnsupportedOperationException("NYI"); - } - - - @Override public void visitEnd() { - mv.visitMaxs(-1, -1); - mv.visitEnd(); + cv.visitEnd(); } - @Override - public void visitTryCatch(Label start, Label end, Label handler, String type) { - // TODO Auto-generated method stub - + static class MethodRewriter implements DexMethodVisitor { + final PatchMethodVisitor mv; + + private Interpreter interpreter; + private int returnRegisterType; // type of the register used to stored + // the return value + + public MethodRewriter(MethodVisitor mv) { + this.mv = new PatchMethodVisitor(mv); + } + + private static int getTypeFromASMType(Type type) { + switch (type.getSort()) { + case Type.BOOLEAN: + return BOOLEAN_TYPE; + case Type.BYTE: + return BYTE_TYPE; + case Type.CHAR: + return CHAR_TYPE; + case Type.SHORT: + return SHORT_TYPE; + case Type.INT: + return INT_TYPE; + case Type.LONG: + return LONG_TYPE; + case Type.FLOAT: + return FLOAT_TYPE; + case Type.DOUBLE: + return DOUBLE_TYPE; + case Type.VOID: + return VOID_TYPE; + default: + return OBJECT_TYPE; + } + } + + private static int getTypeFromFieldDescriptor(String descriptor) { + return getTypeFromASMType(Type.getType(descriptor)); + } + + private static int getReturnTypeFromMethodDescriptor(String descriptor) { + return getTypeFromASMType(Type.getReturnType(descriptor)); + } + + private static void throwNewAssertionError(Opcode opcode) { + throw new AssertionError("invalid opcode " + opcode); + } + + @Override + public void visitCode(int registerSize, int insSize, int outSize) { + mv.visitCode(); + interpreter = new Interpreter(registerSize); + } + + @Override + public void visitInstr(Opcode opcode) { + if (opcode == Opcode.RETURN_VOID) { + mv.visitInsn(RETURN); + interpreter.setDead(); + return; + } + if (opcode == Opcode.NOP) { + mv.visitInsn(NOP); + return; + } + throwNewAssertionError(opcode); + } + + @Override + public void visitInstrField(Opcode opcode, int vsrcOrDest, int vref, + String owner, String name, String desc) { + if (opcode.compareTo(Opcode.IGET) >= 0 + && opcode.compareTo(Opcode.IGET_SHORT) <= 0) { + mv.visitVarInsn(ALOAD, vref); + mv.visitFieldInsn(GETFIELD, owner, name, desc); + int type = getTypeFromFieldDescriptor(desc); + interpreter.store(vsrcOrDest, type); + mv.visitVarInsn(Register.getJavaOpcode(type, ISTORE), + vsrcOrDest); + } else if (opcode.compareTo(Opcode.SGET) >= 0 + && opcode.compareTo(Opcode.SGET_SHORT) <= 0) { + mv.visitFieldInsn(GETSTATIC, owner, name, desc); + int type = getTypeFromFieldDescriptor(desc); + interpreter.store(vsrcOrDest, type); + mv.visitVarInsn(Register.getJavaOpcode(type, ISTORE), + vsrcOrDest); + } else if (opcode.compareTo(Opcode.IPUT) >= 0 + && opcode.compareTo(Opcode.IPUT_SHORT) <= 0) { + mv.visitVarInsn(ALOAD, vref); + int type = getTypeFromFieldDescriptor(desc); + mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrcOrDest); + mv.visitFieldInsn(PUTFIELD, owner, name, desc); + interpreter.load(vsrcOrDest, type); + } else if (opcode.compareTo(Opcode.SPUT) >= 0 + && opcode.compareTo(Opcode.SPUT_SHORT) <= 0) { + int type = getTypeFromFieldDescriptor(desc); + mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrcOrDest); + mv.visitFieldInsn(PUTSTATIC, owner, name, desc); + interpreter.load(vsrcOrDest, type); + } else { + throwNewAssertionError(opcode); + } + } + + @Override + public void visitInstrConstString(Opcode opcode, int vdest, String value) { + mv.visitLdcInsn(value); + mv.visitVarInsn(ASTORE, vdest); + interpreter.store(vdest, OBJECT_TYPE); + } + + @Override + public void visitInstrMethod(Opcode opcode, int num, int va, + int vpacked, String owner, String name, String desc) { + switch (opcode) { + case INVOKE_VIRTUAL: + case INVOKE_STATIC: + case INVOKE_SUPER: + case INVOKE_DIRECT: + int javaOpcode; + int[] registers = { getRegisterD(vpacked), + getRegisterE(vpacked), getRegisterF(vpacked), + getRegisterG(vpacked), va }; + int r; + if (opcode == Opcode.INVOKE_STATIC) { + r = 0; + javaOpcode = INVOKESTATIC; + } else { + r = 1; + javaOpcode = (opcode == Opcode.INVOKE_SUPER) ? INVOKESPECIAL + : (opcode == Opcode.INVOKE_DIRECT && "<init>" + .equals(name)) ? INVOKESPECIAL + : INVOKEVIRTUAL; + int register = registers[0]; + mv.visitVarInsn(ALOAD, register); + interpreter.load(register, OBJECT_TYPE); + } + + Type[] types = Type.getArgumentTypes(desc); + for (int i = 0; i < types.length; i++) { + Type asmType = types[i]; + int type = getTypeFromASMType(asmType); + int register = registers[r]; + mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), + register); + interpreter.load(register, type); + r += asmType.getSize(); + } + mv.visitMethodInsn(javaOpcode, owner, name, desc); + returnRegisterType = getReturnTypeFromMethodDescriptor(desc); + return; + default: + throwNewAssertionError(opcode); + } + } + + @Override + public void visitInstrConstU64(Opcode opcode, final int vdest, + final long value) { + mv.setPatchMode(); + mv.visitLdcInsn(value); + final AbstractInsnNode ldc = mv.getLastInsnNode(); + mv.visitVarInsn(LSTORE, vdest); + final AbstractInsnNode lstore = mv.getLastInsnNode(); + interpreter.storeArbitraryType(vdest, U64_TYPE, new Patchable() { + @Override + protected void patch(int registerType) { + if (registerType == DOUBLE_TYPE) { + mv.patch(ldc, + new LdcInsnNode(Double.longBitsToDouble(value))); + mv.patch(lstore, new VarInsnNode(DSTORE, vdest)); + } + } + }); + } + + // unimplemented + @Override + public void visitLabel(Label label) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrArray(Opcode opcode, int vsrcOrDest, int varray, + int vindex) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrBinOp(Opcode opcode, int vdest, int vsrc, + int vsrc2) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrBinOpAndLiteral(Opcode opcode, int vdest, + int vsrc, int value) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrClass(Opcode opcode, int vdest, String type) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrConstU32(Opcode opcode, int vdest, int value) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrFillArrayData(Opcode opcode, int vsrc, + Object arrayData) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrFilledNewArray(Opcode opcode, int num, int va, + int vpacked, String type) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrGoto(Opcode opcode, Label label) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrIfTest(Opcode opcode, int vsrc1, int vsrc2, + Label label) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrIfTestZ(Opcode opcode, int vsrc, Label label) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrInstanceof(Opcode opcode, int vdest, int vsrc, + String type) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrNewArray(Opcode opcode, int vdest, int vsize, + String type) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrOp(Opcode opcode, int srcOrDst) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrSwitch(Opcode opcode, int vsrc, + Map<Integer, Label> labels) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitInstrUnaryOp(Opcode opcode, int vdest, int vsrc) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public void visitEnd() { + mv.visitMaxs(-1, -1); + mv.visitEnd(); + } + + @Override + public void visitTryCatch(Label start, Label end, Label handler, + String type) { + // TODO Auto-generated method stub + + } } - } }
--- a/src/main/java/org/icedrobot/daneel/rewriter/Interpreter.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Interpreter.java Tue Mar 15 23:25:43 2011 +0100 @@ -4,66 +4,68 @@ import java.util.HashMap; public class Interpreter { - private final Register[] registers; - private final HashMap<Object, Register[]> joinPointMap = - new HashMap<Object, Register[]>(); - private boolean isDead; - - public Interpreter(int maxRegisters) { - Register[] registers = new Register[maxRegisters]; - for(int i=0; i< maxRegisters; i++) { - registers[i] = new Register(); + private final Register[] registers; + private final HashMap<Object, Register[]> joinPointMap = new HashMap<Object, Register[]>(); + private boolean isDead; + + public Interpreter(int maxRegisters) { + Register[] registers = new Register[maxRegisters]; + for (int i = 0; i < maxRegisters; i++) { + registers[i] = new Register(); + } + this.registers = registers; + } + + public void load(int vregister, int expectedType) { + registers[vregister].load(expectedType); + } + + public void store(int vregister, int type) { + registers[vregister].store(type); + } + + public void storeArbitraryType(int vregister, int arbitraryType, + Patchable patchable) { + registers[vregister].storeArbitraryType(arbitraryType, patchable); + } + + public void copy(int vdst, int vsrc) { + registers[vdst].copy(registers[vsrc]); + } + + public void storeJoinPoint(Object label) { + joinPointMap.put(label, registers.clone()); } - this.registers = registers; - } - - public void load(int vregister, int expectedType) { - registers[vregister].load(expectedType); - } - - public void store(int vregister, int type) { - registers[vregister].store(type); - } - - public void storeArbitraryType(int vregister, int arbitraryType, Patchable patchable) { - registers[vregister].storeArbitraryType(arbitraryType, patchable); - } - - public void copy(int vdst, int vsrc) { - registers[vdst].copy(registers[vsrc]); - } - - public void storeJoinPoint(Object label) { - joinPointMap.put(label, registers.clone()); - } - - public Register[] getJoinPoint(Object label) { - return joinPointMap.get(label); - } - - public void setDead() { - this.isDead = true; - } - public boolean isDead() { - return isDead; - } - - public void merge(Register[] registers) { - assert this.registers.length == registers.length; - - if (isDead) { - System.arraycopy(registers, registers.length, this.registers, 0, registers.length); - isDead = false; - return; + + public Register[] getJoinPoint(Object label) { + return joinPointMap.get(label); + } + + public void setDead() { + this.isDead = true; + } + + public boolean isDead() { + return isDead; } - - for(int i=0; i<registers.length; i++) { - this.registers[i].merge(registers[i]); + + public void merge(Register[] registers) { + assert this.registers.length == registers.length; + + if (isDead) { + System.arraycopy(registers, registers.length, this.registers, 0, + registers.length); + isDead = false; + return; + } + + for (int i = 0; i < registers.length; i++) { + this.registers[i].merge(registers[i]); + } } - } - - @Override - public String toString() { - return Arrays.toString(registers); - } + + @Override + public String toString() { + return Arrays.toString(registers); + } }
--- a/src/main/java/org/icedrobot/daneel/rewriter/Main.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Main.java Tue Mar 15 23:25:43 2011 +0100 @@ -14,31 +14,38 @@ import org.objectweb.asm.util.CheckClassAdapter; /** - * Run: java -cp classes:lib/smali-1.2.6.jar:lib/asm-debug-all-4.0.jar org.icedrobot.daneel.rewriter.Main HelloWorld.dex HelloWorld + * Run: java -cp classes:lib/smali-1.2.6.jar:lib/asm-debug-all-4.0.jar + * org.icedrobot.daneel.rewriter.Main HelloWorld.dex HelloWorld */ public class Main { - public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException { - final DexReader dexReader = new DexLibDexReader(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(name, new DexRewriter(writer)); - byte[] array = writer.toByteArray(); - - CheckClassAdapter.verify(new ClassReader(array), true, new PrintWriter(System.err)); - - return defineClass(name, array, 0, array.length); - } - }; - - Class<?> clazz = classLoader.loadClass(args[1]); - Method method = clazz.getMethod("main", String[].class); - try { - method.invoke(null, (Object)Arrays.asList(args).subList(2, args.length).toArray(new String[0])); - } catch(InvocationTargetException e) { - e.getCause().printStackTrace(); + public static void main(String[] args) throws IOException, + ClassNotFoundException, NoSuchMethodException, + IllegalAccessException { + final DexReader dexReader = new DexLibDexReader(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(name, new DexRewriter(writer)); + byte[] array = writer.toByteArray(); + + CheckClassAdapter.verify(new ClassReader(array), true, + new PrintWriter(System.err)); + + return defineClass(name, array, 0, array.length); + } + }; + + Class<?> clazz = classLoader.loadClass(args[1]); + Method method = clazz.getMethod("main", String[].class); + try { + method.invoke(null, + (Object) Arrays.asList(args).subList(2, args.length) + .toArray(new String[0])); + } catch (InvocationTargetException e) { + e.getCause().printStackTrace(); + } } - } }
--- a/src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java Tue Mar 15 23:25:43 2011 +0100 @@ -9,226 +9,201 @@ import org.objectweb.asm.tree.MethodNode; /** - * A method visitor which is able to patch some of its instruction. - * To avoid the overhead of always storing all instructions in memory, - * to patch at least one instruction, the {@link #setPatchMode() patch mode} - * must be activated. + * A method visitor which is able to patch some of its instruction. To avoid the + * overhead of always storing all instructions in memory, to patch at least one + * instruction, the {@link #setPatchMode() patch mode} must be activated. * * By default, this method visitor delegates to the underlying method visitor - * but if the {@link #setPatchMode() patch mode} is activated, - * all new instructions are stored and dumped when {@link #visitMaxs(int, int)} is called. + * but if the {@link #setPatchMode() patch mode} is activated, all new + * instructions are stored and dumped when {@link #visitMaxs(int, int)} is + * called. * - * So if the patch mode is activated, one can get the last instruction {@link #getLastInsnNode()}, - * remember it, and replace it later using {@link #patch(AbstractInsnNode, AbstractInsnNode)} - * with another instruction. + * So if the patch mode is activated, one can get the last instruction + * {@link #getLastInsnNode()}, remember it, and replace it later using + * {@link #patch(AbstractInsnNode, AbstractInsnNode)} with another instruction. * - * The methods {@link #getLastInsnNode()} and {@link #patch(AbstractInsnNode, AbstractInsnNode)} - * can only be called is the patch mode is activated. - * After a call to {@link #visitMaxs(int, int)}, the patch mode is deactivated. - * - * @author Remi Forax + * The methods {@link #getLastInsnNode()} and + * {@link #patch(AbstractInsnNode, AbstractInsnNode)} can only be called is the + * patch mode is activated. After a call to {@link #visitMaxs(int, int)}, the + * patch mode is deactivated. */ public class PatchMethodVisitor implements MethodVisitor { - private final MethodVisitor mv; - private MethodNode methodNode; + private final MethodVisitor mv; + private MethodNode methodNode; - public PatchMethodVisitor(MethodVisitor mv) { - this.mv = mv; - } + public PatchMethodVisitor(MethodVisitor mv) { + this.mv = mv; + } - @Override - public AnnotationVisitor visitAnnotationDefault() { - return mv.visitAnnotationDefault(); - } + @Override + public AnnotationVisitor visitAnnotationDefault() { + return mv.visitAnnotationDefault(); + } - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - return mv.visitAnnotation(desc, visible); - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { - return mv.visitParameterAnnotation(parameter, desc, visible); - } + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return mv.visitAnnotation(desc, visible); + } - @Override - public void visitAttribute(Attribute attr) { - mv.visitAttribute(attr); - } - - @Override - public void visitCode() { - mv.visitCode(); - } - - private MethodVisitor mv() { - return (methodNode == null)? mv: methodNode; - } + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, + String desc, boolean visible) { + return mv.visitParameterAnnotation(parameter, desc, visible); + } - /** - * Switch to patch mode. - * If the patch mode is already activated, this method does nothing. - */ - public void setPatchMode() { - if (methodNode == null) { - methodNode = new MethodNode(); + @Override + public void visitAttribute(Attribute attr) { + mv.visitAttribute(attr); } - } - - public AbstractInsnNode getLastInsnNode() { - if (methodNode == null) { - throw new IllegalStateException("patchMode is not activated"); + + @Override + public void visitCode() { + mv.visitCode(); + } + + private MethodVisitor mv() { + return (methodNode == null) ? mv : methodNode; } - return methodNode.instructions.getLast(); - } - - public void patch(AbstractInsnNode node, AbstractInsnNode newNode) { - if (methodNode == null) { - throw new IllegalStateException("patchMode is not activated"); + + /** + * Switch to patch mode. If the patch mode is already activated, this method + * does nothing. + */ + public void setPatchMode() { + if (methodNode == null) { + methodNode = new MethodNode(); + } } - methodNode.instructions.set(node, newNode); - } - - @Override - public void visitFrame( - int type, - int nLocal, - Object[] local, - int nStack, - Object[] stack) - { - mv().visitFrame(type, nLocal, local, nStack, stack); - } + + public AbstractInsnNode getLastInsnNode() { + if (methodNode == null) { + throw new IllegalStateException("patchMode is not activated"); + } + return methodNode.instructions.getLast(); + } + + public void patch(AbstractInsnNode node, AbstractInsnNode newNode) { + if (methodNode == null) { + throw new IllegalStateException("patchMode is not activated"); + } + methodNode.instructions.set(node, newNode); + } - @Override - public void visitInsn(int opcode) { - mv().visitInsn(opcode); - } + @Override + public void visitFrame(int type, int nLocal, Object[] local, int nStack, + Object[] stack) { + mv().visitFrame(type, nLocal, local, nStack, stack); + } - @Override - public void visitIntInsn(int opcode, int operand) { - mv().visitIntInsn(opcode, operand); - } + @Override + public void visitInsn(int opcode) { + mv().visitInsn(opcode); + } - @Override - public void visitVarInsn(int opcode, int var) { - mv().visitVarInsn(opcode, var); - } + @Override + public void visitIntInsn(int opcode, int operand) { + mv().visitIntInsn(opcode, operand); + } - @Override - public void visitTypeInsn(int opcode, String type) { - mv().visitTypeInsn(opcode, type); - } + @Override + public void visitVarInsn(int opcode, int var) { + mv().visitVarInsn(opcode, var); + } - @Override - public void visitFieldInsn( - int opcode, - String owner, - String name, - String desc) { - mv().visitFieldInsn(opcode, owner, name, desc); - } + @Override + public void visitTypeInsn(int opcode, String type) { + mv().visitTypeInsn(opcode, type); + } - @Override - public void visitMethodInsn( - int opcode, - String owner, - String name, - String desc) { - mv().visitMethodInsn(opcode, owner, name, desc); - } + @Override + public void visitFieldInsn(int opcode, String owner, String name, + String desc) { + mv().visitFieldInsn(opcode, owner, name, desc); + } -// @Override -// public void visitInvokeDynamicInsn( -// String name, -// String desc, -// MethodHandle bsm, -// Object... bsmArgs) { -// mv().visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); -// } - - @Override - public void visitJumpInsn( int opcode, Label label) { - mv().visitJumpInsn(opcode, label); - } + @Override + public void visitMethodInsn(int opcode, String owner, String name, + String desc) { + mv().visitMethodInsn(opcode, owner, name, desc); + } - @Override - public void visitLabel( Label label) { - mv().visitLabel(label); - } + // @Override + // public void visitInvokeDynamicInsn( + // String name, + // String desc, + // MethodHandle bsm, + // Object... bsmArgs) { + // mv().visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + // } - @Override - public void visitLdcInsn( Object cst) { - mv().visitLdcInsn(cst); - } + @Override + public void visitJumpInsn(int opcode, Label label) { + mv().visitJumpInsn(opcode, label); + } - @Override - public void visitIincInsn( int var, int increment) { - mv().visitIincInsn(var, increment); - } + @Override + public void visitLabel(Label label) { + mv().visitLabel(label); + } - @Override - public void visitTableSwitchInsn( - int min, - int max, - Label dflt, - Label... labels) { - mv().visitTableSwitchInsn(min, max, dflt, labels); - } + @Override + public void visitLdcInsn(Object cst) { + mv().visitLdcInsn(cst); + } + + @Override + public void visitIincInsn(int var, int increment) { + mv().visitIincInsn(var, increment); + } - @Override - public void visitLookupSwitchInsn( - Label dflt, - int[] keys, - Label[] labels) { - mv().visitLookupSwitchInsn(dflt, keys, labels); - } + @Override + public void visitTableSwitchInsn(int min, int max, Label dflt, + Label... labels) { + mv().visitTableSwitchInsn(min, max, dflt, labels); + } + + @Override + public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { + mv().visitLookupSwitchInsn(dflt, keys, labels); + } - @Override - public void visitMultiANewArrayInsn( String desc, int dims) { - mv().visitMultiANewArrayInsn(desc, dims); - } + @Override + public void visitMultiANewArrayInsn(String desc, int dims) { + mv().visitMultiANewArrayInsn(desc, dims); + } - @Override - public void visitTryCatchBlock( - Label start, - Label end, - Label handler, - String type) { - mv().visitTryCatchBlock(start, end, handler, type); - } + @Override + public void visitTryCatchBlock(Label start, Label end, Label handler, + String type) { + mv().visitTryCatchBlock(start, end, handler, type); + } - @Override - public void visitLocalVariable( - String name, - String desc, - String signature, - Label start, - Label end, - int index) - { - mv().visitLocalVariable(name, desc, signature, start, end, index); - } + @Override + public void visitLocalVariable(String name, String desc, String signature, + Label start, Label end, int index) { + mv().visitLocalVariable(name, desc, signature, start, end, index); + } - @Override - public void visitLineNumber( int line, Label start) { - mv().visitLineNumber(line, start); - } + @Override + public void visitLineNumber(int line, Label start) { + mv().visitLineNumber(line, start); + } - @Override - public void visitMaxs( int maxStack, int maxLocals) { - if (methodNode != null) { - final MethodVisitor mv = this.mv; - for(AbstractInsnNode insn = methodNode.instructions.getFirst(); insn != null; insn = insn.getNext()) { - insn.accept(mv); - } - methodNode = null; + @Override + public void visitMaxs(int maxStack, int maxLocals) { + if (methodNode != null) { + final MethodVisitor mv = this.mv; + for (AbstractInsnNode insn = methodNode.instructions.getFirst(); insn != null; insn = insn + .getNext()) { + insn.accept(mv); + } + methodNode = null; + } + mv.visitMaxs(maxStack, maxLocals); } - mv.visitMaxs(maxStack, maxLocals); - } - @Override - public void visitEnd() { - mv.visitEnd(); - } + @Override + public void visitEnd() { + mv.visitEnd(); + } }
--- a/src/main/java/org/icedrobot/daneel/rewriter/Patchable.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Patchable.java Tue Mar 15 23:25:43 2011 +0100 @@ -1,14 +1,14 @@ package org.icedrobot.daneel.rewriter; public abstract class Patchable { - private boolean patchCalled; - - void doPatch(int registerType) { - if (patchCalled) - return; - patchCalled = true; - patch(registerType); - } - - protected abstract void patch(int registerType); + private boolean patchCalled; + + void doPatch(int registerType) { + if (patchCalled) + return; + patchCalled = true; + patch(registerType); + } + + protected abstract void patch(int registerType); }
--- a/src/main/java/org/icedrobot/daneel/rewriter/Register.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Register.java Tue Mar 15 23:25:43 2011 +0100 @@ -3,125 +3,129 @@ import org.objectweb.asm.Opcodes; public class Register { - // the order is the same order as java bytecode IALOAD/IASTORE order (see #getJavaOpcode) - public static final int INT_TYPE = 0; // signed int - public static final int LONG_TYPE = 1; // signed long - public static final int FLOAT_TYPE = 2; // 32 bits float - public static final int DOUBLE_TYPE = 3; // 64 bits float - public static final int OBJECT_TYPE = 4; // object reference - public static final int BYTE_TYPE = 5; // byte or boolean - public static final int CHAR_TYPE = 6; // char - public static final int SHORT_TYPE = 7; // short - public static final int BOOLEAN_TYPE = 8; // boolean - public static final int VOID_TYPE = 9; // void, added to simplify management + // the order is the same order as java bytecode IALOAD/IASTORE order (see + // #getJavaOpcode) + public static final int INT_TYPE = 0; // signed int + public static final int LONG_TYPE = 1; // signed long + public static final int FLOAT_TYPE = 2; // 32 bits float + public static final int DOUBLE_TYPE = 3; // 64 bits float + public static final int OBJECT_TYPE = 4; // object reference + public static final int BYTE_TYPE = 5; // byte or boolean + public static final int CHAR_TYPE = 6; // char + public static final int SHORT_TYPE = 7; // short + public static final int BOOLEAN_TYPE = 8; // boolean + public static final int VOID_TYPE = 9; // void, added to simplify management - public static final int U32_TYPE = -1; // arbitrary 32bits constant - public static final int U64_TYPE = -2; // arbitrary 64bits constant - - public static final int NO_TYPE = -3; // unassigned register + public static final int U32_TYPE = -1; // arbitrary 32bits constant + public static final int U64_TYPE = -2; // arbitrary 64bits constant + + public static final int NO_TYPE = -3; // unassigned register - private static final int ARBITRARY_MASK = Integer.MIN_VALUE; + private static final int ARBITRARY_MASK = Integer.MIN_VALUE; - private int type; + private int type; - private Patchable patchable; + private Patchable patchable; - Register() { - type = NO_TYPE; - // and patchable == null - } - - public void load(int expectedType) { - assert (expectedType & ARBITRARY_MASK) == 0; + Register() { + type = NO_TYPE; + // and patchable == null + } - if ((this.type & ARBITRARY_MASK) != 0 && patchable != null) { - patchable.doPatch(expectedType); - patchable = null; - } - this.type = expectedType; - } + public void load(int expectedType) { + assert (expectedType & ARBITRARY_MASK) == 0; - public void store(int type) { - this.type = type; - this.patchable = null; - } - - public void storeArbitraryType(int arbitraryType, Patchable patchable) { - this.type = arbitraryType; - this.patchable = patchable; - } + if ((this.type & ARBITRARY_MASK) != 0 && patchable != null) { + patchable.doPatch(expectedType); + patchable = null; + } + this.type = expectedType; + } - public void copy(Register register) { - this.type = register.type; - this.patchable = register.patchable; - } - - public void merge(Register register) { - int thisType = this.type; - int registerType = register.type; - if (thisType == registerType) { // short cut - return; + public void store(int type) { + this.type = type; + this.patchable = null; + } + + public void storeArbitraryType(int arbitraryType, Patchable patchable) { + this.type = arbitraryType; + this.patchable = patchable; + } + + public void copy(Register register) { + this.type = register.type; + this.patchable = register.patchable; } - - boolean thisIsArbitrary = (thisType & ARBITRARY_MASK) != 0; - boolean registerIsArbitrary = (registerType & ARBITRARY_MASK) != 0; - - if (thisIsArbitrary) { - if (registerIsArbitrary) { - // do nothing, if they are not compatible, the VM verifier will emit a VerifyError - return; - } - if (patchable != null) { // otherwise, it's an uninitialized value - patchable.doPatch(registerType); - patchable = null; - } - this.type = registerType; - return; - } - - // if register.type is not an arbitrary, this means that the code may be not verifiable - // it's ok if the register is no more used - if (!registerIsArbitrary) { - return; - } - - if (register.patchable != null) { - register.patchable.doPatch(thisType); - register.patchable = null; - } - register.type = thisType; - } + + public void merge(Register register) { + int thisType = this.type; + int registerType = register.type; + if (thisType == registerType) { // short cut + return; + } + + boolean thisIsArbitrary = (thisType & ARBITRARY_MASK) != 0; + boolean registerIsArbitrary = (registerType & ARBITRARY_MASK) != 0; + + if (thisIsArbitrary) { + if (registerIsArbitrary) { + // do nothing, if they are not compatible, the VM verifier will + // emit a VerifyError + return; + } + if (patchable != null) { // otherwise, it's an uninitialized value + patchable.doPatch(registerType); + patchable = null; + } + this.type = registerType; + return; + } + + // if register.type is not an arbitrary, this means that the code may be + // not verifiable + // it's ok if the register is no more used + if (!registerIsArbitrary) { + return; + } - public static int getJavaOpcode(int type, int opcode) { - assert (type & ARBITRARY_MASK) == 0; - - if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { - return opcode + ((type != BOOLEAN_TYPE)? type: BYTE_TYPE); - } + if (register.patchable != null) { + register.patchable.doPatch(thisType); + register.patchable = null; + } + register.type = thisType; + } - return opcode + ((type>4)? 0: type); // type > 4, integer numeric promotion - } + public static int getJavaOpcode(int type, int opcode) { + assert (type & ARBITRARY_MASK) == 0; + + if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { + return opcode + ((type != BOOLEAN_TYPE) ? type : BYTE_TYPE); + } + + return opcode + ((type > 4) ? 0 : type); // type > 4, integer numeric + // promotion + } - @Override - public String toString() { - switch(type) { - case OBJECT_TYPE: - return "object"; - case INT_TYPE: - return "int"; - case FLOAT_TYPE: - return "float"; - case LONG_TYPE: - return "long"; - case DOUBLE_TYPE: - return "double"; - case U32_TYPE: - return "u32"; - case U64_TYPE: - return "u64"; - case NO_TYPE: - return "uninitialized"; + @Override + public String toString() { + switch (type) { + case OBJECT_TYPE: + return "object"; + case INT_TYPE: + return "int"; + case FLOAT_TYPE: + return "float"; + case LONG_TYPE: + return "long"; + case DOUBLE_TYPE: + return "double"; + case U32_TYPE: + return "u32"; + case U64_TYPE: + return "u64"; + case NO_TYPE: + return "uninitialized"; + } + throw new AssertionError(); } - throw new AssertionError(); - } }
--- a/src/main/java/org/icedrobot/daneel/rewriter/Registers.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Registers.java Tue Mar 15 23:25:43 2011 +0100 @@ -1,23 +1,23 @@ package org.icedrobot.daneel.rewriter; public class Registers { - private Registers() { - // no instance - } - - public static int getRegisterD(int packed) { - return packed & 0x0F; - } - - public static int getRegisterE(int packed) { - return (packed >> 4) &0x0F; - } - - public static int getRegisterF(int packed) { - return (packed >> 8) &0x0F; - } - - public static int getRegisterG(int packed) { - return (packed >> 12) &0x0F; - } + private Registers() { + // no instance + } + + public static int getRegisterD(int packed) { + return packed & 0x0F; + } + + public static int getRegisterE(int packed) { + return (packed >> 4) & 0x0F; + } + + public static int getRegisterF(int packed) { + return (packed >> 8) & 0x0F; + } + + public static int getRegisterG(int packed) { + return (packed >> 12) & 0x0F; + } }
--- a/src/main/java/org/icedrobot/daneel/util/BufferUtil.java Tue Mar 15 21:53:43 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/util/BufferUtil.java Tue Mar 15 23:25:43 2011 +0100 @@ -25,12 +25,12 @@ /** * Utility methods extending the base functionality of the standard * {@link java.nio.ByteBuffer} class by means of static methods. - * @author Michael Starzinger <michi@complang.tuwien.ac.at> */ public class BufferUtil { /** * Reads an array of integers from the buffer's current position. + * * @param buffer The byte buffer to read from. * @param size The number of values to read. * @return An array containing the read values. @@ -47,6 +47,7 @@ * buffer's current position. A maximum of five bytes is read because only * 32-bit values are encoded this way. For details about this encoding see * the "Dalvik Executable Format" specification. + * * @param buffer The byte buffer to read from. * @return The decoded unsigned 32-bit value. */ @@ -66,6 +67,7 @@ * buffer's current position. A maximum of five bytes is read because only * 32-bit values are encoded this way. For details about this encoding see * the "Dalvik Executable Format" specification. + * * @param buffer The byte buffer to read from. * @return The decoded signed 32-bit value. */ @@ -87,6 +89,7 @@ * Reads string encoded using the "Modified UTF-8" encoding at the buffer's * current position. The number of bytes read from the buffer is implied by * the position of the terminating 0 byte. + * * @param buffer The byte buffer to read from. * @return The decoded string value. */