Permalink
Browse files

Add support for getting byte sizes to dex backed references

  • Loading branch information...
wojtek-kalicinski authored and JesusFreke committed Apr 3, 2017
1 parent 76d69c7 commit b65e942e7e53fab70e177681989eb8eaeb4c89de
View
4 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.
@@ -88,10 +88,41 @@ public int readSleb128() {
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 @@ private int readUleb128(boolean allowLarge) {
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 int readBigUleb128() {
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 String readString(int utf16Length) {
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];
+ }
}
@@ -36,6 +36,7 @@
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 @@ private int getVirtualMethodsOffset() {
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<? extends DexBackedAnnotation> 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;
+ }
}
@@ -33,8 +33,10 @@
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 final int annotationSetOffset;
public final int fieldIndex;
+ private final int startOffset;
+ private final int initialValueOffset;
private int fieldIdItemOffset;
@@ -65,11 +69,13 @@ public DexBackedField(@Nonnull DexReader reader,
// 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 DexBackedField(@Nonnull DexReader reader,
// 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 @@ private int getFieldIdItemOffset() {
}
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<? extends DexBackedAnnotation> 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;
+ }
}
@@ -37,11 +37,13 @@
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 @@
private final int methodAnnotationSetOffset;
public final int methodIndex;
+ private final int startOffset;
private int methodIdItemOffset;
private int protoIdItemOffset;
@@ -72,6 +75,7 @@ public DexBackedMethod(@Nonnull DexReader reader,
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 DexBackedMethod(@Nonnull DexReader reader,
@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 static void skipMethods(@Nonnull DexReader reader, int count) {
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;
+ }
}
Oops, something went wrong.

0 comments on commit b65e942

Please sign in to comment.