mirror of
https://github.com/revanced/Apktool.git
synced 2025-05-01 22:54:24 +02:00
update to smali 2.0.3
This commit is contained in:
parent
2af523d5d4
commit
a91e87bb04
2
CHANGES
2
CHANGES
@ -1,5 +1,5 @@
|
|||||||
v2.0.0 (TBA)
|
v2.0.0 (TBA)
|
||||||
-Updated to smali/baksmali to v2.0.0
|
-Updated to smali/baksmali to v2.0.3
|
||||||
-Updated to Gradle 1.8
|
-Updated to Gradle 1.8
|
||||||
-Fixed (issue #8) - Correctly uses -c to retain original manifest and META-INF. (Thanks M1cha)
|
-Fixed (issue #8) - Correctly uses -c to retain original manifest and META-INF. (Thanks M1cha)
|
||||||
-Fixed (issue #63) - Correctly handles apk's that have unknown files outside of the standard aapt allowed resources.
|
-Fixed (issue #63) - Correctly handles apk's that have unknown files outside of the standard aapt allowed resources.
|
||||||
|
@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
|
|||||||
import org.jf.baksmali.baksmaliOptions;
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
import org.jf.dexlib2.AccessFlags;
|
import org.jf.dexlib2.AccessFlags;
|
||||||
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
||||||
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||||
import org.jf.dexlib2.iface.*;
|
import org.jf.dexlib2.iface.*;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
||||||
@ -79,8 +80,15 @@ public class ClassDefinition {
|
|||||||
case SPUT_SHORT:
|
case SPUT_SHORT:
|
||||||
case SPUT_WIDE: {
|
case SPUT_WIDE: {
|
||||||
Instruction21c ins = (Instruction21c)instruction;
|
Instruction21c ins = (Instruction21c)instruction;
|
||||||
FieldReference fieldRef = (FieldReference)ins.getReference();
|
FieldReference fieldRef = null;
|
||||||
if (fieldRef.getDefiningClass().equals((classDef.getType()))) {
|
try {
|
||||||
|
fieldRef = (FieldReference)ins.getReference();
|
||||||
|
} catch (InvalidItemIndex ex) {
|
||||||
|
// just ignore it for now. We'll deal with it later, when processing the instructions
|
||||||
|
// themselves
|
||||||
|
}
|
||||||
|
if (fieldRef != null &&
|
||||||
|
fieldRef.getDefiningClass().equals((classDef.getType()))) {
|
||||||
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
|
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -65,6 +65,8 @@ public class ArrayDataMethodItem extends InstructionMethodItem<ArrayPayload> {
|
|||||||
for (Number number: elements) {
|
for (Number number: elements) {
|
||||||
LongRenderer.writeSignedIntOrLongTo(writer, number.longValue());
|
LongRenderer.writeSignedIntOrLongTo(writer, number.longValue());
|
||||||
writer.write(suffix);
|
writer.write(suffix);
|
||||||
|
if (elementWidth == 4)
|
||||||
|
writeResourceId(writer, number.intValue());
|
||||||
writer.write("\n");
|
writer.write("\n");
|
||||||
}
|
}
|
||||||
writer.deindent(4);
|
writer.deindent(4);
|
||||||
|
@ -29,20 +29,26 @@
|
|||||||
package org.jf.baksmali.Adaptors.Format;
|
package org.jf.baksmali.Adaptors.Format;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
|
import org.jf.baksmali.Adaptors.MethodDefinition.InvalidSwitchPayload;
|
||||||
import org.jf.baksmali.Adaptors.MethodItem;
|
import org.jf.baksmali.Adaptors.MethodItem;
|
||||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
|
||||||
import org.jf.baksmali.Renderers.LongRenderer;
|
import org.jf.baksmali.Renderers.LongRenderer;
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
|
import org.jf.dexlib2.Opcode;
|
||||||
import org.jf.dexlib2.ReferenceType;
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import org.jf.dexlib2.VerificationError;
|
import org.jf.dexlib2.VerificationError;
|
||||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||||
import org.jf.dexlib2.iface.instruction.*;
|
import org.jf.dexlib2.iface.instruction.*;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
|
import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
|
||||||
import org.jf.dexlib2.iface.reference.Reference;
|
import org.jf.dexlib2.iface.reference.Reference;
|
||||||
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||||
@Nonnull protected final MethodDefinition methodDef;
|
@Nonnull protected final MethodDefinition methodDef;
|
||||||
@ -59,29 +65,105 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isAllowedOdex(@Nonnull Opcode opcode) {
|
||||||
|
baksmaliOptions options = methodDef.classDef.options;
|
||||||
|
if (options.allowOdex) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodDef.classDef.options.apiLevel >= 14) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return opcode.isOdexedInstanceVolatile() || opcode.isOdexedStaticVolatile() ||
|
||||||
|
opcode == Opcode.THROW_VERIFICATION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
boolean invalidReference = false;
|
Opcode opcode = instruction.getOpcode();
|
||||||
if (instruction instanceof ReferenceInstruction) {
|
String verificationErrorName = null;
|
||||||
try {
|
String referenceString = null;
|
||||||
Reference reference = ((ReferenceInstruction)instruction).getReference();
|
|
||||||
} catch (InvalidItemIndex ex) {
|
|
||||||
invalidReference = true;
|
|
||||||
|
|
||||||
writer.write("#invalid ");
|
boolean commentOutInstruction = false;
|
||||||
writer.write(ReferenceType.toString(instruction.getOpcode().referenceType));
|
|
||||||
writer.write(" index: ");
|
if (instruction instanceof Instruction20bc) {
|
||||||
writer.printSignedIntAsDec(ex.getInvalidIndex());
|
int verificationError = ((Instruction20bc)instruction).getVerificationError();
|
||||||
writer.write("\n#");
|
verificationErrorName = VerificationError.getVerificationErrorName(verificationError);
|
||||||
|
if (verificationErrorName == null) {
|
||||||
|
writer.write("#was invalid verification error type: ");
|
||||||
|
writer.printSignedIntAsDec(verificationError);
|
||||||
|
writer.write("\n");
|
||||||
|
verificationErrorName = "generic-error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instruction instanceof ReferenceInstruction) {
|
||||||
|
ReferenceInstruction referenceInstruction = (ReferenceInstruction)instruction;
|
||||||
|
try {
|
||||||
|
Reference reference = referenceInstruction.getReference();
|
||||||
|
referenceString = ReferenceUtil.getReferenceString(reference);
|
||||||
|
assert referenceString != null;
|
||||||
|
} catch (InvalidItemIndex ex) {
|
||||||
|
writer.write("#");
|
||||||
|
writer.write(ex.getMessage());
|
||||||
|
writer.write("\n");
|
||||||
|
commentOutInstruction = true;
|
||||||
|
|
||||||
|
referenceString = String.format("%s@%d",
|
||||||
|
ReferenceType.toString(referenceInstruction.getReferenceType()),
|
||||||
|
ex.getInvalidIndex());
|
||||||
|
} catch (ReferenceType.InvalidReferenceTypeException ex) {
|
||||||
|
writer.write("#invalid reference type: ");
|
||||||
|
writer.printSignedIntAsDec(ex.getReferenceType());
|
||||||
|
commentOutInstruction = true;
|
||||||
|
|
||||||
|
referenceString = "invalid_reference";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction instanceof Instruction31t) {
|
||||||
|
Opcode payloadOpcode;
|
||||||
|
switch (instruction.getOpcode()) {
|
||||||
|
case PACKED_SWITCH:
|
||||||
|
payloadOpcode = Opcode.PACKED_SWITCH_PAYLOAD;
|
||||||
|
break;
|
||||||
|
case SPARSE_SWITCH:
|
||||||
|
payloadOpcode = Opcode.SPARSE_SWITCH_PAYLOAD;
|
||||||
|
break;
|
||||||
|
case FILL_ARRAY_DATA:
|
||||||
|
payloadOpcode = Opcode.ARRAY_PAYLOAD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ExceptionWithContext("Invalid 31t opcode: %s", instruction.getOpcode());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
methodDef.findSwitchPayload(this.codeAddress + ((Instruction31t)instruction).getCodeOffset(),
|
||||||
|
payloadOpcode);
|
||||||
|
} catch (InvalidSwitchPayload ex) {
|
||||||
|
writer.write("#invalid payload reference");
|
||||||
|
commentOutInstruction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opcode.odexOnly()) {
|
||||||
|
if (!isAllowedOdex(opcode)) {
|
||||||
|
writer.write("#disallowed odex opcode\n");
|
||||||
|
commentOutInstruction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commentOutInstruction) {
|
||||||
|
writer.write("#");
|
||||||
|
}
|
||||||
|
|
||||||
switch (instruction.getOpcode().format) {
|
switch (instruction.getOpcode().format) {
|
||||||
case Format10t:
|
case Format10t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeTargetLabel(writer);
|
writeTargetLabel(writer);
|
||||||
return true;
|
break;
|
||||||
case Format10x:
|
case Format10x:
|
||||||
if (instruction instanceof UnknownInstruction) {
|
if (instruction instanceof UnknownInstruction) {
|
||||||
writer.write("#unknown opcode: 0x");
|
writer.write("#unknown opcode: 0x");
|
||||||
@ -89,47 +171,47 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
return true;
|
break;
|
||||||
case Format11n:
|
case Format11n:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeLiteral(writer);
|
writeLiteral(writer);
|
||||||
return true;
|
break;
|
||||||
case Format11x:
|
case Format11x:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
return true;
|
break;
|
||||||
case Format12x:
|
case Format12x:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
return true;
|
break;
|
||||||
case Format20bc:
|
case Format20bc:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeVerificationErrorType(writer);
|
writer.write(verificationErrorName);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format20t:
|
case Format20t:
|
||||||
case Format30t:
|
case Format30t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeTargetLabel(writer);
|
writeTargetLabel(writer);
|
||||||
return true;
|
break;
|
||||||
case Format21c:
|
case Format21c:
|
||||||
case Format31c:
|
case Format31c:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format21ih:
|
case Format21ih:
|
||||||
case Format21lh:
|
case Format21lh:
|
||||||
case Format21s:
|
case Format21s:
|
||||||
@ -140,7 +222,9 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeLiteral(writer);
|
writeLiteral(writer);
|
||||||
return true;
|
if (instruction.getOpcode().setsWideRegister() == false)
|
||||||
|
writeResourceId(writer);
|
||||||
|
break;
|
||||||
case Format21t:
|
case Format21t:
|
||||||
case Format31t:
|
case Format31t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
@ -148,7 +232,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeTargetLabel(writer);
|
writeTargetLabel(writer);
|
||||||
return true;
|
break;
|
||||||
case Format22b:
|
case Format22b:
|
||||||
case Format22s:
|
case Format22s:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
@ -158,7 +242,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeLiteral(writer);
|
writeLiteral(writer);
|
||||||
return true;
|
break;
|
||||||
case Format22c:
|
case Format22c:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -166,8 +250,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format22cs:
|
case Format22cs:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -176,7 +260,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeFieldOffset(writer);
|
writeFieldOffset(writer);
|
||||||
return true;
|
break;
|
||||||
case Format22t:
|
case Format22t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -185,7 +269,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeTargetLabel(writer);
|
writeTargetLabel(writer);
|
||||||
return true;
|
break;
|
||||||
case Format22x:
|
case Format22x:
|
||||||
case Format32x:
|
case Format32x:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
@ -193,7 +277,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
return true;
|
break;
|
||||||
case Format23x:
|
case Format23x:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -202,52 +286,59 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeSecondRegister(writer);
|
writeSecondRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeThirdRegister(writer);
|
writeThirdRegister(writer);
|
||||||
return true;
|
break;
|
||||||
case Format35c:
|
case Format35c:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRegisters(writer);
|
writeInvokeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format35mi:
|
case Format35mi:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRegisters(writer);
|
writeInvokeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeInlineIndex(writer);
|
writeInlineIndex(writer);
|
||||||
return true;
|
break;
|
||||||
case Format35ms:
|
case Format35ms:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRegisters(writer);
|
writeInvokeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeVtableIndex(writer);
|
writeVtableIndex(writer);
|
||||||
return true;
|
break;
|
||||||
case Format3rc:
|
case Format3rc:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRangeRegisters(writer);
|
writeInvokeRangeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writer.write(referenceString);
|
||||||
return true;
|
break;
|
||||||
case Format3rmi:
|
case Format3rmi:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRangeRegisters(writer);
|
writeInvokeRangeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeInlineIndex(writer);
|
writeInlineIndex(writer);
|
||||||
return true;
|
break;
|
||||||
case Format3rms:
|
case Format3rms:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRangeRegisters(writer);
|
writeInvokeRangeRegisters(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeVtableIndex(writer);
|
writeVtableIndex(writer);
|
||||||
return true;
|
break;
|
||||||
|
default:
|
||||||
|
assert false;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
assert false;
|
|
||||||
return false;
|
if (commentOutInstruction) {
|
||||||
|
writer.write("\nnop");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeOpcode(IndentingWriter writer) throws IOException {
|
protected void writeOpcode(IndentingWriter writer) throws IOException {
|
||||||
@ -337,6 +428,18 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral());
|
LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void writeResourceId(IndentingWriter writer) throws IOException {
|
||||||
|
writeResourceId(writer, ((NarrowLiteralInstruction)instruction).getNarrowLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeResourceId(IndentingWriter writer, int val) throws IOException {
|
||||||
|
Map<Integer,String> resourceIds = methodDef.classDef.options.resourceIds;
|
||||||
|
String resource = resourceIds.get(Integer.valueOf(val));
|
||||||
|
if (resource != null) {
|
||||||
|
writer.write(" # ");
|
||||||
|
writer.write(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void writeFieldOffset(IndentingWriter writer) throws IOException {
|
protected void writeFieldOffset(IndentingWriter writer) throws IOException {
|
||||||
writer.write("field@0x");
|
writer.write("field@0x");
|
||||||
@ -352,20 +455,4 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writer.write("vtable@");
|
writer.write("vtable@");
|
||||||
writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex());
|
writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeReference(IndentingWriter writer) throws IOException {
|
|
||||||
try {
|
|
||||||
ReferenceFormatter.writeReference(writer, instruction.getOpcode().referenceType,
|
|
||||||
((ReferenceInstruction)instruction).getReference());
|
|
||||||
} catch (InvalidItemIndex ex) {
|
|
||||||
writer.write(ReferenceType.toString(instruction.getOpcode().referenceType));
|
|
||||||
writer.write("@");
|
|
||||||
writer.printSignedIntAsDec(ex.getInvalidIndex());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
|
|
||||||
int verificationError = ((Instruction20bc)instruction).getVerificationError();
|
|
||||||
writer.write(VerificationError.getVerificationErrorName(verificationError));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -82,9 +82,12 @@ public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchPa
|
|||||||
IntegerRenderer.writeTo(writer, firstKey);
|
IntegerRenderer.writeTo(writer, firstKey);
|
||||||
writer.indent(4);
|
writer.indent(4);
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
|
int key = firstKey;
|
||||||
for (PackedSwitchTarget target: targets) {
|
for (PackedSwitchTarget target: targets) {
|
||||||
target.writeTargetTo(writer);
|
target.writeTargetTo(writer);
|
||||||
|
writeResourceId(writer, key);
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
|
key++;
|
||||||
}
|
}
|
||||||
writer.deindent(4);
|
writer.deindent(4);
|
||||||
writer.write(".end packed-switch");
|
writer.write(".end packed-switch");
|
||||||
|
@ -71,6 +71,7 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchPa
|
|||||||
IntegerRenderer.writeTo(writer, target.getKey());
|
IntegerRenderer.writeTo(writer, target.getKey());
|
||||||
writer.write(" -> ");
|
writer.write(" -> ");
|
||||||
target.writeTargetTo(writer);
|
target.writeTargetTo(writer);
|
||||||
|
writeResourceId(writer, target.getKey());
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
writer.deindent(4);
|
writer.deindent(4);
|
||||||
|
@ -39,6 +39,7 @@ import org.jf.dexlib2.ReferenceType;
|
|||||||
import org.jf.dexlib2.analysis.AnalysisException;
|
import org.jf.dexlib2.analysis.AnalysisException;
|
||||||
import org.jf.dexlib2.analysis.AnalyzedInstruction;
|
import org.jf.dexlib2.analysis.AnalyzedInstruction;
|
||||||
import org.jf.dexlib2.analysis.MethodAnalyzer;
|
import org.jf.dexlib2.analysis.MethodAnalyzer;
|
||||||
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||||
import org.jf.dexlib2.iface.*;
|
import org.jf.dexlib2.iface.*;
|
||||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
@ -46,6 +47,7 @@ import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
|||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||||
import org.jf.dexlib2.util.InstructionOffsetMap;
|
import org.jf.dexlib2.util.InstructionOffsetMap;
|
||||||
|
import org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset;
|
||||||
import org.jf.dexlib2.util.ReferenceUtil;
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||||
import org.jf.dexlib2.util.TypeUtils;
|
import org.jf.dexlib2.util.TypeUtils;
|
||||||
@ -92,15 +94,31 @@ public class MethodDefinition {
|
|||||||
|
|
||||||
Opcode opcode = instruction.getOpcode();
|
Opcode opcode = instruction.getOpcode();
|
||||||
if (opcode == Opcode.PACKED_SWITCH) {
|
if (opcode == Opcode.PACKED_SWITCH) {
|
||||||
|
boolean valid = true;
|
||||||
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||||
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||||
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
|
try {
|
||||||
packedSwitchMap.append(targetOffset, codeOffset);
|
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
|
||||||
|
} catch (InvalidSwitchPayload ex) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
if (valid) {
|
||||||
|
packedSwitchMap.append(targetOffset, codeOffset);
|
||||||
|
}
|
||||||
} else if (opcode == Opcode.SPARSE_SWITCH) {
|
} else if (opcode == Opcode.SPARSE_SWITCH) {
|
||||||
|
boolean valid = true;
|
||||||
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||||
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||||
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
|
try {
|
||||||
sparseSwitchMap.append(targetOffset, codeOffset);
|
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
|
||||||
|
} catch (InvalidSwitchPayload ex) {
|
||||||
|
valid = false;
|
||||||
|
// The offset to the payload instruction was invalid. Nothing to do, except that we won't
|
||||||
|
// add this instruction to the map.
|
||||||
|
}
|
||||||
|
if (valid) {
|
||||||
|
sparseSwitchMap.append(targetOffset, codeOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch (Exception ex) {
|
}catch (Exception ex) {
|
||||||
@ -187,8 +205,13 @@ public class MethodDefinition {
|
|||||||
writer.write(".end method\n");
|
writer.write(".end method\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private int findSwitchPayload(int targetOffset, Opcode type) {
|
public int findSwitchPayload(int targetOffset, Opcode type) {
|
||||||
int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
|
int targetIndex;
|
||||||
|
try {
|
||||||
|
targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
|
||||||
|
} catch (InvalidInstructionOffset ex) {
|
||||||
|
throw new InvalidSwitchPayload(targetOffset);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: does dalvik let you pad with multiple nops?
|
//TODO: does dalvik let you pad with multiple nops?
|
||||||
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
|
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
|
||||||
@ -205,7 +228,7 @@ public class MethodDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset);
|
throw new InvalidSwitchPayload(targetOffset);
|
||||||
} else {
|
} else {
|
||||||
return targetOffset;
|
return targetOffset;
|
||||||
}
|
}
|
||||||
@ -337,10 +360,16 @@ public class MethodDefinition {
|
|||||||
Opcode opcode = instruction.getOpcode();
|
Opcode opcode = instruction.getOpcode();
|
||||||
|
|
||||||
if (opcode.referenceType == ReferenceType.METHOD) {
|
if (opcode.referenceType == ReferenceType.METHOD) {
|
||||||
MethodReference methodReference =
|
MethodReference methodReference = null;
|
||||||
(MethodReference)((ReferenceInstruction)instruction).getReference();
|
try {
|
||||||
|
methodReference = (MethodReference)((ReferenceInstruction)instruction).getReference();
|
||||||
|
} catch (InvalidItemIndex ex) {
|
||||||
|
// just ignore it for now. We'll deal with it later, when processing the instructions
|
||||||
|
// themselves
|
||||||
|
}
|
||||||
|
|
||||||
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
|
if (methodReference != null &&
|
||||||
|
SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
|
||||||
SyntheticAccessorResolver.AccessedMember accessedMember =
|
SyntheticAccessorResolver.AccessedMember accessedMember =
|
||||||
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
|
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
|
||||||
if (accessedMember != null) {
|
if (accessedMember != null) {
|
||||||
@ -510,4 +539,17 @@ public class MethodDefinition {
|
|||||||
return labels.values();
|
return labels.values();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class InvalidSwitchPayload extends ExceptionWithContext {
|
||||||
|
private final int payloadOffset;
|
||||||
|
|
||||||
|
public InvalidSwitchPayload(int payloadOffset) {
|
||||||
|
super("No switch payload at offset: %d", payloadOffset);
|
||||||
|
this.payloadOffset = payloadOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPayloadOffset() {
|
||||||
|
return payloadOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,9 @@ public class ReferenceFormatter {
|
|||||||
return;
|
return;
|
||||||
case ReferenceType.FIELD:
|
case ReferenceType.FIELD:
|
||||||
ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference);
|
ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown reference type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,19 @@ import org.jf.dexlib2.iface.DexFile;
|
|||||||
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||||
import org.jf.util.ClassFileNameHandler;
|
import org.jf.util.ClassFileNameHandler;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import javax.xml.parsers.SAXParser;
|
||||||
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
public class baksmali {
|
public class baksmali {
|
||||||
|
|
||||||
public static boolean disassembleDexFile(DexFile dexFile, final baksmaliOptions options) {
|
public static boolean disassembleDexFile(DexFile dexFile, final baksmaliOptions options) {
|
||||||
@ -60,9 +68,50 @@ public class baksmali {
|
|||||||
Iterables.concat(options.bootClassPathEntries, extraClassPathEntries), dexFile,
|
Iterables.concat(options.bootClassPathEntries, extraClassPathEntries), dexFile,
|
||||||
options.apiLevel);
|
options.apiLevel);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
System.err.println("\n\nError occured while loading boot class path files. Aborting.");
|
System.err.println("\n\nError occurred while loading boot class path files. Aborting.");
|
||||||
ex.printStackTrace(System.err);
|
ex.printStackTrace(System.err);
|
||||||
System.exit(1);
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.resourceIdFileEntries != null) {
|
||||||
|
class PublicHandler extends DefaultHandler {
|
||||||
|
String prefix = null;
|
||||||
|
public PublicHandler(String prefix) {
|
||||||
|
super();
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startElement(String uri, String localName,
|
||||||
|
String qName, Attributes attr) throws SAXException {
|
||||||
|
if (qName.equals("public")) {
|
||||||
|
String type = attr.getValue("type");
|
||||||
|
String name = attr.getValue("name").replace('.', '_');
|
||||||
|
Integer public_key = Integer.decode(attr.getValue("id"));
|
||||||
|
String public_val = new StringBuffer()
|
||||||
|
.append(prefix)
|
||||||
|
.append(".")
|
||||||
|
.append(type)
|
||||||
|
.append(".")
|
||||||
|
.append(name)
|
||||||
|
.toString();
|
||||||
|
options.resourceIds.put(public_key, public_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Entry<String,String> entry: options.resourceIdFileEntries.entrySet()) {
|
||||||
|
try {
|
||||||
|
SAXParser saxp = SAXParserFactory.newInstance().newSAXParser();
|
||||||
|
String prefix = entry.getValue();
|
||||||
|
saxp.parse(entry.getKey(), new PublicHandler(prefix));
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
continue;
|
||||||
|
} catch (SAXException e) {
|
||||||
|
continue;
|
||||||
|
} catch (IOException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +119,7 @@ public class baksmali {
|
|||||||
if (!outputDirectoryFile.exists()) {
|
if (!outputDirectoryFile.exists()) {
|
||||||
if (!outputDirectoryFile.mkdirs()) {
|
if (!outputDirectoryFile.mkdirs()) {
|
||||||
System.err.println("Can't create the output directory " + options.outputDirectory);
|
System.err.println("Can't create the output directory " + options.outputDirectory);
|
||||||
System.exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,22 +147,24 @@ public class baksmali {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean errorOccurred = false;
|
boolean errorOccurred = false;
|
||||||
for (Future<Boolean> task: tasks) {
|
try {
|
||||||
while(true) {
|
for (Future<Boolean> task: tasks) {
|
||||||
try {
|
while(true) {
|
||||||
if (!task.get()) {
|
try {
|
||||||
errorOccurred = true;
|
if (!task.get()) {
|
||||||
|
errorOccurred = true;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
continue;
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException ex) {
|
break;
|
||||||
continue;
|
|
||||||
} catch (ExecutionException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
executor.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
executor.shutdown();
|
|
||||||
return !errorOccurred;
|
return !errorOccurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +219,7 @@ public class baksmali {
|
|||||||
writer = new IndentingWriter(bufWriter);
|
writer = new IndentingWriter(bufWriter);
|
||||||
classDefinition.writeTo((IndentingWriter)writer);
|
classDefinition.writeTo((IndentingWriter)writer);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
System.err.println("\n\nError occured while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class");
|
System.err.println("\n\nError occurred while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class");
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
// noinspection ResultOfMethodCallIgnored
|
// noinspection ResultOfMethodCallIgnored
|
||||||
smaliFile.delete();
|
smaliFile.delete();
|
||||||
@ -180,7 +231,7 @@ public class baksmali {
|
|||||||
try {
|
try {
|
||||||
writer.close();
|
writer.close();
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
System.err.println("\n\nError occured while closing file " + smaliFile.toString());
|
System.err.println("\n\nError occurred while closing file " + smaliFile.toString());
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,9 @@ import org.jf.dexlib2.analysis.InlineMethodResolver;
|
|||||||
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class baksmaliOptions {
|
public class baksmaliOptions {
|
||||||
// register info values
|
// register info values
|
||||||
@ -58,12 +60,16 @@ public class baksmaliOptions {
|
|||||||
public List<String> bootClassPathEntries = Lists.newArrayList();
|
public List<String> bootClassPathEntries = Lists.newArrayList();
|
||||||
public List<String> extraClassPathEntries = Lists.newArrayList();
|
public List<String> extraClassPathEntries = Lists.newArrayList();
|
||||||
|
|
||||||
|
public Map<String,String> resourceIdFileEntries = new HashMap<String,String>();
|
||||||
|
public Map<Integer,String> resourceIds = new HashMap<Integer,String>();
|
||||||
|
|
||||||
public boolean noParameterRegisters = false;
|
public boolean noParameterRegisters = false;
|
||||||
public boolean useLocalsDirective = false;
|
public boolean useLocalsDirective = false;
|
||||||
public boolean useSequentialLabels = false;
|
public boolean useSequentialLabels = false;
|
||||||
public boolean outputDebugInfo = true;
|
public boolean outputDebugInfo = true;
|
||||||
public boolean addCodeOffsets = false;
|
public boolean addCodeOffsets = false;
|
||||||
public boolean noAccessorComments = false;
|
public boolean noAccessorComments = false;
|
||||||
|
public boolean allowOdex = false;
|
||||||
public boolean deodex = false;
|
public boolean deodex = false;
|
||||||
public boolean ignoreErrors = false;
|
public boolean ignoreErrors = false;
|
||||||
public boolean checkPackagePrivateAccess = false;
|
public boolean checkPackagePrivateAccess = false;
|
||||||
@ -84,4 +90,11 @@ public class baksmaliOptions {
|
|||||||
}
|
}
|
||||||
extraClassPathEntries.addAll(Arrays.asList(extraClassPath.split(":")));
|
extraClassPathEntries.addAll(Arrays.asList(extraClassPath.split(":")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setResourceIdFiles(String resourceIdFiles) {
|
||||||
|
for (String resourceIdFile: resourceIdFiles.split(":")) {
|
||||||
|
String[] entry = resourceIdFile.split("=");
|
||||||
|
resourceIdFileEntries.put(entry[1], entry[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,10 @@ public class main {
|
|||||||
case 'j':
|
case 'j':
|
||||||
options.jobs = Integer.parseInt(commandLine.getOptionValue("j"));
|
options.jobs = Integer.parseInt(commandLine.getOptionValue("j"));
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
|
String rif = commandLine.getOptionValue("i");
|
||||||
|
options.setResourceIdFiles(rif);
|
||||||
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
disassemble = false;
|
disassemble = false;
|
||||||
break;
|
break;
|
||||||
@ -215,9 +219,6 @@ public class main {
|
|||||||
case 'T':
|
case 'T':
|
||||||
options.inlineResolver = new CustomInlineMethodResolver(options.classPath, new File(commandLine.getOptionValue("T")));
|
options.inlineResolver = new CustomInlineMethodResolver(options.classPath, new File(commandLine.getOptionValue("T")));
|
||||||
break;
|
break;
|
||||||
case 'K':
|
|
||||||
options.checkPackagePrivateAccess = true;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
}
|
}
|
||||||
@ -235,6 +236,10 @@ public class main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.apiLevel >= 17) {
|
||||||
|
options.checkPackagePrivateAccess = true;
|
||||||
|
}
|
||||||
|
|
||||||
String inputDexFileName = remainingArgs[0];
|
String inputDexFileName = remainingArgs[0];
|
||||||
|
|
||||||
File dexFileFile = new File(inputDexFileName);
|
File dexFileFile = new File(inputDexFileName);
|
||||||
@ -251,6 +256,7 @@ public class main {
|
|||||||
System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
|
System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
|
||||||
System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
|
System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
|
||||||
System.err.println("option");
|
System.err.println("option");
|
||||||
|
options.allowOdex = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
options.deodex = false;
|
options.deodex = false;
|
||||||
@ -407,6 +413,14 @@ public class main {
|
|||||||
.withArgName("NUM_THREADS")
|
.withArgName("NUM_THREADS")
|
||||||
.create("j");
|
.create("j");
|
||||||
|
|
||||||
|
Option resourceIdFilesOption = OptionBuilder.withLongOpt("resource-id-files")
|
||||||
|
.withDescription("the resource ID files to use, for analysis. A colon-separated list of prefix=file " +
|
||||||
|
"pairs. For example R=res/values/public.xml:" +
|
||||||
|
"android.R=$ANDROID_HOME/platforms/android-19/data/res/values/public.xml")
|
||||||
|
.hasArg()
|
||||||
|
.withArgName("FILES")
|
||||||
|
.create("i");
|
||||||
|
|
||||||
Option dumpOption = OptionBuilder.withLongOpt("dump-to")
|
Option dumpOption = OptionBuilder.withLongOpt("dump-to")
|
||||||
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
|
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
|
||||||
" (<dexfile>.dump by default), along with the normal disassembly")
|
" (<dexfile>.dump by default), along with the normal disassembly")
|
||||||
@ -430,12 +444,6 @@ public class main {
|
|||||||
.withArgName("FILE")
|
.withArgName("FILE")
|
||||||
.create("T");
|
.create("T");
|
||||||
|
|
||||||
Option checkPackagePrivateAccess = OptionBuilder.withLongOpt("check-package-private-access")
|
|
||||||
.withDescription("When deodexing, use the new virtual table generation logic that " +
|
|
||||||
"prevents overriding an inaccessible package private method. This is a temporary option " +
|
|
||||||
"that will be removed once this new functionality can be tied to a specific api level.")
|
|
||||||
.create("K");
|
|
||||||
|
|
||||||
basicOptions.addOption(versionOption);
|
basicOptions.addOption(versionOption);
|
||||||
basicOptions.addOption(helpOption);
|
basicOptions.addOption(helpOption);
|
||||||
basicOptions.addOption(outputDirOption);
|
basicOptions.addOption(outputDirOption);
|
||||||
@ -451,12 +459,12 @@ public class main {
|
|||||||
basicOptions.addOption(noAccessorCommentsOption);
|
basicOptions.addOption(noAccessorCommentsOption);
|
||||||
basicOptions.addOption(apiLevelOption);
|
basicOptions.addOption(apiLevelOption);
|
||||||
basicOptions.addOption(jobsOption);
|
basicOptions.addOption(jobsOption);
|
||||||
|
basicOptions.addOption(resourceIdFilesOption);
|
||||||
|
|
||||||
debugOptions.addOption(dumpOption);
|
debugOptions.addOption(dumpOption);
|
||||||
debugOptions.addOption(ignoreErrorsOption);
|
debugOptions.addOption(ignoreErrorsOption);
|
||||||
debugOptions.addOption(noDisassemblyOption);
|
debugOptions.addOption(noDisassemblyOption);
|
||||||
debugOptions.addOption(inlineTableOption);
|
debugOptions.addOption(inlineTableOption);
|
||||||
debugOptions.addOption(checkPackagePrivateAccess);
|
|
||||||
|
|
||||||
for (Object option: basicOptions.getOptions()) {
|
for (Object option: basicOptions.getOptions()) {
|
||||||
options.addOption((Option)option);
|
options.addOption((Option)option);
|
||||||
|
@ -104,8 +104,9 @@ public class AnalysisTest {
|
|||||||
className.substring(1, className.length() - 1));
|
className.substring(1, className.length() - 1));
|
||||||
String smaliContents = readResource(smaliPath);
|
String smaliContents = readResource(smaliPath);
|
||||||
|
|
||||||
Assert.assertEquals(smaliContents.replace("\r", "").replace("\n", System.lineSeparator()),
|
String newline = System.getProperty("line.separator");
|
||||||
stringWriter.toString().replace("\r", "").replace("\n", System.lineSeparator()));
|
Assert.assertEquals(smaliContents.replace("\r", "").replace("\n", newline),
|
||||||
|
stringWriter.toString().replace("\r", "").replace("\n", newline));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,10 @@ public class Opcodes {
|
|||||||
case 0x300:
|
case 0x300:
|
||||||
return Opcode.ARRAY_PAYLOAD;
|
return Opcode.ARRAY_PAYLOAD;
|
||||||
default:
|
default:
|
||||||
return opcodesByValue[opcodeValue];
|
if (opcodeValue >= 0 && opcodeValue < opcodesByValue.length) {
|
||||||
|
return opcodesByValue[opcodeValue];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
|
|
||||||
package org.jf.dexlib2;
|
package org.jf.dexlib2;
|
||||||
|
|
||||||
|
import org.jf.dexlib2.iface.reference.*;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
public final class ReferenceType {
|
public final class ReferenceType {
|
||||||
public static final int STRING = 0;
|
public static final int STRING = 0;
|
||||||
public static final int TYPE = 1;
|
public static final int TYPE = 1;
|
||||||
@ -49,7 +52,50 @@ public final class ReferenceType {
|
|||||||
case METHOD:
|
case METHOD:
|
||||||
return "method";
|
return "method";
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid reference type: " + referenceType);
|
throw new InvalidReferenceTypeException(referenceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getReferenceType(Reference reference) {
|
||||||
|
if (reference instanceof StringReference) {
|
||||||
|
return STRING;
|
||||||
|
} else if (reference instanceof TypeReference) {
|
||||||
|
return TYPE;
|
||||||
|
} else if (reference instanceof FieldReference) {
|
||||||
|
return FIELD;
|
||||||
|
} else if (reference instanceof MethodReference) {
|
||||||
|
return METHOD;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Invalid reference");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a specific reference type. Note that the NONE placeholder is specifically not considered valid here.
|
||||||
|
*
|
||||||
|
* @throws InvalidReferenceTypeException
|
||||||
|
*/
|
||||||
|
public static void validateReferenceType(int referenceType) {
|
||||||
|
if (referenceType < 0 || referenceType > 3) {
|
||||||
|
throw new InvalidReferenceTypeException(referenceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InvalidReferenceTypeException extends ExceptionWithContext {
|
||||||
|
private final int referenceType;
|
||||||
|
|
||||||
|
public InvalidReferenceTypeException(int referenceType) {
|
||||||
|
super("Invalid reference type: %d", referenceType);
|
||||||
|
this.referenceType = referenceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidReferenceTypeException(int referenceType, String message, Object... formatArgs) {
|
||||||
|
super(message, formatArgs);
|
||||||
|
this.referenceType = referenceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReferenceType() {
|
||||||
|
return referenceType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ package org.jf.dexlib2;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class VerificationError {
|
public class VerificationError {
|
||||||
@ -61,6 +62,7 @@ public class VerificationError {
|
|||||||
verificationErrorNames.put("instantiation-error", INSTANTIATION_ERROR);
|
verificationErrorNames.put("instantiation-error", INSTANTIATION_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public static String getVerificationErrorName(int verificationError) {
|
public static String getVerificationErrorName(int verificationError) {
|
||||||
switch (verificationError) {
|
switch (verificationError) {
|
||||||
case GENERIC:
|
case GENERIC:
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
package org.jf.dexlib2.builder;
|
package org.jf.dexlib2.builder;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.ImmutableList;
|
||||||
import org.jf.dexlib2.builder.debug.*;
|
import org.jf.dexlib2.builder.debug.*;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
import org.jf.dexlib2.iface.reference.StringReference;
|
import org.jf.dexlib2.iface.reference.StringReference;
|
||||||
@ -39,18 +39,21 @@ import org.jf.dexlib2.iface.reference.TypeReference;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.AbstractSet;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class MethodLocation {
|
public class MethodLocation {
|
||||||
@Nullable BuilderInstruction instruction;
|
@Nullable BuilderInstruction instruction;
|
||||||
int codeAddress;
|
int codeAddress;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
private List<Label> labels = Lists.newArrayList();
|
// We end up creating and keeping around a *lot* of MethodLocation objects
|
||||||
List<BuilderDebugItem> debugItems = Lists.newArrayList();
|
// when building a new dex file, so it's worth the trouble of lazily creating
|
||||||
|
// the labels and debugItems lists only when they are needed
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private List<Label> labels = null;
|
||||||
|
@Nullable
|
||||||
|
private List<BuilderDebugItem> debugItems = null;
|
||||||
|
|
||||||
MethodLocation(@Nullable BuilderInstruction instruction, int codeAddress, int index) {
|
MethodLocation(@Nullable BuilderInstruction instruction, int codeAddress, int index) {
|
||||||
this.instruction = instruction;
|
this.instruction = instruction;
|
||||||
@ -71,19 +74,51 @@ public class MethodLocation {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private List<Label> getLabels(boolean mutable) {
|
||||||
|
if (labels == null) {
|
||||||
|
if (mutable) {
|
||||||
|
labels = new ArrayList<Label>(1);
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
return ImmutableList.of();
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private List<BuilderDebugItem> getDebugItems(boolean mutable) {
|
||||||
|
if (debugItems == null) {
|
||||||
|
if (mutable) {
|
||||||
|
debugItems = new ArrayList<BuilderDebugItem>(1);
|
||||||
|
return debugItems;
|
||||||
|
}
|
||||||
|
return ImmutableList.of();
|
||||||
|
}
|
||||||
|
return debugItems;
|
||||||
|
}
|
||||||
|
|
||||||
void mergeInto(@Nonnull MethodLocation other) {
|
void mergeInto(@Nonnull MethodLocation other) {
|
||||||
for (Label label: labels) {
|
if (this.labels != null || other.labels != null) {
|
||||||
label.location = other;
|
List<Label> otherLabels = other.getLabels(true);
|
||||||
other.labels.add(label);
|
for (Label label: this.getLabels(false)) {
|
||||||
|
label.location = other;
|
||||||
|
otherLabels.add(label);
|
||||||
|
}
|
||||||
|
this.labels = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to keep the debug items in the same order. We add the other debug items to this list, then reassign
|
if (this.debugItems != null || other.labels != null) {
|
||||||
// the list.
|
// We need to keep the debug items in the same order. We add the other debug items to this list, then reassign
|
||||||
for (BuilderDebugItem debugItem: debugItems) {
|
// the list.
|
||||||
debugItem.location = other;
|
List<BuilderDebugItem> debugItems = getDebugItems(true);
|
||||||
|
for (BuilderDebugItem debugItem: debugItems) {
|
||||||
|
debugItem.location = other;
|
||||||
|
}
|
||||||
|
debugItems.addAll(other.getDebugItems(false));
|
||||||
|
other.debugItems = debugItems;
|
||||||
|
this.debugItems = null;
|
||||||
}
|
}
|
||||||
debugItems.addAll(other.debugItems);
|
|
||||||
other.debugItems = debugItems;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@ -91,7 +126,7 @@ public class MethodLocation {
|
|||||||
return new AbstractSet<Label>() {
|
return new AbstractSet<Label>() {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override public Iterator<Label> iterator() {
|
@Override public Iterator<Label> iterator() {
|
||||||
final Iterator<Label> it = labels.iterator();
|
final Iterator<Label> it = getLabels(false).iterator();
|
||||||
|
|
||||||
return new Iterator<Label>() {
|
return new Iterator<Label>() {
|
||||||
private @Nullable Label currentLabel = null;
|
private @Nullable Label currentLabel = null;
|
||||||
@ -115,7 +150,7 @@ public class MethodLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public int size() {
|
@Override public int size() {
|
||||||
return labels.size();
|
return getLabels(false).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean add(@Nonnull Label label) {
|
@Override public boolean add(@Nonnull Label label) {
|
||||||
@ -124,7 +159,7 @@ public class MethodLocation {
|
|||||||
"it from its current location first.");
|
"it from its current location first.");
|
||||||
}
|
}
|
||||||
label.location = MethodLocation.this;
|
label.location = MethodLocation.this;
|
||||||
labels.add(label);
|
getLabels(true).add(label);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -133,7 +168,7 @@ public class MethodLocation {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
public Label addNewLabel() {
|
public Label addNewLabel() {
|
||||||
Label label = new Label(this);
|
Label label = new Label(this);
|
||||||
labels.add(label);
|
getLabels(true).add(label);
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +177,7 @@ public class MethodLocation {
|
|||||||
return new AbstractSet<BuilderDebugItem>() {
|
return new AbstractSet<BuilderDebugItem>() {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override public Iterator<BuilderDebugItem> iterator() {
|
@Override public Iterator<BuilderDebugItem> iterator() {
|
||||||
final Iterator<BuilderDebugItem> it = debugItems.iterator();
|
final Iterator<BuilderDebugItem> it = getDebugItems(false).iterator();
|
||||||
|
|
||||||
return new Iterator<BuilderDebugItem>() {
|
return new Iterator<BuilderDebugItem>() {
|
||||||
private @Nullable BuilderDebugItem currentDebugItem = null;
|
private @Nullable BuilderDebugItem currentDebugItem = null;
|
||||||
@ -166,7 +201,7 @@ public class MethodLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public int size() {
|
@Override public int size() {
|
||||||
return labels.size();
|
return getDebugItems(false).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean add(@Nonnull BuilderDebugItem debugItem) {
|
@Override public boolean add(@Nonnull BuilderDebugItem debugItem) {
|
||||||
@ -175,7 +210,7 @@ public class MethodLocation {
|
|||||||
"method. You must remove it from its current location first.");
|
"method. You must remove it from its current location first.");
|
||||||
}
|
}
|
||||||
debugItem.location = MethodLocation.this;
|
debugItem.location = MethodLocation.this;
|
||||||
debugItems.add(debugItem);
|
getDebugItems(true).add(debugItem);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -435,6 +435,14 @@ public class MutableMethodImplementation implements MethodImplementation {
|
|||||||
}
|
}
|
||||||
case SPARSE_SWITCH_PAYLOAD:
|
case SPARSE_SWITCH_PAYLOAD:
|
||||||
case PACKED_SWITCH_PAYLOAD:
|
case PACKED_SWITCH_PAYLOAD:
|
||||||
|
if (((BuilderSwitchPayload)instruction).referrer == null) {
|
||||||
|
// if the switch payload isn't referenced, just remove it
|
||||||
|
removeInstruction(index);
|
||||||
|
index--;
|
||||||
|
madeChanges = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// intentional fall-through
|
||||||
case ARRAY_PAYLOAD: {
|
case ARRAY_PAYLOAD: {
|
||||||
if ((location.codeAddress & 0x01) != 0) {
|
if ((location.codeAddress & 0x01) != 0) {
|
||||||
int previousIndex = location.index - 1;
|
int previousIndex = location.index - 1;
|
||||||
|
@ -33,6 +33,7 @@ package org.jf.dexlib2.builder.instruction;
|
|||||||
|
|
||||||
import org.jf.dexlib2.Format;
|
import org.jf.dexlib2.Format;
|
||||||
import org.jf.dexlib2.Opcode;
|
import org.jf.dexlib2.Opcode;
|
||||||
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import org.jf.dexlib2.builder.BuilderInstruction;
|
import org.jf.dexlib2.builder.BuilderInstruction;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||||
import org.jf.dexlib2.iface.reference.Reference;
|
import org.jf.dexlib2.iface.reference.Reference;
|
||||||
@ -56,6 +57,7 @@ public class BuilderInstruction20bc extends BuilderInstruction implements Instru
|
|||||||
|
|
||||||
@Override public int getVerificationError() { return verificationError; }
|
@Override public int getVerificationError() { return verificationError; }
|
||||||
@Nonnull @Override public Reference getReference() { return reference; }
|
@Nonnull @Override public Reference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return ReferenceType.getReferenceType(reference); }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ public class BuilderInstruction21c extends BuilderInstruction implements Instruc
|
|||||||
|
|
||||||
@Override public int getRegisterA() { return registerA; }
|
@Override public int getRegisterA() { return registerA; }
|
||||||
@Nonnull @Override public Reference getReference() { return reference; }
|
@Nonnull @Override public Reference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ public class BuilderInstruction22c extends BuilderInstruction implements Instruc
|
|||||||
@Override public int getRegisterA() { return registerA; }
|
@Override public int getRegisterA() { return registerA; }
|
||||||
@Override public int getRegisterB() { return registerB; }
|
@Override public int getRegisterB() { return registerB; }
|
||||||
@Nonnull @Override public Reference getReference() { return reference; }
|
@Nonnull @Override public Reference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
@ -56,6 +56,7 @@ public class BuilderInstruction31c extends BuilderInstruction implements Instruc
|
|||||||
|
|
||||||
@Override public int getRegisterA() { return registerA; }
|
@Override public int getRegisterA() { return registerA; }
|
||||||
@Nonnull @Override public Reference getReference() { return reference; }
|
@Nonnull @Override public Reference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,7 @@ public class BuilderInstruction35c extends BuilderInstruction implements Instruc
|
|||||||
@Override public int getRegisterF() { return registerF; }
|
@Override public int getRegisterF() { return registerF; }
|
||||||
@Override public int getRegisterG() { return registerG; }
|
@Override public int getRegisterG() { return registerG; }
|
||||||
@Nonnull @Override public Reference getReference() { return reference; }
|
@Nonnull @Override public Reference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,7 @@ public class BuilderInstruction3rc extends BuilderInstruction implements Instruc
|
|||||||
@Override public int getStartRegister() { return startRegister; }
|
@Override public int getStartRegister() { return startRegister; }
|
||||||
@Override public int getRegisterCount() { return registerCount; }
|
@Override public int getRegisterCount() { return registerCount; }
|
||||||
@Nonnull @Override public Reference getReference() { return reference; }
|
@Nonnull @Override public Reference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
|
|||||||
|
|
||||||
public int getMethodIdItemOffset(int methodIndex) {
|
public int getMethodIdItemOffset(int methodIndex) {
|
||||||
if (methodIndex < 0 || methodIndex >= methodCount) {
|
if (methodIndex < 0 || methodIndex >= methodCount) {
|
||||||
throw new InvalidItemIndex(methodIndex, "Method findex out of bounds: %d", methodIndex);
|
throw new InvalidItemIndex(methodIndex, "Method index out of bounds: %d", methodIndex);
|
||||||
}
|
}
|
||||||
return methodStartOffset + methodIndex*MethodIdItem.ITEM_SIZE;
|
return methodStartOffset + methodIndex*MethodIdItem.ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
package org.jf.dexlib2.dexbacked.instruction;
|
package org.jf.dexlib2.dexbacked.instruction;
|
||||||
|
|
||||||
import org.jf.dexlib2.Opcode;
|
import org.jf.dexlib2.Opcode;
|
||||||
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||||
import org.jf.dexlib2.dexbacked.reference.DexBackedReference;
|
import org.jf.dexlib2.dexbacked.reference.DexBackedReference;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||||
@ -51,7 +52,13 @@ public class DexBackedInstruction20bc extends DexBackedInstruction implements In
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Reference getReference() {
|
public Reference getReference() {
|
||||||
int refType = (dexFile.readUbyte(instructionStart + 1) >>> 6) + 1;
|
int referenceType = getReferenceType();
|
||||||
return DexBackedReference.makeReference(dexFile, refType, dexFile.readUshort(instructionStart + 2));
|
return DexBackedReference.makeReference(dexFile, referenceType, dexFile.readUshort(instructionStart + 2));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override public int getReferenceType() {
|
||||||
|
int referenceType = (dexFile.readUbyte(instructionStart + 1) >>> 6) + 1;
|
||||||
|
ReferenceType.validateReferenceType(referenceType);
|
||||||
|
return referenceType;
|
||||||
|
}
|
||||||
|
}
|
@ -53,4 +53,9 @@ public class DexBackedInstruction21c extends DexBackedInstruction implements Ins
|
|||||||
public Reference getReference() {
|
public Reference getReference() {
|
||||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType, dexFile.readUshort(instructionStart + 2));
|
return DexBackedReference.makeReference(dexFile, opcode.referenceType, dexFile.readUshort(instructionStart + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReferenceType() {
|
||||||
|
return opcode.referenceType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,4 +62,9 @@ public class DexBackedInstruction22c extends DexBackedInstruction implements Ins
|
|||||||
public Reference getReference() {
|
public Reference getReference() {
|
||||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType, dexFile.readUshort(instructionStart + 2));
|
return DexBackedReference.makeReference(dexFile, opcode.referenceType, dexFile.readUshort(instructionStart + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReferenceType() {
|
||||||
|
return opcode.referenceType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,4 +54,9 @@ public class DexBackedInstruction31c extends DexBackedInstruction implements Ins
|
|||||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType,
|
return DexBackedReference.makeReference(dexFile, opcode.referenceType,
|
||||||
dexFile.readSmallUint(instructionStart + 2));
|
dexFile.readSmallUint(instructionStart + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReferenceType() {
|
||||||
|
return opcode.referenceType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,4 +82,9 @@ public class DexBackedInstruction35c extends DexBackedInstruction implements Ins
|
|||||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType,
|
return DexBackedReference.makeReference(dexFile, opcode.referenceType,
|
||||||
dexFile.readUshort(instructionStart + 2));
|
dexFile.readUshort(instructionStart + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReferenceType() {
|
||||||
|
return opcode.referenceType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,4 +61,10 @@ public class DexBackedInstruction3rc extends DexBackedInstruction implements Ins
|
|||||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType,
|
return DexBackedReference.makeReference(dexFile, opcode.referenceType,
|
||||||
dexFile.readUshort(instructionStart + 2));
|
dexFile.readUshort(instructionStart + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReferenceType() {
|
||||||
|
return opcode.referenceType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,12 @@ public class DexBackedUnknownInstruction extends DexBackedInstruction implements
|
|||||||
super(dexFile, Opcode.NOP, instructionStart);
|
super(dexFile, Opcode.NOP, instructionStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public short getOriginalOpcode() {
|
@Override public int getOriginalOpcode() {
|
||||||
return (short)dexFile.readUbyte(instructionStart);
|
int opcode = dexFile.readUbyte(instructionStart);
|
||||||
|
if (opcode == 0) {
|
||||||
|
opcode = dexFile.readUshort(instructionStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
return opcode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ import org.jf.dexlib2.iface.instruction.*;
|
|||||||
import org.jf.dexlib2.iface.instruction.formats.*;
|
import org.jf.dexlib2.iface.instruction.formats.*;
|
||||||
import org.jf.dexlib2.util.AnnotatedBytes;
|
import org.jf.dexlib2.util.AnnotatedBytes;
|
||||||
import org.jf.dexlib2.util.ReferenceUtil;
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.util.NumberUtils;
|
import org.jf.util.NumberUtils;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -84,121 +85,160 @@ public class CodeItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
|
public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
|
||||||
DexReader reader = dexFile.readerAt(out.getCursor());
|
try {
|
||||||
|
DexReader reader = dexFile.readerAt(out.getCursor());
|
||||||
|
|
||||||
int registers = reader.readUshort();
|
int registers = reader.readUshort();
|
||||||
out.annotate(2, "registers_size = %d", registers);
|
out.annotate(2, "registers_size = %d", registers);
|
||||||
|
|
||||||
int inSize = reader.readUshort();
|
int inSize = reader.readUshort();
|
||||||
out.annotate(2, "ins_size = %d", inSize);
|
out.annotate(2, "ins_size = %d", inSize);
|
||||||
|
|
||||||
int outSize = reader.readUshort();
|
int outSize = reader.readUshort();
|
||||||
out.annotate(2, "outs_size = %d", outSize);
|
out.annotate(2, "outs_size = %d", outSize);
|
||||||
|
|
||||||
int triesCount = reader.readUshort();
|
int triesCount = reader.readUshort();
|
||||||
out.annotate(2, "tries_size = %d", triesCount);
|
out.annotate(2, "tries_size = %d", triesCount);
|
||||||
|
|
||||||
int debugInfoOffset = reader.readSmallUint();
|
int debugInfoOffset = reader.readSmallUint();
|
||||||
out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset);
|
out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset);
|
||||||
|
|
||||||
if (debugInfoOffset != 0) {
|
if (debugInfoOffset != 0) {
|
||||||
addDebugInfoIdentity(debugInfoOffset, itemIdentity);
|
addDebugInfoIdentity(debugInfoOffset, itemIdentity);
|
||||||
}
|
|
||||||
|
|
||||||
int instructionSize = reader.readSmallUint();
|
|
||||||
out.annotate(4, "insns_size = 0x%x", instructionSize);
|
|
||||||
|
|
||||||
out.annotate(0, "instructions:");
|
|
||||||
out.indent();
|
|
||||||
|
|
||||||
int end = reader.getOffset() + instructionSize*2;
|
|
||||||
while (reader.getOffset() < end) {
|
|
||||||
Instruction instruction = DexBackedInstruction.readFrom(reader);
|
|
||||||
|
|
||||||
switch (instruction.getOpcode().format) {
|
|
||||||
case Format10x:
|
|
||||||
annotateInstruction10x(out, instruction);
|
|
||||||
break;
|
|
||||||
case Format35c:
|
|
||||||
annotateInstruction35c(out, (Instruction35c)instruction);
|
|
||||||
break;
|
|
||||||
case Format3rc:
|
|
||||||
annotateInstruction3rc(out, (Instruction3rc)instruction);
|
|
||||||
break;
|
|
||||||
case ArrayPayload:
|
|
||||||
annotateArrayPayload(out, (ArrayPayload)instruction);
|
|
||||||
break;
|
|
||||||
case PackedSwitchPayload:
|
|
||||||
annotatePackedSwitchPayload(out, (PackedSwitchPayload)instruction);
|
|
||||||
break;
|
|
||||||
case SparseSwitchPayload:
|
|
||||||
annotateSparseSwitchPayload(out, (SparseSwitchPayload)instruction);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
annotateDefaultInstruction(out, instruction);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert reader.getOffset() == out.getCursor();
|
int instructionSize = reader.readSmallUint();
|
||||||
}
|
out.annotate(4, "insns_size = 0x%x", instructionSize);
|
||||||
out.deindent();
|
|
||||||
|
|
||||||
if (triesCount > 0) {
|
out.annotate(0, "instructions:");
|
||||||
if ((reader.getOffset() % 4) != 0) {
|
|
||||||
reader.readUshort();
|
|
||||||
out.annotate(2, "padding");
|
|
||||||
}
|
|
||||||
|
|
||||||
out.annotate(0, "try_items:");
|
|
||||||
out.indent();
|
out.indent();
|
||||||
for (int i=0; i<triesCount; i++) {
|
|
||||||
out.annotate(0, "try_item[%d]:", i);
|
|
||||||
out.indent();
|
|
||||||
int startAddr = reader.readSmallUint();
|
|
||||||
out.annotate(4, "start_addr = 0x%x", startAddr);
|
|
||||||
|
|
||||||
int instructionCount = reader.readUshort();
|
out.setLimit(out.getCursor(), out.getCursor() + instructionSize * 2);
|
||||||
out.annotate(2, "insn_count = 0x%x", instructionCount);
|
|
||||||
|
|
||||||
int handlerOffset = reader.readUshort();
|
int end = reader.getOffset() + instructionSize*2;
|
||||||
out.annotate(2, "handler_off = 0x%x", handlerOffset);
|
try {
|
||||||
|
while (reader.getOffset() < end) {
|
||||||
|
Instruction instruction = DexBackedInstruction.readFrom(reader);
|
||||||
|
|
||||||
|
// if we read past the end of the instruction list
|
||||||
|
if (reader.getOffset() > end) {
|
||||||
|
out.annotateTo(end, "truncated instruction");
|
||||||
|
reader.setOffset(end);
|
||||||
|
} else {
|
||||||
|
switch (instruction.getOpcode().format) {
|
||||||
|
case Format10x:
|
||||||
|
annotateInstruction10x(out, instruction);
|
||||||
|
break;
|
||||||
|
case Format35c:
|
||||||
|
annotateInstruction35c(out, (Instruction35c)instruction);
|
||||||
|
break;
|
||||||
|
case Format3rc:
|
||||||
|
annotateInstruction3rc(out, (Instruction3rc)instruction);
|
||||||
|
break;
|
||||||
|
case ArrayPayload:
|
||||||
|
annotateArrayPayload(out, (ArrayPayload)instruction);
|
||||||
|
break;
|
||||||
|
case PackedSwitchPayload:
|
||||||
|
annotatePackedSwitchPayload(out, (PackedSwitchPayload)instruction);
|
||||||
|
break;
|
||||||
|
case SparseSwitchPayload:
|
||||||
|
annotateSparseSwitchPayload(out, (SparseSwitchPayload)instruction);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
annotateDefaultInstruction(out, instruction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert reader.getOffset() == out.getCursor();
|
||||||
|
}
|
||||||
|
} catch (ExceptionWithContext ex) {
|
||||||
|
ex.printStackTrace(System.err);
|
||||||
|
out.annotate(0, "annotation error: %s", ex.getMessage());
|
||||||
|
out.moveTo(end);
|
||||||
|
reader.setOffset(end);
|
||||||
|
} finally {
|
||||||
|
out.clearLimit();
|
||||||
out.deindent();
|
out.deindent();
|
||||||
}
|
}
|
||||||
out.deindent();
|
|
||||||
|
|
||||||
int handlerListCount = reader.readSmallUleb128();
|
if (triesCount > 0) {
|
||||||
out.annotate(0, "encoded_catch_handler_list:");
|
if ((reader.getOffset() % 4) != 0) {
|
||||||
out.annotateTo(reader.getOffset(), "size = %d", handlerListCount);
|
reader.readUshort();
|
||||||
out.indent();
|
out.annotate(2, "padding");
|
||||||
for (int i=0; i<handlerListCount; i++) {
|
}
|
||||||
out.annotate(0, "encoded_catch_handler[%d]", i);
|
|
||||||
|
out.annotate(0, "try_items:");
|
||||||
out.indent();
|
out.indent();
|
||||||
int handlerCount = reader.readSleb128();
|
try {
|
||||||
out.annotateTo(reader.getOffset(), "size = %d", handlerCount);
|
for (int i=0; i<triesCount; i++) {
|
||||||
boolean hasCatchAll = handlerCount <= 0;
|
out.annotate(0, "try_item[%d]:", i);
|
||||||
handlerCount = Math.abs(handlerCount);
|
|
||||||
if (handlerCount != 0) {
|
|
||||||
out.annotate(0, "handlers:");
|
|
||||||
out.indent();
|
|
||||||
for (int j=0; j<handlerCount; j++) {
|
|
||||||
out.annotate(0, "encoded_type_addr_pair[%d]", i);
|
|
||||||
out.indent();
|
out.indent();
|
||||||
int typeIndex = reader.readSmallUleb128();
|
try {
|
||||||
out.annotateTo(reader.getOffset(), TypeIdItem.getReferenceAnnotation(dexFile, typeIndex));
|
int startAddr = reader.readSmallUint();
|
||||||
|
out.annotate(4, "start_addr = 0x%x", startAddr);
|
||||||
|
|
||||||
int handlerAddress = reader.readSmallUleb128();
|
int instructionCount = reader.readUshort();
|
||||||
out.annotateTo(reader.getOffset(), "addr = 0x%x", handlerAddress);
|
out.annotate(2, "insn_count = 0x%x", instructionCount);
|
||||||
out.deindent();
|
|
||||||
|
int handlerOffset = reader.readUshort();
|
||||||
|
out.annotate(2, "handler_off = 0x%x", handlerOffset);
|
||||||
|
} finally {
|
||||||
|
out.deindent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
out.deindent();
|
out.deindent();
|
||||||
}
|
}
|
||||||
if (hasCatchAll) {
|
|
||||||
int catchAllAddress = reader.readSmallUleb128();
|
int handlerListCount = reader.readSmallUleb128();
|
||||||
out.annotateTo(reader.getOffset(), "catch_all_addr = 0x%x", catchAllAddress);
|
out.annotate(0, "encoded_catch_handler_list:");
|
||||||
|
out.annotateTo(reader.getOffset(), "size = %d", handlerListCount);
|
||||||
|
out.indent();
|
||||||
|
try {
|
||||||
|
for (int i=0; i<handlerListCount; i++) {
|
||||||
|
out.annotate(0, "encoded_catch_handler[%d]", i);
|
||||||
|
out.indent();
|
||||||
|
try {
|
||||||
|
int handlerCount = reader.readSleb128();
|
||||||
|
out.annotateTo(reader.getOffset(), "size = %d", handlerCount);
|
||||||
|
boolean hasCatchAll = handlerCount <= 0;
|
||||||
|
handlerCount = Math.abs(handlerCount);
|
||||||
|
if (handlerCount != 0) {
|
||||||
|
out.annotate(0, "handlers:");
|
||||||
|
out.indent();
|
||||||
|
try {
|
||||||
|
for (int j=0; j<handlerCount; j++) {
|
||||||
|
out.annotate(0, "encoded_type_addr_pair[%d]", i);
|
||||||
|
out.indent();
|
||||||
|
try {
|
||||||
|
int typeIndex = reader.readSmallUleb128();
|
||||||
|
out.annotateTo(reader.getOffset(), TypeIdItem.getReferenceAnnotation(dexFile, typeIndex));
|
||||||
|
|
||||||
|
int handlerAddress = reader.readSmallUleb128();
|
||||||
|
out.annotateTo(reader.getOffset(), "addr = 0x%x", handlerAddress);
|
||||||
|
} finally {
|
||||||
|
out.deindent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
out.deindent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasCatchAll) {
|
||||||
|
int catchAllAddress = reader.readSmallUleb128();
|
||||||
|
out.annotateTo(reader.getOffset(), "catch_all_addr = 0x%x", catchAllAddress);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
out.deindent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
out.deindent();
|
||||||
}
|
}
|
||||||
out.deindent();
|
|
||||||
}
|
}
|
||||||
out.deindent();
|
} catch (ExceptionWithContext ex) {
|
||||||
|
out.annotate(0, "annotation error: %s", ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,13 +303,17 @@ public class CodeItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (instruction instanceof VerificationErrorInstruction) {
|
} else if (instruction instanceof VerificationErrorInstruction) {
|
||||||
args.add(VerificationError.getVerificationErrorName(
|
String verificationError = VerificationError.getVerificationErrorName(
|
||||||
((VerificationErrorInstruction)instruction).getVerificationError()));
|
((VerificationErrorInstruction) instruction).getVerificationError());
|
||||||
|
if (verificationError != null) {
|
||||||
|
args.add(verificationError);
|
||||||
|
} else {
|
||||||
|
args.add("invalid verification error type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instruction instanceof ReferenceInstruction) {
|
if (instruction instanceof ReferenceInstruction) {
|
||||||
args.add(ReferenceUtil.getReferenceString(
|
args.add(ReferenceUtil.getReferenceString(((ReferenceInstruction)instruction).getReference()));
|
||||||
((ReferenceInstruction)instruction).getReference()));
|
|
||||||
} else if (instruction instanceof OffsetInstruction) {
|
} else if (instruction instanceof OffsetInstruction) {
|
||||||
int offset = ((OffsetInstruction)instruction).getCodeOffset();
|
int offset = ((OffsetInstruction)instruction).getCodeOffset();
|
||||||
String sign = offset>=0?"+":"-";
|
String sign = offset>=0?"+":"-";
|
||||||
|
@ -37,4 +37,5 @@ import javax.annotation.Nonnull;
|
|||||||
|
|
||||||
public interface ReferenceInstruction extends Instruction {
|
public interface ReferenceInstruction extends Instruction {
|
||||||
@Nonnull Reference getReference();
|
@Nonnull Reference getReference();
|
||||||
|
int getReferenceType();
|
||||||
}
|
}
|
||||||
|
@ -32,5 +32,5 @@
|
|||||||
package org.jf.dexlib2.iface.instruction.formats;
|
package org.jf.dexlib2.iface.instruction.formats;
|
||||||
|
|
||||||
public interface UnknownInstruction extends Instruction10x {
|
public interface UnknownInstruction extends Instruction10x {
|
||||||
short getOriginalOpcode();
|
int getOriginalOpcode();
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ package org.jf.dexlib2.immutable.instruction;
|
|||||||
|
|
||||||
import org.jf.dexlib2.Format;
|
import org.jf.dexlib2.Format;
|
||||||
import org.jf.dexlib2.Opcode;
|
import org.jf.dexlib2.Opcode;
|
||||||
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||||
import org.jf.dexlib2.iface.reference.Reference;
|
import org.jf.dexlib2.iface.reference.Reference;
|
||||||
import org.jf.dexlib2.immutable.reference.ImmutableReference;
|
import org.jf.dexlib2.immutable.reference.ImmutableReference;
|
||||||
@ -67,6 +68,7 @@ public class ImmutableInstruction20bc extends ImmutableInstruction implements In
|
|||||||
|
|
||||||
@Override public int getVerificationError() { return verificationError; }
|
@Override public int getVerificationError() { return verificationError; }
|
||||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return ReferenceType.getReferenceType(reference); }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,7 @@ public class ImmutableInstruction21c extends ImmutableInstruction implements Ins
|
|||||||
|
|
||||||
@Override public int getRegisterA() { return registerA; }
|
@Override public int getRegisterA() { return registerA; }
|
||||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ public class ImmutableInstruction22c extends ImmutableInstruction implements Ins
|
|||||||
@Override public int getRegisterA() { return registerA; }
|
@Override public int getRegisterA() { return registerA; }
|
||||||
@Override public int getRegisterB() { return registerB; }
|
@Override public int getRegisterB() { return registerB; }
|
||||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
@ -67,6 +67,7 @@ public class ImmutableInstruction31c extends ImmutableInstruction implements Ins
|
|||||||
|
|
||||||
@Override public int getRegisterA() { return registerA; }
|
@Override public int getRegisterA() { return registerA; }
|
||||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,7 @@ public class ImmutableInstruction35c extends ImmutableInstruction implements Ins
|
|||||||
@Override public int getRegisterF() { return registerF; }
|
@Override public int getRegisterF() { return registerF; }
|
||||||
@Override public int getRegisterG() { return registerG; }
|
@Override public int getRegisterG() { return registerG; }
|
||||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ public class ImmutableInstruction3rc extends ImmutableInstruction implements Ins
|
|||||||
@Override public int getStartRegister() { return startRegister; }
|
@Override public int getStartRegister() { return startRegister; }
|
||||||
@Override public int getRegisterCount() { return registerCount; }
|
@Override public int getRegisterCount() { return registerCount; }
|
||||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||||
|
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,9 @@ import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
|
|||||||
public class ImmutableUnknownInstruction extends ImmutableInstruction implements UnknownInstruction {
|
public class ImmutableUnknownInstruction extends ImmutableInstruction implements UnknownInstruction {
|
||||||
public static final Format FORMAT = Format.Format10x;
|
public static final Format FORMAT = Format.Format10x;
|
||||||
|
|
||||||
protected final short originalOpcode;
|
protected final int originalOpcode;
|
||||||
|
|
||||||
public ImmutableUnknownInstruction(short originalOpcode) {
|
public ImmutableUnknownInstruction(int originalOpcode) {
|
||||||
super(Opcode.NOP);
|
super(Opcode.NOP);
|
||||||
this.originalOpcode = originalOpcode;
|
this.originalOpcode = originalOpcode;
|
||||||
}
|
}
|
||||||
@ -53,5 +53,5 @@ public class ImmutableUnknownInstruction extends ImmutableInstruction implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public Format getFormat() { return FORMAT; }
|
@Override public Format getFormat() { return FORMAT; }
|
||||||
@Override public short getOriginalOpcode() { return originalOpcode; }
|
@Override public int getOriginalOpcode() { return originalOpcode; }
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@ package org.jf.dexlib2.util;
|
|||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.util.Hex;
|
import org.jf.util.Hex;
|
||||||
import org.jf.util.TwoColumnOutput;
|
import org.jf.util.TwoColumnOutput;
|
||||||
|
|
||||||
@ -78,6 +80,9 @@ public class AnnotatedBytes {
|
|||||||
*/
|
*/
|
||||||
private int hexCols = 8;
|
private int hexCols = 8;
|
||||||
|
|
||||||
|
private int startLimit = -1;
|
||||||
|
private int endLimit = -1;
|
||||||
|
|
||||||
public AnnotatedBytes(int width) {
|
public AnnotatedBytes(int width) {
|
||||||
this.outputWidth = width;
|
this.outputWidth = width;
|
||||||
}
|
}
|
||||||
@ -115,7 +120,16 @@ public class AnnotatedBytes {
|
|||||||
* @param formatArgs format arguments to pass to String.format
|
* @param formatArgs format arguments to pass to String.format
|
||||||
*/
|
*/
|
||||||
public void annotate(int length, @Nonnull String msg, Object... formatArgs) {
|
public void annotate(int length, @Nonnull String msg, Object... formatArgs) {
|
||||||
String formattedMsg = String.format(msg, formatArgs);
|
if (startLimit != -1 && endLimit != -1 && (cursor < startLimit || cursor >= endLimit)) {
|
||||||
|
throw new ExceptionWithContext("Annotating outside the parent bounds");
|
||||||
|
}
|
||||||
|
|
||||||
|
String formattedMsg;
|
||||||
|
if (formatArgs != null && formatArgs.length > 0) {
|
||||||
|
formattedMsg = String.format(msg, formatArgs);
|
||||||
|
} else {
|
||||||
|
formattedMsg = msg;
|
||||||
|
}
|
||||||
int exclusiveEndOffset = cursor + length;
|
int exclusiveEndOffset = cursor + length;
|
||||||
|
|
||||||
AnnotationEndpoint endPoint = null;
|
AnnotationEndpoint endPoint = null;
|
||||||
@ -129,19 +143,20 @@ public class AnnotatedBytes {
|
|||||||
AnnotationEndpoint previousAnnotations = previousEntry.getValue();
|
AnnotationEndpoint previousAnnotations = previousEntry.getValue();
|
||||||
AnnotationItem previousRangeAnnotation = previousAnnotations.rangeAnnotation;
|
AnnotationItem previousRangeAnnotation = previousAnnotations.rangeAnnotation;
|
||||||
if (previousRangeAnnotation != null) {
|
if (previousRangeAnnotation != null) {
|
||||||
throw new IllegalStateException(
|
throw new ExceptionWithContext(
|
||||||
String.format("Cannot add annotation %s, due to existing annotation %s",
|
"Cannot add annotation %s, due to existing annotation %s",
|
||||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||||
formatAnnotation(previousEntry.getKey(), previousRangeAnnotation.annotation)));
|
formatAnnotation(previousEntry.getKey(),
|
||||||
|
previousRangeAnnotation.annotation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (length > 0) {
|
} else if (length > 0) {
|
||||||
AnnotationItem existingRangeAnnotation = startPoint.rangeAnnotation;
|
AnnotationItem existingRangeAnnotation = startPoint.rangeAnnotation;
|
||||||
if (existingRangeAnnotation != null) {
|
if (existingRangeAnnotation != null) {
|
||||||
throw new IllegalStateException(
|
throw new ExceptionWithContext(
|
||||||
String.format("Cannot add annotation %s, due to existing annotation %s",
|
"Cannot add annotation %s, due to existing annotation %s",
|
||||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||||
formatAnnotation(cursor, existingRangeAnnotation.annotation)));
|
formatAnnotation(cursor, existingRangeAnnotation.annotation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,23 +171,23 @@ public class AnnotatedBytes {
|
|||||||
AnnotationEndpoint nextEndpoint = nextEntry.getValue();
|
AnnotationEndpoint nextEndpoint = nextEntry.getValue();
|
||||||
AnnotationItem nextRangeAnnotation = nextEndpoint.rangeAnnotation;
|
AnnotationItem nextRangeAnnotation = nextEndpoint.rangeAnnotation;
|
||||||
if (nextRangeAnnotation != null) {
|
if (nextRangeAnnotation != null) {
|
||||||
throw new IllegalStateException(
|
throw new ExceptionWithContext(
|
||||||
String.format("Cannot add annotation %s, due to existing annotation %s",
|
"Cannot add annotation %s, due to existing annotation %s",
|
||||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||||
formatAnnotation(nextKey, nextRangeAnnotation.annotation)));
|
formatAnnotation(nextKey, nextRangeAnnotation.annotation));
|
||||||
}
|
}
|
||||||
if (nextEndpoint.pointAnnotations.size() > 0) {
|
if (nextEndpoint.pointAnnotations.size() > 0) {
|
||||||
throw new IllegalStateException(
|
throw new ExceptionWithContext(
|
||||||
String.format("Cannot add annotation %s, due to existing annotation %s",
|
"Cannot add annotation %s, due to existing annotation %s",
|
||||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||||
formatAnnotation(nextKey, nextKey,
|
formatAnnotation(nextKey, nextKey,
|
||||||
nextEndpoint.pointAnnotations.get(0).annotation)));
|
nextEndpoint.pointAnnotations.get(0).annotation));
|
||||||
}
|
}
|
||||||
// There are no annotations on this endpoint. This "shouldn't" happen. We can still throw an exception.
|
// There are no annotations on this endpoint. This "shouldn't" happen. We can still throw an exception.
|
||||||
throw new IllegalStateException(
|
throw new ExceptionWithContext(
|
||||||
String.format("Cannot add annotation %s, due to existing annotation endpoint at %d",
|
"Cannot add annotation %s, due to existing annotation endpoint at %d",
|
||||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||||
nextKey));
|
nextKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextKey == exclusiveEndOffset) {
|
if (nextKey == exclusiveEndOffset) {
|
||||||
@ -312,4 +327,14 @@ public class AnnotatedBytes {
|
|||||||
twoc.write(left, "");
|
twoc.write(left, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLimit(int start, int end) {
|
||||||
|
this.startLimit = start;
|
||||||
|
this.endLimit = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearLimit() {
|
||||||
|
this.startLimit = -1;
|
||||||
|
this.endLimit = -1;
|
||||||
|
}
|
||||||
}
|
}
|
@ -59,7 +59,7 @@ public class InstructionOffsetMap {
|
|||||||
int index = Arrays.binarySearch(instructionCodeOffsets, codeOffset);
|
int index = Arrays.binarySearch(instructionCodeOffsets, codeOffset);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
if (exact) {
|
if (exact) {
|
||||||
throw new ExceptionWithContext("No instruction at offset %d", codeOffset);
|
throw new InvalidInstructionOffset(codeOffset);
|
||||||
} else {
|
} else {
|
||||||
// This calculation would be incorrect if index was -1 (i.e. insertion point of 0). Luckily, we can
|
// This calculation would be incorrect if index was -1 (i.e. insertion point of 0). Luckily, we can
|
||||||
// ignore this case, because codeOffset will always be non-negative, and the code offset of the first
|
// ignore this case, because codeOffset will always be non-negative, and the code offset of the first
|
||||||
@ -72,8 +72,34 @@ public class InstructionOffsetMap {
|
|||||||
|
|
||||||
public int getInstructionCodeOffset(int index) {
|
public int getInstructionCodeOffset(int index) {
|
||||||
if (index < 0 || index >= instructionCodeOffsets.length) {
|
if (index < 0 || index >= instructionCodeOffsets.length) {
|
||||||
throw new ExceptionWithContext("Index out of bounds: %d", index);
|
throw new InvalidInstructionIndex(index);
|
||||||
}
|
}
|
||||||
return instructionCodeOffsets[index];
|
return instructionCodeOffsets[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class InvalidInstructionOffset extends ExceptionWithContext {
|
||||||
|
private final int instructionOffset;
|
||||||
|
|
||||||
|
public InvalidInstructionOffset(int instructionOffset) {
|
||||||
|
super("No instruction at offset %d", instructionOffset);
|
||||||
|
this.instructionOffset = instructionOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInstructionOffset() {
|
||||||
|
return instructionOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InvalidInstructionIndex extends ExceptionWithContext {
|
||||||
|
private final int instructionIndex;
|
||||||
|
|
||||||
|
public InvalidInstructionIndex(int instructionIndex) {
|
||||||
|
super("Instruction index out of bounds: %d", instructionIndex);
|
||||||
|
this.instructionIndex = instructionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInstructionIndex() {
|
||||||
|
return instructionIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import com.google.common.collect.Iterables;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.jf.dexlib2.Opcode;
|
import org.jf.dexlib2.Opcode;
|
||||||
import org.jf.dexlib2.Opcodes;
|
import org.jf.dexlib2.Opcodes;
|
||||||
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import org.jf.dexlib2.builder.MethodImplementationBuilder;
|
import org.jf.dexlib2.builder.MethodImplementationBuilder;
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction10x;
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction10x;
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c;
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c;
|
||||||
@ -136,6 +137,8 @@ public class JumboStringConversionTest {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public int getReferenceType() { return ReferenceType.STRING; }
|
||||||
|
|
||||||
@Override public Opcode getOpcode() {
|
@Override public Opcode getOpcode() {
|
||||||
return Opcode.CONST_STRING;
|
return Opcode.CONST_STRING;
|
||||||
}
|
}
|
||||||
|
@ -922,8 +922,8 @@ insn_format21c_string
|
|||||||
|
|
||||||
insn_format21c_type
|
insn_format21c_type
|
||||||
: //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
|
: //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
|
||||||
INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor
|
INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA nonvoid_type_descriptor
|
||||||
-> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor);
|
-> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER nonvoid_type_descriptor);
|
||||||
|
|
||||||
insn_format21ih
|
insn_format21ih
|
||||||
: //e.g. const/high16 v1, 1234
|
: //e.g. const/high16 v1, 1234
|
||||||
|
@ -840,13 +840,13 @@ insn_format21c_string
|
|||||||
|
|
||||||
insn_format21c_type
|
insn_format21c_type
|
||||||
: //e.g. const-class v2, org/jf/HelloWorld2/HelloWorld2
|
: //e.g. const-class v2, org/jf/HelloWorld2/HelloWorld2
|
||||||
^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor)
|
^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER nonvoid_type_descriptor)
|
||||||
{
|
{
|
||||||
Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text);
|
Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text);
|
||||||
short regA = parseRegister_byte($REGISTER.text);
|
short regA = parseRegister_byte($REGISTER.text);
|
||||||
|
|
||||||
$method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
|
$method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
|
||||||
dexBuilder.internTypeReference($reference_type_descriptor.type)));
|
dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
|
||||||
};
|
};
|
||||||
|
|
||||||
insn_format21ih
|
insn_format21ih
|
||||||
|
@ -142,7 +142,7 @@ public class ClassFileNameHandler {
|
|||||||
writer.close();
|
writer.close();
|
||||||
f.delete(); //doesn't throw IOException
|
f.delete(); //doesn't throw IOException
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
//if an exception occured, it's likely that we're on a windows system.
|
//if an exception occurred, it's likely that we're on a windows system.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user