Add support for the throw-verification-error opcode

This commit is contained in:
Ben Gruver
2011-10-09 14:52:00 -04:00
parent cb3e0ea38a
commit bbe539f2d2
10 changed files with 280 additions and 10 deletions

View File

@ -36,6 +36,7 @@ public enum Format {
Format11n(Instruction11n.Factory, 2),
Format11x(Instruction11x.Factory, 2),
Format12x(Instruction12x.Factory, 2),
Format20bc(Instruction20bc.Factory, 4),
Format20t(Instruction20t.Factory, 4),
Format21c(Instruction21c.Factory, 4),
Format21h(Instruction21h.Factory, 4),

View File

@ -0,0 +1,100 @@
/*
* [The "BSD licence"]
* Copyright (c) 2011 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib.Code.Format;
import org.jf.dexlib.*;
import org.jf.dexlib.Code.*;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.NumberUtils;
public class Instruction20bc extends InstructionWithReference {
public static final Instruction.InstructionFactory Factory = new Factory();
private VerificationErrorType validationErrorType;
public Instruction20bc(Opcode opcode, VerificationErrorType validationErrorType, Item referencedItem) {
super(opcode, referencedItem, getReferenceType(referencedItem));
this.validationErrorType = validationErrorType;
}
private static ReferenceType getReferenceType(Item item) {
if (item instanceof TypeIdItem) {
return ReferenceType.type;
}
if (item instanceof FieldIdItem) {
return ReferenceType.field;
}
if (item instanceof MethodIdItem) {
return ReferenceType.method;
}
return null;
}
private Instruction20bc(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
super(dexFile, opcode, buffer, bufferIndex);
short val = NumberUtils.decodeUnsignedByte(buffer[bufferIndex+1]);
validationErrorType = VerificationErrorType.getValidationErrorType(val & 0x3f);
}
protected ReferenceType readReferenceType(Opcode opcode, byte[] buffer, int bufferIndex) {
short val = NumberUtils.decodeUnsignedByte(buffer[bufferIndex+1]);
short referenceType = (short)(val >> 6);
return ReferenceType.fromValidationErrorReferenceType(referenceType);
}
@Override
public Format getFormat() {
return Format.Format20bc;
}
@Override
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.");
}
out.writeByte(opcode.value);
out.writeByte((this.getReferenceType().getValidationErrorReferenceType() << 6) &
validationErrorType.getValue());
out.writeShort(getReferencedItem().getIndex());
}
public VerificationErrorType getValidationErrorType() {
return validationErrorType;
}
private static class Factory implements Instruction.InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
return new Instruction20bc(dexFile, opcode, buffer, bufferIndex);
}
}
}

View File

@ -33,17 +33,27 @@ import org.jf.dexlib.Util.NumberUtils;
public abstract class InstructionWithReference extends Instruction {
private Item referencedItem;
private ReferenceType referenceType;
protected InstructionWithReference(Opcode opcode, Item referencedItem) {
super(opcode);
this.referencedItem = referencedItem;
this.referenceType = opcode.referenceType;
checkReferenceType();
}
protected InstructionWithReference(Opcode opcode, Item referencedItem, ReferenceType referenceType) {
super(opcode);
this.referencedItem = referencedItem;
this.referenceType = referenceType;
checkReferenceType();
}
protected InstructionWithReference(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
super(opcode);
int itemIndex = getReferencedItemIndex(buffer, bufferIndex);
this.referenceType = readReferenceType(opcode, buffer, bufferIndex);
int itemIndex = getReferencedItemIndex(buffer, bufferIndex);
lookupReferencedItem(dexFile, opcode, itemIndex);
}
@ -51,12 +61,20 @@ public abstract class InstructionWithReference extends Instruction {
return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2);
}
public ReferenceType getReferenceType() {
return referenceType;
}
public Item getReferencedItem() {
return referencedItem;
}
protected ReferenceType readReferenceType(Opcode opcode, byte[] buffer, int bufferIndex) {
return opcode.referenceType;
}
private void lookupReferencedItem(DexFile dexFile, Opcode opcode, int itemIndex) {
switch (opcode.referenceType) {
switch (referenceType) {
case field:
referencedItem = dexFile.FieldIdsSection.getItemByIndex(itemIndex);
return;
@ -73,7 +91,7 @@ public abstract class InstructionWithReference extends Instruction {
private void checkReferenceType() {
switch (opcode.referenceType) {
switch (referenceType) {
case field:
if (!(referencedItem instanceof FieldIdItem)) {
throw new RuntimeException(referencedItem.getClass().getSimpleName() +

View File

@ -263,6 +263,7 @@ public enum Opcode
SGET_WIDE_VOLATILE((byte)0xea, "sget-wide-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
SPUT_WIDE_VOLATILE((byte)0xeb, "sput-wide-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
THROW_VERIFICATION_ERROR((byte)0xed, "throw-verification-error", ReferenceType.none, Format.Format20bc, Opcode.ODEX_ONLY | Opcode.CAN_THROW),
EXECUTE_INLINE((byte)0xee, "execute-inline", ReferenceType.none, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
EXECUTE_INLINE_RANGE((byte)0xef, "execute-inline/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_DIRECT_EMPTY((byte)0xf0, "invoke-direct-empty", ReferenceType.method, Format.Format35s, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),

View File

@ -32,11 +32,17 @@ import org.jf.dexlib.*;
public enum ReferenceType
{
string,
type,
field,
method,
none;
string(-1),
type(0),
field(1),
method(2),
none(-1);
private int validationErrorReferenceType;
private ReferenceType(int validationErrorReferenceType) {
this.validationErrorReferenceType = validationErrorReferenceType;
}
public boolean checkItem(Item item) {
switch (this) {
@ -48,9 +54,27 @@ public enum ReferenceType
return item instanceof FieldIdItem;
case method:
return item instanceof MethodIdItem;
case none:
return item == null;
}
return false;
}
public static ReferenceType fromValidationErrorReferenceType(int validationErrorReferenceType) {
switch (validationErrorReferenceType) {
case 0:
return type;
case 1:
return field;
case 2:
return method;
}
return null;
}
public int getValidationErrorReferenceType() {
if (validationErrorReferenceType == -1) {
throw new RuntimeException("This reference type cannot be referenced from a throw-validation-error" +
" instruction");
}
return validationErrorReferenceType;
}
}

View File

@ -0,0 +1,83 @@
/*
* [The "BSD licence"]
* Copyright (c) 2011 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib.Code;
public enum VerificationErrorType {
None(0, "no-error"),
Generic(1, "generic-error"),
NoClass(2, "no-such-class"),
NoField(3, "no-such-field"),
NoMethod(4, "no-such-method"),
AccessClass(5, "illegal-class-access"),
AccessField(6, "illegal-field-access"),
AccessMethod(7, "illegal-method-access"),
ClassChange(8, "class-change-error"),
Instantiation(9, "instantiation-error");
private int value;
private String name;
private VerificationErrorType(int value, String name) {
this.value = value;
this.name = name;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
public static VerificationErrorType getValidationErrorType(int validationErrorType) {
switch (validationErrorType) {
case 0:
return None;
case 1:
return Generic;
case 2:
return NoClass;
case 3:
return NoField;
case 4:
return NoMethod;
case 5:
return AccessClass;
case 6:
return AccessField;
case 7:
return AccessMethod;
case 8:
return ClassChange;
case 9:
return Instantiation;
}
return null;
}
}