From a198c85a8ec3aff125614af68b7fd8a68556051c Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Tue, 22 May 2018 14:47:17 -0700 Subject: [PATCH] Add support for dumping the new structures --- .../main/java/org/jf/dexlib2/ValueType.java | 43 +++++ .../dexlib2/dexbacked/raw/CallSiteIdItem.java | 36 ++++ .../dexlib2/dexbacked/raw/EncodedValue.java | 164 +++++++++++------- .../dexbacked/raw/MethodHandleItem.java | 38 ++++ .../dexbacked/raw/util/DexAnnotator.java | 8 + 5 files changed, 222 insertions(+), 67 deletions(-) diff --git a/dexlib2/src/main/java/org/jf/dexlib2/ValueType.java b/dexlib2/src/main/java/org/jf/dexlib2/ValueType.java index 0faa7bd3..ecb967bf 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/ValueType.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/ValueType.java @@ -52,4 +52,47 @@ public final class ValueType { public static final int BOOLEAN = 0x1f; private ValueType() {} + + public static String getValueTypeName(int valueType) { + switch (valueType) { + case BYTE: + return "byte"; + case SHORT: + return "short"; + case CHAR: + return "char"; + case INT: + return "int"; + case LONG: + return "long"; + case FLOAT: + return "float"; + case DOUBLE: + return "double"; + case METHOD_TYPE: + return "method_type"; + case METHOD_HANDLE: + return "method_handle"; + case STRING: + return "string"; + case TYPE: + return "type"; + case FIELD: + return "field"; + case METHOD: + return "method"; + case ENUM: + return "enum"; + case ARRAY: + return "array"; + case ANNOTATION: + return "annotation"; + case NULL: + return "null"; + case BOOLEAN: + return "boolean"; + default: + throw new IllegalArgumentException("Unknown encoded value type: " + valueType); + } + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CallSiteIdItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CallSiteIdItem.java index 1faf0aba..784fe0fc 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CallSiteIdItem.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CallSiteIdItem.java @@ -31,6 +31,42 @@ package org.jf.dexlib2.dexbacked.raw; +import org.jf.dexlib2.dexbacked.DexReader; +import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator; +import org.jf.dexlib2.dexbacked.value.DexBackedArrayEncodedValue; +import org.jf.dexlib2.util.AnnotatedBytes; +import org.jf.dexlib2.util.EncodedValueUtils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.StringWriter; + public class CallSiteIdItem { public static final int ITEM_SIZE = 4; + + @Nonnull + public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { + return new SectionAnnotator(annotator, mapItem) { + @Nonnull @Override public String getItemName() { + return "call_site_id_item"; + } + + @Override + protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { + int callSiteOffset = dexFile.readSmallUint(out.getCursor()); + + StringWriter writer = new StringWriter(); + try { + EncodedValueUtils.writeEncodedValue(writer, + new DexBackedArrayEncodedValue(new DexReader(dexFile, callSiteOffset))); + } catch (IOException ex) { + // Shouldn't get an IOException from a StringWriter.. + throw new RuntimeException(ex); + } + + out.annotate(4, "call_site_id_item[0x%x] = %s", callSiteOffset, writer.toString()); + } + }; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/EncodedValue.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/EncodedValue.java index 29851c41..e484251f 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/EncodedValue.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/EncodedValue.java @@ -31,11 +31,15 @@ package org.jf.dexlib2.dexbacked.raw; +import org.jf.dexlib2.ValueType; import org.jf.dexlib2.dexbacked.DexReader; +import org.jf.dexlib2.dexbacked.value.DexBackedEncodedValue; import org.jf.dexlib2.util.AnnotatedBytes; -import org.jf.util.ExceptionWithContext; +import org.jf.dexlib2.util.EncodedValueUtils; import javax.annotation.Nonnull; +import java.io.IOException; +import java.io.StringWriter; public class EncodedValue { public static void annotateEncodedValue(@Nonnull AnnotatedBytes out, @Nonnull DexReader reader) { @@ -45,84 +49,42 @@ public class EncodedValue { int valueType = valueArgType & 0x1f; switch (valueType) { - case 0x00: - out.annotate(1, "valueArg = %d, valueType = 0x%x: byte", valueArg, valueType); - int intValue = reader.readByte(); - out.annotate(1, "value = 0x%x", intValue); + case ValueType.BYTE: + case ValueType.SHORT: + case ValueType.CHAR: + case ValueType.INT: + case ValueType.LONG: + case ValueType.FLOAT: + case ValueType.DOUBLE: + case ValueType.METHOD_TYPE: + case ValueType.METHOD_HANDLE: + case ValueType.STRING: + case ValueType.TYPE: + case ValueType.FIELD: + case ValueType.METHOD: + case ValueType.ENUM: + out.annotate(1, "valueArg = %d, valueType = 0x%x: %s", valueArg, valueType, + ValueType.getValueTypeName(valueType)); + reader.setOffset(reader.getOffset() - 1); + out.annotate(valueArg + 1, "value = %s", asString(reader)); break; - case 0x02: - out.annotate(1, "valueArg = %d, valueType = 0x%x: short", valueArg, valueType); - intValue = reader.readSizedInt(valueArg+1); - out.annotate(valueArg + 1, "value = 0x%x", intValue); - break; - case 0x03: - out.annotate(1, "valueArg = %d, valueType = 0x%x: char", valueArg, valueType); - intValue = reader.readSizedSmallUint(valueArg+1); - out.annotate(valueArg+1, "value = 0x%x", intValue); - break; - case 0x04: - out.annotate(1, "valueArg = %d, valueType = 0x%x: int", valueArg, valueType); - intValue = reader.readSizedInt(valueArg+1); - out.annotate(valueArg+1, "value = 0x%x", intValue); - break; - case 0x06: - out.annotate(1, "valueArg = %d, valueType = 0x%x: long", valueArg, valueType); - long longValue = reader.readSizedLong(valueArg+1); - out.annotate(valueArg+1, "value = 0x%x", longValue); - break; - case 0x10: - out.annotate(1, "valueArg = %d, valueType = 0x%x: float", valueArg, valueType); - float floatValue = Float.intBitsToFloat(reader.readSizedRightExtendedInt(valueArg + 1)); - out.annotate(valueArg+1, "value = %f", floatValue); - break; - case 0x11: - out.annotate(1, "valueArg = %d, valueType = 0x%x: double", valueArg, valueType); - double doubleValue = Double.longBitsToDouble(reader.readSizedRightExtendedLong(valueArg + 1)); - out.annotate(valueArg+1, "value = %f", doubleValue); - break; - case 0x17: - out.annotate(1, "valueArg = %d, valueType = 0x%x: string", valueArg, valueType); - int stringIndex = reader.readSizedSmallUint(valueArg + 1); - out.annotate(valueArg+1, "value = %s", - StringIdItem.getReferenceAnnotation(reader.dexBuf, stringIndex, true)); - break; - case 0x18: - out.annotate(1, "valueArg = %d, valueType = 0x%x: type", valueArg, valueType); - int typeIndex = reader.readSizedSmallUint(valueArg+1); - out.annotate(valueArg+1, "value = %s", TypeIdItem.getReferenceAnnotation(reader.dexBuf, typeIndex)); - break; - case 0x19: - out.annotate(1, "valueArg = %d, valueType = 0x%x: field", valueArg, valueType); - int fieldIndex = reader.readSizedSmallUint(valueArg+1); - out.annotate(valueArg+1, "value = %s", FieldIdItem.getReferenceAnnotation(reader.dexBuf, fieldIndex)); - break; - case 0x1a: - out.annotate(1, "valueArg = %d, valueType = 0x%x: method", valueArg, valueType); - int methodIndex = reader.readSizedSmallUint(valueArg+1); - out.annotate(valueArg+1, "value = %s", MethodIdItem.getReferenceAnnotation(reader.dexBuf, methodIndex)); - break; - case 0x1b: - out.annotate(1, "valueArg = %d, valueType = 0x%x: enum", valueArg, valueType); - fieldIndex = reader.readSizedSmallUint(valueArg+1); - out.annotate(valueArg+1, "value = %s", FieldIdItem.getReferenceAnnotation(reader.dexBuf, fieldIndex)); - break; - case 0x1c: + case ValueType.ARRAY: out.annotate(1, "valueArg = %d, valueType = 0x%x: array", valueArg, valueType); annotateEncodedArray(out, reader); break; - case 0x1d: + case ValueType.ANNOTATION: out.annotate(1, "valueArg = %d, valueType = 0x%x: annotation", valueArg, valueType); annotateEncodedAnnotation(out, reader); break; - case 0x1e: + case ValueType.NULL: out.annotate(1, "valueArg = %d, valueType = 0x%x: null", valueArg, valueType); break; - case 0x1f: + case ValueType.BOOLEAN: out.annotate(1, "valueArg = %d, valueType = 0x%x: boolean, value=%s", valueArg, valueType, valueArg==1); break; default: - throw new ExceptionWithContext("Invalid encoded value type 0x%x at offset 0x%x", valueType, - out.getCursor()); + throw new IllegalArgumentException(String.format("Invalid encoded value type 0x%x at offset 0x%x", valueType, + reader.getOffset())); } } @@ -164,4 +126,72 @@ public class EncodedValue { out.deindent(); } } + + public static String asString(@Nonnull DexReader reader) { + int valueArgType = reader.readUbyte(); + + int valueArg = valueArgType >>> 5; + int valueType = valueArgType & 0x1f; + + switch (valueType) { + case ValueType.BYTE: + int intValue = reader.readByte(); + return String.format("0x%x", intValue); + case ValueType.SHORT: + intValue = reader.readSizedInt(valueArg+1); + return String.format("0x%x", intValue); + case ValueType.CHAR: + intValue = reader.readSizedSmallUint(valueArg+1); + return String.format("0x%x", intValue); + case ValueType.INT: + intValue = reader.readSizedInt(valueArg+1); + return String.format("0x%x", intValue); + case ValueType.LONG: + long longValue = reader.readSizedLong(valueArg+1); + return String.format("0x%x", longValue); + case ValueType.FLOAT: + float floatValue = Float.intBitsToFloat(reader.readSizedRightExtendedInt(valueArg + 1)); + return String.format("%f", floatValue); + case ValueType.DOUBLE: + double doubleValue = Double.longBitsToDouble(reader.readSizedRightExtendedLong(valueArg + 1)); + return String.format("%f", doubleValue); + case ValueType.METHOD_TYPE: + int protoIndex = reader.readSizedSmallUint(valueArg + 1); + return ProtoIdItem.getReferenceAnnotation(reader.dexBuf, protoIndex); + case ValueType.STRING: + int stringIndex = reader.readSizedSmallUint(valueArg + 1); + return StringIdItem.getReferenceAnnotation(reader.dexBuf, stringIndex, true); + case ValueType.TYPE: + int typeIndex = reader.readSizedSmallUint(valueArg+1); + return TypeIdItem.getReferenceAnnotation(reader.dexBuf, typeIndex); + case ValueType.FIELD: + int fieldIndex = reader.readSizedSmallUint(valueArg+1); + return FieldIdItem.getReferenceAnnotation(reader.dexBuf, fieldIndex); + case ValueType.METHOD: + int methodIndex = reader.readSizedSmallUint(valueArg+1); + return MethodIdItem.getReferenceAnnotation(reader.dexBuf, methodIndex); + case ValueType.ENUM: + fieldIndex = reader.readSizedSmallUint(valueArg+1); + return FieldIdItem.getReferenceAnnotation(reader.dexBuf, fieldIndex); + case ValueType.ARRAY: + case ValueType.ANNOTATION: + case ValueType.METHOD_HANDLE: + StringWriter writer = new StringWriter(); + reader.setOffset(reader.getOffset() - 1); + try { + EncodedValueUtils.writeEncodedValue(writer, DexBackedEncodedValue.readFrom(reader)); + } catch (IOException ex) { + // Shouldn't happen with a StringWriter... + throw new RuntimeException(ex); + } + return writer.toString(); + case ValueType.NULL: + return "null"; + case ValueType.BOOLEAN: + return Boolean.toString(valueArg == 1); + default: + throw new IllegalArgumentException(String.format("Invalid encoded value type 0x%x at offset 0x%x", + valueType, reader.getOffset())); + } + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/MethodHandleItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/MethodHandleItem.java index 639eb650..11c8cc10 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/MethodHandleItem.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/MethodHandleItem.java @@ -31,9 +31,47 @@ package org.jf.dexlib2.dexbacked.raw; +import org.jf.dexlib2.MethodHandleType; +import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator; +import org.jf.dexlib2.util.AnnotatedBytes; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class MethodHandleItem { public static final int ITEM_SIZE = 8; public static final int METHOD_HANDLE_TYPE_OFFSET = 0; public static final int MEMBER_ID_OFFSET = 4; + + @Nonnull + public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { + return new SectionAnnotator(annotator, mapItem) { + @Nonnull @Override public String getItemName() { + return "method_handle_item"; + } + + @Override + protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { + int methodHandleType = dexFile.readUshort(out.getCursor()); + out.annotate(2, "type = %s", MethodHandleType.toString(methodHandleType)); + out.annotate(2, "unused"); + + int fieldOrMethodId = dexFile.readUshort(out.getCursor()); + String fieldOrMethodDescriptor; + if (methodHandleType == MethodHandleType.STATIC_INVOKE || + methodHandleType == MethodHandleType.INSTANCE_INVOKE) { + fieldOrMethodDescriptor = MethodIdItem.getReferenceAnnotation(dexFile, fieldOrMethodId); + } else { + fieldOrMethodDescriptor = FieldIdItem.getReferenceAnnotation(dexFile, fieldOrMethodId); + } + + out.annotate(2, "field_or_method_id = %s", fieldOrMethodDescriptor); + out.annotate(2, "unused"); + } + }; + } + + + } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java index c2e0c9ca..9ce22262 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java @@ -61,6 +61,8 @@ public class DexAnnotator extends AnnotatedBytes { ItemType.PROTO_ID_ITEM, ItemType.FIELD_ID_ITEM, ItemType.METHOD_ID_ITEM, + ItemType.CALL_SITE_ID_ITEM, + ItemType.METHOD_HANDLE_ITEM, // these need to be ordered like this, so the item identities can be propagated ItemType.CLASS_DEF_ITEM, @@ -143,6 +145,12 @@ public class DexAnnotator extends AnnotatedBytes { case ItemType.ANNOTATION_DIRECTORY_ITEM: annotators.put(mapItem.getType(), AnnotationDirectoryItem.makeAnnotator(this, mapItem)); break; + case ItemType.CALL_SITE_ID_ITEM: + annotators.put(mapItem.getType(), CallSiteIdItem.makeAnnotator(this, mapItem)); + break; + case ItemType.METHOD_HANDLE_ITEM: + annotators.put(mapItem.getType(), MethodHandleItem.makeAnnotator(this, mapItem)); + break; default: throw new RuntimeException(String.format("Unrecognized item type: 0x%x", mapItem.getType())); }