mirror of
https://github.com/revanced/Apktool.git
synced 2025-01-21 17:27:41 +01:00
[smali] update to smali 2b6
This commit is contained in:
parent
9c957b9308
commit
79c68ed6d9
1
CHANGES
1
CHANGES
@ -22,6 +22,7 @@ v2.0.0 (TBA)
|
|||||||
-Fixed (issue #448) - Merge smali2 into Apktool
|
-Fixed (issue #448) - Merge smali2 into Apktool
|
||||||
-Fixed (issue #496) - Fixes Windows builds caused by java.nio problems
|
-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 #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)
|
-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)
|
-Fixed NPE when handling odex apks even with --no-src specified. (Thanks Rodrigo Chiossi)
|
||||||
|
|
||||||
|
@ -32,10 +32,13 @@ import org.jf.baksmali.Adaptors.MethodDefinition;
|
|||||||
import org.jf.baksmali.Adaptors.MethodItem;
|
import org.jf.baksmali.Adaptors.MethodItem;
|
||||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
||||||
import org.jf.baksmali.Renderers.LongRenderer;
|
import org.jf.baksmali.Renderers.LongRenderer;
|
||||||
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import org.jf.dexlib2.VerificationError;
|
import org.jf.dexlib2.VerificationError;
|
||||||
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||||
import org.jf.dexlib2.iface.instruction.*;
|
import org.jf.dexlib2.iface.instruction.*;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
|
import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
|
||||||
|
import org.jf.dexlib2.iface.reference.Reference;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -58,6 +61,21 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
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) {
|
switch (instruction.getOpcode().format) {
|
||||||
case Format10t:
|
case Format10t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
@ -336,8 +354,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeReference(IndentingWriter writer) throws IOException {
|
protected void writeReference(IndentingWriter writer) throws IOException {
|
||||||
ReferenceFormatter.writeReference(writer, instruction.getOpcode().referenceType,
|
try {
|
||||||
((ReferenceInstruction)instruction).getReference());
|
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 {
|
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
|
||||||
|
@ -148,7 +148,7 @@ public class main {
|
|||||||
options.addCodeOffsets = true;
|
options.addCodeOffsets = true;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
String[] values = commandLine.getOptionValues('r');
|
String[] values = commandLine.getOptionValues("r");
|
||||||
int registerInfo = 0;
|
int registerInfo = 0;
|
||||||
|
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
|
@ -104,7 +104,7 @@ public class AnalysisTest {
|
|||||||
className.substring(1, className.length() - 1));
|
className.substring(1, className.length() - 1));
|
||||||
String smaliContents = readResource(smaliPath);
|
String smaliContents = readResource(smaliPath);
|
||||||
|
|
||||||
Assert.assertEquals(smaliContents, stringWriter.toString());
|
Assert.assertEquals(smaliContents, stringWriter.toString().replace("\r\n", "\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,5 +38,20 @@ public final class ReferenceType {
|
|||||||
public static final int METHOD = 3;
|
public static final int METHOD = 3;
|
||||||
public static final int NONE = 4;
|
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() {}
|
private ReferenceType() {}
|
||||||
}
|
}
|
@ -33,13 +33,28 @@ package org.jf.dexlib2.base;
|
|||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
import org.jf.dexlib2.base.reference.BaseTypeReference;
|
||||||
import org.jf.dexlib2.iface.ExceptionHandler;
|
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||||
|
import org.jf.dexlib2.iface.reference.TypeReference;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public abstract class BaseExceptionHandler implements ExceptionHandler {
|
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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
String exceptionType = getExceptionType();
|
String exceptionType = getExceptionType();
|
||||||
@ -76,6 +91,8 @@ public abstract class BaseExceptionHandler implements ExceptionHandler {
|
|||||||
return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress());
|
return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static final Comparator<ExceptionHandler> BY_EXCEPTION = new Comparator<ExceptionHandler>() {
|
public static final Comparator<ExceptionHandler> BY_EXCEPTION = new Comparator<ExceptionHandler>() {
|
||||||
@Override public int compare(ExceptionHandler o1, ExceptionHandler o2) {
|
@Override public int compare(ExceptionHandler o1, ExceptionHandler o2) {
|
||||||
String exceptionType1 = o1.getExceptionType();
|
String exceptionType1 = o1.getExceptionType();
|
||||||
|
@ -90,6 +90,10 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int readSmallUleb128() {
|
public int readSmallUleb128() {
|
||||||
|
return readUleb128(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readUleb128(boolean allowLarge) {
|
||||||
int end = offset;
|
int end = offset;
|
||||||
int currentByteValue;
|
int currentByteValue;
|
||||||
int result;
|
int result;
|
||||||
@ -113,10 +117,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
|||||||
throw new ExceptionWithContext(
|
throw new ExceptionWithContext(
|
||||||
"Invalid uleb128 integer encountered at offset 0x%x", offset);
|
"Invalid uleb128 integer encountered at offset 0x%x", offset);
|
||||||
} else if ((currentByteValue & 0xf) > 0x07) {
|
} else if ((currentByteValue & 0xf) > 0x07) {
|
||||||
// we assume most significant bit of the result will not be set, so that it can fit into
|
if (!allowLarge) {
|
||||||
// a signed integer without wrapping
|
// for non-large uleb128s, we assume most significant bit of the result will not be
|
||||||
throw new ExceptionWithContext(
|
// set, so that it can fit into a signed integer without wrapping
|
||||||
"Encountered valid uleb128 that is out of range at offset 0x%x", offset);
|
throw new ExceptionWithContext(
|
||||||
|
"Encountered valid uleb128 that is out of range at offset 0x%x", offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result |= currentByteValue << 28;
|
result |= currentByteValue << 28;
|
||||||
}
|
}
|
||||||
@ -128,6 +134,16 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
|||||||
return result;
|
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
|
* 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.
|
* expected semantics of re-interpreting an unsigned value as a signed value.
|
||||||
@ -185,11 +201,6 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
|||||||
if (currentByteValue < 0) {
|
if (currentByteValue < 0) {
|
||||||
throw new ExceptionWithContext(
|
throw new ExceptionWithContext(
|
||||||
"Invalid uleb128 integer encountered at offset 0x%x", offset);
|
"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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,42 +163,42 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
|
|||||||
|
|
||||||
public int getStringIdItemOffset(int stringIndex) {
|
public int getStringIdItemOffset(int stringIndex) {
|
||||||
if (stringIndex < 0 || stringIndex >= stringCount) {
|
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;
|
return stringStartOffset + stringIndex*StringIdItem.ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTypeIdItemOffset(int typeIndex) {
|
public int getTypeIdItemOffset(int typeIndex) {
|
||||||
if (typeIndex < 0 || typeIndex >= typeCount) {
|
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;
|
return typeStartOffset + typeIndex*TypeIdItem.ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFieldIdItemOffset(int fieldIndex) {
|
public int getFieldIdItemOffset(int fieldIndex) {
|
||||||
if (fieldIndex < 0 || fieldIndex >= fieldCount) {
|
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;
|
return fieldStartOffset + fieldIndex*FieldIdItem.ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMethodIdItemOffset(int methodIndex) {
|
public int getMethodIdItemOffset(int methodIndex) {
|
||||||
if (methodIndex < 0 || methodIndex >= methodCount) {
|
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;
|
return methodStartOffset + methodIndex*MethodIdItem.ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getProtoIdItemOffset(int protoIndex) {
|
public int getProtoIdItemOffset(int protoIndex) {
|
||||||
if (protoIndex < 0 || protoIndex >= protoCount) {
|
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;
|
return protoStartOffset + protoIndex*ProtoIdItem.ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getClassDefItemOffset(int classIndex) {
|
public int getClassDefItemOffset(int classIndex) {
|
||||||
if (classIndex < 0 || classIndex >= classCount) {
|
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;
|
return classStartOffset + classIndex*ClassDefItem.ITEM_SIZE;
|
||||||
}
|
}
|
||||||
@ -261,4 +261,22 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
|
|||||||
super(message, cause);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,9 @@ public class DexBackedField extends BaseFieldReference implements Field {
|
|||||||
this.dexFile = reader.dexBuf;
|
this.dexFile = reader.dexBuf;
|
||||||
this.classDef = classDef;
|
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.fieldIndex = fieldIndexDiff + previousFieldIndex;
|
||||||
this.accessFlags = reader.readSmallUleb128();
|
this.accessFlags = reader.readSmallUleb128();
|
||||||
|
|
||||||
@ -78,7 +80,9 @@ public class DexBackedField extends BaseFieldReference implements Field {
|
|||||||
this.dexFile = reader.dexBuf;
|
this.dexFile = reader.dexBuf;
|
||||||
this.classDef = classDef;
|
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.fieldIndex = fieldIndexDiff + previousFieldIndex;
|
||||||
this.accessFlags = reader.readSmallUleb128();
|
this.accessFlags = reader.readSmallUleb128();
|
||||||
|
|
||||||
|
@ -73,7 +73,9 @@ public class DexBackedMethod extends BaseMethodReference implements Method {
|
|||||||
this.dexFile = reader.dexBuf;
|
this.dexFile = reader.dexBuf;
|
||||||
this.classDef = classDef;
|
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.methodIndex = methodIndexDiff + previousMethodIndex;
|
||||||
this.accessFlags = reader.readSmallUleb128();
|
this.accessFlags = reader.readSmallUleb128();
|
||||||
this.codeOffset = reader.readSmallUleb128();
|
this.codeOffset = reader.readSmallUleb128();
|
||||||
@ -90,7 +92,9 @@ public class DexBackedMethod extends BaseMethodReference implements Method {
|
|||||||
this.dexFile = reader.dexBuf;
|
this.dexFile = reader.dexBuf;
|
||||||
this.classDef = classDef;
|
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.methodIndex = methodIndexDiff + previousMethodIndex;
|
||||||
this.accessFlags = reader.readSmallUleb128();
|
this.accessFlags = reader.readSmallUleb128();
|
||||||
this.codeOffset = reader.readSmallUleb128();
|
this.codeOffset = reader.readSmallUleb128();
|
||||||
|
@ -127,7 +127,9 @@ public class ClassDataItem {
|
|||||||
|
|
||||||
private int annotateEncodedField(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile,
|
private int annotateEncodedField(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile,
|
||||||
@Nonnull DexReader reader, int previousIndex) {
|
@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;
|
int fieldIndex = previousIndex + indexDelta;
|
||||||
out.annotateTo(reader.getOffset(), "field_idx_diff = %d: %s", indexDelta,
|
out.annotateTo(reader.getOffset(), "field_idx_diff = %d: %s", indexDelta,
|
||||||
FieldIdItem.getReferenceAnnotation(dexFile, fieldIndex));
|
FieldIdItem.getReferenceAnnotation(dexFile, fieldIndex));
|
||||||
@ -141,7 +143,9 @@ public class ClassDataItem {
|
|||||||
|
|
||||||
private int annotateEncodedMethod(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile,
|
private int annotateEncodedMethod(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile,
|
||||||
@Nonnull DexReader reader, int previousIndex) {
|
@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;
|
int methodIndex = previousIndex + indexDelta;
|
||||||
out.annotateTo(reader.getOffset(), "method_idx_diff = %d: %s", indexDelta,
|
out.annotateTo(reader.getOffset(), "method_idx_diff = %d: %s", indexDelta,
|
||||||
MethodIdItem.getReferenceAnnotation(dexFile, methodIndex));
|
MethodIdItem.getReferenceAnnotation(dexFile, methodIndex));
|
||||||
|
@ -53,6 +53,8 @@ public class DexAnnotator extends AnnotatedBytes {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
int[] sectionOrder = new int[] {
|
int[] sectionOrder = new int[] {
|
||||||
|
ItemType.MAP_LIST,
|
||||||
|
|
||||||
ItemType.HEADER_ITEM,
|
ItemType.HEADER_ITEM,
|
||||||
ItemType.STRING_ID_ITEM,
|
ItemType.STRING_ID_ITEM,
|
||||||
ItemType.TYPE_ID_ITEM,
|
ItemType.TYPE_ID_ITEM,
|
||||||
@ -66,7 +68,6 @@ public class DexAnnotator extends AnnotatedBytes {
|
|||||||
ItemType.CODE_ITEM,
|
ItemType.CODE_ITEM,
|
||||||
ItemType.DEBUG_INFO_ITEM,
|
ItemType.DEBUG_INFO_ITEM,
|
||||||
|
|
||||||
ItemType.MAP_LIST,
|
|
||||||
ItemType.TYPE_LIST,
|
ItemType.TYPE_LIST,
|
||||||
ItemType.ANNOTATION_SET_REF_LIST,
|
ItemType.ANNOTATION_SET_REF_LIST,
|
||||||
ItemType.ANNOTATION_SET_ITEM,
|
ItemType.ANNOTATION_SET_ITEM,
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
package org.jf.dexlib2.iface;
|
package org.jf.dexlib2.iface;
|
||||||
|
|
||||||
|
import org.jf.dexlib2.iface.reference.TypeReference;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -45,6 +47,14 @@ public interface ExceptionHandler extends Comparable<ExceptionHandler> {
|
|||||||
*/
|
*/
|
||||||
@Nullable String getExceptionType();
|
@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.
|
* Gets the code offset of the handler.
|
||||||
*
|
*
|
||||||
|
@ -31,8 +31,11 @@
|
|||||||
|
|
||||||
package org.jf.dexlib2.iface.debug;
|
package org.jf.dexlib2.iface.debug;
|
||||||
|
|
||||||
|
import org.jf.dexlib2.iface.reference.StringReference;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public interface SetSourceFile extends DebugItem {
|
public interface SetSourceFile extends DebugItem {
|
||||||
@Nullable String getSourceFile();
|
@Nullable String getSourceFile();
|
||||||
|
@Nullable StringReference getSourceFileReference();
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,15 @@
|
|||||||
|
|
||||||
package org.jf.dexlib2.iface.debug;
|
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 {
|
public interface StartLocal extends DebugItem, LocalInfo {
|
||||||
int getRegister();
|
int getRegister();
|
||||||
|
|
||||||
|
@Nullable StringReference getNameReference();
|
||||||
|
@Nullable TypeReference getTypeReference();
|
||||||
|
@Nullable StringReference getSignatureReference();
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
package org.jf.dexlib2.immutable.debug;
|
package org.jf.dexlib2.immutable.debug;
|
||||||
|
|
||||||
import org.jf.dexlib2.DebugItemType;
|
import org.jf.dexlib2.DebugItemType;
|
||||||
|
import org.jf.dexlib2.base.reference.BaseStringReference;
|
||||||
import org.jf.dexlib2.iface.debug.SetSourceFile;
|
import org.jf.dexlib2.iface.debug.SetSourceFile;
|
||||||
|
import org.jf.dexlib2.iface.reference.StringReference;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
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 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; }
|
@Override public int getDebugItemType() { return DebugItemType.SET_SOURCE_FILE; }
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,11 @@
|
|||||||
package org.jf.dexlib2.immutable.debug;
|
package org.jf.dexlib2.immutable.debug;
|
||||||
|
|
||||||
import org.jf.dexlib2.DebugItemType;
|
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.debug.StartLocal;
|
||||||
|
import org.jf.dexlib2.iface.reference.StringReference;
|
||||||
|
import org.jf.dexlib2.iface.reference.TypeReference;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -69,6 +73,31 @@ public class ImmutableStartLocal extends ImmutableDebugItem implements StartLoca
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public int getRegister() { return register; }
|
@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 getName() { return name; }
|
||||||
@Nullable @Override public String getType() { return type; }
|
@Nullable @Override public String getType() { return type; }
|
||||||
@Nullable @Override public String getSignature() { return signature; }
|
@Nullable @Override public String getSignature() { return signature; }
|
||||||
|
@ -45,8 +45,8 @@ public abstract class ImmutableInstruction implements Instruction {
|
|||||||
@Nonnull protected final Opcode opcode;
|
@Nonnull protected final Opcode opcode;
|
||||||
|
|
||||||
protected ImmutableInstruction(@Nonnull Opcode opcode) {
|
protected ImmutableInstruction(@Nonnull Opcode opcode) {
|
||||||
this.opcode = opcode;
|
|
||||||
Preconditions.checkFormat(opcode, getFormat());
|
Preconditions.checkFormat(opcode, getFormat());
|
||||||
|
this.opcode = opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@ -46,7 +46,6 @@ public class ImmutableInstruction10t extends ImmutableInstruction implements Ins
|
|||||||
public ImmutableInstruction10t(@Nonnull Opcode opcode,
|
public ImmutableInstruction10t(@Nonnull Opcode opcode,
|
||||||
int codeOffset) {
|
int codeOffset) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.codeOffset = Preconditions.checkByteCodeOffset(codeOffset);
|
this.codeOffset = Preconditions.checkByteCodeOffset(codeOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ package org.jf.dexlib2.immutable.instruction;
|
|||||||
import org.jf.dexlib2.Format;
|
import org.jf.dexlib2.Format;
|
||||||
import org.jf.dexlib2.Opcode;
|
import org.jf.dexlib2.Opcode;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction10x;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction10x;
|
||||||
import org.jf.dexlib2.util.Preconditions;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@ -43,7 +42,6 @@ public class ImmutableInstruction10x extends ImmutableInstruction implements Ins
|
|||||||
|
|
||||||
public ImmutableInstruction10x(@Nonnull Opcode opcode) {
|
public ImmutableInstruction10x(@Nonnull Opcode opcode) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImmutableInstruction10x of(Instruction10x instruction) {
|
public static ImmutableInstruction10x of(Instruction10x instruction) {
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction11n extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
int literal) {
|
int literal) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
||||||
this.literal = Preconditions.checkNibbleLiteral(literal);
|
this.literal = Preconditions.checkNibbleLiteral(literal);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,6 @@ public class ImmutableInstruction11x extends ImmutableInstruction implements Ins
|
|||||||
public ImmutableInstruction11x(@Nonnull Opcode opcode,
|
public ImmutableInstruction11x(@Nonnull Opcode opcode,
|
||||||
int registerA) {
|
int registerA) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction12x extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
int registerB) {
|
int registerB) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
||||||
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,6 @@ public class ImmutableInstruction20bc extends ImmutableInstruction implements In
|
|||||||
int verificationError,
|
int verificationError,
|
||||||
@Nonnull Reference reference) {
|
@Nonnull Reference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.verificationError = Preconditions.checkVerificationError(verificationError);
|
this.verificationError = Preconditions.checkVerificationError(verificationError);
|
||||||
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,6 @@ public class ImmutableInstruction20t extends ImmutableInstruction implements Ins
|
|||||||
public ImmutableInstruction20t(@Nonnull Opcode opcode,
|
public ImmutableInstruction20t(@Nonnull Opcode opcode,
|
||||||
int codeOffset) {
|
int codeOffset) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset);
|
this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ public class ImmutableInstruction21c extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
@Nonnull Reference reference) {
|
@Nonnull Reference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction21ih extends ImmutableInstruction implements In
|
|||||||
int registerA,
|
int registerA,
|
||||||
int literal) {
|
int literal) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.literal = Preconditions.checkIntegerHatLiteral(literal);
|
this.literal = Preconditions.checkIntegerHatLiteral(literal);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction21lh extends ImmutableInstruction implements In
|
|||||||
int registerA,
|
int registerA,
|
||||||
long literal) {
|
long literal) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.literal = Preconditions.checkLongHatLiteral(literal);
|
this.literal = Preconditions.checkLongHatLiteral(literal);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction21s extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
int literal) {
|
int literal) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.literal = Preconditions.checkShortLiteral(literal);
|
this.literal = Preconditions.checkShortLiteral(literal);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction21t extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
int codeOffset) {
|
int codeOffset) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset);
|
this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ public class ImmutableInstruction22b extends ImmutableInstruction implements Ins
|
|||||||
int registerB,
|
int registerB,
|
||||||
int literal) {
|
int literal) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.registerB = Preconditions.checkByteRegister(registerB);
|
this.registerB = Preconditions.checkByteRegister(registerB);
|
||||||
this.literal = Preconditions.checkByteLiteral(literal);
|
this.literal = Preconditions.checkByteLiteral(literal);
|
||||||
|
@ -53,7 +53,6 @@ public class ImmutableInstruction22c extends ImmutableInstruction implements Ins
|
|||||||
int registerB,
|
int registerB,
|
||||||
@Nonnull Reference reference) {
|
@Nonnull Reference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
||||||
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
||||||
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
||||||
|
@ -43,14 +43,13 @@ public class ImmutableInstruction22cs extends ImmutableInstruction implements In
|
|||||||
|
|
||||||
protected final int registerA;
|
protected final int registerA;
|
||||||
protected final int registerB;
|
protected final int registerB;
|
||||||
@Nonnull protected final int fieldOffset;
|
protected final int fieldOffset;
|
||||||
|
|
||||||
public ImmutableInstruction22cs(@Nonnull Opcode opcode,
|
public ImmutableInstruction22cs(@Nonnull Opcode opcode,
|
||||||
int registerA,
|
int registerA,
|
||||||
int registerB,
|
int registerB,
|
||||||
int fieldOffset) {
|
int fieldOffset) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
||||||
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
||||||
this.fieldOffset = Preconditions.checkFieldOffset(fieldOffset);
|
this.fieldOffset = Preconditions.checkFieldOffset(fieldOffset);
|
||||||
|
@ -50,7 +50,6 @@ public class ImmutableInstruction22s extends ImmutableInstruction implements Ins
|
|||||||
int registerB,
|
int registerB,
|
||||||
int literal) {
|
int literal) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
||||||
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
||||||
this.literal = Preconditions.checkShortLiteral(literal);
|
this.literal = Preconditions.checkShortLiteral(literal);
|
||||||
|
@ -50,7 +50,6 @@ public class ImmutableInstruction22t extends ImmutableInstruction implements Ins
|
|||||||
int registerB,
|
int registerB,
|
||||||
int codeOffset) {
|
int codeOffset) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
||||||
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
||||||
this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset);
|
this.codeOffset = Preconditions.checkShortCodeOffset(codeOffset);
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction22x extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
int registerB) {
|
int registerB) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.registerB = Preconditions.checkShortRegister(registerB);
|
this.registerB = Preconditions.checkShortRegister(registerB);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ public class ImmutableInstruction23x extends ImmutableInstruction implements Ins
|
|||||||
int registerB,
|
int registerB,
|
||||||
int registerC) {
|
int registerC) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.registerB = Preconditions.checkByteRegister(registerB);
|
this.registerB = Preconditions.checkByteRegister(registerB);
|
||||||
this.registerC = Preconditions.checkByteRegister(registerC);
|
this.registerC = Preconditions.checkByteRegister(registerC);
|
||||||
|
@ -34,7 +34,6 @@ package org.jf.dexlib2.immutable.instruction;
|
|||||||
import org.jf.dexlib2.Format;
|
import org.jf.dexlib2.Format;
|
||||||
import org.jf.dexlib2.Opcode;
|
import org.jf.dexlib2.Opcode;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction30t;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction30t;
|
||||||
import org.jf.dexlib2.util.Preconditions;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@ -46,7 +45,6 @@ public class ImmutableInstruction30t extends ImmutableInstruction implements Ins
|
|||||||
public ImmutableInstruction30t(@Nonnull Opcode opcode,
|
public ImmutableInstruction30t(@Nonnull Opcode opcode,
|
||||||
int codeOffset) {
|
int codeOffset) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.codeOffset = codeOffset;
|
this.codeOffset = codeOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ public class ImmutableInstruction31c extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
@Nonnull Reference reference) {
|
@Nonnull Reference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction31i extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
int literal) {
|
int literal) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.literal = literal;
|
this.literal = literal;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction31t extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
int codeOffset) {
|
int codeOffset) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.codeOffset = codeOffset;
|
this.codeOffset = codeOffset;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction32x extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
int registerB) {
|
int registerB) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkShortRegister(registerA);
|
this.registerA = Preconditions.checkShortRegister(registerA);
|
||||||
this.registerB = Preconditions.checkShortRegister(registerB);
|
this.registerB = Preconditions.checkShortRegister(registerB);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,6 @@ public class ImmutableInstruction35c extends ImmutableInstruction implements Ins
|
|||||||
int registerG,
|
int registerG,
|
||||||
@Nonnull Reference reference) {
|
@Nonnull Reference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
||||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||||
|
@ -47,7 +47,7 @@ public class ImmutableInstruction35mi extends ImmutableInstruction implements In
|
|||||||
protected final int registerE;
|
protected final int registerE;
|
||||||
protected final int registerF;
|
protected final int registerF;
|
||||||
protected final int registerG;
|
protected final int registerG;
|
||||||
@Nonnull protected final int inlineIndex;
|
protected final int inlineIndex;
|
||||||
|
|
||||||
public ImmutableInstruction35mi(@Nonnull Opcode opcode,
|
public ImmutableInstruction35mi(@Nonnull Opcode opcode,
|
||||||
int registerCount,
|
int registerCount,
|
||||||
@ -58,7 +58,6 @@ public class ImmutableInstruction35mi extends ImmutableInstruction implements In
|
|||||||
int registerG,
|
int registerG,
|
||||||
int inlineIndex) {
|
int inlineIndex) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
||||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||||
|
@ -47,7 +47,7 @@ public class ImmutableInstruction35ms extends ImmutableInstruction implements In
|
|||||||
protected final int registerE;
|
protected final int registerE;
|
||||||
protected final int registerF;
|
protected final int registerF;
|
||||||
protected final int registerG;
|
protected final int registerG;
|
||||||
@Nonnull protected final int vtableIndex;
|
protected final int vtableIndex;
|
||||||
|
|
||||||
public ImmutableInstruction35ms(@Nonnull Opcode opcode,
|
public ImmutableInstruction35ms(@Nonnull Opcode opcode,
|
||||||
int registerCount,
|
int registerCount,
|
||||||
@ -58,7 +58,6 @@ public class ImmutableInstruction35ms extends ImmutableInstruction implements In
|
|||||||
int registerG,
|
int registerG,
|
||||||
int vtableIndex) {
|
int vtableIndex) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
||||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||||
|
@ -54,7 +54,6 @@ public class ImmutableInstruction3rc extends ImmutableInstruction implements Ins
|
|||||||
int registerCount,
|
int registerCount,
|
||||||
@Nonnull Reference reference) {
|
@Nonnull Reference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
||||||
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
||||||
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
this.reference = ImmutableReferenceFactory.of(opcode.referenceType, reference);
|
||||||
|
@ -43,7 +43,6 @@ public class ImmutableInstruction3rmi extends ImmutableInstruction implements In
|
|||||||
|
|
||||||
protected final int startRegister;
|
protected final int startRegister;
|
||||||
protected final int registerCount;
|
protected final int registerCount;
|
||||||
|
|
||||||
protected final int inlineIndex;
|
protected final int inlineIndex;
|
||||||
|
|
||||||
public ImmutableInstruction3rmi(@Nonnull Opcode opcode,
|
public ImmutableInstruction3rmi(@Nonnull Opcode opcode,
|
||||||
@ -51,7 +50,6 @@ public class ImmutableInstruction3rmi extends ImmutableInstruction implements In
|
|||||||
int registerCount,
|
int registerCount,
|
||||||
int inlineIndex) {
|
int inlineIndex) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
||||||
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
||||||
this.inlineIndex = Preconditions.checkInlineIndex(inlineIndex);
|
this.inlineIndex = Preconditions.checkInlineIndex(inlineIndex);
|
||||||
|
@ -43,7 +43,6 @@ public class ImmutableInstruction3rms extends ImmutableInstruction implements In
|
|||||||
|
|
||||||
protected final int startRegister;
|
protected final int startRegister;
|
||||||
protected final int registerCount;
|
protected final int registerCount;
|
||||||
|
|
||||||
protected final int vtableIndex;
|
protected final int vtableIndex;
|
||||||
|
|
||||||
public ImmutableInstruction3rms(@Nonnull Opcode opcode,
|
public ImmutableInstruction3rms(@Nonnull Opcode opcode,
|
||||||
@ -51,7 +50,6 @@ public class ImmutableInstruction3rms extends ImmutableInstruction implements In
|
|||||||
int registerCount,
|
int registerCount,
|
||||||
int vtableIndex) {
|
int vtableIndex) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
||||||
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
||||||
this.vtableIndex = Preconditions.checkVtableIndex(vtableIndex);
|
this.vtableIndex = Preconditions.checkVtableIndex(vtableIndex);
|
||||||
|
@ -48,7 +48,6 @@ public class ImmutableInstruction51l extends ImmutableInstruction implements Ins
|
|||||||
int registerA,
|
int registerA,
|
||||||
long literal) {
|
long literal) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.literal = literal;
|
this.literal = literal;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ import javax.annotation.Nonnull;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ImmutableInstructionFactory implements InstructionFactory<ImmutableInstruction, Reference> {
|
public class ImmutableInstructionFactory implements InstructionFactory<Reference> {
|
||||||
public static final ImmutableInstructionFactory INSTANCE = new ImmutableInstructionFactory();
|
public static final ImmutableInstructionFactory INSTANCE = new ImmutableInstructionFactory();
|
||||||
|
|
||||||
private ImmutableInstructionFactory() {
|
private ImmutableInstructionFactory() {
|
||||||
|
@ -109,20 +109,20 @@ public class Preconditions {
|
|||||||
return literal;
|
return literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int checkByteCodeOffset(int register) {
|
public static int checkByteCodeOffset(int offset) {
|
||||||
if (register < -128 || register > 127) {
|
if (offset < -128 || offset > 127) {
|
||||||
throw new IllegalArgumentException(
|
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) {
|
public static int checkShortCodeOffset(int offset) {
|
||||||
if (register < -32768 || register > 32768) {
|
if (offset < -32768 || offset > 32767) {
|
||||||
throw new IllegalArgumentException(
|
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) {
|
public static int check35cRegisterCount(int registerCount) {
|
||||||
|
@ -31,7 +31,11 @@
|
|||||||
|
|
||||||
package org.jf.dexlib2.writer;
|
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.TryBlock;
|
||||||
|
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -41,8 +45,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public interface ClassSection<StringKey extends CharSequence, TypeKey extends CharSequence, TypeListKey, ClassKey,
|
public interface ClassSection<StringKey extends CharSequence, TypeKey extends CharSequence, TypeListKey, ClassKey,
|
||||||
FieldKey, MethodKey, AnnotationSetKey, EncodedValue, DebugItem, Insn,
|
FieldKey, MethodKey, AnnotationSetKey, EncodedValue> extends IndexSection<ClassKey> {
|
||||||
ExceptionHandler extends org.jf.dexlib2.iface.ExceptionHandler> extends IndexSection<ClassKey> {
|
|
||||||
@Nonnull Collection<? extends ClassKey> getSortedClasses();
|
@Nonnull Collection<? extends ClassKey> getSortedClasses();
|
||||||
|
|
||||||
@Nullable Map.Entry<? extends ClassKey, Integer> getClassEntryByType(@Nullable TypeKey key);
|
@Nullable Map.Entry<? extends ClassKey, Integer> getClassEntryByType(@Nullable TypeKey key);
|
||||||
@ -73,9 +76,10 @@ public interface ClassSection<StringKey extends CharSequence, TypeKey extends Ch
|
|||||||
@Nullable Iterable<? extends StringKey> getParameterNames(@Nonnull MethodKey key);
|
@Nullable Iterable<? extends StringKey> getParameterNames(@Nonnull MethodKey key);
|
||||||
|
|
||||||
int getRegisterCount(@Nonnull MethodKey key);
|
int getRegisterCount(@Nonnull MethodKey key);
|
||||||
@Nullable Iterable<? extends Insn> getInstructions(@Nonnull MethodKey key);
|
@Nullable Iterable<? extends Instruction> getInstructions(@Nonnull MethodKey key);
|
||||||
@Nonnull List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks(@Nonnull MethodKey key);
|
@Nonnull List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks(@Nonnull MethodKey key);
|
||||||
@Nullable TypeKey getExceptionType(@Nonnull ExceptionHandler handler);
|
@Nullable TypeKey getExceptionType(@Nonnull ExceptionHandler handler);
|
||||||
|
@Nonnull MutableMethodImplementation makeMutableMethodImplementation(@Nonnull MethodKey key);
|
||||||
|
|
||||||
void setEncodedArrayOffset(@Nonnull ClassKey key, int offset);
|
void setEncodedArrayOffset(@Nonnull ClassKey key, int offset);
|
||||||
int getEncodedArrayOffset(@Nonnull ClassKey key);
|
int getEncodedArrayOffset(@Nonnull ClassKey key);
|
||||||
@ -89,8 +93,5 @@ public interface ClassSection<StringKey extends CharSequence, TypeKey extends Ch
|
|||||||
void setCodeItemOffset(@Nonnull MethodKey key, int offset);
|
void setCodeItemOffset(@Nonnull MethodKey key, int offset);
|
||||||
int getCodeItemOffset(@Nonnull MethodKey key);
|
int getCodeItemOffset(@Nonnull MethodKey key);
|
||||||
|
|
||||||
void setDebugItemOffset(@Nonnull MethodKey key, int offset);
|
|
||||||
int getDebugItemOffset(@Nonnull MethodKey key);
|
|
||||||
|
|
||||||
void writeDebugItem(@Nonnull DebugWriter<StringKey, TypeKey> writer, DebugItem debugItem) throws IOException;
|
void writeDebugItem(@Nonnull DebugWriter<StringKey, TypeKey> writer, DebugItem debugItem) throws IOException;
|
||||||
}
|
}
|
||||||
|
@ -36,29 +36,40 @@ import com.google.common.collect.Lists;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Ordering;
|
import com.google.common.collect.Ordering;
|
||||||
import org.jf.dexlib2.AccessFlags;
|
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.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.dexbacked.raw.*;
|
||||||
import org.jf.dexlib2.iface.Annotation;
|
import org.jf.dexlib2.iface.Annotation;
|
||||||
|
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||||
import org.jf.dexlib2.iface.TryBlock;
|
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.debug.LineNumber;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
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.instruction.formats.*;
|
||||||
import org.jf.dexlib2.iface.reference.*;
|
import org.jf.dexlib2.iface.reference.*;
|
||||||
|
import org.jf.dexlib2.util.InstructionUtil;
|
||||||
import org.jf.dexlib2.util.MethodUtil;
|
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.dexlib2.writer.util.TryListBuilder;
|
||||||
import org.jf.util.CollectionUtils;
|
import org.jf.util.CollectionUtils;
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.util.RandomAccessFileOutputStream;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -74,9 +85,7 @@ public abstract class DexWriter<
|
|||||||
AnnotationKey extends Annotation, AnnotationSetKey,
|
AnnotationKey extends Annotation, AnnotationSetKey,
|
||||||
TypeListKey,
|
TypeListKey,
|
||||||
FieldKey, MethodKey,
|
FieldKey, MethodKey,
|
||||||
EncodedValue, AnnotationElement,
|
EncodedValue, AnnotationElement> {
|
||||||
DebugItem extends org.jf.dexlib2.iface.debug.DebugItem,
|
|
||||||
Insn extends Instruction, ExceptionHandler extends org.jf.dexlib2.iface.ExceptionHandler> {
|
|
||||||
public static final int NO_INDEX = -1;
|
public static final int NO_INDEX = -1;
|
||||||
public static final int NO_OFFSET = 0;
|
public static final int NO_OFFSET = 0;
|
||||||
|
|
||||||
@ -108,7 +117,7 @@ public abstract class DexWriter<
|
|||||||
protected int numCodeItemItems = 0;
|
protected int numCodeItemItems = 0;
|
||||||
protected int numClassDataItems = 0;
|
protected int numClassDataItems = 0;
|
||||||
|
|
||||||
protected final InstructionFactory<? extends Insn, BaseReference> instructionFactory;
|
protected final InstructionFactory<BaseReference> instructionFactory;
|
||||||
|
|
||||||
protected final StringSection<StringKey, StringRef> stringSection;
|
protected final StringSection<StringKey, StringRef> stringSection;
|
||||||
protected final TypeSection<StringKey, TypeKey, TypeRef> typeSection;
|
protected final TypeSection<StringKey, TypeKey, TypeRef> typeSection;
|
||||||
@ -116,21 +125,21 @@ public abstract class DexWriter<
|
|||||||
protected final FieldSection<StringKey, TypeKey, FieldRefKey, FieldKey> fieldSection;
|
protected final FieldSection<StringKey, TypeKey, FieldRefKey, FieldKey> fieldSection;
|
||||||
protected final MethodSection<StringKey, TypeKey, ProtoKey, MethodRefKey, MethodKey> methodSection;
|
protected final MethodSection<StringKey, TypeKey, ProtoKey, MethodRefKey, MethodKey> methodSection;
|
||||||
protected final ClassSection<StringKey, TypeKey, TypeListKey, ClassKey, FieldKey, MethodKey, AnnotationSetKey,
|
protected final ClassSection<StringKey, TypeKey, TypeListKey, ClassKey, FieldKey, MethodKey, AnnotationSetKey,
|
||||||
EncodedValue, DebugItem, Insn, ExceptionHandler> classSection;
|
EncodedValue> classSection;
|
||||||
|
|
||||||
protected final TypeListSection<TypeKey, TypeListKey> typeListSection;
|
protected final TypeListSection<TypeKey, TypeListKey> typeListSection;
|
||||||
protected final AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement, EncodedValue> annotationSection;
|
protected final AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement, EncodedValue> annotationSection;
|
||||||
protected final AnnotationSetSection<AnnotationKey, AnnotationSetKey> annotationSetSection;
|
protected final AnnotationSetSection<AnnotationKey, AnnotationSetKey> annotationSetSection;
|
||||||
|
|
||||||
protected DexWriter(int api,
|
protected DexWriter(int api,
|
||||||
InstructionFactory<? extends Insn, BaseReference> instructionFactory,
|
InstructionFactory<BaseReference> instructionFactory,
|
||||||
StringSection<StringKey, StringRef> stringSection,
|
StringSection<StringKey, StringRef> stringSection,
|
||||||
TypeSection<StringKey, TypeKey, TypeRef> typeSection,
|
TypeSection<StringKey, TypeKey, TypeRef> typeSection,
|
||||||
ProtoSection<StringKey, TypeKey, ProtoKey, TypeListKey> protoSection,
|
ProtoSection<StringKey, TypeKey, ProtoKey, TypeListKey> protoSection,
|
||||||
FieldSection<StringKey, TypeKey, FieldRefKey, FieldKey> fieldSection,
|
FieldSection<StringKey, TypeKey, FieldRefKey, FieldKey> fieldSection,
|
||||||
MethodSection<StringKey, TypeKey, ProtoKey, MethodRefKey, MethodKey> methodSection,
|
MethodSection<StringKey, TypeKey, ProtoKey, MethodRefKey, MethodKey> methodSection,
|
||||||
ClassSection<StringKey, TypeKey, TypeListKey, ClassKey, FieldKey, MethodKey, AnnotationSetKey,
|
ClassSection<StringKey, TypeKey, TypeListKey, ClassKey, FieldKey, MethodKey, AnnotationSetKey,
|
||||||
EncodedValue, DebugItem, Insn, ExceptionHandler> classSection,
|
EncodedValue> classSection,
|
||||||
TypeListSection<TypeKey, TypeListKey> typeListSection,
|
TypeListSection<TypeKey, TypeListKey> typeListSection,
|
||||||
AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement,
|
AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement,
|
||||||
EncodedValue> annotationSection,
|
EncodedValue> annotationSection,
|
||||||
@ -187,14 +196,17 @@ public abstract class DexWriter<
|
|||||||
classSection.getItems().size() * ClassDefItem.ITEM_SIZE;
|
classSection.getItems().size() * ClassDefItem.ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(String path) throws IOException {
|
public void writeTo(@Nonnull DexDataStore dest) throws IOException {
|
||||||
RandomAccessFile raf = new RandomAccessFile(path, "rw");
|
this.writeTo(dest, MemoryDeferredOutputStream.getFactory());
|
||||||
raf.setLength(0);
|
}
|
||||||
|
|
||||||
|
public void writeTo(@Nonnull DexDataStore dest,
|
||||||
|
@Nonnull DeferredOutputStreamFactory tempFactory) throws IOException {
|
||||||
try {
|
try {
|
||||||
int dataSectionOffset = getDataSectionOffset();
|
int dataSectionOffset = getDataSectionOffset();
|
||||||
DexDataWriter headerWriter = outputAt(raf, 0);
|
DexDataWriter headerWriter = outputAt(dest, 0);
|
||||||
DexDataWriter indexWriter = outputAt(raf, HeaderItem.ITEM_SIZE);
|
DexDataWriter indexWriter = outputAt(dest, HeaderItem.ITEM_SIZE);
|
||||||
DexDataWriter offsetWriter = outputAt(raf, dataSectionOffset);
|
DexDataWriter offsetWriter = outputAt(dest, dataSectionOffset);
|
||||||
try {
|
try {
|
||||||
writeStrings(indexWriter, offsetWriter);
|
writeStrings(indexWriter, offsetWriter);
|
||||||
writeTypes(indexWriter);
|
writeTypes(indexWriter);
|
||||||
@ -207,8 +219,7 @@ public abstract class DexWriter<
|
|||||||
writeAnnotationSets(offsetWriter);
|
writeAnnotationSets(offsetWriter);
|
||||||
writeAnnotationSetRefs(offsetWriter);
|
writeAnnotationSetRefs(offsetWriter);
|
||||||
writeAnnotationDirectories(offsetWriter);
|
writeAnnotationDirectories(offsetWriter);
|
||||||
writeDebugItems(offsetWriter);
|
writeDebugAndCodeItems(offsetWriter, tempFactory.makeDeferredOutputStream());
|
||||||
writeCodeItems(offsetWriter);
|
|
||||||
writeClasses(indexWriter, offsetWriter);
|
writeClasses(indexWriter, offsetWriter);
|
||||||
writeMapItem(offsetWriter);
|
writeMapItem(offsetWriter);
|
||||||
writeHeader(headerWriter, dataSectionOffset, offsetWriter.getPosition());
|
writeHeader(headerWriter, dataSectionOffset, offsetWriter.getPosition());
|
||||||
@ -217,15 +228,14 @@ public abstract class DexWriter<
|
|||||||
indexWriter.close();
|
indexWriter.close();
|
||||||
offsetWriter.close();
|
offsetWriter.close();
|
||||||
}
|
}
|
||||||
FileChannel fileChannel = raf.getChannel();
|
updateSignature(dest);
|
||||||
updateSignature(fileChannel);
|
updateChecksum(dest);
|
||||||
updateChecksum(fileChannel);
|
|
||||||
} finally {
|
} finally {
|
||||||
raf.close();
|
dest.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSignature(FileChannel fileChannel) throws IOException {
|
private void updateSignature(@Nonnull DexDataStore dataStore) throws IOException {
|
||||||
MessageDigest md;
|
MessageDigest md;
|
||||||
try {
|
try {
|
||||||
md = MessageDigest.getInstance("SHA-1");
|
md = MessageDigest.getInstance("SHA-1");
|
||||||
@ -233,14 +243,12 @@ public abstract class DexWriter<
|
|||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(128 * 1024);
|
byte[] buffer = new byte[4 * 1024];
|
||||||
fileChannel.position(HeaderItem.HEADER_SIZE_OFFSET);
|
InputStream input = dataStore.readAt(HeaderItem.HEADER_SIZE_OFFSET);
|
||||||
int bytesRead = fileChannel.read(buffer);
|
int bytesRead = input.read(buffer);
|
||||||
while (bytesRead >= 0) {
|
while (bytesRead >= 0) {
|
||||||
buffer.rewind();
|
md.update(buffer, 0, bytesRead);
|
||||||
md.update(buffer);
|
bytesRead = input.read(buffer);
|
||||||
buffer.clear();
|
|
||||||
bytesRead = fileChannel.read(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] signature = md.digest();
|
byte[] signature = md.digest();
|
||||||
@ -249,38 +257,30 @@ public abstract class DexWriter<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write signature
|
// write signature
|
||||||
fileChannel.position(HeaderItem.SIGNATURE_OFFSET);
|
OutputStream output = dataStore.outputAt(HeaderItem.SIGNATURE_OFFSET);
|
||||||
fileChannel.write(ByteBuffer.wrap(signature));
|
output.write(signature);
|
||||||
|
output.close();
|
||||||
// flush
|
|
||||||
fileChannel.force(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChecksum(FileChannel fileChannel) throws IOException {
|
private void updateChecksum(@Nonnull DexDataStore dataStore) throws IOException {
|
||||||
Adler32 a32 = new Adler32();
|
Adler32 a32 = new Adler32();
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(128 * 1024);
|
byte[] buffer = new byte[4 * 1024];
|
||||||
fileChannel.position(HeaderItem.SIGNATURE_OFFSET);
|
InputStream input = dataStore.readAt(HeaderItem.SIGNATURE_OFFSET);
|
||||||
int bytesRead = fileChannel.read(buffer);
|
int bytesRead = input.read(buffer);
|
||||||
while (bytesRead >= 0) {
|
while (bytesRead >= 0) {
|
||||||
a32.update(buffer.array(), 0, bytesRead);
|
a32.update(buffer, 0, bytesRead);
|
||||||
buffer.clear();
|
bytesRead = input.read(buffer);
|
||||||
bytesRead = fileChannel.read(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// write checksum, utilizing logic in DexWriter to write the integer value properly
|
// write checksum, utilizing logic in DexWriter to write the integer value properly
|
||||||
fileChannel.position(HeaderItem.CHECKSUM_OFFSET);
|
OutputStream output = dataStore.outputAt(HeaderItem.CHECKSUM_OFFSET);
|
||||||
int checksum = (int) a32.getValue();
|
DexDataWriter.writeInt(output, (int)a32.getValue());
|
||||||
ByteArrayOutputStream checksumBuf = new ByteArrayOutputStream();
|
output.close();
|
||||||
DexDataWriter.writeInt(checksumBuf, checksum);
|
|
||||||
fileChannel.write(ByteBuffer.wrap(checksumBuf.toByteArray()));
|
|
||||||
|
|
||||||
// flush
|
|
||||||
fileChannel.force(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DexDataWriter outputAt(RandomAccessFile raf, int filePosition) throws IOException {
|
private static DexDataWriter outputAt(DexDataStore dataStore, int filePosition) throws IOException {
|
||||||
return new DexDataWriter(new RandomAccessFileOutputStream(raf, filePosition), filePosition);
|
return new DexDataWriter(dataStore.outputAt(filePosition), filePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeStrings(@Nonnull DexDataWriter indexWriter, @Nonnull DexDataWriter offsetWriter) throws IOException {
|
private void writeStrings(@Nonnull DexDataWriter indexWriter, @Nonnull DexDataWriter offsetWriter) throws IOException {
|
||||||
@ -462,7 +462,7 @@ public abstract class DexWriter<
|
|||||||
int prevIndex = 0;
|
int prevIndex = 0;
|
||||||
for (FieldKey key: fields) {
|
for (FieldKey key: fields) {
|
||||||
int index = fieldSection.getFieldIndex(key);
|
int index = fieldSection.getFieldIndex(key);
|
||||||
writer.writeUleb128(index-prevIndex);
|
writer.writeUleb128(index - prevIndex);
|
||||||
writer.writeUleb128(classSection.getFieldAccessFlags(key));
|
writer.writeUleb128(classSection.getFieldAccessFlags(key));
|
||||||
prevIndex = index;
|
prevIndex = index;
|
||||||
}
|
}
|
||||||
@ -706,10 +706,26 @@ public abstract class DexWriter<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeDebugItems(@Nonnull DexDataWriter writer) throws IOException {
|
private static class CodeItemOffset<MethodKey> {
|
||||||
debugSectionOffset = writer.getPosition();
|
@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<StringKey, TypeKey> debugWriter =
|
DebugWriter<StringKey, TypeKey> debugWriter =
|
||||||
new DebugWriter<StringKey, TypeKey>(stringSection, typeSection, writer);
|
new DebugWriter<StringKey, TypeKey>(stringSection, typeSection, offsetWriter);
|
||||||
|
|
||||||
|
DexDataWriter codeWriter = new DexDataWriter(temp, 0);
|
||||||
|
|
||||||
|
List<CodeItemOffset<MethodKey>> codeOffsets = Lists.newArrayList();
|
||||||
|
|
||||||
for (ClassKey classKey: classSection.getSortedClasses()) {
|
for (ClassKey classKey: classSection.getSortedClasses()) {
|
||||||
Collection<? extends MethodKey> directMethods = classSection.getSortedDirectMethods(classKey);
|
Collection<? extends MethodKey> directMethods = classSection.getSortedDirectMethods(classKey);
|
||||||
@ -718,284 +734,350 @@ public abstract class DexWriter<
|
|||||||
Iterable<MethodKey> methods = Iterables.concat(directMethods, virtualMethods);
|
Iterable<MethodKey> methods = Iterables.concat(directMethods, virtualMethods);
|
||||||
|
|
||||||
for (MethodKey methodKey: methods) {
|
for (MethodKey methodKey: methods) {
|
||||||
|
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks =
|
||||||
|
classSection.getTryBlocks(methodKey);
|
||||||
|
Iterable<? extends Instruction> instructions = classSection.getInstructions(methodKey);
|
||||||
Iterable<? extends DebugItem> debugItems = classSection.getDebugItems(methodKey);
|
Iterable<? extends DebugItem> debugItems = classSection.getDebugItems(methodKey);
|
||||||
Iterable<? extends StringKey> parameterNames = classSection.getParameterNames(methodKey);
|
|
||||||
|
|
||||||
int parameterCount = 0;
|
if (instructions != null && stringSection.hasJumboIndexes()) {
|
||||||
if (parameterNames != null) {
|
boolean needsFix = false;
|
||||||
int index = 0;
|
for (Instruction instruction: instructions) {
|
||||||
for (StringKey parameterName: parameterNames) {
|
if (instruction.getOpcode() == Opcode.CONST_STRING) {
|
||||||
index++;
|
if (stringSection.getItemIndex(
|
||||||
if (parameterName != null) {
|
(StringRef)((ReferenceInstruction)instruction).getReference()) >= 65536) {
|
||||||
parameterCount = index;
|
needsFix = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (debugItems == null && parameterCount == 0) {
|
if (needsFix) {
|
||||||
continue;
|
MutableMethodImplementation mutableMethodImplementation =
|
||||||
}
|
classSection.makeMutableMethodImplementation(methodKey);
|
||||||
|
fixInstructions(mutableMethodImplementation);
|
||||||
|
|
||||||
numDebugInfoItems++;
|
instructions = mutableMethodImplementation.getInstructions();
|
||||||
|
tryBlocks = mutableMethodImplementation.getTryBlocks();
|
||||||
classSection.setDebugItemOffset(methodKey, writer.getPosition());
|
debugItems = mutableMethodImplementation.getDebugItems();
|
||||||
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) {
|
int debugItemOffset = writeDebugItem(offsetWriter, debugWriter,
|
||||||
debugWriter.reset(startingLineNumber);
|
classSection.getParameterNames(methodKey), debugItems);
|
||||||
|
int codeItemOffset = writeCodeItem(codeWriter, ehBuf, methodKey, tryBlocks, instructions, debugItemOffset);
|
||||||
|
|
||||||
for (DebugItem debugItem: debugItems) {
|
if (codeItemOffset != -1) {
|
||||||
classSection.writeDebugItem(debugWriter, debugItem);
|
codeOffsets.add(new CodeItemOffset<MethodKey>(methodKey, codeItemOffset));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetWriter.align();
|
||||||
|
codeSectionOffset = offsetWriter.getPosition();
|
||||||
|
|
||||||
|
codeWriter.close();
|
||||||
|
temp.writeTo(offsetWriter);
|
||||||
|
temp.close();
|
||||||
|
|
||||||
|
for (CodeItemOffset<MethodKey> codeOffset: codeOffsets) {
|
||||||
|
classSection.setCodeItemOffset(codeOffset.method, codeSectionOffset + codeOffset.codeOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fixInstructions(@Nonnull MutableMethodImplementation methodImplementation) {
|
||||||
|
List<Instruction> instructions = methodImplementation.getInstructions();
|
||||||
|
|
||||||
|
for (int i=0; i<instructions.size(); i++) {
|
||||||
|
Instruction instruction = instructions.get(i);
|
||||||
|
|
||||||
|
if (instruction.getOpcode() == Opcode.CONST_STRING) {
|
||||||
|
if (stringSection.getItemIndex(
|
||||||
|
(StringRef)((ReferenceInstruction)instruction).getReference()) >= 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 {
|
private int writeDebugItem(@Nonnull DexDataWriter writer,
|
||||||
ByteArrayOutputStream ehBuf = new ByteArrayOutputStream();
|
@Nonnull DebugWriter<StringKey, TypeKey> debugWriter,
|
||||||
|
@Nullable Iterable<? extends StringKey> parameterNames,
|
||||||
writer.align();
|
@Nullable Iterable<? extends DebugItem> debugItems) throws IOException {
|
||||||
codeSectionOffset = writer.getPosition();
|
int parameterCount = 0;
|
||||||
for (ClassKey classKey: classSection.getSortedClasses()) {
|
if (parameterNames != null) {
|
||||||
Collection<? extends MethodKey> directMethods = classSection.getSortedDirectMethods(classKey);
|
int index = 0;
|
||||||
Collection<? extends MethodKey> virtualMethods = classSection.getSortedVirtualMethods(classKey);
|
for (StringKey parameterName: parameterNames) {
|
||||||
|
index++;
|
||||||
Iterable<MethodKey> methods = Iterables.concat(directMethods, virtualMethods);
|
if (parameterName != null) {
|
||||||
|
parameterCount = index;
|
||||||
for (MethodKey methodKey: methods) {
|
|
||||||
Iterable<? extends Insn> 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<? extends TypeKey> parameters = typeListSection.getTypes(
|
|
||||||
protoSection.getParameters(methodSection.getPrototype(methodKey)));
|
|
||||||
|
|
||||||
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = classSection.getTryBlocks(methodKey);
|
|
||||||
writer.writeUshort(MethodUtil.getParameterRegisterCount(parameters, isStatic));
|
|
||||||
|
|
||||||
if (instructions != null) {
|
|
||||||
tryBlocks = TryListBuilder.massageTryBlocks(tryBlocks);
|
|
||||||
|
|
||||||
InstructionWriteUtil<Insn, StringRef, BaseReference> instrWriteUtil =
|
|
||||||
new InstructionWriteUtil<Insn, StringRef, BaseReference>(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<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = Maps.newHashMap();
|
|
||||||
for (TryBlock<? extends ExceptionHandler> tryBlock: tryBlocks) {
|
|
||||||
exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0);
|
|
||||||
}
|
|
||||||
DexDataWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size());
|
|
||||||
|
|
||||||
for (TryBlock<? extends ExceptionHandler> 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<? extends TryBlock<? extends ExceptionHandler>> tryBlocks,
|
||||||
|
@Nullable Iterable<? extends Instruction> 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<? extends TypeKey> 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<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = Maps.newHashMap();
|
||||||
|
for (TryBlock<? extends ExceptionHandler> tryBlock: tryBlocks) {
|
||||||
|
exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0);
|
||||||
|
}
|
||||||
|
DexDataWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size());
|
||||||
|
|
||||||
|
for (TryBlock<? extends ExceptionHandler> 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() {
|
private int calcNumItems() {
|
||||||
|
@ -41,36 +41,36 @@ import javax.annotation.Nonnull;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface InstructionFactory<Insn extends Instruction, Ref extends Reference> {
|
public interface InstructionFactory<Ref extends Reference> {
|
||||||
Insn makeInstruction10t(@Nonnull Opcode opcode, int codeOffset);
|
Instruction makeInstruction10t(@Nonnull Opcode opcode, int codeOffset);
|
||||||
Insn makeInstruction10x(@Nonnull Opcode opcode);
|
Instruction makeInstruction10x(@Nonnull Opcode opcode);
|
||||||
Insn makeInstruction11n(@Nonnull Opcode opcode, int registerA, int literal);
|
Instruction makeInstruction11n(@Nonnull Opcode opcode, int registerA, int literal);
|
||||||
Insn makeInstruction11x(@Nonnull Opcode opcode, int registerA);
|
Instruction makeInstruction11x(@Nonnull Opcode opcode, int registerA);
|
||||||
Insn makeInstruction12x(@Nonnull Opcode opcode, int registerA, int registerB);
|
Instruction makeInstruction12x(@Nonnull Opcode opcode, int registerA, int registerB);
|
||||||
Insn makeInstruction20bc(@Nonnull Opcode opcode, int verificationError, @Nonnull Ref reference);
|
Instruction makeInstruction20bc(@Nonnull Opcode opcode, int verificationError, @Nonnull Ref reference);
|
||||||
Insn makeInstruction20t(@Nonnull Opcode opcode, int codeOffset);
|
Instruction makeInstruction20t(@Nonnull Opcode opcode, int codeOffset);
|
||||||
Insn makeInstruction21c(@Nonnull Opcode opcode, int registerA, @Nonnull Ref reference);
|
Instruction makeInstruction21c(@Nonnull Opcode opcode, int registerA, @Nonnull Ref reference);
|
||||||
Insn makeInstruction21ih(@Nonnull Opcode opcode, int registerA, int literal);
|
Instruction makeInstruction21ih(@Nonnull Opcode opcode, int registerA, int literal);
|
||||||
Insn makeInstruction21lh(@Nonnull Opcode opcode, int registerA, long literal);
|
Instruction makeInstruction21lh(@Nonnull Opcode opcode, int registerA, long literal);
|
||||||
Insn makeInstruction21s(@Nonnull Opcode opcode, int registerA, int literal);
|
Instruction makeInstruction21s(@Nonnull Opcode opcode, int registerA, int literal);
|
||||||
Insn makeInstruction21t(@Nonnull Opcode opcode, int registerA, int codeOffset);
|
Instruction makeInstruction21t(@Nonnull Opcode opcode, int registerA, int codeOffset);
|
||||||
Insn makeInstruction22b(@Nonnull Opcode opcode, int registerA, int registerB, int literal);
|
Instruction makeInstruction22b(@Nonnull Opcode opcode, int registerA, int registerB, int literal);
|
||||||
Insn makeInstruction22c(@Nonnull Opcode opcode, int registerA, int registerB, @Nonnull Ref reference);
|
Instruction makeInstruction22c(@Nonnull Opcode opcode, int registerA, int registerB, @Nonnull Ref reference);
|
||||||
Insn makeInstruction22s(@Nonnull Opcode opcode, int registerA, int registerB, int literal);
|
Instruction makeInstruction22s(@Nonnull Opcode opcode, int registerA, int registerB, int literal);
|
||||||
Insn makeInstruction22t(@Nonnull Opcode opcode, int registerA, int registerB, int codeOffset);
|
Instruction makeInstruction22t(@Nonnull Opcode opcode, int registerA, int registerB, int codeOffset);
|
||||||
Insn makeInstruction22x(@Nonnull Opcode opcode, int registerA, int registerB);
|
Instruction makeInstruction22x(@Nonnull Opcode opcode, int registerA, int registerB);
|
||||||
Insn makeInstruction23x(@Nonnull Opcode opcode, int registerA, int registerB, int registerC);
|
Instruction makeInstruction23x(@Nonnull Opcode opcode, int registerA, int registerB, int registerC);
|
||||||
Insn makeInstruction30t(@Nonnull Opcode opcode, int codeOffset);
|
Instruction makeInstruction30t(@Nonnull Opcode opcode, int codeOffset);
|
||||||
Insn makeInstruction31c(@Nonnull Opcode opcode, int registerA, @Nonnull Ref reference);
|
Instruction makeInstruction31c(@Nonnull Opcode opcode, int registerA, @Nonnull Ref reference);
|
||||||
Insn makeInstruction31i(@Nonnull Opcode opcode, int registerA, int literal);
|
Instruction makeInstruction31i(@Nonnull Opcode opcode, int registerA, int literal);
|
||||||
Insn makeInstruction31t(@Nonnull Opcode opcode, int registerA, int codeOffset);
|
Instruction makeInstruction31t(@Nonnull Opcode opcode, int registerA, int codeOffset);
|
||||||
Insn makeInstruction32x(@Nonnull Opcode opcode, int registerA, int registerB);
|
Instruction makeInstruction32x(@Nonnull Opcode opcode, int registerA, int registerB);
|
||||||
Insn makeInstruction35c(@Nonnull Opcode opcode, int registerCount, int registerC, int registerD, int registerE,
|
Instruction makeInstruction35c(@Nonnull Opcode opcode, int registerCount, int registerC, int registerD, int registerE,
|
||||||
int registerF, int registerG, @Nonnull Ref reference);
|
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);
|
@Nonnull Ref reference);
|
||||||
Insn makeInstruction51l(@Nonnull Opcode opcode, int registerA, long literal);
|
Instruction makeInstruction51l(@Nonnull Opcode opcode, int registerA, long literal);
|
||||||
Insn makeSparseSwitchPayload(@Nullable List<? extends SwitchElement> switchElements);
|
Instruction makeSparseSwitchPayload(@Nullable List<? extends SwitchElement> switchElements);
|
||||||
Insn makePackedSwitchPayload(@Nullable List<? extends SwitchElement> switchElements);
|
Instruction makePackedSwitchPayload(@Nullable List<? extends SwitchElement> switchElements);
|
||||||
Insn makeArrayPayload(int elementWidth, @Nullable List<Number> arrayElements);
|
Instruction makeArrayPayload(int elementWidth, @Nullable List<Number> arrayElements);
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,10 @@
|
|||||||
package org.jf.dexlib2.writer;
|
package org.jf.dexlib2.writer;
|
||||||
|
|
||||||
import org.jf.dexlib2.iface.reference.StringReference;
|
import org.jf.dexlib2.iface.reference.StringReference;
|
||||||
import org.jf.dexlib2.writer.util.InstructionWriteUtil;
|
|
||||||
|
|
||||||
public interface StringSection<StringKey, StringRef extends StringReference> extends NullableIndexSection<StringKey>,
|
import javax.annotation.Nonnull;
|
||||||
InstructionWriteUtil.StringIndexProvider<StringRef> {
|
|
||||||
|
public interface StringSection<StringKey, StringRef extends StringReference> extends NullableIndexSection<StringKey> {
|
||||||
|
int getItemIndex(@Nonnull StringRef key);
|
||||||
|
boolean hasJumboIndexes();
|
||||||
}
|
}
|
||||||
|
@ -73,10 +73,20 @@ public class BuilderClassDef extends BaseTypeReference implements ClassDef {
|
|||||||
this.interfaces = interfaces;
|
this.interfaces = interfaces;
|
||||||
this.sourceFile = sourceFile;
|
this.sourceFile = sourceFile;
|
||||||
this.annotations = annotations;
|
this.annotations = annotations;
|
||||||
this.staticFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC));
|
if (fields == null) {
|
||||||
this.instanceFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE));
|
this.staticFields = ImmutableSortedSet.of();
|
||||||
this.directMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_DIRECT));
|
this.instanceFields = ImmutableSortedSet.of();
|
||||||
this.virtualMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_VIRTUAL));
|
} 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(); }
|
@Nonnull @Override public String getType() { return type.getType(); }
|
||||||
|
@ -35,17 +35,19 @@ import com.google.common.base.Function;
|
|||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
import org.jf.dexlib2.DebugItemType;
|
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.Field;
|
||||||
|
import org.jf.dexlib2.iface.MethodImplementation;
|
||||||
import org.jf.dexlib2.iface.TryBlock;
|
import org.jf.dexlib2.iface.TryBlock;
|
||||||
import org.jf.dexlib2.iface.debug.EndLocal;
|
import org.jf.dexlib2.iface.debug.*;
|
||||||
import org.jf.dexlib2.iface.debug.LineNumber;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
import org.jf.dexlib2.iface.debug.RestartLocal;
|
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.iface.value.EncodedValue;
|
||||||
import org.jf.dexlib2.util.EncodedValueUtils;
|
import org.jf.dexlib2.util.EncodedValueUtils;
|
||||||
import org.jf.dexlib2.writer.ClassSection;
|
import org.jf.dexlib2.writer.ClassSection;
|
||||||
import org.jf.dexlib2.writer.DebugWriter;
|
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.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue;
|
||||||
import org.jf.util.AbstractForwardSequentialList;
|
import org.jf.util.AbstractForwardSequentialList;
|
||||||
import org.jf.util.CollectionUtils;
|
import org.jf.util.CollectionUtils;
|
||||||
@ -59,8 +61,7 @@ import java.util.Map.Entry;
|
|||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
public class BuilderClassPool implements ClassSection<BuilderStringReference, BuilderTypeReference, BuilderTypeList,
|
public class BuilderClassPool implements ClassSection<BuilderStringReference, BuilderTypeReference, BuilderTypeList,
|
||||||
BuilderClassDef, BuilderField, BuilderMethod, BuilderAnnotationSet, BuilderEncodedValue, BuilderDebugItem,
|
BuilderClassDef, BuilderField, BuilderMethod, BuilderAnnotationSet, BuilderEncodedValue> {
|
||||||
BuilderInstruction, BuilderExceptionHandler> {
|
|
||||||
@Nonnull private final ConcurrentMap<String, BuilderClassDef> internedItems =
|
@Nonnull private final ConcurrentMap<String, BuilderClassDef> internedItems =
|
||||||
Maps.newConcurrentMap();
|
Maps.newConcurrentMap();
|
||||||
|
|
||||||
@ -266,8 +267,8 @@ public class BuilderClassPool implements ClassSection<BuilderStringReference, Bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable @Override
|
@Nullable @Override
|
||||||
public Iterable<? extends BuilderDebugItem> getDebugItems(@Nonnull BuilderMethod builderMethod) {
|
public Iterable<? extends DebugItem> getDebugItems(@Nonnull BuilderMethod builderMethod) {
|
||||||
BuilderMethodImplementation impl = builderMethod.getImplementation();
|
MethodImplementation impl = builderMethod.getImplementation();
|
||||||
if (impl == null) {
|
if (impl == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -284,16 +285,16 @@ public class BuilderClassPool implements ClassSection<BuilderStringReference, Bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public int getRegisterCount(@Nonnull BuilderMethod builderMethod) {
|
@Override public int getRegisterCount(@Nonnull BuilderMethod builderMethod) {
|
||||||
BuilderMethodImplementation impl = builderMethod.getImplementation();
|
MethodImplementation impl = builderMethod.getImplementation();
|
||||||
if (impl == null) {
|
if (impl == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return impl.registerCount;
|
return impl.getRegisterCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable @Override
|
@Nullable @Override
|
||||||
public Iterable<? extends BuilderInstruction> getInstructions(@Nonnull BuilderMethod builderMethod) {
|
public Iterable<? extends Instruction> getInstructions(@Nonnull BuilderMethod builderMethod) {
|
||||||
BuilderMethodImplementation impl = builderMethod.getImplementation();
|
MethodImplementation impl = builderMethod.getImplementation();
|
||||||
if (impl == null) {
|
if (impl == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -301,16 +302,25 @@ public class BuilderClassPool implements ClassSection<BuilderStringReference, Bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull @Override
|
@Nonnull @Override
|
||||||
public List<? extends TryBlock<? extends BuilderExceptionHandler>> getTryBlocks(@Nonnull BuilderMethod builderMethod) {
|
public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks(@Nonnull BuilderMethod builderMethod) {
|
||||||
BuilderMethodImplementation impl = builderMethod.getImplementation();
|
MethodImplementation impl = builderMethod.getImplementation();
|
||||||
if (impl == null) {
|
if (impl == null) {
|
||||||
return ImmutableList.of();
|
return ImmutableList.of();
|
||||||
}
|
}
|
||||||
return impl.getTryBlocks();
|
return impl.getTryBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable @Override public BuilderTypeReference getExceptionType(@Nonnull BuilderExceptionHandler handler) {
|
@Nullable @Override public BuilderTypeReference getExceptionType(@Nonnull ExceptionHandler handler) {
|
||||||
return handler.exceptionType;
|
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) {
|
@Override public void setEncodedArrayOffset(@Nonnull BuilderClassDef builderClassDef, int offset) {
|
||||||
@ -345,25 +355,41 @@ public class BuilderClassPool implements ClassSection<BuilderStringReference, Bu
|
|||||||
return builderMethod.codeItemOffset;
|
return builderMethod.codeItemOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void setDebugItemOffset(@Nonnull BuilderMethod builderMethod, int offset) {
|
@Nullable private BuilderStringReference checkStringReference(@Nullable StringReference stringReference) {
|
||||||
builderMethod.debugInfoOffset = offset;
|
if (stringReference == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (BuilderStringReference)stringReference;
|
||||||
|
} catch (ClassCastException ex) {
|
||||||
|
throw new IllegalStateException("Only StringReference instances returned by " +
|
||||||
|
"DexBuilder.internStringReference or DexBuilder.internNullableStringReference may be used.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public int getDebugItemOffset(@Nonnull BuilderMethod builderMethod) {
|
@Nullable private BuilderTypeReference checkTypeReference(@Nullable TypeReference typeReference) {
|
||||||
return builderMethod.debugInfoOffset;
|
if (typeReference == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (BuilderTypeReference)typeReference;
|
||||||
|
} catch (ClassCastException ex) {
|
||||||
|
throw new IllegalStateException("Only TypeReference instances returned by " +
|
||||||
|
"DexBuilder.internTypeReference or DexBuilder.internNullableTypeReference may be used.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeDebugItem(@Nonnull DebugWriter<BuilderStringReference, BuilderTypeReference> writer,
|
public void writeDebugItem(@Nonnull DebugWriter<BuilderStringReference, BuilderTypeReference> writer,
|
||||||
BuilderDebugItem debugItem) throws IOException {
|
DebugItem debugItem) throws IOException {
|
||||||
switch (debugItem.getDebugItemType()) {
|
switch (debugItem.getDebugItemType()) {
|
||||||
case DebugItemType.START_LOCAL: {
|
case DebugItemType.START_LOCAL: {
|
||||||
BuilderStartLocal startLocal = (BuilderStartLocal)debugItem;
|
StartLocal startLocal = (StartLocal)debugItem;
|
||||||
writer.writeStartLocal(startLocal.getCodeAddress(),
|
writer.writeStartLocal(startLocal.getCodeAddress(),
|
||||||
startLocal.register,
|
startLocal.getRegister(),
|
||||||
startLocal.name,
|
checkStringReference(startLocal.getNameReference()),
|
||||||
startLocal.type,
|
checkTypeReference(startLocal.getTypeReference()),
|
||||||
startLocal.signature);
|
checkStringReference(startLocal.getSignatureReference()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DebugItemType.END_LOCAL: {
|
case DebugItemType.END_LOCAL: {
|
||||||
@ -390,8 +416,9 @@ public class BuilderClassPool implements ClassSection<BuilderStringReference, Bu
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DebugItemType.SET_SOURCE_FILE: {
|
case DebugItemType.SET_SOURCE_FILE: {
|
||||||
BuilderSetSourceFile setSourceFile = (BuilderSetSourceFile)debugItem;
|
SetSourceFile setSourceFile = (SetSourceFile)debugItem;
|
||||||
writer.writeSetSourceFile(setSourceFile.getCodeAddress(), setSourceFile.sourceFile);
|
writer.writeSetSourceFile(setSourceFile.getCodeAddress(),
|
||||||
|
checkStringReference(setSourceFile.getSourceFileReference()));
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new ExceptionWithContext("Unexpected debug item type: %d", debugItem.getDebugItemType());
|
throw new ExceptionWithContext("Unexpected debug item type: %d", debugItem.getDebugItemType());
|
||||||
|
@ -1,168 +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.DebugItemType;
|
|
||||||
import org.jf.dexlib2.iface.debug.*;
|
|
||||||
import org.jf.dexlib2.immutable.debug.ImmutableEpilogueBegin;
|
|
||||||
import org.jf.dexlib2.immutable.debug.ImmutableLineNumber;
|
|
||||||
import org.jf.dexlib2.immutable.debug.ImmutablePrologueEnd;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public abstract interface BuilderDebugItem extends DebugItem {
|
|
||||||
abstract static class BaseBuilderDebugItem implements BuilderDebugItem {
|
|
||||||
final int codeAddress;
|
|
||||||
|
|
||||||
public BaseBuilderDebugItem(int codeAddress) {
|
|
||||||
this.codeAddress = codeAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getCodeAddress() { return codeAddress; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BuilderStartLocal extends BaseBuilderDebugItem implements StartLocal {
|
|
||||||
final int register;
|
|
||||||
@Nullable final BuilderStringReference name;
|
|
||||||
@Nullable final BuilderTypeReference type;
|
|
||||||
@Nullable final BuilderStringReference signature;
|
|
||||||
|
|
||||||
BuilderStartLocal(int codeAddress,
|
|
||||||
int register,
|
|
||||||
@Nullable BuilderStringReference name,
|
|
||||||
@Nullable BuilderTypeReference type,
|
|
||||||
@Nullable BuilderStringReference signature) {
|
|
||||||
super(codeAddress);
|
|
||||||
this.register = register;
|
|
||||||
this.name = name;
|
|
||||||
this.type = type;
|
|
||||||
this.signature = signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getRegister() { return register; }
|
|
||||||
@Nullable @Override public String getName() { return name==null?null:name.getString(); }
|
|
||||||
@Nullable @Override public String getType() { return type==null?null:type.getType(); }
|
|
||||||
@Nullable @Override public String getSignature() { return signature==null?null:signature.getString(); }
|
|
||||||
|
|
||||||
@Override public int getDebugItemType() { return DebugItemType.START_LOCAL; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BuilderEndLocal extends BaseBuilderDebugItem implements EndLocal {
|
|
||||||
private final int register;
|
|
||||||
|
|
||||||
BuilderEndLocal(int codeAddress, int register) {
|
|
||||||
super(codeAddress);
|
|
||||||
this.register = register;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getRegister() {
|
|
||||||
return register;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getDebugItemType() {
|
|
||||||
return DebugItemType.END_LOCAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public String getName() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public String getType() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public String getSignature() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BuilderRestartLocal extends BaseBuilderDebugItem implements RestartLocal {
|
|
||||||
private final int register;
|
|
||||||
|
|
||||||
BuilderRestartLocal(int codeAddress, int register) {
|
|
||||||
super(codeAddress);
|
|
||||||
this.register = register;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getRegister() {
|
|
||||||
return register;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getDebugItemType() {
|
|
||||||
return DebugItemType.RESTART_LOCAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public String getName() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public String getType() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public String getSignature() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BuilderPrologueEnd extends ImmutablePrologueEnd implements BuilderDebugItem {
|
|
||||||
BuilderPrologueEnd(int codeAddress) {
|
|
||||||
super(codeAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BuilderEpilogueBegin extends ImmutableEpilogueBegin implements BuilderDebugItem {
|
|
||||||
BuilderEpilogueBegin(int codeAddress) {
|
|
||||||
super(codeAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BuilderLineNumber extends ImmutableLineNumber implements BuilderDebugItem {
|
|
||||||
BuilderLineNumber(int codeAddress, int lineNumber) {
|
|
||||||
super(codeAddress, lineNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BuilderSetSourceFile extends BaseBuilderDebugItem implements SetSourceFile {
|
|
||||||
@Nullable final BuilderStringReference sourceFile;
|
|
||||||
|
|
||||||
BuilderSetSourceFile(int codeAddress,
|
|
||||||
@Nullable BuilderStringReference sourceFile) {
|
|
||||||
super(codeAddress);
|
|
||||||
this.sourceFile = sourceFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public String getSourceFile() { return sourceFile==null?null:sourceFile.getString(); }
|
|
||||||
|
|
||||||
@Override public int getDebugItemType() { return DebugItemType.SET_SOURCE_FILE; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -49,6 +49,7 @@ public interface BuilderInstruction extends Instruction {
|
|||||||
@Nonnull protected final Opcode opcode;
|
@Nonnull protected final Opcode opcode;
|
||||||
|
|
||||||
public BaseBuilderInstruction(@Nonnull Opcode opcode) {
|
public BaseBuilderInstruction(@Nonnull Opcode opcode) {
|
||||||
|
Preconditions.checkFormat(opcode, getFormat());
|
||||||
this.opcode = opcode;
|
this.opcode = opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +104,6 @@ public interface BuilderInstruction extends Instruction {
|
|||||||
int verificationError,
|
int verificationError,
|
||||||
@Nonnull BuilderReference reference) {
|
@Nonnull BuilderReference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.verificationError = Preconditions.checkVerificationError(verificationError);
|
this.verificationError = Preconditions.checkVerificationError(verificationError);
|
||||||
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
||||||
}
|
}
|
||||||
@ -130,7 +130,6 @@ public interface BuilderInstruction extends Instruction {
|
|||||||
int registerA,
|
int registerA,
|
||||||
@Nonnull BuilderReference reference) {
|
@Nonnull BuilderReference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
||||||
}
|
}
|
||||||
@ -183,7 +182,6 @@ public interface BuilderInstruction extends Instruction {
|
|||||||
int registerB,
|
int registerB,
|
||||||
@Nonnull BuilderReference reference) {
|
@Nonnull BuilderReference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
this.registerA = Preconditions.checkNibbleRegister(registerA);
|
||||||
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
this.registerB = Preconditions.checkNibbleRegister(registerB);
|
||||||
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
||||||
@ -236,7 +234,6 @@ public interface BuilderInstruction extends Instruction {
|
|||||||
int registerA,
|
int registerA,
|
||||||
@Nonnull BuilderReference reference) {
|
@Nonnull BuilderReference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerA = Preconditions.checkByteRegister(registerA);
|
this.registerA = Preconditions.checkByteRegister(registerA);
|
||||||
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
||||||
}
|
}
|
||||||
@ -285,7 +282,6 @@ public interface BuilderInstruction extends Instruction {
|
|||||||
int registerG,
|
int registerG,
|
||||||
@Nonnull BuilderReference reference) {
|
@Nonnull BuilderReference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
||||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||||
@ -319,8 +315,6 @@ public interface BuilderInstruction extends Instruction {
|
|||||||
int registerCount,
|
int registerCount,
|
||||||
@Nonnull BuilderReference reference) {
|
@Nonnull BuilderReference reference) {
|
||||||
super(opcode);
|
super(opcode);
|
||||||
|
|
||||||
Preconditions.checkFormat(opcode, FORMAT);
|
|
||||||
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
||||||
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
||||||
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
this.reference = Preconditions.checkReference(opcode.referenceType, reference);
|
||||||
|
@ -40,7 +40,7 @@ import javax.annotation.Nonnull;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class BuilderInstructionFactory implements InstructionFactory<BuilderInstruction, BuilderReference> {
|
public class BuilderInstructionFactory implements InstructionFactory<BuilderReference> {
|
||||||
public static final BuilderInstructionFactory INSTANCE = new BuilderInstructionFactory();
|
public static final BuilderInstructionFactory INSTANCE = new BuilderInstructionFactory();
|
||||||
|
|
||||||
private BuilderInstructionFactory() {
|
private BuilderInstructionFactory() {
|
||||||
|
@ -33,6 +33,7 @@ package org.jf.dexlib2.writer.builder;
|
|||||||
|
|
||||||
import org.jf.dexlib2.base.reference.BaseMethodReference;
|
import org.jf.dexlib2.base.reference.BaseMethodReference;
|
||||||
import org.jf.dexlib2.iface.Method;
|
import org.jf.dexlib2.iface.Method;
|
||||||
|
import org.jf.dexlib2.iface.MethodImplementation;
|
||||||
import org.jf.dexlib2.writer.DexWriter;
|
import org.jf.dexlib2.writer.DexWriter;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -44,17 +45,16 @@ public class BuilderMethod extends BaseMethodReference implements Method {
|
|||||||
@Nonnull final List<? extends BuilderMethodParameter> parameters;
|
@Nonnull final List<? extends BuilderMethodParameter> parameters;
|
||||||
final int accessFlags;
|
final int accessFlags;
|
||||||
@Nonnull final BuilderAnnotationSet annotations;
|
@Nonnull final BuilderAnnotationSet annotations;
|
||||||
@Nullable final BuilderMethodImplementation methodImplementation;
|
@Nullable final MethodImplementation methodImplementation;
|
||||||
|
|
||||||
int annotationSetRefListOffset = DexWriter.NO_OFFSET;
|
int annotationSetRefListOffset = DexWriter.NO_OFFSET;
|
||||||
int codeItemOffset = DexWriter.NO_OFFSET;
|
int codeItemOffset = DexWriter.NO_OFFSET;
|
||||||
int debugInfoOffset = DexWriter.NO_OFFSET;
|
|
||||||
|
|
||||||
BuilderMethod(@Nonnull BuilderMethodReference methodReference,
|
BuilderMethod(@Nonnull BuilderMethodReference methodReference,
|
||||||
@Nonnull List<? extends BuilderMethodParameter> parameters,
|
@Nonnull List<? extends BuilderMethodParameter> parameters,
|
||||||
int accessFlags,
|
int accessFlags,
|
||||||
@Nonnull BuilderAnnotationSet annotations,
|
@Nonnull BuilderAnnotationSet annotations,
|
||||||
@Nullable BuilderMethodImplementation methodImplementation) {
|
@Nullable MethodImplementation methodImplementation) {
|
||||||
this.methodReference = methodReference;
|
this.methodReference = methodReference;
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
this.accessFlags = accessFlags;
|
this.accessFlags = accessFlags;
|
||||||
@ -69,5 +69,5 @@ public class BuilderMethod extends BaseMethodReference implements Method {
|
|||||||
@Override @Nonnull public List<? extends BuilderMethodParameter> getParameters() { return parameters; }
|
@Override @Nonnull public List<? extends BuilderMethodParameter> getParameters() { return parameters; }
|
||||||
@Override public int getAccessFlags() { return accessFlags; }
|
@Override public int getAccessFlags() { return accessFlags; }
|
||||||
@Override @Nonnull public BuilderAnnotationSet getAnnotations() { return annotations; }
|
@Override @Nonnull public BuilderAnnotationSet getAnnotations() { return annotations; }
|
||||||
@Override @Nullable public BuilderMethodImplementation getImplementation() { return methodImplementation; }
|
@Override @Nullable public MethodImplementation getImplementation() { return methodImplementation; }
|
||||||
}
|
}
|
||||||
|
@ -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<? extends BuilderInstruction> instructions;
|
|
||||||
@Nonnull protected final List<? extends BuilderTryBlock> tryBlocks;
|
|
||||||
@Nonnull protected final List<? extends BuilderDebugItem> debugItems;
|
|
||||||
|
|
||||||
public BuilderMethodImplementation(int registerCount,
|
|
||||||
@Nonnull List<? extends BuilderInstruction> instructions,
|
|
||||||
@Nonnull List<? extends BuilderTryBlock> tryBlocks,
|
|
||||||
@Nonnull List<? extends BuilderDebugItem> debugItems) {
|
|
||||||
this.registerCount = registerCount;
|
|
||||||
this.instructions = instructions;
|
|
||||||
this.tryBlocks = tryBlocks;
|
|
||||||
this.debugItems = debugItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getRegisterCount() { return registerCount; }
|
|
||||||
@Nonnull @Override public List<? extends BuilderInstruction> getInstructions() { return instructions; }
|
|
||||||
@Nonnull @Override public List<? extends BuilderTryBlock> getTryBlocks() { return tryBlocks; }
|
|
||||||
@Nonnull @Override public List<? extends BuilderDebugItem> getDebugItems() { return debugItems; }
|
|
||||||
}
|
|
@ -69,6 +69,10 @@ class BuilderStringPool implements StringSection<BuilderStringReference, Builder
|
|||||||
return key.index;
|
return key.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean hasJumboIndexes() {
|
||||||
|
return internedItems.size() > 65536;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull @Override public Collection<? extends Entry<? extends BuilderStringReference, Integer>> getItems() {
|
@Nonnull @Override public Collection<? extends Entry<? extends BuilderStringReference, Integer>> getItems() {
|
||||||
return new BuilderMapEntryCollection<BuilderStringReference>(internedItems.values()) {
|
return new BuilderMapEntryCollection<BuilderStringReference>(internedItems.values()) {
|
||||||
@Override protected int getValue(@Nonnull BuilderStringReference key) {
|
@Override protected int getValue(@Nonnull BuilderStringReference key) {
|
||||||
|
@ -37,11 +37,11 @@ import com.google.common.collect.Iterators;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.jf.dexlib2.ValueType;
|
import org.jf.dexlib2.ValueType;
|
||||||
import org.jf.dexlib2.iface.Annotation;
|
import org.jf.dexlib2.iface.Annotation;
|
||||||
|
import org.jf.dexlib2.iface.MethodImplementation;
|
||||||
import org.jf.dexlib2.iface.MethodParameter;
|
import org.jf.dexlib2.iface.MethodParameter;
|
||||||
import org.jf.dexlib2.iface.reference.*;
|
import org.jf.dexlib2.iface.reference.*;
|
||||||
import org.jf.dexlib2.iface.value.*;
|
import org.jf.dexlib2.iface.value.*;
|
||||||
import org.jf.dexlib2.writer.DexWriter;
|
import org.jf.dexlib2.writer.DexWriter;
|
||||||
import org.jf.dexlib2.writer.builder.BuilderDebugItem.*;
|
|
||||||
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.*;
|
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.*;
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ import java.util.Set;
|
|||||||
public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringReference, BuilderTypeReference,
|
public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringReference, BuilderTypeReference,
|
||||||
BuilderTypeReference, BuilderProtoReference, BuilderFieldReference, BuilderMethodReference, BuilderReference,
|
BuilderTypeReference, BuilderProtoReference, BuilderFieldReference, BuilderMethodReference, BuilderReference,
|
||||||
BuilderClassDef, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList, BuilderField, BuilderMethod,
|
BuilderClassDef, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList, BuilderField, BuilderMethod,
|
||||||
BuilderEncodedValue, BuilderAnnotationElement, BuilderDebugItem, BuilderInstruction, BuilderExceptionHandler> {
|
BuilderEncodedValue, BuilderAnnotationElement> {
|
||||||
|
|
||||||
private final BuilderContext context;
|
private final BuilderContext context;
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
|
|||||||
@Nonnull String returnType,
|
@Nonnull String returnType,
|
||||||
int accessFlags,
|
int accessFlags,
|
||||||
@Nonnull Set<? extends Annotation> annotations,
|
@Nonnull Set<? extends Annotation> annotations,
|
||||||
@Nullable BuilderMethodImplementation methodImplementation) {
|
@Nullable MethodImplementation methodImplementation) {
|
||||||
if (parameters == null) {
|
if (parameters == null) {
|
||||||
parameters = ImmutableList.of();
|
parameters = ImmutableList.of();
|
||||||
}
|
}
|
||||||
@ -106,26 +106,6 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
|
|||||||
methodImplementation);
|
methodImplementation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull public BuilderMethodImplementation internMethodImplementation(
|
|
||||||
int registerCount,
|
|
||||||
@Nullable List<? extends BuilderInstruction> instructions,
|
|
||||||
@Nullable List<? extends BuilderTryBlock> tryBlocks,
|
|
||||||
@Nullable List<? extends BuilderDebugItem> 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,
|
@Nonnull public BuilderClassDef internClassDef(@Nonnull String type,
|
||||||
int accessFlags,
|
int accessFlags,
|
||||||
@Nullable String superclass,
|
@Nullable String superclass,
|
||||||
@ -164,10 +144,24 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
|
|||||||
return context.stringPool.internString(string);
|
return context.stringPool.internString(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable public BuilderStringReference internNullableStringReference(@Nullable String string) {
|
||||||
|
if (string != null) {
|
||||||
|
return internStringReference(string);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull public BuilderTypeReference internTypeReference(@Nonnull String type) {
|
@Nonnull public BuilderTypeReference internTypeReference(@Nonnull String type) {
|
||||||
return context.typePool.internType(type);
|
return context.typePool.internType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable public BuilderTypeReference internNullableTypeReference(@Nullable String type) {
|
||||||
|
if (type != null) {
|
||||||
|
return internTypeReference(type);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull public BuilderFieldReference internFieldReference(@Nonnull FieldReference field) {
|
@Nonnull public BuilderFieldReference internFieldReference(@Nonnull FieldReference field) {
|
||||||
return context.fieldPool.internField(field);
|
return context.fieldPool.internField(field);
|
||||||
}
|
}
|
||||||
@ -191,7 +185,7 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
|
|||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Could not determine type of reference");
|
throw new IllegalArgumentException("Could not determine type of reference");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull private List<BuilderMethodParameter> internMethodParameters(
|
@Nonnull private List<BuilderMethodParameter> internMethodParameters(
|
||||||
@Nullable List<? extends MethodParameter> methodParameters) {
|
@Nullable List<? extends MethodParameter> methodParameters) {
|
||||||
if (methodParameters == null) {
|
if (methodParameters == null) {
|
||||||
@ -212,46 +206,6 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
|
|||||||
context.annotationSetPool.internAnnotationSet(methodParameter.getAnnotations()));
|
context.annotationSetPool.internAnnotationSet(methodParameter.getAnnotations()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull public BuilderExceptionHandler internExceptionHandler(@Nullable String exceptionType,
|
|
||||||
int handlerCodeAddress) {
|
|
||||||
return new BuilderExceptionHandler(context.typePool.internNullableType(exceptionType),
|
|
||||||
handlerCodeAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull public BuilderStartLocal internStartLocal(int codeAddress, int register, @Nullable String name,
|
|
||||||
@Nullable String type, @Nullable String signature) {
|
|
||||||
return new BuilderStartLocal(codeAddress,
|
|
||||||
register,
|
|
||||||
context.stringPool.internNullableString(name),
|
|
||||||
context.typePool.internNullableType(type),
|
|
||||||
context.stringPool.internNullableString(signature));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull public BuilderSetSourceFile internSetSourceFile(int codeAddress, @Nullable String sourceFile) {
|
|
||||||
return new BuilderSetSourceFile(codeAddress,
|
|
||||||
context.stringPool.internNullableString(sourceFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull public BuilderEndLocal internEndLocal(int codeAddress, int register) {
|
|
||||||
return new BuilderEndLocal(codeAddress, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull public BuilderRestartLocal internRestartLocal(int codeAddress, int register) {
|
|
||||||
return new BuilderRestartLocal(codeAddress, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull public BuilderPrologueEnd internPrologueEnd(int codeAddress) {
|
|
||||||
return new BuilderPrologueEnd(codeAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull public BuilderEpilogueBegin internEpilogueBegin(int codeAddress) {
|
|
||||||
return new BuilderEpilogueBegin(codeAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull public BuilderLineNumber internLineNumber(int codeAddress, int lineNumber) {
|
|
||||||
return new BuilderLineNumber(codeAddress, lineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer,
|
@Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer,
|
||||||
@Nonnull BuilderEncodedValue encodedValue) throws IOException {
|
@Nonnull BuilderEncodedValue encodedValue) throws IOException {
|
||||||
switch (encodedValue.getValueType()) {
|
switch (encodedValue.getValueType()) {
|
||||||
|
@ -36,6 +36,7 @@ import com.google.common.base.Predicate;
|
|||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
import org.jf.dexlib2.DebugItemType;
|
import org.jf.dexlib2.DebugItemType;
|
||||||
import org.jf.dexlib2.ReferenceType;
|
import org.jf.dexlib2.ReferenceType;
|
||||||
|
import org.jf.dexlib2.builder.MutableMethodImplementation;
|
||||||
import org.jf.dexlib2.iface.*;
|
import org.jf.dexlib2.iface.*;
|
||||||
import org.jf.dexlib2.iface.debug.*;
|
import org.jf.dexlib2.iface.debug.*;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
@ -59,8 +60,7 @@ import java.util.Map.Entry;
|
|||||||
|
|
||||||
public class ClassPool implements ClassSection<CharSequence, CharSequence,
|
public class ClassPool implements ClassSection<CharSequence, CharSequence,
|
||||||
TypeListPool.Key<? extends Collection<? extends CharSequence>>, PoolClassDef, Field, PoolMethod,
|
TypeListPool.Key<? extends Collection<? extends CharSequence>>, PoolClassDef, Field, PoolMethod,
|
||||||
Set<? extends Annotation>,
|
Set<? extends Annotation>, EncodedValue> {
|
||||||
EncodedValue, DebugItem, Instruction, ExceptionHandler> {
|
|
||||||
@Nonnull private HashMap<String, PoolClassDef> internedItems = Maps.newHashMap();
|
@Nonnull private HashMap<String, PoolClassDef> internedItems = Maps.newHashMap();
|
||||||
|
|
||||||
@Nonnull private final StringPool stringPool;
|
@Nonnull private final StringPool stringPool;
|
||||||
@ -434,6 +434,11 @@ public class ClassPool implements ClassSection<CharSequence, CharSequence,
|
|||||||
return handler.getExceptionType();
|
return handler.getExceptionType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull @Override
|
||||||
|
public MutableMethodImplementation makeMutableMethodImplementation(@Nonnull PoolMethod poolMethod) {
|
||||||
|
return new MutableMethodImplementation(poolMethod.getImplementation());
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void setEncodedArrayOffset(@Nonnull PoolClassDef classDef, int offset) {
|
@Override public void setEncodedArrayOffset(@Nonnull PoolClassDef classDef, int offset) {
|
||||||
classDef.encodedArrayOffset = offset;
|
classDef.encodedArrayOffset = offset;
|
||||||
}
|
}
|
||||||
@ -466,14 +471,6 @@ public class ClassPool implements ClassSection<CharSequence, CharSequence,
|
|||||||
return method.codeItemOffset;
|
return method.codeItemOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void setDebugItemOffset(@Nonnull PoolMethod method, int offset) {
|
|
||||||
method.debugInfoOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getDebugItemOffset(@Nonnull PoolMethod method) {
|
|
||||||
return method.debugInfoOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void writeDebugItem(@Nonnull DebugWriter<CharSequence, CharSequence> writer,
|
@Override public void writeDebugItem(@Nonnull DebugWriter<CharSequence, CharSequence> writer,
|
||||||
DebugItem debugItem) throws IOException {
|
DebugItem debugItem) throws IOException {
|
||||||
switch (debugItem.getDebugItemType()) {
|
switch (debugItem.getDebugItemType()) {
|
||||||
|
@ -32,17 +32,20 @@
|
|||||||
package org.jf.dexlib2.writer.pool;
|
package org.jf.dexlib2.writer.pool;
|
||||||
|
|
||||||
import org.jf.dexlib2.ValueType;
|
import org.jf.dexlib2.ValueType;
|
||||||
import org.jf.dexlib2.iface.*;
|
import org.jf.dexlib2.iface.Annotation;
|
||||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
import org.jf.dexlib2.iface.AnnotationElement;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.ClassDef;
|
||||||
|
import org.jf.dexlib2.iface.Field;
|
||||||
import org.jf.dexlib2.iface.reference.*;
|
import org.jf.dexlib2.iface.reference.*;
|
||||||
import org.jf.dexlib2.iface.value.*;
|
import org.jf.dexlib2.iface.value.*;
|
||||||
import org.jf.dexlib2.immutable.instruction.ImmutableInstructionFactory;
|
import org.jf.dexlib2.immutable.instruction.ImmutableInstructionFactory;
|
||||||
import org.jf.dexlib2.writer.DexWriter;
|
import org.jf.dexlib2.writer.DexWriter;
|
||||||
|
import org.jf.dexlib2.writer.io.FileDataStore;
|
||||||
import org.jf.dexlib2.writer.pool.ProtoPool.Key;
|
import org.jf.dexlib2.writer.pool.ProtoPool.Key;
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -51,7 +54,7 @@ public class DexPool extends DexWriter<CharSequence, StringReference, CharSequen
|
|||||||
FieldReference, MethodReference, Reference, PoolClassDef,
|
FieldReference, MethodReference, Reference, PoolClassDef,
|
||||||
Annotation, Set<? extends Annotation>,
|
Annotation, Set<? extends Annotation>,
|
||||||
TypeListPool.Key<? extends Collection<? extends CharSequence>>, Field, PoolMethod,
|
TypeListPool.Key<? extends Collection<? extends CharSequence>>, Field, PoolMethod,
|
||||||
EncodedValue, AnnotationElement, DebugItem, Instruction, ExceptionHandler> {
|
EncodedValue, AnnotationElement> {
|
||||||
|
|
||||||
public static DexPool makeDexPool() {
|
public static DexPool makeDexPool() {
|
||||||
return makeDexPool(15);
|
return makeDexPool(15);
|
||||||
@ -85,7 +88,7 @@ public class DexPool extends DexWriter<CharSequence, StringReference, CharSequen
|
|||||||
for (ClassDef classDef: input.getClasses()) {
|
for (ClassDef classDef: input.getClasses()) {
|
||||||
((ClassPool)dexPool.classSection).intern(classDef);
|
((ClassPool)dexPool.classSection).intern(classDef);
|
||||||
}
|
}
|
||||||
dexPool.writeTo(path);
|
dexPool.writeTo(new FileDataStore(new File(path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer,
|
@Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer,
|
||||||
|
@ -48,7 +48,6 @@ class PoolMethod extends BaseMethodReference implements Method {
|
|||||||
@Nonnull private final Method method;
|
@Nonnull private final Method method;
|
||||||
protected int annotationSetRefListOffset = DexPool.NO_OFFSET;
|
protected int annotationSetRefListOffset = DexPool.NO_OFFSET;
|
||||||
protected int codeItemOffset = DexPool.NO_OFFSET;
|
protected int codeItemOffset = DexPool.NO_OFFSET;
|
||||||
protected int debugInfoOffset = DexPool.NO_OFFSET;
|
|
||||||
|
|
||||||
public static final Function<Method, PoolMethod> TRANSFORM = new Function<Method, PoolMethod>() {
|
public static final Function<Method, PoolMethod> TRANSFORM = new Function<Method, PoolMethod>() {
|
||||||
@Override public PoolMethod apply(Method method) {
|
@Override public PoolMethod apply(Method method) {
|
||||||
|
@ -33,6 +33,7 @@ package org.jf.dexlib2.writer.pool;
|
|||||||
|
|
||||||
import org.jf.dexlib2.iface.reference.StringReference;
|
import org.jf.dexlib2.iface.reference.StringReference;
|
||||||
import org.jf.dexlib2.writer.StringSection;
|
import org.jf.dexlib2.writer.StringSection;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -49,6 +50,14 @@ public class StringPool extends StringTypeBasePool implements StringSection<Char
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public int getItemIndex(@Nonnull StringReference key) {
|
@Override public int getItemIndex(@Nonnull StringReference key) {
|
||||||
return getItemIndex(key.getString());
|
Integer index = internedItems.get(key.toString());
|
||||||
|
if (index == null) {
|
||||||
|
throw new ExceptionWithContext("Item not found.: %s", key.toString());
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean hasJumboIndexes() {
|
||||||
|
return internedItems.size() > 65536;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<Insn extends Instruction, StringRef extends StringReference,
|
|
||||||
BaseReference extends Reference> {
|
|
||||||
private final StringIndexProvider<StringRef> stringIndexProvider;
|
|
||||||
private final InstructionFactory<? extends Insn, BaseReference> instructionFactory;
|
|
||||||
private final Iterable<? extends Insn> originalInstructions;
|
|
||||||
|
|
||||||
private List<Insn> instructions;
|
|
||||||
private ArrayList<Integer> codeOffsetShifts;
|
|
||||||
private HashMap<Integer,Format> offsetToNewInstructionMap;
|
|
||||||
|
|
||||||
private int codeUnitCount;
|
|
||||||
private int outParamCount;
|
|
||||||
|
|
||||||
public static interface StringIndexProvider<StringRef extends StringReference> {
|
|
||||||
int getItemIndex(@Nonnull StringRef reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InstructionWriteUtil(@Nonnull Iterable<? extends Insn> instructions,
|
|
||||||
@Nonnull StringIndexProvider<StringRef> stringIndexProvider,
|
|
||||||
@Nonnull InstructionFactory<? extends Insn, BaseReference> 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<? extends Insn> 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<numCodeOffsetShifts;i++) {
|
|
||||||
if (offset >= 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<SwitchElement> 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<SwitchElement> 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<SwitchElement> modifySwitchElements(SwitchPayload payload, int switchInstructionOffset) {
|
|
||||||
ArrayList<SwitchElement> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -31,351 +31,185 @@
|
|||||||
|
|
||||||
package org.jf.dexlib2.writer;
|
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 com.google.common.collect.Lists;
|
||||||
import junit.framework.Assert;
|
|
||||||
import org.jf.dexlib2.Opcode;
|
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.Instruction;
|
||||||
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.*;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
||||||
import org.jf.dexlib2.iface.reference.Reference;
|
import org.jf.dexlib2.iface.reference.Reference;
|
||||||
import org.jf.dexlib2.iface.reference.StringReference;
|
import org.jf.dexlib2.iface.reference.StringReference;
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethodImplementation;
|
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction10x;
|
||||||
import org.jf.dexlib2.immutable.instruction.*;
|
import org.jf.dexlib2.writer.builder.DexBuilder;
|
||||||
import org.jf.dexlib2.immutable.reference.ImmutableStringReference;
|
import org.jf.dexlib2.writer.io.MemoryDataStore;
|
||||||
import org.jf.dexlib2.writer.util.InstructionWriteUtil;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.ArrayList;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class JumboStringConversionTest {
|
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;
|
MethodImplementationBuilder methodBuilder = new MethodImplementationBuilder(1);
|
||||||
ArrayList<String> mJumboStrings;
|
for (int i=0; i<66000; i++) {
|
||||||
|
methodBuilder.addInstruction(new BuilderInstruction21c(Opcode.CONST_STRING, 0,
|
||||||
private class InsnWriteUtil extends InstructionWriteUtil<Instruction, StringReference, Reference> {
|
dexBuilder.internStringReference(String.format("%08d", i))));
|
||||||
public InsnWriteUtil(@Nonnull MethodImplementation implementation) {
|
|
||||||
super(implementation.getInstructions(), mockStringIndexProvider, ImmutableInstructionFactory.INSTANCE);
|
|
||||||
}
|
}
|
||||||
|
methodBuilder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
|
||||||
|
|
||||||
|
dexBuilder.internClassDef(
|
||||||
|
"Ltest;",
|
||||||
|
0,
|
||||||
|
"Ljava/lang/Object;",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
ImmutableSet.<Annotation>of(),
|
||||||
|
null,
|
||||||
|
ImmutableList.of(
|
||||||
|
dexBuilder.internMethod(
|
||||||
|
"Ltest;",
|
||||||
|
"test",
|
||||||
|
null,
|
||||||
|
"V",
|
||||||
|
0,
|
||||||
|
ImmutableSet.<Annotation>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<? extends Instruction> 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
|
@Test
|
||||||
while (mJumboStrings.size()<MIN_NUM_JUMBO_STRINGS) {
|
public void testJumboStringConversion_NonMethodBuilder() throws IOException {
|
||||||
for (int pos=stringBuilder.length()-1;pos>=0;pos--) {
|
DexBuilder dexBuilder = DexBuilder.makeDexBuilder(15);
|
||||||
for (char ch='a';ch<='z';ch++) {
|
|
||||||
stringBuilder.setCharAt(pos, ch);
|
final List<Instruction> instructions = Lists.newArrayList();
|
||||||
mockStringIndexProvider.intern(stringBuilder.toString(), index++);
|
for (int i=0; i<66000; i++) {
|
||||||
if (mockStringIndexProvider.getNumItems()>0xFFFF) {
|
final StringReference ref = dexBuilder.internStringReference(String.format("%08d", i));
|
||||||
mJumboStrings.add(stringBuilder.toString());
|
|
||||||
}
|
instructions.add(new Instruction21c() {
|
||||||
|
@Override public int getRegisterA() {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
stringBuilder.setLength(stringBuilder.length()+1);
|
@Nonnull @Override public Reference getReference() {
|
||||||
for (int pos=0;pos<stringBuilder.length();pos++) {
|
return ref;
|
||||||
stringBuilder.setCharAt(pos, 'a');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInstruction21c() {
|
|
||||||
ArrayList<ImmutableInstruction> 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<ImmutableInstruction> createSimpleInstructionList() {
|
|
||||||
ArrayList<ImmutableInstruction> 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<SwitchElement> 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<ImmutableInstruction> 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<ImmutableInstruction> 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<ImmutableInstruction> 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<ImmutableInstruction> 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<ImmutableInstruction> 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<ImmutableInstruction> 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<ImmutableInstruction> 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);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Override public Opcode getOpcode() {
|
||||||
public void testSparseSwitchPayload() {
|
return Opcode.CONST_STRING;
|
||||||
ArrayList<ImmutableInstruction> 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);
|
|
||||||
}
|
}
|
||||||
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
|
@Nonnull @Override public Iterable<? extends Instruction> getInstructions() {
|
||||||
public void testArrayPayloadAlignment() {
|
return instructions;
|
||||||
ArrayList<ImmutableInstruction> 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;
|
|
||||||
}
|
}
|
||||||
codeOffset += instr.getCodeUnits();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Nonnull @Override public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
|
||||||
public void testPackedSwitchAlignment() {
|
return ImmutableList.of();
|
||||||
ArrayList<ImmutableInstruction> 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;
|
|
||||||
}
|
}
|
||||||
codeOffset += instr.getCodeUnits();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Nonnull @Override public Iterable<? extends DebugItem> getDebugItems() {
|
||||||
public void testSparseSwitchAlignment() {
|
return ImmutableList.of();
|
||||||
ArrayList<ImmutableInstruction> 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;
|
|
||||||
}
|
}
|
||||||
codeOffset += instr.getCodeUnits();
|
};
|
||||||
|
|
||||||
|
dexBuilder.internClassDef(
|
||||||
|
"Ltest;",
|
||||||
|
0,
|
||||||
|
"Ljava/lang/Object;",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
ImmutableSet.<Annotation>of(),
|
||||||
|
null,
|
||||||
|
ImmutableList.of(
|
||||||
|
dexBuilder.internMethod(
|
||||||
|
"Ltest;",
|
||||||
|
"test",
|
||||||
|
null,
|
||||||
|
"V",
|
||||||
|
0,
|
||||||
|
ImmutableSet.<Annotation>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<? extends Instruction> 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());
|
||||||
}
|
}
|
||||||
}
|
for (int i=65536; i<66000; i++) {
|
||||||
|
Assert.assertEquals(Opcode.CONST_STRING_JUMBO, actualInstructions.get(i).getOpcode());
|
||||||
@Test
|
Assert.assertEquals(String.format("%08d", i),
|
||||||
public void testGotoToGoto16() {
|
((StringReference)((ReferenceInstruction)actualInstructions.get(i)).getReference()).getString());
|
||||||
ArrayList<ImmutableInstruction> 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<ImmutableInstruction> 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<Short.MAX_VALUE;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/16 was not converted to goto/32 properly", instr.getOpcode(), Opcode.GOTO_32);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGotoIterative() {
|
|
||||||
ArrayList<ImmutableInstruction> 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();
|
|
||||||
}
|
}
|
||||||
|
Assert.assertEquals(Opcode.RETURN_VOID, actualInstructions.get(66000).getOpcode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<StringReference> {
|
|
||||||
private HashMap<String, Integer> 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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Instruction, StringReference, Reference> {
|
|
||||||
public InsnWriteUtil(@Nonnull MethodImplementation implementation) {
|
|
||||||
super(implementation.getInstructions(), mockStringIndexProvider, ImmutableInstructionFactory.INSTANCE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup() {
|
|
||||||
mockStringIndexProvider = new MockStringIndexProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testArrayPayloadAlignment() {
|
|
||||||
ArrayList<ImmutableInstruction> 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<ImmutableInstruction> instructions = Lists.newArrayList();
|
|
||||||
// add misaligned packed switch payload
|
|
||||||
ArrayList<SwitchElement> 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<ImmutableInstruction> instructions = Lists.newArrayList();
|
|
||||||
|
|
||||||
// add misaligned sparse switch payload
|
|
||||||
ArrayList<SwitchElement> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -140,10 +140,9 @@ tokens {
|
|||||||
LOCALS_DIRECTIVE;
|
LOCALS_DIRECTIVE;
|
||||||
LONG_LITERAL;
|
LONG_LITERAL;
|
||||||
METHOD_DIRECTIVE;
|
METHOD_DIRECTIVE;
|
||||||
METHOD_NAME;
|
MEMBER_NAME;
|
||||||
NEGATIVE_INTEGER_LITERAL;
|
NEGATIVE_INTEGER_LITERAL;
|
||||||
NULL_LITERAL;
|
NULL_LITERAL;
|
||||||
OFFSET;
|
|
||||||
OPEN_BRACE;
|
OPEN_BRACE;
|
||||||
OPEN_PAREN;
|
OPEN_PAREN;
|
||||||
PACKED_SWITCH_DIRECTIVE;
|
PACKED_SWITCH_DIRECTIVE;
|
||||||
@ -188,7 +187,6 @@ tokens {
|
|||||||
I_METHOD_RETURN_TYPE;
|
I_METHOD_RETURN_TYPE;
|
||||||
I_REGISTERS;
|
I_REGISTERS;
|
||||||
I_LOCALS;
|
I_LOCALS;
|
||||||
I_LABELS;
|
|
||||||
I_LABEL;
|
I_LABEL;
|
||||||
I_ANNOTATIONS;
|
I_ANNOTATIONS;
|
||||||
I_ANNOTATION;
|
I_ANNOTATION;
|
||||||
@ -202,26 +200,20 @@ tokens {
|
|||||||
I_ARRAY_ELEMENTS;
|
I_ARRAY_ELEMENTS;
|
||||||
I_PACKED_SWITCH_START_KEY;
|
I_PACKED_SWITCH_START_KEY;
|
||||||
I_PACKED_SWITCH_ELEMENTS;
|
I_PACKED_SWITCH_ELEMENTS;
|
||||||
I_PACKED_SWITCH_DECLARATION;
|
|
||||||
I_PACKED_SWITCH_DECLARATIONS;
|
|
||||||
I_SPARSE_SWITCH_ELEMENTS;
|
I_SPARSE_SWITCH_ELEMENTS;
|
||||||
I_SPARSE_SWITCH_DECLARATION;
|
|
||||||
I_SPARSE_SWITCH_DECLARATIONS;
|
|
||||||
I_ADDRESS;
|
|
||||||
I_CATCH;
|
I_CATCH;
|
||||||
I_CATCHALL;
|
I_CATCHALL;
|
||||||
I_CATCHES;
|
I_CATCHES;
|
||||||
I_PARAMETER;
|
I_PARAMETER;
|
||||||
I_PARAMETERS;
|
I_PARAMETERS;
|
||||||
I_PARAMETER_NOT_SPECIFIED;
|
I_PARAMETER_NOT_SPECIFIED;
|
||||||
I_ORDERED_DEBUG_DIRECTIVES;
|
|
||||||
I_LINE;
|
I_LINE;
|
||||||
I_LOCAL;
|
I_LOCAL;
|
||||||
I_END_LOCAL;
|
I_END_LOCAL;
|
||||||
I_RESTART_LOCAL;
|
I_RESTART_LOCAL;
|
||||||
I_PROLOGUE;
|
I_PROLOGUE;
|
||||||
I_EPILOGUE;
|
I_EPILOGUE;
|
||||||
I_STATEMENTS;
|
I_ORDERED_METHOD_ITEMS;
|
||||||
I_STATEMENT_FORMAT10t;
|
I_STATEMENT_FORMAT10t;
|
||||||
I_STATEMENT_FORMAT10x;
|
I_STATEMENT_FORMAT10x;
|
||||||
I_STATEMENT_FORMAT11n;
|
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*/
|
add them to the $smali_file::classAnnotations list*/
|
||||||
field
|
field
|
||||||
@init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
|
@init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
|
||||||
: 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);})*
|
( ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
|
||||||
( END_FIELD_DIRECTIVE
|
( 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);}
|
| /*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
|
method
|
||||||
scope {int currentAddress;}
|
: METHOD_DIRECTIVE access_list member_name method_prototype statements_and_directives
|
||||||
: {$method::currentAddress = 0;}
|
|
||||||
METHOD_DIRECTIVE access_list method_name method_prototype statements_and_directives
|
|
||||||
END_METHOD_DIRECTIVE
|
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
|
statements_and_directives
|
||||||
scope
|
scope
|
||||||
{
|
{
|
||||||
boolean hasRegistersDirective;
|
boolean hasRegistersDirective;
|
||||||
List<CommonTree> packedSwitchDeclarations;
|
|
||||||
List<CommonTree> sparseSwitchDeclarations;
|
|
||||||
List<CommonTree> methodAnnotations;
|
List<CommonTree> methodAnnotations;
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
$method::currentAddress = 0;
|
|
||||||
$statements_and_directives::hasRegistersDirective = false;
|
$statements_and_directives::hasRegistersDirective = false;
|
||||||
$statements_and_directives::packedSwitchDeclarations = new ArrayList<CommonTree>();
|
|
||||||
$statements_and_directives::sparseSwitchDeclarations = new ArrayList<CommonTree>();
|
|
||||||
$statements_and_directives::methodAnnotations = new ArrayList<CommonTree>();
|
$statements_and_directives::methodAnnotations = new ArrayList<CommonTree>();
|
||||||
}
|
}
|
||||||
( instruction {$method::currentAddress += $instruction.size/2;}
|
( ordered_method_item
|
||||||
| registers_directive
|
| registers_directive
|
||||||
| label
|
|
||||||
| catch_directive
|
| catch_directive
|
||||||
| catchall_directive
|
| catchall_directive
|
||||||
| parameter_directive
|
| parameter_directive
|
||||||
| ordered_debug_directive
|
|
||||||
| annotation {$statements_and_directives::methodAnnotations.add($annotation.tree);}
|
| annotation {$statements_and_directives::methodAnnotations.add($annotation.tree);}
|
||||||
)*
|
)*
|
||||||
-> registers_directive?
|
-> registers_directive?
|
||||||
^(I_LABELS label*)
|
^(I_ORDERED_METHOD_ITEMS ordered_method_item*)
|
||||||
{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_CATCHES catch_directive* catchall_directive*)
|
^(I_CATCHES catch_directive* catchall_directive*)
|
||||||
^(I_PARAMETERS parameter_directive*)
|
^(I_PARAMETERS parameter_directive*)
|
||||||
^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*)
|
|
||||||
{buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $statements_and_directives::methodAnnotations)};
|
{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
|
registers_directive
|
||||||
: (
|
: (
|
||||||
directive=REGISTERS_DIRECTIVE regCount=integral_literal -> ^(I_REGISTERS[$REGISTERS_DIRECTIVE, "I_REGISTERS"] $regCount)
|
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_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD]
|
||||||
| INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l];
|
| INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l];
|
||||||
|
|
||||||
method_name
|
member_name
|
||||||
: simple_name
|
: simple_name
|
||||||
| METHOD_NAME -> SIMPLE_NAME[$METHOD_NAME];
|
| MEMBER_NAME -> SIMPLE_NAME[$MEMBER_NAME];
|
||||||
|
|
||||||
method_prototype
|
method_prototype
|
||||||
: OPEN_PAREN param_list CLOSE_PAREN type_descriptor
|
: OPEN_PAREN param_list CLOSE_PAREN type_descriptor
|
||||||
@ -680,15 +665,15 @@ fixed_32bit_literal
|
|||||||
| CHAR_LITERAL
|
| CHAR_LITERAL
|
||||||
| BOOL_LITERAL;
|
| BOOL_LITERAL;
|
||||||
|
|
||||||
fixed_literal returns[int size]
|
fixed_literal
|
||||||
: integer_literal {$size = 4;}
|
: integer_literal
|
||||||
| LONG_LITERAL {$size = 8;}
|
| LONG_LITERAL
|
||||||
| SHORT_LITERAL {$size = 2;}
|
| SHORT_LITERAL
|
||||||
| BYTE_LITERAL {$size = 1;}
|
| BYTE_LITERAL
|
||||||
| float_literal {$size = 4;}
|
| float_literal
|
||||||
| double_literal {$size = 8;}
|
| double_literal
|
||||||
| CHAR_LITERAL {$size = 2;}
|
| CHAR_LITERAL
|
||||||
| BOOL_LITERAL {$size = 1;};
|
| BOOL_LITERAL;
|
||||||
|
|
||||||
array_literal
|
array_literal
|
||||||
: OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE
|
: OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE
|
||||||
@ -714,8 +699,8 @@ enum_literal
|
|||||||
type_field_method_literal
|
type_field_method_literal
|
||||||
: reference_type_descriptor
|
: reference_type_descriptor
|
||||||
( ARROW
|
( ARROW
|
||||||
( simple_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor simple_name nonvoid_type_descriptor)
|
( member_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor member_name nonvoid_type_descriptor)
|
||||||
| method_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor method_name method_prototype)
|
| member_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor member_name method_prototype)
|
||||||
)
|
)
|
||||||
| -> reference_type_descriptor
|
| -> reference_type_descriptor
|
||||||
)
|
)
|
||||||
@ -723,20 +708,18 @@ type_field_method_literal
|
|||||||
| VOID_TYPE;
|
| VOID_TYPE;
|
||||||
|
|
||||||
fully_qualified_method
|
fully_qualified_method
|
||||||
: reference_type_descriptor ARROW method_name method_prototype
|
: reference_type_descriptor ARROW member_name method_prototype
|
||||||
-> reference_type_descriptor method_name method_prototype;
|
-> reference_type_descriptor member_name method_prototype;
|
||||||
|
|
||||||
fully_qualified_field
|
fully_qualified_field
|
||||||
: reference_type_descriptor ARROW simple_name COLON nonvoid_type_descriptor
|
: reference_type_descriptor ARROW member_name COLON nonvoid_type_descriptor
|
||||||
-> reference_type_descriptor simple_name nonvoid_type_descriptor;
|
-> reference_type_descriptor member_name nonvoid_type_descriptor;
|
||||||
|
|
||||||
label
|
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
|
label_ref
|
||||||
: COLON simple_name -> simple_name
|
: COLON simple_name -> simple_name;
|
||||||
| OFFSET
|
|
||||||
| NEGATIVE_INTEGER_LITERAL -> OFFSET[$NEGATIVE_INTEGER_LITERAL];
|
|
||||||
|
|
||||||
register_list
|
register_list
|
||||||
: REGISTER (COMMA REGISTER)* -> ^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"] REGISTER*)
|
: 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;
|
: CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method;
|
||||||
|
|
||||||
catch_directive
|
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
|
: CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref
|
||||||
-> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using);
|
-> ^(I_CATCH[$start, "I_CATCH"] nonvoid_type_descriptor $from $to $using);
|
||||||
|
|
||||||
catchall_directive
|
catchall_directive
|
||||||
: CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset
|
: CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref
|
||||||
-> ^(I_CATCHALL[$start, "I_CATCHALL"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] $from $to $using);
|
-> ^(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
|
/*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
|
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))
|
-> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER STRING_LITERAL? ^(I_ANNOTATIONS))
|
||||||
);
|
);
|
||||||
|
|
||||||
ordered_debug_directive
|
debug_directive
|
||||||
: line_directive
|
: line_directive
|
||||||
| local_directive
|
| local_directive
|
||||||
| end_local_directive
|
| end_local_directive
|
||||||
@ -782,33 +765,32 @@ ordered_debug_directive
|
|||||||
|
|
||||||
line_directive
|
line_directive
|
||||||
: LINE_DIRECTIVE integral_literal
|
: 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
|
||||||
: LOCAL_DIRECTIVE REGISTER (COMMA (NULL_LITERAL | name=STRING_LITERAL) COLON (VOID_TYPE | nonvoid_type_descriptor)
|
: LOCAL_DIRECTIVE REGISTER (COMMA (NULL_LITERAL | name=STRING_LITERAL) COLON (VOID_TYPE | nonvoid_type_descriptor)
|
||||||
(COMMA signature=STRING_LITERAL)? )?
|
(COMMA signature=STRING_LITERAL)? )?
|
||||||
-> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER NULL_LITERAL? $name? nonvoid_type_descriptor? $signature?
|
-> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER NULL_LITERAL? $name? nonvoid_type_descriptor? $signature?);
|
||||||
I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
|
|
||||||
|
|
||||||
end_local_directive
|
end_local_directive
|
||||||
: END_LOCAL_DIRECTIVE REGISTER
|
: 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
|
||||||
: RESTART_LOCAL_DIRECTIVE REGISTER
|
: 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
|
||||||
: 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
|
||||||
: 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
|
||||||
: SOURCE_DIRECTIVE STRING_LITERAL?
|
: 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
|
||||||
: INSTRUCTION_FORMAT12x
|
: INSTRUCTION_FORMAT12x
|
||||||
@ -824,88 +806,88 @@ instruction_format31i
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
instruction returns [int size]
|
instruction
|
||||||
: insn_format10t { $size = $insn_format10t.size; }
|
: insn_format10t
|
||||||
| insn_format10x { $size = $insn_format10x.size; }
|
| insn_format10x
|
||||||
| insn_format10x_odex { $size = $insn_format10x_odex.size; }
|
| insn_format10x_odex
|
||||||
| insn_format11n { $size = $insn_format11n.size; }
|
| insn_format11n
|
||||||
| insn_format11x { $size = $insn_format11x.size; }
|
| insn_format11x
|
||||||
| insn_format12x { $size = $insn_format12x.size; }
|
| insn_format12x
|
||||||
| insn_format20bc { $size = $insn_format20bc.size; }
|
| insn_format20bc
|
||||||
| insn_format20t { $size = $insn_format20t.size; }
|
| insn_format20t
|
||||||
| insn_format21c_field { $size = $insn_format21c_field.size; }
|
| insn_format21c_field
|
||||||
| insn_format21c_field_odex { $size = $insn_format21c_field_odex.size; }
|
| insn_format21c_field_odex
|
||||||
| insn_format21c_string { $size = $insn_format21c_string.size; }
|
| insn_format21c_string
|
||||||
| insn_format21c_type { $size = $insn_format21c_type.size; }
|
| insn_format21c_type
|
||||||
| insn_format21ih { $size = $insn_format21ih.size; }
|
| insn_format21ih
|
||||||
| insn_format21lh { $size = $insn_format21lh.size; }
|
| insn_format21lh
|
||||||
| insn_format21s { $size = $insn_format21s.size; }
|
| insn_format21s
|
||||||
| insn_format21t { $size = $insn_format21t.size; }
|
| insn_format21t
|
||||||
| insn_format22b { $size = $insn_format22b.size; }
|
| insn_format22b
|
||||||
| insn_format22c_field { $size = $insn_format22c_field.size; }
|
| insn_format22c_field
|
||||||
| insn_format22c_field_odex { $size = $insn_format22c_field_odex.size; }
|
| insn_format22c_field_odex
|
||||||
| insn_format22c_type { $size = $insn_format22c_type.size; }
|
| insn_format22c_type
|
||||||
| insn_format22cs_field { $size = $insn_format22cs_field.size; }
|
| insn_format22cs_field
|
||||||
| insn_format22s { $size = $insn_format22s.size; }
|
| insn_format22s
|
||||||
| insn_format22t { $size = $insn_format22t.size; }
|
| insn_format22t
|
||||||
| insn_format22x { $size = $insn_format22x.size; }
|
| insn_format22x
|
||||||
| insn_format23x { $size = $insn_format23x.size; }
|
| insn_format23x
|
||||||
| insn_format30t { $size = $insn_format30t.size; }
|
| insn_format30t
|
||||||
| insn_format31c { $size = $insn_format31c.size; }
|
| insn_format31c
|
||||||
| insn_format31i { $size = $insn_format31i.size; }
|
| insn_format31i
|
||||||
| insn_format31t { $size = $insn_format31t.size; }
|
| insn_format31t
|
||||||
| insn_format32x { $size = $insn_format32x.size; }
|
| insn_format32x
|
||||||
| insn_format35c_method { $size = $insn_format35c_method.size; }
|
| insn_format35c_method
|
||||||
| insn_format35c_type { $size = $insn_format35c_type.size; }
|
| insn_format35c_type
|
||||||
| insn_format35c_method_odex { $size = $insn_format35c_method_odex.size; }
|
| insn_format35c_method_odex
|
||||||
| insn_format35mi_method { $size = $insn_format35mi_method.size; }
|
| insn_format35mi_method
|
||||||
| insn_format35ms_method { $size = $insn_format35ms_method.size; }
|
| insn_format35ms_method
|
||||||
| insn_format3rc_method { $size = $insn_format3rc_method.size; }
|
| insn_format3rc_method
|
||||||
| insn_format3rc_method_odex { $size = $insn_format3rc_method_odex.size; }
|
| insn_format3rc_method_odex
|
||||||
| insn_format3rc_type { $size = $insn_format3rc_type.size; }
|
| insn_format3rc_type
|
||||||
| insn_format3rmi_method { $size = $insn_format3rmi_method.size; }
|
| insn_format3rmi_method
|
||||||
| insn_format3rms_method { $size = $insn_format3rms_method.size; }
|
| insn_format3rms_method
|
||||||
| insn_format51l { $size = $insn_format51l.size; }
|
| insn_format51l
|
||||||
| insn_array_data_directive { $size = $insn_array_data_directive.size; }
|
| insn_array_data_directive
|
||||||
| insn_packed_switch_directive { $size = $insn_packed_switch_directive.size; }
|
| insn_packed_switch_directive
|
||||||
| insn_sparse_switch_directive { $size = $insn_sparse_switch_directive.size; };
|
| insn_sparse_switch_directive;
|
||||||
|
|
||||||
insn_format10t returns [int size]
|
insn_format10t
|
||||||
: //e.g. goto endloop:
|
: //e.g. goto endloop:
|
||||||
//e.g. goto +3
|
//e.g. goto +3
|
||||||
INSTRUCTION_FORMAT10t label_ref_or_offset {$size = Format.Format10t.size;}
|
INSTRUCTION_FORMAT10t label_ref
|
||||||
-> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref_or_offset);
|
-> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref);
|
||||||
|
|
||||||
insn_format10x returns [int size]
|
insn_format10x
|
||||||
: //e.g. return-void
|
: //e.g. return-void
|
||||||
INSTRUCTION_FORMAT10x {$size = Format.Format10x.size;}
|
INSTRUCTION_FORMAT10x
|
||||||
-> ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] 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
|
: //e.g. return-void-barrier
|
||||||
INSTRUCTION_FORMAT10x_ODEX {$size = Format.Format10x.size;}
|
INSTRUCTION_FORMAT10x_ODEX
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT10x_ODEX.text);
|
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT10x_ODEX.text);
|
||||||
};
|
};
|
||||||
|
|
||||||
insn_format11n returns [int size]
|
insn_format11n
|
||||||
: //e.g. const/4 v0, 5
|
: //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);
|
-> ^(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
|
: //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);
|
-> ^(I_STATEMENT_FORMAT11x[$start, "I_STATEMENT_FORMAT11x"] INSTRUCTION_FORMAT11x REGISTER);
|
||||||
|
|
||||||
insn_format12x returns [int size]
|
insn_format12x
|
||||||
: //e.g. move v1 v2
|
: //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);
|
-> ^(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;
|
: //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) {
|
if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT20bc.text) == null || apiLevel >= 14) {
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text);
|
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);
|
-> ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE verification_error_reference);
|
||||||
|
|
||||||
insn_format20t returns [int size]
|
insn_format20t
|
||||||
: //e.g. goto/16 endloop:
|
: //e.g. goto/16 endloop:
|
||||||
INSTRUCTION_FORMAT20t label_ref_or_offset {$size = Format.Format20t.size;}
|
INSTRUCTION_FORMAT20t label_ref
|
||||||
-> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref_or_offset);
|
-> ^(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;
|
: //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);
|
-> ^(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;
|
: //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) {
|
if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_FIELD_ODEX.text) == null || apiLevel >= 14) {
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT21c_FIELD_ODEX.text);
|
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);
|
-> ^(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!"
|
: //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);
|
-> ^(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;
|
: //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);
|
-> ^(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
|
: //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);
|
-> ^(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
|
: //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);
|
-> ^(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
|
: //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);
|
-> ^(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:
|
: //e.g. if-eqz v0, endloop:
|
||||||
INSTRUCTION_FORMAT21t REGISTER COMMA (label_ref_or_offset) {$size = Format.Format21t.size;}
|
INSTRUCTION_FORMAT21t REGISTER COMMA label_ref
|
||||||
-> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER label_ref_or_offset);
|
-> ^(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
|
: //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);
|
-> ^(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;
|
: //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);
|
-> ^(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;
|
: //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) {
|
if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_FIELD_ODEX.text) == null || apiLevel >= 14) {
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22c_FIELD_ODEX.text);
|
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);
|
-> ^(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;
|
: //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);
|
-> ^(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
|
: //e.g. iget-quick v0, v1, field@0xc
|
||||||
INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET
|
INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22cs_FIELD.text);
|
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22cs_FIELD.text);
|
||||||
};
|
};
|
||||||
|
|
||||||
insn_format22s returns [int size]
|
insn_format22s
|
||||||
: //e.g. add-int/lit16 v0, v1, 12345
|
: //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);
|
-> ^(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:
|
: //e.g. if-eq v0, v1, endloop:
|
||||||
INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref_or_offset {$size = Format.Format22t.size;}
|
INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref
|
||||||
-> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER label_ref_or_offset);
|
-> ^(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
|
: //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);
|
-> ^(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
|
: //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);
|
-> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER);
|
||||||
|
|
||||||
insn_format30t returns [int size]
|
insn_format30t
|
||||||
: //e.g. goto/32 endloop:
|
: //e.g. goto/32 endloop:
|
||||||
INSTRUCTION_FORMAT30t label_ref_or_offset {$size = Format.Format30t.size;}
|
INSTRUCTION_FORMAT30t label_ref
|
||||||
-> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t label_ref_or_offset);
|
-> ^(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!"
|
: //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);
|
->^(I_STATEMENT_FORMAT31c[$start, "I_STATEMENT_FORMAT31c"] INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL);
|
||||||
|
|
||||||
insn_format31i returns [int size]
|
insn_format31i
|
||||||
: //e.g. const v0, 123456
|
: //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);
|
-> ^(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:
|
: //e.g. fill-array-data v0, ArrayData:
|
||||||
INSTRUCTION_FORMAT31t REGISTER COMMA label_ref_or_offset {$size = Format.Format31t.size;}
|
INSTRUCTION_FORMAT31t REGISTER COMMA label_ref
|
||||||
{
|
-> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER label_ref);
|
||||||
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);
|
|
||||||
|
|
||||||
insn_format32x returns [int size]
|
insn_format32x
|
||||||
: //e.g. move/16 v4567, v1234
|
: //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);
|
-> ^(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
|
: //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);
|
-> ^(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
|
: //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);
|
-> ^(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;-><init>()V
|
: //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||||
INSTRUCTION_FORMAT35c_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
|
INSTRUCTION_FORMAT35c_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35c_METHOD_ODEX.text);
|
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35c_METHOD_ODEX.text);
|
||||||
};
|
};
|
||||||
|
|
||||||
insn_format35mi_method returns [int size]
|
insn_format35mi_method
|
||||||
: //e.g. execute-inline {v0, v1}, inline@0x4
|
: //e.g. execute-inline {v0, v1}, inline@0x4
|
||||||
INSTRUCTION_FORMAT35mi_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA INLINE_INDEX
|
INSTRUCTION_FORMAT35mi_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA INLINE_INDEX
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35mi_METHOD.text);
|
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35mi_METHOD.text);
|
||||||
};
|
};
|
||||||
|
|
||||||
insn_format35ms_method returns [int size]
|
insn_format35ms_method
|
||||||
: //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4
|
: //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4
|
||||||
INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_INDEX
|
INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_INDEX
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35ms_METHOD.text);
|
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;
|
: //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);
|
-> ^(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;-><init>()V
|
: //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
|
||||||
INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
|
INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rc_METHOD_ODEX.text);
|
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
|
: //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);
|
-> ^(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
|
: //e.g. execute-inline/range {v0 .. v10}, inline@0x14
|
||||||
INSTRUCTION_FORMAT3rmi_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA INLINE_INDEX
|
INSTRUCTION_FORMAT3rmi_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA INLINE_INDEX
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rmi_METHOD.text);
|
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
|
: //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14
|
||||||
INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_INDEX
|
INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_INDEX
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text);
|
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text);
|
||||||
};
|
};
|
||||||
|
|
||||||
insn_format51l returns [int size]
|
insn_format51l
|
||||||
: //e.g. const-wide v0, 5000000000L
|
: //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);
|
-> ^(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
|
: ARRAY_DATA_DIRECTIVE
|
||||||
parsed_integer_literal
|
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);
|
throw new SemanticException(input, $start, "Invalid element width: \%d. Must be 1, 2, 4 or 8", elementWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fixed_literal* END_ARRAY_DATA_DIRECTIVE
|
||||||
(fixed_literal {$size+=elementWidth;})* END_ARRAY_DATA_DIRECTIVE
|
|
||||||
{$size = (($size + 1) & ~1) + 8;}
|
|
||||||
|
|
||||||
-> ^(I_STATEMENT_ARRAY_DATA[$start, "I_STATEMENT_ARRAY_DATA"] ^(I_ARRAY_ELEMENT_SIZE parsed_integer_literal)
|
-> ^(I_STATEMENT_ARRAY_DATA[$start, "I_STATEMENT_ARRAY_DATA"] ^(I_ARRAY_ELEMENT_SIZE parsed_integer_literal)
|
||||||
^(I_ARRAY_ELEMENTS fixed_literal*));
|
^(I_ARRAY_ELEMENTS fixed_literal*));
|
||||||
|
|
||||||
insn_packed_switch_directive returns [int size]
|
insn_packed_switch_directive
|
||||||
: PACKED_SWITCH_DIRECTIVE
|
: PACKED_SWITCH_DIRECTIVE
|
||||||
fixed_32bit_literal
|
fixed_32bit_literal
|
||||||
|
label_ref*
|
||||||
(switch_target += label_ref_or_offset {$size+=4;})*
|
END_PACKED_SWITCH_DIRECTIVE
|
||||||
|
|
||||||
END_PACKED_SWITCH_DIRECTIVE {$size = $size + 8;}
|
|
||||||
|
|
||||||
-> ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
|
-> ^(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_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
|
||||||
^(I_PACKED_SWITCH_ELEMENTS[$start, "I_PACKED_SWITCH_ELEMENTS"]
|
^(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
|
: SPARSE_SWITCH_DIRECTIVE
|
||||||
(fixed_32bit_literal ARROW switch_target += label_ref_or_offset {$size += 8;})*
|
(fixed_32bit_literal ARROW label_ref)*
|
||||||
|
END_SPARSE_SWITCH_DIRECTIVE
|
||||||
END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;}
|
|
||||||
|
|
||||||
-> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
|
-> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
|
||||||
^(I_SPARSE_SWITCH_ELEMENTS[$start, "I_SPARSE_SWITCH_ELEMENTS"] (fixed_32bit_literal $switch_target)*));
|
^(I_SPARSE_SWITCH_ELEMENTS[$start, "I_SPARSE_SWITCH_ELEMENTS"] (fixed_32bit_literal label_ref)*));
|
File diff suppressed because it is too large
Load Diff
@ -36,6 +36,7 @@ import org.antlr.runtime.tree.CommonTree;
|
|||||||
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
||||||
import org.apache.commons.cli.*;
|
import org.apache.commons.cli.*;
|
||||||
import org.jf.dexlib2.writer.builder.DexBuilder;
|
import org.jf.dexlib2.writer.builder.DexBuilder;
|
||||||
|
import org.jf.dexlib2.writer.io.FileDataStore;
|
||||||
import org.jf.util.ConsoleUtil;
|
import org.jf.util.ConsoleUtil;
|
||||||
import org.jf.util.SmaliHelpFormatter;
|
import org.jf.util.SmaliHelpFormatter;
|
||||||
|
|
||||||
@ -225,7 +226,7 @@ public class main {
|
|||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
dexBuilder.writeTo(outputDexFile);
|
dexBuilder.writeTo(new FileDataStore(new File(outputDexFile)));
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
|
System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
@ -241,14 +242,14 @@ public class main {
|
|||||||
File[] files = dir.listFiles();
|
File[] files = dir.listFiles();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
for(File file: files) {
|
for(File file: files) {
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
getSmaliFilesInDir(file, smaliFiles);
|
getSmaliFilesInDir(file, smaliFiles);
|
||||||
} else if (file.getName().endsWith(".smali")) {
|
} else if (file.getName().endsWith(".smali")) {
|
||||||
smaliFiles.add(file);
|
smaliFiles.add(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, boolean verboseErrors,
|
private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, boolean verboseErrors,
|
||||||
boolean printTokens, boolean allowOdex, int apiLevel)
|
boolean printTokens, boolean allowOdex, int apiLevel)
|
||||||
|
@ -377,8 +377,6 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
|
|||||||
"vtable@0x" {HexDigit}+ { return newToken(VTABLE_INDEX); }
|
"vtable@0x" {HexDigit}+ { return newToken(VTABLE_INDEX); }
|
||||||
"field@0x" {HexDigit}+ { return newToken(FIELD_OFFSET); }
|
"field@0x" {HexDigit}+ { return newToken(FIELD_OFFSET); }
|
||||||
|
|
||||||
"+" {Integer} { return newToken(OFFSET); }
|
|
||||||
|
|
||||||
# [^\r\n]* { return newToken(LINE_COMMENT, true); }
|
# [^\r\n]* { return newToken(LINE_COMMENT, true); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -592,7 +590,7 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
|
|||||||
{PrimitiveType} {PrimitiveType}+ { return newToken(PARAM_LIST_OR_ID); }
|
{PrimitiveType} {PrimitiveType}+ { return newToken(PARAM_LIST_OR_ID); }
|
||||||
{Type} {Type}+ { return newToken(PARAM_LIST); }
|
{Type} {Type}+ { return newToken(PARAM_LIST); }
|
||||||
{SimpleName} { return newToken(SIMPLE_NAME); }
|
{SimpleName} { return newToken(SIMPLE_NAME); }
|
||||||
"<init>" | "<clinit>" { return newToken(METHOD_NAME); }
|
"<" {SimpleName} ">" { return newToken(MEMBER_NAME); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Symbols/Whitespace/EOF*/
|
/*Symbols/Whitespace/EOF*/
|
||||||
|
@ -67,12 +67,12 @@ SIMPLE_NAME("field") INVALID_TOKEN("@")
|
|||||||
SIMPLE_NAME("field") INVALID_TOKEN("@") SIMPLE_NAME("zzz")
|
SIMPLE_NAME("field") INVALID_TOKEN("@") SIMPLE_NAME("zzz")
|
||||||
SIMPLE_NAME("field") INVALID_TOKEN("@") SIMPLE_NAME("abcd")
|
SIMPLE_NAME("field") INVALID_TOKEN("@") SIMPLE_NAME("abcd")
|
||||||
|
|
||||||
OFFSET("+0")
|
INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("0")
|
||||||
OFFSET("+10")
|
INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("10")
|
||||||
OFFSET("+01")
|
INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("01")
|
||||||
OFFSET("+0777")
|
INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("0777")
|
||||||
OFFSET("+0x1234ABC")
|
INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("0x1234ABC")
|
||||||
OFFSET("+1234")
|
INVALID_TOKEN("+") POSITIVE_INTEGER_LITERAL("1234")
|
||||||
|
|
||||||
OFFSET("+0") POSITIVE_INTEGER_LITERAL("8")
|
INVALID_TOKEN("+") SIMPLE_NAME("08")
|
||||||
INVALID_TOKEN("+")
|
INVALID_TOKEN("+")
|
@ -152,7 +152,7 @@ END_FIELD_DIRECTIVE(".end field")
|
|||||||
METHOD_DIRECTIVE(".method")
|
METHOD_DIRECTIVE(".method")
|
||||||
ACCESS_SPEC("static")
|
ACCESS_SPEC("static")
|
||||||
ACCESS_SPEC("constructor")
|
ACCESS_SPEC("constructor")
|
||||||
METHOD_NAME("<clinit>")
|
MEMBER_NAME("<clinit>")
|
||||||
OPEN_PAREN("(")
|
OPEN_PAREN("(")
|
||||||
CLOSE_PAREN(")")
|
CLOSE_PAREN(")")
|
||||||
VOID_TYPE("V")
|
VOID_TYPE("V")
|
||||||
@ -211,7 +211,7 @@ CLOSE_BRACE("}")
|
|||||||
COMMA(",")
|
COMMA(",")
|
||||||
CLASS_DESCRIPTOR("Lcom/android/internal/os/BatteryStatsImpl$1;")
|
CLASS_DESCRIPTOR("Lcom/android/internal/os/BatteryStatsImpl$1;")
|
||||||
ARROW("->")
|
ARROW("->")
|
||||||
METHOD_NAME("<init>")
|
MEMBER_NAME("<init>")
|
||||||
OPEN_PAREN("(")
|
OPEN_PAREN("(")
|
||||||
CLOSE_PAREN(")")
|
CLOSE_PAREN(")")
|
||||||
VOID_TYPE("V")
|
VOID_TYPE("V")
|
||||||
@ -259,7 +259,7 @@ END_ARRAY_DATA_DIRECTIVE(".end array-data")
|
|||||||
END_METHOD_DIRECTIVE(".end method")
|
END_METHOD_DIRECTIVE(".end method")
|
||||||
METHOD_DIRECTIVE(".method")
|
METHOD_DIRECTIVE(".method")
|
||||||
ACCESS_SPEC("constructor")
|
ACCESS_SPEC("constructor")
|
||||||
METHOD_NAME("<init>")
|
MEMBER_NAME("<init>")
|
||||||
OPEN_PAREN("(")
|
OPEN_PAREN("(")
|
||||||
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/cdma/CDMAPhone;")
|
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/cdma/CDMAPhone;")
|
||||||
CLOSE_PAREN(")")
|
CLOSE_PAREN(")")
|
||||||
@ -282,7 +282,7 @@ CLOSE_BRACE("}")
|
|||||||
COMMA(",")
|
COMMA(",")
|
||||||
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/IccFileHandler;")
|
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/IccFileHandler;")
|
||||||
ARROW("->")
|
ARROW("->")
|
||||||
METHOD_NAME("<init>")
|
MEMBER_NAME("<init>")
|
||||||
OPEN_PAREN("(")
|
OPEN_PAREN("(")
|
||||||
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/PhoneBase;")
|
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/PhoneBase;")
|
||||||
CLOSE_PAREN(")")
|
CLOSE_PAREN(")")
|
||||||
@ -402,7 +402,7 @@ CLOSE_BRACE("}")
|
|||||||
COMMA(",")
|
COMMA(",")
|
||||||
CLASS_DESCRIPTOR("Ljava/lang/StringBuilder;")
|
CLASS_DESCRIPTOR("Ljava/lang/StringBuilder;")
|
||||||
ARROW("->")
|
ARROW("->")
|
||||||
METHOD_NAME("<init>")
|
MEMBER_NAME("<init>")
|
||||||
OPEN_PAREN("(")
|
OPEN_PAREN("(")
|
||||||
CLOSE_PAREN(")")
|
CLOSE_PAREN(")")
|
||||||
VOID_TYPE("V")
|
VOID_TYPE("V")
|
||||||
@ -464,7 +464,7 @@ CLOSE_BRACE("}")
|
|||||||
COMMA(",")
|
COMMA(",")
|
||||||
CLASS_DESCRIPTOR("Ljava/lang/RuntimeException;")
|
CLASS_DESCRIPTOR("Ljava/lang/RuntimeException;")
|
||||||
ARROW("->")
|
ARROW("->")
|
||||||
METHOD_NAME("<init>")
|
MEMBER_NAME("<init>")
|
||||||
OPEN_PAREN("(")
|
OPEN_PAREN("(")
|
||||||
CLASS_DESCRIPTOR("Ljava/lang/String;")
|
CLASS_DESCRIPTOR("Ljava/lang/String;")
|
||||||
CLOSE_PAREN(")")
|
CLOSE_PAREN(")")
|
||||||
|
@ -34,6 +34,8 @@ Ljava/lang/String;Ljava/lang/String;
|
|||||||
|
|
||||||
<init>
|
<init>
|
||||||
<clinit>
|
<clinit>
|
||||||
|
<blah>
|
||||||
|
<init->
|
||||||
|
|
||||||
Ljava/lang/String
|
Ljava/lang/String
|
||||||
L;
|
L;
|
||||||
|
@ -32,8 +32,10 @@ PARAM_LIST("[I[I[I")
|
|||||||
PARAM_LIST("[I[Z")
|
PARAM_LIST("[I[Z")
|
||||||
PARAM_LIST("[I[Ljava/lang/String;")
|
PARAM_LIST("[I[Ljava/lang/String;")
|
||||||
|
|
||||||
METHOD_NAME("<init>")
|
MEMBER_NAME("<init>")
|
||||||
METHOD_NAME("<clinit>")
|
MEMBER_NAME("<clinit>")
|
||||||
|
MEMBER_NAME("<blah>")
|
||||||
|
MEMBER_NAME("<init->")
|
||||||
|
|
||||||
SIMPLE_NAME("Ljava") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String")
|
SIMPLE_NAME("Ljava") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String")
|
||||||
SIMPLE_NAME("L") INVALID_TOKEN(";")
|
SIMPLE_NAME("L") INVALID_TOKEN(";")
|
||||||
@ -45,4 +47,4 @@ INVALID_TOKEN("[") VOID_TYPE("V")
|
|||||||
INVALID_TOKEN("[") SIMPLE_NAME("java") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String") INVALID_TOKEN(";")
|
INVALID_TOKEN("[") SIMPLE_NAME("java") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String") INVALID_TOKEN(";")
|
||||||
INVALID_TOKEN("[") INVALID_TOKEN(";")
|
INVALID_TOKEN("[") INVALID_TOKEN(";")
|
||||||
|
|
||||||
INVALID_TOKEN("<") SIMPLE_NAME("linit") INVALID_TOKEN(">")
|
MEMBER_NAME("<linit>")
|
@ -31,6 +31,7 @@ package org.jf.util;
|
|||||||
import ds.tree.RadixTree;
|
import ds.tree.RadixTree;
|
||||||
import ds.tree.RadixTreeImpl;
|
import ds.tree.RadixTreeImpl;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -41,6 +42,9 @@ import java.util.regex.Pattern;
|
|||||||
* class name to distinguish it from another class with a name that differes only by case. i.e. a.smali and a_2.smali
|
* class name to distinguish it from another class with a name that differes only by case. i.e. a.smali and a_2.smali
|
||||||
*/
|
*/
|
||||||
public class ClassFileNameHandler {
|
public class ClassFileNameHandler {
|
||||||
|
// we leave an extra 10 characters to allow for a numeric suffix to be added, if it's needed
|
||||||
|
private static final int MAX_FILENAME_LENGTH = 245;
|
||||||
|
|
||||||
private PackageNameEntry top;
|
private PackageNameEntry top;
|
||||||
private String fileExtension;
|
private String fileExtension;
|
||||||
private boolean modifyWindowsReservedFilenames;
|
private boolean modifyWindowsReservedFilenames;
|
||||||
@ -83,6 +87,10 @@ public class ClassFileNameHandler {
|
|||||||
packageElement += "#";
|
packageElement += "#";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (packageElement.length() > MAX_FILENAME_LENGTH) {
|
||||||
|
packageElement = shortenPathComponent(packageElement, MAX_FILENAME_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
packageElements[elementIndex++] = packageElement;
|
packageElements[elementIndex++] = packageElement;
|
||||||
elementStart = ++i;
|
elementStart = ++i;
|
||||||
}
|
}
|
||||||
@ -101,28 +109,44 @@ public class ClassFileNameHandler {
|
|||||||
packageElement += "#";
|
packageElement += "#";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((packageElement.length() + fileExtension.length()) > MAX_FILENAME_LENGTH) {
|
||||||
|
packageElement = shortenPathComponent(packageElement, MAX_FILENAME_LENGTH - fileExtension.length());
|
||||||
|
}
|
||||||
|
|
||||||
packageElements[elementIndex] = packageElement;
|
packageElements[elementIndex] = packageElement;
|
||||||
|
|
||||||
return top.addUniqueChild(packageElements, 0);
|
return top.addUniqueChild(packageElements, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean testForWindowsReservedFileNames(File path) {
|
@Nonnull
|
||||||
File f = new File(path, "aux.smali");
|
static String shortenPathComponent(@Nonnull String pathComponent, int maxLength) {
|
||||||
if (f.exists()) {
|
int toRemove = pathComponent.length() - maxLength + 1;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
int firstIndex = (pathComponent.length()/2) - (toRemove/2);
|
||||||
FileWriter writer = new FileWriter(f);
|
return pathComponent.substring(0, firstIndex) + "#" + pathComponent.substring(firstIndex+toRemove);
|
||||||
writer.write("test");
|
}
|
||||||
writer.flush();
|
|
||||||
writer.close();
|
private static boolean testForWindowsReservedFileNames(File path) {
|
||||||
f.delete(); //doesn't throw IOException
|
String[] reservedNames = new String[]{"aux", "con", "com1", "com9", "lpt1", "com9"};
|
||||||
return false;
|
|
||||||
} catch (IOException ex) {
|
for (String reservedName: reservedNames) {
|
||||||
//if an exception occured, it's likely that we're on a windows system.
|
File f = new File(path, reservedName + ".smali");
|
||||||
return true;
|
if (f.exists()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileWriter writer = new FileWriter(f);
|
||||||
|
writer.write("test");
|
||||||
|
writer.flush();
|
||||||
|
writer.close();
|
||||||
|
f.delete(); //doesn't throw IOException
|
||||||
|
} catch (IOException ex) {
|
||||||
|
//if an exception occured, it's likely that we're on a windows system.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Pattern reservedFileNameRegex = Pattern.compile("^CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9]$",
|
private static Pattern reservedFileNameRegex = Pattern.compile("^CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9]$",
|
||||||
@ -242,7 +266,6 @@ public class ClassFileNameHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pathElementsIndex == pathElements.length - 1) {
|
if (pathElementsIndex == pathElements.length - 1) {
|
||||||
String fileName;
|
String fileName;
|
||||||
if (!isCaseSensitive()) {
|
if (!isCaseSensitive()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user