diff --git a/CHANGES b/CHANGES index 704d0ae5..a54fb962 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,7 @@ v2.0.0 (TBA) -Fixed (issue #448) - Merge smali2 into Apktool -Fixed (issue #496) - Fixes Windows builds caused by java.nio problems -Fixed (issue #510) - Any error output is sent stderr instead of stdout +-Fixed (issue #426) - Filename too long (JesusFreke) -Updated known bytes for configurations to 38 (from addition of layout direction) -Fixed NPE when handling odex apks even with --no-src specified. (Thanks Rodrigo Chiossi) diff --git a/brut.apktool.smali/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/brut.apktool.smali/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java index 3aa0b187..b4508005 100644 --- a/brut.apktool.smali/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java +++ b/brut.apktool.smali/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java @@ -32,10 +32,13 @@ import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.baksmali.Adaptors.MethodItem; import org.jf.baksmali.Adaptors.ReferenceFormatter; import org.jf.baksmali.Renderers.LongRenderer; +import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.VerificationError; +import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex; import org.jf.dexlib2.iface.instruction.*; import org.jf.dexlib2.iface.instruction.formats.Instruction20bc; import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction; +import org.jf.dexlib2.iface.reference.Reference; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; @@ -58,6 +61,21 @@ public class InstructionMethodItem extends MethodItem { @Override public boolean writeTo(IndentingWriter writer) throws IOException { + boolean invalidReference = false; + if (instruction instanceof ReferenceInstruction) { + try { + Reference reference = ((ReferenceInstruction)instruction).getReference(); + } catch (InvalidItemIndex ex) { + invalidReference = true; + + writer.write("#invalid "); + writer.write(ReferenceType.toString(instruction.getOpcode().referenceType)); + writer.write(" index: "); + writer.printSignedIntAsDec(ex.getInvalidIndex()); + writer.write("\n#"); + } + } + switch (instruction.getOpcode().format) { case Format10t: writeOpcode(writer); @@ -336,8 +354,14 @@ public class InstructionMethodItem extends MethodItem { } protected void writeReference(IndentingWriter writer) throws IOException { - ReferenceFormatter.writeReference(writer, instruction.getOpcode().referenceType, - ((ReferenceInstruction)instruction).getReference()); + try { + ReferenceFormatter.writeReference(writer, instruction.getOpcode().referenceType, + ((ReferenceInstruction)instruction).getReference()); + } catch (InvalidItemIndex ex) { + writer.write(ReferenceType.toString(instruction.getOpcode().referenceType)); + writer.write("@"); + writer.printSignedIntAsDec(ex.getInvalidIndex()); + } } protected void writeVerificationErrorType(IndentingWriter writer) throws IOException { diff --git a/brut.apktool.smali/baksmali/src/main/java/org/jf/baksmali/main.java b/brut.apktool.smali/baksmali/src/main/java/org/jf/baksmali/main.java index 83009a6d..e9d80389 100644 --- a/brut.apktool.smali/baksmali/src/main/java/org/jf/baksmali/main.java +++ b/brut.apktool.smali/baksmali/src/main/java/org/jf/baksmali/main.java @@ -148,7 +148,7 @@ public class main { options.addCodeOffsets = true; break; case 'r': - String[] values = commandLine.getOptionValues('r'); + String[] values = commandLine.getOptionValues("r"); int registerInfo = 0; if (values == null || values.length == 0) { diff --git a/brut.apktool.smali/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java b/brut.apktool.smali/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java index c511a37c..046ee493 100644 --- a/brut.apktool.smali/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java +++ b/brut.apktool.smali/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java @@ -104,7 +104,7 @@ public class AnalysisTest { className.substring(1, className.length() - 1)); String smaliContents = readResource(smaliPath); - Assert.assertEquals(smaliContents, stringWriter.toString()); + Assert.assertEquals(smaliContents, stringWriter.toString().replace("\r\n", "\n")); } } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java index 0f71f4ed..5b74e7dc 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java @@ -38,5 +38,20 @@ public final class ReferenceType { public static final int METHOD = 3; public static final int NONE = 4; + public static String toString(int referenceType) { + switch (referenceType) { + case STRING: + return "string"; + case TYPE: + return "type"; + case FIELD: + return "field"; + case METHOD: + return "method"; + default: + throw new IllegalArgumentException("Invalid reference type: " + referenceType); + } + } + private ReferenceType() {} } \ No newline at end of file diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/base/BaseExceptionHandler.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/base/BaseExceptionHandler.java index 8ca974be..9ad6b648 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/base/BaseExceptionHandler.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/base/BaseExceptionHandler.java @@ -33,13 +33,28 @@ package org.jf.dexlib2.base; import com.google.common.base.Objects; import com.google.common.primitives.Ints; +import org.jf.dexlib2.base.reference.BaseTypeReference; import org.jf.dexlib2.iface.ExceptionHandler; +import org.jf.dexlib2.iface.reference.TypeReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Comparator; public abstract class BaseExceptionHandler implements ExceptionHandler { + @Nullable @Override public TypeReference getExceptionTypeReference() { + final String exceptionType = getExceptionType(); + if (exceptionType == null) { + return null; + } + + return new BaseTypeReference() { + @Nonnull @Override public String getType() { + return exceptionType; + } + }; + } + @Override public int hashCode() { String exceptionType = getExceptionType(); @@ -76,6 +91,8 @@ public abstract class BaseExceptionHandler implements ExceptionHandler { return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress()); } + + public static final Comparator BY_EXCEPTION = new Comparator() { @Override public int compare(ExceptionHandler o1, ExceptionHandler o2) { String exceptionType1 = o1.getExceptionType(); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java index 71c563fe..262fb546 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java @@ -90,6 +90,10 @@ public class BaseDexReader { } public int readSmallUleb128() { + return readUleb128(false); + } + + private int readUleb128(boolean allowLarge) { int end = offset; int currentByteValue; int result; @@ -113,10 +117,12 @@ public class BaseDexReader { throw new ExceptionWithContext( "Invalid uleb128 integer encountered at offset 0x%x", offset); } else if ((currentByteValue & 0xf) > 0x07) { - // we assume most significant bit of the result will not be set, so that it can fit into - // a signed integer without wrapping - throw new ExceptionWithContext( - "Encountered valid uleb128 that is out of range at offset 0x%x", offset); + if (!allowLarge) { + // for non-large uleb128s, we assume most significant bit of the result will not be + // set, so that it can fit into a signed integer without wrapping + throw new ExceptionWithContext( + "Encountered valid uleb128 that is out of range at offset 0x%x", offset); + } } result |= currentByteValue << 28; } @@ -128,6 +134,16 @@ public class BaseDexReader { return result; } + /** + * Reads a "large" uleb128. That is, one that may legitimately be greater than a signed int. + * + * The value is returned as if it were signed. i.e. a value of 0xFFFFFFFF would be returned as -1. It is up to the + * caller to handle the value appropriately. + */ + public int readLargeUleb128() { + return readUleb128(true); + } + /** * Reads a "big" uleb128 that can legitimately be > 2^31. The value is returned as a signed integer, with the * expected semantics of re-interpreting an unsigned value as a signed value. @@ -185,11 +201,6 @@ public class BaseDexReader { if (currentByteValue < 0) { throw new ExceptionWithContext( "Invalid uleb128 integer encountered at offset 0x%x", offset); - } else if ((currentByteValue & 0xf) > 0x07) { - // we assume most significant bit of the result will not be set, so that it can fit into - // a signed integer without wrapping - throw new ExceptionWithContext( - "Encountered valid uleb128 that is out of range at offset 0x%x", offset); } } } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java index f36c9c35..32c7ef94 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java @@ -163,42 +163,42 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile { public int getStringIdItemOffset(int stringIndex) { if (stringIndex < 0 || stringIndex >= stringCount) { - throw new ExceptionWithContext("String index out of bounds: %d", stringIndex); + throw new InvalidItemIndex(stringIndex, "String index out of bounds: %d", stringIndex); } return stringStartOffset + stringIndex*StringIdItem.ITEM_SIZE; } public int getTypeIdItemOffset(int typeIndex) { if (typeIndex < 0 || typeIndex >= typeCount) { - throw new ExceptionWithContext("Type index out of bounds: %d", typeIndex); + throw new InvalidItemIndex(typeIndex, "Type index out of bounds: %d", typeIndex); } return typeStartOffset + typeIndex*TypeIdItem.ITEM_SIZE; } public int getFieldIdItemOffset(int fieldIndex) { if (fieldIndex < 0 || fieldIndex >= fieldCount) { - throw new ExceptionWithContext("Field index out of bounds: %d", fieldIndex); + throw new InvalidItemIndex(fieldIndex, "Field index out of bounds: %d", fieldIndex); } return fieldStartOffset + fieldIndex*FieldIdItem.ITEM_SIZE; } public int getMethodIdItemOffset(int methodIndex) { if (methodIndex < 0 || methodIndex >= methodCount) { - throw new ExceptionWithContext("Method index out of bounds: %d", methodIndex); + throw new InvalidItemIndex(methodIndex, "Method findex out of bounds: %d", methodIndex); } return methodStartOffset + methodIndex*MethodIdItem.ITEM_SIZE; } public int getProtoIdItemOffset(int protoIndex) { if (protoIndex < 0 || protoIndex >= protoCount) { - throw new ExceptionWithContext("Proto index out of bounds: %d", protoIndex); + throw new InvalidItemIndex(protoIndex, "Proto index out of bounds: %d", protoIndex); } return protoStartOffset + protoIndex*ProtoIdItem.ITEM_SIZE; } public int getClassDefItemOffset(int classIndex) { if (classIndex < 0 || classIndex >= classCount) { - throw new ExceptionWithContext("Class index out of bounds: %d", classIndex); + throw new InvalidItemIndex(classIndex, "Class index out of bounds: %d", classIndex); } return classStartOffset + classIndex*ClassDefItem.ITEM_SIZE; } @@ -261,4 +261,22 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile { super(message, cause); } } + + public static class InvalidItemIndex extends ExceptionWithContext { + private final int itemIndex; + + public InvalidItemIndex(int itemIndex) { + super(""); + this.itemIndex = itemIndex; + } + + public InvalidItemIndex(int itemIndex, String message, Object... formatArgs) { + super(message, formatArgs); + this.itemIndex = itemIndex; + } + + public int getInvalidIndex() { + return itemIndex; + } + } } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java index 303e8b7e..5eff67a1 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java @@ -63,7 +63,9 @@ public class DexBackedField extends BaseFieldReference implements Field { this.dexFile = reader.dexBuf; this.classDef = classDef; - int fieldIndexDiff = reader.readSmallUleb128(); + // large values may be used for the index delta, which cause the cumulative index to overflow upon + // addition, effectively allowing out of order entries. + int fieldIndexDiff = reader.readLargeUleb128(); this.fieldIndex = fieldIndexDiff + previousFieldIndex; this.accessFlags = reader.readSmallUleb128(); @@ -78,7 +80,9 @@ public class DexBackedField extends BaseFieldReference implements Field { this.dexFile = reader.dexBuf; this.classDef = classDef; - int fieldIndexDiff = reader.readSmallUleb128(); + // large values may be used for the index delta, which cause the cumulative index to overflow upon + // addition, effectively allowing out of order entries. + int fieldIndexDiff = reader.readLargeUleb128(); this.fieldIndex = fieldIndexDiff + previousFieldIndex; this.accessFlags = reader.readSmallUleb128(); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java index 099f33c7..f26b7e12 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java @@ -73,7 +73,9 @@ public class DexBackedMethod extends BaseMethodReference implements Method { this.dexFile = reader.dexBuf; this.classDef = classDef; - int methodIndexDiff = reader.readSmallUleb128(); + // large values may be used for the index delta, which cause the cumulative index to overflow upon + // addition, effectively allowing out of order entries. + int methodIndexDiff = reader.readLargeUleb128(); this.methodIndex = methodIndexDiff + previousMethodIndex; this.accessFlags = reader.readSmallUleb128(); this.codeOffset = reader.readSmallUleb128(); @@ -90,7 +92,9 @@ public class DexBackedMethod extends BaseMethodReference implements Method { this.dexFile = reader.dexBuf; this.classDef = classDef; - int methodIndexDiff = reader.readSmallUleb128(); + // large values may be used for the index delta, which cause the cumulative index to overflow upon + // addition, effectively allowing out of order entries. + int methodIndexDiff = reader.readLargeUleb128(); this.methodIndex = methodIndexDiff + previousMethodIndex; this.accessFlags = reader.readSmallUleb128(); this.codeOffset = reader.readSmallUleb128(); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/ClassDataItem.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/ClassDataItem.java index 99164ac2..ff5291e1 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/ClassDataItem.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/ClassDataItem.java @@ -127,7 +127,9 @@ public class ClassDataItem { private int annotateEncodedField(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile, @Nonnull DexReader reader, int previousIndex) { - int indexDelta = reader.readSmallUleb128(); + // large values may be used for the index delta, which cause the cumulative index to overflow upon + // addition, effectively allowing out of order entries. + int indexDelta = reader.readLargeUleb128(); int fieldIndex = previousIndex + indexDelta; out.annotateTo(reader.getOffset(), "field_idx_diff = %d: %s", indexDelta, FieldIdItem.getReferenceAnnotation(dexFile, fieldIndex)); @@ -141,7 +143,9 @@ public class ClassDataItem { private int annotateEncodedMethod(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile, @Nonnull DexReader reader, int previousIndex) { - int indexDelta = reader.readSmallUleb128(); + // large values may be used for the index delta, which cause the cumulative index to overflow upon + // addition, effectively allowing out of order entries. + int indexDelta = reader.readLargeUleb128(); int methodIndex = previousIndex + indexDelta; out.annotateTo(reader.getOffset(), "method_idx_diff = %d: %s", indexDelta, MethodIdItem.getReferenceAnnotation(dexFile, methodIndex)); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java index 3f35ef3b..c2e0c9ca 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java @@ -53,6 +53,8 @@ public class DexAnnotator extends AnnotatedBytes { static { int[] sectionOrder = new int[] { + ItemType.MAP_LIST, + ItemType.HEADER_ITEM, ItemType.STRING_ID_ITEM, ItemType.TYPE_ID_ITEM, @@ -66,7 +68,6 @@ public class DexAnnotator extends AnnotatedBytes { ItemType.CODE_ITEM, ItemType.DEBUG_INFO_ITEM, - ItemType.MAP_LIST, ItemType.TYPE_LIST, ItemType.ANNOTATION_SET_REF_LIST, ItemType.ANNOTATION_SET_ITEM, diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/ExceptionHandler.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/ExceptionHandler.java index 07defc78..ede016eb 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/ExceptionHandler.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/ExceptionHandler.java @@ -31,6 +31,8 @@ package org.jf.dexlib2.iface; +import org.jf.dexlib2.iface.reference.TypeReference; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -45,6 +47,14 @@ public interface ExceptionHandler extends Comparable { */ @Nullable String getExceptionType(); + /** + * Gets the type of exception that is handled by this handler. + * + * @return A TypeReference to the type of exception that is handled by this handler, or null if this is a + * catch-all handler. + */ + @Nullable TypeReference getExceptionTypeReference(); + /** * Gets the code offset of the handler. * diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/debug/SetSourceFile.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/debug/SetSourceFile.java index d992423d..de243abc 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/debug/SetSourceFile.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/debug/SetSourceFile.java @@ -31,8 +31,11 @@ package org.jf.dexlib2.iface.debug; +import org.jf.dexlib2.iface.reference.StringReference; + import javax.annotation.Nullable; public interface SetSourceFile extends DebugItem { @Nullable String getSourceFile(); + @Nullable StringReference getSourceFileReference(); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/debug/StartLocal.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/debug/StartLocal.java index 01ec1e09..90a55475 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/debug/StartLocal.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/debug/StartLocal.java @@ -31,6 +31,15 @@ package org.jf.dexlib2.iface.debug; +import org.jf.dexlib2.iface.reference.StringReference; +import org.jf.dexlib2.iface.reference.TypeReference; + +import javax.annotation.Nullable; + public interface StartLocal extends DebugItem, LocalInfo { int getRegister(); + + @Nullable StringReference getNameReference(); + @Nullable TypeReference getTypeReference(); + @Nullable StringReference getSignatureReference(); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/debug/ImmutableSetSourceFile.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/debug/ImmutableSetSourceFile.java index 54d7e29c..b74adab0 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/debug/ImmutableSetSourceFile.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/debug/ImmutableSetSourceFile.java @@ -32,7 +32,9 @@ package org.jf.dexlib2.immutable.debug; import org.jf.dexlib2.DebugItemType; +import org.jf.dexlib2.base.reference.BaseStringReference; import org.jf.dexlib2.iface.debug.SetSourceFile; +import org.jf.dexlib2.iface.reference.StringReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -58,5 +60,14 @@ public class ImmutableSetSourceFile extends ImmutableDebugItem implements SetSou @Nullable @Override public String getSourceFile() { return sourceFile; } + @Nullable @Override public StringReference getSourceFileReference() { + return sourceFile==null?null:new BaseStringReference() { + @Nonnull @Override public String getString() { + return sourceFile; + } + }; + } + + @Override public int getDebugItemType() { return DebugItemType.SET_SOURCE_FILE; } } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/debug/ImmutableStartLocal.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/debug/ImmutableStartLocal.java index 24eb7c83..635e92ad 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/debug/ImmutableStartLocal.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/debug/ImmutableStartLocal.java @@ -32,7 +32,11 @@ package org.jf.dexlib2.immutable.debug; import org.jf.dexlib2.DebugItemType; +import org.jf.dexlib2.base.reference.BaseStringReference; +import org.jf.dexlib2.base.reference.BaseTypeReference; import org.jf.dexlib2.iface.debug.StartLocal; +import org.jf.dexlib2.iface.reference.StringReference; +import org.jf.dexlib2.iface.reference.TypeReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -69,6 +73,31 @@ public class ImmutableStartLocal extends ImmutableDebugItem implements StartLoca } @Override public int getRegister() { return register; } + + @Nullable @Override public StringReference getNameReference() { + return name==null?null:new BaseStringReference() { + @Nonnull @Override public String getString() { + return name; + } + }; + } + + @Nullable @Override public TypeReference getTypeReference() { + return type==null?null:new BaseTypeReference() { + @Nonnull @Override public String getType() { + return type; + } + }; + } + + @Nullable @Override public StringReference getSignatureReference() { + return signature==null?null:new BaseStringReference() { + @Nonnull @Override public String getString() { + return signature; + } + }; + } + @Nullable @Override public String getName() { return name; } @Nullable @Override public String getType() { return type; } @Nullable @Override public String getSignature() { return signature; } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java index 2916aef1..432f1930 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java @@ -45,8 +45,8 @@ public abstract class ImmutableInstruction implements Instruction { @Nonnull protected final Opcode opcode; protected ImmutableInstruction(@Nonnull Opcode opcode) { - this.opcode = opcode; Preconditions.checkFormat(opcode, getFormat()); + this.opcode = opcode; } @Nonnull diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction10t.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction10t.java index be773ee7..5f8ecd1f 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction10t.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction10t.java @@ -46,7 +46,6 @@ public class ImmutableInstruction10t extends ImmutableInstruction implements Ins public ImmutableInstruction10t(@Nonnull Opcode opcode, int codeOffset) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.codeOffset = Preconditions.checkByteCodeOffset(codeOffset); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction10x.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction10x.java index ea1e49fc..c69eda75 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction10x.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction10x.java @@ -34,7 +34,6 @@ package org.jf.dexlib2.immutable.instruction; import org.jf.dexlib2.Format; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.iface.instruction.formats.Instruction10x; -import org.jf.dexlib2.util.Preconditions; import javax.annotation.Nonnull; @@ -43,7 +42,6 @@ public class ImmutableInstruction10x extends ImmutableInstruction implements Ins public ImmutableInstruction10x(@Nonnull Opcode opcode) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); } public static ImmutableInstruction10x of(Instruction10x instruction) { diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction11n.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction11n.java index e7f66c7c..05ad13c5 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction11n.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction11n.java @@ -48,7 +48,6 @@ public class ImmutableInstruction11n extends ImmutableInstruction implements Ins int registerA, int literal) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkNibbleRegister(registerA); this.literal = Preconditions.checkNibbleLiteral(literal); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction11x.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction11x.java index 2abbf4e6..7b7b2aee 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction11x.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction11x.java @@ -46,7 +46,6 @@ public class ImmutableInstruction11x extends ImmutableInstruction implements Ins public ImmutableInstruction11x(@Nonnull Opcode opcode, int registerA) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction12x.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction12x.java index d9062540..c192f983 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction12x.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction12x.java @@ -48,7 +48,6 @@ public class ImmutableInstruction12x extends ImmutableInstruction implements Ins int registerA, int registerB) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkNibbleRegister(registerA); this.registerB = Preconditions.checkNibbleRegister(registerB); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction20bc.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction20bc.java index 9674d3d4..2fa9b004 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction20bc.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction20bc.java @@ -51,7 +51,6 @@ public class ImmutableInstruction20bc extends ImmutableInstruction implements In int verificationError, @Nonnull Reference reference) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.verificationError = Preconditions.checkVerificationError(verificationError); this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction20t.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction20t.java index 19a6d9f1..92f45471 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction20t.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction20t.java @@ -46,7 +46,6 @@ public class ImmutableInstruction20t extends ImmutableInstruction implements Ins public ImmutableInstruction20t(@Nonnull Opcode opcode, int codeOffset) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21c.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21c.java index c0d2b179..c4d13a7b 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21c.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21c.java @@ -51,7 +51,6 @@ public class ImmutableInstruction21c extends ImmutableInstruction implements Ins int registerA, @Nonnull Reference reference) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21ih.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21ih.java index b27f7ed5..a095c2a8 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21ih.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21ih.java @@ -48,7 +48,6 @@ public class ImmutableInstruction21ih extends ImmutableInstruction implements In int registerA, int literal) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.literal = Preconditions.checkIntegerHatLiteral(literal); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21lh.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21lh.java index dff19984..ed63cdd4 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21lh.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21lh.java @@ -48,7 +48,6 @@ public class ImmutableInstruction21lh extends ImmutableInstruction implements In int registerA, long literal) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.literal = Preconditions.checkLongHatLiteral(literal); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21s.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21s.java index 9f5315e1..259c74b6 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21s.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21s.java @@ -48,7 +48,6 @@ public class ImmutableInstruction21s extends ImmutableInstruction implements Ins int registerA, int literal) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.literal = Preconditions.checkShortLiteral(literal); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21t.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21t.java index 9fdb3a09..c9db4e65 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21t.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction21t.java @@ -48,7 +48,6 @@ public class ImmutableInstruction21t extends ImmutableInstruction implements Ins int registerA, int codeOffset) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22b.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22b.java index d9b2dc97..9dae4384 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22b.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22b.java @@ -50,7 +50,6 @@ public class ImmutableInstruction22b extends ImmutableInstruction implements Ins int registerB, int literal) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.registerB = Preconditions.checkByteRegister(registerB); this.literal = Preconditions.checkByteLiteral(literal); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22c.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22c.java index 99e32366..c5741a7c 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22c.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22c.java @@ -53,7 +53,6 @@ public class ImmutableInstruction22c extends ImmutableInstruction implements Ins int registerB, @Nonnull Reference reference) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkNibbleRegister(registerA); this.registerB = Preconditions.checkNibbleRegister(registerB); this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22cs.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22cs.java index 5704d207..f17e88dd 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22cs.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22cs.java @@ -43,14 +43,13 @@ public class ImmutableInstruction22cs extends ImmutableInstruction implements In protected final int registerA; protected final int registerB; - @Nonnull protected final int fieldOffset; + protected final int fieldOffset; public ImmutableInstruction22cs(@Nonnull Opcode opcode, int registerA, int registerB, int fieldOffset) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkNibbleRegister(registerA); this.registerB = Preconditions.checkNibbleRegister(registerB); this.fieldOffset = Preconditions.checkFieldOffset(fieldOffset); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22s.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22s.java index f0c25376..96a9f0e6 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22s.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22s.java @@ -50,7 +50,6 @@ public class ImmutableInstruction22s extends ImmutableInstruction implements Ins int registerB, int literal) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkNibbleRegister(registerA); this.registerB = Preconditions.checkNibbleRegister(registerB); this.literal = Preconditions.checkShortLiteral(literal); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22t.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22t.java index c4662e1a..9e334ddd 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22t.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22t.java @@ -50,7 +50,6 @@ public class ImmutableInstruction22t extends ImmutableInstruction implements Ins int registerB, int codeOffset) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkNibbleRegister(registerA); this.registerB = Preconditions.checkNibbleRegister(registerB); this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22x.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22x.java index 7fd74558..cad66877 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22x.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction22x.java @@ -48,7 +48,6 @@ public class ImmutableInstruction22x extends ImmutableInstruction implements Ins int registerA, int registerB) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.registerB = Preconditions.checkShortRegister(registerB); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction23x.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction23x.java index fb2f2a30..e5ef91a0 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction23x.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction23x.java @@ -50,7 +50,6 @@ public class ImmutableInstruction23x extends ImmutableInstruction implements Ins int registerB, int registerC) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.registerB = Preconditions.checkByteRegister(registerB); this.registerC = Preconditions.checkByteRegister(registerC); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction30t.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction30t.java index 9e73cc46..364e3a6f 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction30t.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction30t.java @@ -34,7 +34,6 @@ package org.jf.dexlib2.immutable.instruction; import org.jf.dexlib2.Format; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.iface.instruction.formats.Instruction30t; -import org.jf.dexlib2.util.Preconditions; import javax.annotation.Nonnull; @@ -46,7 +45,6 @@ public class ImmutableInstruction30t extends ImmutableInstruction implements Ins public ImmutableInstruction30t(@Nonnull Opcode opcode, int codeOffset) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.codeOffset = codeOffset; } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31c.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31c.java index 9cfa95b6..4935e33b 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31c.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31c.java @@ -51,7 +51,6 @@ public class ImmutableInstruction31c extends ImmutableInstruction implements Ins int registerA, @Nonnull Reference reference) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31i.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31i.java index ffcde117..7d8f644d 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31i.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31i.java @@ -48,7 +48,6 @@ public class ImmutableInstruction31i extends ImmutableInstruction implements Ins int registerA, int literal) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.literal = literal; } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31t.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31t.java index 3fc3da21..6f865ee8 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31t.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction31t.java @@ -48,7 +48,6 @@ public class ImmutableInstruction31t extends ImmutableInstruction implements Ins int registerA, int codeOffset) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.codeOffset = codeOffset; } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction32x.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction32x.java index aa46b23c..10270986 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction32x.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction32x.java @@ -48,7 +48,6 @@ public class ImmutableInstruction32x extends ImmutableInstruction implements Ins int registerA, int registerB) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkShortRegister(registerA); this.registerB = Preconditions.checkShortRegister(registerB); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35c.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35c.java index a0b8fe39..a09051b2 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35c.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35c.java @@ -61,7 +61,6 @@ public class ImmutableInstruction35c extends ImmutableInstruction implements Ins int registerG, @Nonnull Reference reference) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerCount = Preconditions.check35cRegisterCount(registerCount); this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0; this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0; diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35mi.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35mi.java index a31474ea..def7eb60 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35mi.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35mi.java @@ -47,7 +47,7 @@ public class ImmutableInstruction35mi extends ImmutableInstruction implements In protected final int registerE; protected final int registerF; protected final int registerG; - @Nonnull protected final int inlineIndex; + protected final int inlineIndex; public ImmutableInstruction35mi(@Nonnull Opcode opcode, int registerCount, @@ -58,7 +58,6 @@ public class ImmutableInstruction35mi extends ImmutableInstruction implements In int registerG, int inlineIndex) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerCount = Preconditions.check35cRegisterCount(registerCount); this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0; this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0; diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35ms.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35ms.java index 4711bea7..16d7e913 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35ms.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35ms.java @@ -47,7 +47,7 @@ public class ImmutableInstruction35ms extends ImmutableInstruction implements In protected final int registerE; protected final int registerF; protected final int registerG; - @Nonnull protected final int vtableIndex; + protected final int vtableIndex; public ImmutableInstruction35ms(@Nonnull Opcode opcode, int registerCount, @@ -58,7 +58,6 @@ public class ImmutableInstruction35ms extends ImmutableInstruction implements In int registerG, int vtableIndex) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerCount = Preconditions.check35cRegisterCount(registerCount); this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0; this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0; diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rc.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rc.java index 19e211bd..61037414 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rc.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rc.java @@ -54,7 +54,6 @@ public class ImmutableInstruction3rc extends ImmutableInstruction implements Ins int registerCount, @Nonnull Reference reference) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.startRegister = Preconditions.checkShortRegister(startRegister); this.registerCount = Preconditions.checkRegisterRangeCount(registerCount); this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rmi.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rmi.java index 6943930e..a5136bc7 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rmi.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rmi.java @@ -43,7 +43,6 @@ public class ImmutableInstruction3rmi extends ImmutableInstruction implements In protected final int startRegister; protected final int registerCount; - protected final int inlineIndex; public ImmutableInstruction3rmi(@Nonnull Opcode opcode, @@ -51,7 +50,6 @@ public class ImmutableInstruction3rmi extends ImmutableInstruction implements In int registerCount, int inlineIndex) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.startRegister = Preconditions.checkShortRegister(startRegister); this.registerCount = Preconditions.checkRegisterRangeCount(registerCount); this.inlineIndex = Preconditions.checkInlineIndex(inlineIndex); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rms.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rms.java index f1e72d25..a81edb05 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rms.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction3rms.java @@ -43,7 +43,6 @@ public class ImmutableInstruction3rms extends ImmutableInstruction implements In protected final int startRegister; protected final int registerCount; - protected final int vtableIndex; public ImmutableInstruction3rms(@Nonnull Opcode opcode, @@ -51,7 +50,6 @@ public class ImmutableInstruction3rms extends ImmutableInstruction implements In int registerCount, int vtableIndex) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.startRegister = Preconditions.checkShortRegister(startRegister); this.registerCount = Preconditions.checkRegisterRangeCount(registerCount); this.vtableIndex = Preconditions.checkVtableIndex(vtableIndex); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction51l.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction51l.java index a092ea57..01afad96 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction51l.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction51l.java @@ -48,7 +48,6 @@ public class ImmutableInstruction51l extends ImmutableInstruction implements Ins int registerA, long literal) { super(opcode); - Preconditions.checkFormat(opcode, FORMAT); this.registerA = Preconditions.checkByteRegister(registerA); this.literal = literal; } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstructionFactory.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstructionFactory.java index ad562019..38a4d1d6 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstructionFactory.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstructionFactory.java @@ -40,7 +40,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; -public class ImmutableInstructionFactory implements InstructionFactory { +public class ImmutableInstructionFactory implements InstructionFactory { public static final ImmutableInstructionFactory INSTANCE = new ImmutableInstructionFactory(); private ImmutableInstructionFactory() { diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java index b20684d6..ab86b652 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java @@ -109,20 +109,20 @@ public class Preconditions { return literal; } - public static int checkByteCodeOffset(int register) { - if (register < -128 || register > 127) { + public static int checkByteCodeOffset(int offset) { + if (offset < -128 || offset > 127) { throw new IllegalArgumentException( - String.format("Invalid code offset: %d. Must be between -128 and 127, inclusive.", register)); + String.format("Invalid code offset: %d. Must be between -128 and 127, inclusive.", offset)); } - return register; + return offset; } - public static int checkShortCodeOffset(int register) { - if (register < -32768 || register > 32768) { + public static int checkShortCodeOffset(int offset) { + if (offset < -32768 || offset > 32767) { throw new IllegalArgumentException( - String.format("Invalid code offset: %d. Must be between -32768 and 32767, inclusive.", register)); + String.format("Invalid code offset: %d. Must be between -32768 and 32767, inclusive.", offset)); } - return register; + return offset; } public static int check35cRegisterCount(int registerCount) { diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java index c41b17e0..bb2e4a72 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java @@ -31,7 +31,11 @@ package org.jf.dexlib2.writer; +import org.jf.dexlib2.builder.MutableMethodImplementation; +import org.jf.dexlib2.iface.ExceptionHandler; import org.jf.dexlib2.iface.TryBlock; +import org.jf.dexlib2.iface.debug.DebugItem; +import org.jf.dexlib2.iface.instruction.Instruction; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -41,8 +45,7 @@ import java.util.List; import java.util.Map; public interface ClassSection extends IndexSection { + FieldKey, MethodKey, AnnotationSetKey, EncodedValue> extends IndexSection { @Nonnull Collection getSortedClasses(); @Nullable Map.Entry getClassEntryByType(@Nullable TypeKey key); @@ -73,9 +76,10 @@ public interface ClassSection getParameterNames(@Nonnull MethodKey key); int getRegisterCount(@Nonnull MethodKey key); - @Nullable Iterable getInstructions(@Nonnull MethodKey key); + @Nullable Iterable getInstructions(@Nonnull MethodKey key); @Nonnull List> getTryBlocks(@Nonnull MethodKey key); @Nullable TypeKey getExceptionType(@Nonnull ExceptionHandler handler); + @Nonnull MutableMethodImplementation makeMutableMethodImplementation(@Nonnull MethodKey key); void setEncodedArrayOffset(@Nonnull ClassKey key, int offset); int getEncodedArrayOffset(@Nonnull ClassKey key); @@ -89,8 +93,5 @@ public interface ClassSection writer, DebugItem debugItem) throws IOException; } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java index 9c979b74..0a26a5f7 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java @@ -36,29 +36,40 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; import org.jf.dexlib2.AccessFlags; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.base.BaseAnnotation; +import org.jf.dexlib2.builder.MutableMethodImplementation; +import org.jf.dexlib2.builder.instruction.BuilderInstruction31c; import org.jf.dexlib2.dexbacked.raw.*; import org.jf.dexlib2.iface.Annotation; +import org.jf.dexlib2.iface.ExceptionHandler; import org.jf.dexlib2.iface.TryBlock; +import org.jf.dexlib2.iface.debug.DebugItem; import org.jf.dexlib2.iface.debug.LineNumber; import org.jf.dexlib2.iface.instruction.Instruction; +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction; +import org.jf.dexlib2.iface.instruction.ReferenceInstruction; import org.jf.dexlib2.iface.instruction.formats.*; import org.jf.dexlib2.iface.reference.*; +import org.jf.dexlib2.util.InstructionUtil; import org.jf.dexlib2.util.MethodUtil; -import org.jf.dexlib2.writer.util.InstructionWriteUtil; +import org.jf.dexlib2.writer.io.DeferredOutputStream; +import org.jf.dexlib2.writer.io.DeferredOutputStreamFactory; +import org.jf.dexlib2.writer.io.DexDataStore; +import org.jf.dexlib2.writer.io.MemoryDeferredOutputStream; import org.jf.dexlib2.writer.util.TryListBuilder; import org.jf.util.CollectionUtils; import org.jf.util.ExceptionWithContext; -import org.jf.util.RandomAccessFileOutputStream; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.RandomAccessFile; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.channels.FileChannel; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; @@ -74,9 +85,7 @@ public abstract class DexWriter< AnnotationKey extends Annotation, AnnotationSetKey, TypeListKey, FieldKey, MethodKey, - EncodedValue, AnnotationElement, - DebugItem extends org.jf.dexlib2.iface.debug.DebugItem, - Insn extends Instruction, ExceptionHandler extends org.jf.dexlib2.iface.ExceptionHandler> { + EncodedValue, AnnotationElement> { public static final int NO_INDEX = -1; public static final int NO_OFFSET = 0; @@ -108,7 +117,7 @@ public abstract class DexWriter< protected int numCodeItemItems = 0; protected int numClassDataItems = 0; - protected final InstructionFactory instructionFactory; + protected final InstructionFactory instructionFactory; protected final StringSection stringSection; protected final TypeSection typeSection; @@ -116,21 +125,21 @@ public abstract class DexWriter< protected final FieldSection fieldSection; protected final MethodSection methodSection; protected final ClassSection classSection; + EncodedValue> classSection; protected final TypeListSection typeListSection; protected final AnnotationSection annotationSection; protected final AnnotationSetSection annotationSetSection; protected DexWriter(int api, - InstructionFactory instructionFactory, + InstructionFactory instructionFactory, StringSection stringSection, TypeSection typeSection, ProtoSection protoSection, FieldSection fieldSection, MethodSection methodSection, ClassSection classSection, + EncodedValue> classSection, TypeListSection typeListSection, AnnotationSection annotationSection, @@ -187,14 +196,17 @@ public abstract class DexWriter< classSection.getItems().size() * ClassDefItem.ITEM_SIZE; } - public void writeTo(String path) throws IOException { - RandomAccessFile raf = new RandomAccessFile(path, "rw"); - raf.setLength(0); + public void writeTo(@Nonnull DexDataStore dest) throws IOException { + this.writeTo(dest, MemoryDeferredOutputStream.getFactory()); + } + + public void writeTo(@Nonnull DexDataStore dest, + @Nonnull DeferredOutputStreamFactory tempFactory) throws IOException { try { int dataSectionOffset = getDataSectionOffset(); - DexDataWriter headerWriter = outputAt(raf, 0); - DexDataWriter indexWriter = outputAt(raf, HeaderItem.ITEM_SIZE); - DexDataWriter offsetWriter = outputAt(raf, dataSectionOffset); + DexDataWriter headerWriter = outputAt(dest, 0); + DexDataWriter indexWriter = outputAt(dest, HeaderItem.ITEM_SIZE); + DexDataWriter offsetWriter = outputAt(dest, dataSectionOffset); try { writeStrings(indexWriter, offsetWriter); writeTypes(indexWriter); @@ -207,8 +219,7 @@ public abstract class DexWriter< writeAnnotationSets(offsetWriter); writeAnnotationSetRefs(offsetWriter); writeAnnotationDirectories(offsetWriter); - writeDebugItems(offsetWriter); - writeCodeItems(offsetWriter); + writeDebugAndCodeItems(offsetWriter, tempFactory.makeDeferredOutputStream()); writeClasses(indexWriter, offsetWriter); writeMapItem(offsetWriter); writeHeader(headerWriter, dataSectionOffset, offsetWriter.getPosition()); @@ -217,15 +228,14 @@ public abstract class DexWriter< indexWriter.close(); offsetWriter.close(); } - FileChannel fileChannel = raf.getChannel(); - updateSignature(fileChannel); - updateChecksum(fileChannel); + updateSignature(dest); + updateChecksum(dest); } finally { - raf.close(); + dest.close(); } } - private void updateSignature(FileChannel fileChannel) throws IOException { + private void updateSignature(@Nonnull DexDataStore dataStore) throws IOException { MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); @@ -233,14 +243,12 @@ public abstract class DexWriter< throw new RuntimeException(ex); } - ByteBuffer buffer = ByteBuffer.allocate(128 * 1024); - fileChannel.position(HeaderItem.HEADER_SIZE_OFFSET); - int bytesRead = fileChannel.read(buffer); + byte[] buffer = new byte[4 * 1024]; + InputStream input = dataStore.readAt(HeaderItem.HEADER_SIZE_OFFSET); + int bytesRead = input.read(buffer); while (bytesRead >= 0) { - buffer.rewind(); - md.update(buffer); - buffer.clear(); - bytesRead = fileChannel.read(buffer); + md.update(buffer, 0, bytesRead); + bytesRead = input.read(buffer); } byte[] signature = md.digest(); @@ -249,38 +257,30 @@ public abstract class DexWriter< } // write signature - fileChannel.position(HeaderItem.SIGNATURE_OFFSET); - fileChannel.write(ByteBuffer.wrap(signature)); - - // flush - fileChannel.force(false); + OutputStream output = dataStore.outputAt(HeaderItem.SIGNATURE_OFFSET); + output.write(signature); + output.close(); } - private void updateChecksum(FileChannel fileChannel) throws IOException { + private void updateChecksum(@Nonnull DexDataStore dataStore) throws IOException { Adler32 a32 = new Adler32(); - ByteBuffer buffer = ByteBuffer.allocate(128 * 1024); - fileChannel.position(HeaderItem.SIGNATURE_OFFSET); - int bytesRead = fileChannel.read(buffer); + byte[] buffer = new byte[4 * 1024]; + InputStream input = dataStore.readAt(HeaderItem.SIGNATURE_OFFSET); + int bytesRead = input.read(buffer); while (bytesRead >= 0) { - a32.update(buffer.array(), 0, bytesRead); - buffer.clear(); - bytesRead = fileChannel.read(buffer); + a32.update(buffer, 0, bytesRead); + bytesRead = input.read(buffer); } // write checksum, utilizing logic in DexWriter to write the integer value properly - fileChannel.position(HeaderItem.CHECKSUM_OFFSET); - int checksum = (int) a32.getValue(); - ByteArrayOutputStream checksumBuf = new ByteArrayOutputStream(); - DexDataWriter.writeInt(checksumBuf, checksum); - fileChannel.write(ByteBuffer.wrap(checksumBuf.toByteArray())); - - // flush - fileChannel.force(false); + OutputStream output = dataStore.outputAt(HeaderItem.CHECKSUM_OFFSET); + DexDataWriter.writeInt(output, (int)a32.getValue()); + output.close(); } - private static DexDataWriter outputAt(RandomAccessFile raf, int filePosition) throws IOException { - return new DexDataWriter(new RandomAccessFileOutputStream(raf, filePosition), filePosition); + private static DexDataWriter outputAt(DexDataStore dataStore, int filePosition) throws IOException { + return new DexDataWriter(dataStore.outputAt(filePosition), filePosition); } private void writeStrings(@Nonnull DexDataWriter indexWriter, @Nonnull DexDataWriter offsetWriter) throws IOException { @@ -462,7 +462,7 @@ public abstract class DexWriter< int prevIndex = 0; for (FieldKey key: fields) { int index = fieldSection.getFieldIndex(key); - writer.writeUleb128(index-prevIndex); + writer.writeUleb128(index - prevIndex); writer.writeUleb128(classSection.getFieldAccessFlags(key)); prevIndex = index; } @@ -706,10 +706,26 @@ public abstract class DexWriter< } } - private void writeDebugItems(@Nonnull DexDataWriter writer) throws IOException { - debugSectionOffset = writer.getPosition(); + private static class CodeItemOffset { + @Nonnull MethodKey method; + int codeOffset; + + private CodeItemOffset(@Nonnull MethodKey method, int codeOffset) { + this.codeOffset = codeOffset; + this.method = method; + } + } + + private void writeDebugAndCodeItems(@Nonnull DexDataWriter offsetWriter, + @Nonnull DeferredOutputStream temp) throws IOException { + ByteArrayOutputStream ehBuf = new ByteArrayOutputStream(); + debugSectionOffset = offsetWriter.getPosition(); DebugWriter debugWriter = - new DebugWriter(stringSection, typeSection, writer); + new DebugWriter(stringSection, typeSection, offsetWriter); + + DexDataWriter codeWriter = new DexDataWriter(temp, 0); + + List> codeOffsets = Lists.newArrayList(); for (ClassKey classKey: classSection.getSortedClasses()) { Collection directMethods = classSection.getSortedDirectMethods(classKey); @@ -718,284 +734,350 @@ public abstract class DexWriter< Iterable methods = Iterables.concat(directMethods, virtualMethods); for (MethodKey methodKey: methods) { + List> tryBlocks = + classSection.getTryBlocks(methodKey); + Iterable instructions = classSection.getInstructions(methodKey); Iterable debugItems = classSection.getDebugItems(methodKey); - Iterable parameterNames = classSection.getParameterNames(methodKey); - int parameterCount = 0; - if (parameterNames != null) { - int index = 0; - for (StringKey parameterName: parameterNames) { - index++; - if (parameterName != null) { - parameterCount = index; + if (instructions != null && stringSection.hasJumboIndexes()) { + boolean needsFix = false; + for (Instruction instruction: instructions) { + if (instruction.getOpcode() == Opcode.CONST_STRING) { + if (stringSection.getItemIndex( + (StringRef)((ReferenceInstruction)instruction).getReference()) >= 65536) { + needsFix = true; + break; + } } } - } - if (debugItems == null && parameterCount == 0) { - continue; - } + if (needsFix) { + MutableMethodImplementation mutableMethodImplementation = + classSection.makeMutableMethodImplementation(methodKey); + fixInstructions(mutableMethodImplementation); - numDebugInfoItems++; - - classSection.setDebugItemOffset(methodKey, writer.getPosition()); - int startingLineNumber = 0; - - if (debugItems != null) { - for (org.jf.dexlib2.iface.debug.DebugItem debugItem: debugItems) { - if (debugItem instanceof LineNumber) { - startingLineNumber = ((LineNumber)debugItem).getLineNumber(); - break; - } - } - } - writer.writeUleb128(startingLineNumber); - - writer.writeUleb128(parameterCount); - if (parameterNames != null) { - int index = 0; - for (StringKey parameterName: parameterNames) { - if (index == parameterCount) { - break; - } - index++; - writer.writeUleb128(stringSection.getNullableItemIndex(parameterName) + 1); + instructions = mutableMethodImplementation.getInstructions(); + tryBlocks = mutableMethodImplementation.getTryBlocks(); + debugItems = mutableMethodImplementation.getDebugItems(); } } - if (debugItems != null) { - debugWriter.reset(startingLineNumber); + int debugItemOffset = writeDebugItem(offsetWriter, debugWriter, + classSection.getParameterNames(methodKey), debugItems); + int codeItemOffset = writeCodeItem(codeWriter, ehBuf, methodKey, tryBlocks, instructions, debugItemOffset); - for (DebugItem debugItem: debugItems) { - classSection.writeDebugItem(debugWriter, debugItem); - } + if (codeItemOffset != -1) { + codeOffsets.add(new CodeItemOffset(methodKey, codeItemOffset)); + } + } + } + + offsetWriter.align(); + codeSectionOffset = offsetWriter.getPosition(); + + codeWriter.close(); + temp.writeTo(offsetWriter); + temp.close(); + + for (CodeItemOffset codeOffset: codeOffsets) { + classSection.setCodeItemOffset(codeOffset.method, codeSectionOffset + codeOffset.codeOffset); + } + } + + private void fixInstructions(@Nonnull MutableMethodImplementation methodImplementation) { + List instructions = methodImplementation.getInstructions(); + + for (int i=0; i= 65536) { + methodImplementation.replaceInstruction(i, new BuilderInstruction31c(Opcode.CONST_STRING_JUMBO, + ((OneRegisterInstruction)instruction).getRegisterA(), + ((ReferenceInstruction)instruction).getReference())); } - // write an END_SEQUENCE opcode, to end the debug item - writer.write(0); } } } - private void writeCodeItems(@Nonnull DexDataWriter writer) throws IOException { - ByteArrayOutputStream ehBuf = new ByteArrayOutputStream(); - - writer.align(); - codeSectionOffset = writer.getPosition(); - for (ClassKey classKey: classSection.getSortedClasses()) { - Collection directMethods = classSection.getSortedDirectMethods(classKey); - Collection virtualMethods = classSection.getSortedVirtualMethods(classKey); - - Iterable methods = Iterables.concat(directMethods, virtualMethods); - - for (MethodKey methodKey: methods) { - Iterable instructions = classSection.getInstructions(methodKey); - int debugItemOffset = classSection.getDebugItemOffset(methodKey); - - if (instructions == null && debugItemOffset == NO_OFFSET) { - continue; - } - - numCodeItemItems++; - - writer.align(); - classSection.setCodeItemOffset(methodKey, writer.getPosition()); - - writer.writeUshort(classSection.getRegisterCount(methodKey)); - - boolean isStatic = AccessFlags.STATIC.isSet(classSection.getMethodAccessFlags(methodKey)); - Collection parameters = typeListSection.getTypes( - protoSection.getParameters(methodSection.getPrototype(methodKey))); - - List> tryBlocks = classSection.getTryBlocks(methodKey); - writer.writeUshort(MethodUtil.getParameterRegisterCount(parameters, isStatic)); - - if (instructions != null) { - tryBlocks = TryListBuilder.massageTryBlocks(tryBlocks); - - InstructionWriteUtil instrWriteUtil = - new InstructionWriteUtil(instructions, stringSection, instructionFactory); - writer.writeUshort(instrWriteUtil.getOutParamCount()); - writer.writeUshort(tryBlocks.size()); - writer.writeInt(debugItemOffset); - - InstructionWriter instructionWriter = - InstructionWriter.makeInstructionWriter(writer, stringSection, typeSection, fieldSection, - methodSection); - - writer.writeInt(instrWriteUtil.getCodeUnitCount()); - for (Insn instruction: instrWriteUtil.getInstructions()) { - switch (instruction.getOpcode().format) { - case Format10t: - instructionWriter.write((Instruction10t)instruction); - break; - case Format10x: - instructionWriter.write((Instruction10x)instruction); - break; - case Format11n: - instructionWriter.write((Instruction11n)instruction); - break; - case Format11x: - instructionWriter.write((Instruction11x)instruction); - break; - case Format12x: - instructionWriter.write((Instruction12x)instruction); - break; - case Format20bc: - instructionWriter.write((Instruction20bc)instruction); - break; - case Format20t: - instructionWriter.write((Instruction20t)instruction); - break; - case Format21c: - instructionWriter.write((Instruction21c)instruction); - break; - case Format21ih: - instructionWriter.write((Instruction21ih)instruction); - break; - case Format21lh: - instructionWriter.write((Instruction21lh)instruction); - break; - case Format21s: - instructionWriter.write((Instruction21s)instruction); - break; - case Format21t: - instructionWriter.write((Instruction21t)instruction); - break; - case Format22b: - instructionWriter.write((Instruction22b)instruction); - break; - case Format22c: - instructionWriter.write((Instruction22c)instruction); - break; - case Format22s: - instructionWriter.write((Instruction22s)instruction); - break; - case Format22t: - instructionWriter.write((Instruction22t)instruction); - break; - case Format22x: - instructionWriter.write((Instruction22x)instruction); - break; - case Format23x: - instructionWriter.write((Instruction23x)instruction); - break; - case Format30t: - instructionWriter.write((Instruction30t)instruction); - break; - case Format31c: - instructionWriter.write((Instruction31c)instruction); - break; - case Format31i: - instructionWriter.write((Instruction31i)instruction); - break; - case Format31t: - instructionWriter.write((Instruction31t)instruction); - break; - case Format32x: - instructionWriter.write((Instruction32x)instruction); - break; - case Format35c: - instructionWriter.write((Instruction35c)instruction); - break; - case Format3rc: - instructionWriter.write((Instruction3rc)instruction); - break; - case Format51l: - instructionWriter.write((Instruction51l)instruction); - break; - case ArrayPayload: - instructionWriter.write((ArrayPayload)instruction); - break; - case PackedSwitchPayload: - instructionWriter.write((PackedSwitchPayload)instruction); - break; - case SparseSwitchPayload: - instructionWriter.write((SparseSwitchPayload)instruction); - break; - default: - throw new ExceptionWithContext("Unsupported instruction format: %s", - instruction.getOpcode().format); - } - } - - if (tryBlocks.size() > 0) { - writer.align(); - - - - // filter out unique lists of exception handlers - Map, Integer> exceptionHandlerOffsetMap = Maps.newHashMap(); - for (TryBlock tryBlock: tryBlocks) { - exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0); - } - DexDataWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size()); - - for (TryBlock tryBlock: tryBlocks) { - int startAddress = tryBlock.getStartCodeAddress(); - int endAddress = startAddress + tryBlock.getCodeUnitCount(); - - startAddress += instrWriteUtil.codeOffsetShift(startAddress); - endAddress += instrWriteUtil.codeOffsetShift(endAddress); - int tbCodeUnitCount = endAddress - startAddress; - - writer.writeInt(startAddress); - writer.writeUshort(tbCodeUnitCount); - - if (tryBlock.getExceptionHandlers().size() == 0) { - throw new ExceptionWithContext("No exception handlers for the try block!"); - } - - Integer offset = exceptionHandlerOffsetMap.get(tryBlock.getExceptionHandlers()); - if (offset != 0) { - // exception handler has already been written out, just use it - writer.writeUshort(offset); - } else { - // if offset has not been set yet, we are about to write out a new exception handler - offset = ehBuf.size(); - writer.writeUshort(offset); - exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), offset); - - // check if the last exception handler is a catch-all and adjust the size accordingly - int ehSize = tryBlock.getExceptionHandlers().size(); - ExceptionHandler ehLast = tryBlock.getExceptionHandlers().get(ehSize-1); - if (ehLast.getExceptionType() == null) { - ehSize = ehSize * (-1) + 1; - } - - // now let's layout the exception handlers, assuming that catch-all is always last - DexDataWriter.writeSleb128(ehBuf, ehSize); - for (ExceptionHandler eh : tryBlock.getExceptionHandlers()) { - TypeKey exceptionTypeKey = classSection.getExceptionType(eh); - - int codeAddress = eh.getHandlerCodeAddress(); - codeAddress += instrWriteUtil.codeOffsetShift(codeAddress); - - if (exceptionTypeKey != null) { - //regular exception handling - DexDataWriter.writeUleb128(ehBuf, typeSection.getItemIndex(exceptionTypeKey)); - DexDataWriter.writeUleb128(ehBuf, codeAddress); - } else { - //catch-all - DexDataWriter.writeUleb128(ehBuf, codeAddress); - } - } - } - } - - if (ehBuf.size() > 0) { - ehBuf.writeTo(writer); - ehBuf.reset(); - } - } - } else { - // no instructions, all we have is the debug item offset - writer.writeUshort(0); - writer.writeUshort(0); - writer.writeInt(debugItemOffset); - writer.writeInt(0); + private int writeDebugItem(@Nonnull DexDataWriter writer, + @Nonnull DebugWriter debugWriter, + @Nullable Iterable parameterNames, + @Nullable Iterable debugItems) throws IOException { + int parameterCount = 0; + if (parameterNames != null) { + int index = 0; + for (StringKey parameterName: parameterNames) { + index++; + if (parameterName != null) { + parameterCount = index; } } } + + if (debugItems == null && parameterCount == 0) { + return NO_OFFSET; + } + + numDebugInfoItems++; + + int debugItemOffset = writer.getPosition(); + int startingLineNumber = 0; + + if (debugItems != null) { + for (org.jf.dexlib2.iface.debug.DebugItem debugItem: debugItems) { + if (debugItem instanceof LineNumber) { + startingLineNumber = ((LineNumber)debugItem).getLineNumber(); + break; + } + } + } + writer.writeUleb128(startingLineNumber); + + writer.writeUleb128(parameterCount); + if (parameterNames != null) { + int index = 0; + for (StringKey parameterName: parameterNames) { + if (index == parameterCount) { + break; + } + index++; + writer.writeUleb128(stringSection.getNullableItemIndex(parameterName) + 1); + } + } + + if (debugItems != null) { + debugWriter.reset(startingLineNumber); + + for (DebugItem debugItem: debugItems) { + classSection.writeDebugItem(debugWriter, debugItem); + } + } + // write an END_SEQUENCE opcode, to end the debug item + writer.write(0); + + return debugItemOffset; + } + + private int writeCodeItem(@Nonnull DexDataWriter writer, + @Nonnull ByteArrayOutputStream ehBuf, + @Nonnull MethodKey methodKey, + @Nonnull List> tryBlocks, + @Nullable Iterable instructions, + int debugItemOffset) throws IOException { + if (instructions == null && debugItemOffset == NO_OFFSET) { + return -1; + } + + numCodeItemItems++; + + writer.align(); + + int codeItemOffset = writer.getPosition(); + + writer.writeUshort(classSection.getRegisterCount(methodKey)); + + boolean isStatic = AccessFlags.STATIC.isSet(classSection.getMethodAccessFlags(methodKey)); + Collection parameters = typeListSection.getTypes( + protoSection.getParameters(methodSection.getPrototype(methodKey))); + + writer.writeUshort(MethodUtil.getParameterRegisterCount(parameters, isStatic)); + + if (instructions != null) { + tryBlocks = TryListBuilder.massageTryBlocks(tryBlocks); + + int outParamCount = 0; + int codeUnitCount = 0; + for (Instruction instruction: instructions) { + codeUnitCount += instruction.getCodeUnits(); + if (instruction.getOpcode().referenceType == ReferenceType.METHOD) { + ReferenceInstruction refInsn = (ReferenceInstruction)instruction; + MethodReference methodRef = (MethodReference)refInsn.getReference(); + int paramCount = MethodUtil.getParameterRegisterCount(methodRef, InstructionUtil.isInvokeStatic(instruction.getOpcode())); + if (paramCount > outParamCount) { + outParamCount = paramCount; + } + } + } + + writer.writeUshort(outParamCount); + writer.writeUshort(tryBlocks.size()); + writer.writeInt(debugItemOffset); + + InstructionWriter instructionWriter = + InstructionWriter.makeInstructionWriter(writer, stringSection, typeSection, fieldSection, + methodSection); + + writer.writeInt(codeUnitCount); + for (Instruction instruction: instructions) { + switch (instruction.getOpcode().format) { + case Format10t: + instructionWriter.write((Instruction10t)instruction); + break; + case Format10x: + instructionWriter.write((Instruction10x)instruction); + break; + case Format11n: + instructionWriter.write((Instruction11n)instruction); + break; + case Format11x: + instructionWriter.write((Instruction11x)instruction); + break; + case Format12x: + instructionWriter.write((Instruction12x)instruction); + break; + case Format20bc: + instructionWriter.write((Instruction20bc)instruction); + break; + case Format20t: + instructionWriter.write((Instruction20t)instruction); + break; + case Format21c: + instructionWriter.write((Instruction21c)instruction); + break; + case Format21ih: + instructionWriter.write((Instruction21ih)instruction); + break; + case Format21lh: + instructionWriter.write((Instruction21lh)instruction); + break; + case Format21s: + instructionWriter.write((Instruction21s)instruction); + break; + case Format21t: + instructionWriter.write((Instruction21t)instruction); + break; + case Format22b: + instructionWriter.write((Instruction22b)instruction); + break; + case Format22c: + instructionWriter.write((Instruction22c)instruction); + break; + case Format22s: + instructionWriter.write((Instruction22s)instruction); + break; + case Format22t: + instructionWriter.write((Instruction22t)instruction); + break; + case Format22x: + instructionWriter.write((Instruction22x)instruction); + break; + case Format23x: + instructionWriter.write((Instruction23x)instruction); + break; + case Format30t: + instructionWriter.write((Instruction30t)instruction); + break; + case Format31c: + instructionWriter.write((Instruction31c)instruction); + break; + case Format31i: + instructionWriter.write((Instruction31i)instruction); + break; + case Format31t: + instructionWriter.write((Instruction31t)instruction); + break; + case Format32x: + instructionWriter.write((Instruction32x)instruction); + break; + case Format35c: + instructionWriter.write((Instruction35c)instruction); + break; + case Format3rc: + instructionWriter.write((Instruction3rc)instruction); + break; + case Format51l: + instructionWriter.write((Instruction51l)instruction); + break; + case ArrayPayload: + instructionWriter.write((ArrayPayload)instruction); + break; + case PackedSwitchPayload: + instructionWriter.write((PackedSwitchPayload)instruction); + break; + case SparseSwitchPayload: + instructionWriter.write((SparseSwitchPayload)instruction); + break; + default: + throw new ExceptionWithContext("Unsupported instruction format: %s", + instruction.getOpcode().format); + } + } + + if (tryBlocks.size() > 0) { + writer.align(); + + // filter out unique lists of exception handlers + Map, Integer> exceptionHandlerOffsetMap = Maps.newHashMap(); + for (TryBlock tryBlock: tryBlocks) { + exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0); + } + DexDataWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size()); + + for (TryBlock tryBlock: tryBlocks) { + int startAddress = tryBlock.getStartCodeAddress(); + int endAddress = startAddress + tryBlock.getCodeUnitCount(); + + int tbCodeUnitCount = endAddress - startAddress; + + writer.writeInt(startAddress); + writer.writeUshort(tbCodeUnitCount); + + if (tryBlock.getExceptionHandlers().size() == 0) { + throw new ExceptionWithContext("No exception handlers for the try block!"); + } + + Integer offset = exceptionHandlerOffsetMap.get(tryBlock.getExceptionHandlers()); + if (offset != 0) { + // exception handler has already been written out, just use it + writer.writeUshort(offset); + } else { + // if offset has not been set yet, we are about to write out a new exception handler + offset = ehBuf.size(); + writer.writeUshort(offset); + exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), offset); + + // check if the last exception handler is a catch-all and adjust the size accordingly + int ehSize = tryBlock.getExceptionHandlers().size(); + ExceptionHandler ehLast = tryBlock.getExceptionHandlers().get(ehSize-1); + if (ehLast.getExceptionType() == null) { + ehSize = ehSize * (-1) + 1; + } + + // now let's layout the exception handlers, assuming that catch-all is always last + DexDataWriter.writeSleb128(ehBuf, ehSize); + for (ExceptionHandler eh : tryBlock.getExceptionHandlers()) { + TypeKey exceptionTypeKey = classSection.getExceptionType(eh); + + int codeAddress = eh.getHandlerCodeAddress(); + + if (exceptionTypeKey != null) { + //regular exception handling + DexDataWriter.writeUleb128(ehBuf, typeSection.getItemIndex(exceptionTypeKey)); + DexDataWriter.writeUleb128(ehBuf, codeAddress); + } else { + //catch-all + DexDataWriter.writeUleb128(ehBuf, codeAddress); + } + } + } + } + + if (ehBuf.size() > 0) { + ehBuf.writeTo(writer); + ehBuf.reset(); + } + } + } else { + // no instructions, all we have is the debug item offset + writer.writeUshort(0); + writer.writeUshort(0); + writer.writeInt(debugItemOffset); + writer.writeInt(0); + } + + return codeItemOffset; } private int calcNumItems() { diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionFactory.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionFactory.java index 63a41562..31db1b8c 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionFactory.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionFactory.java @@ -41,36 +41,36 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; -public interface InstructionFactory { - Insn makeInstruction10t(@Nonnull Opcode opcode, int codeOffset); - Insn makeInstruction10x(@Nonnull Opcode opcode); - Insn makeInstruction11n(@Nonnull Opcode opcode, int registerA, int literal); - Insn makeInstruction11x(@Nonnull Opcode opcode, int registerA); - Insn makeInstruction12x(@Nonnull Opcode opcode, int registerA, int registerB); - Insn makeInstruction20bc(@Nonnull Opcode opcode, int verificationError, @Nonnull Ref reference); - Insn makeInstruction20t(@Nonnull Opcode opcode, int codeOffset); - Insn makeInstruction21c(@Nonnull Opcode opcode, int registerA, @Nonnull Ref reference); - Insn makeInstruction21ih(@Nonnull Opcode opcode, int registerA, int literal); - Insn makeInstruction21lh(@Nonnull Opcode opcode, int registerA, long literal); - Insn makeInstruction21s(@Nonnull Opcode opcode, int registerA, int literal); - Insn makeInstruction21t(@Nonnull Opcode opcode, int registerA, int codeOffset); - Insn makeInstruction22b(@Nonnull Opcode opcode, int registerA, int registerB, int literal); - Insn makeInstruction22c(@Nonnull Opcode opcode, int registerA, int registerB, @Nonnull Ref reference); - Insn makeInstruction22s(@Nonnull Opcode opcode, int registerA, int registerB, int literal); - Insn makeInstruction22t(@Nonnull Opcode opcode, int registerA, int registerB, int codeOffset); - Insn makeInstruction22x(@Nonnull Opcode opcode, int registerA, int registerB); - Insn makeInstruction23x(@Nonnull Opcode opcode, int registerA, int registerB, int registerC); - Insn makeInstruction30t(@Nonnull Opcode opcode, int codeOffset); - Insn makeInstruction31c(@Nonnull Opcode opcode, int registerA, @Nonnull Ref reference); - Insn makeInstruction31i(@Nonnull Opcode opcode, int registerA, int literal); - Insn makeInstruction31t(@Nonnull Opcode opcode, int registerA, int codeOffset); - Insn makeInstruction32x(@Nonnull Opcode opcode, int registerA, int registerB); - Insn makeInstruction35c(@Nonnull Opcode opcode, int registerCount, int registerC, int registerD, int registerE, +public interface InstructionFactory { + Instruction makeInstruction10t(@Nonnull Opcode opcode, int codeOffset); + Instruction makeInstruction10x(@Nonnull Opcode opcode); + Instruction makeInstruction11n(@Nonnull Opcode opcode, int registerA, int literal); + Instruction makeInstruction11x(@Nonnull Opcode opcode, int registerA); + Instruction makeInstruction12x(@Nonnull Opcode opcode, int registerA, int registerB); + Instruction makeInstruction20bc(@Nonnull Opcode opcode, int verificationError, @Nonnull Ref reference); + Instruction makeInstruction20t(@Nonnull Opcode opcode, int codeOffset); + Instruction makeInstruction21c(@Nonnull Opcode opcode, int registerA, @Nonnull Ref reference); + Instruction makeInstruction21ih(@Nonnull Opcode opcode, int registerA, int literal); + Instruction makeInstruction21lh(@Nonnull Opcode opcode, int registerA, long literal); + Instruction makeInstruction21s(@Nonnull Opcode opcode, int registerA, int literal); + Instruction makeInstruction21t(@Nonnull Opcode opcode, int registerA, int codeOffset); + Instruction makeInstruction22b(@Nonnull Opcode opcode, int registerA, int registerB, int literal); + Instruction makeInstruction22c(@Nonnull Opcode opcode, int registerA, int registerB, @Nonnull Ref reference); + Instruction makeInstruction22s(@Nonnull Opcode opcode, int registerA, int registerB, int literal); + Instruction makeInstruction22t(@Nonnull Opcode opcode, int registerA, int registerB, int codeOffset); + Instruction makeInstruction22x(@Nonnull Opcode opcode, int registerA, int registerB); + Instruction makeInstruction23x(@Nonnull Opcode opcode, int registerA, int registerB, int registerC); + Instruction makeInstruction30t(@Nonnull Opcode opcode, int codeOffset); + Instruction makeInstruction31c(@Nonnull Opcode opcode, int registerA, @Nonnull Ref reference); + Instruction makeInstruction31i(@Nonnull Opcode opcode, int registerA, int literal); + Instruction makeInstruction31t(@Nonnull Opcode opcode, int registerA, int codeOffset); + Instruction makeInstruction32x(@Nonnull Opcode opcode, int registerA, int registerB); + Instruction makeInstruction35c(@Nonnull Opcode opcode, int registerCount, int registerC, int registerD, int registerE, int registerF, int registerG, @Nonnull Ref reference); - Insn makeInstruction3rc(@Nonnull Opcode opcode, int startRegister, int registerCount, + Instruction makeInstruction3rc(@Nonnull Opcode opcode, int startRegister, int registerCount, @Nonnull Ref reference); - Insn makeInstruction51l(@Nonnull Opcode opcode, int registerA, long literal); - Insn makeSparseSwitchPayload(@Nullable List switchElements); - Insn makePackedSwitchPayload(@Nullable List switchElements); - Insn makeArrayPayload(int elementWidth, @Nullable List arrayElements); + Instruction makeInstruction51l(@Nonnull Opcode opcode, int registerA, long literal); + Instruction makeSparseSwitchPayload(@Nullable List switchElements); + Instruction makePackedSwitchPayload(@Nullable List switchElements); + Instruction makeArrayPayload(int elementWidth, @Nullable List arrayElements); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/StringSection.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/StringSection.java index 9dc5886e..3f370ee8 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/StringSection.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/StringSection.java @@ -32,8 +32,10 @@ package org.jf.dexlib2.writer; import org.jf.dexlib2.iface.reference.StringReference; -import org.jf.dexlib2.writer.util.InstructionWriteUtil; -public interface StringSection extends NullableIndexSection, - InstructionWriteUtil.StringIndexProvider { +import javax.annotation.Nonnull; + +public interface StringSection extends NullableIndexSection { + int getItemIndex(@Nonnull StringRef key); + boolean hasJumboIndexes(); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java index a793b9ea..fd5cc540 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java @@ -73,10 +73,20 @@ public class BuilderClassDef extends BaseTypeReference implements ClassDef { this.interfaces = interfaces; this.sourceFile = sourceFile; this.annotations = annotations; - this.staticFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC)); - this.instanceFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE)); - this.directMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_DIRECT)); - this.virtualMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_VIRTUAL)); + if (fields == null) { + this.staticFields = ImmutableSortedSet.of(); + this.instanceFields = ImmutableSortedSet.of(); + } else { + this.staticFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC)); + this.instanceFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE)); + } + if (methods == null) { + this.directMethods = ImmutableSortedSet.of(); + this.virtualMethods = ImmutableSortedSet.of(); + } else { + this.directMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_DIRECT)); + this.virtualMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_VIRTUAL)); + } } @Nonnull @Override public String getType() { return type.getType(); } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java index cda9a4e2..91f6d4c8 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java @@ -35,17 +35,19 @@ import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.*; import org.jf.dexlib2.DebugItemType; +import org.jf.dexlib2.builder.MutableMethodImplementation; +import org.jf.dexlib2.iface.ExceptionHandler; import org.jf.dexlib2.iface.Field; +import org.jf.dexlib2.iface.MethodImplementation; import org.jf.dexlib2.iface.TryBlock; -import org.jf.dexlib2.iface.debug.EndLocal; -import org.jf.dexlib2.iface.debug.LineNumber; -import org.jf.dexlib2.iface.debug.RestartLocal; +import org.jf.dexlib2.iface.debug.*; +import org.jf.dexlib2.iface.instruction.Instruction; +import org.jf.dexlib2.iface.reference.StringReference; +import org.jf.dexlib2.iface.reference.TypeReference; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.util.EncodedValueUtils; import org.jf.dexlib2.writer.ClassSection; import org.jf.dexlib2.writer.DebugWriter; -import org.jf.dexlib2.writer.builder.BuilderDebugItem.BuilderSetSourceFile; -import org.jf.dexlib2.writer.builder.BuilderDebugItem.BuilderStartLocal; import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue; import org.jf.util.AbstractForwardSequentialList; import org.jf.util.CollectionUtils; @@ -59,8 +61,7 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; public class BuilderClassPool implements ClassSection { + BuilderClassDef, BuilderField, BuilderMethod, BuilderAnnotationSet, BuilderEncodedValue> { @Nonnull private final ConcurrentMap internedItems = Maps.newConcurrentMap(); @@ -266,8 +267,8 @@ public class BuilderClassPool implements ClassSection getDebugItems(@Nonnull BuilderMethod builderMethod) { - BuilderMethodImplementation impl = builderMethod.getImplementation(); + public Iterable getDebugItems(@Nonnull BuilderMethod builderMethod) { + MethodImplementation impl = builderMethod.getImplementation(); if (impl == null) { return null; } @@ -284,16 +285,16 @@ public class BuilderClassPool implements ClassSection getInstructions(@Nonnull BuilderMethod builderMethod) { - BuilderMethodImplementation impl = builderMethod.getImplementation(); + public Iterable getInstructions(@Nonnull BuilderMethod builderMethod) { + MethodImplementation impl = builderMethod.getImplementation(); if (impl == null) { return null; } @@ -301,16 +302,25 @@ public class BuilderClassPool implements ClassSection> getTryBlocks(@Nonnull BuilderMethod builderMethod) { - BuilderMethodImplementation impl = builderMethod.getImplementation(); + public List> getTryBlocks(@Nonnull BuilderMethod builderMethod) { + MethodImplementation impl = builderMethod.getImplementation(); if (impl == null) { return ImmutableList.of(); } return impl.getTryBlocks(); } - @Nullable @Override public BuilderTypeReference getExceptionType(@Nonnull BuilderExceptionHandler handler) { - return handler.exceptionType; + @Nullable @Override public BuilderTypeReference getExceptionType(@Nonnull ExceptionHandler handler) { + return checkTypeReference(handler.getExceptionTypeReference()); + } + + @Nonnull @Override + public MutableMethodImplementation makeMutableMethodImplementation(@Nonnull BuilderMethod builderMethod) { + MethodImplementation impl = builderMethod.getImplementation(); + if (impl instanceof MutableMethodImplementation) { + return (MutableMethodImplementation)impl; + } + return new MutableMethodImplementation(impl); } @Override public void setEncodedArrayOffset(@Nonnull BuilderClassDef builderClassDef, int offset) { @@ -345,25 +355,41 @@ public class BuilderClassPool implements ClassSection writer, - BuilderDebugItem debugItem) throws IOException { + DebugItem debugItem) throws IOException { switch (debugItem.getDebugItemType()) { case DebugItemType.START_LOCAL: { - BuilderStartLocal startLocal = (BuilderStartLocal)debugItem; + StartLocal startLocal = (StartLocal)debugItem; writer.writeStartLocal(startLocal.getCodeAddress(), - startLocal.register, - startLocal.name, - startLocal.type, - startLocal.signature); + startLocal.getRegister(), + checkStringReference(startLocal.getNameReference()), + checkTypeReference(startLocal.getTypeReference()), + checkStringReference(startLocal.getSignatureReference())); break; } case DebugItemType.END_LOCAL: { @@ -390,8 +416,9 @@ public class BuilderClassPool implements ClassSection0) ? Preconditions.checkNibbleRegister(registerC) : 0; this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0; @@ -319,8 +315,6 @@ public interface BuilderInstruction extends Instruction { int registerCount, @Nonnull BuilderReference reference) { super(opcode); - - Preconditions.checkFormat(opcode, FORMAT); this.startRegister = Preconditions.checkShortRegister(startRegister); this.registerCount = Preconditions.checkRegisterRangeCount(registerCount); this.reference = Preconditions.checkReference(opcode.referenceType, reference); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderInstructionFactory.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderInstructionFactory.java index 349c7e23..280c318d 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderInstructionFactory.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderInstructionFactory.java @@ -40,7 +40,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; -public class BuilderInstructionFactory implements InstructionFactory { +public class BuilderInstructionFactory implements InstructionFactory { public static final BuilderInstructionFactory INSTANCE = new BuilderInstructionFactory(); private BuilderInstructionFactory() { diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethod.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethod.java index fea8fd0a..dc48c98c 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethod.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethod.java @@ -33,6 +33,7 @@ package org.jf.dexlib2.writer.builder; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.Method; +import org.jf.dexlib2.iface.MethodImplementation; import org.jf.dexlib2.writer.DexWriter; import javax.annotation.Nonnull; @@ -44,17 +45,16 @@ public class BuilderMethod extends BaseMethodReference implements Method { @Nonnull final List parameters; final int accessFlags; @Nonnull final BuilderAnnotationSet annotations; - @Nullable final BuilderMethodImplementation methodImplementation; + @Nullable final MethodImplementation methodImplementation; int annotationSetRefListOffset = DexWriter.NO_OFFSET; int codeItemOffset = DexWriter.NO_OFFSET; - int debugInfoOffset = DexWriter.NO_OFFSET; BuilderMethod(@Nonnull BuilderMethodReference methodReference, @Nonnull List parameters, int accessFlags, @Nonnull BuilderAnnotationSet annotations, - @Nullable BuilderMethodImplementation methodImplementation) { + @Nullable MethodImplementation methodImplementation) { this.methodReference = methodReference; this.parameters = parameters; this.accessFlags = accessFlags; @@ -69,5 +69,5 @@ public class BuilderMethod extends BaseMethodReference implements Method { @Override @Nonnull public List getParameters() { return parameters; } @Override public int getAccessFlags() { return accessFlags; } @Override @Nonnull public BuilderAnnotationSet getAnnotations() { return annotations; } - @Override @Nullable public BuilderMethodImplementation getImplementation() { return methodImplementation; } + @Override @Nullable public MethodImplementation getImplementation() { return methodImplementation; } } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodImplementation.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodImplementation.java deleted file mode 100644 index 5c901c02..00000000 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodImplementation.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.jf.dexlib2.writer.builder; - -import org.jf.dexlib2.iface.MethodImplementation; - -import javax.annotation.Nonnull; -import java.util.List; - -public class BuilderMethodImplementation implements MethodImplementation { - protected final int registerCount; - @Nonnull protected final List instructions; - @Nonnull protected final List tryBlocks; - @Nonnull protected final List debugItems; - - public BuilderMethodImplementation(int registerCount, - @Nonnull List instructions, - @Nonnull List tryBlocks, - @Nonnull List debugItems) { - this.registerCount = registerCount; - this.instructions = instructions; - this.tryBlocks = tryBlocks; - this.debugItems = debugItems; - } - - @Override public int getRegisterCount() { return registerCount; } - @Nonnull @Override public List getInstructions() { return instructions; } - @Nonnull @Override public List getTryBlocks() { return tryBlocks; } - @Nonnull @Override public List getDebugItems() { return debugItems; } -} diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderStringPool.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderStringPool.java index cab91927..6b60e9f8 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderStringPool.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderStringPool.java @@ -69,6 +69,10 @@ class BuilderStringPool implements StringSection 65536; + } + @Nonnull @Override public Collection> getItems() { return new BuilderMapEntryCollection(internedItems.values()) { @Override protected int getValue(@Nonnull BuilderStringReference key) { diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java index 913765f3..aabf071e 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java @@ -37,11 +37,11 @@ import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.Annotation; +import org.jf.dexlib2.iface.MethodImplementation; import org.jf.dexlib2.iface.MethodParameter; import org.jf.dexlib2.iface.reference.*; import org.jf.dexlib2.iface.value.*; import org.jf.dexlib2.writer.DexWriter; -import org.jf.dexlib2.writer.builder.BuilderDebugItem.*; import org.jf.dexlib2.writer.builder.BuilderEncodedValues.*; import org.jf.util.ExceptionWithContext; @@ -56,7 +56,7 @@ import java.util.Set; public class DexBuilder extends DexWriter { + BuilderEncodedValue, BuilderAnnotationElement> { private final BuilderContext context; @@ -95,7 +95,7 @@ public class DexBuilder extends DexWriter annotations, - @Nullable BuilderMethodImplementation methodImplementation) { + @Nullable MethodImplementation methodImplementation) { if (parameters == null) { parameters = ImmutableList.of(); } @@ -106,26 +106,6 @@ public class DexBuilder extends DexWriter instructions, - @Nullable List tryBlocks, - @Nullable List debugItems) { - if (instructions == null) { - instructions = ImmutableList.of(); - } - - if (tryBlocks == null) { - tryBlocks = ImmutableList.of(); - } - - if (debugItems == null) { - debugItems = ImmutableList.of(); - } - - return new BuilderMethodImplementation(registerCount, instructions, tryBlocks, debugItems); - } - @Nonnull public BuilderClassDef internClassDef(@Nonnull String type, int accessFlags, @Nullable String superclass, @@ -164,10 +144,24 @@ public class DexBuilder extends DexWriter internMethodParameters( @Nullable List methodParameters) { if (methodParameters == null) { @@ -212,46 +206,6 @@ public class DexBuilder extends DexWriter>, PoolClassDef, Field, PoolMethod, - Set, - EncodedValue, DebugItem, Instruction, ExceptionHandler> { + Set, EncodedValue> { @Nonnull private HashMap internedItems = Maps.newHashMap(); @Nonnull private final StringPool stringPool; @@ -434,6 +434,11 @@ public class ClassPool implements ClassSection writer, DebugItem debugItem) throws IOException { switch (debugItem.getDebugItemType()) { diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java index 1eda265a..fd3db366 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java @@ -32,17 +32,20 @@ package org.jf.dexlib2.writer.pool; import org.jf.dexlib2.ValueType; -import org.jf.dexlib2.iface.*; -import org.jf.dexlib2.iface.debug.DebugItem; -import org.jf.dexlib2.iface.instruction.Instruction; +import org.jf.dexlib2.iface.Annotation; +import org.jf.dexlib2.iface.AnnotationElement; +import org.jf.dexlib2.iface.ClassDef; +import org.jf.dexlib2.iface.Field; import org.jf.dexlib2.iface.reference.*; import org.jf.dexlib2.iface.value.*; import org.jf.dexlib2.immutable.instruction.ImmutableInstructionFactory; import org.jf.dexlib2.writer.DexWriter; +import org.jf.dexlib2.writer.io.FileDataStore; import org.jf.dexlib2.writer.pool.ProtoPool.Key; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; +import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Set; @@ -51,7 +54,7 @@ public class DexPool extends DexWriter, TypeListPool.Key>, Field, PoolMethod, - EncodedValue, AnnotationElement, DebugItem, Instruction, ExceptionHandler> { + EncodedValue, AnnotationElement> { public static DexPool makeDexPool() { return makeDexPool(15); @@ -85,7 +88,7 @@ public class DexPool extends DexWriter TRANSFORM = new Function() { @Override public PoolMethod apply(Method method) { diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/StringPool.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/StringPool.java index e071582e..5886b4f6 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/StringPool.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/StringPool.java @@ -33,6 +33,7 @@ package org.jf.dexlib2.writer.pool; import org.jf.dexlib2.iface.reference.StringReference; import org.jf.dexlib2.writer.StringSection; +import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -49,6 +50,14 @@ public class StringPool extends StringTypeBasePool implements StringSection 65536; } } diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/util/InstructionWriteUtil.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/util/InstructionWriteUtil.java deleted file mode 100644 index 9a9d417f..00000000 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/util/InstructionWriteUtil.java +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright 2013, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.jf.dexlib2.writer.util; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.jf.dexlib2.Format; -import org.jf.dexlib2.Opcode; -import org.jf.dexlib2.ReferenceType; -import org.jf.dexlib2.iface.instruction.Instruction; -import org.jf.dexlib2.iface.instruction.ReferenceInstruction; -import org.jf.dexlib2.iface.instruction.SwitchElement; -import org.jf.dexlib2.iface.instruction.SwitchPayload; -import org.jf.dexlib2.iface.instruction.formats.*; -import org.jf.dexlib2.iface.reference.*; -import org.jf.dexlib2.immutable.instruction.*; -import org.jf.dexlib2.util.InstructionUtil; -import org.jf.dexlib2.util.MethodUtil; -import org.jf.dexlib2.writer.InstructionFactory; -import org.jf.util.ExceptionWithContext; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -public class InstructionWriteUtil { - private final StringIndexProvider stringIndexProvider; - private final InstructionFactory instructionFactory; - private final Iterable originalInstructions; - - private List instructions; - private ArrayList codeOffsetShifts; - private HashMap offsetToNewInstructionMap; - - private int codeUnitCount; - private int outParamCount; - - public static interface StringIndexProvider { - int getItemIndex(@Nonnull StringRef reference); - } - - public InstructionWriteUtil(@Nonnull Iterable instructions, - @Nonnull StringIndexProvider stringIndexProvider, - @Nonnull InstructionFactory instructionFactory) { - this.stringIndexProvider = stringIndexProvider; - this.instructionFactory = instructionFactory; - this.originalInstructions = instructions; - calculateMaxOutParamCount(); - findCodeOffsetShifts(); - modifyInstructions(); - } - - private void calculateMaxOutParamCount() { - for (Insn instruction: originalInstructions) { - codeUnitCount += instruction.getCodeUnits(); - if (instruction.getOpcode().referenceType == ReferenceType.METHOD) { - ReferenceInstruction refInsn = (ReferenceInstruction)instruction; - MethodReference methodRef = (MethodReference)refInsn.getReference(); - int paramCount = MethodUtil.getParameterRegisterCount(methodRef, InstructionUtil.isInvokeStatic(instruction.getOpcode())); - if (paramCount > outParamCount) { - outParamCount = paramCount; - } - } - } - } - public Iterable getInstructions() { - if (instructions != null) { - return instructions; - } else { - return originalInstructions; - } - } - - public int getCodeUnitCount() { - return codeUnitCount; - } - - public int getOutParamCount() { - return outParamCount; - } - - private int targetOffsetShift(int instrOffset, int targetOffset) { - int targetOffsetShift = 0; - if (codeOffsetShifts != null) { - int instrShift = codeOffsetShift(instrOffset); - int targetShift = codeOffsetShift(instrOffset+targetOffset); - targetOffsetShift = targetShift - instrShift; - } - return targetOffsetShift; - } - - public int codeOffsetShift(int offset) { - int shift = 0; - if (codeOffsetShifts != null) { - int numCodeOffsetShifts = codeOffsetShifts.size(); - if (numCodeOffsetShifts > 0) { - if (offset >= codeOffsetShifts.get(numCodeOffsetShifts-1)) { - shift = numCodeOffsetShifts; - } else if (numCodeOffsetShifts>1) { - for (int i=1;i= codeOffsetShifts.get(i-1) && offset < codeOffsetShifts.get(i)) { - shift = i; - break; - } - } - } - } - } - return shift; - } - - /* - * This method creates a list of code offsets of instructions, whose (and subsequent instructions') - * code offset will get shifted by one code unit with respect to previous instruction(s). - * This happens when the previous instruction has to be changed to a larger sized one - * to fit the new value or payload instruction has to be prepended by nop to ensure alignment. - */ - private void findCodeOffsetShifts() { - // first, process const-string to const-string/jumbo conversions - int currentCodeOffset = 0; - codeOffsetShifts = Lists.newArrayList(); - offsetToNewInstructionMap = Maps.newHashMap(); - - for (Instruction instruction: originalInstructions) { - if (instruction.getOpcode().equals(Opcode.CONST_STRING)) { - ReferenceInstruction refInstr = (ReferenceInstruction) instruction; - int referenceIndex = stringIndexProvider.getItemIndex((StringRef)refInstr.getReference()); - if (referenceIndex > 0xFFFF) { - codeOffsetShifts.add(currentCodeOffset+instruction.getCodeUnits()); - offsetToNewInstructionMap.put(currentCodeOffset, Opcode.CONST_STRING_JUMBO.format); - } - } - currentCodeOffset += instruction.getCodeUnits(); - } - - // next, let's check if this caused any conversions in goto instructions due to changes in offset values - // since code offset delta is equivalent to the position of instruction's code offset in the shift list, - // we use it as a position here - // we also check if we will have to insert nops to ensure 4-byte alignment for switch statements and packed arrays - boolean shiftsInserted; - do { - currentCodeOffset = 0; - shiftsInserted = false; - for (Instruction instruction: originalInstructions) { - if (instruction.getOpcode().format.equals(Format.Format10t) && !offsetToNewInstructionMap.containsKey(currentCodeOffset)) { - int targetOffset = ((Instruction10t)instruction).getCodeOffset(); - int codeOffsetDelta = codeOffsetShift(currentCodeOffset); - int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset); - if ((byte)newTargetOffset != newTargetOffset) { - if ((short)newTargetOffset != newTargetOffset) { - // handling very small (negligible) possibility of goto becoming goto/32 - // we insert extra 1 code unit shift referring to the same position - // this will cause subsequent code offsets to be shifted by 2 code units - codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits()); - offsetToNewInstructionMap.put(currentCodeOffset, Format.Format30t); - } else { - offsetToNewInstructionMap.put(currentCodeOffset, Format.Format20t); - } - codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits()); - shiftsInserted = true; - } - } else if (instruction.getOpcode().format.equals(Format.Format20t) && !offsetToNewInstructionMap.containsKey(currentCodeOffset)) { - int targetOffset = ((Instruction20t)instruction).getCodeOffset(); - int codeOffsetDelta = codeOffsetShift(currentCodeOffset); - int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset); - if ((short)newTargetOffset != newTargetOffset) { - codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits()); - offsetToNewInstructionMap.put(currentCodeOffset, Format.Format30t); - shiftsInserted = true; - } - } else if (instruction.getOpcode().format.equals(Format.ArrayPayload) - || instruction.getOpcode().format.equals(Format.SparseSwitchPayload) - || instruction.getOpcode().format.equals(Format.PackedSwitchPayload)) { - int codeOffsetDelta = codeOffsetShift(currentCodeOffset); - if ((currentCodeOffset+codeOffsetDelta)%2 != 0) { - if (codeOffsetShifts.contains(currentCodeOffset)) { - codeOffsetShifts.remove(codeOffsetDelta-1); - offsetToNewInstructionMap.remove(currentCodeOffset); - } else { - codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset); - offsetToNewInstructionMap.put(currentCodeOffset, Format.Format10x); - shiftsInserted = true; - } - } - } - currentCodeOffset += instruction.getCodeUnits(); - } - } while (shiftsInserted); - - codeUnitCount += codeOffsetShifts.size(); - } - - private void modifyInstructions() { - if (codeOffsetShifts == null) { - return; - } - - instructions = Lists.newArrayList(); - int currentCodeOffset = 0; - for (Insn instruction: originalInstructions) { - Insn modifiedInstruction = null; - switch (instruction.getOpcode().format) { - case Format10t: { - Instruction10t instr = (Instruction10t)instruction; - int targetOffset = instr.getCodeOffset(); - int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset); - Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset); - if (newInstructionFormat != null) { - if (newInstructionFormat.equals(Format.Format30t)) { - modifiedInstruction = instructionFactory.makeInstruction30t(Opcode.GOTO_32, newTargetOffset); - } else if (newInstructionFormat.equals(Format.Format20t)) { - modifiedInstruction = instructionFactory.makeInstruction20t(Opcode.GOTO_16, newTargetOffset); - } - } else if (newTargetOffset != targetOffset) { - modifiedInstruction = instructionFactory.makeInstruction10t(instr.getOpcode(), newTargetOffset); - } - break; - } - case Format20t: { - Instruction20t instr = (Instruction20t)instruction; - int targetOffset = instr.getCodeOffset(); - int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset); - Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset); - if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format30t)) { - modifiedInstruction = instructionFactory.makeInstruction30t(Opcode.GOTO_32, newTargetOffset); - } else if (newTargetOffset != targetOffset) { - modifiedInstruction = instructionFactory.makeInstruction20t(Opcode.GOTO_16, newTargetOffset); - } - break; - } - case Format21c: { - Instruction21c instr = (Instruction21c)instruction; - if (instr.getOpcode().equals(Opcode.CONST_STRING)) { - int referenceIndex = stringIndexProvider.getItemIndex((StringRef)instr.getReference()); - if (referenceIndex > 0xFFFF) { - modifiedInstruction = instructionFactory.makeInstruction31c(Opcode.CONST_STRING_JUMBO, - instr.getRegisterA(), (BaseReference)instr.getReference()); - } - } - break; - } - case Format21t: { - Instruction21t instr = (Instruction21t)instruction; - int targetOffset = instr.getCodeOffset(); - int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset); - if (newTargetOffset != targetOffset) { - modifiedInstruction = instructionFactory.makeInstruction21t(instr.getOpcode(), - instr.getRegisterA(), newTargetOffset); - } - break; - } - case Format22t: { - Instruction22t instr = (Instruction22t)instruction; - int targetOffset = instr.getCodeOffset(); - int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset); - if (newTargetOffset != targetOffset) { - modifiedInstruction = instructionFactory.makeInstruction22t(instr.getOpcode(), - instr.getRegisterA(), instr.getRegisterB(), newTargetOffset); - } - break; - } - case Format30t: { - Instruction30t instr = (Instruction30t)instruction; - int targetOffset = instr.getCodeOffset(); - int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset); - if (newTargetOffset != targetOffset) { - modifiedInstruction = instructionFactory.makeInstruction30t(instr.getOpcode(), newTargetOffset); - } - break; - } - case Format31t: { - Instruction31t instr = (Instruction31t)instruction; - int targetOffset = instr.getCodeOffset(); - int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset); - if (newTargetOffset != targetOffset) { - modifiedInstruction = instructionFactory.makeInstruction31t(instr.getOpcode(), - instr.getRegisterA(), newTargetOffset); - } - break; - } - case SparseSwitchPayload: { - alignPayload(currentCodeOffset); - int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset); - SwitchPayload payload = (SwitchPayload)instruction; - if (isSwitchTargetOffsetChanged(payload, switchInstructionOffset)) { - List newSwitchElements = modifySwitchElements(payload, switchInstructionOffset); - modifiedInstruction = instructionFactory.makeSparseSwitchPayload(newSwitchElements); - } - break; - } - case PackedSwitchPayload: { - alignPayload(currentCodeOffset); - int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset); - SwitchPayload payload = (SwitchPayload)instruction; - if (isSwitchTargetOffsetChanged(payload, switchInstructionOffset)) { - List newSwitchElements = modifySwitchElements(payload, switchInstructionOffset); - modifiedInstruction = instructionFactory.makePackedSwitchPayload(newSwitchElements); - } - break; - } - case ArrayPayload: { - alignPayload(currentCodeOffset); - break; - } - } - - if (modifiedInstruction != null) { - instructions.add(modifiedInstruction); - } else { - instructions.add(instruction); - } - - currentCodeOffset += instruction.getCodeUnits(); - } - } - - private void alignPayload(int codeOffset) { - Format newInstructionFormat = offsetToNewInstructionMap.get(codeOffset); - if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format10x)) { - instructions.add(instructionFactory.makeInstruction10x(Opcode.NOP)); - } - } - - private int findSwitchInstructionOffset(int payloadOffset) { - int currentCodeOffset = 0; - int switchInstructionOffset = -1; - for (Instruction instruction: originalInstructions) { - if (instruction.getOpcode().equals(Opcode.PACKED_SWITCH) - || instruction.getOpcode().equals(Opcode.SPARSE_SWITCH)) { - int targetOffset = currentCodeOffset + ((Instruction31t)instruction).getCodeOffset(); - if (targetOffset == payloadOffset) { - if (switchInstructionOffset < 0) { - switchInstructionOffset = currentCodeOffset; - } else { - throw new ExceptionWithContext("Multiple switch instructions refer to the same switch payload!"); - } - } - } - currentCodeOffset += instruction.getCodeUnits(); - } - return switchInstructionOffset; - } - - private boolean isSwitchTargetOffsetChanged(SwitchPayload payload, int switchInstructionOffset) { - for (SwitchElement switchElement: payload.getSwitchElements()) { - if (targetOffsetShift(switchInstructionOffset, switchElement.getOffset()) != 0) { - return true; - } - } - return false; - } - - private ArrayList modifySwitchElements(SwitchPayload payload, int switchInstructionOffset) { - ArrayList switchElements = Lists.newArrayList(); - for (SwitchElement switchElement: payload.getSwitchElements()) { - int targetOffset = switchElement.getOffset(); - int newTargetOffset = targetOffset + targetOffsetShift(switchInstructionOffset, targetOffset); - if (newTargetOffset != targetOffset) { - ImmutableSwitchElement immuSwitchElement = new ImmutableSwitchElement(switchElement.getKey(), newTargetOffset); - switchElements.add(immuSwitchElement); - } else { - switchElements.add(switchElement); - } - } - return switchElements; - } - -} - - diff --git a/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java b/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java index 7ca6b45a..ab903b9b 100644 --- a/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java +++ b/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java @@ -31,351 +31,185 @@ package org.jf.dexlib2.writer; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import junit.framework.Assert; import org.jf.dexlib2.Opcode; -import org.jf.dexlib2.iface.MethodImplementation; +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.builder.MethodImplementationBuilder; +import org.jf.dexlib2.builder.instruction.BuilderInstruction10x; +import org.jf.dexlib2.builder.instruction.BuilderInstruction21c; +import org.jf.dexlib2.dexbacked.DexBackedDexFile; +import org.jf.dexlib2.iface.*; +import org.jf.dexlib2.iface.debug.DebugItem; import org.jf.dexlib2.iface.instruction.Instruction; -import org.jf.dexlib2.iface.instruction.SwitchElement; -import org.jf.dexlib2.iface.instruction.formats.*; +import org.jf.dexlib2.iface.instruction.ReferenceInstruction; +import org.jf.dexlib2.iface.instruction.formats.Instruction21c; import org.jf.dexlib2.iface.reference.Reference; import org.jf.dexlib2.iface.reference.StringReference; -import org.jf.dexlib2.immutable.ImmutableMethodImplementation; -import org.jf.dexlib2.immutable.instruction.*; -import org.jf.dexlib2.immutable.reference.ImmutableStringReference; -import org.jf.dexlib2.writer.util.InstructionWriteUtil; -import org.junit.Before; +import org.jf.dexlib2.immutable.instruction.ImmutableInstruction10x; +import org.jf.dexlib2.writer.builder.DexBuilder; +import org.jf.dexlib2.writer.io.MemoryDataStore; +import org.junit.Assert; import org.junit.Test; import javax.annotation.Nonnull; -import java.util.ArrayList; +import java.io.IOException; +import java.util.List; public class JumboStringConversionTest { - private static final int MIN_NUM_JUMBO_STRINGS = 2; + @Test + public void testJumboStringConversion() throws IOException { + DexBuilder dexBuilder = DexBuilder.makeDexBuilder(15); - private MockStringIndexProvider mockStringIndexProvider; - ArrayList mJumboStrings; - - private class InsnWriteUtil extends InstructionWriteUtil { - public InsnWriteUtil(@Nonnull MethodImplementation implementation) { - super(implementation.getInstructions(), mockStringIndexProvider, ImmutableInstructionFactory.INSTANCE); + MethodImplementationBuilder methodBuilder = new MethodImplementationBuilder(1); + for (int i=0; i<66000; i++) { + methodBuilder.addInstruction(new BuilderInstruction21c(Opcode.CONST_STRING, 0, + dexBuilder.internStringReference(String.format("%08d", i)))); } + methodBuilder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID)); + + dexBuilder.internClassDef( + "Ltest;", + 0, + "Ljava/lang/Object;", + null, + null, + ImmutableSet.of(), + null, + ImmutableList.of( + dexBuilder.internMethod( + "Ltest;", + "test", + null, + "V", + 0, + ImmutableSet.of(), + methodBuilder.getMethodImplementation()))); + + MemoryDataStore dexStore = new MemoryDataStore(); + dexBuilder.writeTo(dexStore); + + DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15), dexStore.getData()); + + ClassDef classDef = Iterables.getFirst(dexFile.getClasses(), null); + Assert.assertNotNull(classDef); + + Method method = Iterables.getFirst(classDef.getMethods(), null); + Assert.assertNotNull(method); + + MethodImplementation impl = method.getImplementation(); + Assert.assertNotNull(impl); + + List instructions = Lists.newArrayList(impl.getInstructions()); + Assert.assertEquals(66001, instructions.size()); + + for (int i=0; i<65536; i++) { + Assert.assertEquals(Opcode.CONST_STRING, instructions.get(i).getOpcode()); + Assert.assertEquals(String.format("%08d", i), + ((StringReference)((ReferenceInstruction)instructions.get(i)).getReference()).getString()); + } + for (int i=65536; i<66000; i++) { + Assert.assertEquals(Opcode.CONST_STRING_JUMBO, instructions.get(i).getOpcode()); + Assert.assertEquals(String.format("%08d", i), + ((StringReference)((ReferenceInstruction)instructions.get(i)).getReference()).getString()); + } + Assert.assertEquals(Opcode.RETURN_VOID, instructions.get(66000).getOpcode()); } - @Before - public void setup() { - mockStringIndexProvider = new MockStringIndexProvider(); - StringBuilder stringBuilder = new StringBuilder("a"); - mJumboStrings = Lists.newArrayList(); - int index = 0; - // populate StringPool, make sure there are more than 64k+MIN_NUM_JUMBO_STRINGS strings - while (mJumboStrings.size()=0;pos--) { - for (char ch='a';ch<='z';ch++) { - stringBuilder.setCharAt(pos, ch); - mockStringIndexProvider.intern(stringBuilder.toString(), index++); - if (mockStringIndexProvider.getNumItems()>0xFFFF) { - mJumboStrings.add(stringBuilder.toString()); - } + @Test + public void testJumboStringConversion_NonMethodBuilder() throws IOException { + DexBuilder dexBuilder = DexBuilder.makeDexBuilder(15); + + final List instructions = Lists.newArrayList(); + for (int i=0; i<66000; i++) { + final StringReference ref = dexBuilder.internStringReference(String.format("%08d", i)); + + instructions.add(new Instruction21c() { + @Override public int getRegisterA() { + return 0; } - } - stringBuilder.setLength(stringBuilder.length()+1); - for (int pos=0;pos instructions = Lists.newArrayList(); - instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, - new ImmutableStringReference(mJumboStrings.get(0)))); - - ImmutableMethodImplementation methodImplementation = - new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - Assert.assertEquals("Jumbo string conversion was not performed!", - instr.getOpcode(), Opcode.CONST_STRING_JUMBO); - } - } - - private ArrayList createSimpleInstructionList() { - ArrayList instructions = Lists.newArrayList(); - instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0)))); - instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(1)))); - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - - ArrayList switchElements = Lists.newArrayList(); - switchElements.add(new ImmutableSwitchElement(0, 5)); - instructions.add(new ImmutablePackedSwitchPayload(switchElements)); - instructions.add(new ImmutableSparseSwitchPayload(switchElements)); - - return instructions; - } - - @Test - public void testInstruction10tSimple() { - ArrayList instructions = createSimpleInstructionList(); - instructions.add(1, new ImmutableInstruction10t(Opcode.GOTO, 3)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - if (instr instanceof Instruction10t) { - Instruction10t instruction = (Instruction10t) instr; - Assert.assertEquals("goto (Format10t) target was not modified properly", instruction.getCodeOffset(), 4); - break; - } - } - } - - @Test - public void testInstruction20tSimple() { - ArrayList instructions = createSimpleInstructionList(); - instructions.add(1, new ImmutableInstruction20t(Opcode.GOTO_16, 4)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - if (instr instanceof Instruction20t) { - Instruction20t instruction = (Instruction20t) instr; - Assert.assertEquals("goto/16 (Format20t) target was not modified properly", instruction.getCodeOffset(), 5); - break; - } - } - } - - @Test - public void testInstruction30t() { - ArrayList instructions = createSimpleInstructionList(); - instructions.add(1, new ImmutableInstruction30t(Opcode.GOTO_32, 5)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - if (instr instanceof Instruction30t) { - Instruction30t instruction = (Instruction30t) instr; - Assert.assertEquals("goto/32 (Format30t) target was not modified properly", instruction.getCodeOffset(), 6); - break; - } - } - } - - @Test - public void testInstruction21t() { - ArrayList instructions = createSimpleInstructionList(); - instructions.add(1, new ImmutableInstruction21t(Opcode.IF_EQZ, 0, 4)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - if (instr instanceof Instruction21t) { - Instruction21t instruction = (Instruction21t) instr; - Assert.assertEquals("branch instruction (Format21t) target was not modified properly", instruction.getCodeOffset(), 5); - break; - } - } - } - - @Test - public void testInstruction22t() { - ArrayList instructions = createSimpleInstructionList(); - instructions.add(1, new ImmutableInstruction22t(Opcode.IF_EQ, 0, 1, 4)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - if (instr instanceof Instruction22t) { - Instruction22t instruction = (Instruction22t) instr; - Assert.assertEquals("branch instruction (Format22t) target was not modified properly", instruction.getCodeOffset(), 5); - break; - } - } - } - - @Test - public void testInstruction31t() { - ArrayList instructions = createSimpleInstructionList(); - instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 5)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - if (instr instanceof Instruction31t) { - Instruction31t instruction = (Instruction31t) instr; - Assert.assertEquals("branch instruction (Format31t) target was not modified properly", instruction.getCodeOffset(), 6); - break; - } - } - } - - @Test - public void testPackedSwitchPayload() { - ArrayList instructions = createSimpleInstructionList(); - instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 6)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - if (instr instanceof PackedSwitchPayload) { - PackedSwitchPayload instruction = (PackedSwitchPayload) instr; - for (SwitchElement switchElement: instruction.getSwitchElements()) { - Assert.assertEquals("packed switch payload offset was not modified properly", switchElement.getOffset(), 6); + @Nonnull @Override public Reference getReference() { + return ref; } - break; - } - } - } - @Test - public void testSparseSwitchPayload() { - ArrayList instructions = createSimpleInstructionList(); - instructions.add(1, new ImmutableInstruction31t(Opcode.SPARSE_SWITCH, 0, 12)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - for (Instruction instr: writeUtil.getInstructions()) { - if (instr instanceof SparseSwitchPayload) { - SparseSwitchPayload instruction = (SparseSwitchPayload) instr; - for (SwitchElement switchElement: instruction.getSwitchElements()) { - Assert.assertEquals("packed switch payload offset was not modified properly", switchElement.getOffset(), 6); + @Override public Opcode getOpcode() { + return Opcode.CONST_STRING; } - break; + + @Override public int getCodeUnits() { + return getOpcode().format.size / 2; + } + }); + } + instructions.add(new ImmutableInstruction10x(Opcode.RETURN_VOID)); + + MethodImplementation methodImpl = new MethodImplementation() { + @Override public int getRegisterCount() { + return 1; } - } - } - @Test - public void testArrayPayloadAlignment() { - ArrayList instructions = createSimpleInstructionList(); - // add misaligned array payload - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - instructions.add(new ImmutableArrayPayload(4, null)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - int codeOffset = 0; - for (Instruction instr: writeUtil.getInstructions()) { - if (codeOffset == 21) { - Assert.assertEquals("array payload was not aligned properly", instr.getOpcode(), Opcode.NOP); - break; + @Nonnull @Override public Iterable getInstructions() { + return instructions; } - codeOffset += instr.getCodeUnits(); - } - } - @Test - public void testPackedSwitchAlignment() { - ArrayList instructions = createSimpleInstructionList(); - // packed switch instruction is already misaligned - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - int codeOffset = 0; - for (Instruction instr: writeUtil.getInstructions()) { - if (codeOffset == 7) { - Assert.assertEquals("packed switch payload was not aligned properly", instr.getOpcode(), Opcode.NOP); - break; + @Nonnull @Override public List> getTryBlocks() { + return ImmutableList.of(); } - codeOffset += instr.getCodeUnits(); - } - } - @Test - public void testSparseSwitchAlignment() { - ArrayList instructions = createSimpleInstructionList(); - // insert a nop to mis-align sparse switch payload - instructions.add(4, new ImmutableInstruction10x(Opcode.NOP)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - int codeOffset = 0; - for (Instruction instr: writeUtil.getInstructions()) { - if (codeOffset == 15) { - Assert.assertEquals("packed switch payload was not aligned properly", instr.getOpcode(), Opcode.NOP); - break; + @Nonnull @Override public Iterable getDebugItems() { + return ImmutableList.of(); } - codeOffset += instr.getCodeUnits(); + }; + + dexBuilder.internClassDef( + "Ltest;", + 0, + "Ljava/lang/Object;", + null, + null, + ImmutableSet.of(), + null, + ImmutableList.of( + dexBuilder.internMethod( + "Ltest;", + "test", + null, + "V", + 0, + ImmutableSet.of(), + methodImpl))); + + MemoryDataStore dexStore = new MemoryDataStore(); + dexBuilder.writeTo(dexStore); + + DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15), dexStore.getData()); + + ClassDef classDef = Iterables.getFirst(dexFile.getClasses(), null); + Assert.assertNotNull(classDef); + + Method method = Iterables.getFirst(classDef.getMethods(), null); + Assert.assertNotNull(method); + + MethodImplementation impl = method.getImplementation(); + Assert.assertNotNull(impl); + + List actualInstructions = Lists.newArrayList(impl.getInstructions()); + Assert.assertEquals(66001, actualInstructions.size()); + + for (int i=0; i<65536; i++) { + Assert.assertEquals(Opcode.CONST_STRING, actualInstructions.get(i).getOpcode()); + Assert.assertEquals(String.format("%08d", i), + ((StringReference)((ReferenceInstruction)actualInstructions.get(i)).getReference()).getString()); } - } - - @Test - public void testGotoToGoto16() { - ArrayList instructions = Lists.newArrayList(); - instructions.add(new ImmutableInstruction10t(Opcode.GOTO, 127)); - instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0)))); - for (int i=0;i<127;i++) { - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - } - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - Instruction instr = writeUtil.getInstructions().iterator().next(); - Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16); - } - - @Test - public void testGoto16ToGoto32() { - ArrayList instructions = Lists.newArrayList(); - instructions.add(new ImmutableInstruction20t(Opcode.GOTO_16, Short.MAX_VALUE)); - instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0)))); - for (int i=0;i instructions = Lists.newArrayList(); - - instructions.add(new ImmutableInstruction10t(Opcode.GOTO, 126)); - instructions.add(new ImmutableInstruction10t(Opcode.GOTO, 127)); - instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0)))); - for (int i=0;i<122;i++) { - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - } - instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(1)))); - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - - // this misaligned array payload will cause nop insertion on the first pass and its removal on the second pass - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - instructions.add(new ImmutableArrayPayload(4, null)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - Instruction instr = writeUtil.getInstructions().iterator().next(); - Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16); - - int codeOffset = 0; - for (Instruction instruction: writeUtil.getInstructions()) { - if (instruction instanceof ArrayPayload) { - Assert.assertEquals("packed switch payload was not aligned properly", codeOffset%2, 0); - } - codeOffset += instruction.getCodeUnits(); + for (int i=65536; i<66000; i++) { + Assert.assertEquals(Opcode.CONST_STRING_JUMBO, actualInstructions.get(i).getOpcode()); + Assert.assertEquals(String.format("%08d", i), + ((StringReference)((ReferenceInstruction)actualInstructions.get(i)).getReference()).getString()); } + Assert.assertEquals(Opcode.RETURN_VOID, actualInstructions.get(66000).getOpcode()); } } diff --git a/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/MockStringIndexProvider.java b/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/MockStringIndexProvider.java deleted file mode 100644 index 442a1d22..00000000 --- a/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/MockStringIndexProvider.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.jf.dexlib2.writer; - -import com.google.common.collect.Maps; -import org.jf.dexlib2.iface.reference.StringReference; -import org.jf.dexlib2.writer.util.InstructionWriteUtil.StringIndexProvider; - -import javax.annotation.Nonnull; -import java.util.HashMap; - -public class MockStringIndexProvider implements StringIndexProvider { - private HashMap internedItems = Maps.newHashMap(); - - public void intern(@Nonnull CharSequence string, int index) { - internedItems.put(string.toString(), index); - } - - @Override public int getItemIndex(@Nonnull StringReference reference) { - return internedItems.get(reference.getString()); - } - - public int getNumItems() { - return internedItems.size(); - } -} diff --git a/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/PayloadAlignmentTest.java b/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/PayloadAlignmentTest.java deleted file mode 100644 index fe25f42b..00000000 --- a/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/PayloadAlignmentTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2012, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.jf.dexlib2.writer; - -import com.google.common.collect.Lists; -import junit.framework.Assert; -import org.jf.dexlib2.Opcode; -import org.jf.dexlib2.iface.MethodImplementation; -import org.jf.dexlib2.iface.instruction.Instruction; -import org.jf.dexlib2.iface.instruction.SwitchElement; -import org.jf.dexlib2.iface.reference.Reference; -import org.jf.dexlib2.iface.reference.StringReference; -import org.jf.dexlib2.immutable.ImmutableMethodImplementation; -import org.jf.dexlib2.immutable.instruction.*; -import org.jf.dexlib2.writer.util.InstructionWriteUtil; -import org.junit.Before; -import org.junit.Test; - -import javax.annotation.Nonnull; -import java.util.ArrayList; - -public class PayloadAlignmentTest { - private MockStringIndexProvider mockStringIndexProvider; - - private class InsnWriteUtil extends InstructionWriteUtil { - public InsnWriteUtil(@Nonnull MethodImplementation implementation) { - super(implementation.getInstructions(), mockStringIndexProvider, ImmutableInstructionFactory.INSTANCE); - } - } - - @Before - public void setup() { - mockStringIndexProvider = new MockStringIndexProvider(); - } - - @Test - public void testArrayPayloadAlignment() { - ArrayList instructions = Lists.newArrayList(); - - // add misaligned array payload - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - instructions.add(new ImmutableArrayPayload(4, null)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - int codeOffset = 0; - for (Instruction instr: writeUtil.getInstructions()) { - if (instr.getOpcode().equals(Opcode.ARRAY_PAYLOAD)) { - Assert.assertEquals("array payload was not aligned properly", codeOffset%2, 0); - break; - } - codeOffset += instr.getCodeUnits(); - } - } - - @Test - public void testPackedSwitchAlignment() { - ArrayList instructions = Lists.newArrayList(); - // add misaligned packed switch payload - ArrayList switchElements = Lists.newArrayList(); - switchElements.add(new ImmutableSwitchElement(0, 5)); - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - instructions.add(new ImmutablePackedSwitchPayload(switchElements)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - int codeOffset = 0; - for (Instruction instr: writeUtil.getInstructions()) { - if (instr.getOpcode().equals(Opcode.PACKED_SWITCH_PAYLOAD)) { - Assert.assertEquals("packed switch payload was not aligned properly", codeOffset%2, 0); - break; - } - codeOffset += instr.getCodeUnits(); - } - } - - @Test - public void testSparseSwitchAlignment() { - ArrayList instructions = Lists.newArrayList(); - - // add misaligned sparse switch payload - ArrayList switchElements = Lists.newArrayList(); - switchElements.add(new ImmutableSwitchElement(0, 5)); - - instructions.add(new ImmutableInstruction10x(Opcode.NOP)); - instructions.add(new ImmutableSparseSwitchPayload(switchElements)); - - ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null); - InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation); - - int codeOffset = 0; - for (Instruction instr: writeUtil.getInstructions()) { - if (instr.getOpcode().equals(Opcode.SPARSE_SWITCH_PAYLOAD)) { - Assert.assertEquals("packed switch payload was not aligned properly", codeOffset%2, 0); - break; - } - codeOffset += instr.getCodeUnits(); - } - } -} diff --git a/brut.apktool.smali/smali/src/main/antlr3/smaliParser.g b/brut.apktool.smali/smali/src/main/antlr3/smaliParser.g index 1007d797..7c0a1e56 100644 --- a/brut.apktool.smali/smali/src/main/antlr3/smaliParser.g +++ b/brut.apktool.smali/smali/src/main/antlr3/smaliParser.g @@ -140,10 +140,9 @@ tokens { LOCALS_DIRECTIVE; LONG_LITERAL; METHOD_DIRECTIVE; - METHOD_NAME; + MEMBER_NAME; NEGATIVE_INTEGER_LITERAL; NULL_LITERAL; - OFFSET; OPEN_BRACE; OPEN_PAREN; PACKED_SWITCH_DIRECTIVE; @@ -188,7 +187,6 @@ tokens { I_METHOD_RETURN_TYPE; I_REGISTERS; I_LOCALS; - I_LABELS; I_LABEL; I_ANNOTATIONS; I_ANNOTATION; @@ -202,26 +200,20 @@ tokens { I_ARRAY_ELEMENTS; I_PACKED_SWITCH_START_KEY; I_PACKED_SWITCH_ELEMENTS; - I_PACKED_SWITCH_DECLARATION; - I_PACKED_SWITCH_DECLARATIONS; I_SPARSE_SWITCH_ELEMENTS; - I_SPARSE_SWITCH_DECLARATION; - I_SPARSE_SWITCH_DECLARATIONS; - I_ADDRESS; I_CATCH; I_CATCHALL; I_CATCHES; I_PARAMETER; I_PARAMETERS; I_PARAMETER_NOT_SPECIFIED; - I_ORDERED_DEBUG_DIRECTIVES; I_LINE; I_LOCAL; I_END_LOCAL; I_RESTART_LOCAL; I_PROLOGUE; I_EPILOGUE; - I_STATEMENTS; + I_ORDERED_METHOD_ITEMS; I_STATEMENT_FORMAT10t; I_STATEMENT_FORMAT10x; I_STATEMENT_FORMAT11n; @@ -500,56 +492,49 @@ the annotations. If it turns out that they are field annotations, we include the add them to the $smali_file::classAnnotations list*/ field @init {List annotations = new ArrayList();} - : FIELD_DIRECTIVE access_list simple_name COLON nonvoid_type_descriptor (EQUAL literal)? + : FIELD_DIRECTIVE access_list member_name COLON nonvoid_type_descriptor (EQUAL literal)? ( ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})* ( END_FIELD_DIRECTIVE - -> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*)) + -> ^(I_FIELD[$start, "I_FIELD"] member_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*)) | /*epsilon*/ {$smali_file::classAnnotations.addAll(annotations);} - -> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS)) + -> ^(I_FIELD[$start, "I_FIELD"] member_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS)) ) ); method - scope {int currentAddress;} - : {$method::currentAddress = 0;} - METHOD_DIRECTIVE access_list method_name method_prototype statements_and_directives + : METHOD_DIRECTIVE access_list member_name method_prototype statements_and_directives END_METHOD_DIRECTIVE - -> ^(I_METHOD[$start, "I_METHOD"] method_name method_prototype access_list statements_and_directives); + -> ^(I_METHOD[$start, "I_METHOD"] member_name method_prototype access_list statements_and_directives); statements_and_directives scope { boolean hasRegistersDirective; - List packedSwitchDeclarations; - List sparseSwitchDeclarations; List methodAnnotations; } : { - $method::currentAddress = 0; $statements_and_directives::hasRegistersDirective = false; - $statements_and_directives::packedSwitchDeclarations = new ArrayList(); - $statements_and_directives::sparseSwitchDeclarations = new ArrayList(); $statements_and_directives::methodAnnotations = new ArrayList(); } - ( instruction {$method::currentAddress += $instruction.size/2;} + ( ordered_method_item | registers_directive - | label | catch_directive | catchall_directive | parameter_directive - | ordered_debug_directive | annotation {$statements_and_directives::methodAnnotations.add($annotation.tree);} )* -> registers_directive? - ^(I_LABELS label*) - {buildTree(I_PACKED_SWITCH_DECLARATIONS, "I_PACKED_SWITCH_DECLARATIONS", $statements_and_directives::packedSwitchDeclarations)} - {buildTree(I_SPARSE_SWITCH_DECLARATIONS, "I_SPARSE_SWITCH_DECLARATIONS", $statements_and_directives::sparseSwitchDeclarations)} - ^(I_STATEMENTS instruction*) + ^(I_ORDERED_METHOD_ITEMS ordered_method_item*) ^(I_CATCHES catch_directive* catchall_directive*) ^(I_PARAMETERS parameter_directive*) - ^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*) {buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $statements_and_directives::methodAnnotations)}; +/* Method items whose order/location is important */ +ordered_method_item + : label + | instruction + | debug_directive; + registers_directive : ( directive=REGISTERS_DIRECTIVE regCount=integral_literal -> ^(I_REGISTERS[$REGISTERS_DIRECTIVE, "I_REGISTERS"] $regCount) @@ -605,9 +590,9 @@ simple_name | INSTRUCTION_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD] | INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l]; -method_name +member_name : simple_name - | METHOD_NAME -> SIMPLE_NAME[$METHOD_NAME]; + | MEMBER_NAME -> SIMPLE_NAME[$MEMBER_NAME]; method_prototype : OPEN_PAREN param_list CLOSE_PAREN type_descriptor @@ -680,15 +665,15 @@ fixed_32bit_literal | CHAR_LITERAL | BOOL_LITERAL; -fixed_literal returns[int size] - : integer_literal {$size = 4;} - | LONG_LITERAL {$size = 8;} - | SHORT_LITERAL {$size = 2;} - | BYTE_LITERAL {$size = 1;} - | float_literal {$size = 4;} - | double_literal {$size = 8;} - | CHAR_LITERAL {$size = 2;} - | BOOL_LITERAL {$size = 1;}; +fixed_literal + : integer_literal + | LONG_LITERAL + | SHORT_LITERAL + | BYTE_LITERAL + | float_literal + | double_literal + | CHAR_LITERAL + | BOOL_LITERAL; array_literal : OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE @@ -714,8 +699,8 @@ enum_literal type_field_method_literal : reference_type_descriptor ( ARROW - ( simple_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor simple_name nonvoid_type_descriptor) - | method_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor method_name method_prototype) + ( member_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor member_name nonvoid_type_descriptor) + | member_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor member_name method_prototype) ) | -> reference_type_descriptor ) @@ -723,20 +708,18 @@ type_field_method_literal | VOID_TYPE; fully_qualified_method - : reference_type_descriptor ARROW method_name method_prototype - -> reference_type_descriptor method_name method_prototype; + : reference_type_descriptor ARROW member_name method_prototype + -> reference_type_descriptor member_name method_prototype; fully_qualified_field - : reference_type_descriptor ARROW simple_name COLON nonvoid_type_descriptor - -> reference_type_descriptor simple_name nonvoid_type_descriptor; + : reference_type_descriptor ARROW member_name COLON nonvoid_type_descriptor + -> reference_type_descriptor member_name nonvoid_type_descriptor; label - : COLON simple_name -> ^(I_LABEL[$COLON, "I_LABEL"] simple_name I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + : COLON simple_name -> ^(I_LABEL[$COLON, "I_LABEL"] simple_name); -label_ref_or_offset - : COLON simple_name -> simple_name - | OFFSET - | NEGATIVE_INTEGER_LITERAL -> OFFSET[$NEGATIVE_INTEGER_LITERAL]; +label_ref + : COLON simple_name -> simple_name; register_list : REGISTER (COMMA REGISTER)* -> ^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"] REGISTER*) @@ -749,12 +732,12 @@ verification_error_reference : CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method; catch_directive - : CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset - -> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using); + : CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref + -> ^(I_CATCH[$start, "I_CATCH"] nonvoid_type_descriptor $from $to $using); catchall_directive - : CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset - -> ^(I_CATCHALL[$start, "I_CATCHALL"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] $from $to $using); + : CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref + -> ^(I_CATCHALL[$start, "I_CATCHALL"] $from $to $using); /*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse @@ -771,7 +754,7 @@ parameter_directive -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER STRING_LITERAL? ^(I_ANNOTATIONS)) ); -ordered_debug_directive +debug_directive : line_directive | local_directive | end_local_directive @@ -782,33 +765,32 @@ ordered_debug_directive line_directive : LINE_DIRECTIVE integral_literal - -> ^(I_LINE[$start, "I_LINE"] integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + -> ^(I_LINE[$start, "I_LINE"] integral_literal); local_directive : LOCAL_DIRECTIVE REGISTER (COMMA (NULL_LITERAL | name=STRING_LITERAL) COLON (VOID_TYPE | nonvoid_type_descriptor) (COMMA signature=STRING_LITERAL)? )? - -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER NULL_LITERAL? $name? nonvoid_type_descriptor? $signature? - I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER NULL_LITERAL? $name? nonvoid_type_descriptor? $signature?); end_local_directive : END_LOCAL_DIRECTIVE REGISTER - -> ^(I_END_LOCAL[$start, "I_END_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + -> ^(I_END_LOCAL[$start, "I_END_LOCAL"] REGISTER); restart_local_directive : RESTART_LOCAL_DIRECTIVE REGISTER - -> ^(I_RESTART_LOCAL[$start, "I_RESTART_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + -> ^(I_RESTART_LOCAL[$start, "I_RESTART_LOCAL"] REGISTER); prologue_directive : PROLOGUE_DIRECTIVE - -> ^(I_PROLOGUE[$start, "I_PROLOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + -> ^(I_PROLOGUE[$start, "I_PROLOGUE"]); epilogue_directive : EPILOGUE_DIRECTIVE - -> ^(I_EPILOGUE[$start, "I_EPILOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + -> ^(I_EPILOGUE[$start, "I_EPILOGUE"]); source_directive : SOURCE_DIRECTIVE STRING_LITERAL? - -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]); + -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL?); instruction_format12x : INSTRUCTION_FORMAT12x @@ -824,88 +806,88 @@ instruction_format31i -instruction returns [int size] - : insn_format10t { $size = $insn_format10t.size; } - | insn_format10x { $size = $insn_format10x.size; } - | insn_format10x_odex { $size = $insn_format10x_odex.size; } - | insn_format11n { $size = $insn_format11n.size; } - | insn_format11x { $size = $insn_format11x.size; } - | insn_format12x { $size = $insn_format12x.size; } - | insn_format20bc { $size = $insn_format20bc.size; } - | insn_format20t { $size = $insn_format20t.size; } - | insn_format21c_field { $size = $insn_format21c_field.size; } - | insn_format21c_field_odex { $size = $insn_format21c_field_odex.size; } - | insn_format21c_string { $size = $insn_format21c_string.size; } - | insn_format21c_type { $size = $insn_format21c_type.size; } - | insn_format21ih { $size = $insn_format21ih.size; } - | insn_format21lh { $size = $insn_format21lh.size; } - | insn_format21s { $size = $insn_format21s.size; } - | insn_format21t { $size = $insn_format21t.size; } - | insn_format22b { $size = $insn_format22b.size; } - | insn_format22c_field { $size = $insn_format22c_field.size; } - | insn_format22c_field_odex { $size = $insn_format22c_field_odex.size; } - | insn_format22c_type { $size = $insn_format22c_type.size; } - | insn_format22cs_field { $size = $insn_format22cs_field.size; } - | insn_format22s { $size = $insn_format22s.size; } - | insn_format22t { $size = $insn_format22t.size; } - | insn_format22x { $size = $insn_format22x.size; } - | insn_format23x { $size = $insn_format23x.size; } - | insn_format30t { $size = $insn_format30t.size; } - | insn_format31c { $size = $insn_format31c.size; } - | insn_format31i { $size = $insn_format31i.size; } - | insn_format31t { $size = $insn_format31t.size; } - | insn_format32x { $size = $insn_format32x.size; } - | insn_format35c_method { $size = $insn_format35c_method.size; } - | insn_format35c_type { $size = $insn_format35c_type.size; } - | insn_format35c_method_odex { $size = $insn_format35c_method_odex.size; } - | insn_format35mi_method { $size = $insn_format35mi_method.size; } - | insn_format35ms_method { $size = $insn_format35ms_method.size; } - | insn_format3rc_method { $size = $insn_format3rc_method.size; } - | insn_format3rc_method_odex { $size = $insn_format3rc_method_odex.size; } - | insn_format3rc_type { $size = $insn_format3rc_type.size; } - | insn_format3rmi_method { $size = $insn_format3rmi_method.size; } - | insn_format3rms_method { $size = $insn_format3rms_method.size; } - | insn_format51l { $size = $insn_format51l.size; } - | insn_array_data_directive { $size = $insn_array_data_directive.size; } - | insn_packed_switch_directive { $size = $insn_packed_switch_directive.size; } - | insn_sparse_switch_directive { $size = $insn_sparse_switch_directive.size; }; +instruction + : insn_format10t + | insn_format10x + | insn_format10x_odex + | insn_format11n + | insn_format11x + | insn_format12x + | insn_format20bc + | insn_format20t + | insn_format21c_field + | insn_format21c_field_odex + | insn_format21c_string + | insn_format21c_type + | insn_format21ih + | insn_format21lh + | insn_format21s + | insn_format21t + | insn_format22b + | insn_format22c_field + | insn_format22c_field_odex + | insn_format22c_type + | insn_format22cs_field + | insn_format22s + | insn_format22t + | insn_format22x + | insn_format23x + | insn_format30t + | insn_format31c + | insn_format31i + | insn_format31t + | insn_format32x + | insn_format35c_method + | insn_format35c_type + | insn_format35c_method_odex + | insn_format35mi_method + | insn_format35ms_method + | insn_format3rc_method + | insn_format3rc_method_odex + | insn_format3rc_type + | insn_format3rmi_method + | insn_format3rms_method + | insn_format51l + | insn_array_data_directive + | insn_packed_switch_directive + | insn_sparse_switch_directive; -insn_format10t returns [int size] +insn_format10t : //e.g. goto endloop: //e.g. goto +3 - INSTRUCTION_FORMAT10t label_ref_or_offset {$size = Format.Format10t.size;} - -> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref_or_offset); + INSTRUCTION_FORMAT10t label_ref + -> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref); -insn_format10x returns [int size] +insn_format10x : //e.g. return-void - INSTRUCTION_FORMAT10x {$size = Format.Format10x.size;} + INSTRUCTION_FORMAT10x -> ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x); -insn_format10x_odex returns [int size] +insn_format10x_odex : //e.g. return-void-barrier - INSTRUCTION_FORMAT10x_ODEX {$size = Format.Format10x.size;} + INSTRUCTION_FORMAT10x_ODEX { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT10x_ODEX.text); }; -insn_format11n returns [int size] +insn_format11n : //e.g. const/4 v0, 5 - INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal {$size = Format.Format11n.size;} + INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal -> ^(I_STATEMENT_FORMAT11n[$start, "I_STATEMENT_FORMAT11n"] INSTRUCTION_FORMAT11n REGISTER integral_literal); -insn_format11x returns [int size] +insn_format11x : //e.g. move-result-object v1 - INSTRUCTION_FORMAT11x REGISTER {$size = Format.Format11x.size;} + INSTRUCTION_FORMAT11x REGISTER -> ^(I_STATEMENT_FORMAT11x[$start, "I_STATEMENT_FORMAT11x"] INSTRUCTION_FORMAT11x REGISTER); -insn_format12x returns [int size] +insn_format12x : //e.g. move v1 v2 - instruction_format12x REGISTER COMMA REGISTER {$size = Format.Format12x.size;} + instruction_format12x REGISTER COMMA REGISTER -> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] instruction_format12x REGISTER REGISTER); -insn_format20bc returns [int size] +insn_format20bc : //e.g. throw-verification-error generic-error, Lsome/class; - INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference {$size += Format.Format20bc.size;} + INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference { if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT20bc.text) == null || apiLevel >= 14) { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text); @@ -913,19 +895,19 @@ insn_format20bc returns [int size] } -> ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE verification_error_reference); -insn_format20t returns [int size] +insn_format20t : //e.g. goto/16 endloop: - INSTRUCTION_FORMAT20t label_ref_or_offset {$size = Format.Format20t.size;} - -> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref_or_offset); + INSTRUCTION_FORMAT20t label_ref + -> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref); -insn_format21c_field returns [int size] +insn_format21c_field : //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream; - INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;} + INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field -> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field); -insn_format21c_field_odex returns [int size] +insn_format21c_field_odex : //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream; - INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;} + INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA fully_qualified_field { if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_FIELD_ODEX.text) == null || apiLevel >= 14) { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT21c_FIELD_ODEX.text); @@ -933,49 +915,49 @@ insn_format21c_field_odex returns [int size] } -> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER fully_qualified_field); -insn_format21c_string returns [int size] +insn_format21c_string : //e.g. const-string v1, "Hello World!" - INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL {$size = Format.Format21c.size;} + INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL -> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL); -insn_format21c_type returns [int size] +insn_format21c_type : //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2; - INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor {$size = Format.Format21c.size;} + INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor); -insn_format21ih returns [int size] +insn_format21ih : //e.g. const/high16 v1, 1234 - INSTRUCTION_FORMAT21ih REGISTER COMMA fixed_32bit_literal {$size = Format.Format21ih.size;} + INSTRUCTION_FORMAT21ih REGISTER COMMA fixed_32bit_literal -> ^(I_STATEMENT_FORMAT21ih[$start, "I_STATEMENT_FORMAT21ih"] INSTRUCTION_FORMAT21ih REGISTER fixed_32bit_literal); -insn_format21lh returns [int size] +insn_format21lh : //e.g. const-wide/high16 v1, 1234 - INSTRUCTION_FORMAT21lh REGISTER COMMA fixed_32bit_literal {$size = Format.Format21lh.size;} + INSTRUCTION_FORMAT21lh REGISTER COMMA fixed_32bit_literal -> ^(I_STATEMENT_FORMAT21lh[$start, "I_STATEMENT_FORMAT21lh"] INSTRUCTION_FORMAT21lh REGISTER fixed_32bit_literal); -insn_format21s returns [int size] +insn_format21s : //e.g. const/16 v1, 1234 - INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal {$size = Format.Format21s.size;} + INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal -> ^(I_STATEMENT_FORMAT21s[$start, "I_STATEMENT_FORMAT21s"] INSTRUCTION_FORMAT21s REGISTER integral_literal); -insn_format21t returns [int size] +insn_format21t : //e.g. if-eqz v0, endloop: - INSTRUCTION_FORMAT21t REGISTER COMMA (label_ref_or_offset) {$size = Format.Format21t.size;} - -> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER label_ref_or_offset); + INSTRUCTION_FORMAT21t REGISTER COMMA label_ref + -> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER label_ref); -insn_format22b returns [int size] +insn_format22b : //e.g. add-int v0, v1, 123 - INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22b.size;} + INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal -> ^(I_STATEMENT_FORMAT22b[$start, "I_STATEMENT_FORMAT22b"] INSTRUCTION_FORMAT22b REGISTER REGISTER integral_literal); -insn_format22c_field returns [int size] +insn_format22c_field : //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; - INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format22c.size;} + INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field); -insn_format22c_field_odex returns [int size] +insn_format22c_field_odex : //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; - INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format22c.size;} + INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field { if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_FIELD_ODEX.text) == null || apiLevel >= 14) { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22c_FIELD_ODEX.text); @@ -983,146 +965,131 @@ insn_format22c_field_odex returns [int size] } -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER REGISTER fully_qualified_field); -insn_format22c_type returns [int size] +insn_format22c_type : //e.g. instance-of v0, v1, Ljava/lang/String; - INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor {$size = Format.Format22c.size;} + INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor -> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor); -insn_format22cs_field returns [int size] +insn_format22cs_field : //e.g. iget-quick v0, v1, field@0xc INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22cs_FIELD.text); }; -insn_format22s returns [int size] +insn_format22s : //e.g. add-int/lit16 v0, v1, 12345 - instruction_format22s REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22s.size;} + instruction_format22s REGISTER COMMA REGISTER COMMA integral_literal -> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] instruction_format22s REGISTER REGISTER integral_literal); -insn_format22t returns [int size] +insn_format22t : //e.g. if-eq v0, v1, endloop: - INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref_or_offset {$size = Format.Format22t.size;} - -> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER label_ref_or_offset); + INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref + -> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER label_ref); -insn_format22x returns [int size] +insn_format22x : //e.g. move/from16 v1, v1234 - INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER {$size = Format.Format22x.size;} + INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER -> ^(I_STATEMENT_FORMAT22x[$start, "I_STATEMENT_FORMAT22x"] INSTRUCTION_FORMAT22x REGISTER REGISTER); -insn_format23x returns [int size] +insn_format23x : //e.g. add-int v1, v2, v3 - INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER {$size = Format.Format23x.size;} + INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER -> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER); -insn_format30t returns [int size] +insn_format30t : //e.g. goto/32 endloop: - INSTRUCTION_FORMAT30t label_ref_or_offset {$size = Format.Format30t.size;} - -> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t label_ref_or_offset); + INSTRUCTION_FORMAT30t label_ref + -> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t label_ref); -insn_format31c returns [int size] +insn_format31c : //e.g. const-string/jumbo v1 "Hello World!" - INSTRUCTION_FORMAT31c REGISTER COMMA STRING_LITERAL {$size = Format.Format31c.size;} + INSTRUCTION_FORMAT31c REGISTER COMMA STRING_LITERAL ->^(I_STATEMENT_FORMAT31c[$start, "I_STATEMENT_FORMAT31c"] INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL); -insn_format31i returns [int size] +insn_format31i : //e.g. const v0, 123456 - instruction_format31i REGISTER COMMA fixed_32bit_literal {$size = Format.Format31i.size;} + instruction_format31i REGISTER COMMA fixed_32bit_literal -> ^(I_STATEMENT_FORMAT31i[$start, "I_STATEMENT_FORMAT31i"] instruction_format31i REGISTER fixed_32bit_literal); -insn_format31t returns [int size] +insn_format31t : //e.g. fill-array-data v0, ArrayData: - INSTRUCTION_FORMAT31t REGISTER COMMA label_ref_or_offset {$size = Format.Format31t.size;} - { - if ($INSTRUCTION_FORMAT31t.text.equals("packed-switch")) { - CommonTree root = new CommonTree(new CommonToken(I_PACKED_SWITCH_DECLARATION, "I_PACKED_SWITCH_DECLARATION")); - CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress))); - root.addChild(address); - root.addChild($label_ref_or_offset.tree.dupNode()); - $statements_and_directives::packedSwitchDeclarations.add(root); - } else if ($INSTRUCTION_FORMAT31t.text.equals("sparse-switch")) { - CommonTree root = new CommonTree(new CommonToken(I_SPARSE_SWITCH_DECLARATION, "I_SPARSE_SWITCH_DECLARATION")); - CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress))); - root.addChild(address); - root.addChild($label_ref_or_offset.tree.dupNode()); - $statements_and_directives::sparseSwitchDeclarations.add(root); - } - } - -> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER label_ref_or_offset); + INSTRUCTION_FORMAT31t REGISTER COMMA label_ref + -> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER label_ref); -insn_format32x returns [int size] +insn_format32x : //e.g. move/16 v4567, v1234 - INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER {$size = Format.Format32x.size;} + INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER -> ^(I_STATEMENT_FORMAT32x[$start, "I_STATEMENT_FORMAT32x"] INSTRUCTION_FORMAT32x REGISTER REGISTER); -insn_format35c_method returns [int size] +insn_format35c_method : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V - INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format35c.size;} + INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method -> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list fully_qualified_method); -insn_format35c_type returns [int size] +insn_format35c_type : //e.g. filled-new-array {v0,v1}, I - INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format35c.size;} + INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor -> ^(I_STATEMENT_FORMAT35c_TYPE[$start, "I_STATEMENT_FORMAT35c_TYPE"] INSTRUCTION_FORMAT35c_TYPE register_list nonvoid_type_descriptor); -insn_format35c_method_odex returns [int size] +insn_format35c_method_odex : //e.g. invoke-direct {p0}, Ljava/lang/Object;->()V INSTRUCTION_FORMAT35c_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35c_METHOD_ODEX.text); }; -insn_format35mi_method returns [int size] +insn_format35mi_method : //e.g. execute-inline {v0, v1}, inline@0x4 INSTRUCTION_FORMAT35mi_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA INLINE_INDEX { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35mi_METHOD.text); }; -insn_format35ms_method returns [int size] +insn_format35ms_method : //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4 INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_INDEX { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35ms_METHOD.text); }; -insn_format3rc_method returns [int size] +insn_format3rc_method : //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; - INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format3rc.size;} + INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method -> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method); -insn_format3rc_method_odex returns [int size] +insn_format3rc_method_odex : //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;->()V INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rc_METHOD_ODEX.text); }; -insn_format3rc_type returns [int size] +insn_format3rc_type : //e.g. filled-new-array/range {v0..v6}, I - INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format3rc.size;} + INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor -> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor); -insn_format3rmi_method returns [int size] +insn_format3rmi_method : //e.g. execute-inline/range {v0 .. v10}, inline@0x14 INSTRUCTION_FORMAT3rmi_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA INLINE_INDEX { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rmi_METHOD.text); }; -insn_format3rms_method returns [int size] +insn_format3rms_method : //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14 INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_INDEX { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text); }; -insn_format51l returns [int size] +insn_format51l : //e.g. const-wide v0, 5000000000L - INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal {$size = Format.Format51l.size;} + INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal -> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal); -insn_array_data_directive returns [int size] +insn_array_data_directive : ARRAY_DATA_DIRECTIVE parsed_integer_literal { @@ -1131,32 +1098,25 @@ insn_array_data_directive returns [int size] throw new SemanticException(input, $start, "Invalid element width: \%d. Must be 1, 2, 4 or 8", elementWidth); } } - - (fixed_literal {$size+=elementWidth;})* END_ARRAY_DATA_DIRECTIVE - {$size = (($size + 1) & ~1) + 8;} + fixed_literal* END_ARRAY_DATA_DIRECTIVE -> ^(I_STATEMENT_ARRAY_DATA[$start, "I_STATEMENT_ARRAY_DATA"] ^(I_ARRAY_ELEMENT_SIZE parsed_integer_literal) ^(I_ARRAY_ELEMENTS fixed_literal*)); -insn_packed_switch_directive returns [int size] +insn_packed_switch_directive : PACKED_SWITCH_DIRECTIVE fixed_32bit_literal - - (switch_target += label_ref_or_offset {$size+=4;})* - - END_PACKED_SWITCH_DIRECTIVE {$size = $size + 8;} - + label_ref* + END_PACKED_SWITCH_DIRECTIVE -> ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"] ^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal) ^(I_PACKED_SWITCH_ELEMENTS[$start, "I_PACKED_SWITCH_ELEMENTS"] - $switch_target*) + label_ref*) ); -insn_sparse_switch_directive returns [int size] +insn_sparse_switch_directive : SPARSE_SWITCH_DIRECTIVE - (fixed_32bit_literal ARROW switch_target += label_ref_or_offset {$size += 8;})* - - END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;} - + (fixed_32bit_literal ARROW label_ref)* + END_SPARSE_SWITCH_DIRECTIVE -> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"] - ^(I_SPARSE_SWITCH_ELEMENTS[$start, "I_SPARSE_SWITCH_ELEMENTS"] (fixed_32bit_literal $switch_target)*)); \ No newline at end of file + ^(I_SPARSE_SWITCH_ELEMENTS[$start, "I_SPARSE_SWITCH_ELEMENTS"] (fixed_32bit_literal label_ref)*)); \ No newline at end of file diff --git a/brut.apktool.smali/smali/src/main/antlr3/smaliTreeWalker.g b/brut.apktool.smali/smali/src/main/antlr3/smaliTreeWalker.g index cc68073e..035c8724 100644 --- a/brut.apktool.smali/smali/src/main/antlr3/smaliTreeWalker.g +++ b/brut.apktool.smali/smali/src/main/antlr3/smaliTreeWalker.g @@ -36,33 +36,41 @@ options { @header { package org.jf.smali; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Set; -import java.util.regex.*; - -import com.google.common.collect.Lists; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.antlr.runtime.BitSet; +import org.antlr.runtime.*; +import org.antlr.runtime.tree.CommonTree; +import org.antlr.runtime.tree.TreeNodeStream; +import org.antlr.runtime.tree.TreeParser; +import org.antlr.runtime.tree.TreeRuleReturnScope; import org.jf.dexlib2.*; -import org.jf.dexlib2.dexbacked.raw.*; -import org.jf.dexlib2.iface.*; -import org.jf.dexlib2.iface.debug.DebugItem; -import org.jf.dexlib2.iface.instruction.Instruction; -import org.jf.dexlib2.iface.instruction.SwitchElement; -import org.jf.dexlib2.iface.instruction.formats.*; -import org.jf.dexlib2.iface.reference.*; +import org.jf.dexlib2.builder.Label; +import org.jf.dexlib2.builder.MethodImplementationBuilder; +import org.jf.dexlib2.builder.SwitchLabelElement; +import org.jf.dexlib2.builder.instruction.*; +import org.jf.dexlib2.iface.Annotation; +import org.jf.dexlib2.iface.AnnotationElement; +import org.jf.dexlib2.iface.ClassDef; +import org.jf.dexlib2.iface.MethodImplementation; +import org.jf.dexlib2.iface.reference.FieldReference; +import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.value.EncodedValue; -import org.jf.dexlib2.immutable.*; -import org.jf.dexlib2.immutable.debug.*; -import org.jf.dexlib2.immutable.instruction.*; -import org.jf.dexlib2.immutable.reference.*; +import org.jf.dexlib2.immutable.ImmutableAnnotation; +import org.jf.dexlib2.immutable.ImmutableAnnotationElement; +import org.jf.dexlib2.immutable.reference.ImmutableFieldReference; +import org.jf.dexlib2.immutable.reference.ImmutableMethodReference; +import org.jf.dexlib2.immutable.reference.ImmutableReference; +import org.jf.dexlib2.immutable.reference.ImmutableTypeReference; import org.jf.dexlib2.immutable.value.*; +import org.jf.dexlib2.util.MethodUtil; import org.jf.dexlib2.writer.InstructionFactory; import org.jf.dexlib2.writer.builder.*; -import org.jf.dexlib2.util.MethodUtil; import org.jf.util.LinearSearch; + +import java.util.*; } @members { @@ -71,7 +79,7 @@ import org.jf.util.LinearSearch; private int apiLevel = 15; private Opcodes opcodes = new Opcodes(apiLevel); private DexBuilder dexBuilder; - private InstructionFactory instructionFactory = + private InstructionFactory instructionFactory = BuilderInstructionFactory.INSTANCE; public void setDexBuilder(DexBuilder dexBuilder) { @@ -320,50 +328,36 @@ array_elements returns[List elements] $elements.add($fixed_64bit_literal_number.value); })*); -packed_switch_elements[int baseAddress, int firstKey] returns[List elements] +packed_switch_elements returns[List