mirror of
https://github.com/revanced/Apktool.git
synced 2025-06-12 21:27:36 +02:00
update to smali 2.0.3
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user