General cleanup/refactoring/maintentance

- Added some additional context information for exceptions in various locations
- Refactored all code offsets so that they use 2-byte code block address, instead of a byte offset.
- Additionally changed all "offset" terminology refering to code offsets to "address" instead
- Changed the way the getItemByIndex and getOffsettedItemByOffset work, so that they throw an
exception if the index/offset is -1/0.
- Added additional getOptionalItemByIndex and getOptionalOffsettedItemByOffset methods, to be used
in the cases where an index/offset of -1/0 is valid, to indicate the absence of an item
- Other misc cleanup/maintentance

git-svn-id: https://smali.googlecode.com/svn/trunk@552 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com
2010-01-12 07:56:16 +00:00
parent 3ae5a27b60
commit 16a911620c
106 changed files with 937 additions and 906 deletions

View File

@ -28,6 +28,7 @@
package org.jf.dexlib;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.dexlib.Util.Input;
import org.jf.dexlib.Util.AnnotatedOutput;
@ -166,8 +167,8 @@ public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> {
/** {@inheritDoc} */
protected void readItem(Input in, ReadContext readContext) {
classAnnotations = (AnnotationSetItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_ANNOTATION_SET_ITEM,
in.readInt());
classAnnotations = (AnnotationSetItem)readContext.getOptionalOffsettedItemByOffset(
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
fieldAnnotationFields = new FieldIdItem[in.readInt()];
fieldAnnotations = new AnnotationSetItem[fieldAnnotationFields.length];
@ -178,21 +179,36 @@ public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> {
parameterAnnotations = new AnnotationSetRefList[parameterAnnotationMethods.length];
for (int i=0; i<fieldAnnotations.length; i++) {
fieldAnnotationFields[i] = dexFile.FieldIdsSection.getItemByIndex(in.readInt());
fieldAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset(
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
try {
fieldAnnotationFields[i] = dexFile.FieldIdsSection.getItemByIndex(in.readInt());
fieldAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset(
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex,
"Error occured while reading FieldAnnotation at index " + i);
}
}
for (int i=0; i<methodAnnotations.length; i++) {
methodAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt());
methodAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset(
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
try {
methodAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt());
methodAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset(
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex,
"Error occured while reading MethodAnnotation at index " + i);
}
}
for (int i=0; i<parameterAnnotations.length; i++) {
parameterAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt());
parameterAnnotations[i] = (AnnotationSetRefList)readContext.getOffsettedItemByOffset(
ItemType.TYPE_ANNOTATION_SET_REF_LIST, in.readInt());
try {
parameterAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt());
parameterAnnotations[i] = (AnnotationSetRefList)readContext.getOffsettedItemByOffset(
ItemType.TYPE_ANNOTATION_SET_REF_LIST, in.readInt());
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex,
"Error occured while reading ParameterAnnotation at index " + i);
}
}
}
@ -289,13 +305,17 @@ public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> {
}
}
/** {@inheritDoc} */public ItemType getItemType() {
/** {@inheritDoc} */
public ItemType getItemType() {
return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
}
/** {@inheritDoc} */
public String getConciseIdentity() {
return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
if (parent == null) {
return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
}
return "annotation_directory_item @0x" + Integer.toHexString(getOffset()) + " (" + parent.getClassType() + ")";
}
/** {@inheritDoc} */
@ -327,7 +347,13 @@ public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> {
*/
public void iterateFieldAnnotations(FieldAnnotationIteratorDelegate delegate) {
for (int i=0; i<fieldAnnotationFields.length; i++) {
delegate.processFieldAnnotations(fieldAnnotationFields[i], fieldAnnotations[i]);
try {
delegate.processFieldAnnotations(fieldAnnotationFields[i], fieldAnnotations[i]);
} catch (Exception ex) {
throw addExceptionContext(ExceptionWithContext.withContext(ex,
"Error occured while processing field annotations for field: " +
fieldAnnotationFields[i].getFieldString()));
}
}
}
@ -348,7 +374,13 @@ public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> {
*/
public void iterateMethodAnnotations(MethodAnnotationIteratorDelegate delegate) {
for (int i=0; i<methodAnnotationMethods.length; i++) {
delegate.processMethodAnnotations(methodAnnotationMethods[i], methodAnnotations[i]);
try {
delegate.processMethodAnnotations(methodAnnotationMethods[i], methodAnnotations[i]);
} catch (Exception ex) {
throw addExceptionContext(ExceptionWithContext.withContext(ex,
"Error occured while processing method annotations for method: " +
methodAnnotationMethods[i].getMethodString()));
}
}
}
@ -369,7 +401,13 @@ public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> {
*/
public void iterateParameterAnnotations(ParameterAnnotationIteratorDelegate delegate) {
for (int i=0; i<parameterAnnotationMethods.length; i++) {
delegate.processParameterAnnotations(parameterAnnotationMethods[i], parameterAnnotations[i]);
try {
delegate.processParameterAnnotations(parameterAnnotationMethods[i], parameterAnnotations[i]);
} catch (Exception ex) {
throw addExceptionContext(ExceptionWithContext.withContext(ex,
"Error occured while processing parameter annotations for method: " +
parameterAnnotationMethods[i].getMethodString()));
}
}
}

View File

@ -76,7 +76,7 @@ public class AnnotationSetRefList extends Item<AnnotationSetRefList> {
annotationSets = new AnnotationSetItem[in.readInt()];
for (int i=0; i<annotationSets.length; i++) {
annotationSets[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset(
annotationSets[i] = (AnnotationSetItem)readContext.getOptionalOffsettedItemByOffset(
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
}
}

View File

@ -28,6 +28,8 @@
package org.jf.dexlib;
import org.jf.dexlib.Util.ExceptionWithContext;
public enum AnnotationVisibility {
BUILD((byte)0),
RUNTIME((byte)1),
@ -47,7 +49,7 @@ public enum AnnotationVisibility {
case (byte)2:
return SYSTEM;
default:
throw new RuntimeException("Invalid annotation visibility value " + value);
throw new RuntimeException("Invalid annotation visibility value: " + value);
}
}
}

View File

@ -122,24 +122,40 @@ public class ClassDataItem extends Item<ClassDataItem> {
EncodedField previousEncodedField = null;
for (int i=0; i<staticFields.length; i++) {
staticFields[i] = previousEncodedField = new EncodedField(dexFile, in, previousEncodedField);
try {
staticFields[i] = previousEncodedField = new EncodedField(dexFile, in, previousEncodedField);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading static field at index " + i);
}
}
previousEncodedField = null;
for (int i=0; i<instanceFields.length; i++) {
instanceFields[i] = previousEncodedField = new EncodedField(dexFile, in, previousEncodedField);
try {
instanceFields[i] = previousEncodedField = new EncodedField(dexFile, in, previousEncodedField);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading instance field at index " + i);
}
}
EncodedMethod previousEncodedMethod = null;
for (int i=0; i<directMethods.length; i++) {
directMethods[i] = previousEncodedMethod = new EncodedMethod(dexFile, readContext, in,
previousEncodedMethod);
try {
directMethods[i] = previousEncodedMethod = new EncodedMethod(dexFile, readContext, in,
previousEncodedMethod);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading direct method at index " + i);
}
}
previousEncodedMethod = null;
for (int i=0; i<virtualMethods.length; i++) {
virtualMethods[i] = previousEncodedMethod = new EncodedMethod(dexFile, readContext, in,
previousEncodedMethod);
try {
virtualMethods[i] = previousEncodedMethod = new EncodedMethod(dexFile, readContext, in,
previousEncodedMethod);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading virtual method at index " + i);
}
}
}
@ -271,7 +287,10 @@ public class ClassDataItem extends Item<ClassDataItem> {
/** {@inheritDoc} */
public String getConciseIdentity() {
return "class_data_item @0x" + Integer.toHexString(getOffset());
if (parent == null) {
return "class_data_item @0x" + Integer.toHexString(getOffset());
}
return "class_data_item @0x" + Integer.toHexString(getOffset()) + " (" + parent.getClassType() +")";
}
/** {@inheritDoc} */
@ -459,7 +478,8 @@ public class ClassDataItem extends Item<ClassDataItem> {
int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex();
method = dexFile.MethodIdsSection.getItemByIndex(in.readUnsignedLeb128() + previousIndex);
accessFlags = in.readUnsignedLeb128();
codeItem = (CodeItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_CODE_ITEM, in.readUnsignedLeb128());
codeItem = (CodeItem)readContext.getOptionalOffsettedItemByOffset(ItemType.TYPE_CODE_ITEM,
in.readUnsignedLeb128());
if (codeItem != null) {
codeItem.setParent(this);
}
@ -480,7 +500,7 @@ public class ClassDataItem extends Item<ClassDataItem> {
out.annotate("access_flags: " + AccessFlags.formatAccessFlagsForMethod(accessFlags));
out.writeUnsignedLeb128(accessFlags);
if (codeItem != null) {
out.annotate("code_off: 0x" + codeItem.getOffset());
out.annotate("code_off: 0x" + Integer.toHexString(codeItem.getOffset()));
out.writeUnsignedLeb128(codeItem.getOffset());
} else {
out.annotate("code_off: 0x0");

View File

@ -76,6 +76,7 @@ public class ClassDefItem extends Item<ClassDefItem> {
AnnotationDirectoryItem annotations, ClassDataItem classData,
EncodedArrayItem staticFieldInitializers) {
super(dexFile);
assert classType != null;
this.classType = classType;
this.accessFlags = accessFlags;
this.superType = superType;
@ -131,14 +132,14 @@ public class ClassDefItem extends Item<ClassDefItem> {
protected void readItem(Input in, ReadContext readContext) {
classType = dexFile.TypeIdsSection.getItemByIndex(in.readInt());
accessFlags = in.readInt();
superType = dexFile.TypeIdsSection.getItemByIndex(in.readInt());
implementedInterfaces = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST,
superType = dexFile.TypeIdsSection.getOptionalItemByIndex(in.readInt());
implementedInterfaces = (TypeListItem)readContext.getOptionalOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST,
in.readInt());
sourceFile = dexFile.StringIdsSection.getItemByIndex(in.readInt());
annotations = (AnnotationDirectoryItem)readContext.getOffsettedItemByOffset(
sourceFile = dexFile.StringIdsSection.getOptionalItemByIndex(in.readInt());
annotations = (AnnotationDirectoryItem)readContext.getOptionalOffsettedItemByOffset(
ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM, in.readInt());
classData = (ClassDataItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_CLASS_DATA_ITEM, in.readInt());
staticFieldInitializers = (EncodedArrayItem)readContext.getOffsettedItemByOffset(
classData = (ClassDataItem)readContext.getOptionalOffsettedItemByOffset(ItemType.TYPE_CLASS_DATA_ITEM, in.readInt());
staticFieldInitializers = (EncodedArrayItem)readContext.getOptionalOffsettedItemByOffset(
ItemType.TYPE_ENCODED_ARRAY_ITEM, in.readInt());
if (classData != null) {

View File

@ -41,10 +41,8 @@ public class ArrayDataPseudoInstruction extends Instruction {
private byte[] encodedValues;
@Override
public int getSize(int offset) {
assert offset % 2 == 0;
int size = getElementWidth() * getElementCount();
return size + (size & 0x01) + 8 + (offset % 4);
public int getSize(int codeAddress) {
return ((encodedValues.length + 1)/2) + 4 + (codeAddress % 2);
}
public ArrayDataPseudoInstruction(int elementWidth, byte[] encodedValues) {
@ -77,11 +75,8 @@ public class ArrayDataPseudoInstruction extends Instruction {
System.arraycopy(buffer, bufferIndex+8, encodedValues, 0, elementCount * elementWidth);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
//write out padding, if necessary
if (out.getCursor() % 4 != 0) {
out.writeShort(0);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.alignTo(4);
int elementCount = encodedValues.length / elementWidth;
@ -90,14 +85,13 @@ public class ArrayDataPseudoInstruction extends Instruction {
out.writeShort(elementWidth);
out.writeInt(elementCount);
out.write(encodedValues);
if ((encodedValues.length % 2) != 0) {
//must write out an even number of bytes
out.writeByte(0);
}
//make sure we're written out an even number of bytes
out.alignTo(2);
}
protected void annotateInstruction(AnnotatedOutput out, int currentCodeOffset) {
out.annotate(getSize(currentCodeOffset), "[0x" + Integer.toHexString(currentCodeOffset/2) + "] " +
protected void annotateInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.annotate(getSize(currentCodeAddress)*2, "[0x" + Integer.toHexString(currentCodeAddress) + "] " +
"fill-array-data instruction");
}
@ -149,7 +143,7 @@ public class ArrayDataPseudoInstruction extends Instruction {
private static class Factory implements Instruction.InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
if (opcode != Opcode.NOP) {
throw new RuntimeException("The opcode for an ArrayDataPseudoInstruction must by NOP");
throw new RuntimeException("The opcode for an ArrayDataPseudoInstruction must be NOP");
}
return new ArrayDataPseudoInstruction(buffer, bufferIndex);
}

View File

@ -39,13 +39,13 @@ public class DeadInstruction extends Instruction {
this.OriginalInstruction = originalInstruction;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
//don't write anything
}
@Override
public int getSize(int offset) {
return OriginalInstruction.getSize(offset);
public int getSize(int codeAddress) {
return OriginalInstruction.getSize(codeAddress);
}
public Format getFormat() {

View File

@ -36,17 +36,17 @@ import org.jf.dexlib.Util.AnnotatedOutput;
public class Instruction10t extends Instruction implements OffsetInstruction {
public static final InstructionFactory Factory = new Factory();
private int offset;
private int targetAddressOffset;
public Instruction10t(Opcode opcode, int offA) {
super(opcode);
this.offset = offA;
this.targetAddressOffset = offA;
if (offset == 0) {
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead.");
if (targetAddressOffset == 0) {
throw new RuntimeException("The address offset cannot be 0. Use goto/32 instead.");
}
//allow out of range offsets here, so we have the option of replacing this instruction
//allow out of range address offsets here, so we have the option of replacing this instruction
//with goto/16 or goto/32 later
}
@ -55,33 +55,33 @@ public class Instruction10t extends Instruction implements OffsetInstruction {
assert buffer[bufferIndex] == opcode.value;
this.offset = buffer[bufferIndex + 1];
assert offset != 0;
this.targetAddressOffset = buffer[bufferIndex + 1];
assert targetAddressOffset != 0;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
if (offset == 0) {
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead");
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
if (targetAddressOffset == 0) {
throw new RuntimeException("The address offset cannot be 0. Use goto/32 instead");
}
if (offset < -128 || offset > 127) {
throw new RuntimeException("The offset is out of range. It must be in [-128,-1] or [1, 127]");
if (targetAddressOffset < -128 || targetAddressOffset > 127) {
throw new RuntimeException("The address offset is out of range. It must be in [-128,-1] or [1, 127]");
}
out.writeByte(opcode.value);
out.writeByte(offset);
out.writeByte(targetAddressOffset);
}
public void updateOffset(int offset) {
this.offset = offset;
public void updateTargetAddressOffset(int targetAddressOffset) {
this.targetAddressOffset = targetAddressOffset;
}
public Format getFormat() {
return Format.Format10t;
}
public int getOffset() {
return offset;
public int getTargetAddressOffset() {
return targetAddressOffset;
}
private static class Factory implements InstructionFactory {

View File

@ -47,7 +47,7 @@ public class Instruction10x extends Instruction {
assert buffer[bufferIndex + 1] == 0x00;
}
public void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
public void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(0);
}

View File

@ -64,7 +64,7 @@ public class Instruction11n extends Instruction implements SingleRegisterInstruc
this.litB = NumberUtils.decodeHighSignedNibble(buffer[bufferIndex + 1]);
}
public void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
public void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((litB << 4) | regA);
}

View File

@ -55,7 +55,7 @@ public class Instruction11x extends Instruction implements SingleRegisterInstruc
this.regA = (byte)NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
}
public void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
public void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
}

View File

@ -58,7 +58,7 @@ public class Instruction12x extends Instruction implements TwoRegisterInstructio
this.regB = NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]);
}
public void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
public void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
}

View File

@ -37,17 +37,17 @@ import org.jf.dexlib.Util.NumberUtils;
public class Instruction20t extends Instruction implements OffsetInstruction {
public static final InstructionFactory Factory = new Factory();
private int offset;
private int targetAddressOffset;
public Instruction20t(Opcode opcode, int offA) {
super(opcode);
this.offset = offA;
this.targetAddressOffset = offA;
if (offset == 0) {
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead.");
if (targetAddressOffset == 0) {
throw new RuntimeException("The address offset cannot be 0. Use goto/32 instead.");
}
//allow out of range offsets here, so we have the option of replacing this instruction
//allow out of range address offsets here, so we have the option of replacing this instruction
//with goto/16 or goto/32 later
}
@ -56,34 +56,34 @@ public class Instruction20t extends Instruction implements OffsetInstruction {
assert buffer[bufferIndex] == opcode.value;
this.offset = NumberUtils.decodeShort(buffer, bufferIndex+2);
assert offset != 0;
this.targetAddressOffset = NumberUtils.decodeShort(buffer, bufferIndex+2);
assert targetAddressOffset != 0;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
if (offset == 0) {
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead");
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
if (targetAddressOffset == 0) {
throw new RuntimeException("The address offset cannot be 0. Use goto/32 instead");
}
if (offset < -32768 || offset > 32767) {
throw new RuntimeException("The offset is out of range. It must be in [-32768,-1] or [1, 32768]");
if (targetAddressOffset < -32768 || targetAddressOffset > 32767) {
throw new RuntimeException("The address offset is out of range. It must be in [-32768,-1] or [1, 32768]");
}
out.writeByte(opcode.value);
out.writeByte(0x00);
out.writeShort(offset);
out.writeShort(targetAddressOffset);
}
public void updateOffset(int offset) {
this.offset = offset;
public void updateTargetAddressOffset(int targetAddressOffset) {
this.targetAddressOffset = targetAddressOffset;
}
public Format getFormat() {
return Format.Format20t;
}
public int getOffset() {
return offset;
public int getTargetAddressOffset() {
return targetAddressOffset;
}
private static class Factory implements InstructionFactory {

View File

@ -68,7 +68,7 @@ public class Instruction21c extends InstructionWithReference implements SingleRe
this.regA = buffer[bufferIndex + 1];
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
if(opcode == Opcode.CONST_STRING && getReferencedItem().getIndex() > 0xFFFF) {
throw new RuntimeException("String offset is too large for const-string. Use string-const/jumbo instead.");
}

View File

@ -59,7 +59,7 @@ public class Instruction21h extends Instruction implements SingleRegisterInstruc
this.litB = NumberUtils.decodeShort(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(litB);

View File

@ -59,7 +59,7 @@ public class Instruction21s extends Instruction implements SingleRegisterInstruc
this.litB = NumberUtils.decodeShort(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(litB);

View File

@ -36,7 +36,7 @@ import org.jf.dexlib.Util.AnnotatedOutput;
public class Instruction21t extends Instruction implements OffsetInstruction, SingleRegisterInstruction {
public static final Instruction.InstructionFactory Factory = new Factory();
private byte regA;
private short offset;
private short targetAddressOffset;
public Instruction21t(Opcode opcode, short regA, short offB) {
super(opcode);
@ -46,11 +46,11 @@ public class Instruction21t extends Instruction implements OffsetInstruction, Si
}
if (offB == 0) {
throw new RuntimeException("The offset cannot be 0.");
throw new RuntimeException("The address offset cannot be 0.");
}
this.regA = (byte)regA;
this.offset = offB;
this.targetAddressOffset = offB;
}
private Instruction21t(Opcode opcode, byte[] buffer, int bufferIndex) {
@ -59,24 +59,25 @@ public class Instruction21t extends Instruction implements OffsetInstruction, Si
assert buffer[bufferIndex] == opcode.value;
regA = buffer[bufferIndex + 1];
offset = NumberUtils.decodeShort(buffer, bufferIndex + 2);
assert offset != 0;
targetAddressOffset = NumberUtils.decodeShort(buffer, bufferIndex + 2);
assert targetAddressOffset != 0;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(offset);
out.writeShort(targetAddressOffset);
}
public void updateOffset(int offset) {
if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
throw new RuntimeException("The offset " + offset + " is out of range. It must be in [-32768, 32767]");
public void updateTargetAddressOffset(int targetAddressOffset) {
if (targetAddressOffset < Short.MIN_VALUE || targetAddressOffset > Short.MAX_VALUE) {
throw new RuntimeException("The address offset " + targetAddressOffset +
" is out of range. It must be in [-32768, 32767]");
}
if (offset == 0) {
throw new RuntimeException("The offset cannot be 0");
if (targetAddressOffset == 0) {
throw new RuntimeException("The address offset cannot be 0");
}
this.offset = (short)offset;
this.targetAddressOffset = (short) targetAddressOffset;
}
public Format getFormat() {
@ -87,8 +88,8 @@ public class Instruction21t extends Instruction implements OffsetInstruction, Si
return regA & 0xFF;
}
public int getOffset() {
return offset;
public int getTargetAddressOffset() {
return targetAddressOffset;
}
private static class Factory implements Instruction.InstructionFactory {

View File

@ -62,7 +62,7 @@ public class Instruction22b extends Instruction implements TwoRegisterInstructio
this.litC = buffer[bufferIndex + 3];
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeByte(regB);

View File

@ -61,7 +61,7 @@ public class Instruction22c extends InstructionWithReference implements TwoRegis
this.regB = NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
out.writeShort(getReferencedItem().getIndex());

View File

@ -66,7 +66,7 @@ public class Instruction22cs extends Instruction implements TwoRegisterInstructi
this.fieldOffset = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
out.writeShort(fieldOffset);

View File

@ -43,7 +43,7 @@ public class Instruction22csf extends InstructionWithReference implements TwoReg
this.unfixedInstruction = unfixedInstruction;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
byte regA = (byte)getRegisterA();
byte regB = (byte)getRegisterB();

View File

@ -63,7 +63,7 @@ public class Instruction22s extends Instruction implements TwoRegisterInstructio
this.litC = NumberUtils.decodeShort(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
out.writeShort(litC);

View File

@ -40,7 +40,7 @@ public class Instruction22t extends Instruction implements OffsetInstruction, Tw
public static final Instruction.InstructionFactory Factory = new Factory();
private byte regA;
private byte regB;
private short offset;
private short targetAddressOffset;
public Instruction22t(Opcode opcode, byte regA, byte regB, short offC) {
super(opcode);
@ -51,12 +51,12 @@ public class Instruction22t extends Instruction implements OffsetInstruction, Tw
}
if (offC == 0) {
throw new RuntimeException("The offset cannot be 0.");
throw new RuntimeException("The address offset cannot be 0.");
}
this.regA = regA;
this.regB = regB;
this.offset = offC;
this.targetAddressOffset = offC;
}
private Instruction22t(Opcode opcode, byte[] buffer, int bufferIndex) {
@ -66,25 +66,26 @@ public class Instruction22t extends Instruction implements OffsetInstruction, Tw
regA = NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]);
regB = NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]);
offset = NumberUtils.decodeShort(buffer, bufferIndex + 2);
targetAddressOffset = NumberUtils.decodeShort(buffer, bufferIndex + 2);
assert offset != 0;
assert targetAddressOffset != 0;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((regB << 4) | regA);
out.writeShort(offset);
out.writeShort(targetAddressOffset);
}
public void updateOffset(int offset) {
if (offset < -32768 || offset > 32767) {
throw new RuntimeException("The offset " + offset + " is out of range. It must be in [-32768, 32767]");
public void updateTargetAddressOffset(int targetAddressOffset) {
if (targetAddressOffset < -32768 || targetAddressOffset > 32767) {
throw new RuntimeException("The address offset " + targetAddressOffset +
" is out of range. It must be in [-32768, 32767]");
}
if (offset == 0) {
throw new RuntimeException("The offset cannot be 0");
if (targetAddressOffset == 0) {
throw new RuntimeException("The address offset cannot be 0");
}
this.offset = (short)offset;
this.targetAddressOffset = (short)targetAddressOffset;
}
public Format getFormat() {
@ -99,8 +100,8 @@ public class Instruction22t extends Instruction implements OffsetInstruction, Tw
return regB;
}
public int getOffset() {
return offset;
public int getTargetAddressOffset() {
return targetAddressOffset;
}
private static class Factory implements Instruction.InstructionFactory {

View File

@ -62,7 +62,7 @@ public class Instruction22x extends Instruction implements TwoRegisterInstructio
this.regB = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeShort(regB);

View File

@ -62,7 +62,7 @@ public class Instruction23x extends Instruction implements ThreeRegisterInstruct
this.regC = buffer[bufferIndex + 3];
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeByte(regB);

View File

@ -37,11 +37,11 @@ import org.jf.dexlib.Util.NumberUtils;
public class Instruction30t extends Instruction implements OffsetInstruction {
public static final InstructionFactory Factory = new Factory();
private int offset;
private int targetAddressOffset;
public Instruction30t(Opcode opcode, int offA) {
super(opcode);
this.offset = offA;
this.targetAddressOffset = offA;
}
private Instruction30t(Opcode opcode, byte[] buffer, int bufferIndex) {
@ -49,25 +49,25 @@ public class Instruction30t extends Instruction implements OffsetInstruction {
assert buffer[bufferIndex] == opcode.value;
this.offset = NumberUtils.decodeInt(buffer, bufferIndex+2);
this.targetAddressOffset = NumberUtils.decodeInt(buffer, bufferIndex+2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(0x00);
out.writeInt(offset);
out.writeInt(targetAddressOffset);
}
public void updateOffset(int offset) {
this.offset = offset;
public void updateTargetAddressOffset(int targetAddressOffset) {
this.targetAddressOffset = targetAddressOffset;
}
public Format getFormat() {
return Format.Format30t;
}
public int getOffset() {
return offset;
public int getTargetAddressOffset() {
return targetAddressOffset;
}
private static class Factory implements InstructionFactory {

View File

@ -57,7 +57,7 @@ public class Instruction31c extends InstructionWithReference implements SingleRe
this.regA = buffer[bufferIndex + 1];
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeInt(getReferencedItem().getIndex());

View File

@ -59,7 +59,7 @@ public class Instruction31i extends Instruction implements SingleRegisterInstruc
this.litB = NumberUtils.decodeInt(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeInt(litB);

View File

@ -39,7 +39,7 @@ import org.jf.dexlib.Util.AnnotatedOutput;
public class Instruction31t extends Instruction implements OffsetInstruction, SingleRegisterInstruction {
public static final Instruction.InstructionFactory Factory = new Factory();
private byte regA;
private int offset;
private int targetAddressOffset;
public Instruction31t(Opcode opcode, short regA, int offB) {
super(opcode);
@ -49,24 +49,25 @@ public class Instruction31t extends Instruction implements OffsetInstruction, Si
}
this.regA = (byte)regA;
this.offset = offB;
this.targetAddressOffset = offB;
}
private Instruction31t(Opcode opcode, byte[] buffer, int bufferIndex) {
super(opcode);
this.regA = buffer[bufferIndex + 1];
this.offset = NumberUtils.decodeInt(buffer, bufferIndex + 2);
this.targetAddressOffset = NumberUtils.decodeInt(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeInt(offset + (((currentCodeOffset/2) + offset) % 2));
//align the address offset so that the absolute address is aligned on a 4-byte boundary (2 code block boundary)
out.writeInt(targetAddressOffset + ((currentCodeAddress + targetAddressOffset) % 2));
}
public void updateOffset(int offset) {
this.offset = offset;
public void updateTargetAddressOffset(int targetAddressOffset) {
this.targetAddressOffset = targetAddressOffset;
}
public Format getFormat() {
@ -77,8 +78,8 @@ public class Instruction31t extends Instruction implements OffsetInstruction, Si
return regA & 0xFF;
}
public int getOffset() {
return offset;
public int getTargetAddressOffset() {
return targetAddressOffset;
}
private static class Factory implements Instruction.InstructionFactory {

View File

@ -59,7 +59,7 @@ public class Instruction32x extends Instruction implements TwoRegisterInstructio
this.regB = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(0);
out.writeShort(regA);

View File

@ -92,7 +92,7 @@ public class Instruction35c extends InstructionWithReference implements FiveRegi
checkItem(opcode, getReferencedItem(), getRegCount());
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((regCount << 4) | regA);
out.writeShort(getReferencedItem().getIndex());

View File

@ -86,7 +86,7 @@ public class Instruction35ms extends Instruction implements FiveRegisterInstruct
this.methodIndex = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((regCount << 4) | regA);
out.writeShort(methodIndex);

View File

@ -43,7 +43,7 @@ public class Instruction35msf extends InstructionWithReference implements FiveRe
this.unfixedInstruction = unfixedInstruction;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
byte regA = getRegisterA();
byte regCount = getRegCount();
byte regD = getRegisterD();

View File

@ -92,7 +92,7 @@ public class Instruction35s extends InstructionWithReference implements FiveRegi
this.regG = NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 5]);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte((regCount << 4) | regA);
out.writeShort(getReferencedItem().getIndex());

View File

@ -41,7 +41,7 @@ public class Instruction35sf extends InstructionWithReference implements FiveReg
this.unfixedInstruction = unfixedInstruction;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
byte regA = getRegisterA();
byte regCount = getRegCount();
byte regD = getRegisterD();

View File

@ -78,7 +78,7 @@ public class Instruction3rc extends InstructionWithReference implements Register
checkItem(opcode, getReferencedItem(), getRegCount());
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regCount);
out.writeShort(this.getReferencedItem().getIndex());

View File

@ -75,7 +75,7 @@ public class Instruction3rms extends Instruction implements RegisterRangeInstruc
this.startReg = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regCount);
out.writeShort(methodIndex);

View File

@ -43,7 +43,7 @@ public class Instruction3rmsf extends InstructionWithReference implements Regist
this.unfixedInstruction = unfixedInstruction;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
short regCount = getRegCount();
int startReg = getStartRegister();

View File

@ -59,7 +59,7 @@ public class Instruction51l extends Instruction implements SingleRegisterInstruc
litB = NumberUtils.decodeLong(buffer, bufferIndex + 2);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(opcode.value);
out.writeByte(regA);
out.writeLong(litB);

View File

@ -43,9 +43,8 @@ public class PackedSwitchDataPseudoInstruction extends Instruction implements Mu
private int[] targets;
@Override
public int getSize(int offset) {
assert offset % 2 == 0;
return getTargetCount() * 4 + 8 + (offset % 4);
public int getSize(int codeAddress) {
return getTargetCount() * 2 + 4 + (codeAddress % 2);
}
public PackedSwitchDataPseudoInstruction(int firstKey, int[] targets) {
@ -81,11 +80,8 @@ public class PackedSwitchDataPseudoInstruction extends Instruction implements Mu
}
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
//write out padding, if necessary
if (currentCodeOffset % 4 != 0) {
out.writeShort(0);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.alignTo(4);
out.writeByte(0x00);
out.writeByte(0x01);
@ -97,13 +93,13 @@ public class PackedSwitchDataPseudoInstruction extends Instruction implements Mu
}
}
protected void annotateInstruction(AnnotatedOutput out, int currentCodeOffset) {
out.annotate(getSize(currentCodeOffset), "[0x" + Integer.toHexString(currentCodeOffset/2) + "] " +
protected void annotateInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.annotate(getSize(currentCodeAddress)*2, "[0x" + Integer.toHexString(currentCodeAddress) + "] " +
"packed-switch-data instruction");
}
public void updateTarget(int targetIndex, int targetOffset) {
targets[targetIndex] = targetOffset;
public void updateTarget(int targetIndex, int targetAddressOffset) {
targets[targetIndex] = targetAddressOffset;
}
public Format getFormat() {
@ -124,7 +120,7 @@ public class PackedSwitchDataPseudoInstruction extends Instruction implements Mu
public static class PackedSwitchTarget {
public int value;
public int target;
public int targetAddressOffset;
}
public Iterator<PackedSwitchTarget> iterateKeysAndTargets() {
@ -141,7 +137,7 @@ public class PackedSwitchDataPseudoInstruction extends Instruction implements Mu
public PackedSwitchTarget next() {
packedSwitchTarget.value = value++;
packedSwitchTarget.target = targets[i];
packedSwitchTarget.targetAddressOffset = targets[i];
i++;
return packedSwitchTarget;
}
@ -151,14 +147,10 @@ public class PackedSwitchDataPseudoInstruction extends Instruction implements Mu
};
}
public static interface PackedSwitchTargetIteratorDelegate {
void ProcessPackedSwitchTarget(int value, int target);
}
private static class Factory implements Instruction.InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
if (opcode != Opcode.NOP) {
throw new RuntimeException("The opcode for a PackedSwitchDataPseudoInstruction must by NOP");
throw new RuntimeException("The opcode for a PackedSwitchDataPseudoInstruction must be NOP");
}
return new PackedSwitchDataPseudoInstruction(buffer, bufferIndex);
}

View File

@ -43,16 +43,15 @@ public class SparseSwitchDataPseudoInstruction extends Instruction implements Mu
private int[] targets;
@Override
public int getSize(int offset) {
assert offset % 2 == 0;
return getTargetCount() * 8 + 4 + (offset % 4);
public int getSize(int codeAddress) {
return getTargetCount() * 4 + 2 + (codeAddress % 2);
}
public SparseSwitchDataPseudoInstruction(int[] keys, int[] targets) {
super(Opcode.NOP);
if (keys.length != targets.length) {
throw new RuntimeException("The number of keys and offsets don't match");
throw new RuntimeException("The number of keys and targets don't match");
}
if (targets.length == 0) {
@ -90,11 +89,8 @@ public class SparseSwitchDataPseudoInstruction extends Instruction implements Mu
}
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
//write out padding, if necessary
if (currentCodeOffset % 4 != 0) {
out.writeShort(0);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.alignTo(4);
out.writeByte(0x00);
out.writeByte(0x02);
@ -117,13 +113,13 @@ public class SparseSwitchDataPseudoInstruction extends Instruction implements Mu
}
}
protected void annotateInstruction(AnnotatedOutput out, int currentCodeOffset) {
out.annotate(getSize(currentCodeOffset), "[0x" + Integer.toHexString(currentCodeOffset/2) + "] " +
protected void annotateInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.annotate(getSize(currentCodeAddress)*2, "[0x" + Integer.toHexString(currentCodeAddress) + "] " +
"sparse-switch-data instruction");
}
public void updateTarget(int targetIndex, int targetOffset) {
targets[targetIndex] = targetOffset;
public void updateTarget(int targetIndex, int targetAddressOffset) {
targets[targetIndex] = targetAddressOffset;
}
public Format getFormat() {
@ -144,7 +140,7 @@ public class SparseSwitchDataPseudoInstruction extends Instruction implements Mu
public static class SparseSwitchTarget {
public int key;
public int target;
public int targetAddressOffset;
}
public Iterator<SparseSwitchTarget> iterateKeysAndTargets() {
@ -160,7 +156,7 @@ public class SparseSwitchDataPseudoInstruction extends Instruction implements Mu
public SparseSwitchTarget next() {
sparseSwitchTarget.key = keys[i];
sparseSwitchTarget.target = targets[i];
sparseSwitchTarget.targetAddressOffset = targets[i];
i++;
return sparseSwitchTarget;
}
@ -173,7 +169,7 @@ public class SparseSwitchDataPseudoInstruction extends Instruction implements Mu
private static class Factory implements Instruction.InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
if (opcode != Opcode.NOP) {
throw new RuntimeException("The opcode for a SparseSwitchDataPseudoInstruction must by NOP");
throw new RuntimeException("The opcode for a SparseSwitchDataPseudoInstruction must be NOP");
}
return new SparseSwitchDataPseudoInstruction(buffer, bufferIndex);
}

View File

@ -47,13 +47,13 @@ public class UnresolvedNullReference extends Instruction {
this.ObjectRegisterNum = objectRegisterNumber;
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeOffset) {
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
throw new RuntimeException("Cannot rewrite an instruction that couldn't be deodexed");
}
@Override
public int getSize(int offset) {
return OriginalInstruction.getSize(offset);
public int getSize(int codeAddress) {
return OriginalInstruction.getSize(codeAddress);
}
public Format getFormat() {

View File

@ -29,15 +29,19 @@
package org.jf.dexlib.Code;
import org.jf.dexlib.*;
import org.jf.dexlib.Util.ByteArrayInput;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Code.Format.Format;
public abstract class Instruction {
public final Opcode opcode;
public int getSize(int offset) {
return opcode.format.size;
/**
* Returns the size of this instruction in code blocks, assuming the instruction is located at the given address
* @param codeAddress the code address where the instruction is located
* @return The size of this instruction in code blocks
**/
public int getSize(int codeAddress) {
return opcode.format.size/2;
}
protected Instruction(Opcode opcode) {
@ -46,20 +50,20 @@ public abstract class Instruction {
public abstract Format getFormat();
public int write(AnnotatedOutput out, int currentCodeOffset) {
public int write(AnnotatedOutput out, int currentCodeAddress) {
if (out.annotates()) {
annotateInstruction(out, currentCodeOffset);
annotateInstruction(out, currentCodeAddress);
}
writeInstruction(out, currentCodeOffset);
return currentCodeOffset + getSize(currentCodeOffset);
writeInstruction(out, currentCodeAddress);
return currentCodeAddress + getSize(currentCodeAddress);
}
protected void annotateInstruction(AnnotatedOutput out, int currentCodeOffset) {
out.annotate(getSize(currentCodeOffset), "[0x" + Integer.toHexString(currentCodeOffset/2) + "] " +
protected void annotateInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.annotate(getSize(currentCodeAddress)*2, "[0x" + Integer.toHexString(currentCodeAddress) + "] " +
opcode.name + " instruction");
}
protected abstract void writeInstruction(AnnotatedOutput out, int currentCodeOffset);
protected abstract void writeInstruction(AnnotatedOutput out, int currentCodeAddress);
public static interface InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex);

View File

@ -28,177 +28,65 @@
package org.jf.dexlib.Code;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.dexlib.Util.Hex;
import org.jf.dexlib.Util.NumberUtils;
import org.jf.dexlib.Code.Format.*;
import org.jf.dexlib.DexFile;
public class InstructionIterator {
/**
* This method partially decodes the instructions in the given byte array and iterates over them, calling
* the appropriate ProcessRawInstructionDelegate method for each instruction
* @param insns a byte array containing the instructions
* @param processRawInstruction a <code>ProcessInstructionDelegate</code> object containing the methods
* that get called for each instruction that is encountered
*/
public static void IterateInstructions(byte[] insns, ProcessRawInstructionDelegate processRawInstruction) {
public static void IterateInstructions(DexFile dexFile, byte[] insns, ProcessInstructionDelegate delegate) {
int insnsPosition = 0;
while (insnsPosition < insns.length) {
Opcode opcode = Opcode.getOpcodeByValue(insns[insnsPosition]);
try
{
Opcode opcode = Opcode.getOpcodeByValue(insns[insnsPosition]);
if (opcode == null) {
throw new RuntimeException("Unknown opcode: " + Hex.u1(insns[insnsPosition]));
}
Instruction instruction = null;
if (opcode.referenceType == ReferenceType.none) {
byte secondByte = insns[insnsPosition+1];
//if this is one of the "special" opcodes
if (opcode == Opcode.NOP && secondByte > 0) {
if (opcode == null) {
throw new RuntimeException("Unknown opcode: " + Hex.u1(insns[insnsPosition]));
}
if (opcode == Opcode.NOP) {
byte secondByte = insns[insnsPosition + 1];
switch (secondByte) {
case 0:
{
instruction = new Instruction10x(Opcode.NOP, insns, insnsPosition);
break;
}
case 1:
{
//packed-switch
int size = NumberUtils.decodeUnsignedShort(insns[insnsPosition+2], insns[insnsPosition+3]);
int end = insnsPosition + size * 4 + 8;
processRawInstruction.ProcessPackedSwitchInstruction(insnsPosition, size, end-insnsPosition);
insnsPosition = end;
instruction = new PackedSwitchDataPseudoInstruction(insns, insnsPosition);
break;
}
case 2:
{
//sparse-switch
int size = NumberUtils.decodeUnsignedShort(insns[insnsPosition+2], insns[insnsPosition+3]);
int end = insnsPosition + size * 8 + 4;
processRawInstruction.ProcessSparseSwitchInstruction(insnsPosition, size, end-insnsPosition);
insnsPosition = end;
instruction = new SparseSwitchDataPseudoInstruction(insns, insnsPosition);
break;
}
case 3:
{
//fill-array-data
int elementWidth = NumberUtils.decodeUnsignedShort(insns[insnsPosition+2],
insns[insnsPosition+3]);
int size = NumberUtils.decodeInt(insns[insnsPosition+4], insns[insnsPosition+5],
insns[insnsPosition+6], insns[insnsPosition+7]);
int end = insnsPosition + (size * elementWidth) + 8;
if (end % 2 == 1) {
end++;
}
processRawInstruction.ProcessFillArrayDataInstruction(insnsPosition, elementWidth, size,
end-insnsPosition);
insnsPosition = end;
instruction = new ArrayDataPseudoInstruction(insns, insnsPosition);
break;
}
}
} else {
processRawInstruction.ProcessNormalInstruction(opcode, insnsPosition);
insnsPosition += opcode.format.size;
instruction = opcode.format.Factory.makeInstruction(dexFile, opcode, insns, insnsPosition);
}
} else {
processRawInstruction.ProcessReferenceInstruction(opcode, insnsPosition);
insnsPosition += opcode.format.size;
assert instruction != null;
delegate.ProcessInstruction(insnsPosition/2, instruction);
insnsPosition += instruction.getSize(insnsPosition/2)*2;
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error occured at code address " + insnsPosition * 2);
}
}
}
public static void IterateInstructions(DexFile dexFile, byte[] insns, ProcessInstructionDelegate delegate) {
int currentCodeOffset = 0;
while (currentCodeOffset < insns.length) {
Opcode opcode = Opcode.getOpcodeByValue(insns[currentCodeOffset]);
Instruction instruction = null;
if (opcode == null) {
throw new RuntimeException("Unknown opcode: " + Hex.u1(insns[currentCodeOffset]));
}
if (opcode == Opcode.NOP) {
byte secondByte = insns[currentCodeOffset+1];
switch (secondByte) {
case 0:
{
instruction = new Instruction10x(Opcode.NOP, insns, currentCodeOffset);
break;
}
case 1:
{
instruction = new PackedSwitchDataPseudoInstruction(insns, currentCodeOffset);
break;
}
case 2:
{
instruction = new SparseSwitchDataPseudoInstruction(insns, currentCodeOffset);
break;
}
case 3:
{
instruction = new ArrayDataPseudoInstruction(insns, currentCodeOffset);
break;
}
}
} else {
instruction = opcode.format.Factory.makeInstruction(dexFile, opcode, insns, currentCodeOffset);
}
assert instruction != null;
delegate.ProcessInstruction(currentCodeOffset, instruction);
currentCodeOffset += instruction.getSize(currentCodeOffset);
}
}
public static interface ProcessRawInstructionDelegate {
/**
* The <code>InstructionIterator</code> calls this method when a "normal" instruction is encountered. I.e.
* not a special or reference instruction
* @param opcode the opcode of the instruction that was encountered
* @param index the start index of the instruction in the byte array that the
* <code>InstructionIterator</code> is iterating
*/
public void ProcessNormalInstruction(Opcode opcode, int index);
/**
* The <code>InstructionIterator</code> calls this method when a "reference" instruction is encountered.
* I.e. an instruction that contains an index that is a reference to a string, method, type or field.
* @param opcode the opcode of the instruction that was encountered
* @param index the start index of the instruction in the byte array that the
* <code>InstructionIterator</code> is iterating
*/
public void ProcessReferenceInstruction(Opcode opcode, int index);
/**
* The <code>InstructionIterator</code> calls this method when a packed switch instruction is encountered.
* @param index the start index of the instruction in the byte array that the
* <code>InstructionIterator</code> is iterating
* @param targetCount the number of targets that this packed switch structure contains
* @param instructionLength the length of this instruction in bytes
*/
public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength);
/**
* The <code>InstructionIterator</code> calls this method when a sparse switch instruction is encountered.
* @param index the start index of the instruction in the byte array that the
* <code>InstructionIterator</code> is iterating
* @param targetCount the number of targets that this sparse switch structure contains
* @param instructionLength the length of this instruction in bytes
*/
public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength);
/**
* The <code>InstructionIterator</code> calls this method when a fill-array-data instruction is encountered.
* @param index the start index of the instruction in the byte array that the
* <code>InstructionIterator</code> is iterating
* @param elementWidth the width of the elements contained in this fill-array-data structure
* @param elementCount the number of elements contained in this fill-array-data structure
* @param instructionLength the length of this instruction in bytes
*/
public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount,
int instructionLength);
}
public static interface ProcessInstructionDelegate {
public void ProcessInstruction(int index, Instruction instruction);
public void ProcessInstruction(int codeAddress, Instruction instruction);
}
}

View File

@ -30,5 +30,5 @@ package org.jf.dexlib.Code;
public interface MultiOffsetInstruction {
public int[] getTargets();
public void updateTarget(int targetIndex, int targetOffset);
public void updateTarget(int targetIndex, int targetAddressOffset);
}

View File

@ -29,6 +29,6 @@
package org.jf.dexlib.Code;
public interface OffsetInstruction {
public int getOffset();
public void updateOffset(int offset);
public int getTargetAddressOffset();
public void updateTargetAddressOffset(int targetAddressOffset);
}

View File

@ -33,6 +33,7 @@ import org.jf.dexlib.Code.Format.Instruction20t;
import org.jf.dexlib.Code.Format.Instruction30t;
import org.jf.dexlib.Code.Format.Instruction21c;
import org.jf.dexlib.Code.Format.Instruction31c;
import org.jf.dexlib.Debug.DebugOpcode;
import org.jf.dexlib.Util.*;
import org.jf.dexlib.Debug.DebugInstructionIterator;
@ -142,7 +143,7 @@ public class CodeItem extends Item<CodeItem> {
this.inWords = in.readShort();
this.outWords = in.readShort();
int triesCount = in.readShort();
this.debugInfo = (DebugInfoItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_DEBUG_INFO_ITEM,
this.debugInfo = (DebugInfoItem)readContext.getOptionalOffsettedItemByOffset(ItemType.TYPE_DEBUG_INFO_ITEM,
in.readInt());
if (this.debugInfo != null) {
this.debugInfo.setParent(this);
@ -154,7 +155,7 @@ public class CodeItem extends Item<CodeItem> {
byte[] encodedInstructions = in.readBytes(instructionCount * 2);
InstructionIterator.IterateInstructions(dexFile, encodedInstructions,
new InstructionIterator.ProcessInstructionDelegate() {
public void ProcessInstruction(int index, Instruction instruction) {
public void ProcessInstruction(int codeAddress, Instruction instruction) {
instructionList.add(instruction);
}
});
@ -175,9 +176,13 @@ public class CodeItem extends Item<CodeItem> {
SparseArray<EncodedCatchHandler> handlerMap = new SparseArray<EncodedCatchHandler>(handlerCount);
encodedCatchHandlers = new EncodedCatchHandler[handlerCount];
for (int i=0; i<handlerCount; i++) {
int position = in.getCursor() - encodedHandlerStart;
encodedCatchHandlers[i] = new EncodedCatchHandler(dexFile, in);
handlerMap.append(position, encodedCatchHandlers[i]);
try {
int position = in.getCursor() - encodedHandlerStart;
encodedCatchHandlers[i] = new EncodedCatchHandler(dexFile, in);
handlerMap.append(position, encodedCatchHandlers[i]);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading EncodedCatchHandler at index " + i);
}
}
int codeItemEnd = in.getCursor();
@ -185,7 +190,11 @@ public class CodeItem extends Item<CodeItem> {
in.setCursor(triesOffset);
tries = new TryItem[triesCount];
for (int i=0; i<triesCount; i++) {
tries[i] = new TryItem(in, handlerMap);
try {
tries[i] = new TryItem(in, handlerMap);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading TryItem at index " + i);
}
}
//and now back to the end of the code item
@ -195,12 +204,10 @@ public class CodeItem extends Item<CodeItem> {
/** {@inheritDoc} */
protected int placeItem(int offset) {
offset += 16 + getInstructionsLength();
offset += 16 + getInstructionsLength() * 2;
if (tries != null && tries.length > 0) {
if (offset % 4 != 0) {
offset+=2;
}
offset = AlignmentUtils.alignOffset(offset, 4);
offset += tries.length * 8;
int encodedCatchHandlerBaseOffset = offset;
@ -214,7 +221,7 @@ public class CodeItem extends Item<CodeItem> {
/** {@inheritDoc} */
protected void writeItem(final AnnotatedOutput out) {
int instructionsLength = getInstructionsLength()/2;
int instructionsLength = getInstructionsLength();
if (out.annotates()) {
out.annotate(0, parent.method.getMethodString());
@ -246,21 +253,16 @@ public class CodeItem extends Item<CodeItem> {
out.writeInt(debugInfo.getOffset());
}
int currentCodeOffset = 0;
for (Instruction instruction: instructions) {
currentCodeOffset += instruction.getSize(currentCodeOffset);
}
out.writeInt(instructionsLength);
currentCodeOffset = 0;
int currentCodeAddress = 0;
for (Instruction instruction: instructions) {
currentCodeOffset = instruction.write(out, currentCodeOffset);
currentCodeAddress = instruction.write(out, currentCodeAddress);
}
if (tries != null && tries.length > 0) {
if (out.annotates()) {
if ((currentCodeOffset % 4) != 0) {
if ((currentCodeAddress % 2) != 0) {
out.annotate("padding");
out.writeShort(0);
}
@ -285,7 +287,7 @@ public class CodeItem extends Item<CodeItem> {
out.deindent();
}
} else {
if ((currentCodeOffset % 4) != 0) {
if ((currentCodeAddress % 2) != 0) {
out.writeShort(0);
}
@ -309,7 +311,10 @@ public class CodeItem extends Item<CodeItem> {
/** {@inheritDoc} */
public String getConciseIdentity() {
return "code_item @0x" + Integer.toHexString(getOffset());
if (this.parent == null) {
return "code_item @0x" + Integer.toHexString(getOffset());
}
return "code_item @0x" + Integer.toHexString(getOffset()) + " (" + parent.method.getMethodString() + ")";
}
/** {@inheritDoc} */
@ -385,12 +390,15 @@ public class CodeItem extends Item<CodeItem> {
this.instructions = newInstructions;
}
/**
* @return The length of the instructions in this CodeItem, in 2-byte code blocks
*/
private int getInstructionsLength() {
int offset = 0;
int currentCodeAddress = 0;
for (Instruction instruction: instructions) {
offset += instruction.getSize(offset);
currentCodeAddress += instruction.getSize(currentCodeAddress);
}
return offset;
return currentCodeAddress;
}
/**
@ -403,71 +411,84 @@ public class CodeItem extends Item<CodeItem> {
* The above fixes are applied iteratively, until no more fixes have been performed
*/
public void fixInstructions(boolean fixStringConst, boolean fixGoto) {
boolean didSomething = false;
try {
boolean didSomething = false;
do
{
didSomething = false;
do
{
didSomething = false;
int currentCodeOffset = 0;
for (int i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
if (fixGoto && instruction.opcode == Opcode.GOTO) {
int offset = ((OffsetInstruction)instruction).getOffset();
try {
if (fixGoto && instruction.opcode == Opcode.GOTO) {
int codeAddress = ((OffsetInstruction)instruction).getTargetAddressOffset();
if (((byte)offset) != offset) {
//the offset doesn't fit within a byte, we need to upgrade to a goto/16 or goto/32
if (((byte) codeAddress) != codeAddress) {
//the address doesn't fit within a byte, we need to upgrade to a goto/16 or goto/32
if ((short)offset == offset) {
//the offset fits in a short, so upgrade to a goto/16 h
replaceInstructionAtOffset(currentCodeOffset, new Instruction20t(Opcode.GOTO_16, offset));
if ((short) codeAddress == codeAddress) {
//the address fits in a short, so upgrade to a goto/16
replaceInstructionAtAddress(currentCodeAddress,
new Instruction20t(Opcode.GOTO_16, codeAddress));
}
else {
//The address won't fit into a short, we have to upgrade to a goto/32
replaceInstructionAtAddress(currentCodeAddress,
new Instruction30t(Opcode.GOTO_32, codeAddress));
}
didSomething = true;
break;
}
} else if (fixGoto && instruction.opcode == Opcode.GOTO_16) {
int codeAddress = ((OffsetInstruction)instruction).getTargetAddressOffset();
if (((short) codeAddress) != codeAddress) {
//the address doesn't fit within a short, we need to upgrade to a goto/32
replaceInstructionAtAddress(currentCodeAddress,
new Instruction30t(Opcode.GOTO_32, codeAddress));
didSomething = true;
break;
}
} else if (fixStringConst && instruction.opcode == Opcode.CONST_STRING) {
Instruction21c constStringInstruction = (Instruction21c)instruction;
if (constStringInstruction.getReferencedItem().getIndex() > 0xFFFF) {
replaceInstructionAtAddress(currentCodeAddress,
new Instruction31c(Opcode.CONST_STRING_JUMBO,
(short)constStringInstruction.getRegisterA(),
constStringInstruction.getReferencedItem()));
didSomething = true;
break;
}
}
else {
//The offset won't fit into a short, we have to upgrade to a goto/32
replaceInstructionAtOffset(currentCodeOffset, new Instruction30t(Opcode.GOTO_32, offset));
}
didSomething = true;
break;
}
} else if (fixGoto && instruction.opcode == Opcode.GOTO_16) {
int offset = ((OffsetInstruction)instruction).getOffset();
if (((short)offset) != offset) {
//the offset doesn't fit within a short, we need to upgrade to a goto/32
replaceInstructionAtOffset(currentCodeOffset, new Instruction30t(Opcode.GOTO_32, offset));
didSomething = true;
break;
}
} else if (fixStringConst && instruction.opcode == Opcode.CONST_STRING) {
Instruction21c constStringInstruction = (Instruction21c)instruction;
if (constStringInstruction.getReferencedItem().getIndex() > 0xFFFF) {
replaceInstructionAtOffset(currentCodeOffset, new Instruction31c(Opcode.CONST_STRING_JUMBO,
(short)constStringInstruction.getRegisterA(),
constStringInstruction.getReferencedItem()));
didSomething = true;
break;
currentCodeAddress += instruction.getSize(currentCodeAddress);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while attempting to fix " +
instruction.opcode.name + " instruction at address " + currentCodeAddress);
}
}
currentCodeOffset += instruction.getSize(currentCodeOffset);
}
}while(didSomething);
}while(didSomething);
} catch (Exception ex) {
throw this.addExceptionContext(ex);
}
}
private void replaceInstructionAtOffset(int offset, Instruction replacementInstruction) {
private void replaceInstructionAtAddress(int codeAddress, Instruction replacementInstruction) {
Instruction originalInstruction = null;
int[] originalInstructionOffsets = new int[instructions.length+1];
SparseIntArray originalSwitchOffsetByOriginalSwitchDataOffset = new SparseIntArray();
int[] originalInstructionCodeAddresses = new int[instructions.length+1];
SparseIntArray originalSwitchAddressByOriginalSwitchDataAddress = new SparseIntArray();
int currentCodeOffset = 0;
int currentCodeAddress = 0;
int instructionIndex = 0;
int i;
for (i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
if (currentCodeOffset == offset) {
if (currentCodeAddress == codeAddress) {
originalInstruction = instruction;
instructionIndex = i;
}
@ -475,97 +496,100 @@ public class CodeItem extends Item<CodeItem> {
if (instruction.opcode == Opcode.PACKED_SWITCH || instruction.opcode == Opcode.SPARSE_SWITCH) {
OffsetInstruction offsetInstruction = (OffsetInstruction)instruction;
int switchDataOffset = currentCodeOffset + offsetInstruction.getOffset() * 2;
if (originalSwitchOffsetByOriginalSwitchDataOffset.indexOfKey(switchDataOffset) < 0) {
originalSwitchOffsetByOriginalSwitchDataOffset.put(switchDataOffset, currentCodeOffset);
int switchDataAddress = currentCodeAddress + offsetInstruction.getTargetAddressOffset();
if (originalSwitchAddressByOriginalSwitchDataAddress.indexOfKey(switchDataAddress) < 0) {
originalSwitchAddressByOriginalSwitchDataAddress.put(switchDataAddress, currentCodeAddress);
}
}
originalInstructionOffsets[i] = currentCodeOffset;
currentCodeOffset += instruction.getSize(currentCodeOffset);
originalInstructionCodeAddresses[i] = currentCodeAddress;
currentCodeAddress += instruction.getSize(currentCodeAddress);
}
//add the offset just past the end of the last instruction, to help when fixing up try blocks that end
//add the address just past the end of the last instruction, to help when fixing up try blocks that end
//at the end of the method
originalInstructionOffsets[i] = currentCodeOffset;
originalInstructionCodeAddresses[i] = currentCodeAddress;
if (originalInstruction == null) {
throw new RuntimeException("There is no instruction at offset " + offset);
throw new RuntimeException("There is no instruction at address " + codeAddress);
}
instructions[instructionIndex] = replacementInstruction;
//if we're replacing the instruction with one of the same size, we don't have to worry about fixing
//up any offsets
if (originalInstruction.getSize(offset) == replacementInstruction.getSize(offset)) {
//up any address
if (originalInstruction.getSize(codeAddress) == replacementInstruction.getSize(codeAddress)) {
return;
}
final SparseIntArray originalOffsetsByNewOffset = new SparseIntArray();
final SparseIntArray newOffsetsByOriginalOffset = new SparseIntArray();
final SparseIntArray originalAddressByNewAddress = new SparseIntArray();
final SparseIntArray newAddressByOriginalAddress = new SparseIntArray();
currentCodeOffset = 0;
currentCodeAddress = 0;
for (i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
int originalOffset = originalInstructionOffsets[i];
originalOffsetsByNewOffset.append(currentCodeOffset, originalOffset);
newOffsetsByOriginalOffset.append(originalOffset, currentCodeOffset);
int originalAddress = originalInstructionCodeAddresses[i];
originalAddressByNewAddress.append(currentCodeAddress, originalAddress);
newAddressByOriginalAddress.append(originalAddress, currentCodeAddress);
currentCodeOffset += instruction.getSize(currentCodeOffset);
currentCodeAddress += instruction.getSize(currentCodeAddress);
}
//add the offset just past the end of the last instruction, to help when fixing up try blocks that end
//add the address just past the end of the last instruction, to help when fixing up try blocks that end
//at the end of the method
originalOffsetsByNewOffset.append(currentCodeOffset, originalInstructionOffsets[i]);
newOffsetsByOriginalOffset.append(originalInstructionOffsets[i], currentCodeOffset);
originalAddressByNewAddress.append(currentCodeAddress, originalInstructionCodeAddresses[i]);
newAddressByOriginalAddress.append(originalInstructionCodeAddresses[i], currentCodeAddress);
//update any "offset" instructions, or switch data instructions
currentCodeOffset = 0;
currentCodeAddress = 0;
for (i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
if (instruction instanceof OffsetInstruction) {
OffsetInstruction offsetInstruction = (OffsetInstruction)instruction;
assert originalOffsetsByNewOffset.indexOfKey(currentCodeOffset) >= 0;
int originalOffset = originalOffsetsByNewOffset.get(currentCodeOffset);
assert originalAddressByNewAddress.indexOfKey(currentCodeAddress) >= 0;
int originalAddress = originalAddressByNewAddress.get(currentCodeAddress);
int originalInstructionTarget = originalOffset + offsetInstruction.getOffset() * 2;
int originalInstructionTarget = originalAddress + offsetInstruction.getTargetAddressOffset();
assert newOffsetsByOriginalOffset.indexOfKey(originalInstructionTarget) >= 0;
int newInstructionTarget = newOffsetsByOriginalOffset.get(originalInstructionTarget);
assert newAddressByOriginalAddress.indexOfKey(originalInstructionTarget) >= 0;
int newInstructionTarget = newAddressByOriginalAddress.get(originalInstructionTarget);
int newOffset = (newInstructionTarget - currentCodeOffset) / 2;
int newCodeAddress = (newInstructionTarget - currentCodeAddress);
if (newOffset != offsetInstruction.getOffset()) {
offsetInstruction.updateOffset(newOffset);
if (newCodeAddress != offsetInstruction.getTargetAddressOffset()) {
offsetInstruction.updateTargetAddressOffset(newCodeAddress);
}
} else if (instruction instanceof MultiOffsetInstruction) {
MultiOffsetInstruction multiOffsetInstruction = (MultiOffsetInstruction)instruction;
assert originalOffsetsByNewOffset.indexOfKey(currentCodeOffset) >= 0;
int originalDataOffset = originalOffsetsByNewOffset.get(currentCodeOffset);
assert originalAddressByNewAddress.indexOfKey(currentCodeAddress) >= 0;
int originalDataAddress = originalAddressByNewAddress.get(currentCodeAddress);
int originalSwitchOffset = originalSwitchOffsetByOriginalSwitchDataOffset.get(originalDataOffset, -1);
if (originalSwitchOffset == -1) {
throw new RuntimeException("This method contains an unreferenced switch data block, and can't be automatically fixed.");
int originalSwitchAddress =
originalSwitchAddressByOriginalSwitchDataAddress.get(originalDataAddress, -1);
if (originalSwitchAddress == -1) {
//TODO: maybe we could just remove the unreferenced switch data?
throw new RuntimeException("This method contains an unreferenced switch data block at address " +
+ currentCodeAddress + " and can't be automatically fixed.");
}
assert newOffsetsByOriginalOffset.indexOfKey(originalSwitchOffset) >= 0;
int newSwitchOffset = newOffsetsByOriginalOffset.get(originalSwitchOffset);
assert newAddressByOriginalAddress.indexOfKey(originalSwitchAddress) >= 0;
int newSwitchAddress = newAddressByOriginalAddress.get(originalSwitchAddress);
int[] targets = multiOffsetInstruction.getTargets();
for (int t=0; t<targets.length; t++) {
int originalTargetOffset = originalSwitchOffset + targets[t]*2;
assert newOffsetsByOriginalOffset.indexOfKey(originalTargetOffset) >= 0;
int newTargetOffset = newOffsetsByOriginalOffset.get(originalTargetOffset);
int newOffset = (newTargetOffset - newSwitchOffset)/2;
if (newOffset != targets[t]) {
multiOffsetInstruction.updateTarget(t, newOffset);
int originalTargetCodeAddress = originalSwitchAddress + targets[t];
assert newAddressByOriginalAddress.indexOfKey(originalTargetCodeAddress) >= 0;
int newTargetCodeAddress = newAddressByOriginalAddress.get(originalTargetCodeAddress);
int newCodeAddress = newTargetCodeAddress - newSwitchAddress;
if (newCodeAddress != targets[t]) {
multiOffsetInstruction.updateTarget(t, newCodeAddress);
}
}
}
currentCodeOffset += instruction.getSize(currentCodeOffset);
currentCodeAddress += instruction.getSize(currentCodeAddress);
}
if (debugInfo != null) {
@ -574,7 +598,7 @@ public class CodeItem extends Item<CodeItem> {
ByteArrayInput debugInput = new ByteArrayInput(encodedDebugInfo);
DebugInstructionFixer debugInstructionFixer = new DebugInstructionFixer(encodedDebugInfo,
newOffsetsByOriginalOffset, originalOffsetsByNewOffset);
newAddressByOriginalAddress);
DebugInstructionIterator.IterateInstructions(debugInput, debugInstructionFixer);
if (debugInstructionFixer.result != null) {
@ -585,122 +609,124 @@ public class CodeItem extends Item<CodeItem> {
if (encodedCatchHandlers != null) {
for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) {
if (encodedCatchHandler.catchAllHandlerAddress != -1) {
assert newOffsetsByOriginalOffset.indexOfKey(encodedCatchHandler.catchAllHandlerAddress*2) >= 0;
assert newAddressByOriginalAddress.indexOfKey(encodedCatchHandler.catchAllHandlerAddress) >= 0;
encodedCatchHandler.catchAllHandlerAddress =
newOffsetsByOriginalOffset.get(encodedCatchHandler.catchAllHandlerAddress*2)/2;
newAddressByOriginalAddress.get(encodedCatchHandler.catchAllHandlerAddress);
}
for (EncodedTypeAddrPair handler: encodedCatchHandler.handlers) {
assert newOffsetsByOriginalOffset.indexOfKey(handler.handlerAddress*2) >= 0;
handler.handlerAddress = newOffsetsByOriginalOffset.get(handler.handlerAddress*2)/2;
assert newAddressByOriginalAddress.indexOfKey(handler.handlerAddress) >= 0;
handler.handlerAddress = newAddressByOriginalAddress.get(handler.handlerAddress);
}
}
}
if (this.tries != null) {
for (TryItem tryItem: tries) {
int startAddress = tryItem.startAddress;
int endAddress = tryItem.startAddress + tryItem.instructionCount;
int startAddress = tryItem.startCodeAddress;
int endAddress = tryItem.startCodeAddress + tryItem.tryLength;
assert newOffsetsByOriginalOffset.indexOfKey(startAddress * 2) >= 0;
tryItem.startAddress = newOffsetsByOriginalOffset.get(startAddress * 2)/2;
assert newAddressByOriginalAddress.indexOfKey(startAddress) >= 0;
tryItem.startCodeAddress = newAddressByOriginalAddress.get(startAddress);
assert newOffsetsByOriginalOffset.indexOfKey(endAddress * 2) >= 0;
tryItem.instructionCount = newOffsetsByOriginalOffset.get(endAddress * 2)/2 - tryItem.startAddress;
assert newAddressByOriginalAddress.indexOfKey(endAddress) >= 0;
tryItem.tryLength = newAddressByOriginalAddress.get(endAddress) - tryItem.startCodeAddress;
}
}
}
private class DebugInstructionFixer extends DebugInstructionIterator.ProcessRawDebugInstructionDelegate {
private int address = 0;
private SparseIntArray newOffsetsByOriginalOffset;
private SparseIntArray originalOffsetsByNewOffset;
private int currentCodeAddress = 0;
private SparseIntArray newAddressByOriginalAddress;
private final byte[] originalEncodedDebugInfo;
public byte[] result = null;
public DebugInstructionFixer(byte[] originalEncodedDebugInfo, SparseIntArray newOffsetsByOriginalOffset,
SparseIntArray originalOffsetsByNewOffset) {
this.newOffsetsByOriginalOffset = newOffsetsByOriginalOffset;
this.originalOffsetsByNewOffset = originalOffsetsByNewOffset;
public DebugInstructionFixer(byte[] originalEncodedDebugInfo, SparseIntArray newAddressByOriginalAddress) {
this.newAddressByOriginalAddress = newAddressByOriginalAddress;
this.originalEncodedDebugInfo = originalEncodedDebugInfo;
}
@Override
public void ProcessAdvancePC(int startOffset, int length, int addressDelta) {
address += addressDelta;
public void ProcessAdvancePC(int startDebugOffset, int debugInstructionLength, int codeAddressDelta) {
currentCodeAddress += codeAddressDelta;
if (result != null) {
return;
}
int newOffset = newOffsetsByOriginalOffset.get(address*2, -1);
int newCodeAddress = newAddressByOriginalAddress.get(currentCodeAddress, -1);
//The address might not point to an actual instruction in some cases, for example, if an AdvancePC
//instruction was inserted just before a "special" instruction, to fix up the offsets for a previous
//instruction was inserted just before a "special" instruction, to fix up the addresses for a previous
//instruction replacement.
//In this case, it should be safe to skip, because there will be another AdvancePC/SpecialOpcode that will
//bump up the address to point to a valid instruction before anything (line/local/etc.) is emitted
if (newOffset == -1) {
if (newCodeAddress == -1) {
return;
}
assert newOffset != -1;
newOffset = newOffset / 2;
if (newCodeAddress != currentCodeAddress) {
int newCodeAddressDelta = newCodeAddress - (currentCodeAddress - codeAddressDelta);
assert newCodeAddressDelta > 0;
int codeAddressDeltaLeb128Size = Leb128Utils.unsignedLeb128Size(newCodeAddressDelta);
if (newOffset != address) {
int newAddressDelta = newOffset - (address - addressDelta);
assert newAddressDelta > 0;
int addressDiffSize = Leb128Utils.unsignedLeb128Size(newAddressDelta);
//if the length of the new code address delta is the same, we can use the existing buffer
if (codeAddressDeltaLeb128Size + 1 == debugInstructionLength) {
result = originalEncodedDebugInfo;
Leb128Utils.writeUnsignedLeb128(newCodeAddressDelta, result, startDebugOffset+1);
} else {
//The length of the new code address delta is different, so create a new buffer with enough
//additional space to accomodate the new code address delta value.
result = new byte[originalEncodedDebugInfo.length + codeAddressDeltaLeb128Size -
(debugInstructionLength - 1)];
result = new byte[originalEncodedDebugInfo.length + addressDiffSize - (length - 1)];
System.arraycopy(originalEncodedDebugInfo, 0, result, 0, startDebugOffset);
System.arraycopy(originalEncodedDebugInfo, 0, result, 0, startOffset);
result[startDebugOffset] = DebugOpcode.DBG_ADVANCE_PC.value;
Leb128Utils.writeUnsignedLeb128(newCodeAddressDelta, result, startDebugOffset+1);
result[startOffset] = 0x01; //DBG_ADVANCE_PC debug opcode
Leb128Utils.writeUnsignedLeb128(newAddressDelta, result, startOffset+1);
System.arraycopy(originalEncodedDebugInfo, startOffset+length, result,
startOffset + addressDiffSize + 1,
originalEncodedDebugInfo.length - (startOffset + addressDiffSize + 1));
System.arraycopy(originalEncodedDebugInfo, startDebugOffset + debugInstructionLength, result,
startDebugOffset + codeAddressDeltaLeb128Size + 1,
originalEncodedDebugInfo.length - (startDebugOffset + codeAddressDeltaLeb128Size + 1));
}
}
}
@Override
public void ProcessSpecialOpcode(int startOffset, int debugOpcode, int lineDelta,
int addressDelta) {
address += addressDelta;
public void ProcessSpecialOpcode(int startDebugOffset, int debugOpcode, int lineDelta,
int codeAddressDelta) {
currentCodeAddress += codeAddressDelta;
if (result != null) {
return;
}
int newOffset = newOffsetsByOriginalOffset.get(address*2, -1);
assert newOffset != -1;
newOffset = newOffset / 2;
int newCodeAddress = newAddressByOriginalAddress.get(currentCodeAddress, -1);
assert newCodeAddress != -1;
if (newOffset != address) {
int newAddressDelta = newOffset - (address - addressDelta);
assert newAddressDelta > 0;
if (newCodeAddress != currentCodeAddress) {
int newCodeAddressDelta = newCodeAddress - (currentCodeAddress - codeAddressDelta);
assert newCodeAddressDelta > 0;
//if the new address delta won't fit in the special opcode, we need to insert
//if the new code address delta won't fit in the special opcode, we need to insert
//an additional DBG_ADVANCE_PC opcode
if (lineDelta < 2 && newAddressDelta > 16 || lineDelta > 1 && newAddressDelta > 15) {
int additionalAddressDelta = newOffset - address;
int additionalAddressDeltaSize = Leb128Utils.signedLeb128Size(additionalAddressDelta);
if (lineDelta < 2 && newCodeAddressDelta > 16 || lineDelta > 1 && newCodeAddressDelta > 15) {
int additionalCodeAddressDelta = newCodeAddress - currentCodeAddress;
int additionalCodeAddressDeltaLeb128Size = Leb128Utils.signedLeb128Size(additionalCodeAddressDelta);
result = new byte[originalEncodedDebugInfo.length + additionalAddressDeltaSize + 1];
//create a new buffer with enough additional space for the new opcode
result = new byte[originalEncodedDebugInfo.length + additionalCodeAddressDeltaLeb128Size + 1];
System.arraycopy(originalEncodedDebugInfo, 0, result, 0, startOffset);
result[startOffset] = 0x01; //DBG_ADVANCE_PC
Leb128Utils.writeUnsignedLeb128(additionalAddressDelta, result, startOffset+1);
System.arraycopy(originalEncodedDebugInfo, startOffset, result,
startOffset+additionalAddressDeltaSize+1,
result.length - (startOffset+additionalAddressDeltaSize+1));
System.arraycopy(originalEncodedDebugInfo, 0, result, 0, startDebugOffset);
result[startDebugOffset] = 0x01; //DBG_ADVANCE_PC
Leb128Utils.writeUnsignedLeb128(additionalCodeAddressDelta, result, startDebugOffset+1);
System.arraycopy(originalEncodedDebugInfo, startDebugOffset, result,
startDebugOffset+additionalCodeAddressDeltaLeb128Size+1,
result.length - (startDebugOffset+additionalCodeAddressDeltaLeb128Size+1));
} else {
result = new byte[originalEncodedDebugInfo.length];
System.arraycopy(originalEncodedDebugInfo, 0, result, 0, result.length);
result[startOffset] = DebugInfoBuilder.calculateSpecialOpcode(lineDelta,
newAddressDelta);
result = originalEncodedDebugInfo;
result[startDebugOffset] = DebugInfoBuilder.calculateSpecialOpcode(lineDelta,
newCodeAddressDelta);
}
}
}
@ -710,12 +736,12 @@ public class CodeItem extends Item<CodeItem> {
/**
* The address (in 2-byte words) within the code where the try block starts
*/
private int startAddress;
private int startCodeAddress;
/**
* The number of 2-byte words that the try block covers
*/
private int instructionCount;
private int tryLength;
/**
* The associated exception handler
@ -724,13 +750,13 @@ public class CodeItem extends Item<CodeItem> {
/**
* Construct a new <code>TryItem</code> with the given values
* @param startAddress the address (in 2-byte words) within the code where the try block starts
* @param instructionCount the number of 2-byte words that the try block covers
* @param startCodeAddress the code address within the code where the try block starts
* @param tryLength the number of code blocks that the try block covers
* @param encodedCatchHandler the associated exception handler
*/
public TryItem(int startAddress, int instructionCount, EncodedCatchHandler encodedCatchHandler) {
this.startAddress = startAddress;
this.instructionCount = instructionCount;
public TryItem(int startCodeAddress, int tryLength, EncodedCatchHandler encodedCatchHandler) {
this.startCodeAddress = startCodeAddress;
this.tryLength = tryLength;
this.encodedCatchHandler = encodedCatchHandler;
}
@ -742,8 +768,8 @@ public class CodeItem extends Item<CodeItem> {
* structure.
*/
private TryItem(Input in, SparseArray<EncodedCatchHandler> encodedCatchHandlers) {
startAddress = in.readInt();
instructionCount = in.readShort();
startCodeAddress = in.readInt();
tryLength = in.readShort();
encodedCatchHandler = encodedCatchHandlers.get(in.readShort());
if (encodedCatchHandler == null) {
@ -757,29 +783,29 @@ public class CodeItem extends Item<CodeItem> {
*/
private void writeTo(AnnotatedOutput out) {
if (out.annotates()) {
out.annotate(4, "start_addr: 0x" + Integer.toHexString(startAddress));
out.annotate(2, "insn_count: 0x" + Integer.toHexString(instructionCount) + " (" + instructionCount +
out.annotate(4, "start_addr: 0x" + Integer.toHexString(startCodeAddress));
out.annotate(2, "try_length: 0x" + Integer.toHexString(tryLength) + " (" + tryLength +
")");
out.annotate(2, "handler_off: 0x" + Integer.toHexString(encodedCatchHandler.getOffsetInList()));
}
out.writeInt(startAddress);
out.writeShort(instructionCount);
out.writeInt(startCodeAddress);
out.writeShort(tryLength);
out.writeShort(encodedCatchHandler.getOffsetInList());
}
/**
* @return The address (in 2-byte words) within the code where the try block starts
*/
public int getStartAddress() {
return startAddress;
public int getStartCodeAddress() {
return startCodeAddress;
}
/**
* @return The number of 2-byte words that the try block covers
* @return The number of code blocks that the try block covers
*/
public int getInstructionCount() {
return instructionCount;
public int getTryLength() {
return tryLength;
}
}
@ -825,7 +851,11 @@ public class CodeItem extends Item<CodeItem> {
}
for (int i=0; i<handlers.length; i++) {
handlers[i] = new EncodedTypeAddrPair(dexFile, in);
try {
handlers[i] = new EncodedTypeAddrPair(dexFile, in);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading EncodedTypeAddrPair at index " + i);
}
}
if (handlerCount <= 0) {

View File

@ -44,29 +44,31 @@ public class DebugInstructionIterator {
* for each instruction that is encountered
*/
public static void IterateInstructions(Input in, ProcessRawDebugInstructionDelegate processDebugInstruction) {
int startOffset;
int startDebugOffset;
while(true)
{
startOffset = in.getCursor();
startDebugOffset = in.getCursor();
byte debugOpcode = in.readByte();
switch (debugOpcode) {
case 0x00:
{
processDebugInstruction.ProcessEndSequence(startOffset);
processDebugInstruction.ProcessEndSequence(startDebugOffset);
return;
}
case 0x01:
{
int addressDiff = in.readUnsignedLeb128();
processDebugInstruction.ProcessAdvancePC(startOffset, in.getCursor() - startOffset, addressDiff);
int codeAddressDiff = in.readUnsignedLeb128();
processDebugInstruction.ProcessAdvancePC(startDebugOffset, in.getCursor() - startDebugOffset,
codeAddressDiff);
break;
}
case 0x02:
{
int lineDiff = in.readSignedLeb128();
processDebugInstruction.ProcessAdvanceLine(startOffset, in.getCursor() - startOffset, lineDiff);
processDebugInstruction.ProcessAdvanceLine(startDebugOffset, in.getCursor() - startDebugOffset,
lineDiff);
break;
}
case 0x03:
@ -79,8 +81,8 @@ public class DebugInstructionIterator {
}
int nameIndex = in.readUnsignedLeb128() - 1;
int typeIndex = in.readUnsignedLeb128() - 1;
processDebugInstruction.ProcessStartLocal(startOffset, in.getCursor() - startOffset, registerNum,
nameIndex, typeIndex, isSignedRegister);
processDebugInstruction.ProcessStartLocal(startDebugOffset, in.getCursor() - startDebugOffset,
registerNum, nameIndex, typeIndex, isSignedRegister);
break;
}
case 0x04:
@ -94,8 +96,9 @@ public class DebugInstructionIterator {
int nameIndex = in.readUnsignedLeb128() - 1;
int typeIndex = in.readUnsignedLeb128() - 1;
int signatureIndex = in.readUnsignedLeb128() - 1;
processDebugInstruction.ProcessStartLocalExtended(startOffset, in.getCursor() - startOffset,
registerNum, nameIndex, typeIndex, signatureIndex, isSignedRegister);
processDebugInstruction.ProcessStartLocalExtended(startDebugOffset,
in.getCursor() - startDebugOffset, registerNum, nameIndex, typeIndex, signatureIndex,
isSignedRegister);
break;
}
case 0x05:
@ -106,8 +109,8 @@ public class DebugInstructionIterator {
isSignedRegister = true;
registerNum = ~registerNum;
}
processDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum,
isSignedRegister);
processDebugInstruction.ProcessEndLocal(startDebugOffset, in.getCursor() - startDebugOffset,
registerNum, isSignedRegister);
break;
}
case 0x06:
@ -118,30 +121,31 @@ public class DebugInstructionIterator {
isSignedRegister = true;
registerNum = ~registerNum;
}
processDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset, registerNum,
isSignedRegister);
processDebugInstruction.ProcessRestartLocal(startDebugOffset, in.getCursor() - startDebugOffset,
registerNum, isSignedRegister);
break;
}
case 0x07:
{
processDebugInstruction.ProcessSetPrologueEnd(startOffset);
processDebugInstruction.ProcessSetPrologueEnd(startDebugOffset);
break;
}
case 0x08:
{
processDebugInstruction.ProcessSetEpilogueBegin(startOffset);
processDebugInstruction.ProcessSetEpilogueBegin(startDebugOffset);
break;
}
case 0x09:
{
int nameIndex = in.readUnsignedLeb128();
processDebugInstruction.ProcessSetFile(startOffset, in.getCursor() - startOffset, nameIndex);
processDebugInstruction.ProcessSetFile(startDebugOffset, in.getCursor() - startDebugOffset,
nameIndex);
break;
}
default:
{
int base = ((debugOpcode & 0xFF) - 0x0A);
processDebugInstruction.ProcessSpecialOpcode(startOffset, debugOpcode, (base % 15) - 4, base / 15);
processDebugInstruction.ProcessSpecialOpcode(startDebugOffset, debugOpcode, (base % 15) - 4, base / 15);
}
}
}
@ -157,8 +161,8 @@ public class DebugInstructionIterator {
*/
public static void DecodeInstructions(DebugInfoItem debugInfoItem, int registerCount,
ProcessDecodedDebugInstructionDelegate processDecodedDebugInstruction) {
int startOffset;
int address = 0;
int startDebugOffset;
int currentCodeAddress = 0;
int line = debugInfoItem.getLineStart();
Input in = new ByteArrayInput(debugInfoItem.getEncodedDebugInfo());
DexFile dexFile = debugInfoItem.getDexFile();
@ -167,96 +171,97 @@ public class DebugInstructionIterator {
while(true)
{
startOffset = in.getCursor();
startDebugOffset = in.getCursor();
byte debugOpcode = in.readByte();
switch (debugOpcode) {
case 0x00:
switch (DebugOpcode.getDebugOpcodeByValue(debugOpcode)) {
case DBG_END_SEQUENCE:
{
return;
}
case 0x01:
case DBG_ADVANCE_PC:
{
int addressDiff = in.readUnsignedLeb128();
address += addressDiff;
int codeAddressDiff = in.readUnsignedLeb128();
currentCodeAddress += codeAddressDiff;
break;
}
case 0x02:
case DBG_ADVANCE_LINE:
{
int lineDiff = in.readSignedLeb128();
line += lineDiff;
break;
}
case 0x03:
case DBG_START_LOCAL:
{
int registerNum = in.readUnsignedLeb128();
StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
TypeIdItem type = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
StringIdItem name = dexFile.StringIdsSection.getOptionalItemByIndex(in.readUnsignedLeb128() - 1);
TypeIdItem type = dexFile.TypeIdsSection.getOptionalItemByIndex(in.readUnsignedLeb128() - 1);
locals[registerNum] = new Local(registerNum, name, type, null);
processDecodedDebugInstruction.ProcessStartLocal(address, in.getCursor() - startOffset, registerNum,
name, type);
processDecodedDebugInstruction.ProcessStartLocal(currentCodeAddress,
in.getCursor() - startDebugOffset, registerNum, name, type);
break;
}
case 0x04:
case DBG_START_LOCAL_EXTENDED:
{
int registerNum = in.readUnsignedLeb128();
StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
TypeIdItem type = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
StringIdItem signature = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
StringIdItem name = dexFile.StringIdsSection.getOptionalItemByIndex(in.readUnsignedLeb128() - 1);
TypeIdItem type = dexFile.TypeIdsSection.getOptionalItemByIndex(in.readUnsignedLeb128() - 1);
StringIdItem signature =
dexFile.StringIdsSection.getOptionalItemByIndex(in.readUnsignedLeb128() - 1);
locals[registerNum] = new Local(registerNum, name, type, signature);
processDecodedDebugInstruction.ProcessStartLocalExtended(address, in.getCursor() - startOffset,
registerNum, name, type, signature);
processDecodedDebugInstruction.ProcessStartLocalExtended(currentCodeAddress,
in.getCursor() - startDebugOffset, registerNum, name, type, signature);
break;
}
case 0x05:
case DBG_END_LOCAL:
{
int registerNum = in.readUnsignedLeb128();
Local local = locals[registerNum];
if (local == null) {
processDecodedDebugInstruction.ProcessEndLocal(address, in.getCursor() - startOffset, registerNum,
processDecodedDebugInstruction.ProcessEndLocal(currentCodeAddress, in.getCursor() - startDebugOffset, registerNum,
null, null, null);
} else {
processDecodedDebugInstruction.ProcessEndLocal(address, in.getCursor() - startOffset, registerNum,
processDecodedDebugInstruction.ProcessEndLocal(currentCodeAddress, in.getCursor() - startDebugOffset, registerNum,
local.name, local.type, local.signature);
}
break;
}
case 0x06:
case DBG_RESTART_LOCAL:
{
int registerNum = in.readUnsignedLeb128();
Local local = locals[registerNum];
if (local == null) {
processDecodedDebugInstruction.ProcessRestartLocal(address, in.getCursor() - startOffset,
processDecodedDebugInstruction.ProcessRestartLocal(currentCodeAddress, in.getCursor() - startDebugOffset,
registerNum, null, null, null);
} else {
processDecodedDebugInstruction.ProcessRestartLocal(address, in.getCursor() - startOffset,
processDecodedDebugInstruction.ProcessRestartLocal(currentCodeAddress, in.getCursor() - startDebugOffset,
registerNum, local.name, local.type, local.signature);
}
break;
}
case 0x07:
case DBG_SET_PROLOGUE_END:
{
processDecodedDebugInstruction.ProcessSetPrologueEnd(address);
processDecodedDebugInstruction.ProcessSetPrologueEnd(currentCodeAddress);
break;
}
case 0x08:
case DBG_SET_EPILOGUE_BEGIN:
{
processDecodedDebugInstruction.ProcessSetEpilogueBegin(address);
processDecodedDebugInstruction.ProcessSetEpilogueBegin(currentCodeAddress);
break;
}
case 0x09:
case DBG_SET_FILE:
{
StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
processDecodedDebugInstruction.ProcessSetFile(address, in.getCursor() - startOffset, name);
StringIdItem name = dexFile.StringIdsSection.getOptionalItemByIndex(in.readUnsignedLeb128() - 1);
processDecodedDebugInstruction.ProcessSetFile(currentCodeAddress, in.getCursor() - startDebugOffset, name);
break;
}
default:
case DBG_SPECIAL_OPCODE:
{
int base = ((debugOpcode & 0xFF) - 0x0A);
address += base / 15;
currentCodeAddress += base / 15;
line += (base % 15) - 4;
processDecodedDebugInstruction.ProcessLineEmit(address, line);
processDecodedDebugInstruction.ProcessLineEmit(currentCodeAddress, line);
}
}
}
@ -265,50 +270,50 @@ public class DebugInstructionIterator {
public static class ProcessRawDebugInstructionDelegate
{
//TODO: add javadocs
public void ProcessEndSequence(int startOffset) {
ProcessStaticOpcode(DebugOpcode.DBG_END_SEQUENCE, startOffset, 1);
public void ProcessEndSequence(int startDebugOffset) {
ProcessStaticOpcode(DebugOpcode.DBG_END_SEQUENCE, startDebugOffset, 1);
}
public void ProcessAdvancePC(int startOffset, int length, int addressDiff) {
ProcessStaticOpcode(DebugOpcode.DBG_ADVANCE_PC, startOffset, length);
public void ProcessAdvancePC(int startDebugOffset, int length, int codeAddressDiff) {
ProcessStaticOpcode(DebugOpcode.DBG_ADVANCE_PC, startDebugOffset, length);
}
public void ProcessAdvanceLine(int startOffset, int length, int lineDiff) {
ProcessStaticOpcode(DebugOpcode.DBG_ADVANCE_LINE, startOffset, length);
public void ProcessAdvanceLine(int startDebugOffset, int length, int lineDiff) {
ProcessStaticOpcode(DebugOpcode.DBG_ADVANCE_LINE, startDebugOffset, length);
}
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, int typeIndex,
public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex, int typeIndex,
boolean registerIsSigned) {
}
public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex,
public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNum, int nameIndex,
int typeIndex,int signatureIndex, boolean registerIsSigned) {
}
public void ProcessEndLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) {
ProcessStaticOpcode(DebugOpcode.DBG_END_LOCAL, startOffset, length);
public void ProcessEndLocal(int startDebugOffset, int length, int registerNum, boolean registerIsSigned) {
ProcessStaticOpcode(DebugOpcode.DBG_END_LOCAL, startDebugOffset, length);
}
public void ProcessRestartLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) {
ProcessStaticOpcode(DebugOpcode.DBG_RESTART_LOCAL, startOffset, length);
public void ProcessRestartLocal(int startDebugOffset, int length, int registerNum, boolean registerIsSigned) {
ProcessStaticOpcode(DebugOpcode.DBG_RESTART_LOCAL, startDebugOffset, length);
}
public void ProcessSetPrologueEnd(int startOffset) {
ProcessStaticOpcode(DebugOpcode.DBG_SET_PROLOGUE_END, startOffset, 1);
public void ProcessSetPrologueEnd(int startDebugOffset) {
ProcessStaticOpcode(DebugOpcode.DBG_SET_PROLOGUE_END, startDebugOffset, 1);
}
public void ProcessSetEpilogueBegin(int startOffset) {
ProcessStaticOpcode(DebugOpcode.DBG_SET_EPILOGUE_BEGIN, startOffset, 1);
public void ProcessSetEpilogueBegin(int startDebugOffset) {
ProcessStaticOpcode(DebugOpcode.DBG_SET_EPILOGUE_BEGIN, startDebugOffset, 1);
}
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
}
public void ProcessSpecialOpcode(int startOffset, int debugOpcode, int lineDiff, int addressDiff) {
ProcessStaticOpcode(DebugOpcode.DBG_SPECIAL_OPCODE, startOffset, 1);
public void ProcessSpecialOpcode(int startDebugOffset, int debugOpcode, int lineDiff, int codeAddressDiff) {
ProcessStaticOpcode(DebugOpcode.DBG_SPECIAL_OPCODE, startDebugOffset, 1);
}
public void ProcessStaticOpcode(DebugOpcode debugOpcode, int startOffset, int length) {
public void ProcessStaticOpcode(DebugOpcode debugOpcode, int startDebugOffset, int length) {
}
}

View File

@ -52,7 +52,7 @@ public enum DebugOpcode {
}
public static DebugOpcode getDebugOpcodeByValue(byte debugOpcodeValue) {
debugOpcodeValue = (byte)Math.min(debugOpcodeValue, 0x0A);
debugOpcodeValue = (byte)Math.min(debugOpcodeValue & 0xFF, 0x0A);
return opcodesByValue[debugOpcodeValue];
}

View File

@ -103,12 +103,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
parameterNames = new StringIdItem[in.readUnsignedLeb128()];
IndexedSection<StringIdItem> stringIdSection = dexFile.StringIdsSection;
for (int i=0; i<parameterNames.length; i++) {
int index = in.readUnsignedLeb128() - 1;
if (index < 0) {
parameterNames[i] = null;
} else {
parameterNames[i] = stringIdSection.getItemByIndex(index);
}
parameterNames[i] = stringIdSection.getOptionalItemByIndex(in.readUnsignedLeb128() - 1);
}
int start = in.getCursor();
@ -116,7 +111,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
DebugInstructionIterator.IterateInstructions(in,
new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() {
@Override
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex,
public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex,
int typeIndex, boolean registerIsSigned) {
if (nameIndex != -1) {
referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
@ -127,8 +122,8 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessStartLocalExtended(int startOffset, int length, int registerNume, int nameIndex,
int typeIndex, int signatureIndex,
public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNume,
int nameIndex, int typeIndex, int signatureIndex,
boolean registerIsSigned) {
if (nameIndex != -1) {
referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
@ -142,7 +137,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
if (nameIndex != -1) {
referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
}
@ -187,12 +182,12 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
private int referencedItemsPosition = 0;
@Override
public void ProcessStaticOpcode(DebugOpcode opcode, int startOffset, int length) {
public void ProcessStaticOpcode(DebugOpcode opcode, int startDebugOffset, int length) {
this.length+=length;
}
@Override
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex,
public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex,
int typeIndex, boolean registerIsSigned) {
this.length++;
if (dexFile.getPreserveSignedRegisters() && registerIsSigned) {
@ -216,7 +211,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex,
public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNum, int nameIndex,
int typeIndex, int signatureIndex,
boolean registerIsSigned) {
this.length++;
@ -246,7 +241,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
this.length++;
if (nameIndex != -1) {
this.length+=
@ -261,7 +256,6 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
/** {@inheritDoc} */
protected void writeItem(final AnnotatedOutput out) {
if (out.annotates()) {
writeItemWithAnnotations(out);
} else {
@ -275,7 +269,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
* @param encodedDebugInfo the new encoded debug info
*/
protected void setEncodedDebugInfo(byte[] encodedDebugInfo) {
//TODO: I would rather replace this method with some way of saying "The (code) instruction at offset changed from A bytes to B bytes. Fixup the debug info accordingly"
//TODO: I would rather replace this method with some way of saying "The (code) instruction at address changed from A bytes to B bytes. Fixup the debug info accordingly"
this.encodedDebugInfo = encodedDebugInfo;
}
@ -302,12 +296,12 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
private int referencedItemsPosition = 0;
@Override
public void ProcessStaticOpcode(DebugOpcode opcode, int startOffset, int length) {
out.write(encodedDebugInfo, startOffset, length);
public void ProcessStaticOpcode(DebugOpcode opcode, int startDebugOffset, int length) {
out.write(encodedDebugInfo, startDebugOffset, length);
}
@Override
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex,
public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex,
int typeIndex, boolean registerIsSigned) {
out.writeByte(DebugOpcode.DBG_START_LOCAL.value);
if (dexFile.getPreserveSignedRegisters() && registerIsSigned) {
@ -328,7 +322,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex,
public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNum, int nameIndex,
int typeIndex, int signatureIndex,
boolean registerIsSigned) {
out.writeByte(DebugOpcode.DBG_START_LOCAL_EXTENDED.value);
@ -355,7 +349,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
out.writeByte(DebugOpcode.DBG_SET_FILE.value);
if (nameIndex != -1) {
out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
@ -395,13 +389,13 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
private int referencedItemsPosition = 0;
@Override
public void ProcessEndSequence(int startOffset) {
public void ProcessEndSequence(int startDebugOffset) {
out.annotate("DBG_END_SEQUENCE");
out.writeByte(DebugOpcode.DBG_END_SEQUENCE.value);
}
@Override
public void ProcessAdvancePC(int startOffset, int length, int addressDiff) {
public void ProcessAdvancePC(int startDebugOffset, int length, int addressDiff) {
out.annotate("DBG_ADVANCE_PC");
out.writeByte(DebugOpcode.DBG_ADVANCE_PC.value);
out.indent();
@ -411,7 +405,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessAdvanceLine(int startOffset, int length, int lineDiff) {
public void ProcessAdvanceLine(int startDebugOffset, int length, int lineDiff) {
out.annotate("DBG_ADVANCE_LINE");
out.writeByte(DebugOpcode.DBG_ADVANCE_LINE.value);
out.indent();
@ -421,7 +415,7 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex,
public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex,
int typeIndex, boolean registerIsSigned) {
out.annotate("DBG_START_LOCAL");
out.writeByte(DebugOpcode.DBG_START_LOCAL.value);
@ -454,8 +448,8 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex,
int typeIndex, int signatureIndex,
public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNum,
int nameIndex, int typeIndex, int signatureIndex,
boolean registerIsSigned) {
out.annotate("DBG_START_LOCAL_EXTENDED");
out.writeByte(DebugOpcode.DBG_START_LOCAL_EXTENDED.value);
@ -497,7 +491,8 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessEndLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) {
public void ProcessEndLocal(int startDebugOffset, int length, int registerNum,
boolean registerIsSigned) {
out.annotate("DBG_END_LOCAL");
out.writeByte(DebugOpcode.DBG_END_LOCAL.value);
out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")");
@ -509,7 +504,8 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessRestartLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) {
public void ProcessRestartLocal(int startDebugOffset, int length, int registerNum,
boolean registerIsSigned) {
out.annotate("DBG_RESTART_LOCAL");
out.writeByte(DebugOpcode.DBG_RESTART_LOCAL.value);
out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")");
@ -521,19 +517,19 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessSetPrologueEnd(int startOffset) {
public void ProcessSetPrologueEnd(int startDebugOffset) {
out.annotate("DBG_SET_PROLOGUE_END");
out.writeByte(DebugOpcode.DBG_SET_PROLOGUE_END.value);
}
@Override
public void ProcessSetEpilogueBegin(int startOffset) {
public void ProcessSetEpilogueBegin(int startDebugOffset) {
out.annotate("DBG_SET_EPILOGUE_BEGIN");
out.writeByte(DebugOpcode.DBG_SET_EPILOGUE_BEGIN.value);
}
@Override
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
out.annotate("DBG_SET_FILE");
out.writeByte(DebugOpcode.DBG_SET_FILE.value);
if (nameIndex != -1) {
@ -548,7 +544,8 @@ public class DebugInfoItem extends Item<DebugInfoItem> {
}
@Override
public void ProcessSpecialOpcode(int startOffset, int debugOpcode, int lineDiff, int addressDiff) {
public void ProcessSpecialOpcode(int startDebugOffset, int debugOpcode, int lineDiff,
int addressDiff) {
out.annotate("DBG_SPECIAL_OPCODE: line_diff=0x" + Integer.toHexString(lineDiff) + "(" +
lineDiff +"),addressDiff=0x" + Integer.toHexString(addressDiff) + "(" + addressDiff +
")");

View File

@ -113,12 +113,7 @@ public class FieldIdItem extends Item<FieldIdItem> {
/** {@inheritDoc} */
public String getConciseIdentity() {
String parentClass = classType.getTypeDescriptor();
//strip off the leading L and trailing ;
parentClass = parentClass.substring(1, parentClass.length() - 1);
return parentClass + "/" + fieldName.getStringValue() +
":" + fieldType.getTypeDescriptor();
return getFieldString();
}
/** {@inheritDoc} */

View File

@ -28,6 +28,7 @@
package org.jf.dexlib;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.dexlib.Util.Input;
public class IndexedSection<T extends Item> extends Section<T> {
@ -51,17 +52,30 @@ public class IndexedSection<T extends Item> extends Section<T> {
}
/**
* Gets the item at the specified index in this section
* Gets the item at the specified index in this section, or null if the index is -1
* @param index the index of the item to get
* @return the item at the specified index in this section
* @throws IndexOutOfBoundsException if index is outside the bounds of this section
* @return the item at the specified index in this section, or null if the index is -1
*/
public T getItemByIndex(int index) {
public T getOptionalItemByIndex(int index) {
if (index == -1) {
return null;
}
//if index is out of bounds, just let it throw an exception
return items.get(index);
return getItemByIndex(index);
}
/**
* Gets the item at the specified index in this section
* @param index the index of the item to get
* @return the item at the specified index in this section
*/
public T getItemByIndex(int index) {
try {
//if index is out of bounds, just let it throw an exception
return items.get(index);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error occured while retrieving the " + this.ItemType.TypeName +
" item at index " + index);
}
}
}

View File

@ -28,9 +28,10 @@
package org.jf.dexlib;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.Input;
import org.jf.dexlib.Util.AlignmentUtils;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.dexlib.Util.Input;
public abstract class Item<T extends Item> implements Comparable<T> {
/**
@ -53,6 +54,8 @@ public abstract class Item<T extends Item> implements Comparable<T> {
* @param dexFile the <code>DexFile</code> that this item is associated with
*/
protected Item(DexFile dexFile) {
assert dexFile != null;
this.dexFile = dexFile;
}
@ -64,11 +67,16 @@ public abstract class Item<T extends Item> implements Comparable<T> {
* only needed while reading in a file
*/
protected void readFrom(Input in, int index, ReadContext readContext) {
assert in.getCursor() % getItemType().ItemAlignment == 0;
try {
assert AlignmentUtils.isAligned(in.getCursor(), getItemType().ItemAlignment);
this.offset = in.getCursor();
this.index = index;
this.readItem(in, readContext);
this.offset = in.getCursor();
this.index = index;
this.readItem(in, readContext);
} catch (Exception ex) {
throw addExceptionContext(ex);
}
}
/**
@ -78,12 +86,16 @@ public abstract class Item<T extends Item> implements Comparable<T> {
* @return The offset of the byte following this item
*/
protected int placeAt(int offset, int index) {
assert offset % getItemType().ItemAlignment == 0;
assert !dexFile.getInplace() || (offset == this.offset && this.index == index);
try {
assert AlignmentUtils.isAligned(offset, getItemType().ItemAlignment);
assert !dexFile.getInplace() || (offset == this.offset && this.index == index);
this.offset = offset;
this.index = index;
return this.placeItem(offset);
this.offset = offset;
this.index = index;
return this.placeItem(offset);
} catch (Exception ex) {
throw addExceptionContext(ex);
}
}
/**
@ -91,16 +103,21 @@ public abstract class Item<T extends Item> implements Comparable<T> {
* @param out The output stream to write and annotate to
*/
protected void writeTo(AnnotatedOutput out) {
assert out.getCursor() % getItemType().ItemAlignment == 0;
assert out.getCursor() == offset;
try {
assert AlignmentUtils.isAligned(offset, getItemType().ItemAlignment);
//ensure that it is being written to the same offset where it was previously placed
assert out.getCursor() == offset;
if (out.annotates()) {
out.annotate(0, "[" + index + "] " + this.getItemType().TypeName);
if (out.annotates()) {
out.annotate(0, "[" + index + "] " + this.getItemType().TypeName);
}
out.indent();
writeItem(out);
out.deindent();
} catch (Exception ex) {
throw addExceptionContext(ex);
}
out.indent();
writeItem(out);
out.deindent();
}
/**
@ -148,6 +165,17 @@ public abstract class Item<T extends Item> implements Comparable<T> {
*/
protected abstract void writeItem(AnnotatedOutput out);
/**
* This method is called to add item specific context information to an exception, to identify the "current item"
* when the exception occured. It adds the value returned by <code>getConciseIdentity</code> as context for the
* exception
* @param ex The exception that occured
* @return A RuntimeException with additional details about the item added
*/
protected final RuntimeException addExceptionContext(Exception ex) {
return ExceptionWithContext.withContext(ex, getConciseIdentity());
}
/**
* @return An ItemType enum that represents the item type of this item
*/

View File

@ -82,7 +82,7 @@ public class ProtoIdItem extends Item<ProtoIdItem> {
protected void readItem(Input in, ReadContext readContext) {
shortyDescriptor = dexFile.StringIdsSection.getItemByIndex(in.readInt());
returnType = dexFile.TypeIdsSection.getItemByIndex(in.readInt());
parameters = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, in.readInt());
parameters = (TypeListItem)readContext.getOptionalOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, in.readInt());
}
/** {@inheritDoc} */

View File

@ -74,7 +74,7 @@ class ReadContext {
null, //map_list
null //header_item
};
/**
* The section sizes that are passed in while reading HeaderItem/MapItem, via the
@ -110,7 +110,7 @@ class ReadContext {
* @param itemType The type of item to get
* @return a SparseArray containing the items of the given type
* that have been pre-created while reading in other sections, or
* null if the ItemType isn't an offsetted item
* null if the ItemType isn't an offsetted item
*/
public SparseArray getItemsByType(ItemType itemType) {
return itemsByType[itemType.SectionIndex];
@ -121,9 +121,14 @@ class ReadContext {
* given offset. Multiple calls to this method with the same itemType
* and offset will return the same item.
*
* This method expects that offset will be a valid offset, not
* zero or negative. Use getOptionalOffsetedItemByOffset to handle
* the case of an optional item, where an offset of 0 is used to
* indicate the item isn't present
*
* It should not be assumed that the item that is returned will be
* initialized. It is only guaranteed that the item will be read in
* and initiliazed after the entire dex file has been read in.
* and initialiazed once the entire dex file has been read in.
*
* Note that it *is* guaranteed that this exact item will be added to
* its corresponding section and read in. In other words, when the
@ -132,14 +137,14 @@ class ReadContext {
* new items for offsets that haven't been pre-created yet.
*
* @param itemType The type of item to get
* @param offset The offset of the StringDataItem
* @return a StringDataItem for the given offset
* @param offset The offset of the item
* @return an item of the requested type for the given offset
*/
public Item getOffsettedItemByOffset(ItemType itemType, int offset) {
assert !itemType.isIndexedItem();
if (offset == 0) {
return null;
if (offset <= 0) {
throw new RuntimeException("Invalid offset " + offset + " for item type " + itemType.TypeName);
}
SparseArray<Item> sa = itemsByType[itemType.SectionIndex];
@ -152,7 +157,27 @@ class ReadContext {
}
/**
* Adds the size and offset information for the given offset
* This method is similar to getOffsettedItemByOffset, except that it allows
* the offset to be 0, in which case it will simply return null. This method
* should be used for an optional item, where an item offset of 0 indicates
* that the item isn't present
* @param itemType The type of item to get
* @param offset the offset of the item
* @return an item of the requested type for the given offset, or null if
* offset is 0
*/
public Item getOptionalOffsettedItemByOffset(ItemType itemType, int offset) {
assert !itemType.isIndexedItem();
if (offset == 0) {
return null;
}
return getOffsettedItemByOffset(itemType, offset);
}
/**
* Adds the size and offset information for the given offset
* @param itemType the item type of the section
* @param sectionSize the size of the section
* @param sectionOffset the offset of the section
@ -168,7 +193,7 @@ class ReadContext {
if (storedSectionSize != sectionSize) {
throw new RuntimeException("The section size in the header and map for item type "
+ itemType + " do not match");
}
}
}
int storedSectionOffset = sectionOffsets[itemType.SectionIndex];

View File

@ -34,4 +34,8 @@ public abstract class AlignmentUtils {
assert (alignment >= 0) && ((mask & alignment) == 0);
return (offset + mask) & ~mask;
}
public static boolean isAligned(int offset, int alignment) {
return (offset % alignment) == 0;
}
}

View File

@ -144,12 +144,12 @@ public class DeodexUtil {
final ArrayList<insn> insns = new ArrayList<insn>();
final SparseArray<insn> insnsMap = new SparseArray<insn>();
int currentCodeOffset = 0;
int currentCodeAddress = 0;
for (Instruction instruction: codeItem.getInstructions()) {
insn ins = new insn(codeItem, instruction, insnsMap, currentCodeOffset/2);
insn ins = new insn(codeItem, instruction, insnsMap, currentCodeAddress);
insns.add(ins);
insnsMap.append(currentCodeOffset/2, ins);
currentCodeOffset += instruction.getSize(currentCodeOffset);
insnsMap.append(currentCodeAddress, ins);
currentCodeAddress += instruction.getSize(currentCodeAddress);
}
if (codeItem.getTries() != null) {
@ -168,13 +168,13 @@ public class DeodexUtil {
handlers[i] = insnsMap.get(tryItem.encodedCatchHandler.handlers[i].getHandlerAddress());
}
int insnoffset = tryItem.getStartAddress();
while (insnoffset < tryItem.getStartAddress() + tryItem.getInstructionCount()) {
insn i = insnsMap.get(insnoffset);
int currentInsnAddress = tryItem.getStartCodeAddress();
while (currentInsnAddress < tryItem.getStartCodeAddress() + tryItem.getTryLength()) {
insn i = insnsMap.get(currentInsnAddress);
i.exceptionHandlers = handlers;
insnoffset += i.instruction.getSize(insnoffset*2)/2;
currentInsnAddress += i.instruction.getSize(currentInsnAddress);
}
}
}
@ -266,7 +266,7 @@ public class DeodexUtil {
i.fixedInstruction = new Instruction35msf(opcode, (Instruction35ms)i.instruction,
inlineMethod.getMethodIdItem());
insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize(i.offset*2)/2);
insn nextInstruction = i.getInstructionAtAddress(i.address + i.instruction.getSize(i.address));
assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.registerReferenceType =
@ -302,7 +302,7 @@ public class DeodexUtil {
i.fixedInstruction = new Instruction3rmsf(opcode, (Instruction3rms)i.instruction,
inlineMethod.getMethodIdItem());
insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize(i.offset*2)/2);
insn nextInstruction = i.getInstructionAtAddress(i.address + i.instruction.getSize(i.address));
assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.registerReferenceType =
@ -650,7 +650,7 @@ public class DeodexUtil {
i.fixedInstruction = new Instruction35msf(Opcode.INVOKE_VIRTUAL, (Instruction35ms)i.instruction,
method);
insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize(i.offset*2)/2);
insn nextInstruction = i.getInstructionAtAddress(i.address + i.instruction.getSize(i.address));
assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.updateRegisterReferenceType(
@ -697,7 +697,7 @@ public class DeodexUtil {
i.fixedInstruction = new Instruction3rmsf(Opcode.INVOKE_VIRTUAL_RANGE, (Instruction3rms)i.instruction,
method);
insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize(i.offset*2)/2);
insn nextInstruction = i.getInstructionAtAddress(i.address + i.instruction.getSize(i.address));
assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.updateRegisterReferenceType(
@ -745,7 +745,7 @@ public class DeodexUtil {
i.fixedInstruction = new Instruction35msf(Opcode.INVOKE_SUPER, (Instruction35ms)i.instruction,
method);
insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize(i.offset*2)/2);
insn nextInstruction = i.getInstructionAtAddress(i.address + i.instruction.getSize(i.address));
assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.updateRegisterReferenceType(
@ -792,7 +792,7 @@ public class DeodexUtil {
i.fixedInstruction = new Instruction3rmsf(Opcode.INVOKE_SUPER_RANGE, (Instruction3rms)i.instruction,
method);
insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize(i.offset*2)/2);
insn nextInstruction = i.getInstructionAtAddress(i.address + i.instruction.getSize(i.address));
assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.updateRegisterReferenceType(
@ -837,21 +837,21 @@ public class DeodexUtil {
*/
public final Instruction instruction;
/**
* The offset in the instruction stream, in 2-byte instruction blocks
* The code address of the instruction, in 2-byte instruction blocks
*/
public final int offset;
public final int address;
/**
* True if this instruction can throw an exception
*/
public final boolean canThrow;
/**
* maps an instruction stream offset to an insn
* maps a code address to an insn
*/
public final SparseArray<insn> insnsMap;
/**
* Instructions that can execution could pass on to next
* Instructions that execution could pass on to next
*/
public LinkedList<insn> successors = new LinkedList<insn>();
@ -925,10 +925,10 @@ public class DeodexUtil {
public final RegisterType[] registerMap;
public final String[] registerTypes;
public insn(CodeItem codeItem, Instruction instruction, SparseArray<insn> insnsMap, int offset) {
public insn(CodeItem codeItem, Instruction instruction, SparseArray<insn> insnsMap, int address) {
this.codeItem = codeItem;
this.instruction = instruction;
this.offset = offset;
this.address = address;
this.canThrow = DeodexUtil.instructionThrowTable.get(instruction.opcode.value & 0xFF);
this.insnsMap = insnsMap;
@ -965,8 +965,8 @@ public class DeodexUtil {
}
}
private insn getInstructionAtOffset(int offset) {
insn i = insnsMap.get(offset);
private insn getInstructionAtAddress(int address) {
insn i = insnsMap.get(address);
assert i != null;
return i;
}
@ -989,7 +989,7 @@ public class DeodexUtil {
case GOTO:
case GOTO_16:
case GOTO_32:
addSuccessor(getInstructionAtOffset(offset + ((OffsetInstruction)instruction).getOffset()));
addSuccessor(getInstructionAtAddress(address + ((OffsetInstruction)instruction).getTargetAddressOffset()));
return;
case IF_EQ:
case IF_GE:
@ -1003,19 +1003,19 @@ public class DeodexUtil {
case IF_LEZ:
case IF_LTZ:
case IF_NEZ:
addSuccessor(getInstructionAtOffset(offset + ((OffsetInstruction)instruction).getOffset()));
addSuccessor(getInstructionAtAddress(address + ((OffsetInstruction)instruction).getTargetAddressOffset()));
break;
case PACKED_SWITCH:
case SPARSE_SWITCH:
{
insn packedSwitchDataInsn =
getInstructionAtOffset(offset + ((OffsetInstruction)instruction).getOffset());
getInstructionAtAddress(address + ((OffsetInstruction)instruction).getTargetAddressOffset());
assert packedSwitchDataInsn.instruction instanceof MultiOffsetInstruction;
MultiOffsetInstruction switchData =
(MultiOffsetInstruction)(packedSwitchDataInsn.instruction);
int[] packedSwitchTargets = switchData.getTargets();
for (int i=0; i<packedSwitchTargets.length; i++) {
addSuccessor(getInstructionAtOffset(offset + packedSwitchTargets[i]));
addSuccessor(getInstructionAtAddress(address + packedSwitchTargets[i]));
}
break;
}
@ -1167,7 +1167,7 @@ public class DeodexUtil {
//the array size for that case, but support the case of multiple exception types as well
List<String> exceptionTypes = new ArrayList<String>(1);
for (CodeItem.TryItem tryItem: codeItem.getTries()) {
if (tryItem.encodedCatchHandler.getCatchAllHandlerAddress() == this.offset) {
if (tryItem.encodedCatchHandler.getCatchAllHandlerAddress() == this.address) {
//if this is a catch all handler, the only possible type is Ljava/lang/Throwable;
registerReferenceType = "Ljava/lang/Throwable;";
@ -1181,7 +1181,7 @@ public class DeodexUtil {
}
for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
if (handler.getHandlerAddress() == this.offset) {
if (handler.getHandlerAddress() == this.address) {
exceptionTypes.add(handler.exceptionType.getTypeDescriptor());
}
}
@ -1262,7 +1262,7 @@ public class DeodexUtil {
//if we got here, then we can assume that it's possible for execution to continue on to the next
//instruction. Otherwise, we would have returned from within the switch statement
addSuccessor(getInstructionAtOffset(offset + instruction.getSize(offset)/2));
addSuccessor(getInstructionAtAddress(address + instruction.getSize(address)));
}
private String findCommonSuperclass(String type1, String type2) {