mirror of
https://github.com/revanced/Apktool.git
synced 2025-02-09 10:36:46 +01: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)
|
||||
-Updated to smali/baksmali to v2.0.0
|
||||
-Updated to smali/baksmali to v2.0.3
|
||||
-Updated to Gradle 1.8
|
||||
-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.
|
||||
|
@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
|
||||
import org.jf.baksmali.baksmaliOptions;
|
||||
import org.jf.dexlib2.AccessFlags;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||
import org.jf.dexlib2.iface.*;
|
||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
||||
@ -79,8 +80,15 @@ public class ClassDefinition {
|
||||
case SPUT_SHORT:
|
||||
case SPUT_WIDE: {
|
||||
Instruction21c ins = (Instruction21c)instruction;
|
||||
FieldReference fieldRef = (FieldReference)ins.getReference();
|
||||
if (fieldRef.getDefiningClass().equals((classDef.getType()))) {
|
||||
FieldReference fieldRef = null;
|
||||
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));
|
||||
}
|
||||
break;
|
||||
|
@ -65,6 +65,8 @@ public class ArrayDataMethodItem extends InstructionMethodItem<ArrayPayload> {
|
||||
for (Number number: elements) {
|
||||
LongRenderer.writeSignedIntOrLongTo(writer, number.longValue());
|
||||
writer.write(suffix);
|
||||
if (elementWidth == 4)
|
||||
writeResourceId(writer, number.intValue());
|
||||
writer.write("\n");
|
||||
}
|
||||
writer.deindent(4);
|
||||
|
@ -29,20 +29,26 @@
|
||||
package org.jf.baksmali.Adaptors.Format;
|
||||
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition.InvalidSwitchPayload;
|
||||
import org.jf.baksmali.Adaptors.MethodItem;
|
||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
||||
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.VerificationError;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||
import org.jf.dexlib2.iface.instruction.*;
|
||||
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.reference.Reference;
|
||||
import org.jf.dexlib2.util.ReferenceUtil;
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
import org.jf.util.IndentingWriter;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
@Nonnull protected final MethodDefinition methodDef;
|
||||
@ -59,29 +65,105 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
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
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
boolean invalidReference = false;
|
||||
if (instruction instanceof ReferenceInstruction) {
|
||||
try {
|
||||
Reference reference = ((ReferenceInstruction)instruction).getReference();
|
||||
} catch (InvalidItemIndex ex) {
|
||||
invalidReference = true;
|
||||
Opcode opcode = instruction.getOpcode();
|
||||
String verificationErrorName = null;
|
||||
String referenceString = null;
|
||||
|
||||
writer.write("#invalid ");
|
||||
writer.write(ReferenceType.toString(instruction.getOpcode().referenceType));
|
||||
writer.write(" index: ");
|
||||
writer.printSignedIntAsDec(ex.getInvalidIndex());
|
||||
writer.write("\n#");
|
||||
boolean commentOutInstruction = false;
|
||||
|
||||
if (instruction instanceof Instruction20bc) {
|
||||
int verificationError = ((Instruction20bc)instruction).getVerificationError();
|
||||
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) {
|
||||
case Format10t:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeTargetLabel(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format10x:
|
||||
if (instruction instanceof UnknownInstruction) {
|
||||
writer.write("#unknown opcode: 0x");
|
||||
@ -89,47 +171,47 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write('\n');
|
||||
}
|
||||
writeOpcode(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format11n:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeFirstRegister(writer);
|
||||
writer.write(", ");
|
||||
writeLiteral(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format11x:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeFirstRegister(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format12x:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeFirstRegister(writer);
|
||||
writer.write(", ");
|
||||
writeSecondRegister(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format20bc:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeVerificationErrorType(writer);
|
||||
writer.write(verificationErrorName);
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
writer.write(referenceString);
|
||||
break;
|
||||
case Format20t:
|
||||
case Format30t:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeTargetLabel(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format21c:
|
||||
case Format31c:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeFirstRegister(writer);
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
writer.write(referenceString);
|
||||
break;
|
||||
case Format21ih:
|
||||
case Format21lh:
|
||||
case Format21s:
|
||||
@ -140,7 +222,9 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeFirstRegister(writer);
|
||||
writer.write(", ");
|
||||
writeLiteral(writer);
|
||||
return true;
|
||||
if (instruction.getOpcode().setsWideRegister() == false)
|
||||
writeResourceId(writer);
|
||||
break;
|
||||
case Format21t:
|
||||
case Format31t:
|
||||
writeOpcode(writer);
|
||||
@ -148,7 +232,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeFirstRegister(writer);
|
||||
writer.write(", ");
|
||||
writeTargetLabel(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format22b:
|
||||
case Format22s:
|
||||
writeOpcode(writer);
|
||||
@ -158,7 +242,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeSecondRegister(writer);
|
||||
writer.write(", ");
|
||||
writeLiteral(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format22c:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
@ -166,8 +250,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write(", ");
|
||||
writeSecondRegister(writer);
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
writer.write(referenceString);
|
||||
break;
|
||||
case Format22cs:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
@ -176,7 +260,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeSecondRegister(writer);
|
||||
writer.write(", ");
|
||||
writeFieldOffset(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format22t:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
@ -185,7 +269,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeSecondRegister(writer);
|
||||
writer.write(", ");
|
||||
writeTargetLabel(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format22x:
|
||||
case Format32x:
|
||||
writeOpcode(writer);
|
||||
@ -193,7 +277,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeFirstRegister(writer);
|
||||
writer.write(", ");
|
||||
writeSecondRegister(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format23x:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
@ -202,52 +286,59 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeSecondRegister(writer);
|
||||
writer.write(", ");
|
||||
writeThirdRegister(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format35c:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
writer.write(referenceString);
|
||||
break;
|
||||
case Format35mi:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writeInlineIndex(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format35ms:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writeVtableIndex(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format3rc:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRangeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
writer.write(referenceString);
|
||||
break;
|
||||
case Format3rmi:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRangeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writeInlineIndex(writer);
|
||||
return true;
|
||||
break;
|
||||
case Format3rms:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRangeRegisters(writer);
|
||||
writer.write(", ");
|
||||
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 {
|
||||
@ -337,6 +428,18 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
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 {
|
||||
writer.write("field@0x");
|
||||
@ -352,20 +455,4 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write("vtable@");
|
||||
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);
|
||||
writer.indent(4);
|
||||
writer.write('\n');
|
||||
int key = firstKey;
|
||||
for (PackedSwitchTarget target: targets) {
|
||||
target.writeTargetTo(writer);
|
||||
writeResourceId(writer, key);
|
||||
writer.write('\n');
|
||||
key++;
|
||||
}
|
||||
writer.deindent(4);
|
||||
writer.write(".end packed-switch");
|
||||
|
@ -71,6 +71,7 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchPa
|
||||
IntegerRenderer.writeTo(writer, target.getKey());
|
||||
writer.write(" -> ");
|
||||
target.writeTargetTo(writer);
|
||||
writeResourceId(writer, target.getKey());
|
||||
writer.write('\n');
|
||||
}
|
||||
writer.deindent(4);
|
||||
|
@ -39,6 +39,7 @@ import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.analysis.AnalysisException;
|
||||
import org.jf.dexlib2.analysis.AnalyzedInstruction;
|
||||
import org.jf.dexlib2.analysis.MethodAnalyzer;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||
import org.jf.dexlib2.iface.*;
|
||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||
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.reference.MethodReference;
|
||||
import org.jf.dexlib2.util.InstructionOffsetMap;
|
||||
import org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset;
|
||||
import org.jf.dexlib2.util.ReferenceUtil;
|
||||
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||
import org.jf.dexlib2.util.TypeUtils;
|
||||
@ -92,15 +94,31 @@ public class MethodDefinition {
|
||||
|
||||
Opcode opcode = instruction.getOpcode();
|
||||
if (opcode == Opcode.PACKED_SWITCH) {
|
||||
boolean valid = true;
|
||||
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
|
||||
packedSwitchMap.append(targetOffset, codeOffset);
|
||||
try {
|
||||
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
|
||||
} catch (InvalidSwitchPayload ex) {
|
||||
valid = false;
|
||||
}
|
||||
if (valid) {
|
||||
packedSwitchMap.append(targetOffset, codeOffset);
|
||||
}
|
||||
} else if (opcode == Opcode.SPARSE_SWITCH) {
|
||||
boolean valid = true;
|
||||
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
|
||||
sparseSwitchMap.append(targetOffset, codeOffset);
|
||||
try {
|
||||
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) {
|
||||
@ -187,8 +205,13 @@ public class MethodDefinition {
|
||||
writer.write(".end method\n");
|
||||
}
|
||||
|
||||
private int findSwitchPayload(int targetOffset, Opcode type) {
|
||||
int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
|
||||
public int findSwitchPayload(int targetOffset, Opcode type) {
|
||||
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 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 {
|
||||
return targetOffset;
|
||||
}
|
||||
@ -337,10 +360,16 @@ public class MethodDefinition {
|
||||
Opcode opcode = instruction.getOpcode();
|
||||
|
||||
if (opcode.referenceType == ReferenceType.METHOD) {
|
||||
MethodReference methodReference =
|
||||
(MethodReference)((ReferenceInstruction)instruction).getReference();
|
||||
MethodReference methodReference = null;
|
||||
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 =
|
||||
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
|
||||
if (accessedMember != null) {
|
||||
@ -510,4 +539,17 @@ public class MethodDefinition {
|
||||
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;
|
||||
case ReferenceType.FIELD:
|
||||
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.util.ClassFileNameHandler;
|
||||
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.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
public class baksmali {
|
||||
|
||||
public static boolean disassembleDexFile(DexFile dexFile, final baksmaliOptions options) {
|
||||
@ -60,9 +68,50 @@ public class baksmali {
|
||||
Iterables.concat(options.bootClassPathEntries, extraClassPathEntries), dexFile,
|
||||
options.apiLevel);
|
||||
} 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);
|
||||
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.mkdirs()) {
|
||||
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;
|
||||
for (Future<Boolean> task: tasks) {
|
||||
while(true) {
|
||||
try {
|
||||
if (!task.get()) {
|
||||
errorOccurred = true;
|
||||
try {
|
||||
for (Future<Boolean> task: tasks) {
|
||||
while(true) {
|
||||
try {
|
||||
if (!task.get()) {
|
||||
errorOccurred = true;
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
continue;
|
||||
} catch (ExecutionException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
continue;
|
||||
} catch (ExecutionException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
return !errorOccurred;
|
||||
}
|
||||
|
||||
@ -168,7 +219,7 @@ public class baksmali {
|
||||
writer = new IndentingWriter(bufWriter);
|
||||
classDefinition.writeTo((IndentingWriter)writer);
|
||||
} 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();
|
||||
// noinspection ResultOfMethodCallIgnored
|
||||
smaliFile.delete();
|
||||
@ -180,7 +231,7 @@ public class baksmali {
|
||||
try {
|
||||
writer.close();
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,9 @@ import org.jf.dexlib2.analysis.InlineMethodResolver;
|
||||
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class baksmaliOptions {
|
||||
// register info values
|
||||
@ -58,12 +60,16 @@ public class baksmaliOptions {
|
||||
public List<String> bootClassPathEntries = 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 useLocalsDirective = false;
|
||||
public boolean useSequentialLabels = false;
|
||||
public boolean outputDebugInfo = true;
|
||||
public boolean addCodeOffsets = false;
|
||||
public boolean noAccessorComments = false;
|
||||
public boolean allowOdex = false;
|
||||
public boolean deodex = false;
|
||||
public boolean ignoreErrors = false;
|
||||
public boolean checkPackagePrivateAccess = false;
|
||||
@ -84,4 +90,11 @@ public class baksmaliOptions {
|
||||
}
|
||||
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':
|
||||
options.jobs = Integer.parseInt(commandLine.getOptionValue("j"));
|
||||
break;
|
||||
case 'i':
|
||||
String rif = commandLine.getOptionValue("i");
|
||||
options.setResourceIdFiles(rif);
|
||||
break;
|
||||
case 'N':
|
||||
disassemble = false;
|
||||
break;
|
||||
@ -215,9 +219,6 @@ public class main {
|
||||
case 'T':
|
||||
options.inlineResolver = new CustomInlineMethodResolver(options.classPath, new File(commandLine.getOptionValue("T")));
|
||||
break;
|
||||
case 'K':
|
||||
options.checkPackagePrivateAccess = true;
|
||||
break;
|
||||
default:
|
||||
assert false;
|
||||
}
|
||||
@ -235,6 +236,10 @@ public class main {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.apiLevel >= 17) {
|
||||
options.checkPackagePrivateAccess = true;
|
||||
}
|
||||
|
||||
String inputDexFileName = remainingArgs[0];
|
||||
|
||||
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("won't be able to re-assemble the results unless you deodex it with the -x");
|
||||
System.err.println("option");
|
||||
options.allowOdex = true;
|
||||
}
|
||||
} else {
|
||||
options.deodex = false;
|
||||
@ -407,6 +413,14 @@ public class main {
|
||||
.withArgName("NUM_THREADS")
|
||||
.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")
|
||||
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
|
||||
" (<dexfile>.dump by default), along with the normal disassembly")
|
||||
@ -430,12 +444,6 @@ public class main {
|
||||
.withArgName("FILE")
|
||||
.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(helpOption);
|
||||
basicOptions.addOption(outputDirOption);
|
||||
@ -451,12 +459,12 @@ public class main {
|
||||
basicOptions.addOption(noAccessorCommentsOption);
|
||||
basicOptions.addOption(apiLevelOption);
|
||||
basicOptions.addOption(jobsOption);
|
||||
basicOptions.addOption(resourceIdFilesOption);
|
||||
|
||||
debugOptions.addOption(dumpOption);
|
||||
debugOptions.addOption(ignoreErrorsOption);
|
||||
debugOptions.addOption(noDisassemblyOption);
|
||||
debugOptions.addOption(inlineTableOption);
|
||||
debugOptions.addOption(checkPackagePrivateAccess);
|
||||
|
||||
for (Object option: basicOptions.getOptions()) {
|
||||
options.addOption((Option)option);
|
||||
|
@ -104,8 +104,9 @@ public class AnalysisTest {
|
||||
className.substring(1, className.length() - 1));
|
||||
String smaliContents = readResource(smaliPath);
|
||||
|
||||
Assert.assertEquals(smaliContents.replace("\r", "").replace("\n", System.lineSeparator()),
|
||||
stringWriter.toString().replace("\r", "").replace("\n", System.lineSeparator()));
|
||||
String newline = System.getProperty("line.separator");
|
||||
Assert.assertEquals(smaliContents.replace("\r", "").replace("\n", newline),
|
||||
stringWriter.toString().replace("\r", "").replace("\n", newline));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,10 @@ public class Opcodes {
|
||||
case 0x300:
|
||||
return Opcode.ARRAY_PAYLOAD;
|
||||
default:
|
||||
return opcodesByValue[opcodeValue];
|
||||
if (opcodeValue >= 0 && opcodeValue < opcodesByValue.length) {
|
||||
return opcodesByValue[opcodeValue];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,9 @@
|
||||
|
||||
package org.jf.dexlib2;
|
||||
|
||||
import org.jf.dexlib2.iface.reference.*;
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
|
||||
public final class ReferenceType {
|
||||
public static final int STRING = 0;
|
||||
public static final int TYPE = 1;
|
||||
@ -49,7 +52,50 @@ public final class ReferenceType {
|
||||
case METHOD:
|
||||
return "method";
|
||||
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 org.jf.util.ExceptionWithContext;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class VerificationError {
|
||||
@ -61,6 +62,7 @@ public class VerificationError {
|
||||
verificationErrorNames.put("instantiation-error", INSTANTIATION_ERROR);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getVerificationErrorName(int verificationError) {
|
||||
switch (verificationError) {
|
||||
case GENERIC:
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
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.iface.instruction.Instruction;
|
||||
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.Nullable;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class MethodLocation {
|
||||
@Nullable BuilderInstruction instruction;
|
||||
int codeAddress;
|
||||
int index;
|
||||
|
||||
private List<Label> labels = Lists.newArrayList();
|
||||
List<BuilderDebugItem> debugItems = Lists.newArrayList();
|
||||
// We end up creating and keeping around a *lot* of MethodLocation objects
|
||||
// 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) {
|
||||
this.instruction = instruction;
|
||||
@ -71,19 +74,51 @@ public class MethodLocation {
|
||||
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) {
|
||||
for (Label label: labels) {
|
||||
label.location = other;
|
||||
other.labels.add(label);
|
||||
if (this.labels != null || other.labels != null) {
|
||||
List<Label> otherLabels = other.getLabels(true);
|
||||
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
|
||||
// the list.
|
||||
for (BuilderDebugItem debugItem: debugItems) {
|
||||
debugItem.location = other;
|
||||
if (this.debugItems != null || other.labels != null) {
|
||||
// We need to keep the debug items in the same order. We add the other debug items to this list, then reassign
|
||||
// the list.
|
||||
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
|
||||
@ -91,7 +126,7 @@ public class MethodLocation {
|
||||
return new AbstractSet<Label>() {
|
||||
@Nonnull
|
||||
@Override public Iterator<Label> iterator() {
|
||||
final Iterator<Label> it = labels.iterator();
|
||||
final Iterator<Label> it = getLabels(false).iterator();
|
||||
|
||||
return new Iterator<Label>() {
|
||||
private @Nullable Label currentLabel = null;
|
||||
@ -115,7 +150,7 @@ public class MethodLocation {
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return labels.size();
|
||||
return getLabels(false).size();
|
||||
}
|
||||
|
||||
@Override public boolean add(@Nonnull Label label) {
|
||||
@ -124,7 +159,7 @@ public class MethodLocation {
|
||||
"it from its current location first.");
|
||||
}
|
||||
label.location = MethodLocation.this;
|
||||
labels.add(label);
|
||||
getLabels(true).add(label);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -133,7 +168,7 @@ public class MethodLocation {
|
||||
@Nonnull
|
||||
public Label addNewLabel() {
|
||||
Label label = new Label(this);
|
||||
labels.add(label);
|
||||
getLabels(true).add(label);
|
||||
return label;
|
||||
}
|
||||
|
||||
@ -142,7 +177,7 @@ public class MethodLocation {
|
||||
return new AbstractSet<BuilderDebugItem>() {
|
||||
@Nonnull
|
||||
@Override public Iterator<BuilderDebugItem> iterator() {
|
||||
final Iterator<BuilderDebugItem> it = debugItems.iterator();
|
||||
final Iterator<BuilderDebugItem> it = getDebugItems(false).iterator();
|
||||
|
||||
return new Iterator<BuilderDebugItem>() {
|
||||
private @Nullable BuilderDebugItem currentDebugItem = null;
|
||||
@ -166,7 +201,7 @@ public class MethodLocation {
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return labels.size();
|
||||
return getDebugItems(false).size();
|
||||
}
|
||||
|
||||
@Override public boolean add(@Nonnull BuilderDebugItem debugItem) {
|
||||
@ -175,7 +210,7 @@ public class MethodLocation {
|
||||
"method. You must remove it from its current location first.");
|
||||
}
|
||||
debugItem.location = MethodLocation.this;
|
||||
debugItems.add(debugItem);
|
||||
getDebugItems(true).add(debugItem);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -435,6 +435,14 @@ public class MutableMethodImplementation implements MethodImplementation {
|
||||
}
|
||||
case SPARSE_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: {
|
||||
if ((location.codeAddress & 0x01) != 0) {
|
||||
int previousIndex = location.index - 1;
|
||||
|
@ -33,6 +33,7 @@ package org.jf.dexlib2.builder.instruction;
|
||||
|
||||
import org.jf.dexlib2.Format;
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.builder.BuilderInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
@ -56,6 +57,7 @@ public class BuilderInstruction20bc extends BuilderInstruction implements Instru
|
||||
|
||||
@Override public int getVerificationError() { return verificationError; }
|
||||
@Nonnull @Override public Reference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return ReferenceType.getReferenceType(reference); }
|
||||
|
||||
@Override public Format getFormat() { return FORMAT; }
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ public class BuilderInstruction21c extends BuilderInstruction implements Instruc
|
||||
|
||||
@Override public int getRegisterA() { return registerA; }
|
||||
@Nonnull @Override public Reference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@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 getRegisterB() { return registerB; }
|
||||
@Nonnull @Override public Reference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@Override public Format getFormat() { return FORMAT; }
|
||||
}
|
@ -56,6 +56,7 @@ public class BuilderInstruction31c extends BuilderInstruction implements Instruc
|
||||
|
||||
@Override public int getRegisterA() { return registerA; }
|
||||
@Nonnull @Override public Reference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@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 getRegisterG() { return registerG; }
|
||||
@Nonnull @Override public Reference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@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 getRegisterCount() { return registerCount; }
|
||||
@Nonnull @Override public Reference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@Override public Format getFormat() { return FORMAT; }
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
|
||||
|
||||
public int getMethodIdItemOffset(int methodIndex) {
|
||||
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;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
package org.jf.dexlib2.dexbacked.instruction;
|
||||
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.dexbacked.reference.DexBackedReference;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||
@ -51,7 +52,13 @@ public class DexBackedInstruction20bc extends DexBackedInstruction implements In
|
||||
@Nonnull
|
||||
@Override
|
||||
public Reference getReference() {
|
||||
int refType = (dexFile.readUbyte(instructionStart + 1) >>> 6) + 1;
|
||||
return DexBackedReference.makeReference(dexFile, refType, dexFile.readUshort(instructionStart + 2));
|
||||
int referenceType = getReferenceType();
|
||||
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() {
|
||||
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() {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
@Override public short getOriginalOpcode() {
|
||||
return (short)dexFile.readUbyte(instructionStart);
|
||||
@Override public int getOriginalOpcode() {
|
||||
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.util.AnnotatedBytes;
|
||||
import org.jf.dexlib2.util.ReferenceUtil;
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
import org.jf.util.NumberUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -84,121 +85,160 @@ public class CodeItem {
|
||||
|
||||
@Override
|
||||
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();
|
||||
out.annotate(2, "registers_size = %d", registers);
|
||||
int registers = reader.readUshort();
|
||||
out.annotate(2, "registers_size = %d", registers);
|
||||
|
||||
int inSize = reader.readUshort();
|
||||
out.annotate(2, "ins_size = %d", inSize);
|
||||
int inSize = reader.readUshort();
|
||||
out.annotate(2, "ins_size = %d", inSize);
|
||||
|
||||
int outSize = reader.readUshort();
|
||||
out.annotate(2, "outs_size = %d", outSize);
|
||||
int outSize = reader.readUshort();
|
||||
out.annotate(2, "outs_size = %d", outSize);
|
||||
|
||||
int triesCount = reader.readUshort();
|
||||
out.annotate(2, "tries_size = %d", triesCount);
|
||||
int triesCount = reader.readUshort();
|
||||
out.annotate(2, "tries_size = %d", triesCount);
|
||||
|
||||
int debugInfoOffset = reader.readSmallUint();
|
||||
out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset);
|
||||
int debugInfoOffset = reader.readSmallUint();
|
||||
out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset);
|
||||
|
||||
if (debugInfoOffset != 0) {
|
||||
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;
|
||||
if (debugInfoOffset != 0) {
|
||||
addDebugInfoIdentity(debugInfoOffset, itemIdentity);
|
||||
}
|
||||
|
||||
assert reader.getOffset() == out.getCursor();
|
||||
}
|
||||
out.deindent();
|
||||
int instructionSize = reader.readSmallUint();
|
||||
out.annotate(4, "insns_size = 0x%x", instructionSize);
|
||||
|
||||
if (triesCount > 0) {
|
||||
if ((reader.getOffset() % 4) != 0) {
|
||||
reader.readUshort();
|
||||
out.annotate(2, "padding");
|
||||
}
|
||||
|
||||
out.annotate(0, "try_items:");
|
||||
out.annotate(0, "instructions:");
|
||||
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.annotate(2, "insn_count = 0x%x", instructionCount);
|
||||
out.setLimit(out.getCursor(), out.getCursor() + instructionSize * 2);
|
||||
|
||||
int handlerOffset = reader.readUshort();
|
||||
out.annotate(2, "handler_off = 0x%x", handlerOffset);
|
||||
int end = reader.getOffset() + instructionSize*2;
|
||||
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();
|
||||
|
||||
int handlerListCount = reader.readSmallUleb128();
|
||||
out.annotate(0, "encoded_catch_handler_list:");
|
||||
out.annotateTo(reader.getOffset(), "size = %d", handlerListCount);
|
||||
out.indent();
|
||||
for (int i=0; i<handlerListCount; i++) {
|
||||
out.annotate(0, "encoded_catch_handler[%d]", i);
|
||||
if (triesCount > 0) {
|
||||
if ((reader.getOffset() % 4) != 0) {
|
||||
reader.readUshort();
|
||||
out.annotate(2, "padding");
|
||||
}
|
||||
|
||||
out.annotate(0, "try_items:");
|
||||
out.indent();
|
||||
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();
|
||||
for (int j=0; j<handlerCount; j++) {
|
||||
out.annotate(0, "encoded_type_addr_pair[%d]", i);
|
||||
try {
|
||||
for (int i=0; i<triesCount; i++) {
|
||||
out.annotate(0, "try_item[%d]:", i);
|
||||
out.indent();
|
||||
int typeIndex = reader.readSmallUleb128();
|
||||
out.annotateTo(reader.getOffset(), TypeIdItem.getReferenceAnnotation(dexFile, typeIndex));
|
||||
try {
|
||||
int startAddr = reader.readSmallUint();
|
||||
out.annotate(4, "start_addr = 0x%x", startAddr);
|
||||
|
||||
int handlerAddress = reader.readSmallUleb128();
|
||||
out.annotateTo(reader.getOffset(), "addr = 0x%x", handlerAddress);
|
||||
out.deindent();
|
||||
int instructionCount = reader.readUshort();
|
||||
out.annotate(2, "insn_count = 0x%x", instructionCount);
|
||||
|
||||
int handlerOffset = reader.readUshort();
|
||||
out.annotate(2, "handler_off = 0x%x", handlerOffset);
|
||||
} finally {
|
||||
out.deindent();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
out.deindent();
|
||||
}
|
||||
if (hasCatchAll) {
|
||||
int catchAllAddress = reader.readSmallUleb128();
|
||||
out.annotateTo(reader.getOffset(), "catch_all_addr = 0x%x", catchAllAddress);
|
||||
|
||||
int handlerListCount = reader.readSmallUleb128();
|
||||
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) {
|
||||
args.add(VerificationError.getVerificationErrorName(
|
||||
((VerificationErrorInstruction)instruction).getVerificationError()));
|
||||
String verificationError = VerificationError.getVerificationErrorName(
|
||||
((VerificationErrorInstruction) instruction).getVerificationError());
|
||||
if (verificationError != null) {
|
||||
args.add(verificationError);
|
||||
} else {
|
||||
args.add("invalid verification error type");
|
||||
}
|
||||
}
|
||||
|
||||
if (instruction instanceof ReferenceInstruction) {
|
||||
args.add(ReferenceUtil.getReferenceString(
|
||||
((ReferenceInstruction)instruction).getReference()));
|
||||
args.add(ReferenceUtil.getReferenceString(((ReferenceInstruction)instruction).getReference()));
|
||||
} else if (instruction instanceof OffsetInstruction) {
|
||||
int offset = ((OffsetInstruction)instruction).getCodeOffset();
|
||||
String sign = offset>=0?"+":"-";
|
||||
|
@ -37,4 +37,5 @@ import javax.annotation.Nonnull;
|
||||
|
||||
public interface ReferenceInstruction extends Instruction {
|
||||
@Nonnull Reference getReference();
|
||||
int getReferenceType();
|
||||
}
|
||||
|
@ -32,5 +32,5 @@
|
||||
package org.jf.dexlib2.iface.instruction.formats;
|
||||
|
||||
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.Opcode;
|
||||
import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableReference;
|
||||
@ -67,6 +68,7 @@ public class ImmutableInstruction20bc extends ImmutableInstruction implements In
|
||||
|
||||
@Override public int getVerificationError() { return verificationError; }
|
||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return ReferenceType.getReferenceType(reference); }
|
||||
|
||||
@Override public Format getFormat() { return FORMAT; }
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ public class ImmutableInstruction21c extends ImmutableInstruction implements Ins
|
||||
|
||||
@Override public int getRegisterA() { return registerA; }
|
||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@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 getRegisterB() { return registerB; }
|
||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@Override public Format getFormat() { return FORMAT; }
|
||||
}
|
@ -67,6 +67,7 @@ public class ImmutableInstruction31c extends ImmutableInstruction implements Ins
|
||||
|
||||
@Override public int getRegisterA() { return registerA; }
|
||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@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 getRegisterG() { return registerG; }
|
||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@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 getRegisterCount() { return registerCount; }
|
||||
@Nonnull @Override public ImmutableReference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
|
||||
@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 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);
|
||||
this.originalOpcode = originalOpcode;
|
||||
}
|
||||
@ -53,5 +53,5 @@ public class ImmutableUnknownInstruction extends ImmutableInstruction implements
|
||||
}
|
||||
|
||||
@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.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
import org.jf.util.Hex;
|
||||
import org.jf.util.TwoColumnOutput;
|
||||
|
||||
@ -78,6 +80,9 @@ public class AnnotatedBytes {
|
||||
*/
|
||||
private int hexCols = 8;
|
||||
|
||||
private int startLimit = -1;
|
||||
private int endLimit = -1;
|
||||
|
||||
public AnnotatedBytes(int width) {
|
||||
this.outputWidth = width;
|
||||
}
|
||||
@ -115,7 +120,16 @@ public class AnnotatedBytes {
|
||||
* @param formatArgs format arguments to pass to String.format
|
||||
*/
|
||||
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;
|
||||
|
||||
AnnotationEndpoint endPoint = null;
|
||||
@ -129,19 +143,20 @@ public class AnnotatedBytes {
|
||||
AnnotationEndpoint previousAnnotations = previousEntry.getValue();
|
||||
AnnotationItem previousRangeAnnotation = previousAnnotations.rangeAnnotation;
|
||||
if (previousRangeAnnotation != null) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Cannot add annotation %s, due to existing annotation %s",
|
||||
throw new ExceptionWithContext(
|
||||
"Cannot add annotation %s, due to existing annotation %s",
|
||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||
formatAnnotation(previousEntry.getKey(), previousRangeAnnotation.annotation)));
|
||||
formatAnnotation(previousEntry.getKey(),
|
||||
previousRangeAnnotation.annotation));
|
||||
}
|
||||
}
|
||||
} else if (length > 0) {
|
||||
AnnotationItem existingRangeAnnotation = startPoint.rangeAnnotation;
|
||||
if (existingRangeAnnotation != null) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Cannot add annotation %s, due to existing annotation %s",
|
||||
throw new ExceptionWithContext(
|
||||
"Cannot add annotation %s, due to existing annotation %s",
|
||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||
formatAnnotation(cursor, existingRangeAnnotation.annotation)));
|
||||
formatAnnotation(cursor, existingRangeAnnotation.annotation));
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,23 +171,23 @@ public class AnnotatedBytes {
|
||||
AnnotationEndpoint nextEndpoint = nextEntry.getValue();
|
||||
AnnotationItem nextRangeAnnotation = nextEndpoint.rangeAnnotation;
|
||||
if (nextRangeAnnotation != null) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Cannot add annotation %s, due to existing annotation %s",
|
||||
throw new ExceptionWithContext(
|
||||
"Cannot add annotation %s, due to existing annotation %s",
|
||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||
formatAnnotation(nextKey, nextRangeAnnotation.annotation)));
|
||||
formatAnnotation(nextKey, nextRangeAnnotation.annotation));
|
||||
}
|
||||
if (nextEndpoint.pointAnnotations.size() > 0) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Cannot add annotation %s, due to existing annotation %s",
|
||||
throw new ExceptionWithContext(
|
||||
"Cannot add annotation %s, due to existing annotation %s",
|
||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||
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.
|
||||
throw new IllegalStateException(
|
||||
String.format("Cannot add annotation %s, due to existing annotation endpoint at %d",
|
||||
throw new ExceptionWithContext(
|
||||
"Cannot add annotation %s, due to existing annotation endpoint at %d",
|
||||
formatAnnotation(cursor, cursor + length, formattedMsg),
|
||||
nextKey));
|
||||
nextKey);
|
||||
}
|
||||
|
||||
if (nextKey == exclusiveEndOffset) {
|
||||
@ -312,4 +327,14 @@ public class AnnotatedBytes {
|
||||
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);
|
||||
if (index < 0) {
|
||||
if (exact) {
|
||||
throw new ExceptionWithContext("No instruction at offset %d", codeOffset);
|
||||
throw new InvalidInstructionOffset(codeOffset);
|
||||
} else {
|
||||
// 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
|
||||
@ -72,8 +72,34 @@ public class InstructionOffsetMap {
|
||||
|
||||
public int getInstructionCodeOffset(int index) {
|
||||
if (index < 0 || index >= instructionCodeOffsets.length) {
|
||||
throw new ExceptionWithContext("Index out of bounds: %d", index);
|
||||
throw new InvalidInstructionIndex(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 org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.Opcodes;
|
||||
import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.builder.MethodImplementationBuilder;
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction10x;
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c;
|
||||
@ -136,6 +137,8 @@ public class JumboStringConversionTest {
|
||||
return ref;
|
||||
}
|
||||
|
||||
@Override public int getReferenceType() { return ReferenceType.STRING; }
|
||||
|
||||
@Override public Opcode getOpcode() {
|
||||
return Opcode.CONST_STRING;
|
||||
}
|
||||
|
@ -922,8 +922,8 @@ insn_format21c_string
|
||||
|
||||
insn_format21c_type
|
||||
: //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
|
||||
INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor
|
||||
-> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor);
|
||||
INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA nonvoid_type_descriptor
|
||||
-> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER nonvoid_type_descriptor);
|
||||
|
||||
insn_format21ih
|
||||
: //e.g. const/high16 v1, 1234
|
||||
|
@ -840,13 +840,13 @@ insn_format21c_string
|
||||
|
||||
insn_format21c_type
|
||||
: //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);
|
||||
short regA = parseRegister_byte($REGISTER.text);
|
||||
|
||||
$method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
|
||||
dexBuilder.internTypeReference($reference_type_descriptor.type)));
|
||||
dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
|
||||
};
|
||||
|
||||
insn_format21ih
|
||||
|
@ -142,7 +142,7 @@ public class ClassFileNameHandler {
|
||||
writer.close();
|
||||
f.delete(); //doesn't throw IOException
|
||||
} catch (IOException ex) {
|
||||
//if an exception occured, it's likely that we're on a windows system.
|
||||
//if an exception occurred, it's likely that we're on a windows system.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user