From b65e942e7e53fab70e177681989eb8eaeb4c89de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojtek=20Kalici=C5=84ski?= Date: Mon, 3 Apr 2017 13:37:51 +0100 Subject: Add support for getting byte sizes to dex backed references --- NOTICE | 4 +- .../org/jf/dexlib2/dexbacked/BaseDexReader.java | 104 +++++++++++++++++++++ .../jf/dexlib2/dexbacked/DexBackedClassDef.java | 63 +++++++++++++ .../org/jf/dexlib2/dexbacked/DexBackedField.java | 42 +++++++++ .../org/jf/dexlib2/dexbacked/DexBackedMethod.java | 33 +++++++ .../dexbacked/DexBackedMethodImplementation.java | 28 ++++++ .../reference/DexBackedFieldReference.java | 11 +++ .../reference/DexBackedMethodProtoReference.java | 16 ++++ .../reference/DexBackedMethodReference.java | 15 +++ .../reference/DexBackedStringReference.java | 23 +++++ .../reference/DexBackedTypeReference.java | 13 +++ .../org/jf/dexlib2/dexbacked/util/DebugInfo.java | 21 +++++ .../dexbacked/util/StaticInitialValueIterator.java | 6 ++ .../util/VariableSizeLookaheadIterator.java | 4 + .../dexlib2/dexbacked/BaseDexReaderLeb128Test.java | 10 ++ .../dexbacked/BaseDexReaderSleb128Test.java | 9 ++ 16 files changed, 400 insertions(+), 2 deletions(-) diff --git a/NOTICE b/NOTICE index e29e98b8..7c80c51c 100644 --- a/NOTICE +++ b/NOTICE @@ -30,8 +30,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Unless otherwise stated in the code/commit message, any changes with the -committer of bgruv@google.com is copyrighted by Google Inc. and released -under the following license: +committer of bgruv@google.com or wkal@google.com is copyrighted by +Google Inc. and released under the following license: ******************************************************************************* Copyright 2011, Google Inc. diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java index 13c0a7b0..e6880de2 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java @@ -88,10 +88,41 @@ public class BaseDexReader { return result; } + public int peekSleb128Size() { + int end = dexBuf.baseOffset + offset; + int currentByteValue; + int result; + byte[] buf = dexBuf.buf; + + result = buf[end++] & 0xff; + if (result > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + throw new ExceptionWithContext( + "Invalid sleb128 integer encountered at offset 0x%x", offset); + } + } + } + } + } + + return end - (dexBuf.baseOffset + offset); + } + public int readSmallUleb128() { return readUleb128(false); } + public int peekSmallUleb128Size() { + return peekUleb128Size(false); + } + private int readUleb128(boolean allowLarge) { int end = dexBuf.baseOffset + offset; int currentByteValue; @@ -133,6 +164,43 @@ public class BaseDexReader { return result; } + private int peekUleb128Size(boolean allowLarge) { + int end = dexBuf.baseOffset + offset; + int currentByteValue; + int result; + byte[] buf = dexBuf.buf; + + result = buf[end++] & 0xff; + if (result > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++]; + + // MSB shouldn't be set on last byte + if (currentByteValue < 0) { + throw new ExceptionWithContext( + "Invalid uleb128 integer encountered at offset 0x%x", offset); + } else if ((currentByteValue & 0xf) > 0x07) { + 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); + } + } + } + } + } + } + + return end - (dexBuf.baseOffset + offset); + } + + /** * Reads a "large" uleb128. That is, one that may legitimately be greater than a signed int. * @@ -183,6 +251,35 @@ public class BaseDexReader { return result; } + public int peekBigUleb128Size() { + int end = dexBuf.baseOffset + offset; + int currentByteValue; + int result; + byte[] buf = dexBuf.buf; + + result = buf[end++] & 0xff; + if (result > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++] & 0xff; + if (currentByteValue > 0x7f) { + currentByteValue = buf[end++]; + + // MSB shouldn't be set on last byte + if (currentByteValue < 0) { + throw new ExceptionWithContext( + "Invalid uleb128 integer encountered at offset 0x%x", offset); + } + } + } + } + } + + return end - (dexBuf.baseOffset + offset); + } + public void skipUleb128() { int end = dexBuf.baseOffset + offset; byte currentByteValue; @@ -516,4 +613,11 @@ public class BaseDexReader { offset += ret[0]; return value; } + + public int peekStringLength(int utf16Length) { + int[] ret = new int[1]; + Utf8Utils.utf8BytesWithUtf16LengthToString( + dexBuf.buf, dexBuf.baseOffset + offset, utf16Length, ret); + return ret[0]; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java index 88f1dce9..9159fc6b 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java @@ -36,6 +36,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import org.jf.dexlib2.base.reference.BaseTypeReference; import org.jf.dexlib2.dexbacked.raw.ClassDefItem; +import org.jf.dexlib2.dexbacked.raw.TypeIdItem; import org.jf.dexlib2.dexbacked.util.AnnotationsDirectory; import org.jf.dexlib2.dexbacked.util.FixedSizeSet; import org.jf.dexlib2.dexbacked.util.StaticInitialValueIterator; @@ -434,4 +435,66 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { virtualMethodsOffset = reader.getOffset(); return virtualMethodsOffset; } + + /** + * Calculate and return the private size of a class definition. + * + * Calculated as: class_def_item size + type_id size + interfaces type_list + + * annotations_directory_item overhead + class_data_item + static values overhead + + * methods size + fields size + * + * @return size in bytes + */ + public int getSize() { + int size = 8 * 4; //class_def_item has 8 uint fields in dex files + size += TypeIdItem.ITEM_SIZE; //type_ids size + + //add interface list size if any + int interfacesLength = getInterfaces().size(); + if (interfacesLength > 0) { + //add size of the type_list + size += 4; //uint for size + size += interfacesLength * 2; //ushort per type_item + } + + //annotations directory size if it exists + AnnotationsDirectory directory = getAnnotationsDirectory(); + if (!AnnotationsDirectory.EMPTY.equals(directory)) { + size += 4 * 4; //4 uints in annotations_directory_item + Set classAnnotations = directory.getClassAnnotations(); + if (!classAnnotations.isEmpty()) { + size += 4; //uint for size + size += classAnnotations.size() * 4; //uint per annotation_off + //TODO: should we add annotation_item size? what if it's shared? + } + } + + //static values and/or metadata + int staticInitialValuesOffset = + dexFile.readSmallUint(classDefOffset + ClassDefItem.STATIC_VALUES_OFFSET); + if (staticInitialValuesOffset != 0) { + DexReader reader = dexFile.readerAt(staticInitialValuesOffset); + size += reader.peekSmallUleb128Size(); //encoded_array size field + } + + //class_data_item + int classDataOffset = dexFile.readSmallUint(classDefOffset + ClassDefItem.CLASS_DATA_OFFSET); + if (classDataOffset > 0) { + DexReader reader = dexFile.readerAt(classDataOffset); + reader.readSmallUleb128(); //staticFieldCount + reader.readSmallUleb128(); //instanceFieldCount + reader.readSmallUleb128(); //directMethodCount + reader.readSmallUleb128(); //virtualMethodCount + size += reader.getOffset() - classDataOffset; + } + + for (DexBackedField dexBackedField : getFields()) { + size += dexBackedField.getSize(); + } + + for (DexBackedMethod dexBackedMethod : getMethods()) { + size += dexBackedMethod.getSize(); + } + return size; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java index 5eff67a1..653cdbd3 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java @@ -33,8 +33,10 @@ package org.jf.dexlib2.dexbacked; import org.jf.dexlib2.base.reference.BaseFieldReference; import org.jf.dexlib2.dexbacked.raw.FieldIdItem; +import org.jf.dexlib2.dexbacked.reference.DexBackedFieldReference; import org.jf.dexlib2.dexbacked.util.AnnotationsDirectory; import org.jf.dexlib2.dexbacked.util.StaticInitialValueIterator; +import org.jf.dexlib2.dexbacked.value.DexBackedEncodedValue; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.Field; import org.jf.dexlib2.iface.value.EncodedValue; @@ -52,6 +54,8 @@ public class DexBackedField extends BaseFieldReference implements Field { public final int annotationSetOffset; public final int fieldIndex; + private final int startOffset; + private final int initialValueOffset; private int fieldIdItemOffset; @@ -65,11 +69,13 @@ public class DexBackedField extends BaseFieldReference implements Field { // large values may be used for the index delta, which cause the cumulative index to overflow upon // addition, effectively allowing out of order entries. + startOffset = reader.getOffset(); int fieldIndexDiff = reader.readLargeUleb128(); this.fieldIndex = fieldIndexDiff + previousFieldIndex; this.accessFlags = reader.readSmallUleb128(); this.annotationSetOffset = annotationIterator.seekTo(fieldIndex); + initialValueOffset = staticInitialValueIterator.getReaderOffset(); this.initialValue = staticInitialValueIterator.getNextOrNull(); } @@ -82,11 +88,13 @@ public class DexBackedField extends BaseFieldReference implements Field { // large values may be used for the index delta, which cause the cumulative index to overflow upon // addition, effectively allowing out of order entries. + startOffset = reader.getOffset(); int fieldIndexDiff = reader.readLargeUleb128(); this.fieldIndex = fieldIndexDiff + previousFieldIndex; this.accessFlags = reader.readSmallUleb128(); this.annotationSetOffset = annotationIterator.seekTo(fieldIndex); + initialValueOffset = 0; this.initialValue = null; } @@ -131,4 +139,38 @@ public class DexBackedField extends BaseFieldReference implements Field { } return fieldIdItemOffset; } + + /** + * Calculate and return the private size of a field definition. + * + * Calculated as: field_idx_diff + access_flags + annotations overhead + + * initial value size + field reference size + * + * @return size in bytes + */ + public int getSize() { + int size = 0; + DexReader reader = dexFile.readerAt(startOffset); + reader.readLargeUleb128(); //field_idx_diff + reader.readSmallUleb128(); //access_flags + size += reader.getOffset() - startOffset; + + Set annotations = getAnnotations(); + if (!annotations.isEmpty()) { + size += 2 * 4; //2 * uint overhead from field_annotation + } + + if (initialValueOffset > 0) { + reader.setOffset(initialValueOffset); + if (initialValue != null) { + DexBackedEncodedValue.skipFrom(reader); + size += reader.getOffset() - initialValueOffset; + } + } + + DexBackedFieldReference fieldRef = new DexBackedFieldReference(dexFile, fieldIndex); + size += fieldRef.getSize(); + + return size; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java index eccb9218..821d2232 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java @@ -37,11 +37,13 @@ import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.dexbacked.raw.MethodIdItem; import org.jf.dexlib2.dexbacked.raw.ProtoIdItem; import org.jf.dexlib2.dexbacked.raw.TypeListItem; +import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference; import org.jf.dexlib2.dexbacked.util.AnnotationsDirectory; import org.jf.dexlib2.dexbacked.util.FixedSizeList; import org.jf.dexlib2.dexbacked.util.ParameterIterator; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Method; +import org.jf.dexlib2.iface.MethodImplementation; import org.jf.dexlib2.iface.MethodParameter; import org.jf.util.AbstractForwardSequentialList; @@ -62,6 +64,7 @@ public class DexBackedMethod extends BaseMethodReference implements Method { private final int methodAnnotationSetOffset; public final int methodIndex; + private final int startOffset; private int methodIdItemOffset; private int protoIdItemOffset; @@ -72,6 +75,7 @@ public class DexBackedMethod extends BaseMethodReference implements Method { int previousMethodIndex) { this.dexFile = reader.dexBuf; this.classDef = classDef; + startOffset = reader.getOffset(); // large values may be used for the index delta, which cause the cumulative index to overflow upon // addition, effectively allowing out of order entries. @@ -91,6 +95,7 @@ public class DexBackedMethod extends BaseMethodReference implements Method { @Nonnull AnnotationsDirectory.AnnotationIterator paramaterAnnotationIterator) { this.dexFile = reader.dexBuf; this.classDef = classDef; + startOffset = reader.getOffset(); // large values may be used for the index delta, which cause the cumulative index to overflow upon // addition, effectively allowing out of order entries. @@ -224,4 +229,32 @@ public class DexBackedMethod extends BaseMethodReference implements Method { reader.skipUleb128(); } } + + /** + * Calculate and return the private size of a method definition. + * + * Calculated as: method_idx_diff + access_flags + code_off + + * implementation size + reference size + * + * @return size in bytes + */ + public int getSize() { + int size = 0; + + DexReader reader = dexFile.readerAt(startOffset); + reader.readLargeUleb128(); //method_idx_diff + reader.readSmallUleb128(); //access_flags + reader.readSmallUleb128(); //code_off + size += reader.getOffset() - startOffset; + + DexBackedMethodImplementation impl = getImplementation(); + if (impl != null) { + size += impl.getSize(); + } + + DexBackedMethodReference methodRef = new DexBackedMethodReference(dexFile, methodIndex); + size += methodRef.getSize(); + + return size; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java index a82032a1..3d93d901 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java @@ -36,6 +36,7 @@ import org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction; import org.jf.dexlib2.dexbacked.raw.CodeItem; import org.jf.dexlib2.dexbacked.util.DebugInfo; import org.jf.dexlib2.dexbacked.util.FixedSizeList; +import org.jf.dexlib2.dexbacked.util.VariableSizeListIterator; import org.jf.dexlib2.dexbacked.util.VariableSizeLookaheadIterator; import org.jf.dexlib2.iface.MethodImplementation; import org.jf.dexlib2.iface.debug.DebugItem; @@ -148,4 +149,31 @@ public class DexBackedMethodImplementation implements MethodImplementation { public Iterator getParameterNames(@Nullable DexReader dexReader) { return getDebugInfo().getParameterNames(dexReader); } + + /** + * Calculate and return the private size of a method implementation. + * + * Calculated as: debug info size + instructions size + try-catch size + * + * @return size in bytes + */ + public int getSize() { + int debugSize = getDebugInfo().getSize(); + + //set code_item ending offset to the end of instructions list (insns_size * ushort) + int lastOffset = dexFile.readSmallUint(codeOffset + CodeItem.INSTRUCTION_COUNT_OFFSET) * 2; + + //read any exception handlers and move code_item offset to the end + for (DexBackedTryBlock tryBlock: getTryBlocks()) { + Iterator tryHandlerIter = + tryBlock.getExceptionHandlers().iterator(); + while (tryHandlerIter.hasNext()) { + tryHandlerIter.next(); + } + lastOffset = ((VariableSizeListIterator)tryHandlerIter).getReaderOffset(); + } + + //method impl size = debug block size + code_item size + return debugSize + (lastOffset - codeOffset); + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedFieldReference.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedFieldReference.java index c3655d54..a00c987a 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedFieldReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedFieldReference.java @@ -63,4 +63,15 @@ public class DexBackedFieldReference extends BaseFieldReference { public String getType() { return dexFile.getType(dexFile.readUshort(fieldIdItemOffset + FieldIdItem.TYPE_OFFSET)); } + + /** + * Calculate and return the private size of a field reference. + * + * Calculated as: class_idx + type_idx + name_idx + * + * @return size in bytes + */ + public int getSize() { + return FieldIdItem.ITEM_SIZE; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java index 12875b7b..9d9c6b18 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java @@ -74,4 +74,20 @@ public class DexBackedMethodProtoReference extends BaseMethodProtoReference { public String getReturnType() { return dexFile.getType(dexFile.readSmallUint(protoIdItemOffset + ProtoIdItem.RETURN_TYPE_OFFSET)); } + + /** + * Calculate and return the private size of a method proto. + * + * Calculated as: shorty_idx + return_type_idx + parameters_off + type_list size + * + * @return size in bytes + */ + public int getSize() { + int size = ProtoIdItem.ITEM_SIZE; //3 * uint + List parameters = getParameterTypes(); + if (!parameters.isEmpty()) { + size += 4 + parameters.size() * 2; //uint + size * ushort for type_idxs + } + return size; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodReference.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodReference.java index 6a85e8b9..f2b0b597 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodReference.java @@ -98,4 +98,19 @@ public class DexBackedMethodReference extends BaseMethodReference { } return protoIdItemOffset; } + + /** + * Calculate and return the private size of a method reference. + * + * Calculated as: class_idx + proto_idx + name_idx + prototype size + * + * @return size in bytes + */ + public int getSize() { + int size = MethodIdItem.ITEM_SIZE; //ushort + ushort + uint for indices + DexBackedMethodProtoReference protoRef = new DexBackedMethodProtoReference(dexFile, + dexFile.readUshort(methodIdItemOffset + MethodIdItem.PROTO_OFFSET)); + size += protoRef.getSize(); + return size; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedStringReference.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedStringReference.java index 61d0c818..4eb0097d 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedStringReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedStringReference.java @@ -33,6 +33,8 @@ package org.jf.dexlib2.dexbacked.reference; import org.jf.dexlib2.base.reference.BaseStringReference; import org.jf.dexlib2.dexbacked.DexBackedDexFile; +import org.jf.dexlib2.dexbacked.DexReader; +import org.jf.dexlib2.dexbacked.raw.StringIdItem; import javax.annotation.Nonnull; @@ -50,4 +52,25 @@ public class DexBackedStringReference extends BaseStringReference { public String getString() { return dexFile.getString(stringIndex); } + + + /** + * Calculate and return the private size of a string reference. + * + * Calculated as: string_data_off + string_data_item size + * + * @return size in bytes + */ + public int getSize() { + int size = StringIdItem.ITEM_SIZE; //uint for string_data_off + //add the string data length: + int stringOffset = dexFile.getStringIdItemOffset(stringIndex); + int stringDataOffset = dexFile.readSmallUint(stringOffset); + DexReader reader = dexFile.readerAt(stringDataOffset); + size += reader.peekSmallUleb128Size(); + int utf16Length = reader.readSmallUleb128(); + //and string data itself: + size += reader.peekStringLength(utf16Length); + return size; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedTypeReference.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedTypeReference.java index 2fcff0a2..5dc52410 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedTypeReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedTypeReference.java @@ -33,6 +33,7 @@ package org.jf.dexlib2.dexbacked.reference; import org.jf.dexlib2.base.reference.BaseTypeReference; import org.jf.dexlib2.dexbacked.DexBackedDexFile; +import org.jf.dexlib2.dexbacked.raw.TypeIdItem; import javax.annotation.Nonnull; @@ -49,4 +50,16 @@ public class DexBackedTypeReference extends BaseTypeReference { @Nonnull public String getType() { return dexFile.getType(typeIndex); } + + + /** + * Calculate and return the private size of a type reference. + * + * Calculated as: descriptor_idx + * + * @return size in bytes + */ + public int getSize() { + return TypeIdItem.ITEM_SIZE; //uint for descriptor_idx + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java index ef240718..d82e4d6f 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java @@ -59,6 +59,13 @@ public abstract class DebugInfo implements Iterable { */ @Nonnull public abstract Iterator getParameterNames(@Nullable DexReader reader); + /** + * Calculate and return the private size of debuginfo. + * + * @return size in bytes + */ + public abstract int getSize(); + public static DebugInfo newOrEmpty(@Nonnull DexBackedDexFile dexFile, int debugInfoOffset, @Nonnull DexBackedMethodImplementation methodImpl) { if (debugInfoOffset == 0) { @@ -78,6 +85,11 @@ public abstract class DebugInfo implements Iterable { @Nonnull @Override public Iterator getParameterNames(@Nullable DexReader reader) { return ImmutableSet.of().iterator(); } + + @Override + public int getSize() { + return 0; + } } private static class DebugInfoImpl extends DebugInfo { @@ -279,5 +291,14 @@ public abstract class DebugInfo implements Iterable { } }; } + + @Override + public int getSize() { + Iterator iter = iterator(); + while(iter.hasNext()) { + iter.next(); + } + return ((VariableSizeLookaheadIterator) iter).getReaderOffset() - debugInfoOffset; + } } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/StaticInitialValueIterator.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/StaticInitialValueIterator.java index 1c452ae3..f17b938a 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/StaticInitialValueIterator.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/StaticInitialValueIterator.java @@ -43,10 +43,12 @@ public abstract class StaticInitialValueIterator { public static final StaticInitialValueIterator EMPTY = new StaticInitialValueIterator() { @Nullable @Override public EncodedValue getNextOrNull() { return null; } @Override public void skipNext() {} + @Override public int getReaderOffset() { return 0; } }; @Nullable public abstract EncodedValue getNextOrNull(); public abstract void skipNext(); + public abstract int getReaderOffset(); @Nonnull public static StaticInitialValueIterator newOrEmpty(@Nonnull DexBackedDexFile dexFile, int offset) { @@ -81,5 +83,9 @@ public abstract class StaticInitialValueIterator { DexBackedEncodedValue.skipFrom(reader); } } + + public int getReaderOffset() { + return reader.getOffset(); + } } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/VariableSizeLookaheadIterator.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/VariableSizeLookaheadIterator.java index 1f4259ff..bc2f5056 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/VariableSizeLookaheadIterator.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/VariableSizeLookaheadIterator.java @@ -59,4 +59,8 @@ public abstract class VariableSizeLookaheadIterator extends AbstractIterator< protected T computeNext() { return readNextItem(reader); } + + public final int getReaderOffset() { + return reader.getOffset(); + } } diff --git a/dexlib2/src/test/java/org/jf/dexlib2/dexbacked/BaseDexReaderLeb128Test.java b/dexlib2/src/test/java/org/jf/dexlib2/dexbacked/BaseDexReaderLeb128Test.java index 79da5ecb..bcaaaeee 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/dexbacked/BaseDexReaderLeb128Test.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/dexbacked/BaseDexReaderLeb128Test.java @@ -254,11 +254,21 @@ public class BaseDexReaderLeb128Test { reader = dexBuf.readerAt(0); reader.skipUleb128(); Assert.assertEquals(expectedLength, reader.getOffset()); + + reader = dexBuf.readerAt(0); + Assert.assertEquals(expectedLength, reader.peekSmallUleb128Size()); } private void performFailureTest(byte[] buf) { BaseDexBuffer dexBuf = new BaseDexBuffer(buf); BaseDexReader reader = dexBuf.readerAt(0); + try { + reader.peekSmallUleb128Size(); + Assert.fail(); + } catch (ExceptionWithContext ex) { + // expected exception + } + try { reader.readSmallUleb128(); Assert.fail(); diff --git a/dexlib2/src/test/java/org/jf/dexlib2/dexbacked/BaseDexReaderSleb128Test.java b/dexlib2/src/test/java/org/jf/dexlib2/dexbacked/BaseDexReaderSleb128Test.java index cd1cc1a1..846ebb6f 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/dexbacked/BaseDexReaderSleb128Test.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/dexbacked/BaseDexReaderSleb128Test.java @@ -257,11 +257,20 @@ public class BaseDexReaderSleb128Test { BaseDexReader reader = dexBuf.readerAt(0); Assert.assertEquals(expectedValue, reader.readSleb128()); Assert.assertEquals(expectedLength, reader.getOffset()); + + reader = dexBuf.readerAt(0); + Assert.assertEquals(expectedLength, reader.peekSleb128Size()); } private void performFailureTest(byte[] buf) { BaseDexBuffer dexBuf = new BaseDexBuffer(buf); BaseDexReader reader = dexBuf.readerAt(0); + try { + reader.peekSleb128Size(); + Assert.fail(); + } catch (ExceptionWithContext ex) { + // expected exception + } try { reader.readSleb128(); Assert.fail(); -- cgit v1.2.3 From dd1192152912fc183c4584101b9e89cfe4286012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojtek=20Kalici=C5=84ski?= Date: Mon, 24 Apr 2017 17:12:58 +0100 Subject: Fix for counting method implementation sizes --- .../java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java index 3d93d901..cfe16aa6 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java @@ -160,8 +160,11 @@ public class DexBackedMethodImplementation implements MethodImplementation { public int getSize() { int debugSize = getDebugInfo().getSize(); + //set last offset just before bytecode instructions (after insns_size) + int lastOffset = codeOffset + CodeItem.INSTRUCTION_START_OFFSET; + //set code_item ending offset to the end of instructions list (insns_size * ushort) - int lastOffset = dexFile.readSmallUint(codeOffset + CodeItem.INSTRUCTION_COUNT_OFFSET) * 2; + lastOffset += dexFile.readSmallUint(codeOffset + CodeItem.INSTRUCTION_COUNT_OFFSET) * 2; //read any exception handlers and move code_item offset to the end for (DexBackedTryBlock tryBlock: getTryBlocks()) { -- cgit v1.2.3 From 58a4809720867b8f11d907ee83f1f20839499fc2 Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Wed, 3 May 2017 00:04:06 +0800 Subject: Update Gradle wrapper to 3.5 --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 52928 -> 54783 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradlew | 19 +++++++++++-------- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 9e8205d4..cbcbf72f 100644 --- a/build.gradle +++ b/build.gradle @@ -204,6 +204,6 @@ buildscript { } task wrapper(type: Wrapper) { - gradleVersion = '3.1' + gradleVersion = '3.5' distributionType = Wrapper.DistributionType.ALL } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 6ffa2378..241a7ad1 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8ee9c631..ea282cc8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Sep 28 23:22:26 AEST 2016 +#Wed May 03 00:04:05 SGT 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip diff --git a/gradlew b/gradlew index 9aa616c2..4453ccea 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -154,16 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then cd "$(dirname "$0")" fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" -- cgit v1.2.3 From dd22a795d86aa1461d85c452cae7b7b811c462e2 Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Mon, 15 May 2017 16:25:10 -0700 Subject: Add an option to baksmali to allow disassembling odex opcodes These instructions should never be present in a dex file, only in odex/oat files. However, it's sometimes useful to be able to disassemble an otherwise valid dex file that happens to contain odex instructions. --- baksmali/src/main/java/org/jf/baksmali/DisassembleCommand.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/baksmali/src/main/java/org/jf/baksmali/DisassembleCommand.java b/baksmali/src/main/java/org/jf/baksmali/DisassembleCommand.java index 2e3eb79e..eb670df4 100644 --- a/baksmali/src/main/java/org/jf/baksmali/DisassembleCommand.java +++ b/baksmali/src/main/java/org/jf/baksmali/DisassembleCommand.java @@ -132,6 +132,10 @@ public class DisassembleCommand extends DexInputCommand { "fields from the current class.") private boolean implicitReferences = false; + @Parameter(names = "--allow-odex-opcodes", + description = "Allows odex opcodes to be disassembled, even if the result won't be able to be reassembled.") + private boolean allowOdex = false; + @Parameter(names = "--classes", description = "A comma separated list of classes. Only disassemble these classes") @ExtendedParameter(argumentNames = "classes") @@ -282,6 +286,10 @@ public class DisassembleCommand extends DexInputCommand { dexFile.getClasses()); } + if (allowOdex) { + options.allowOdex = true; + } + return options; } } -- cgit v1.2.3 From d4702a45a78b5345dcd33b4b14e7791045658e0f Mon Sep 17 00:00:00 2001 From: Daniel Bali Date: Tue, 16 May 2017 14:00:52 -0700 Subject: Add basic support for ODEX instructions --- .../builder/MutableMethodImplementation.java | 68 ++++++++++++++++++ .../instruction/BuilderInstruction22cs.java | 65 ++++++++++++++++++ .../instruction/BuilderInstruction35mi.java | 80 ++++++++++++++++++++++ .../instruction/BuilderInstruction35ms.java | 79 +++++++++++++++++++++ .../instruction/BuilderInstruction3rmi.java | 65 ++++++++++++++++++ .../instruction/BuilderInstruction3rms.java | 66 ++++++++++++++++++ .../main/java/org/jf/dexlib2/writer/DexWriter.java | 15 ++++ .../org/jf/dexlib2/writer/InstructionWriter.java | 57 +++++++++++++++ 8 files changed, 495 insertions(+) create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction22cs.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35mi.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35ms.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction3rmi.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction3rms.java diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java index 148bafd1..a77ae253 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java @@ -601,6 +601,9 @@ public class MutableMethodImplementation implements MethodImplementation { case Format22c: setInstruction(location, newBuilderInstruction22c((Instruction22c) instruction)); return; + case Format22cs: + setInstruction(location, newBuilderInstruction22cs((Instruction22cs) instruction)); + return; case Format22s: setInstruction(location, newBuilderInstruction22s((Instruction22s) instruction)); return; @@ -636,9 +639,21 @@ public class MutableMethodImplementation implements MethodImplementation { case Format35c: setInstruction(location, newBuilderInstruction35c((Instruction35c) instruction)); return; + case Format35mi: + setInstruction(location, newBuilderInstruction35mi((Instruction35mi) instruction)); + return; + case Format35ms: + setInstruction(location, newBuilderInstruction35ms((Instruction35ms) instruction)); + return; case Format3rc: setInstruction(location, newBuilderInstruction3rc((Instruction3rc)instruction)); return; + case Format3rmi: + setInstruction(location, newBuilderInstruction3rmi((Instruction3rmi)instruction)); + return; + case Format3rms: + setInstruction(location, newBuilderInstruction3rms((Instruction3rms)instruction)); + return; case Format51l: setInstruction(location, newBuilderInstruction51l((Instruction51l)instruction)); return; @@ -770,6 +785,15 @@ public class MutableMethodImplementation implements MethodImplementation { instruction.getReference()); } + @Nonnull + private BuilderInstruction22cs newBuilderInstruction22cs(@Nonnull Instruction22cs instruction) { + return new BuilderInstruction22cs( + instruction.getOpcode(), + instruction.getRegisterA(), + instruction.getRegisterB(), + instruction.getFieldOffset()); + } + @Nonnull private BuilderInstruction22s newBuilderInstruction22s(@Nonnull Instruction22s instruction) { return new BuilderInstruction22s( @@ -868,6 +892,32 @@ public class MutableMethodImplementation implements MethodImplementation { instruction.getReference()); } + @Nonnull + private BuilderInstruction35mi newBuilderInstruction35mi(@Nonnull Instruction35mi instruction) { + return new BuilderInstruction35mi( + instruction.getOpcode(), + instruction.getRegisterCount(), + instruction.getRegisterC(), + instruction.getRegisterD(), + instruction.getRegisterE(), + instruction.getRegisterF(), + instruction.getRegisterG(), + instruction.getInlineIndex()); + } + + @Nonnull + private BuilderInstruction35ms newBuilderInstruction35ms(@Nonnull Instruction35ms instruction) { + return new BuilderInstruction35ms( + instruction.getOpcode(), + instruction.getRegisterCount(), + instruction.getRegisterC(), + instruction.getRegisterD(), + instruction.getRegisterE(), + instruction.getRegisterF(), + instruction.getRegisterG(), + instruction.getVtableIndex()); + } + @Nonnull private BuilderInstruction3rc newBuilderInstruction3rc(@Nonnull Instruction3rc instruction) { return new BuilderInstruction3rc( @@ -877,6 +927,24 @@ public class MutableMethodImplementation implements MethodImplementation { instruction.getReference()); } + @Nonnull + private BuilderInstruction3rmi newBuilderInstruction3rmi(@Nonnull Instruction3rmi instruction) { + return new BuilderInstruction3rmi( + instruction.getOpcode(), + instruction.getStartRegister(), + instruction.getRegisterCount(), + instruction.getInlineIndex()); + } + + @Nonnull + private BuilderInstruction3rms newBuilderInstruction3rms(@Nonnull Instruction3rms instruction) { + return new BuilderInstruction3rms( + instruction.getOpcode(), + instruction.getStartRegister(), + instruction.getRegisterCount(), + instruction.getVtableIndex()); + } + @Nonnull private BuilderInstruction51l newBuilderInstruction51l(@Nonnull Instruction51l instruction) { return new BuilderInstruction51l( diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction22cs.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction22cs.java new file mode 100644 index 00000000..e43f39da --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction22cs.java @@ -0,0 +1,65 @@ +/* + * 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.builder.instruction; + +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.builder.BuilderInstruction; +import org.jf.dexlib2.iface.instruction.formats.Instruction22c; +import org.jf.dexlib2.iface.instruction.formats.Instruction22cs; +import org.jf.dexlib2.iface.reference.Reference; +import org.jf.dexlib2.util.Preconditions; + +import javax.annotation.Nonnull; + +public class BuilderInstruction22cs extends BuilderInstruction implements Instruction22cs { + public static final Format FORMAT = Format.Format22cs; + + protected final int registerA; + protected final int registerB; + protected final int fieldOffset; + + public BuilderInstruction22cs(@Nonnull Opcode opcode, + int registerA, + int registerB, + int fieldOffset) { + super(opcode); + this.registerA = Preconditions.checkNibbleRegister(registerA); + this.registerB = Preconditions.checkNibbleRegister(registerB); + this.fieldOffset = fieldOffset; + } + + @Override public int getRegisterA() { return registerA; } + @Override public int getRegisterB() { return registerB; } + @Override public int getFieldOffset() { return fieldOffset; } + @Override public Format getFormat() { return FORMAT; } +} \ No newline at end of file diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35mi.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35mi.java new file mode 100644 index 00000000..43aed787 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35mi.java @@ -0,0 +1,80 @@ +/* + * 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.builder.instruction; + +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.builder.BuilderInstruction; +import org.jf.dexlib2.iface.instruction.formats.Instruction35mi; +import org.jf.dexlib2.util.Preconditions; + +import javax.annotation.Nonnull; + +public class BuilderInstruction35mi extends BuilderInstruction implements Instruction35mi { + public static final Format FORMAT = Format.Format35mi; + + protected final int registerCount; + protected final int registerC; + protected final int registerD; + protected final int registerE; + protected final int registerF; + protected final int registerG; + protected final int inlineIndex; + + public BuilderInstruction35mi(@Nonnull Opcode opcode, + int registerCount, + int registerC, + int registerD, + int registerE, + int registerF, + int registerG, + int inlineIndex) { + super(opcode); + this.registerCount = Preconditions.check35cAnd45ccRegisterCount(registerCount); + this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0; + this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0; + this.registerE = (registerCount>2) ? Preconditions.checkNibbleRegister(registerE) : 0; + this.registerF = (registerCount>3) ? Preconditions.checkNibbleRegister(registerF) : 0; + this.registerG = (registerCount>4) ? Preconditions.checkNibbleRegister(registerG) : 0; + this.inlineIndex = inlineIndex; + } + + @Override public int getRegisterCount() { return registerCount; } + @Override public int getRegisterC() { return registerC; } + @Override public int getRegisterD() { return registerD; } + @Override public int getRegisterE() { return registerE; } + @Override public int getRegisterF() { return registerF; } + @Override public int getRegisterG() { return registerG; } + @Override public int getInlineIndex() { return inlineIndex; } + @Override public Format getFormat() { return FORMAT; } + +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35ms.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35ms.java new file mode 100644 index 00000000..824dbd8e --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35ms.java @@ -0,0 +1,79 @@ +/* + * 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.builder.instruction; + +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.builder.BuilderInstruction; +import org.jf.dexlib2.iface.instruction.formats.Instruction35ms; +import org.jf.dexlib2.util.Preconditions; + +import javax.annotation.Nonnull; + +public class BuilderInstruction35ms extends BuilderInstruction implements Instruction35ms { + public static final Format FORMAT = Format.Format35ms; + + protected final int registerCount; + protected final int registerC; + protected final int registerD; + protected final int registerE; + protected final int registerF; + protected final int registerG; + protected final int vtableIndex; + + public BuilderInstruction35ms(@Nonnull Opcode opcode, + int registerCount, + int registerC, + int registerD, + int registerE, + int registerF, + int registerG, + int vtableIndex) { + super(opcode); + this.registerCount = Preconditions.check35cAnd45ccRegisterCount(registerCount); + this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0; + this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0; + this.registerE = (registerCount>2) ? Preconditions.checkNibbleRegister(registerE) : 0; + this.registerF = (registerCount>3) ? Preconditions.checkNibbleRegister(registerF) : 0; + this.registerG = (registerCount>4) ? Preconditions.checkNibbleRegister(registerG) : 0; + this.vtableIndex = vtableIndex; + } + + @Override public int getRegisterCount() { return registerCount; } + @Override public int getRegisterC() { return registerC; } + @Override public int getRegisterD() { return registerD; } + @Override public int getRegisterE() { return registerE; } + @Override public int getRegisterF() { return registerF; } + @Override public int getRegisterG() { return registerG; } + @Override public int getVtableIndex() { return vtableIndex; } + @Override public Format getFormat() { return FORMAT; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction3rmi.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction3rmi.java new file mode 100644 index 00000000..1df7b308 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction3rmi.java @@ -0,0 +1,65 @@ +/* + * 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.builder.instruction; + +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.builder.BuilderInstruction; +import org.jf.dexlib2.iface.instruction.formats.Instruction3rmi; +import org.jf.dexlib2.iface.instruction.formats.Instruction3rms; +import org.jf.dexlib2.util.Preconditions; + +import javax.annotation.Nonnull; + +public class BuilderInstruction3rmi extends BuilderInstruction implements Instruction3rmi { + public static final Format FORMAT = Format.Format3rmi; + + protected final int startRegister; + protected final int registerCount; + protected final int inlineIndex; + + public BuilderInstruction3rmi(@Nonnull Opcode opcode, + int startRegister, + int registerCount, + int inlineIndex) { + super(opcode); + this.startRegister = Preconditions.checkShortRegister(startRegister); + this.registerCount = Preconditions.checkRegisterRangeCount(registerCount); + this.inlineIndex = inlineIndex; + } + + @Override public int getStartRegister() { return startRegister; } + @Override public int getRegisterCount() { return registerCount; } + @Override public int getInlineIndex() { return inlineIndex; } + @Override public Format getFormat() { return FORMAT; } +} + diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction3rms.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction3rms.java new file mode 100644 index 00000000..bd73901f --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction3rms.java @@ -0,0 +1,66 @@ +/* + * 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.builder.instruction; + +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.builder.BuilderInstruction; +import org.jf.dexlib2.iface.instruction.formats.Instruction3rc; +import org.jf.dexlib2.iface.instruction.formats.Instruction3rms; +import org.jf.dexlib2.iface.reference.Reference; +import org.jf.dexlib2.util.Preconditions; + +import javax.annotation.Nonnull; + +public class BuilderInstruction3rms extends BuilderInstruction implements Instruction3rms { + public static final Format FORMAT = Format.Format3rms; + + protected final int startRegister; + protected final int registerCount; + protected final int vtableIndex; + + public BuilderInstruction3rms(@Nonnull Opcode opcode, + int startRegister, + int registerCount, + int vtableIndex) { + super(opcode); + this.startRegister = Preconditions.checkShortRegister(startRegister); + this.registerCount = Preconditions.checkRegisterRangeCount(registerCount); + this.vtableIndex = vtableIndex; + } + + @Override public int getStartRegister() { return startRegister; } + @Override public int getRegisterCount() { return registerCount; } + @Override public int getVtableIndex() { return vtableIndex; } + @Override public Format getFormat() { return FORMAT; } +} + diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java index 00cce65d..1b0d9df0 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java @@ -1017,6 +1017,9 @@ public abstract class DexWriter< case Format22c: instructionWriter.write((Instruction22c)instruction); break; + case Format22cs: + instructionWriter.write((Instruction22cs)instruction); + break; case Format22s: instructionWriter.write((Instruction22s)instruction); break; @@ -1047,9 +1050,21 @@ public abstract class DexWriter< case Format35c: instructionWriter.write((Instruction35c)instruction); break; + case Format35mi: + instructionWriter.write((Instruction35mi)instruction); + break; + case Format35ms: + instructionWriter.write((Instruction35ms)instruction); + break; case Format3rc: instructionWriter.write((Instruction3rc)instruction); break; + case Format3rmi: + instructionWriter.write((Instruction3rmi)instruction); + break; + case Format3rms: + instructionWriter.write((Instruction3rms)instruction); + break; case Format45cc: instructionWriter.write((Instruction45cc)instruction); break; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java index 1b883f1f..f6fd52fd 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java @@ -239,6 +239,16 @@ public class InstructionWriter Date: Wed, 17 May 2017 11:32:05 -0700 Subject: Bump the version to 2.2.1 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index cbcbf72f..08da9c85 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ apply plugin: 'idea' -version = '2.2.0' +version = '2.2.1' def jcommanderVersion = '' if (!('release' in gradle.startParameter.taskNames)) { @@ -206,4 +206,4 @@ buildscript { task wrapper(type: Wrapper) { gradleVersion = '3.5' distributionType = Wrapper.DistributionType.ALL -} \ No newline at end of file +} -- cgit v1.2.3 From b84345935a5ab15340dbca045a0af39c1f5a6124 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Thu, 31 Aug 2017 09:29:49 +0100 Subject: Fix out registers for invoke-polymorphic The calculation of the number of output registers for invoke-polymorphic and invoke-polymorphic-range should be based on the number of registers provided. --- dexlib2/src/main/java/org/jf/dexlib2/util/InstructionUtil.java | 4 ++++ dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/InstructionUtil.java b/dexlib2/src/main/java/org/jf/dexlib2/util/InstructionUtil.java index eb1f8d92..58ce2628 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/util/InstructionUtil.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/util/InstructionUtil.java @@ -38,5 +38,9 @@ public final class InstructionUtil { return opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE; } + public static boolean isInvokePolymorphic(Opcode opcode) { + return opcode == Opcode.INVOKE_POLYMORPHIC || opcode == Opcode.INVOKE_POLYMORPHIC_RANGE; + } + private InstructionUtil() {} } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java index 1b0d9df0..3020f326 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java @@ -52,6 +52,7 @@ 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.VariableRegisterInstruction; import org.jf.dexlib2.iface.instruction.formats.*; import org.jf.dexlib2.iface.reference.*; import org.jf.dexlib2.util.InstructionUtil; @@ -955,7 +956,13 @@ public abstract class DexWriter< if (instruction.getOpcode().referenceType == ReferenceType.METHOD) { ReferenceInstruction refInsn = (ReferenceInstruction)instruction; MethodReference methodRef = (MethodReference)refInsn.getReference(); - int paramCount = MethodUtil.getParameterRegisterCount(methodRef, InstructionUtil.isInvokeStatic(instruction.getOpcode())); + Opcode opcode = instruction.getOpcode(); + int paramCount; + if (InstructionUtil.isInvokePolymorphic(opcode)) { + paramCount = ((VariableRegisterInstruction)instruction).getRegisterCount(); + } else { + paramCount = MethodUtil.getParameterRegisterCount(methodRef, InstructionUtil.isInvokeStatic(opcode)); + } if (paramCount > outParamCount) { outParamCount = paramCount; } -- cgit v1.2.3