mirror of
https://github.com/revanced/Apktool.git
synced 2025-05-01 06:34:25 +02:00
Update to smali 2b5
This commit is contained in:
parent
115db91fab
commit
007a6d45a2
1
brut.apktool.smali/baksmali/.gitignore
vendored
1
brut.apktool.smali/baksmali/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/target
|
|
@ -29,11 +29,19 @@
|
|||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
proguard
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':brut.apktool.smali:util')
|
compile project(':util')
|
||||||
compile project(':brut.apktool.smali:dexlib')
|
compile project(':dexlib2')
|
||||||
compile 'commons-cli:commons-cli:1.2'
|
compile depends.commons_cli
|
||||||
compile 'com.google.code.findbugs:jsr305:1.3.9'
|
compile depends.guava
|
||||||
|
|
||||||
|
testCompile depends.junit
|
||||||
|
|
||||||
|
proguard depends.proguard
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources.inputs.property('version', version)
|
processResources.inputs.property('version', version)
|
||||||
@ -46,4 +54,28 @@ jar {
|
|||||||
manifest {
|
manifest {
|
||||||
attributes("Main-Class": "org.jf.baksmali.main")
|
attributes("Main-Class": "org.jf.baksmali.main")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
doLast {
|
||||||
|
ant.symlink(link: file("${destinationDir}/baksmali.jar"), resource: archivePath, overwrite: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task proguard(type: JavaExec, dependsOn: jar) {
|
||||||
|
def outFile = jar.destinationDir.getPath() + '/' + jar.baseName + '-' + jar.version + '-small' + '.' + jar.extension
|
||||||
|
inputs.file jar.archivePath
|
||||||
|
outputs.file outFile
|
||||||
|
|
||||||
|
classpath = configurations.proguard
|
||||||
|
main = 'proguard.ProGuard'
|
||||||
|
args '-injars ' + jar.archivePath
|
||||||
|
args '-outjars ' + outFile
|
||||||
|
args '-libraryjars ' + System.properties['java.home'] + '/lib/rt.jar'
|
||||||
|
args '-dontobfuscate'
|
||||||
|
args '-dontoptimize'
|
||||||
|
args '-keep public class org.jf.baksmali.main { public static void main(java.lang.String[]); }'
|
||||||
|
args '-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }'
|
||||||
|
args '-dontwarn com.google.common.**'
|
||||||
|
args '-dontnote com.google.common.**'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.getByPath(':release').dependsOn(proguard)
|
||||||
|
@ -29,35 +29,36 @@
|
|||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.EncodedValue.AnnotationEncodedValueAdaptor;
|
import org.jf.baksmali.Adaptors.EncodedValue.AnnotationEncodedValueAdaptor;
|
||||||
|
import org.jf.dexlib2.AnnotationVisibility;
|
||||||
|
import org.jf.dexlib2.iface.Annotation;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.AnnotationItem;
|
|
||||||
import org.jf.dexlib.AnnotationSetItem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
public class AnnotationFormatter {
|
public class AnnotationFormatter {
|
||||||
|
|
||||||
public static void writeTo(IndentingWriter writer, AnnotationSetItem annotationSet) throws IOException {
|
public static void writeTo(IndentingWriter writer,
|
||||||
|
Collection<? extends Annotation> annotations) throws IOException {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
|
for (Annotation annotation: annotations) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
writeTo(writer, annotationItem);
|
writeTo(writer, annotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeTo(IndentingWriter writer, AnnotationItem annotationItem) throws IOException {
|
public static void writeTo(IndentingWriter writer, Annotation annotation) throws IOException {
|
||||||
writer.write(".annotation ");
|
writer.write(".annotation ");
|
||||||
writer.write(annotationItem.getVisibility().visibility);
|
writer.write(AnnotationVisibility.getVisibility(annotation.getVisibility()));
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
ReferenceFormatter.writeTypeReference(writer, annotationItem.getEncodedAnnotation().annotationType);
|
writer.write(annotation.getType());
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
|
|
||||||
AnnotationEncodedValueAdaptor.writeElementsTo(writer, annotationItem.getEncodedAnnotation());
|
AnnotationEncodedValueAdaptor.writeElementsTo(writer, annotation.getElements());
|
||||||
|
|
||||||
writer.write(".end annotation\n");
|
writer.write(".end annotation\n");
|
||||||
}
|
}
|
||||||
|
@ -28,33 +28,36 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.TypeIdItem;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class CatchMethodItem extends MethodItem {
|
public class CatchMethodItem extends MethodItem {
|
||||||
private final TypeIdItem exceptionType;
|
private final String exceptionType;
|
||||||
|
|
||||||
private final LabelMethodItem tryStartLabel;
|
private final LabelMethodItem tryStartLabel;
|
||||||
private final LabelMethodItem tryEndLabel;
|
private final LabelMethodItem tryEndLabel;
|
||||||
private final LabelMethodItem handlerLabel;
|
private final LabelMethodItem handlerLabel;
|
||||||
|
|
||||||
public CatchMethodItem(MethodDefinition.LabelCache labelCache, int codeAddress, TypeIdItem exceptionType,
|
public CatchMethodItem(@Nonnull baksmaliOptions options, @Nonnull MethodDefinition.LabelCache labelCache,
|
||||||
int startAddress, int endAddress, int handlerAddress) {
|
int codeAddress, @Nullable String exceptionType, int startAddress, int endAddress,
|
||||||
|
int handlerAddress) {
|
||||||
super(codeAddress);
|
super(codeAddress);
|
||||||
this.exceptionType = exceptionType;
|
this.exceptionType = exceptionType;
|
||||||
|
|
||||||
tryStartLabel = labelCache.internLabel(new LabelMethodItem(startAddress, "try_start_"));
|
tryStartLabel = labelCache.internLabel(new LabelMethodItem(options, startAddress, "try_start_"));
|
||||||
|
|
||||||
//use the address from the last covered instruction, but make the label
|
//use the address from the last covered instruction, but make the label
|
||||||
//name refer to the address of the next instruction
|
//name refer to the address of the next instruction
|
||||||
tryEndLabel = labelCache.internLabel(new EndTryLabelMethodItem(codeAddress, endAddress));
|
tryEndLabel = labelCache.internLabel(new EndTryLabelMethodItem(options, codeAddress, endAddress));
|
||||||
|
|
||||||
if (exceptionType == null) {
|
if (exceptionType == null) {
|
||||||
handlerLabel = labelCache.internLabel(new LabelMethodItem(handlerAddress, "catchall_"));
|
handlerLabel = labelCache.internLabel(new LabelMethodItem(options, handlerAddress, "catchall_"));
|
||||||
} else {
|
} else {
|
||||||
handlerLabel = labelCache.internLabel(new LabelMethodItem(handlerAddress, "catch_"));
|
handlerLabel = labelCache.internLabel(new LabelMethodItem(options, handlerAddress, "catch_"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +84,7 @@ public class CatchMethodItem extends MethodItem {
|
|||||||
writer.write(".catchall");
|
writer.write(".catchall");
|
||||||
} else {
|
} else {
|
||||||
writer.write(".catch ");
|
writer.write(".catch ");
|
||||||
ReferenceFormatter.writeTypeReference(writer, exceptionType);
|
writer.write(exceptionType);
|
||||||
}
|
}
|
||||||
writer.write(" {");
|
writer.write(" {");
|
||||||
tryStartLabel.writeTo(writer);
|
tryStartLabel.writeTo(writer);
|
||||||
|
@ -28,81 +28,69 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
import org.jf.dexlib.Util.Utf8Utils;
|
import com.google.common.collect.Lists;
|
||||||
import org.jf.util.CommentingIndentingWriter;
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
|
import org.jf.dexlib2.AccessFlags;
|
||||||
|
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
||||||
|
import org.jf.dexlib2.iface.*;
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
||||||
|
import org.jf.dexlib2.iface.reference.FieldReference;
|
||||||
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.*;
|
import org.jf.util.StringUtils;
|
||||||
import org.jf.dexlib.Code.Analysis.ValidationException;
|
|
||||||
import org.jf.dexlib.Code.Format.Instruction21c;
|
|
||||||
import org.jf.dexlib.Code.Format.Instruction41c;
|
|
||||||
import org.jf.dexlib.Code.Instruction;
|
|
||||||
import org.jf.dexlib.EncodedValue.EncodedValue;
|
|
||||||
import org.jf.dexlib.Util.AccessFlags;
|
|
||||||
import org.jf.dexlib.Util.SparseArray;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
|
|
||||||
public class ClassDefinition {
|
public class ClassDefinition {
|
||||||
private ClassDefItem classDefItem;
|
@Nonnull public final baksmaliOptions options;
|
||||||
@Nullable
|
@Nonnull public final ClassDef classDef;
|
||||||
private ClassDataItem classDataItem;
|
@Nonnull private final HashSet<String> fieldsSetInStaticConstructor;
|
||||||
|
|
||||||
private SparseArray<FieldIdItem> fieldsSetInStaticConstructor;
|
|
||||||
|
|
||||||
protected boolean validationErrors;
|
protected boolean validationErrors;
|
||||||
|
|
||||||
public ClassDefinition(ClassDefItem classDefItem) {
|
public ClassDefinition(@Nonnull baksmaliOptions options, @Nonnull ClassDef classDef) {
|
||||||
this.classDefItem = classDefItem;
|
this.options = options;
|
||||||
this.classDataItem = classDefItem.getClassData();
|
this.classDef = classDef;
|
||||||
findFieldsSetInStaticConstructor();
|
fieldsSetInStaticConstructor = findFieldsSetInStaticConstructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hadValidationErrors() {
|
public boolean hadValidationErrors() {
|
||||||
return validationErrors;
|
return validationErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findFieldsSetInStaticConstructor() {
|
@Nonnull
|
||||||
fieldsSetInStaticConstructor = new SparseArray<FieldIdItem>();
|
private HashSet<String> findFieldsSetInStaticConstructor() {
|
||||||
|
HashSet<String> fieldsSetInStaticConstructor = new HashSet<String>();
|
||||||
|
|
||||||
if (classDataItem == null) {
|
for (Method method: classDef.getDirectMethods()) {
|
||||||
return;
|
if (method.getName().equals("<clinit>")) {
|
||||||
}
|
MethodImplementation impl = method.getImplementation();
|
||||||
|
if (impl != null) {
|
||||||
for (ClassDataItem.EncodedMethod directMethod: classDataItem.getDirectMethods()) {
|
for (Instruction instruction: impl.getInstructions()) {
|
||||||
if (directMethod.method.getMethodName().getStringValue().equals("<clinit>") &&
|
switch (instruction.getOpcode()) {
|
||||||
directMethod.codeItem != null) {
|
case SPUT:
|
||||||
for (Instruction instruction: directMethod.codeItem.getInstructions()) {
|
case SPUT_BOOLEAN:
|
||||||
switch (instruction.opcode) {
|
case SPUT_BYTE:
|
||||||
case SPUT:
|
case SPUT_CHAR:
|
||||||
case SPUT_BOOLEAN:
|
case SPUT_OBJECT:
|
||||||
case SPUT_BYTE:
|
case SPUT_SHORT:
|
||||||
case SPUT_CHAR:
|
case SPUT_WIDE: {
|
||||||
case SPUT_OBJECT:
|
Instruction21c ins = (Instruction21c)instruction;
|
||||||
case SPUT_SHORT:
|
FieldReference fieldRef = (FieldReference)ins.getReference();
|
||||||
case SPUT_WIDE: {
|
if (fieldRef.getDefiningClass().equals((classDef.getType()))) {
|
||||||
Instruction21c ins = (Instruction21c)instruction;
|
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
|
||||||
FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem();
|
}
|
||||||
fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
case SPUT_JUMBO:
|
|
||||||
case SPUT_BOOLEAN_JUMBO:
|
|
||||||
case SPUT_BYTE_JUMBO:
|
|
||||||
case SPUT_CHAR_JUMBO:
|
|
||||||
case SPUT_OBJECT_JUMBO:
|
|
||||||
case SPUT_SHORT_JUMBO:
|
|
||||||
case SPUT_WIDE_JUMBO: {
|
|
||||||
Instruction41c ins = (Instruction41c)instruction;
|
|
||||||
FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem();
|
|
||||||
fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return fieldsSetInStaticConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(IndentingWriter writer) throws IOException {
|
public void writeTo(IndentingWriter writer) throws IOException {
|
||||||
@ -111,238 +99,219 @@ public class ClassDefinition {
|
|||||||
writeSourceFile(writer);
|
writeSourceFile(writer);
|
||||||
writeInterfaces(writer);
|
writeInterfaces(writer);
|
||||||
writeAnnotations(writer);
|
writeAnnotations(writer);
|
||||||
writeStaticFields(writer);
|
Set<String> staticFields = writeStaticFields(writer);
|
||||||
writeInstanceFields(writer);
|
writeInstanceFields(writer, staticFields);
|
||||||
writeDirectMethods(writer);
|
Set<String> directMethods = writeDirectMethods(writer);
|
||||||
writeVirtualMethods(writer);
|
writeVirtualMethods(writer, directMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeClass(IndentingWriter writer) throws IOException {
|
private void writeClass(IndentingWriter writer) throws IOException {
|
||||||
writer.write(".class ");
|
writer.write(".class ");
|
||||||
writeAccessFlags(writer);
|
writeAccessFlags(writer);
|
||||||
writer.write(classDefItem.getClassType().getTypeDescriptor());
|
writer.write(classDef.getType());
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAccessFlags(IndentingWriter writer) throws IOException {
|
private void writeAccessFlags(IndentingWriter writer) throws IOException {
|
||||||
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) {
|
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDef.getAccessFlags())) {
|
||||||
writer.write(accessFlag.toString());
|
writer.write(accessFlag.toString());
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeSuper(IndentingWriter writer) throws IOException {
|
private void writeSuper(IndentingWriter writer) throws IOException {
|
||||||
TypeIdItem superClass = classDefItem.getSuperclass();
|
String superClass = classDef.getSuperclass();
|
||||||
if (superClass != null) {
|
if (superClass != null) {
|
||||||
writer.write(".super ");
|
writer.write(".super ");
|
||||||
writer.write(superClass.getTypeDescriptor());
|
writer.write(superClass);
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeSourceFile(IndentingWriter writer) throws IOException {
|
private void writeSourceFile(IndentingWriter writer) throws IOException {
|
||||||
StringIdItem sourceFile = classDefItem.getSourceFile();
|
String sourceFile = classDef.getSourceFile();
|
||||||
if (sourceFile != null) {
|
if (sourceFile != null) {
|
||||||
writer.write(".source \"");
|
writer.write(".source \"");
|
||||||
Utf8Utils.writeEscapedString(writer, sourceFile.getStringValue());
|
StringUtils.writeEscapedString(writer, sourceFile);
|
||||||
writer.write("\"\n");
|
writer.write("\"\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeInterfaces(IndentingWriter writer) throws IOException {
|
private void writeInterfaces(IndentingWriter writer) throws IOException {
|
||||||
TypeListItem interfaceList = classDefItem.getInterfaces();
|
List<String> interfaces = Lists.newArrayList(classDef.getInterfaces());
|
||||||
if (interfaceList == null) {
|
Collections.sort(interfaces);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TypeIdItem> interfaces = interfaceList.getTypes();
|
if (interfaces.size() != 0) {
|
||||||
if (interfaces == null || interfaces.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.write('\n');
|
|
||||||
writer.write("# interfaces\n");
|
|
||||||
for (TypeIdItem typeIdItem: interfaceList.getTypes()) {
|
|
||||||
writer.write(".implements ");
|
|
||||||
writer.write(typeIdItem.getTypeDescriptor());
|
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
|
writer.write("# interfaces\n");
|
||||||
|
for (String interfaceName: interfaces) {
|
||||||
|
writer.write(".implements ");
|
||||||
|
writer.write(interfaceName);
|
||||||
|
writer.write('\n');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAnnotations(IndentingWriter writer) throws IOException {
|
private void writeAnnotations(IndentingWriter writer) throws IOException {
|
||||||
AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations();
|
Collection<? extends Annotation> classAnnotations = classDef.getAnnotations();
|
||||||
if (annotationDirectory == null) {
|
if (classAnnotations.size() != 0) {
|
||||||
return;
|
writer.write("\n\n");
|
||||||
|
writer.write("# annotations\n");
|
||||||
|
AnnotationFormatter.writeTo(writer, classAnnotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations();
|
|
||||||
if (annotationSet == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.write("\n\n");
|
|
||||||
writer.write("# annotations\n");
|
|
||||||
AnnotationFormatter.writeTo(writer, annotationSet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeStaticFields(IndentingWriter writer) throws IOException {
|
private Set<String> writeStaticFields(IndentingWriter writer) throws IOException {
|
||||||
if (classDataItem == null) {
|
boolean wroteHeader = false;
|
||||||
return;
|
Set<String> writtenFields = new HashSet<String>();
|
||||||
}
|
|
||||||
//if classDataItem is not null, then classDefItem won't be null either
|
|
||||||
assert(classDefItem != null);
|
|
||||||
|
|
||||||
EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers();
|
Iterable<? extends Field> staticFields;
|
||||||
|
if (classDef instanceof DexBackedClassDef) {
|
||||||
EncodedValue[] staticInitializers;
|
staticFields = ((DexBackedClassDef)classDef).getStaticFields(false);
|
||||||
if (encodedStaticInitializers != null) {
|
|
||||||
staticInitializers = encodedStaticInitializers.getEncodedArray().values;
|
|
||||||
} else {
|
} else {
|
||||||
staticInitializers = new EncodedValue[0];
|
staticFields = classDef.getStaticFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ClassDataItem.EncodedField> encodedFields = classDataItem.getStaticFields();
|
for (Field field: staticFields) {
|
||||||
if (encodedFields.size() == 0) {
|
if (!wroteHeader) {
|
||||||
return;
|
writer.write("\n\n");
|
||||||
|
writer.write("# static fields");
|
||||||
|
wroteHeader = true;
|
||||||
|
}
|
||||||
|
writer.write('\n');
|
||||||
|
|
||||||
|
boolean setInStaticConstructor;
|
||||||
|
IndentingWriter fieldWriter = writer;
|
||||||
|
String fieldString = ReferenceUtil.getShortFieldDescriptor(field);
|
||||||
|
if (!writtenFields.add(fieldString)) {
|
||||||
|
writer.write("# duplicate field ignored\n");
|
||||||
|
fieldWriter = new CommentingIndentingWriter(writer);
|
||||||
|
System.err.println(String.format("Ignoring duplicate field: %s->%s", classDef.getType(), fieldString));
|
||||||
|
setInStaticConstructor = false;
|
||||||
|
} else {
|
||||||
|
setInStaticConstructor = fieldsSetInStaticConstructor.contains(fieldString);
|
||||||
|
}
|
||||||
|
FieldDefinition.writeTo(fieldWriter, field, setInStaticConstructor);
|
||||||
|
}
|
||||||
|
return writtenFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeInstanceFields(IndentingWriter writer, Set<String> staticFields) throws IOException {
|
||||||
|
boolean wroteHeader = false;
|
||||||
|
Set<String> writtenFields = new HashSet<String>();
|
||||||
|
|
||||||
|
Iterable<? extends Field> instanceFields;
|
||||||
|
if (classDef instanceof DexBackedClassDef) {
|
||||||
|
instanceFields = ((DexBackedClassDef)classDef).getInstanceFields(false);
|
||||||
|
} else {
|
||||||
|
instanceFields = classDef.getInstanceFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write("\n\n");
|
for (Field field: instanceFields) {
|
||||||
writer.write("# static fields\n");
|
if (!wroteHeader) {
|
||||||
|
writer.write("\n\n");
|
||||||
for (int i=0; i<encodedFields.size(); i++) {
|
writer.write("# instance fields");
|
||||||
if (i > 0) {
|
wroteHeader = true;
|
||||||
writer.write('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassDataItem.EncodedField field = encodedFields.get(i);
|
|
||||||
EncodedValue encodedValue = null;
|
|
||||||
if (i < staticInitializers.length) {
|
|
||||||
encodedValue = staticInitializers[i];
|
|
||||||
}
|
|
||||||
AnnotationSetItem fieldAnnotations = null;
|
|
||||||
AnnotationDirectoryItem annotations = classDefItem.getAnnotations();
|
|
||||||
if (annotations != null) {
|
|
||||||
fieldAnnotations = annotations.getFieldAnnotations(field.field);
|
|
||||||
}
|
}
|
||||||
|
writer.write('\n');
|
||||||
|
|
||||||
IndentingWriter fieldWriter = writer;
|
IndentingWriter fieldWriter = writer;
|
||||||
// the encoded fields are sorted, so we just have to compare with the previous one to detect duplicates
|
String fieldString = ReferenceUtil.getShortFieldDescriptor(field);
|
||||||
if (i > 0 && field.equals(encodedFields.get(i-1))) {
|
if (!writtenFields.add(fieldString)) {
|
||||||
fieldWriter = new CommentingIndentingWriter(writer, "#");
|
writer.write("# duplicate field ignored\n");
|
||||||
fieldWriter.write("Ignoring field with duplicate signature\n");
|
fieldWriter = new CommentingIndentingWriter(writer);
|
||||||
System.err.println(String.format("Warning: class %s has duplicate static field %s, Ignoring.",
|
System.err.println(String.format("Ignoring duplicate field: %s->%s", classDef.getType(), fieldString));
|
||||||
classDefItem.getClassType().getTypeDescriptor(), field.field.getShortFieldString()));
|
} else if (staticFields.contains(fieldString)) {
|
||||||
|
System.err.println(String.format("Duplicate static+instance field found: %s->%s",
|
||||||
|
classDef.getType(), fieldString));
|
||||||
|
System.err.println("You will need to rename one of these fields, including all references.");
|
||||||
|
|
||||||
|
writer.write("# There is both a static and instance field with this signature.\n" +
|
||||||
|
"# You will need to rename one of these fields, including all references.\n");
|
||||||
}
|
}
|
||||||
|
FieldDefinition.writeTo(fieldWriter, field, false);
|
||||||
boolean setInStaticConstructor =
|
|
||||||
fieldsSetInStaticConstructor.get(field.field.getIndex()) != null;
|
|
||||||
|
|
||||||
FieldDefinition.writeTo(fieldWriter, field, encodedValue, fieldAnnotations, setInStaticConstructor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeInstanceFields(IndentingWriter writer) throws IOException {
|
private Set<String> writeDirectMethods(IndentingWriter writer) throws IOException {
|
||||||
if (classDataItem == null) {
|
boolean wroteHeader = false;
|
||||||
return;
|
Set<String> writtenMethods = new HashSet<String>();
|
||||||
|
|
||||||
|
Iterable<? extends Method> directMethods;
|
||||||
|
if (classDef instanceof DexBackedClassDef) {
|
||||||
|
directMethods = ((DexBackedClassDef)classDef).getDirectMethods(false);
|
||||||
|
} else {
|
||||||
|
directMethods = classDef.getDirectMethods();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ClassDataItem.EncodedField> encodedFields = classDataItem.getInstanceFields();
|
for (Method method: directMethods) {
|
||||||
if (encodedFields.size() == 0) {
|
if (!wroteHeader) {
|
||||||
return;
|
writer.write("\n\n");
|
||||||
}
|
writer.write("# direct methods");
|
||||||
|
wroteHeader = true;
|
||||||
writer.write("\n\n");
|
|
||||||
writer.write("# instance fields\n");
|
|
||||||
for (int i=0; i<encodedFields.size(); i++) {
|
|
||||||
ClassDataItem.EncodedField field = encodedFields.get(i);
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
writer.write('\n');
|
|
||||||
}
|
}
|
||||||
|
writer.write('\n');
|
||||||
|
|
||||||
AnnotationSetItem fieldAnnotations = null;
|
// TODO: check for method validation errors
|
||||||
AnnotationDirectoryItem annotations = classDefItem.getAnnotations();
|
String methodString = ReferenceUtil.getShortMethodDescriptor(method);
|
||||||
if (annotations != null) {
|
|
||||||
fieldAnnotations = annotations.getFieldAnnotations(field.field);
|
|
||||||
}
|
|
||||||
|
|
||||||
IndentingWriter fieldWriter = writer;
|
|
||||||
// the encoded fields are sorted, so we just have to compare with the previous one to detect duplicates
|
|
||||||
if (i > 0 && field.equals(encodedFields.get(i-1))) {
|
|
||||||
fieldWriter = new CommentingIndentingWriter(writer, "#");
|
|
||||||
fieldWriter.write("Ignoring field with duplicate signature\n");
|
|
||||||
System.err.println(String.format("Warning: class %s has duplicate instance field %s, Ignoring.",
|
|
||||||
classDefItem.getClassType().getTypeDescriptor(), field.field.getShortFieldString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldDefinition.writeTo(fieldWriter, field, null, fieldAnnotations, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeDirectMethods(IndentingWriter writer) throws IOException {
|
|
||||||
if (classDataItem == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ClassDataItem.EncodedMethod> directMethods = classDataItem.getDirectMethods();
|
|
||||||
if (directMethods.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.write("\n\n");
|
|
||||||
writer.write("# direct methods\n");
|
|
||||||
writeMethods(writer, directMethods);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeVirtualMethods(IndentingWriter writer) throws IOException {
|
|
||||||
if (classDataItem == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ClassDataItem.EncodedMethod> virtualMethods = classDataItem.getVirtualMethods();
|
|
||||||
|
|
||||||
if (virtualMethods.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.write("\n\n");
|
|
||||||
writer.write("# virtual methods\n");
|
|
||||||
writeMethods(writer, virtualMethods);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeMethods(IndentingWriter writer, List<ClassDataItem.EncodedMethod> methods) throws IOException {
|
|
||||||
for (int i=0; i<methods.size(); i++) {
|
|
||||||
ClassDataItem.EncodedMethod method = methods.get(i);
|
|
||||||
if (i > 0) {
|
|
||||||
writer.write('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
AnnotationSetItem methodAnnotations = null;
|
|
||||||
AnnotationSetRefList parameterAnnotations = null;
|
|
||||||
AnnotationDirectoryItem annotations = classDefItem.getAnnotations();
|
|
||||||
if (annotations != null) {
|
|
||||||
methodAnnotations = annotations.getMethodAnnotations(method.method);
|
|
||||||
parameterAnnotations = annotations.getParameterAnnotations(method.method);
|
|
||||||
}
|
|
||||||
|
|
||||||
IndentingWriter methodWriter = writer;
|
IndentingWriter methodWriter = writer;
|
||||||
// the encoded methods are sorted, so we just have to compare with the previous one to detect duplicates
|
if (!writtenMethods.add(methodString)) {
|
||||||
if (i > 0 && method.equals(methods.get(i-1))) {
|
writer.write("# duplicate method ignored\n");
|
||||||
methodWriter = new CommentingIndentingWriter(writer, "#");
|
methodWriter = new CommentingIndentingWriter(writer);
|
||||||
methodWriter.write("Ignoring method with duplicate signature\n");
|
|
||||||
System.err.println(String.format("Warning: class %s has duplicate method %s, Ignoring.",
|
|
||||||
classDefItem.getClassType().getTypeDescriptor(), method.method.getShortMethodString()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodDefinition methodDefinition = new MethodDefinition(method);
|
MethodImplementation methodImpl = method.getImplementation();
|
||||||
methodDefinition.writeTo(methodWriter, methodAnnotations, parameterAnnotations);
|
if (methodImpl == null) {
|
||||||
|
MethodDefinition.writeEmptyMethodTo(methodWriter, method);
|
||||||
|
} else {
|
||||||
|
MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl);
|
||||||
|
methodDefinition.writeTo(methodWriter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return writtenMethods;
|
||||||
|
}
|
||||||
|
|
||||||
ValidationException validationException = methodDefinition.getValidationException();
|
private void writeVirtualMethods(IndentingWriter writer, Set<String> directMethods) throws IOException {
|
||||||
if (validationException != null) {
|
boolean wroteHeader = false;
|
||||||
System.err.println(String.format("Error while disassembling method %s. Continuing.",
|
Set<String> writtenMethods = new HashSet<String>();
|
||||||
method.method.getMethodString()));
|
|
||||||
validationException.printStackTrace(System.err);
|
Iterable<? extends Method> virtualMethods;
|
||||||
this.validationErrors = true;
|
if (classDef instanceof DexBackedClassDef) {
|
||||||
|
virtualMethods = ((DexBackedClassDef)classDef).getVirtualMethods(false);
|
||||||
|
} else {
|
||||||
|
virtualMethods = classDef.getVirtualMethods();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Method method: virtualMethods) {
|
||||||
|
if (!wroteHeader) {
|
||||||
|
writer.write("\n\n");
|
||||||
|
writer.write("# virtual methods");
|
||||||
|
wroteHeader = true;
|
||||||
|
}
|
||||||
|
writer.write('\n');
|
||||||
|
|
||||||
|
// TODO: check for method validation errors
|
||||||
|
String methodString = ReferenceUtil.getShortMethodDescriptor(method);
|
||||||
|
|
||||||
|
IndentingWriter methodWriter = writer;
|
||||||
|
if (!writtenMethods.add(methodString)) {
|
||||||
|
writer.write("# duplicate method ignored\n");
|
||||||
|
methodWriter = new CommentingIndentingWriter(writer);
|
||||||
|
} else if (directMethods.contains(methodString)) {
|
||||||
|
writer.write("# There is both a direct and virtual method with this signature.\n" +
|
||||||
|
"# You will need to rename one of these methods, including all references.\n");
|
||||||
|
System.err.println(String.format("Duplicate direct+virtual method found: %s->%s",
|
||||||
|
classDef.getType(), methodString));
|
||||||
|
System.err.println("You will need to rename one of these methods, including all references.");
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodImplementation methodImpl = method.getImplementation();
|
||||||
|
if (methodImpl == null) {
|
||||||
|
MethodDefinition.writeEmptyMethodTo(methodWriter, method);
|
||||||
|
} else {
|
||||||
|
MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl);
|
||||||
|
methodDefinition.writeTo(methodWriter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012, Google Inc.
|
* Copyright 2013, Google Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -29,20 +29,20 @@
|
|||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jf.util;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
|
||||||
public class CommentingIndentingWriter extends IndentingWriter {
|
public class CommentingIndentingWriter extends IndentingWriter {
|
||||||
private final String commentStr;
|
public CommentingIndentingWriter(Writer writer) {
|
||||||
|
|
||||||
public CommentingIndentingWriter(Writer writer, String commentStr) {
|
|
||||||
super(writer);
|
super(writer);
|
||||||
this.commentStr = commentStr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeLineStart() throws IOException {
|
@Override protected void writeIndent() throws IOException {
|
||||||
writer.write(commentStr);
|
writer.write("# ");
|
||||||
|
super.writeIndent();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class BeginEpilogueMethodItem extends DebugMethodItem {
|
||||||
|
public BeginEpilogueMethodItem(int codeAddress, int sortOrder) {
|
||||||
|
super(codeAddress, sortOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
writer.write(".prologue");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.baksmali.Adaptors.MethodItem;
|
||||||
|
import org.jf.baksmali.Adaptors.RegisterFormatter;
|
||||||
|
import org.jf.dexlib2.DebugItemType;
|
||||||
|
import org.jf.dexlib2.iface.debug.*;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
|
public abstract class DebugMethodItem extends MethodItem {
|
||||||
|
private final int sortOrder;
|
||||||
|
|
||||||
|
protected DebugMethodItem(int codeAddress, int sortOrder) {
|
||||||
|
super(codeAddress);
|
||||||
|
this.sortOrder = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public double getSortOrder() { return sortOrder; }
|
||||||
|
|
||||||
|
public static DebugMethodItem build(RegisterFormatter registerFormatter, DebugItem debugItem) {
|
||||||
|
int codeAddress = debugItem.getCodeAddress();
|
||||||
|
switch (debugItem.getDebugItemType()) {
|
||||||
|
case DebugItemType.START_LOCAL:
|
||||||
|
return new StartLocalMethodItem(codeAddress, -1, registerFormatter, (StartLocal)debugItem);
|
||||||
|
case DebugItemType.END_LOCAL:
|
||||||
|
return new EndLocalMethodItem(codeAddress, -1, registerFormatter, (EndLocal)debugItem);
|
||||||
|
case DebugItemType.RESTART_LOCAL:
|
||||||
|
return new RestartLocalMethodItem(codeAddress, -1, registerFormatter, (RestartLocal)debugItem);
|
||||||
|
case DebugItemType.EPILOGUE_BEGIN:
|
||||||
|
return new BeginEpilogueMethodItem(codeAddress, -4);
|
||||||
|
case DebugItemType.PROLOGUE_END:
|
||||||
|
return new EndPrologueMethodItem(codeAddress, -4);
|
||||||
|
case DebugItemType.SET_SOURCE_FILE:
|
||||||
|
return new SetSourceFileMethodItem(codeAddress, -3, (SetSourceFile)debugItem);
|
||||||
|
case DebugItemType.LINE_NUMBER:
|
||||||
|
return new LineNumberMethodItem(codeAddress, -2, (LineNumber)debugItem);
|
||||||
|
default:
|
||||||
|
throw new ExceptionWithContext("Invalid debug item type: %d", debugItem.getDebugItemType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.baksmali.Adaptors.RegisterFormatter;
|
||||||
|
import org.jf.dexlib2.iface.debug.EndLocal;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EndLocalMethodItem extends DebugMethodItem {
|
||||||
|
@Nonnull private final EndLocal endLocal;
|
||||||
|
@Nonnull private final RegisterFormatter registerFormatter;
|
||||||
|
|
||||||
|
public EndLocalMethodItem(int codeAddress, int sortOrder, @Nonnull RegisterFormatter registerFormatter,
|
||||||
|
@Nonnull EndLocal endLocal) {
|
||||||
|
super(codeAddress, sortOrder);
|
||||||
|
this.endLocal = endLocal;
|
||||||
|
this.registerFormatter = registerFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
writer.write(".end local ");
|
||||||
|
registerFormatter.writeTo(writer, endLocal.getRegister());
|
||||||
|
|
||||||
|
String name = endLocal.getName();
|
||||||
|
String type = endLocal.getType();
|
||||||
|
String signature = endLocal.getSignature();
|
||||||
|
if (name != null || type != null || signature != null) {
|
||||||
|
writer.write(" # ");
|
||||||
|
LocalFormatter.writeLocal(writer, name, type, signature);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EndPrologueMethodItem extends DebugMethodItem {
|
||||||
|
public EndPrologueMethodItem(int codeAddress, int sortOrder) {
|
||||||
|
super(codeAddress, sortOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
writer.write(".prologue");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.dexlib2.iface.debug.LineNumber;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class LineNumberMethodItem extends DebugMethodItem {
|
||||||
|
private final int lineNumber;
|
||||||
|
|
||||||
|
public LineNumberMethodItem(int codeAddress, int sortOrder, @Nonnull LineNumber lineNumber) {
|
||||||
|
super(codeAddress, sortOrder);
|
||||||
|
this.lineNumber = lineNumber.getLineNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
writer.write(".line ");
|
||||||
|
writer.printUnsignedIntAsDec(lineNumber);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class LocalFormatter {
|
||||||
|
/**
|
||||||
|
* Writes out the given local info
|
||||||
|
*
|
||||||
|
* The written string will be something like:
|
||||||
|
*
|
||||||
|
* "localVar":Ljava/lang/String;, "SomeSignature"
|
||||||
|
* "localVar":Ljava/lang/String;
|
||||||
|
* "localVar":V, "SomeSignature"
|
||||||
|
* null:Ljava/lang/String;, "SomeSignature"
|
||||||
|
* null:V, "SomeSignature"
|
||||||
|
*
|
||||||
|
* One of name, type or signature must be non-null
|
||||||
|
*/
|
||||||
|
public static void writeLocal(@Nonnull IndentingWriter writer, @Nullable String name, @Nullable String type,
|
||||||
|
@Nullable String signature) throws IOException {
|
||||||
|
if (name != null) {
|
||||||
|
ReferenceFormatter.writeStringReference(writer, name);
|
||||||
|
} else {
|
||||||
|
writer.write("null");
|
||||||
|
}
|
||||||
|
writer.write(':');
|
||||||
|
if (type != null) {
|
||||||
|
writer.write(type);
|
||||||
|
} else {
|
||||||
|
writer.write("V");
|
||||||
|
}
|
||||||
|
if (signature != null) {
|
||||||
|
writer.write(", ");
|
||||||
|
ReferenceFormatter.writeStringReference(writer, signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.baksmali.Adaptors.RegisterFormatter;
|
||||||
|
import org.jf.dexlib2.iface.debug.RestartLocal;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class RestartLocalMethodItem extends DebugMethodItem {
|
||||||
|
@Nonnull private final RestartLocal restartLocal;
|
||||||
|
@Nonnull private final RegisterFormatter registerFormatter;
|
||||||
|
|
||||||
|
public RestartLocalMethodItem(int codeAddress, int sortOrder, @Nonnull RegisterFormatter registerFormatter,
|
||||||
|
@Nonnull RestartLocal restartLocal) {
|
||||||
|
super(codeAddress, sortOrder);
|
||||||
|
this.restartLocal = restartLocal;
|
||||||
|
this.registerFormatter = registerFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
writer.write(".restart local ");
|
||||||
|
registerFormatter.writeTo(writer, restartLocal.getRegister());
|
||||||
|
|
||||||
|
String name = restartLocal.getName();
|
||||||
|
String type = restartLocal.getType();
|
||||||
|
String signature = restartLocal.getSignature();
|
||||||
|
if (name != null || type != null || signature != null) {
|
||||||
|
writer.write(" # ");
|
||||||
|
LocalFormatter.writeLocal(writer, name, type, signature);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.dexlib2.iface.debug.SetSourceFile;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
import org.jf.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SetSourceFileMethodItem extends DebugMethodItem {
|
||||||
|
@Nullable private final String sourceFile;
|
||||||
|
|
||||||
|
public SetSourceFileMethodItem(int codeAddress, int sortOrder, @Nonnull SetSourceFile setSourceFile) {
|
||||||
|
super(codeAddress, sortOrder);
|
||||||
|
this.sourceFile = setSourceFile.getSourceFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
writer.write(".source");
|
||||||
|
|
||||||
|
if (sourceFile != null) {
|
||||||
|
writer.write(" \"");
|
||||||
|
StringUtils.writeEscapedString(writer, sourceFile);
|
||||||
|
writer.write('"');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors.Debug;
|
||||||
|
|
||||||
|
import org.jf.baksmali.Adaptors.RegisterFormatter;
|
||||||
|
import org.jf.dexlib2.iface.debug.StartLocal;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class StartLocalMethodItem extends DebugMethodItem {
|
||||||
|
@Nonnull private final StartLocal startLocal;
|
||||||
|
@Nonnull private final RegisterFormatter registerFormatter;
|
||||||
|
|
||||||
|
public StartLocalMethodItem(int codeAddress, int sortOrder, @Nonnull RegisterFormatter registerFormatter,
|
||||||
|
@Nonnull StartLocal startLocal) {
|
||||||
|
super(codeAddress, sortOrder);
|
||||||
|
this.startLocal = startLocal;
|
||||||
|
this.registerFormatter = registerFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
writer.write(".local ");
|
||||||
|
registerFormatter.writeTo(writer, startLocal.getRegister());
|
||||||
|
|
||||||
|
String name = startLocal.getName();
|
||||||
|
String type = startLocal.getType();
|
||||||
|
String signature = startLocal.getSignature();
|
||||||
|
|
||||||
|
if (name != null || type != null || signature != null) {
|
||||||
|
writer.write(", ");
|
||||||
|
LocalFormatter.writeLocal(writer, name, type, signature);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,123 +0,0 @@
|
|||||||
/*
|
|
||||||
* [The "BSD licence"]
|
|
||||||
* Copyright (c) 2010 Ben Gruver (JesusFreke)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
|
||||||
|
|
||||||
import org.jf.dexlib.Util.Utf8Utils;
|
|
||||||
import org.jf.util.IndentingWriter;
|
|
||||||
import org.jf.dexlib.CodeItem;
|
|
||||||
import org.jf.dexlib.StringIdItem;
|
|
||||||
import org.jf.dexlib.TypeIdItem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public abstract class DebugMethodItem extends MethodItem {
|
|
||||||
private final double sortOrder;
|
|
||||||
|
|
||||||
public DebugMethodItem(int codeAddress, double sortOrder) {
|
|
||||||
super(codeAddress);
|
|
||||||
this.sortOrder = sortOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getSortOrder() {
|
|
||||||
return sortOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void writeLine(IndentingWriter writer, int line) throws IOException {
|
|
||||||
writer.write(".line ");
|
|
||||||
writer.printSignedIntAsDec(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void writeEndPrologue(IndentingWriter writer) throws IOException {
|
|
||||||
writer.write(".prologue");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void writeBeginEpilogue(IndentingWriter writer) throws IOException {
|
|
||||||
writer.write(".epilogue");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void writeStartLocal(IndentingWriter writer, CodeItem codeItem, int register,
|
|
||||||
StringIdItem name, TypeIdItem type, StringIdItem signature)
|
|
||||||
throws IOException {
|
|
||||||
writer.write(".local ");
|
|
||||||
RegisterFormatter.writeTo(writer, codeItem, register);
|
|
||||||
writer.write(", ");
|
|
||||||
writer.write(name.getStringValue());
|
|
||||||
writer.write(':');
|
|
||||||
writer.write(type.getTypeDescriptor());
|
|
||||||
if (signature != null) {
|
|
||||||
writer.write(",\"");
|
|
||||||
writer.write(signature.getStringValue());
|
|
||||||
writer.write('"');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void writeEndLocal(IndentingWriter writer, CodeItem codeItem, int register, StringIdItem name,
|
|
||||||
TypeIdItem type, StringIdItem signature) throws IOException {
|
|
||||||
writer.write(".end local ");
|
|
||||||
RegisterFormatter.writeTo(writer, codeItem, register);
|
|
||||||
|
|
||||||
if (name != null) {
|
|
||||||
writer.write(" #");
|
|
||||||
writer.write(name.getStringValue());
|
|
||||||
writer.write(':');
|
|
||||||
writer.write(type.getTypeDescriptor());
|
|
||||||
if (signature != null) {
|
|
||||||
writer.write(",\"");
|
|
||||||
writer.write(signature.getStringValue());
|
|
||||||
writer.write('"');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected static void writeRestartLocal(IndentingWriter writer, CodeItem codeItem, int register,
|
|
||||||
StringIdItem name, TypeIdItem type, StringIdItem signature)
|
|
||||||
throws IOException {
|
|
||||||
writer.write(".restart local ");
|
|
||||||
RegisterFormatter.writeTo(writer, codeItem, register);
|
|
||||||
|
|
||||||
if (name != null) {
|
|
||||||
writer.write(" #");
|
|
||||||
writer.write(name.getStringValue());
|
|
||||||
writer.write(':');
|
|
||||||
writer.write(type.getTypeDescriptor());
|
|
||||||
if (signature != null) {
|
|
||||||
writer.write(",\"");
|
|
||||||
writer.write(signature.getStringValue());
|
|
||||||
writer.write('"');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void writeSetFile(IndentingWriter writer, String fileName) throws IOException {
|
|
||||||
writer.write(".source \"");
|
|
||||||
Utf8Utils.writeEscapedString(writer, fileName);
|
|
||||||
writer.write('"');
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,32 +28,32 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors.EncodedValue;
|
package org.jf.baksmali.Adaptors.EncodedValue;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
import org.jf.dexlib2.iface.AnnotationElement;
|
||||||
|
import org.jf.dexlib2.iface.value.AnnotationEncodedValue;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
public abstract class AnnotationEncodedValueAdaptor {
|
public abstract class AnnotationEncodedValueAdaptor {
|
||||||
|
|
||||||
public static void writeTo(IndentingWriter writer, AnnotationEncodedSubValue encodedAnnotation)
|
public static void writeTo(IndentingWriter writer, AnnotationEncodedValue annotationEncodedValue)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
writer.write(".subannotation ");
|
writer.write(".subannotation ");
|
||||||
ReferenceFormatter.writeTypeReference(writer, encodedAnnotation.annotationType);
|
writer.write(annotationEncodedValue.getType());
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
|
|
||||||
writeElementsTo(writer, encodedAnnotation);
|
writeElementsTo(writer, annotationEncodedValue.getElements());
|
||||||
writer.write(".end subannotation");
|
writer.write(".end subannotation");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeElementsTo(IndentingWriter writer, AnnotationEncodedSubValue encodedAnnotation)
|
public static void writeElementsTo(IndentingWriter writer,
|
||||||
throws IOException {
|
Collection<? extends AnnotationElement> annotationElements) throws IOException {
|
||||||
writer.indent(4);
|
writer.indent(4);
|
||||||
for (int i=0; i<encodedAnnotation.names.length; i++) {
|
for (AnnotationElement annotationElement: annotationElements) {
|
||||||
writer.write(encodedAnnotation.names[i].getStringValue());
|
writer.write(annotationElement.getName());
|
||||||
writer.write(" = ");
|
writer.write(" = ");
|
||||||
|
EncodedValueAdaptor.writeTo(writer, annotationElement.getValue());
|
||||||
EncodedValueAdaptor.writeTo(writer, encodedAnnotation.values[i]);
|
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
writer.deindent(4);
|
writer.deindent(4);
|
||||||
|
@ -29,16 +29,17 @@
|
|||||||
package org.jf.baksmali.Adaptors.EncodedValue;
|
package org.jf.baksmali.Adaptors.EncodedValue;
|
||||||
|
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.EncodedValue.ArrayEncodedValue;
|
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
|
||||||
import org.jf.dexlib.EncodedValue.EncodedValue;
|
import org.jf.dexlib2.iface.value.EncodedValue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
public class ArrayEncodedValueAdaptor {
|
public class ArrayEncodedValueAdaptor {
|
||||||
public static void writeTo(IndentingWriter writer, ArrayEncodedValue encodedArray) throws IOException {
|
public static void writeTo(IndentingWriter writer, ArrayEncodedValue arrayEncodedValue) throws IOException {
|
||||||
writer.write('{');
|
writer.write('{');
|
||||||
EncodedValue[] values = encodedArray.values;
|
Collection<? extends EncodedValue> values = arrayEncodedValue.getValue();
|
||||||
if (values == null || values.length == 0) {
|
if (values.size() == 0) {
|
||||||
writer.write('}');
|
writer.write('}');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -46,7 +47,7 @@ public class ArrayEncodedValueAdaptor {
|
|||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
writer.indent(4);
|
writer.indent(4);
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (EncodedValue encodedValue: encodedArray.values) {
|
for (EncodedValue encodedValue: values) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
writer.write(",\n");
|
writer.write(",\n");
|
||||||
}
|
}
|
||||||
|
@ -29,62 +29,65 @@
|
|||||||
package org.jf.baksmali.Adaptors.EncodedValue;
|
package org.jf.baksmali.Adaptors.EncodedValue;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
||||||
|
import org.jf.dexlib2.ValueType;
|
||||||
|
import org.jf.dexlib2.iface.value.*;
|
||||||
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.Renderers.*;
|
import org.jf.baksmali.Renderers.*;
|
||||||
import org.jf.dexlib.EncodedValue.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public abstract class EncodedValueAdaptor {
|
public abstract class EncodedValueAdaptor {
|
||||||
public static void writeTo(IndentingWriter writer, EncodedValue encodedValue) throws IOException {
|
public static void writeTo(IndentingWriter writer, EncodedValue encodedValue) throws IOException {
|
||||||
switch (encodedValue.getValueType()) {
|
switch (encodedValue.getValueType()) {
|
||||||
case VALUE_ANNOTATION:
|
case ValueType.ANNOTATION:
|
||||||
AnnotationEncodedValueAdaptor.writeTo(writer, (AnnotationEncodedValue)encodedValue);
|
AnnotationEncodedValueAdaptor.writeTo(writer, (AnnotationEncodedValue)encodedValue);
|
||||||
return;
|
return;
|
||||||
case VALUE_ARRAY:
|
case ValueType.ARRAY:
|
||||||
ArrayEncodedValueAdaptor.writeTo(writer, (ArrayEncodedValue)encodedValue);
|
ArrayEncodedValueAdaptor.writeTo(writer, (ArrayEncodedValue)encodedValue);
|
||||||
return;
|
return;
|
||||||
case VALUE_BOOLEAN:
|
case ValueType.BOOLEAN:
|
||||||
BooleanRenderer.writeTo(writer, ((BooleanEncodedValue)encodedValue).value);
|
BooleanRenderer.writeTo(writer, ((BooleanEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_BYTE:
|
case ValueType.BYTE:
|
||||||
ByteRenderer.writeTo(writer, ((ByteEncodedValue)encodedValue).value);
|
ByteRenderer.writeTo(writer, ((ByteEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_CHAR:
|
case ValueType.CHAR:
|
||||||
CharRenderer.writeTo(writer, ((CharEncodedValue)encodedValue).value);
|
CharRenderer.writeTo(writer, ((CharEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_DOUBLE:
|
case ValueType.DOUBLE:
|
||||||
DoubleRenderer.writeTo(writer, ((DoubleEncodedValue)encodedValue).value);
|
DoubleRenderer.writeTo(writer, ((DoubleEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_ENUM:
|
case ValueType.ENUM:
|
||||||
EnumEncodedValueAdaptor.writeTo(writer, ((EnumEncodedValue)encodedValue).value);
|
writer.write(".enum ");
|
||||||
|
ReferenceUtil.writeFieldDescriptor(writer, ((EnumEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_FIELD:
|
case ValueType.FIELD:
|
||||||
ReferenceFormatter.writeFieldReference(writer, ((FieldEncodedValue)encodedValue).value);
|
ReferenceUtil.writeFieldDescriptor(writer, ((FieldEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_FLOAT:
|
case ValueType.FLOAT:
|
||||||
FloatRenderer.writeTo(writer, ((FloatEncodedValue)encodedValue).value);
|
FloatRenderer.writeTo(writer, ((FloatEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_INT:
|
case ValueType.INT:
|
||||||
IntegerRenderer.writeTo(writer, ((IntEncodedValue)encodedValue).value);
|
IntegerRenderer.writeTo(writer, ((IntEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_LONG:
|
case ValueType.LONG:
|
||||||
LongRenderer.writeTo(writer, ((LongEncodedValue)encodedValue).value);
|
LongRenderer.writeTo(writer, ((LongEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_METHOD:
|
case ValueType.METHOD:
|
||||||
ReferenceFormatter.writeMethodReference(writer, ((MethodEncodedValue)encodedValue).value);
|
ReferenceUtil.writeMethodDescriptor(writer, ((MethodEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_NULL:
|
case ValueType.NULL:
|
||||||
writer.write("null");
|
writer.write("null");
|
||||||
return;
|
return;
|
||||||
case VALUE_SHORT:
|
case ValueType.SHORT:
|
||||||
ShortRenderer.writeTo(writer, ((ShortEncodedValue)encodedValue).value);
|
ShortRenderer.writeTo(writer, ((ShortEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_STRING:
|
case ValueType.STRING:
|
||||||
ReferenceFormatter.writeStringReference(writer, ((StringEncodedValue)encodedValue).value);
|
ReferenceFormatter.writeStringReference(writer, ((StringEncodedValue)encodedValue).getValue());
|
||||||
return;
|
return;
|
||||||
case VALUE_TYPE:
|
case ValueType.TYPE:
|
||||||
ReferenceFormatter.writeTypeReference(writer, ((TypeEncodedValue)encodedValue).value);
|
writer.write(((TypeEncodedValue)encodedValue).getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* [The "BSD licence"]
|
|
||||||
* Copyright (c) 2010 Ben Gruver (JesusFreke)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jf.baksmali.Adaptors.EncodedValue;
|
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
|
||||||
import org.jf.util.IndentingWriter;
|
|
||||||
import org.jf.dexlib.FieldIdItem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class EnumEncodedValueAdaptor {
|
|
||||||
public static void writeTo(IndentingWriter writer, FieldIdItem item) throws IOException {
|
|
||||||
writer.write(".enum ");
|
|
||||||
ReferenceFormatter.writeFieldReference(writer, item);
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,11 +28,15 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public class EndTryLabelMethodItem extends LabelMethodItem {
|
public class EndTryLabelMethodItem extends LabelMethodItem {
|
||||||
private int endTryAddress;
|
private int endTryAddress;
|
||||||
|
|
||||||
public EndTryLabelMethodItem(int codeAddress, int endTryAddress) {
|
public EndTryLabelMethodItem(@Nonnull baksmaliOptions options, int codeAddress, int endTryAddress) {
|
||||||
super(codeAddress, "try_end_");
|
super(options, codeAddress, "try_end_");
|
||||||
this.endTryAddress = endTryAddress;
|
this.endTryAddress = endTryAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,40 +29,39 @@
|
|||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.EncodedValue.EncodedValueAdaptor;
|
import org.jf.baksmali.Adaptors.EncodedValue.EncodedValueAdaptor;
|
||||||
|
import org.jf.dexlib2.AccessFlags;
|
||||||
|
import org.jf.dexlib2.iface.Annotation;
|
||||||
|
import org.jf.dexlib2.iface.Field;
|
||||||
|
import org.jf.dexlib2.iface.value.EncodedValue;
|
||||||
|
import org.jf.dexlib2.util.EncodedValueUtils;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.AnnotationSetItem;
|
|
||||||
import org.jf.dexlib.ClassDataItem;
|
|
||||||
import org.jf.dexlib.EncodedValue.EncodedValue;
|
|
||||||
import org.jf.dexlib.EncodedValue.NullEncodedValue;
|
|
||||||
import org.jf.dexlib.Util.AccessFlags;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
public class FieldDefinition {
|
public class FieldDefinition {
|
||||||
public static void writeTo(IndentingWriter writer, ClassDataItem.EncodedField encodedField,
|
public static void writeTo(IndentingWriter writer, Field field, boolean setInStaticConstructor) throws IOException {
|
||||||
EncodedValue initialValue, AnnotationSetItem annotationSet,
|
EncodedValue initialValue = field.getInitialValue();
|
||||||
boolean setInStaticConstructor) throws IOException {
|
int accessFlags = field.getAccessFlags();
|
||||||
|
|
||||||
String fieldTypeDescriptor = encodedField.field.getFieldType().getTypeDescriptor();
|
|
||||||
|
|
||||||
if (setInStaticConstructor &&
|
if (setInStaticConstructor &&
|
||||||
encodedField.isStatic() &&
|
AccessFlags.STATIC.isSet(accessFlags) &&
|
||||||
(encodedField.accessFlags & AccessFlags.FINAL.getValue()) != 0 &&
|
AccessFlags.FINAL.isSet(accessFlags) &&
|
||||||
initialValue != null &&
|
initialValue != null) {
|
||||||
(
|
if (!EncodedValueUtils.isDefaultValue(initialValue)) {
|
||||||
//it's a primitive type, or it's an array/reference type and the initial value isn't null
|
writer.write("# The value of this static final field might be set in the static constructor\n");
|
||||||
fieldTypeDescriptor.length() == 1 ||
|
} else {
|
||||||
initialValue != NullEncodedValue.NullValue
|
// don't write out the default initial value for static final fields that get set in the static
|
||||||
)) {
|
// constructor
|
||||||
|
initialValue = null;
|
||||||
writer.write("#the value of this static final field might be set in the static constructor\n");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write(".field ");
|
writer.write(".field ");
|
||||||
writeAccessFlags(writer, encodedField);
|
writeAccessFlags(writer, field.getAccessFlags());
|
||||||
writer.write(encodedField.field.getFieldName().getStringValue());
|
writer.write(field.getName());
|
||||||
writer.write(':');
|
writer.write(':');
|
||||||
writer.write(encodedField.field.getFieldType().getTypeDescriptor());
|
writer.write(field.getType());
|
||||||
if (initialValue != null) {
|
if (initialValue != null) {
|
||||||
writer.write(" = ");
|
writer.write(" = ");
|
||||||
EncodedValueAdaptor.writeTo(writer, initialValue);
|
EncodedValueAdaptor.writeTo(writer, initialValue);
|
||||||
@ -70,17 +69,17 @@ public class FieldDefinition {
|
|||||||
|
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
|
|
||||||
if (annotationSet != null) {
|
Collection<? extends Annotation> annotations = field.getAnnotations();
|
||||||
|
if (annotations.size() > 0) {
|
||||||
writer.indent(4);
|
writer.indent(4);
|
||||||
AnnotationFormatter.writeTo(writer, annotationSet);
|
AnnotationFormatter.writeTo(writer, annotations);
|
||||||
writer.deindent(4);
|
writer.deindent(4);
|
||||||
writer.write(".end field\n");
|
writer.write(".end field\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeAccessFlags(IndentingWriter writer, ClassDataItem.EncodedField encodedField)
|
private static void writeAccessFlags(IndentingWriter writer, int accessFlags) throws IOException {
|
||||||
throws IOException {
|
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForField(accessFlags)) {
|
||||||
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForField(encodedField.accessFlags)) {
|
|
||||||
writer.write(accessFlag.toString());
|
writer.write(accessFlag.toString());
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
}
|
}
|
||||||
|
@ -28,36 +28,44 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors.Format;
|
package org.jf.baksmali.Adaptors.Format;
|
||||||
|
|
||||||
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
|
import org.jf.baksmali.Renderers.LongRenderer;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.Renderers.ByteRenderer;
|
|
||||||
import org.jf.dexlib.Code.Format.ArrayDataPseudoInstruction;
|
|
||||||
import org.jf.dexlib.CodeItem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
import java.util.List;
|
||||||
|
|
||||||
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayDataPseudoInstruction> {
|
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayPayload> {
|
||||||
public ArrayDataMethodItem(CodeItem codeItem, int codeAddress, ArrayDataPseudoInstruction instruction) {
|
public ArrayDataMethodItem(MethodDefinition methodDef, int codeAddress, ArrayPayload instruction) {
|
||||||
super(codeItem, codeAddress, instruction);
|
super(methodDef, codeAddress, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
writer.write(".array-data 0x");
|
int elementWidth = instruction.getElementWidth();
|
||||||
writer.printUnsignedLongAsHex(instruction.getElementWidth());
|
|
||||||
|
writer.write(".array-data ");
|
||||||
|
writer.printSignedIntAsDec(instruction.getElementWidth());
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
|
|
||||||
writer.indent(4);
|
writer.indent(4);
|
||||||
Iterator<ArrayDataPseudoInstruction.ArrayElement> iterator = instruction.getElements();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
ArrayDataPseudoInstruction.ArrayElement element = iterator.next();
|
|
||||||
|
|
||||||
for (int i=0; i<element.elementWidth; i++) {
|
List<Number> elements = instruction.getArrayElements();
|
||||||
if (i!=0) {
|
|
||||||
writer.write(' ');
|
String suffix = "";
|
||||||
}
|
switch (elementWidth) {
|
||||||
ByteRenderer.writeUnsignedTo(writer, element.buffer[element.bufferIndex+i]);
|
case 1:
|
||||||
}
|
suffix = "t";
|
||||||
writer.write('\n');
|
break;
|
||||||
|
case 2:
|
||||||
|
suffix = "s";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Number number: elements) {
|
||||||
|
LongRenderer.writeSignedIntOrLongTo(writer, number.longValue());
|
||||||
|
writer.write(suffix);
|
||||||
|
writer.write("\n");
|
||||||
}
|
}
|
||||||
writer.deindent(4);
|
writer.deindent(4);
|
||||||
writer.write(".end array-data");
|
writer.write(".end array-data");
|
||||||
|
@ -28,26 +28,26 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors.Format;
|
package org.jf.baksmali.Adaptors.Format;
|
||||||
|
|
||||||
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
import org.jf.baksmali.Adaptors.MethodItem;
|
import org.jf.baksmali.Adaptors.MethodItem;
|
||||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
||||||
import org.jf.baksmali.Adaptors.RegisterFormatter;
|
|
||||||
import org.jf.dexlib.Code.Format.Instruction20bc;
|
|
||||||
import org.jf.dexlib.Code.Format.UnknownInstruction;
|
|
||||||
import org.jf.util.IndentingWriter;
|
|
||||||
import org.jf.baksmali.Renderers.LongRenderer;
|
import org.jf.baksmali.Renderers.LongRenderer;
|
||||||
import org.jf.dexlib.Code.*;
|
import org.jf.dexlib2.VerificationError;
|
||||||
import org.jf.dexlib.CodeItem;
|
import org.jf.dexlib2.iface.instruction.*;
|
||||||
import org.jf.dexlib.Item;
|
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||||
protected final CodeItem codeItem;
|
@Nonnull protected final MethodDefinition methodDef;
|
||||||
protected final T instruction;
|
@Nonnull protected final T instruction;
|
||||||
|
|
||||||
public InstructionMethodItem(CodeItem codeItem, int codeAddress, T instruction) {
|
public InstructionMethodItem(@Nonnull MethodDefinition methodDef, int codeAddress, @Nonnull T instruction) {
|
||||||
super(codeAddress);
|
super(codeAddress);
|
||||||
this.codeItem = codeItem;
|
this.methodDef = methodDef;
|
||||||
this.instruction = instruction;
|
this.instruction = instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
switch (instruction.getFormat()) {
|
switch (instruction.getOpcode().format) {
|
||||||
case Format10t:
|
case Format10t:
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -67,7 +67,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
case Format10x:
|
case Format10x:
|
||||||
if (instruction instanceof UnknownInstruction) {
|
if (instruction instanceof UnknownInstruction) {
|
||||||
writer.write("#unknown opcode: 0x");
|
writer.write("#unknown opcode: 0x");
|
||||||
writer.printUnsignedLongAsHex(((UnknownInstruction) instruction).getOriginalOpcode() & 0xFFFF);
|
writer.printUnsignedLongAsHex(((UnknownInstruction)instruction).getOriginalOpcode());
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
@ -106,14 +106,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
return true;
|
return true;
|
||||||
case Format21c:
|
case Format21c:
|
||||||
case Format31c:
|
case Format31c:
|
||||||
case Format41c:
|
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeReference(writer);
|
writeReference(writer);
|
||||||
return true;
|
return true;
|
||||||
case Format21h:
|
case Format21ih:
|
||||||
|
case Format21lh:
|
||||||
case Format21s:
|
case Format21s:
|
||||||
case Format31i:
|
case Format31i:
|
||||||
case Format51l:
|
case Format51l:
|
||||||
@ -142,7 +142,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeLiteral(writer);
|
writeLiteral(writer);
|
||||||
return true;
|
return true;
|
||||||
case Format22c:
|
case Format22c:
|
||||||
case Format52c:
|
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeFirstRegister(writer);
|
writeFirstRegister(writer);
|
||||||
@ -208,7 +207,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeVtableIndex(writer);
|
writeVtableIndex(writer);
|
||||||
return true;
|
return true;
|
||||||
case Format3rc:
|
case Format3rc:
|
||||||
case Format5rc:
|
|
||||||
writeOpcode(writer);
|
writeOpcode(writer);
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writeInvokeRangeRegisters(writer);
|
writeInvokeRangeRegisters(writer);
|
||||||
@ -235,21 +233,21 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeOpcode(IndentingWriter writer) throws IOException {
|
protected void writeOpcode(IndentingWriter writer) throws IOException {
|
||||||
writer.write(instruction.opcode.name);
|
writer.write(instruction.getOpcode().name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeTargetLabel(IndentingWriter writer) throws IOException {
|
protected void writeTargetLabel(IndentingWriter writer) throws IOException {
|
||||||
//this method is overrided by OffsetInstructionMethodItem, and should only be called for the formats that
|
//this method is overridden by OffsetInstructionMethodItem, and should only be called for the formats that
|
||||||
//have a target
|
//have a target
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeRegister(IndentingWriter writer, int registerNumber) throws IOException {
|
protected void writeRegister(IndentingWriter writer, int registerNumber) throws IOException {
|
||||||
RegisterFormatter.writeTo(writer, codeItem, registerNumber);
|
methodDef.registerFormatter.writeTo(writer, registerNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeFirstRegister(IndentingWriter writer) throws IOException {
|
protected void writeFirstRegister(IndentingWriter writer) throws IOException {
|
||||||
writeRegister(writer, ((SingleRegisterInstruction)instruction).getRegisterA());
|
writeRegister(writer, ((OneRegisterInstruction)instruction).getRegisterA());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeSecondRegister(IndentingWriter writer) throws IOException {
|
protected void writeSecondRegister(IndentingWriter writer) throws IOException {
|
||||||
@ -257,40 +255,42 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeThirdRegister(IndentingWriter writer) throws IOException {
|
protected void writeThirdRegister(IndentingWriter writer) throws IOException {
|
||||||
writeRegister(writer, ((ThreeRegisterInstruction)instruction).getRegisterC());
|
writeRegister(writer, ((ThreeRegisterInstruction) instruction).getRegisterC());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeInvokeRegisters(IndentingWriter writer) throws IOException {
|
protected void writeInvokeRegisters(IndentingWriter writer) throws IOException {
|
||||||
FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction;
|
FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction;
|
||||||
final int regCount = instruction.getRegCount();
|
final int regCount = instruction.getRegisterCount();
|
||||||
|
|
||||||
writer.write('{');
|
writer.write('{');
|
||||||
switch (regCount) {
|
switch (regCount) {
|
||||||
case 1:
|
case 1:
|
||||||
writeRegister(writer, instruction.getRegisterD());
|
writeRegister(writer, instruction.getRegisterC());
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
writeRegister(writer, instruction.getRegisterD());
|
writeRegister(writer, instruction.getRegisterC());
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterE());
|
writeRegister(writer, instruction.getRegisterD());
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
writeRegister(writer, instruction.getRegisterC());
|
||||||
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterD());
|
writeRegister(writer, instruction.getRegisterD());
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterE());
|
writeRegister(writer, instruction.getRegisterE());
|
||||||
writer.write(", ");
|
|
||||||
writeRegister(writer, instruction.getRegisterF());
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
writeRegister(writer, instruction.getRegisterC());
|
||||||
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterD());
|
writeRegister(writer, instruction.getRegisterD());
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterE());
|
writeRegister(writer, instruction.getRegisterE());
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterF());
|
writeRegister(writer, instruction.getRegisterF());
|
||||||
writer.write(", ");
|
|
||||||
writeRegister(writer, instruction.getRegisterG());
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
|
writeRegister(writer, instruction.getRegisterC());
|
||||||
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterD());
|
writeRegister(writer, instruction.getRegisterD());
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterE());
|
writeRegister(writer, instruction.getRegisterE());
|
||||||
@ -298,8 +298,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
writeRegister(writer, instruction.getRegisterF());
|
writeRegister(writer, instruction.getRegisterF());
|
||||||
writer.write(", ");
|
writer.write(", ");
|
||||||
writeRegister(writer, instruction.getRegisterG());
|
writeRegister(writer, instruction.getRegisterG());
|
||||||
writer.write(", ");
|
|
||||||
writeRegister(writer, instruction.getRegisterA());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
writer.write('}');
|
writer.write('}');
|
||||||
@ -308,41 +306,42 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
|||||||
protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException {
|
protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException {
|
||||||
RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction;
|
RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction;
|
||||||
|
|
||||||
int regCount = instruction.getRegCount();
|
int regCount = instruction.getRegisterCount();
|
||||||
if (regCount == 0) {
|
if (regCount == 0) {
|
||||||
writer.write("{}");
|
writer.write("{}");
|
||||||
} else {
|
} else {
|
||||||
int startRegister = instruction.getStartRegister();
|
int startRegister = instruction.getStartRegister();
|
||||||
RegisterFormatter.writeRegisterRange(writer, codeItem, startRegister, startRegister+regCount-1);
|
methodDef.registerFormatter.writeRegisterRange(writer, startRegister, startRegister+regCount-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeLiteral(IndentingWriter writer) throws IOException {
|
protected void writeLiteral(IndentingWriter writer) throws IOException {
|
||||||
LongRenderer.writeSignedIntOrLongTo(writer, ((LiteralInstruction)instruction).getLiteral());
|
LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void writeFieldOffset(IndentingWriter writer) throws IOException {
|
protected void writeFieldOffset(IndentingWriter writer) throws IOException {
|
||||||
writer.write("field@0x");
|
writer.write("field@0x");
|
||||||
writer.printUnsignedLongAsHex(((OdexedFieldAccess) instruction).getFieldOffset());
|
writer.printUnsignedLongAsHex(((FieldOffsetInstruction)instruction).getFieldOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeInlineIndex(IndentingWriter writer) throws IOException {
|
protected void writeInlineIndex(IndentingWriter writer) throws IOException {
|
||||||
writer.write("inline@0x");
|
writer.write("inline@");
|
||||||
writer.printUnsignedLongAsHex(((OdexedInvokeInline) instruction).getInlineIndex());
|
writer.printSignedIntAsDec(((InlineIndexInstruction)instruction).getInlineIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeVtableIndex(IndentingWriter writer) throws IOException {
|
protected void writeVtableIndex(IndentingWriter writer) throws IOException {
|
||||||
writer.write("vtable@0x");
|
writer.write("vtable@");
|
||||||
writer.printUnsignedLongAsHex(((OdexedInvokeVirtual) instruction).getVtableIndex());
|
writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeReference(IndentingWriter writer) throws IOException {
|
protected void writeReference(IndentingWriter writer) throws IOException {
|
||||||
Item item = ((InstructionWithReference)instruction).getReferencedItem();
|
ReferenceFormatter.writeReference(writer, instruction.getOpcode().referenceType,
|
||||||
ReferenceFormatter.writeReference(writer, item);
|
((ReferenceInstruction)instruction).getReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
|
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
|
||||||
VerificationErrorType validationErrorType = ((Instruction20bc)instruction).getValidationErrorType();
|
int verificationError = ((Instruction20bc)instruction).getVerificationError();
|
||||||
writer.write(validationErrorType.getName());
|
writer.write(VerificationError.getVerificationErrorName(verificationError));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,37 +29,39 @@
|
|||||||
package org.jf.baksmali.Adaptors.Format;
|
package org.jf.baksmali.Adaptors.Format;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
import org.jf.dexlib.Code.Format.*;
|
import org.jf.dexlib2.analysis.UnresolvedOdexInstruction;
|
||||||
import org.jf.dexlib.Code.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
import org.jf.dexlib.Code.OffsetInstruction;
|
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
||||||
import org.jf.dexlib.CodeItem;
|
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload;
|
||||||
|
|
||||||
public class InstructionMethodItemFactory {
|
public class InstructionMethodItemFactory {
|
||||||
private InstructionMethodItemFactory() {
|
private InstructionMethodItemFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InstructionMethodItem makeInstructionFormatMethodItem(
|
public static InstructionMethodItem makeInstructionFormatMethodItem(
|
||||||
MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, Instruction instruction) {
|
MethodDefinition methodDef, int codeAddress, Instruction instruction) {
|
||||||
|
|
||||||
if (instruction instanceof OffsetInstruction) {
|
if (instruction instanceof OffsetInstruction) {
|
||||||
return new OffsetInstructionFormatMethodItem(methodDefinition.getLabelCache(), codeItem,
|
return new OffsetInstructionFormatMethodItem(methodDef.classDef.options, methodDef, codeAddress,
|
||||||
codeAddress, (OffsetInstruction)instruction);
|
(OffsetInstruction)instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (instruction.getFormat()) {
|
if (instruction instanceof UnresolvedOdexInstruction) {
|
||||||
case ArrayData:
|
return new UnresolvedOdexInstructionMethodItem(methodDef, codeAddress,
|
||||||
return new ArrayDataMethodItem(codeItem, codeAddress,
|
(UnresolvedOdexInstruction)instruction);
|
||||||
(ArrayDataPseudoInstruction)instruction);
|
}
|
||||||
case PackedSwitchData:
|
|
||||||
return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress,
|
switch (instruction.getOpcode().format) {
|
||||||
(PackedSwitchDataPseudoInstruction)instruction);
|
case ArrayPayload:
|
||||||
case SparseSwitchData:
|
return new ArrayDataMethodItem(methodDef, codeAddress, (ArrayPayload)instruction);
|
||||||
return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress,
|
case PackedSwitchPayload:
|
||||||
(SparseSwitchDataPseudoInstruction)instruction);
|
return new PackedSwitchMethodItem(methodDef, codeAddress, (PackedSwitchPayload)instruction);
|
||||||
case UnresolvedOdexInstruction:
|
case SparseSwitchPayload:
|
||||||
return new UnresolvedOdexInstructionMethodItem(codeItem, codeAddress,
|
return new SparseSwitchMethodItem(methodDef, codeAddress, (SparseSwitchPayload)instruction);
|
||||||
(UnresolvedOdexInstruction)instruction);
|
|
||||||
default:
|
default:
|
||||||
return new InstructionMethodItem<Instruction>(codeItem, codeAddress, instruction);
|
return new InstructionMethodItem<Instruction>(methodDef, codeAddress, instruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,22 +30,23 @@ package org.jf.baksmali.Adaptors.Format;
|
|||||||
|
|
||||||
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
||||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
|
import org.jf.dexlib2.Opcode;
|
||||||
|
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.Code.OffsetInstruction;
|
|
||||||
import org.jf.dexlib.Code.Opcode;
|
|
||||||
import org.jf.dexlib.CodeItem;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<OffsetInstruction> {
|
public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<OffsetInstruction> {
|
||||||
protected LabelMethodItem label;
|
protected LabelMethodItem label;
|
||||||
|
|
||||||
public OffsetInstructionFormatMethodItem(MethodDefinition.LabelCache labelCache, CodeItem codeItem, int codeAddress,
|
public OffsetInstructionFormatMethodItem(@Nonnull baksmaliOptions options, @Nonnull MethodDefinition methodDef,
|
||||||
OffsetInstruction instruction) {
|
int codeAddress, OffsetInstruction instruction) {
|
||||||
super(codeItem, codeAddress, instruction);
|
super(methodDef, codeAddress, instruction);
|
||||||
|
|
||||||
label = new LabelMethodItem(codeAddress + instruction.getTargetAddressOffset(), getLabelPrefix());
|
label = new LabelMethodItem(options, codeAddress + instruction.getCodeOffset(), getLabelPrefix());
|
||||||
label = labelCache.internLabel(label);
|
label = methodDef.getLabelCache().internLabel(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -58,7 +59,8 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<Off
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getLabelPrefix() {
|
private String getLabelPrefix() {
|
||||||
switch (instruction.getFormat()) {
|
Opcode opcode = instruction.getOpcode();
|
||||||
|
switch (opcode.format) {
|
||||||
case Format10t:
|
case Format10t:
|
||||||
case Format20t:
|
case Format20t:
|
||||||
case Format30t:
|
case Format30t:
|
||||||
@ -67,13 +69,13 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<Off
|
|||||||
case Format22t:
|
case Format22t:
|
||||||
return "cond_";
|
return "cond_";
|
||||||
case Format31t:
|
case Format31t:
|
||||||
if (instruction.opcode == Opcode.FILL_ARRAY_DATA) {
|
if (opcode == Opcode.FILL_ARRAY_DATA) {
|
||||||
return "array_";
|
return "array_";
|
||||||
}
|
}
|
||||||
if (instruction.opcode == Opcode.PACKED_SWITCH) {
|
if (opcode == Opcode.PACKED_SWITCH) {
|
||||||
return "pswitch_data_";
|
return "pswitch_data_";
|
||||||
}
|
}
|
||||||
assert instruction.opcode == Opcode.SPARSE_SWITCH;
|
// Opcode.SPARSE_SWITCH;
|
||||||
return "sswitch_data_";
|
return "sswitch_data_";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,55 +30,56 @@ package org.jf.baksmali.Adaptors.Format;
|
|||||||
|
|
||||||
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
||||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
|
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.Renderers.IntegerRenderer;
|
import org.jf.baksmali.Renderers.IntegerRenderer;
|
||||||
import org.jf.dexlib.Code.Format.PackedSwitchDataPseudoInstruction;
|
|
||||||
import org.jf.dexlib.CodeItem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDataPseudoInstruction> {
|
public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchPayload> {
|
||||||
private final List<PackedSwitchTarget> targets;
|
private final List<PackedSwitchTarget> targets;
|
||||||
|
private final int firstKey;
|
||||||
|
|
||||||
public PackedSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress,
|
public PackedSwitchMethodItem(MethodDefinition methodDef, int codeAddress, PackedSwitchPayload instruction) {
|
||||||
PackedSwitchDataPseudoInstruction instruction) {
|
super(methodDef, codeAddress, instruction);
|
||||||
super(codeItem, codeAddress, instruction);
|
|
||||||
|
|
||||||
int baseCodeAddress = methodDefinition.getPackedSwitchBaseAddress(codeAddress);
|
int baseCodeAddress = methodDef.getPackedSwitchBaseAddress(codeAddress);
|
||||||
|
|
||||||
targets = new ArrayList<PackedSwitchTarget>();
|
targets = new ArrayList<PackedSwitchTarget>();
|
||||||
Iterator<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> iterator = instruction.iterateKeysAndTargets();
|
|
||||||
|
|
||||||
|
boolean first = true;
|
||||||
|
//TODO: does dalvik allow switc payloads with no cases?
|
||||||
|
int firstKey = 0;
|
||||||
if (baseCodeAddress >= 0) {
|
if (baseCodeAddress >= 0) {
|
||||||
while (iterator.hasNext()) {
|
for (SwitchElement switchElement: instruction.getSwitchElements()) {
|
||||||
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
|
if (first) {
|
||||||
PackedSwitchLabelTarget packedSwitchLabelTarget = new PackedSwitchLabelTarget();
|
firstKey = switchElement.getKey();
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "pswitch_");
|
LabelMethodItem label = methodDef.getLabelCache().internLabel(
|
||||||
label = methodDefinition.getLabelCache().internLabel(label);
|
new LabelMethodItem(methodDef.classDef.options, baseCodeAddress + switchElement.getOffset(),
|
||||||
packedSwitchLabelTarget.Target = label;
|
"pswitch_"));
|
||||||
targets.add(packedSwitchLabelTarget);
|
targets.add(new PackedSwitchLabelTarget(label));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (iterator.hasNext()) {
|
for (SwitchElement switchElement: instruction.getSwitchElements()) {
|
||||||
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
|
if (first) {
|
||||||
PackedSwitchOffsetTarget packedSwitchOffsetTarget = new PackedSwitchOffsetTarget();
|
firstKey = switchElement.getKey();
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
packedSwitchOffsetTarget.Target = target.targetAddressOffset;
|
targets.add(new PackedSwitchOffsetTarget(switchElement.getOffset()));
|
||||||
targets.add(packedSwitchOffsetTarget);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.firstKey = firstKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
writer.write(".packed-switch ");
|
writer.write(".packed-switch ");
|
||||||
IntegerRenderer.writeTo(writer, instruction.getFirstKey());
|
IntegerRenderer.writeTo(writer, firstKey);
|
||||||
writer.indent(4);
|
writer.indent(4);
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
for (PackedSwitchTarget target: targets) {
|
for (PackedSwitchTarget target: targets) {
|
||||||
@ -95,19 +96,25 @@ public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class PackedSwitchLabelTarget extends PackedSwitchTarget {
|
private static class PackedSwitchLabelTarget extends PackedSwitchTarget {
|
||||||
public LabelMethodItem Target;
|
private final LabelMethodItem target;
|
||||||
|
public PackedSwitchLabelTarget(LabelMethodItem target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
||||||
Target.writeTo(writer);
|
target.writeTo(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PackedSwitchOffsetTarget extends PackedSwitchTarget {
|
private static class PackedSwitchOffsetTarget extends PackedSwitchTarget {
|
||||||
public int Target;
|
private final int target;
|
||||||
|
public PackedSwitchOffsetTarget(int target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
||||||
if (Target >= 0) {
|
if (target >= 0) {
|
||||||
writer.write('+');
|
writer.write('+');
|
||||||
}
|
}
|
||||||
writer.printSignedIntAsDec(Target);
|
writer.printSignedIntAsDec(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,48 +30,35 @@ package org.jf.baksmali.Adaptors.Format;
|
|||||||
|
|
||||||
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
||||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
|
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.Renderers.IntegerRenderer;
|
import org.jf.baksmali.Renderers.IntegerRenderer;
|
||||||
import org.jf.dexlib.Code.Format.SparseSwitchDataPseudoInstruction;
|
|
||||||
import org.jf.dexlib.CodeItem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDataPseudoInstruction> {
|
public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchPayload> {
|
||||||
private final List<SparseSwitchTarget> targets;
|
private final List<SparseSwitchTarget> targets;
|
||||||
|
|
||||||
public SparseSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress,
|
public SparseSwitchMethodItem(MethodDefinition methodDef, int codeAddress, SparseSwitchPayload instruction) {
|
||||||
SparseSwitchDataPseudoInstruction instruction) {
|
super(methodDef, codeAddress, instruction);
|
||||||
super(codeItem, codeAddress, instruction);
|
|
||||||
|
|
||||||
int baseCodeAddress = methodDefinition.getSparseSwitchBaseAddress(codeAddress);
|
int baseCodeAddress = methodDef.getSparseSwitchBaseAddress(codeAddress);
|
||||||
|
|
||||||
targets = new ArrayList<SparseSwitchTarget>();
|
targets = new ArrayList<SparseSwitchTarget>();
|
||||||
Iterator<SparseSwitchDataPseudoInstruction.SparseSwitchTarget> iterator = instruction.iterateKeysAndTargets();
|
|
||||||
if (baseCodeAddress >= 0) {
|
if (baseCodeAddress >= 0) {
|
||||||
while (iterator.hasNext()) {
|
for (SwitchElement switchElement: instruction.getSwitchElements()) {
|
||||||
SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next();
|
LabelMethodItem label = methodDef.getLabelCache().internLabel(
|
||||||
SparseSwitchLabelTarget sparseSwitchLabelTarget = new SparseSwitchLabelTarget();
|
new LabelMethodItem( methodDef.classDef.options, baseCodeAddress + switchElement.getOffset(),
|
||||||
sparseSwitchLabelTarget.Key = target.key;
|
"sswitch_"));
|
||||||
|
targets.add(new SparseSwitchLabelTarget(switchElement.getKey(), label));
|
||||||
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "sswitch_");
|
|
||||||
label = methodDefinition.getLabelCache().internLabel(label);
|
|
||||||
sparseSwitchLabelTarget.Target = label;
|
|
||||||
|
|
||||||
targets.add(sparseSwitchLabelTarget);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//if we couldn't determine a base address, just use relative offsets rather than labels
|
//if we couldn't determine a base address, just use relative offsets rather than labels
|
||||||
while (iterator.hasNext()) {
|
for (SwitchElement switchElement: instruction.getSwitchElements()) {
|
||||||
SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next();
|
targets.add(new SparseSwitchOffsetTarget(switchElement.getKey(), switchElement.getOffset()));
|
||||||
SparseSwitchOffsetTarget sparseSwitchOffsetTarget = new SparseSwitchOffsetTarget();
|
|
||||||
sparseSwitchOffsetTarget.Key = target.key;
|
|
||||||
|
|
||||||
sparseSwitchOffsetTarget.Target = target.targetAddressOffset;
|
|
||||||
targets.add(sparseSwitchOffsetTarget);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +68,7 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
|
|||||||
writer.write(".sparse-switch\n");
|
writer.write(".sparse-switch\n");
|
||||||
writer.indent(4);
|
writer.indent(4);
|
||||||
for (SparseSwitchTarget target: targets) {
|
for (SparseSwitchTarget target: targets) {
|
||||||
IntegerRenderer.writeTo(writer, target.Key);
|
IntegerRenderer.writeTo(writer, target.getKey());
|
||||||
writer.write(" -> ");
|
writer.write(" -> ");
|
||||||
target.writeTargetTo(writer);
|
target.writeTargetTo(writer);
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
@ -92,24 +79,38 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static abstract class SparseSwitchTarget {
|
private static abstract class SparseSwitchTarget {
|
||||||
public int Key;
|
private final int key;
|
||||||
|
public SparseSwitchTarget(int key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
public int getKey() { return key; }
|
||||||
public abstract void writeTargetTo(IndentingWriter writer) throws IOException;
|
public abstract void writeTargetTo(IndentingWriter writer) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SparseSwitchLabelTarget extends SparseSwitchTarget {
|
private static class SparseSwitchLabelTarget extends SparseSwitchTarget {
|
||||||
public LabelMethodItem Target;
|
private final LabelMethodItem target;
|
||||||
|
public SparseSwitchLabelTarget(int key, LabelMethodItem target) {
|
||||||
|
super(key);
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
||||||
Target.writeTo(writer);
|
target.writeTo(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SparseSwitchOffsetTarget extends SparseSwitchTarget {
|
private static class SparseSwitchOffsetTarget extends SparseSwitchTarget {
|
||||||
public int Target;
|
private final int target;
|
||||||
|
public SparseSwitchOffsetTarget(int key, int target) {
|
||||||
|
super(key);
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
||||||
if (Target >= 0) {
|
if (target >= 0) {
|
||||||
writer.write('+');
|
writer.write('+');
|
||||||
}
|
}
|
||||||
writer.printSignedIntAsDec(Target);
|
writer.printSignedIntAsDec(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,17 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors.Format;
|
package org.jf.baksmali.Adaptors.Format;
|
||||||
|
|
||||||
|
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||||
|
import org.jf.dexlib2.analysis.UnresolvedOdexInstruction;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.Code.Format.UnresolvedOdexInstruction;
|
|
||||||
import org.jf.dexlib.CodeItem;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<UnresolvedOdexInstruction> {
|
public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<UnresolvedOdexInstruction> {
|
||||||
public UnresolvedOdexInstructionMethodItem(CodeItem codeItem, int codeAddress, UnresolvedOdexInstruction instruction) {
|
public UnresolvedOdexInstructionMethodItem(@Nonnull MethodDefinition methodDef, int codeAddress,
|
||||||
super(codeItem, codeAddress, instruction);
|
@Nonnull UnresolvedOdexInstruction instruction) {
|
||||||
|
super(methodDef, codeAddress, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
@ -47,6 +49,6 @@ public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<U
|
|||||||
private void writeThrowTo(IndentingWriter writer) throws IOException {
|
private void writeThrowTo(IndentingWriter writer) throws IOException {
|
||||||
writer.write("#Replaced unresolvable odex instruction with a throw\n");
|
writer.write("#Replaced unresolvable odex instruction with a throw\n");
|
||||||
writer.write("throw ");
|
writer.write("throw ");
|
||||||
writeRegister(writer, instruction.ObjectRegisterNum);
|
writeRegister(writer, instruction.objectRegisterNum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,17 +28,20 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.baksmali;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class LabelMethodItem extends MethodItem {
|
public class LabelMethodItem extends MethodItem {
|
||||||
|
private final baksmaliOptions options;
|
||||||
private final String labelPrefix;
|
private final String labelPrefix;
|
||||||
private int labelSequence;
|
private int labelSequence;
|
||||||
|
|
||||||
public LabelMethodItem(int codeAddress, String labelPrefix) {
|
public LabelMethodItem(@Nonnull baksmaliOptions options, int codeAddress, @Nonnull String labelPrefix) {
|
||||||
super(codeAddress);
|
super(codeAddress);
|
||||||
|
this.options = options;
|
||||||
this.labelPrefix = labelPrefix;
|
this.labelPrefix = labelPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +76,7 @@ public class LabelMethodItem extends MethodItem {
|
|||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
writer.write(':');
|
writer.write(':');
|
||||||
writer.write(labelPrefix);
|
writer.write(labelPrefix);
|
||||||
if (baksmali.useSequentialLabels) {
|
if (options.useSequentialLabels) {
|
||||||
writer.printUnsignedLongAsHex(labelSequence);
|
writer.printUnsignedLongAsHex(labelSequence);
|
||||||
} else {
|
} else {
|
||||||
writer.printUnsignedLongAsHex(this.getLabelAddress());
|
writer.printUnsignedLongAsHex(this.getLabelAddress());
|
||||||
|
@ -28,297 +28,256 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import org.jf.baksmali.Adaptors.Debug.DebugMethodItem;
|
||||||
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
|
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
|
||||||
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
|
import org.jf.dexlib2.AccessFlags;
|
||||||
import org.jf.dexlib.Code.InstructionWithReference;
|
import org.jf.dexlib2.Format;
|
||||||
|
import org.jf.dexlib2.Opcode;
|
||||||
|
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.iface.*;
|
||||||
|
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
|
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.ReferenceUtil;
|
||||||
|
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||||
|
import org.jf.dexlib2.util.TypeUtils;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.baksmali;
|
import org.jf.util.SparseIntArray;
|
||||||
import org.jf.dexlib.*;
|
|
||||||
import org.jf.dexlib.Code.Analysis.AnalyzedInstruction;
|
|
||||||
import org.jf.dexlib.Code.Analysis.MethodAnalyzer;
|
|
||||||
import org.jf.dexlib.Code.Analysis.ValidationException;
|
|
||||||
import org.jf.dexlib.Code.Format.Format;
|
|
||||||
import org.jf.dexlib.Code.Instruction;
|
|
||||||
import org.jf.dexlib.Code.OffsetInstruction;
|
|
||||||
import org.jf.dexlib.Code.Opcode;
|
|
||||||
import org.jf.dexlib.Debug.DebugInstructionIterator;
|
|
||||||
import org.jf.dexlib.Util.AccessFlags;
|
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
|
||||||
import org.jf.dexlib.Util.SparseIntArray;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class MethodDefinition {
|
public class MethodDefinition {
|
||||||
private final ClassDataItem.EncodedMethod encodedMethod;
|
@Nonnull public final ClassDefinition classDef;
|
||||||
private MethodAnalyzer methodAnalyzer;
|
@Nonnull public final Method method;
|
||||||
|
@Nonnull public final MethodImplementation methodImpl;
|
||||||
|
@Nonnull public final ImmutableList<Instruction> instructions;
|
||||||
|
@Nonnull public final ImmutableList<MethodParameter> methodParameters;
|
||||||
|
public RegisterFormatter registerFormatter;
|
||||||
|
|
||||||
private final LabelCache labelCache = new LabelCache();
|
@Nonnull private final LabelCache labelCache = new LabelCache();
|
||||||
|
|
||||||
private final SparseIntArray packedSwitchMap;
|
@Nonnull private final SparseIntArray packedSwitchMap;
|
||||||
private final SparseIntArray sparseSwitchMap;
|
@Nonnull private final SparseIntArray sparseSwitchMap;
|
||||||
private final SparseIntArray instructionMap;
|
@Nonnull private final InstructionOffsetMap instructionOffsetMap;
|
||||||
|
|
||||||
public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) {
|
|
||||||
|
|
||||||
|
public MethodDefinition(@Nonnull ClassDefinition classDef, @Nonnull Method method,
|
||||||
|
@Nonnull MethodImplementation methodImpl) {
|
||||||
|
this.classDef = classDef;
|
||||||
|
this.method = method;
|
||||||
|
this.methodImpl = methodImpl;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.encodedMethod = encodedMethod;
|
|
||||||
|
|
||||||
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
|
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
|
||||||
|
|
||||||
if (encodedMethod.codeItem != null) {
|
instructions = ImmutableList.copyOf(methodImpl.getInstructions());
|
||||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
methodParameters = ImmutableList.copyOf(method.getParameters());
|
||||||
|
|
||||||
packedSwitchMap = new SparseIntArray(1);
|
packedSwitchMap = new SparseIntArray(0);
|
||||||
sparseSwitchMap = new SparseIntArray(1);
|
sparseSwitchMap = new SparseIntArray(0);
|
||||||
instructionMap = new SparseIntArray(instructions.length);
|
instructionOffsetMap = new InstructionOffsetMap(instructions);
|
||||||
|
|
||||||
int currentCodeAddress = 0;
|
for (int i=0; i<instructions.size(); i++) {
|
||||||
for (int i=0; i<instructions.length; i++) {
|
Instruction instruction = instructions.get(i);
|
||||||
Instruction instruction = instructions[i];
|
|
||||||
if (instruction.opcode == Opcode.PACKED_SWITCH) {
|
Opcode opcode = instruction.getOpcode();
|
||||||
packedSwitchMap.append(
|
if (opcode == Opcode.PACKED_SWITCH) {
|
||||||
currentCodeAddress +
|
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||||
((OffsetInstruction)instruction).getTargetAddressOffset(),
|
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||||
currentCodeAddress);
|
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
|
||||||
} else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
|
packedSwitchMap.append(targetOffset, codeOffset);
|
||||||
sparseSwitchMap.append(
|
} else if (opcode == Opcode.SPARSE_SWITCH) {
|
||||||
currentCodeAddress +
|
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||||
((OffsetInstruction)instruction).getTargetAddressOffset(),
|
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||||
currentCodeAddress);
|
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
|
||||||
}
|
sparseSwitchMap.append(targetOffset, codeOffset);
|
||||||
instructionMap.append(currentCodeAddress, i);
|
|
||||||
currentCodeAddress += instruction.getSize(currentCodeAddress);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
packedSwitchMap = null;
|
|
||||||
sparseSwitchMap = null;
|
|
||||||
instructionMap = null;
|
|
||||||
methodAnalyzer = null;
|
|
||||||
}
|
}
|
||||||
}catch (Exception ex) {
|
}catch (Exception ex) {
|
||||||
throw ExceptionWithContext.withContext(ex, String.format("Error while processing method %s",
|
String methodString;
|
||||||
encodedMethod.method.getMethodString()));
|
try {
|
||||||
|
methodString = ReferenceUtil.getMethodDescriptor(method);
|
||||||
|
} catch (Exception ex2) {
|
||||||
|
throw ExceptionWithContext.withContext(ex, "Error while processing method");
|
||||||
|
}
|
||||||
|
throw ExceptionWithContext.withContext(ex, "Error while processing method %s", methodString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(IndentingWriter writer, AnnotationSetItem annotationSet,
|
public static void writeEmptyMethodTo(IndentingWriter writer, Method method) throws IOException {
|
||||||
AnnotationSetRefList parameterAnnotations) throws IOException {
|
|
||||||
final CodeItem codeItem = encodedMethod.codeItem;
|
|
||||||
|
|
||||||
writer.write(".method ");
|
writer.write(".method ");
|
||||||
writeAccessFlags(writer, encodedMethod);
|
writeAccessFlags(writer, method.getAccessFlags());
|
||||||
writer.write(encodedMethod.method.getMethodName().getStringValue());
|
writer.write(method.getName());
|
||||||
writer.write(encodedMethod.method.getPrototype().getPrototypeString());
|
writer.write("(");
|
||||||
|
ImmutableList<MethodParameter> methodParameters = ImmutableList.copyOf(method.getParameters());
|
||||||
|
for (MethodParameter parameter: methodParameters) {
|
||||||
|
writer.write(parameter.getType());
|
||||||
|
}
|
||||||
|
writer.write(")");
|
||||||
|
writer.write(method.getReturnType());
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
|
|
||||||
writer.indent(4);
|
writer.indent(4);
|
||||||
if (codeItem != null) {
|
writeParameters(writer, method, methodParameters);
|
||||||
if (baksmali.useLocalsDirective) {
|
AnnotationFormatter.writeTo(writer, method.getAnnotations());
|
||||||
writer.write(".locals ");
|
writer.deindent(4);
|
||||||
} else {
|
writer.write(".end method\n");
|
||||||
writer.write(".registers ");
|
}
|
||||||
}
|
|
||||||
writer.printSignedIntAsDec(getRegisterCount(encodedMethod));
|
|
||||||
writer.write('\n');
|
|
||||||
writeParameters(writer, codeItem, parameterAnnotations);
|
|
||||||
if (annotationSet != null) {
|
|
||||||
AnnotationFormatter.writeTo(writer, annotationSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.write('\n');
|
public void writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
int parameterRegisterCount = 0;
|
||||||
|
if (!AccessFlags.STATIC.isSet(method.getAccessFlags())) {
|
||||||
|
parameterRegisterCount++;
|
||||||
|
}
|
||||||
|
|
||||||
for (MethodItem methodItem: getMethodItems()) {
|
writer.write(".method ");
|
||||||
if (methodItem.writeTo(writer)) {
|
writeAccessFlags(writer, method.getAccessFlags());
|
||||||
writer.write('\n');
|
writer.write(method.getName());
|
||||||
}
|
writer.write("(");
|
||||||
|
for (MethodParameter parameter: methodParameters) {
|
||||||
|
String type = parameter.getType();
|
||||||
|
writer.write(type);
|
||||||
|
parameterRegisterCount++;
|
||||||
|
if (TypeUtils.isWideType(type)) {
|
||||||
|
parameterRegisterCount++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
writer.write(")");
|
||||||
|
writer.write(method.getReturnType());
|
||||||
|
writer.write('\n');
|
||||||
|
|
||||||
|
writer.indent(4);
|
||||||
|
if (classDef.options.useLocalsDirective) {
|
||||||
|
writer.write(".locals ");
|
||||||
|
writer.printSignedIntAsDec(methodImpl.getRegisterCount() - parameterRegisterCount);
|
||||||
} else {
|
} else {
|
||||||
writeParameters(writer, codeItem, parameterAnnotations);
|
writer.write(".registers ");
|
||||||
if (annotationSet != null) {
|
writer.printSignedIntAsDec(methodImpl.getRegisterCount());
|
||||||
AnnotationFormatter.writeTo(writer, annotationSet);
|
}
|
||||||
|
writer.write('\n');
|
||||||
|
writeParameters(writer, method, methodParameters);
|
||||||
|
|
||||||
|
if (registerFormatter == null) {
|
||||||
|
registerFormatter = new RegisterFormatter(classDef.options, methodImpl.getRegisterCount(),
|
||||||
|
parameterRegisterCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnotationFormatter.writeTo(writer, method.getAnnotations());
|
||||||
|
|
||||||
|
writer.write('\n');
|
||||||
|
|
||||||
|
List<MethodItem> methodItems = getMethodItems();
|
||||||
|
for (MethodItem methodItem: methodItems) {
|
||||||
|
if (methodItem.writeTo(writer)) {
|
||||||
|
writer.write('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.deindent(4);
|
writer.deindent(4);
|
||||||
writer.write(".end method\n");
|
writer.write(".end method\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod)
|
private int findSwitchPayload(int targetOffset, Opcode type) {
|
||||||
{
|
int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
|
||||||
int totalRegisters = encodedMethod.codeItem.getRegisterCount();
|
|
||||||
if (baksmali.useLocalsDirective) {
|
//TODO: does dalvik let you pad with multiple nops?
|
||||||
int parameterRegisters = encodedMethod.method.getPrototype().getParameterRegisterCount();
|
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
|
||||||
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
|
|
||||||
parameterRegisters++;
|
Instruction instruction = instructions.get(targetIndex);
|
||||||
|
if (instruction.getOpcode() != type) {
|
||||||
|
// maybe it's pointing to a NOP padding instruction. Look at the next instruction
|
||||||
|
if (instruction.getOpcode() == Opcode.NOP) {
|
||||||
|
targetIndex += 1;
|
||||||
|
if (targetIndex < instructions.size()) {
|
||||||
|
instruction = instructions.get(targetIndex);
|
||||||
|
if (instruction.getOpcode() == type) {
|
||||||
|
return instructionOffsetMap.getInstructionCodeOffset(targetIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return totalRegisters - parameterRegisters;
|
throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset);
|
||||||
|
} else {
|
||||||
|
return targetOffset;
|
||||||
}
|
}
|
||||||
return totalRegisters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeAccessFlags(IndentingWriter writer, ClassDataItem.EncodedMethod encodedMethod)
|
private static void writeAccessFlags(IndentingWriter writer, int accessFlags)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) {
|
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(accessFlags)) {
|
||||||
writer.write(accessFlag.toString());
|
writer.write(accessFlag.toString());
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeParameters(IndentingWriter writer, CodeItem codeItem,
|
private static void writeParameters(IndentingWriter writer, Method method,
|
||||||
AnnotationSetRefList parameterAnnotations) throws IOException {
|
List<? extends MethodParameter> parameters) throws IOException {
|
||||||
DebugInfoItem debugInfoItem = null;
|
boolean isStatic = AccessFlags.STATIC.isSet(method.getAccessFlags());
|
||||||
if (baksmali.outputDebugInfo && codeItem != null) {
|
int registerNumber = isStatic?0:1;
|
||||||
debugInfoItem = codeItem.getDebugInfo();
|
for (MethodParameter parameter: parameters) {
|
||||||
}
|
String parameterType = parameter.getType();
|
||||||
|
String parameterName = parameter.getName();
|
||||||
|
Collection<? extends Annotation> annotations = parameter.getAnnotations();
|
||||||
|
if (parameterName != null || annotations.size() != 0) {
|
||||||
|
writer.write(".param p");
|
||||||
|
writer.printSignedIntAsDec(registerNumber);
|
||||||
|
|
||||||
int parameterCount = 0;
|
if (parameterName != null) {
|
||||||
AnnotationSetItem[] annotations;
|
writer.write(", ");
|
||||||
StringIdItem[] parameterNames = null;
|
ReferenceFormatter.writeStringReference(writer, parameterName);
|
||||||
|
}
|
||||||
if (parameterAnnotations != null) {
|
writer.write(" # ");
|
||||||
annotations = parameterAnnotations.getAnnotationSets();
|
writer.write(parameterType);
|
||||||
parameterCount = annotations.length;
|
writer.write("\n");
|
||||||
} else {
|
if (annotations.size() > 0) {
|
||||||
annotations = new AnnotationSetItem[0];
|
writer.indent(4);
|
||||||
}
|
AnnotationFormatter.writeTo(writer, annotations);
|
||||||
|
writer.deindent(4);
|
||||||
if (debugInfoItem != null) {
|
writer.write(".end param\n");
|
||||||
parameterNames = debugInfoItem.getParameterNames();
|
}
|
||||||
}
|
|
||||||
if (parameterNames == null) {
|
|
||||||
parameterNames = new StringIdItem[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parameterCount < parameterNames.length) {
|
|
||||||
parameterCount = parameterNames.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0; i<parameterCount; i++) {
|
|
||||||
AnnotationSetItem annotationSet = null;
|
|
||||||
if (i < annotations.length) {
|
|
||||||
annotationSet = annotations[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringIdItem parameterName = null;
|
registerNumber++;
|
||||||
if (i < parameterNames.length) {
|
if (TypeUtils.isWideType(parameterType)) {
|
||||||
parameterName = parameterNames[i];
|
registerNumber++;
|
||||||
}
|
|
||||||
|
|
||||||
writer.write(".parameter");
|
|
||||||
|
|
||||||
if (parameterName != null) {
|
|
||||||
writer.write(" \"");
|
|
||||||
writer.write(parameterName.getStringValue());
|
|
||||||
writer.write('"');
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.write('\n');
|
|
||||||
if (annotationSet != null) {
|
|
||||||
writer.indent(4);
|
|
||||||
AnnotationFormatter.writeTo(writer, annotationSet);
|
|
||||||
writer.deindent(4);
|
|
||||||
|
|
||||||
writer.write(".end parameter\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LabelCache getLabelCache() {
|
@Nonnull public LabelCache getLabelCache() {
|
||||||
return labelCache;
|
return labelCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValidationException getValidationException() {
|
public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) {
|
||||||
if (methodAnalyzer == null) {
|
return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return methodAnalyzer.getValidationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPackedSwitchBaseAddress(int packedSwitchDataAddress) {
|
public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) {
|
||||||
int packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress, -1);
|
return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1);
|
||||||
|
|
||||||
if (packedSwitchBaseAddress == -1) {
|
|
||||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
|
||||||
int index = instructionMap.get(packedSwitchDataAddress);
|
|
||||||
|
|
||||||
if (instructions[index].opcode == Opcode.NOP) {
|
|
||||||
packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress+2, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return packedSwitchBaseAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSparseSwitchBaseAddress(int sparseSwitchDataAddress) {
|
|
||||||
int sparseSwitchBaseAddress = this.sparseSwitchMap.get(sparseSwitchDataAddress, -1);
|
|
||||||
|
|
||||||
if (sparseSwitchBaseAddress == -1) {
|
|
||||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
|
||||||
int index = instructionMap.get(sparseSwitchDataAddress);
|
|
||||||
|
|
||||||
if (instructions[index].opcode == Opcode.NOP) {
|
|
||||||
sparseSwitchBaseAddress = this.packedSwitchMap.get(sparseSwitchDataAddress+2, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sparseSwitchBaseAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param instructions The instructions array for this method
|
|
||||||
* @param instruction The instruction
|
|
||||||
* @return true if the specified instruction is a NOP, and the next instruction is one of the variable sized
|
|
||||||
* switch/array data structures
|
|
||||||
*/
|
|
||||||
private boolean isInstructionPaddingNop(List<AnalyzedInstruction> instructions, AnalyzedInstruction instruction) {
|
|
||||||
if (instruction.getInstruction().opcode != Opcode.NOP ||
|
|
||||||
instruction.getInstruction().getFormat().variableSizeFormat) {
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instruction.getInstructionIndex() == instructions.size()-1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnalyzedInstruction nextInstruction = instructions.get(instruction.getInstructionIndex()+1);
|
|
||||||
if (nextInstruction.getInstruction().getFormat().variableSizeFormat) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean needsAnalyzed() {
|
|
||||||
for (Instruction instruction: encodedMethod.codeItem.getInstructions()) {
|
|
||||||
if (instruction.opcode.odexOnly()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MethodItem> getMethodItems() {
|
private List<MethodItem> getMethodItems() {
|
||||||
ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
|
ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
|
||||||
|
|
||||||
if (encodedMethod.codeItem == null) {
|
if ((classDef.options.registerInfo != 0) || (classDef.options.deodex && needsAnalyzed())) {
|
||||||
return methodItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((baksmali.registerInfo != 0) || baksmali.verify ||
|
|
||||||
(baksmali.deodex && needsAnalyzed())) {
|
|
||||||
addAnalyzedInstructionMethodItems(methodItems);
|
addAnalyzedInstructionMethodItems(methodItems);
|
||||||
} else {
|
} else {
|
||||||
addInstructionMethodItems(methodItems);
|
addInstructionMethodItems(methodItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTries(methodItems);
|
addTries(methodItems);
|
||||||
if (baksmali.outputDebugInfo) {
|
if (classDef.options.outputDebugInfo) {
|
||||||
addDebugInfo(methodItems);
|
addDebugInfo(methodItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baksmali.useSequentialLabels) {
|
if (classDef.options.useSequentialLabels) {
|
||||||
setLabelSequentialNumbers();
|
setLabelSequentialNumbers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,23 +290,30 @@ public class MethodDefinition {
|
|||||||
return methodItems;
|
return methodItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addInstructionMethodItems(List<MethodItem> methodItems) {
|
private boolean needsAnalyzed() {
|
||||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
for (Instruction instruction: methodImpl.getInstructions()) {
|
||||||
|
if (instruction.getOpcode().odexOnly()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addInstructionMethodItems(List<MethodItem> methodItems) {
|
||||||
int currentCodeAddress = 0;
|
int currentCodeAddress = 0;
|
||||||
for (int i=0; i<instructions.length; i++) {
|
for (int i=0; i<instructions.size(); i++) {
|
||||||
Instruction instruction = instructions[i];
|
Instruction instruction = instructions.get(i);
|
||||||
|
|
||||||
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
|
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
|
||||||
encodedMethod.codeItem, currentCodeAddress, instruction);
|
currentCodeAddress, instruction);
|
||||||
|
|
||||||
methodItems.add(methodItem);
|
methodItems.add(methodItem);
|
||||||
|
|
||||||
if (i != instructions.length - 1) {
|
if (i != instructions.size() - 1) {
|
||||||
methodItems.add(new BlankMethodItem(currentCodeAddress));
|
methodItems.add(new BlankMethodItem(currentCodeAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baksmali.addCodeOffsets) {
|
if (classDef.options.addCodeOffsets) {
|
||||||
methodItems.add(new MethodItem(currentCodeAddress) {
|
methodItems.add(new MethodItem(currentCodeAddress) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -358,20 +324,22 @@ public class MethodDefinition {
|
|||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
writer.write("#@");
|
writer.write("#@");
|
||||||
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
|
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
|
if (!classDef.options.noAccessorComments && (instruction instanceof ReferenceInstruction)) {
|
||||||
if (instruction.opcode == Opcode.INVOKE_STATIC || instruction.opcode == Opcode.INVOKE_STATIC_RANGE) {
|
Opcode opcode = instruction.getOpcode();
|
||||||
MethodIdItem methodIdItem =
|
|
||||||
(MethodIdItem)((InstructionWithReference) instruction).getReferencedItem();
|
|
||||||
|
|
||||||
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodIdItem)) {
|
if (opcode.referenceType == ReferenceType.METHOD) {
|
||||||
|
MethodReference methodReference =
|
||||||
|
(MethodReference)((ReferenceInstruction)instruction).getReference();
|
||||||
|
|
||||||
|
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
|
||||||
SyntheticAccessorResolver.AccessedMember accessedMember =
|
SyntheticAccessorResolver.AccessedMember accessedMember =
|
||||||
baksmali.syntheticAccessorResolver.getAccessedMember(methodIdItem);
|
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
|
||||||
if (accessedMember != null) {
|
if (accessedMember != null) {
|
||||||
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
|
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
|
||||||
}
|
}
|
||||||
@ -379,53 +347,45 @@ public class MethodDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCodeAddress += instruction.getSize(currentCodeAddress);
|
currentCodeAddress += instruction.getCodeUnits();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
|
private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
|
||||||
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
|
MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classDef.options.classPath, method,
|
||||||
|
classDef.options.inlineResolver);
|
||||||
|
|
||||||
methodAnalyzer.analyze();
|
AnalysisException analysisException = methodAnalyzer.getAnalysisException();
|
||||||
|
if (analysisException != null) {
|
||||||
ValidationException validationException = methodAnalyzer.getValidationException();
|
// TODO: need to keep track of whether any errors occurred, so we can exit with a non-zero result
|
||||||
if (validationException != null) {
|
|
||||||
methodItems.add(new CommentMethodItem(
|
methodItems.add(new CommentMethodItem(
|
||||||
String.format("ValidationException: %s" ,validationException.getMessage()),
|
String.format("AnalysisException: %s", analysisException.getMessage()),
|
||||||
validationException.getCodeAddress(), Integer.MIN_VALUE));
|
analysisException.codeAddress, Integer.MIN_VALUE));
|
||||||
} else if (baksmali.verify) {
|
analysisException.printStackTrace(System.err);
|
||||||
methodAnalyzer.verify();
|
|
||||||
|
|
||||||
validationException = methodAnalyzer.getValidationException();
|
|
||||||
if (validationException != null) {
|
|
||||||
methodItems.add(new CommentMethodItem(
|
|
||||||
String.format("ValidationException: %s" ,validationException.getMessage()),
|
|
||||||
validationException.getCodeAddress(), Integer.MIN_VALUE));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
|
List<AnalyzedInstruction> instructions = methodAnalyzer.getAnalyzedInstructions();
|
||||||
|
|
||||||
int currentCodeAddress = 0;
|
int currentCodeAddress = 0;
|
||||||
for (int i=0; i<instructions.size(); i++) {
|
for (int i=0; i<instructions.size(); i++) {
|
||||||
AnalyzedInstruction instruction = instructions.get(i);
|
AnalyzedInstruction instruction = instructions.get(i);
|
||||||
|
|
||||||
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
|
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(
|
||||||
encodedMethod.codeItem, currentCodeAddress, instruction.getInstruction());
|
this, currentCodeAddress, instruction.getInstruction());
|
||||||
|
|
||||||
methodItems.add(methodItem);
|
methodItems.add(methodItem);
|
||||||
|
|
||||||
if (instruction.getInstruction().getFormat() == Format.UnresolvedOdexInstruction) {
|
if (instruction.getInstruction().getOpcode().format == Format.UnresolvedOdexInstruction) {
|
||||||
methodItems.add(new CommentedOutMethodItem(
|
methodItems.add(new CommentedOutMethodItem(
|
||||||
InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
|
InstructionMethodItemFactory.makeInstructionFormatMethodItem(
|
||||||
encodedMethod.codeItem, currentCodeAddress, instruction.getOriginalInstruction())));
|
this, currentCodeAddress, instruction.getOriginalInstruction())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != instructions.size() - 1) {
|
if (i != instructions.size() - 1) {
|
||||||
methodItems.add(new BlankMethodItem(currentCodeAddress));
|
methodItems.add(new BlankMethodItem(currentCodeAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baksmali.addCodeOffsets) {
|
if (classDef.options.addCodeOffsets) {
|
||||||
methodItems.add(new MethodItem(currentCodeAddress) {
|
methodItems.add(new MethodItem(currentCodeAddress) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -436,36 +396,38 @@ public class MethodDefinition {
|
|||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
writer.write("#@");
|
writer.write("#@");
|
||||||
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
|
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baksmali.registerInfo != 0 && !instruction.getInstruction().getFormat().variableSizeFormat) {
|
if (classDef.options.registerInfo != 0 &&
|
||||||
|
!instruction.getInstruction().getOpcode().format.isPayloadFormat) {
|
||||||
methodItems.add(
|
methodItems.add(
|
||||||
new PreInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
|
new PreInstructionRegisterInfoMethodItem(classDef.options.registerInfo,
|
||||||
|
methodAnalyzer, registerFormatter, instruction, currentCodeAddress));
|
||||||
|
|
||||||
methodItems.add(
|
methodItems.add(
|
||||||
new PostInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
|
new PostInstructionRegisterInfoMethodItem(registerFormatter, instruction, currentCodeAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress);
|
currentCodeAddress += instruction.getInstruction().getCodeUnits();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addTries(List<MethodItem> methodItems) {
|
private void addTries(List<MethodItem> methodItems) {
|
||||||
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) {
|
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = methodImpl.getTryBlocks();
|
||||||
|
if (tryBlocks.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
|
||||||
int lastInstructionAddress = instructionMap.keyAt(instructionMap.size()-1);
|
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
|
||||||
int codeSize = lastInstructionAddress + instructions[instructions.length - 1].getSize(lastInstructionAddress);
|
|
||||||
|
|
||||||
for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) {
|
for (TryBlock<? extends ExceptionHandler> tryBlock: tryBlocks) {
|
||||||
int startAddress = tryItem.getStartCodeAddress();
|
int startAddress = tryBlock.getStartCodeAddress();
|
||||||
int endAddress = tryItem.getStartCodeAddress() + tryItem.getTryLength();
|
int endAddress = startAddress + tryBlock.getCodeUnitCount();
|
||||||
|
|
||||||
if (startAddress >= codeSize) {
|
if (startAddress >= codeSize) {
|
||||||
throw new RuntimeException(String.format("Try start offset %d is past the end of the code block.",
|
throw new RuntimeException(String.format("Try start offset %d is past the end of the code block.",
|
||||||
@ -484,142 +446,28 @@ public class MethodDefinition {
|
|||||||
* the address for that instruction
|
* the address for that instruction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int lastCoveredIndex = instructionMap.getClosestSmaller(endAddress-1);
|
int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false);
|
||||||
int lastCoveredAddress = instructionMap.keyAt(lastCoveredIndex);
|
int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex);
|
||||||
|
|
||||||
//add the catch all handler if it exists
|
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
|
||||||
int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
|
int handlerAddress = handler.getHandlerCodeAddress();
|
||||||
if (catchAllAddress != -1) {
|
if (handlerAddress >= codeSize) {
|
||||||
if (catchAllAddress >= codeSize) {
|
throw new ExceptionWithContext(
|
||||||
throw new RuntimeException(String.format(
|
"Exception handler offset %d is past the end of the code block.", handlerAddress);
|
||||||
"Catch all handler offset %d is past the end of the code block.", catchAllAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
CatchMethodItem catchAllMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress, null,
|
|
||||||
startAddress, endAddress, catchAllAddress);
|
|
||||||
methodItems.add(catchAllMethodItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add the rest of the handlers
|
|
||||||
for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
|
|
||||||
if (handler.getHandlerAddress() >= codeSize) {
|
|
||||||
throw new RuntimeException(String.format(
|
|
||||||
"Exception handler offset %d is past the end of the code block.", catchAllAddress));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//use the address from the last covered instruction
|
//use the address from the last covered instruction
|
||||||
CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress,
|
CatchMethodItem catchMethodItem = new CatchMethodItem(classDef.options, labelCache, lastCoveredAddress,
|
||||||
handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress());
|
handler.getExceptionType(), startAddress, endAddress, handlerAddress);
|
||||||
methodItems.add(catchMethodItem);
|
methodItems.add(catchMethodItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDebugInfo(final List<MethodItem> methodItems) {
|
private void addDebugInfo(final List<MethodItem> methodItems) {
|
||||||
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getDebugInfo() == null) {
|
for (DebugItem debugItem: methodImpl.getDebugItems()) {
|
||||||
return;
|
methodItems.add(DebugMethodItem.build(registerFormatter, debugItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
final CodeItem codeItem = encodedMethod.codeItem;
|
|
||||||
DebugInfoItem debugInfoItem = codeItem.getDebugInfo();
|
|
||||||
|
|
||||||
DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(),
|
|
||||||
new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() {
|
|
||||||
@Override
|
|
||||||
public void ProcessStartLocal(final int codeAddress, final int length, final int registerNum,
|
|
||||||
final StringIdItem name, final TypeIdItem type) {
|
|
||||||
methodItems.add(new DebugMethodItem(codeAddress, -1) {
|
|
||||||
@Override
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
|
||||||
writeStartLocal(writer, codeItem, registerNum, name, type, null);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ProcessStartLocalExtended(final int codeAddress, final int length,
|
|
||||||
final int registerNum, final StringIdItem name,
|
|
||||||
final TypeIdItem type, final StringIdItem signature) {
|
|
||||||
methodItems.add(new DebugMethodItem(codeAddress, -1) {
|
|
||||||
@Override
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
|
||||||
writeStartLocal(writer, codeItem, registerNum, name, type, signature);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ProcessEndLocal(final int codeAddress, final int length, final int registerNum,
|
|
||||||
final StringIdItem name, final TypeIdItem type,
|
|
||||||
final StringIdItem signature) {
|
|
||||||
methodItems.add(new DebugMethodItem(codeAddress, -1) {
|
|
||||||
@Override
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
|
||||||
writeEndLocal(writer, codeItem, registerNum, name, type, signature);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ProcessRestartLocal(final int codeAddress, final int length, final int registerNum,
|
|
||||||
final StringIdItem name, final TypeIdItem type,
|
|
||||||
final StringIdItem signature) {
|
|
||||||
methodItems.add(new DebugMethodItem(codeAddress, -1) {
|
|
||||||
@Override
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
|
||||||
writeRestartLocal(writer, codeItem, registerNum, name, type, signature);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ProcessSetPrologueEnd(int codeAddress) {
|
|
||||||
methodItems.add(new DebugMethodItem(codeAddress, -4) {
|
|
||||||
@Override
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
|
||||||
writeEndPrologue(writer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ProcessSetEpilogueBegin(int codeAddress) {
|
|
||||||
methodItems.add(new DebugMethodItem(codeAddress, -4) {
|
|
||||||
@Override
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
|
||||||
writeBeginEpilogue(writer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) {
|
|
||||||
methodItems.add(new DebugMethodItem(codeAddress, -3) {
|
|
||||||
@Override
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
|
||||||
writeSetFile(writer, name.getStringValue());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ProcessLineEmit(int codeAddress, final int line) {
|
|
||||||
methodItems.add(new DebugMethodItem(codeAddress, -2) {
|
|
||||||
@Override
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
|
||||||
writeLine(writer, line);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setLabelSequentialNumbers() {
|
private void setLabelSequentialNumbers() {
|
||||||
|
@ -28,26 +28,25 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
|
import org.jf.dexlib2.analysis.AnalyzedInstruction;
|
||||||
|
import org.jf.dexlib2.analysis.RegisterType;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.baksmali;
|
|
||||||
import org.jf.baksmali.main;
|
|
||||||
import org.jf.dexlib.ClassDataItem;
|
|
||||||
import org.jf.dexlib.Code.Analysis.AnalyzedInstruction;
|
|
||||||
import org.jf.dexlib.Code.Analysis.MethodAnalyzer;
|
|
||||||
import org.jf.dexlib.Code.Analysis.RegisterType;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
|
||||||
public class PostInstructionRegisterInfoMethodItem extends MethodItem {
|
public class PostInstructionRegisterInfoMethodItem extends MethodItem {
|
||||||
private final AnalyzedInstruction analyzedInstruction;
|
@Nonnull private final RegisterFormatter registerFormatter;
|
||||||
private final MethodAnalyzer methodAnalyzer;
|
@Nonnull private final AnalyzedInstruction analyzedInstruction;
|
||||||
|
|
||||||
public PostInstructionRegisterInfoMethodItem(AnalyzedInstruction analyzedInstruction, MethodAnalyzer methodAnalyzer,
|
public PostInstructionRegisterInfoMethodItem(@Nonnull RegisterFormatter registerFormatter,
|
||||||
int codeAddress) {
|
@Nonnull AnalyzedInstruction analyzedInstruction,
|
||||||
|
int codeAddress) {
|
||||||
super(codeAddress);
|
super(codeAddress);
|
||||||
|
this.registerFormatter = registerFormatter;
|
||||||
this.analyzedInstruction = analyzedInstruction;
|
this.analyzedInstruction = analyzedInstruction;
|
||||||
this.methodAnalyzer = methodAnalyzer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -57,16 +56,16 @@ public class PostInstructionRegisterInfoMethodItem extends MethodItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
int registerInfo = baksmali.registerInfo;
|
int registerInfo = registerFormatter.options.registerInfo;
|
||||||
int registerCount = analyzedInstruction.getRegisterCount();
|
int registerCount = analyzedInstruction.getRegisterCount();
|
||||||
BitSet registers = new BitSet(registerCount);
|
BitSet registers = new BitSet(registerCount);
|
||||||
|
|
||||||
if ((registerInfo & main.ALL) != 0) {
|
if ((registerInfo & baksmaliOptions.ALL) != 0) {
|
||||||
registers.set(0, registerCount);
|
registers.set(0, registerCount);
|
||||||
} else {
|
} else {
|
||||||
if ((registerInfo & main.ALLPOST) != 0) {
|
if ((registerInfo & baksmaliOptions.ALLPOST) != 0) {
|
||||||
registers.set(0, registerCount);
|
registers.set(0, registerCount);
|
||||||
} else if ((registerInfo & main.DEST) != 0) {
|
} else if ((registerInfo & baksmaliOptions.DEST) != 0) {
|
||||||
addDestRegs(registers, registerCount);
|
addDestRegs(registers, registerCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,16 +75,14 @@ public class PostInstructionRegisterInfoMethodItem extends MethodItem {
|
|||||||
|
|
||||||
private void addDestRegs(BitSet printPostRegister, int registerCount) {
|
private void addDestRegs(BitSet printPostRegister, int registerCount) {
|
||||||
for (int registerNum=0; registerNum<registerCount; registerNum++) {
|
for (int registerNum=0; registerNum<registerCount; registerNum++) {
|
||||||
if (analyzedInstruction.getPreInstructionRegisterType(registerNum) !=
|
if (!analyzedInstruction.getPreInstructionRegisterType(registerNum).equals(
|
||||||
analyzedInstruction.getPostInstructionRegisterType(registerNum)) {
|
analyzedInstruction.getPostInstructionRegisterType(registerNum))) {
|
||||||
printPostRegister.set(registerNum);
|
printPostRegister.set(registerNum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers) throws IOException {
|
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers) throws IOException {
|
||||||
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
|
|
||||||
|
|
||||||
int registerNum = registers.nextSetBit(0);
|
int registerNum = registers.nextSetBit(0);
|
||||||
if (registerNum < 0) {
|
if (registerNum < 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -93,17 +90,11 @@ public class PostInstructionRegisterInfoMethodItem extends MethodItem {
|
|||||||
|
|
||||||
writer.write('#');
|
writer.write('#');
|
||||||
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
|
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
|
||||||
|
|
||||||
RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum);
|
RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum);
|
||||||
|
|
||||||
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
|
registerFormatter.writeTo(writer, registerNum);
|
||||||
writer.write('=');
|
writer.write('=');
|
||||||
|
registerType.writeTo(writer);
|
||||||
if (registerType == null) {
|
|
||||||
writer.write("null");
|
|
||||||
} else {
|
|
||||||
registerType.writeTo(writer);
|
|
||||||
}
|
|
||||||
writer.write(';');
|
writer.write(';');
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -28,30 +28,33 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
|
import org.jf.dexlib2.analysis.AnalyzedInstruction;
|
||||||
|
import org.jf.dexlib2.analysis.MethodAnalyzer;
|
||||||
|
import org.jf.dexlib2.analysis.RegisterType;
|
||||||
|
import org.jf.dexlib2.iface.instruction.*;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.baksmali;
|
|
||||||
import org.jf.baksmali.main;
|
|
||||||
import org.jf.dexlib.ClassDataItem;
|
|
||||||
import org.jf.dexlib.Code.Analysis.AnalyzedInstruction;
|
|
||||||
import org.jf.dexlib.Code.Analysis.MethodAnalyzer;
|
|
||||||
import org.jf.dexlib.Code.Analysis.RegisterType;
|
|
||||||
import org.jf.dexlib.Code.*;
|
|
||||||
import org.jf.dexlib.Util.AccessFlags;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
|
||||||
public class PreInstructionRegisterInfoMethodItem extends MethodItem {
|
public class PreInstructionRegisterInfoMethodItem extends MethodItem {
|
||||||
private static AnalyzedInstruction lastInstruction;
|
private final int registerInfo;
|
||||||
|
@Nonnull private final MethodAnalyzer methodAnalyzer;
|
||||||
private final AnalyzedInstruction analyzedInstruction;
|
@Nonnull private final RegisterFormatter registerFormatter;
|
||||||
private final MethodAnalyzer methodAnalyzer;
|
@Nonnull private final AnalyzedInstruction analyzedInstruction;
|
||||||
|
|
||||||
public PreInstructionRegisterInfoMethodItem(AnalyzedInstruction analyzedInstruction, MethodAnalyzer methodAnalyzer,
|
public PreInstructionRegisterInfoMethodItem(int registerInfo,
|
||||||
|
@Nonnull MethodAnalyzer methodAnalyzer,
|
||||||
|
@Nonnull RegisterFormatter registerFormatter,
|
||||||
|
@Nonnull AnalyzedInstruction analyzedInstruction,
|
||||||
int codeAddress) {
|
int codeAddress) {
|
||||||
super(codeAddress);
|
super(codeAddress);
|
||||||
this.analyzedInstruction = analyzedInstruction;
|
this.registerInfo = registerInfo;
|
||||||
this.methodAnalyzer = methodAnalyzer;
|
this.methodAnalyzer = methodAnalyzer;
|
||||||
|
this.registerFormatter = registerFormatter;
|
||||||
|
this.analyzedInstruction = analyzedInstruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -61,39 +64,44 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
int registerInfo = baksmali.registerInfo;
|
|
||||||
int registerCount = analyzedInstruction.getRegisterCount();
|
int registerCount = analyzedInstruction.getRegisterCount();
|
||||||
BitSet registers = new BitSet(registerCount);
|
BitSet registers = new BitSet(registerCount);
|
||||||
|
BitSet mergeRegisters = null;
|
||||||
|
|
||||||
if ((registerInfo & main.ALL) != 0) {
|
if ((registerInfo & baksmaliOptions.ALL) != 0) {
|
||||||
registers.set(0, registerCount);
|
registers.set(0, registerCount);
|
||||||
} else {
|
} else {
|
||||||
if ((registerInfo & main.ALLPRE) != 0) {
|
if ((registerInfo & baksmaliOptions.ALLPRE) != 0) {
|
||||||
registers.set(0, registerCount);
|
registers.set(0, registerCount);
|
||||||
} else {
|
} else {
|
||||||
if ((registerInfo & main.ARGS) != 0) {
|
if ((registerInfo & baksmaliOptions.ARGS) != 0) {
|
||||||
addArgsRegs(registers);
|
addArgsRegs(registers);
|
||||||
}
|
}
|
||||||
if ((registerInfo & main.DIFFPRE) != 0) {
|
if ((registerInfo & baksmaliOptions.MERGE) != 0) {
|
||||||
addDiffRegs(registers);
|
if (analyzedInstruction.isBeginningInstruction()) {
|
||||||
}
|
addParamRegs(registers, registerCount);
|
||||||
if ((registerInfo & main.MERGE) != 0) {
|
}
|
||||||
addMergeRegs(registers, registerCount);
|
mergeRegisters = new BitSet(registerCount);
|
||||||
} else if ((registerInfo & main.FULLMERGE) != 0 &&
|
addMergeRegs(mergeRegisters, registerCount);
|
||||||
|
} else if ((registerInfo & baksmaliOptions.FULLMERGE) != 0 &&
|
||||||
(analyzedInstruction.isBeginningInstruction())) {
|
(analyzedInstruction.isBeginningInstruction())) {
|
||||||
addParamRegs(registers, registerCount);
|
addParamRegs(registers, registerCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean printedSomething = false;
|
if ((registerInfo & baksmaliOptions.FULLMERGE) != 0) {
|
||||||
if ((registerInfo & main.FULLMERGE) != 0) {
|
if (mergeRegisters == null) {
|
||||||
printedSomething = writeFullMergeRegs(writer, registers, registerCount);
|
mergeRegisters = new BitSet(registerCount);
|
||||||
|
addMergeRegs(mergeRegisters, registerCount);
|
||||||
|
}
|
||||||
|
registers.or(mergeRegisters);
|
||||||
|
} else if (mergeRegisters != null) {
|
||||||
|
registers.or(mergeRegisters);
|
||||||
|
mergeRegisters = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
printedSomething |= writeRegisterInfo(writer, registers, printedSomething);
|
return writeRegisterInfo(writer, registers, mergeRegisters);
|
||||||
|
|
||||||
return printedSomething;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addArgsRegs(BitSet registers) {
|
private void addArgsRegs(BitSet registers) {
|
||||||
@ -101,25 +109,25 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
|
|||||||
RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction();
|
RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction();
|
||||||
|
|
||||||
registers.set(instruction.getStartRegister(),
|
registers.set(instruction.getStartRegister(),
|
||||||
instruction.getStartRegister() + instruction.getRegCount());
|
instruction.getStartRegister() + instruction.getRegisterCount());
|
||||||
} else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) {
|
} else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) {
|
||||||
FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction();
|
FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction();
|
||||||
int regCount = instruction.getRegCount();
|
int regCount = instruction.getRegisterCount();
|
||||||
switch (regCount) {
|
switch (regCount) {
|
||||||
case 5:
|
case 5:
|
||||||
registers.set(instruction.getRegisterA());
|
|
||||||
//fall through
|
|
||||||
case 4:
|
|
||||||
registers.set(instruction.getRegisterG());
|
registers.set(instruction.getRegisterG());
|
||||||
//fall through
|
//fall through
|
||||||
case 3:
|
case 4:
|
||||||
registers.set(instruction.getRegisterF());
|
registers.set(instruction.getRegisterF());
|
||||||
//fall through
|
//fall through
|
||||||
case 2:
|
case 3:
|
||||||
registers.set(instruction.getRegisterE());
|
registers.set(instruction.getRegisterE());
|
||||||
//fall through
|
//fall through
|
||||||
case 1:
|
case 2:
|
||||||
registers.set(instruction.getRegisterD());
|
registers.set(instruction.getRegisterD());
|
||||||
|
//fall through
|
||||||
|
case 1:
|
||||||
|
registers.set(instruction.getRegisterC());
|
||||||
}
|
}
|
||||||
} else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) {
|
} else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) {
|
||||||
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction();
|
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction();
|
||||||
@ -130,30 +138,13 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
|
|||||||
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction();
|
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction();
|
||||||
registers.set(instruction.getRegisterA());
|
registers.set(instruction.getRegisterA());
|
||||||
registers.set(instruction.getRegisterB());
|
registers.set(instruction.getRegisterB());
|
||||||
} else if (analyzedInstruction.getInstruction() instanceof SingleRegisterInstruction) {
|
} else if (analyzedInstruction.getInstruction() instanceof OneRegisterInstruction) {
|
||||||
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.getInstruction();
|
OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.getInstruction();
|
||||||
registers.set(instruction.getRegisterA());
|
registers.set(instruction.getRegisterA());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDiffRegs(BitSet registers) {
|
|
||||||
if (!analyzedInstruction.isBeginningInstruction()) {
|
|
||||||
for (int i = 0; i < analyzedInstruction.getRegisterCount(); i++) {
|
|
||||||
|
|
||||||
if (lastInstruction.getPreInstructionRegisterType(i).category
|
|
||||||
!= analyzedInstruction.getPreInstructionRegisterType(i).category) {
|
|
||||||
registers.set(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastInstruction = analyzedInstruction;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addMergeRegs(BitSet registers, int registerCount) {
|
private void addMergeRegs(BitSet registers, int registerCount) {
|
||||||
if (analyzedInstruction.isBeginningInstruction()) {
|
|
||||||
addParamRegs(registers, registerCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (analyzedInstruction.getPredecessorCount() <= 1) {
|
if (analyzedInstruction.getPredecessorCount() <= 1) {
|
||||||
//in the common case of an instruction that only has a single predecessor which is the previous
|
//in the common case of an instruction that only has a single predecessor which is the previous
|
||||||
//instruction, the pre-instruction registers will always match the previous instruction's
|
//instruction, the pre-instruction registers will always match the previous instruction's
|
||||||
@ -165,118 +156,86 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
|
|||||||
RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
|
RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
|
||||||
|
|
||||||
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
|
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
|
||||||
if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) {
|
RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
|
||||||
|
if (predecessorRegisterType.category != RegisterType.UNKNOWN &&
|
||||||
|
!predecessorRegisterType.equals(mergedRegisterType)) {
|
||||||
registers.set(registerNum);
|
registers.set(registerNum);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addParamRegs(BitSet registers, int registerCount) {
|
private void addParamRegs(BitSet registers, int registerCount) {
|
||||||
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
|
int parameterRegisterCount = methodAnalyzer.getParamRegisterCount();
|
||||||
int parameterRegisterCount = encodedMethod.method.getPrototype().getParameterRegisterCount();
|
|
||||||
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
|
|
||||||
parameterRegisterCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
registers.set(registerCount-parameterRegisterCount, registerCount);
|
registers.set(registerCount-parameterRegisterCount, registerCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean writeFullMergeRegs(IndentingWriter writer, BitSet registers, int registerCount)
|
private void writeFullMerge(IndentingWriter writer, int registerNum) throws IOException {
|
||||||
throws IOException {
|
registerFormatter.writeTo(writer, registerNum);
|
||||||
if (analyzedInstruction.getPredecessorCount() <= 1) {
|
writer.write('=');
|
||||||
return false;
|
analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer);
|
||||||
}
|
writer.write(":merge{");
|
||||||
|
|
||||||
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
|
boolean first = true;
|
||||||
|
|
||||||
boolean firstRegister = true;
|
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
|
||||||
|
RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
|
||||||
|
|
||||||
for (int registerNum=0; registerNum<registerCount; registerNum++) {
|
if (!first) {
|
||||||
RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
|
writer.write(',');
|
||||||
boolean addRegister = false;
|
|
||||||
|
|
||||||
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
|
|
||||||
RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
|
|
||||||
if (predecessorRegisterType.category != RegisterType.Category.Unknown &&
|
|
||||||
predecessorRegisterType != mergedRegisterType) {
|
|
||||||
|
|
||||||
addRegister = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!addRegister) {
|
if (predecessor.getInstructionIndex() == -1) {
|
||||||
continue;
|
//the fake "StartOfMethod" instruction
|
||||||
}
|
writer.write("Start:");
|
||||||
|
|
||||||
if (firstRegister) {
|
|
||||||
firstRegister = false;
|
|
||||||
} else {
|
} else {
|
||||||
writer.write('\n');
|
writer.write("0x");
|
||||||
|
writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor));
|
||||||
|
writer.write(':');
|
||||||
}
|
}
|
||||||
|
predecessorRegisterType.writeTo(writer);
|
||||||
|
|
||||||
writer.write('#');
|
first = false;
|
||||||
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
|
|
||||||
writer.write('=');
|
|
||||||
analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer);
|
|
||||||
writer.write(":merge{");
|
|
||||||
|
|
||||||
boolean first = true;
|
|
||||||
|
|
||||||
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
|
|
||||||
RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
|
|
||||||
|
|
||||||
if (!first) {
|
|
||||||
writer.write(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (predecessor.getInstructionIndex() == -1) {
|
|
||||||
//the fake "StartOfMethod" instruction
|
|
||||||
writer.write("Start:");
|
|
||||||
} else {
|
|
||||||
writer.write("0x");
|
|
||||||
writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor));
|
|
||||||
writer.write(':');
|
|
||||||
}
|
|
||||||
predecessorRegisterType.writeTo(writer);
|
|
||||||
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
writer.write('}');
|
|
||||||
|
|
||||||
registers.clear(registerNum);
|
|
||||||
}
|
}
|
||||||
return !firstRegister;
|
writer.write('}');
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers,
|
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers,
|
||||||
boolean addNewline) throws IOException {
|
BitSet fullMergeRegisters) throws IOException {
|
||||||
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
|
boolean firstRegister = true;
|
||||||
|
boolean previousWasFullMerge = false;
|
||||||
int registerNum = registers.nextSetBit(0);
|
int registerNum = registers.nextSetBit(0);
|
||||||
if (registerNum < 0) {
|
if (registerNum < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addNewline) {
|
|
||||||
writer.write('\n');
|
|
||||||
}
|
|
||||||
writer.write('#');
|
writer.write('#');
|
||||||
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
|
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
|
||||||
|
boolean fullMerge = fullMergeRegisters!=null && fullMergeRegisters.get(registerNum);
|
||||||
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
|
if (fullMerge) {
|
||||||
|
if (!firstRegister) {
|
||||||
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
|
writer.write('\n');
|
||||||
writer.write('=');
|
writer.write('#');
|
||||||
|
}
|
||||||
if (registerType == null) {
|
writeFullMerge(writer, registerNum);
|
||||||
writer.write("null");
|
previousWasFullMerge = true;
|
||||||
} else {
|
} else {
|
||||||
|
if (previousWasFullMerge) {
|
||||||
|
writer.write('\n');
|
||||||
|
writer.write('#');
|
||||||
|
previousWasFullMerge = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
|
||||||
|
|
||||||
|
registerFormatter.writeTo(writer, registerNum);
|
||||||
|
writer.write('=');
|
||||||
|
|
||||||
registerType.writeTo(writer);
|
registerType.writeTo(writer);
|
||||||
|
writer.write(';');
|
||||||
}
|
}
|
||||||
writer.write(';');
|
|
||||||
|
firstRegister = false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -28,52 +28,35 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.dexlib2.ReferenceType;
|
||||||
|
import org.jf.dexlib2.iface.reference.*;
|
||||||
|
import org.jf.dexlib2.util.ReferenceUtil;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.*;
|
import org.jf.util.StringUtils;
|
||||||
import org.jf.dexlib.Util.Utf8Utils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class ReferenceFormatter {
|
public class ReferenceFormatter {
|
||||||
public static void writeReference(IndentingWriter writer, Item item) throws IOException {
|
public static void writeStringReference(IndentingWriter writer, String item) throws IOException {
|
||||||
switch (item.getItemType()) {
|
writer.write('"');
|
||||||
case TYPE_METHOD_ID_ITEM:
|
StringUtils.writeEscapedString(writer, item);
|
||||||
writeMethodReference(writer, (MethodIdItem)item);
|
writer.write('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeReference(IndentingWriter writer, int referenceType,
|
||||||
|
Reference reference) throws IOException {
|
||||||
|
switch (referenceType) {
|
||||||
|
case ReferenceType.STRING:
|
||||||
|
writeStringReference(writer, ((StringReference)reference).getString());
|
||||||
return;
|
return;
|
||||||
case TYPE_FIELD_ID_ITEM:
|
case ReferenceType.TYPE:
|
||||||
writeFieldReference(writer, (FieldIdItem)item);
|
writer.write(((TypeReference)reference).getType());
|
||||||
return;
|
return;
|
||||||
case TYPE_STRING_ID_ITEM:
|
case ReferenceType.METHOD:
|
||||||
writeStringReference(writer, (StringIdItem)item);
|
ReferenceUtil.writeMethodDescriptor(writer, (MethodReference)reference);
|
||||||
return;
|
|
||||||
case TYPE_TYPE_ID_ITEM:
|
|
||||||
writeTypeReference(writer, (TypeIdItem)item);
|
|
||||||
return;
|
return;
|
||||||
|
case ReferenceType.FIELD:
|
||||||
|
ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeMethodReference(IndentingWriter writer, MethodIdItem item) throws IOException {
|
|
||||||
writer.write(item.getContainingClass().getTypeDescriptor());
|
|
||||||
writer.write("->");
|
|
||||||
writer.write(item.getMethodName().getStringValue());
|
|
||||||
writer.write(item.getPrototype().getPrototypeString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeFieldReference(IndentingWriter writer, FieldIdItem item) throws IOException {
|
|
||||||
writer.write(item.getContainingClass().getTypeDescriptor());
|
|
||||||
writer.write("->");
|
|
||||||
writer.write(item.getFieldName().getStringValue());
|
|
||||||
writer.write(':');
|
|
||||||
writer.write(item.getFieldType().getTypeDescriptor());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeStringReference(IndentingWriter writer, StringIdItem item) throws IOException {
|
|
||||||
writer.write('"');
|
|
||||||
Utf8Utils.writeEscapedString(writer, item.getStringValue());
|
|
||||||
writer.write('"');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeTypeReference(IndentingWriter writer, TypeIdItem item) throws IOException {
|
|
||||||
writer.write(item.getTypeDescriptor());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -28,17 +28,25 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.baksmali.baksmaliOptions;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.baksmali;
|
|
||||||
import org.jf.dexlib.CodeItem;
|
|
||||||
import org.jf.dexlib.Util.AccessFlags;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class contains the logic used for formatting registers
|
* This class contains the logic used for formatting registers
|
||||||
*/
|
*/
|
||||||
public class RegisterFormatter {
|
public class RegisterFormatter {
|
||||||
|
@Nonnull public final baksmaliOptions options;
|
||||||
|
public final int registerCount;
|
||||||
|
public final int parameterRegisterCount;
|
||||||
|
|
||||||
|
public RegisterFormatter(@Nonnull baksmaliOptions options, int registerCount, int parameterRegisterCount) {
|
||||||
|
this.options = options;
|
||||||
|
this.registerCount = registerCount;
|
||||||
|
this.parameterRegisterCount = parameterRegisterCount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write out the register range value used by Format3rc. If baksmali.noParameterRegisters is true, it will always
|
* Write out the register range value used by Format3rc. If baksmali.noParameterRegisters is true, it will always
|
||||||
@ -46,19 +54,11 @@ public class RegisterFormatter {
|
|||||||
* registers, and if so, use the p<n> format for both. If only the last register is a parameter register, it will
|
* registers, and if so, use the p<n> format for both. If only the last register is a parameter register, it will
|
||||||
* use the v<n> format for both, otherwise it would be confusing to have something like {v20 .. p1}
|
* use the v<n> format for both, otherwise it would be confusing to have something like {v20 .. p1}
|
||||||
* @param writer the <code>IndentingWriter</code> to write to
|
* @param writer the <code>IndentingWriter</code> to write to
|
||||||
* @param codeItem the <code>CodeItem</code> that the register is from
|
|
||||||
* @param startRegister the first register in the range
|
* @param startRegister the first register in the range
|
||||||
* @param lastRegister the last register in the range
|
* @param lastRegister the last register in the range
|
||||||
*/
|
*/
|
||||||
public static void writeRegisterRange(IndentingWriter writer, CodeItem codeItem, int startRegister,
|
public void writeRegisterRange(IndentingWriter writer, int startRegister, int lastRegister) throws IOException {
|
||||||
int lastRegister) throws IOException {
|
if (!options.noParameterRegisters) {
|
||||||
assert lastRegister >= startRegister;
|
|
||||||
|
|
||||||
if (!baksmali.noParameterRegisters) {
|
|
||||||
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
|
|
||||||
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
|
|
||||||
int registerCount = codeItem.getRegisterCount();
|
|
||||||
|
|
||||||
assert startRegister <= lastRegister;
|
assert startRegister <= lastRegister;
|
||||||
|
|
||||||
if (startRegister >= registerCount - parameterRegisterCount) {
|
if (startRegister >= registerCount - parameterRegisterCount) {
|
||||||
@ -83,14 +83,10 @@ public class RegisterFormatter {
|
|||||||
* and if so, formats it in the p<n> format instead.
|
* and if so, formats it in the p<n> format instead.
|
||||||
*
|
*
|
||||||
* @param writer the <code>IndentingWriter</code> to write to
|
* @param writer the <code>IndentingWriter</code> to write to
|
||||||
* @param codeItem the <code>CodeItem</code> that the register is from
|
|
||||||
* @param register the register number
|
* @param register the register number
|
||||||
*/
|
*/
|
||||||
public static void writeTo(IndentingWriter writer, CodeItem codeItem, int register) throws IOException {
|
public void writeTo(IndentingWriter writer, int register) throws IOException {
|
||||||
if (!baksmali.noParameterRegisters) {
|
if (!options.noParameterRegisters) {
|
||||||
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
|
|
||||||
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
|
|
||||||
int registerCount = codeItem.getRegisterCount();
|
|
||||||
if (register >= registerCount - parameterRegisterCount) {
|
if (register >= registerCount - parameterRegisterCount) {
|
||||||
writer.write('p');
|
writer.write('p');
|
||||||
writer.printSignedIntAsDec((register - (registerCount - parameterRegisterCount)));
|
writer.printSignedIntAsDec((register - (registerCount - parameterRegisterCount)));
|
||||||
|
@ -28,16 +28,17 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import static org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver.AccessedMember;
|
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class SyntheticAccessCommentMethodItem extends MethodItem {
|
public class SyntheticAccessCommentMethodItem extends MethodItem {
|
||||||
private final AccessedMember accessedMember;
|
private final SyntheticAccessorResolver.AccessedMember accessedMember;
|
||||||
|
|
||||||
public SyntheticAccessCommentMethodItem(AccessedMember accessedMember, int codeAddress) {
|
public SyntheticAccessCommentMethodItem(SyntheticAccessorResolver.AccessedMember accessedMember, int codeAddress) {
|
||||||
super(codeAddress);
|
super(codeAddress);
|
||||||
this.accessedMember = accessedMember;
|
this.accessedMember = accessedMember;
|
||||||
}
|
}
|
||||||
@ -48,15 +49,73 @@ public class SyntheticAccessCommentMethodItem extends MethodItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
writer.write('#');
|
writer.write("# ");
|
||||||
if (accessedMember.accessedMemberType == SyntheticAccessorResolver.METHOD) {
|
switch (accessedMember.accessedMemberType) {
|
||||||
writer.write("calls: ");
|
case SyntheticAccessorResolver.METHOD:
|
||||||
} else if (accessedMember.accessedMemberType == SyntheticAccessorResolver.GETTER) {
|
writer.write("invokes: ");
|
||||||
writer.write("getter for: ");
|
break;
|
||||||
} else {
|
case SyntheticAccessorResolver.GETTER:
|
||||||
writer.write("setter for: ");
|
writer.write("getter for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.SETTER:
|
||||||
|
writer.write("setter for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.PREFIX_INCREMENT:
|
||||||
|
writer.write("++operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.POSTFIX_INCREMENT:
|
||||||
|
writer.write("operator++ for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.PREFIX_DECREMENT:
|
||||||
|
writer.write("--operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.POSTFIX_DECREMENT:
|
||||||
|
writer.write("operator-- for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.ADD_ASSIGNMENT:
|
||||||
|
writer.write("+= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.SUB_ASSIGNMENT:
|
||||||
|
writer.write("-= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.MUL_ASSIGNMENT:
|
||||||
|
writer.write("*= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.DIV_ASSIGNMENT:
|
||||||
|
writer.write("/= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.REM_ASSIGNMENT:
|
||||||
|
writer.write("%= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.AND_ASSIGNMENT:
|
||||||
|
writer.write("&= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.OR_ASSIGNMENT:
|
||||||
|
writer.write("|= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.XOR_ASSIGNMENT:
|
||||||
|
writer.write("^= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.SHL_ASSIGNMENT:
|
||||||
|
writer.write("<<= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.SHR_ASSIGNMENT:
|
||||||
|
writer.write(">>= operator for: ");
|
||||||
|
break;
|
||||||
|
case SyntheticAccessorResolver.USHR_ASSIGNMENT:
|
||||||
|
writer.write(">>>= operator for: ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ExceptionWithContext("Unknown access type: %d", accessedMember.accessedMemberType);
|
||||||
}
|
}
|
||||||
ReferenceFormatter.writeReference(writer, accessedMember.accessedMember);
|
|
||||||
|
int referenceType;
|
||||||
|
if (accessedMember.accessedMemberType == SyntheticAccessorResolver.METHOD) {
|
||||||
|
referenceType = ReferenceType.METHOD;
|
||||||
|
} else {
|
||||||
|
referenceType = ReferenceType.FIELD;
|
||||||
|
}
|
||||||
|
ReferenceFormatter.writeReference(writer, referenceType, accessedMember.accessedMember);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,14 @@
|
|||||||
package org.jf.baksmali.Renderers;
|
package org.jf.baksmali.Renderers;
|
||||||
|
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.dexlib.Util.Utf8Utils;
|
import org.jf.util.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class CharRenderer {
|
public class CharRenderer {
|
||||||
public static void writeTo(IndentingWriter writer, char val) throws IOException {
|
public static void writeTo(IndentingWriter writer, char val) throws IOException {
|
||||||
writer.write('\'');
|
writer.write('\'');
|
||||||
Utf8Utils.writeEscapedChar(writer, val);
|
StringUtils.writeEscapedChar(writer, val);
|
||||||
writer.write('\'');
|
writer.write('\'');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,83 +28,37 @@
|
|||||||
|
|
||||||
package org.jf.baksmali;
|
package org.jf.baksmali;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Ordering;
|
||||||
import org.jf.baksmali.Adaptors.ClassDefinition;
|
import org.jf.baksmali.Adaptors.ClassDefinition;
|
||||||
import org.jf.dexlib.ClassDefItem;
|
import org.jf.dexlib2.analysis.ClassPath;
|
||||||
import org.jf.dexlib.Code.Analysis.*;
|
import org.jf.dexlib2.iface.ClassDef;
|
||||||
import org.jf.dexlib.DexFile;
|
import org.jf.dexlib2.iface.DexFile;
|
||||||
|
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||||
import org.jf.util.ClassFileNameHandler;
|
import org.jf.util.ClassFileNameHandler;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
import java.util.Collections;
|
import java.util.concurrent.*;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class baksmali {
|
public class baksmali {
|
||||||
public static boolean noParameterRegisters = false;
|
|
||||||
public static boolean useLocalsDirective = false;
|
|
||||||
public static boolean useSequentialLabels = false;
|
|
||||||
public static boolean outputDebugInfo = true;
|
|
||||||
public static boolean addCodeOffsets = false;
|
|
||||||
public static boolean noAccessorComments = false;
|
|
||||||
public static boolean deodex = false;
|
|
||||||
public static boolean verify = false;
|
|
||||||
public static InlineMethodResolver inlineResolver = null;
|
|
||||||
public static int registerInfo = 0;
|
|
||||||
public static String bootClassPath;
|
|
||||||
|
|
||||||
public static SyntheticAccessorResolver syntheticAccessorResolver = null;
|
public static boolean disassembleDexFile(DexFile dexFile, final baksmaliOptions options) {
|
||||||
|
if (options.registerInfo != 0 || options.deodex) {
|
||||||
public static void disassembleDexFile(String dexFilePath, DexFile dexFile, boolean deodex, String outputDirectory,
|
|
||||||
String[] classPathDirs, String bootClassPath, String extraBootClassPath,
|
|
||||||
boolean noParameterRegisters, boolean useLocalsDirective,
|
|
||||||
boolean useSequentialLabels, boolean outputDebugInfo, boolean addCodeOffsets,
|
|
||||||
boolean noAccessorComments, int registerInfo, boolean verify,
|
|
||||||
boolean ignoreErrors, String inlineTable, boolean checkPackagePrivateAccess)
|
|
||||||
{
|
|
||||||
baksmali.noParameterRegisters = noParameterRegisters;
|
|
||||||
baksmali.useLocalsDirective = useLocalsDirective;
|
|
||||||
baksmali.useSequentialLabels = useSequentialLabels;
|
|
||||||
baksmali.outputDebugInfo = outputDebugInfo;
|
|
||||||
baksmali.addCodeOffsets = addCodeOffsets;
|
|
||||||
baksmali.noAccessorComments = noAccessorComments;
|
|
||||||
baksmali.deodex = deodex;
|
|
||||||
baksmali.registerInfo = registerInfo;
|
|
||||||
baksmali.bootClassPath = bootClassPath;
|
|
||||||
baksmali.verify = verify;
|
|
||||||
|
|
||||||
if (registerInfo != 0 || deodex || verify) {
|
|
||||||
try {
|
try {
|
||||||
String[] extraBootClassPathArray = null;
|
Iterable<String> extraClassPathEntries;
|
||||||
if (extraBootClassPath != null && extraBootClassPath.length() > 0) {
|
if (options.extraClassPathEntries != null) {
|
||||||
assert extraBootClassPath.charAt(0) == ':';
|
extraClassPathEntries = options.extraClassPathEntries;
|
||||||
extraBootClassPathArray = extraBootClassPath.substring(1).split(":");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dexFile.isOdex() && bootClassPath == null) {
|
|
||||||
//ext.jar is a special case - it is typically the 2nd jar in the boot class path, but it also
|
|
||||||
//depends on classes in framework.jar (typically the 3rd jar in the BCP). If the user didn't
|
|
||||||
//specify a -c option, we should add framework.jar to the boot class path by default, so that it
|
|
||||||
//"just works"
|
|
||||||
if (extraBootClassPathArray == null && isExtJar(dexFilePath)) {
|
|
||||||
extraBootClassPathArray = new String[] {"framework.jar"};
|
|
||||||
}
|
|
||||||
ClassPath.InitializeClassPathFromOdex(classPathDirs, extraBootClassPathArray, dexFilePath, dexFile,
|
|
||||||
checkPackagePrivateAccess);
|
|
||||||
} else {
|
} else {
|
||||||
String[] bootClassPathArray = null;
|
extraClassPathEntries = ImmutableList.of();
|
||||||
if (bootClassPath != null) {
|
|
||||||
bootClassPathArray = bootClassPath.split(":");
|
|
||||||
}
|
|
||||||
ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray,
|
|
||||||
dexFilePath, dexFile, checkPackagePrivateAccess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inlineTable != null) {
|
options.classPath = ClassPath.fromClassPath(options.bootClassPathDirs,
|
||||||
inlineResolver = new CustomInlineMethodResolver(inlineTable);
|
Iterables.concat(options.bootClassPathEntries, extraClassPathEntries), dexFile,
|
||||||
}
|
options.apiLevel);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
System.err.println("\n\nError occured while loading boot class path files. Aborting.");
|
System.err.println("\n\nError occured while loading boot class path files. Aborting.");
|
||||||
ex.printStackTrace(System.err);
|
ex.printStackTrace(System.err);
|
||||||
@ -112,104 +66,125 @@ public class baksmali {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File outputDirectoryFile = new File(outputDirectory);
|
File outputDirectoryFile = new File(options.outputDirectory);
|
||||||
if (!outputDirectoryFile.exists()) {
|
if (!outputDirectoryFile.exists()) {
|
||||||
if (!outputDirectoryFile.mkdirs()) {
|
if (!outputDirectoryFile.mkdirs()) {
|
||||||
System.err.println("Can't create the output directory " + outputDirectory);
|
System.err.println("Can't create the output directory " + options.outputDirectory);
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!noAccessorComments) {
|
|
||||||
syntheticAccessorResolver = new SyntheticAccessorResolver(dexFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
//sort the classes, so that if we're on a case-insensitive file system and need to handle classes with file
|
//sort the classes, so that if we're on a case-insensitive file system and need to handle classes with file
|
||||||
//name collisions, then we'll use the same name for each class, if the dex file goes through multiple
|
//name collisions, then we'll use the same name for each class, if the dex file goes through multiple
|
||||||
//baksmali/smali cycles for some reason. If a class with a colliding name is added or removed, the filenames
|
//baksmali/smali cycles for some reason. If a class with a colliding name is added or removed, the filenames
|
||||||
//may still change of course
|
//may still change of course
|
||||||
ArrayList<ClassDefItem> classDefItems = new ArrayList<ClassDefItem>(dexFile.ClassDefsSection.getItems());
|
List<? extends ClassDef> classDefs = Ordering.natural().sortedCopy(dexFile.getClasses());
|
||||||
Collections.sort(classDefItems, new Comparator<ClassDefItem>() {
|
|
||||||
public int compare(ClassDefItem classDefItem1, ClassDefItem classDefItem2) {
|
|
||||||
return classDefItem1.getClassType().getTypeDescriptor().compareTo(classDefItem1.getClassType().getTypeDescriptor());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ClassFileNameHandler fileNameHandler = new ClassFileNameHandler(outputDirectoryFile, ".smali");
|
if (!options.noAccessorComments) {
|
||||||
|
options.syntheticAccessorResolver = new SyntheticAccessorResolver(classDefs);
|
||||||
|
}
|
||||||
|
|
||||||
for (ClassDefItem classDefItem: classDefItems) {
|
final ClassFileNameHandler fileNameHandler = new ClassFileNameHandler(outputDirectoryFile, ".smali");
|
||||||
/**
|
|
||||||
* The path for the disassembly file is based on the package name
|
|
||||||
* The class descriptor will look something like:
|
|
||||||
* Ljava/lang/Object;
|
|
||||||
* Where the there is leading 'L' and a trailing ';', and the parts of the
|
|
||||||
* package name are separated by '/'
|
|
||||||
*/
|
|
||||||
|
|
||||||
String classDescriptor = classDefItem.getClassType().getTypeDescriptor();
|
ExecutorService executor = Executors.newFixedThreadPool(options.jobs);
|
||||||
|
List<Future<Boolean>> tasks = Lists.newArrayList();
|
||||||
|
|
||||||
//validate that the descriptor is formatted like we expect
|
for (final ClassDef classDef: classDefs) {
|
||||||
if (classDescriptor.charAt(0) != 'L' ||
|
tasks.add(executor.submit(new Callable<Boolean>() {
|
||||||
classDescriptor.charAt(classDescriptor.length()-1) != ';') {
|
@Override public Boolean call() throws Exception {
|
||||||
System.err.println("Unrecognized class descriptor - " + classDescriptor + " - skipping class");
|
return disassembleClass(classDef, fileNameHandler, options);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
File smaliFile = fileNameHandler.getUniqueFilenameForClass(classDescriptor);
|
|
||||||
|
|
||||||
//create and initialize the top level string template
|
|
||||||
ClassDefinition classDefinition = new ClassDefinition(classDefItem);
|
|
||||||
|
|
||||||
//write the disassembly
|
|
||||||
Writer writer = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File smaliParent = smaliFile.getParentFile();
|
|
||||||
if (!smaliParent.exists()) {
|
|
||||||
if (!smaliParent.mkdirs()) {
|
|
||||||
System.err.println("Unable to create directory " + smaliParent.toString() + " - skipping class");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if (!smaliFile.exists()){
|
boolean errorOccurred = false;
|
||||||
if (!smaliFile.createNewFile()) {
|
for (Future<Boolean> task: tasks) {
|
||||||
System.err.println("Unable to create file " + smaliFile.toString() + " - skipping class");
|
while(true) {
|
||||||
continue;
|
try {
|
||||||
|
if (!task.get()) {
|
||||||
|
errorOccurred = true;
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
continue;
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
BufferedWriter bufWriter = new BufferedWriter(new OutputStreamWriter(
|
|
||||||
new FileOutputStream(smaliFile), "UTF8"));
|
|
||||||
|
|
||||||
writer = new IndentingWriter(bufWriter);
|
|
||||||
classDefinition.writeTo((IndentingWriter)writer);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
System.err.println("\n\nError occured while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class");
|
|
||||||
ex.printStackTrace();
|
|
||||||
smaliFile.delete();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (writer != null) {
|
|
||||||
try {
|
|
||||||
writer.close();
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
System.err.println("\n\nError occured while closing file " + smaliFile.toString());
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ignoreErrors && classDefinition.hadValidationErrors()) {
|
|
||||||
System.exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
executor.shutdown();
|
||||||
|
return !errorOccurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern extJarPattern = Pattern.compile("(?:^|\\\\|/)ext.(?:jar|odex)$");
|
private static boolean disassembleClass(ClassDef classDef, ClassFileNameHandler fileNameHandler,
|
||||||
private static boolean isExtJar(String dexFilePath) {
|
baksmaliOptions options) {
|
||||||
Matcher m = extJarPattern.matcher(dexFilePath);
|
/**
|
||||||
return m.find();
|
* The path for the disassembly file is based on the package name
|
||||||
|
* The class descriptor will look something like:
|
||||||
|
* Ljava/lang/Object;
|
||||||
|
* Where the there is leading 'L' and a trailing ';', and the parts of the
|
||||||
|
* package name are separated by '/'
|
||||||
|
*/
|
||||||
|
String classDescriptor = classDef.getType();
|
||||||
|
|
||||||
|
//validate that the descriptor is formatted like we expect
|
||||||
|
if (classDescriptor.charAt(0) != 'L' ||
|
||||||
|
classDescriptor.charAt(classDescriptor.length()-1) != ';') {
|
||||||
|
System.err.println("Unrecognized class descriptor - " + classDescriptor + " - skipping class");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File smaliFile = fileNameHandler.getUniqueFilenameForClass(classDescriptor);
|
||||||
|
|
||||||
|
//create and initialize the top level string template
|
||||||
|
ClassDefinition classDefinition = new ClassDefinition(options, classDef);
|
||||||
|
|
||||||
|
//write the disassembly
|
||||||
|
Writer writer = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File smaliParent = smaliFile.getParentFile();
|
||||||
|
if (!smaliParent.exists()) {
|
||||||
|
if (!smaliParent.mkdirs()) {
|
||||||
|
// check again, it's likely it was created in a different thread
|
||||||
|
if (!smaliParent.exists()) {
|
||||||
|
System.err.println("Unable to create directory " + smaliParent.toString() + " - skipping class");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!smaliFile.exists()){
|
||||||
|
if (!smaliFile.createNewFile()) {
|
||||||
|
System.err.println("Unable to create file " + smaliFile.toString() + " - skipping class");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedWriter bufWriter = new BufferedWriter(new OutputStreamWriter(
|
||||||
|
new FileOutputStream(smaliFile), "UTF8"));
|
||||||
|
|
||||||
|
writer = new IndentingWriter(bufWriter);
|
||||||
|
classDefinition.writeTo((IndentingWriter)writer);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
System.err.println("\n\nError occured while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class");
|
||||||
|
ex.printStackTrace();
|
||||||
|
// noinspection ResultOfMethodCallIgnored
|
||||||
|
smaliFile.delete();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (writer != null) {
|
||||||
|
try {
|
||||||
|
writer.close();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
System.err.println("\n\nError occured while closing file " + smaliFile.toString());
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.jf.dexlib2.analysis.ClassPath;
|
||||||
|
import org.jf.dexlib2.analysis.InlineMethodResolver;
|
||||||
|
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class baksmaliOptions {
|
||||||
|
// register info values
|
||||||
|
public static final int ALL = 1;
|
||||||
|
public static final int ALLPRE = 2;
|
||||||
|
public static final int ALLPOST = 4;
|
||||||
|
public static final int ARGS = 8;
|
||||||
|
public static final int DEST = 16;
|
||||||
|
public static final int MERGE = 32;
|
||||||
|
public static final int FULLMERGE = 64;
|
||||||
|
|
||||||
|
public int apiLevel = 15;
|
||||||
|
public String outputDirectory = "out";
|
||||||
|
public List<String> bootClassPathDirs = Lists.newArrayList();
|
||||||
|
|
||||||
|
public List<String> bootClassPathEntries = Lists.newArrayList();
|
||||||
|
public List<String> extraClassPathEntries = Lists.newArrayList();
|
||||||
|
|
||||||
|
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 deodex = false;
|
||||||
|
public boolean ignoreErrors = false;
|
||||||
|
public boolean checkPackagePrivateAccess = false;
|
||||||
|
public InlineMethodResolver inlineResolver = null;
|
||||||
|
public int registerInfo = 0;
|
||||||
|
public ClassPath classPath = null;
|
||||||
|
public int jobs = -1;
|
||||||
|
|
||||||
|
public SyntheticAccessorResolver syntheticAccessorResolver = null;
|
||||||
|
|
||||||
|
public void setBootClassPath(String bootClassPath) {
|
||||||
|
bootClassPathEntries = Lists.newArrayList(bootClassPath.split(":"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addExtraClassPath(String extraClassPath) {
|
||||||
|
if (extraClassPath.startsWith(":")) {
|
||||||
|
extraClassPath = extraClassPath.substring(1);
|
||||||
|
}
|
||||||
|
extraClassPathEntries.addAll(Arrays.asList(extraClassPath.split(":")));
|
||||||
|
}
|
||||||
|
}
|
@ -28,79 +28,43 @@
|
|||||||
|
|
||||||
package org.jf.baksmali;
|
package org.jf.baksmali;
|
||||||
|
|
||||||
import org.jf.dexlib.DexFile;
|
import org.jf.dexlib2.Opcodes;
|
||||||
import org.jf.dexlib.Util.ByteArrayAnnotatedOutput;
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||||
|
import org.jf.dexlib2.dexbacked.raw.RawDexFile;
|
||||||
|
import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator;
|
||||||
|
import org.jf.util.ConsoleUtil;
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.BufferedWriter;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
public class dump {
|
public class dump {
|
||||||
public static void dump(DexFile dexFile, String dumpFileName, String outputDexFileName, boolean sort)
|
public static void dump(DexBackedDexFile dexFile, String dumpFileName, int apiLevel) throws IOException {
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
if (sort) {
|
|
||||||
//sort all items, to guarantee a unique ordering
|
|
||||||
dexFile.setSortAllItems(true);
|
|
||||||
} else {
|
|
||||||
//don't change the order
|
|
||||||
dexFile.setInplace(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
|
|
||||||
|
|
||||||
if (dumpFileName != null) {
|
if (dumpFileName != null) {
|
||||||
out.enableAnnotations(120, true);
|
Writer writer = null;
|
||||||
}
|
|
||||||
|
|
||||||
dexFile.place();
|
|
||||||
dexFile.writeTo(out);
|
|
||||||
|
|
||||||
//write the dump
|
|
||||||
if (dumpFileName != null) {
|
|
||||||
out.finishAnnotating();
|
|
||||||
FileWriter writer = null;
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
writer = new FileWriter(dumpFileName);
|
writer = new BufferedWriter(new FileWriter(dumpFileName));
|
||||||
out.writeAnnotationsTo(writer);
|
|
||||||
|
int consoleWidth = ConsoleUtil.getConsoleWidth();
|
||||||
|
if (consoleWidth <= 0) {
|
||||||
|
consoleWidth = 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
RawDexFile rawDexFile = new RawDexFile(new Opcodes(apiLevel), dexFile);
|
||||||
|
DexAnnotator annotator = new DexAnnotator(rawDexFile, consoleWidth);
|
||||||
|
annotator.writeAnnotations(writer);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
System.err.println("\n\nThere was an error while dumping the dex file to " + dumpFileName);
|
System.err.println("There was an error while dumping the dex file to " + dumpFileName);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace(System.err);
|
||||||
} finally {
|
} finally {
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
try {
|
try {
|
||||||
writer.close();
|
writer.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
System.err.println("\n\nThere was an error while closing the dump file " + dumpFileName);
|
System.err.println("There was an error while closing the dump file " + dumpFileName);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace(System.err);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//rewrite the dex file
|
|
||||||
if (outputDexFileName != null) {
|
|
||||||
byte[] bytes = out.toByteArray();
|
|
||||||
|
|
||||||
DexFile.calcSignature(bytes);
|
|
||||||
DexFile.calcChecksum(bytes);
|
|
||||||
|
|
||||||
FileOutputStream fileOutputStream = null;
|
|
||||||
try {
|
|
||||||
fileOutputStream = new FileOutputStream(outputDexFileName);
|
|
||||||
fileOutputStream.write(bytes);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
System.err.println("\n\nThere was an error while writing the dex file " + outputDexFileName);
|
|
||||||
ex.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
if (fileOutputStream != null) {
|
|
||||||
try {
|
|
||||||
fileOutputStream.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
System.err.println("\n\nThere was an error while closing the dex file " + outputDexFileName);
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,16 +28,20 @@
|
|||||||
|
|
||||||
package org.jf.baksmali;
|
package org.jf.baksmali;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import org.apache.commons.cli.*;
|
import org.apache.commons.cli.*;
|
||||||
import org.jf.dexlib.Code.Opcode;
|
import org.jf.dexlib2.DexFileFactory;
|
||||||
import org.jf.dexlib.DexFile;
|
import org.jf.dexlib2.analysis.CustomInlineMethodResolver;
|
||||||
|
import org.jf.dexlib2.analysis.InlineMethodResolver;
|
||||||
|
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||||
|
import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
|
||||||
import org.jf.util.ConsoleUtil;
|
import org.jf.util.ConsoleUtil;
|
||||||
import org.jf.util.SmaliHelpFormatter;
|
import org.jf.util.SmaliHelpFormatter;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@ -50,16 +54,6 @@ public class main {
|
|||||||
private static final Options debugOptions;
|
private static final Options debugOptions;
|
||||||
private static final Options options;
|
private static final Options options;
|
||||||
|
|
||||||
public static final int ALL = 1;
|
|
||||||
public static final int ALLPRE = 2;
|
|
||||||
public static final int ALLPOST = 4;
|
|
||||||
public static final int ARGS = 8;
|
|
||||||
public static final int DEST = 16;
|
|
||||||
public static final int MERGE = 32;
|
|
||||||
public static final int FULLMERGE = 64;
|
|
||||||
|
|
||||||
public static final int DIFFPRE = 128;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
options = new Options();
|
options = new Options();
|
||||||
basicOptions = new Options();
|
basicOptions = new Options();
|
||||||
@ -67,14 +61,19 @@ public class main {
|
|||||||
buildOptions();
|
buildOptions();
|
||||||
|
|
||||||
InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties");
|
InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties");
|
||||||
Properties properties = new Properties();
|
if (templateStream != null) {
|
||||||
String version = "(unknown)";
|
Properties properties = new Properties();
|
||||||
try {
|
String version = "(unknown)";
|
||||||
properties.load(templateStream);
|
try {
|
||||||
version = properties.getProperty("application.version");
|
properties.load(templateStream);
|
||||||
} catch (IOException ex) {
|
version = properties.getProperty("application.version");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
VERSION = version;
|
||||||
|
} else {
|
||||||
|
VERSION = "[unknown version]";
|
||||||
}
|
}
|
||||||
VERSION = version;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,7 +85,7 @@ public class main {
|
|||||||
/**
|
/**
|
||||||
* Run!
|
* Run!
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws IOException {
|
||||||
Locale locale = new Locale("en", "US");
|
Locale locale = new Locale("en", "US");
|
||||||
Locale.setDefault(locale);
|
Locale.setDefault(locale);
|
||||||
|
|
||||||
@ -100,43 +99,18 @@ public class main {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baksmaliOptions options = new baksmaliOptions();
|
||||||
|
|
||||||
boolean disassemble = true;
|
boolean disassemble = true;
|
||||||
boolean doDump = false;
|
boolean doDump = false;
|
||||||
boolean write = false;
|
|
||||||
boolean sort = false;
|
|
||||||
boolean fixRegisters = false;
|
|
||||||
boolean noParameterRegisters = false;
|
|
||||||
boolean useLocalsDirective = false;
|
|
||||||
boolean useSequentialLabels = false;
|
|
||||||
boolean outputDebugInfo = true;
|
|
||||||
boolean addCodeOffsets = false;
|
|
||||||
boolean noAccessorComments = false;
|
|
||||||
boolean deodex = false;
|
|
||||||
boolean verify = false;
|
|
||||||
boolean ignoreErrors = false;
|
|
||||||
boolean checkPackagePrivateAccess = false;
|
|
||||||
|
|
||||||
int apiLevel = 14;
|
|
||||||
|
|
||||||
int registerInfo = 0;
|
|
||||||
|
|
||||||
String outputDirectory = "out";
|
|
||||||
String dumpFileName = null;
|
String dumpFileName = null;
|
||||||
String outputDexFileName = null;
|
boolean setBootClassPath = false;
|
||||||
String inputDexFileName = null;
|
|
||||||
String bootClassPath = null;
|
|
||||||
StringBuffer extraBootClassPathEntries = new StringBuffer();
|
|
||||||
List<String> bootClassPathDirs = new ArrayList<String>();
|
|
||||||
bootClassPathDirs.add(".");
|
|
||||||
String inlineTable = null;
|
|
||||||
boolean jumboInstructions = false;
|
|
||||||
|
|
||||||
String[] remainingArgs = commandLine.getArgs();
|
String[] remainingArgs = commandLine.getArgs();
|
||||||
|
Option[] clOptions = commandLine.getOptions();
|
||||||
|
|
||||||
Option[] options = commandLine.getOptions();
|
for (int i=0; i<clOptions.length; i++) {
|
||||||
|
Option option = clOptions[i];
|
||||||
for (int i=0; i<options.length; i++) {
|
|
||||||
Option option = options[i];
|
|
||||||
String opt = option.getOpt();
|
String opt = option.getOpt();
|
||||||
|
|
||||||
switch (opt.charAt(0)) {
|
switch (opt.charAt(0)) {
|
||||||
@ -144,8 +118,8 @@ public class main {
|
|||||||
version();
|
version();
|
||||||
return;
|
return;
|
||||||
case '?':
|
case '?':
|
||||||
while (++i < options.length) {
|
while (++i < clOptions.length) {
|
||||||
if (options[i].getOpt().charAt(0) == '?') {
|
if (clOptions[i].getOpt().charAt(0) == '?') {
|
||||||
usage(true);
|
usage(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -153,109 +127,96 @@ public class main {
|
|||||||
usage(false);
|
usage(false);
|
||||||
return;
|
return;
|
||||||
case 'o':
|
case 'o':
|
||||||
outputDirectory = commandLine.getOptionValue("o");
|
options.outputDirectory = commandLine.getOptionValue("o");
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
noParameterRegisters = true;
|
options.noParameterRegisters = true;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
useLocalsDirective = true;
|
options.useLocalsDirective = true;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
useSequentialLabels = true;
|
options.useSequentialLabels = true;
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
outputDebugInfo = false;
|
options.outputDebugInfo = false;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
bootClassPathDirs.add(option.getValue());
|
options.bootClassPathDirs.add(option.getValue());
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
addCodeOffsets = true;
|
options.addCodeOffsets = true;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
String[] values = commandLine.getOptionValues('r');
|
String[] values = commandLine.getOptionValues('r');
|
||||||
|
int registerInfo = 0;
|
||||||
|
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
registerInfo = ARGS | DEST;
|
registerInfo = baksmaliOptions.ARGS | baksmaliOptions.DEST;
|
||||||
} else {
|
} else {
|
||||||
for (String value: values) {
|
for (String value: values) {
|
||||||
if (value.equalsIgnoreCase("ALL")) {
|
if (value.equalsIgnoreCase("ALL")) {
|
||||||
registerInfo |= ALL;
|
registerInfo |= baksmaliOptions.ALL;
|
||||||
} else if (value.equalsIgnoreCase("ALLPRE")) {
|
} else if (value.equalsIgnoreCase("ALLPRE")) {
|
||||||
registerInfo |= ALLPRE;
|
registerInfo |= baksmaliOptions.ALLPRE;
|
||||||
} else if (value.equalsIgnoreCase("ALLPOST")) {
|
} else if (value.equalsIgnoreCase("ALLPOST")) {
|
||||||
registerInfo |= ALLPOST;
|
registerInfo |= baksmaliOptions.ALLPOST;
|
||||||
} else if (value.equalsIgnoreCase("ARGS")) {
|
} else if (value.equalsIgnoreCase("ARGS")) {
|
||||||
registerInfo |= ARGS;
|
registerInfo |= baksmaliOptions.ARGS;
|
||||||
} else if (value.equalsIgnoreCase("DEST")) {
|
} else if (value.equalsIgnoreCase("DEST")) {
|
||||||
registerInfo |= DEST;
|
registerInfo |= baksmaliOptions.DEST;
|
||||||
} else if (value.equalsIgnoreCase("MERGE")) {
|
} else if (value.equalsIgnoreCase("MERGE")) {
|
||||||
registerInfo |= MERGE;
|
registerInfo |= baksmaliOptions.MERGE;
|
||||||
} else if (value.equalsIgnoreCase("FULLMERGE")) {
|
} else if (value.equalsIgnoreCase("FULLMERGE")) {
|
||||||
registerInfo |= FULLMERGE;
|
registerInfo |= baksmaliOptions.FULLMERGE;
|
||||||
} else {
|
} else {
|
||||||
usage();
|
usage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((registerInfo & FULLMERGE) != 0) {
|
if ((registerInfo & baksmaliOptions.FULLMERGE) != 0) {
|
||||||
registerInfo &= ~MERGE;
|
registerInfo &= ~baksmaliOptions.MERGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
options.registerInfo = registerInfo;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
String bcp = commandLine.getOptionValue("c");
|
String bcp = commandLine.getOptionValue("c");
|
||||||
if (bcp != null && bcp.charAt(0) == ':') {
|
if (bcp != null && bcp.charAt(0) == ':') {
|
||||||
extraBootClassPathEntries.append(bcp);
|
options.addExtraClassPath(bcp);
|
||||||
} else {
|
} else {
|
||||||
bootClassPath = bcp;
|
setBootClassPath = true;
|
||||||
|
options.setBootClassPath(bcp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
deodex = true;
|
options.deodex = true;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
noAccessorComments = true;
|
options.noAccessorComments = true;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
|
options.apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
|
||||||
if (apiLevel >= 17) {
|
break;
|
||||||
checkPackagePrivateAccess = true;
|
case 'j':
|
||||||
}
|
options.jobs = Integer.parseInt(commandLine.getOptionValue("j"));
|
||||||
break;
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
disassemble = false;
|
disassemble = false;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
doDump = true;
|
doDump = true;
|
||||||
dumpFileName = commandLine.getOptionValue("D", inputDexFileName + ".dump");
|
dumpFileName = commandLine.getOptionValue("D");
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
ignoreErrors = true;
|
options.ignoreErrors = true;
|
||||||
break;
|
|
||||||
case 'J':
|
|
||||||
jumboInstructions = true;
|
|
||||||
break;
|
|
||||||
case 'W':
|
|
||||||
write = true;
|
|
||||||
outputDexFileName = commandLine.getOptionValue("W");
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
sort = true;
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
fixRegisters = true;
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
verify = true;
|
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
inlineTable = commandLine.getOptionValue("T");
|
options.inlineResolver = new CustomInlineMethodResolver(options.classPath, new File(commandLine.getOptionValue("T")));
|
||||||
break;
|
break;
|
||||||
case 'K':
|
case 'K':
|
||||||
checkPackagePrivateAccess = true;
|
options.checkPackagePrivateAccess = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
@ -267,68 +228,60 @@ public class main {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
inputDexFileName = remainingArgs[0];
|
if (options.jobs <= 0) {
|
||||||
|
options.jobs = Runtime.getRuntime().availableProcessors();
|
||||||
try {
|
if (options.jobs > 6) {
|
||||||
File dexFileFile = new File(inputDexFileName);
|
options.jobs = 6;
|
||||||
if (!dexFileFile.exists()) {
|
|
||||||
System.err.println("Can't find the file " + inputDexFileName);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Opcode.updateMapsForApiLevel(apiLevel, jumboInstructions);
|
String inputDexFileName = remainingArgs[0];
|
||||||
|
|
||||||
//Read in and parse the dex file
|
File dexFileFile = new File(inputDexFileName);
|
||||||
DexFile dexFile = new DexFile(dexFileFile, !fixRegisters, false);
|
if (!dexFileFile.exists()) {
|
||||||
|
System.err.println("Can't find the file " + inputDexFileName);
|
||||||
if (dexFile.isOdex()) {
|
|
||||||
if (doDump) {
|
|
||||||
System.err.println("-D cannot be used with on odex file. Ignoring -D");
|
|
||||||
}
|
|
||||||
if (write) {
|
|
||||||
System.err.println("-W cannot be used with an odex file. Ignoring -W");
|
|
||||||
}
|
|
||||||
if (!deodex) {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
deodex = false;
|
|
||||||
|
|
||||||
if (bootClassPath == null) {
|
|
||||||
bootClassPath = "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disassemble) {
|
|
||||||
String[] bootClassPathDirsArray = new String[bootClassPathDirs.size()];
|
|
||||||
for (int i=0; i<bootClassPathDirsArray.length; i++) {
|
|
||||||
bootClassPathDirsArray[i] = bootClassPathDirs.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
baksmali.disassembleDexFile(dexFileFile.getPath(), dexFile, deodex, outputDirectory,
|
|
||||||
bootClassPathDirsArray, bootClassPath, extraBootClassPathEntries.toString(),
|
|
||||||
noParameterRegisters, useLocalsDirective, useSequentialLabels, outputDebugInfo, addCodeOffsets,
|
|
||||||
noAccessorComments, registerInfo, verify, ignoreErrors, inlineTable, checkPackagePrivateAccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((doDump || write) && !dexFile.isOdex()) {
|
|
||||||
try
|
|
||||||
{
|
|
||||||
dump.dump(dexFile, dumpFileName, outputDexFileName, sort);
|
|
||||||
}catch (IOException ex) {
|
|
||||||
System.err.println("Error occured while writing dump file");
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (RuntimeException ex) {
|
|
||||||
System.err.println("\n\nUNEXPECTED TOP-LEVEL EXCEPTION:");
|
|
||||||
ex.printStackTrace();
|
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
} catch (Throwable ex) {
|
}
|
||||||
System.err.println("\n\nUNEXPECTED TOP-LEVEL ERROR:");
|
|
||||||
ex.printStackTrace();
|
//Read in and parse the dex file
|
||||||
|
DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, options.apiLevel);
|
||||||
|
|
||||||
|
if (dexFile.isOdexFile()) {
|
||||||
|
if (!options.deodex) {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
options.deodex = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setBootClassPath && (options.deodex || options.registerInfo != 0)) {
|
||||||
|
if (dexFile instanceof DexBackedOdexFile) {
|
||||||
|
options.bootClassPathEntries = ((DexBackedOdexFile)dexFile).getDependencies();
|
||||||
|
} else {
|
||||||
|
options.bootClassPathEntries = getDefaultBootClassPathForApi(options.apiLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.inlineResolver == null && dexFile instanceof DexBackedOdexFile) {
|
||||||
|
options.inlineResolver =
|
||||||
|
InlineMethodResolver.createInlineMethodResolver(((DexBackedOdexFile)dexFile).getOdexVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean errorOccurred = false;
|
||||||
|
if (disassemble) {
|
||||||
|
errorOccurred = !baksmali.disassembleDexFile(dexFile, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doDump) {
|
||||||
|
if (dumpFileName == null) {
|
||||||
|
dumpFileName = commandLine.getOptionValue(inputDexFileName + ".dump");
|
||||||
|
}
|
||||||
|
dump.dump(dexFile, dumpFileName, options.apiLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorOccurred) {
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -363,6 +316,7 @@ public class main {
|
|||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("AccessStaticViaInstance")
|
||||||
private static void buildOptions() {
|
private static void buildOptions() {
|
||||||
Option versionOption = OptionBuilder.withLongOpt("version")
|
Option versionOption = OptionBuilder.withLongOpt("version")
|
||||||
.withDescription("prints the version then exits")
|
.withDescription("prints the version then exits")
|
||||||
@ -441,11 +395,18 @@ public class main {
|
|||||||
|
|
||||||
Option apiLevelOption = OptionBuilder.withLongOpt("api-level")
|
Option apiLevelOption = OptionBuilder.withLongOpt("api-level")
|
||||||
.withDescription("The numeric api-level of the file being disassembled. If not " +
|
.withDescription("The numeric api-level of the file being disassembled. If not " +
|
||||||
"specified, it defaults to 14 (ICS).")
|
"specified, it defaults to 15 (ICS).")
|
||||||
.hasArg()
|
.hasArg()
|
||||||
.withArgName("API_LEVEL")
|
.withArgName("API_LEVEL")
|
||||||
.create("a");
|
.create("a");
|
||||||
|
|
||||||
|
Option jobsOption = OptionBuilder.withLongOpt("jobs")
|
||||||
|
.withDescription("The number of threads to use. Defaults to the number of cores available, up to a " +
|
||||||
|
"maximum of 6")
|
||||||
|
.hasArg()
|
||||||
|
.withArgName("NUM_THREADS")
|
||||||
|
.create("j");
|
||||||
|
|
||||||
Option dumpOption = OptionBuilder.withLongOpt("dump-to")
|
Option dumpOption = OptionBuilder.withLongOpt("dump-to")
|
||||||
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
|
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
|
||||||
" (<dexfile>.dump by default), along with the normal disassembly")
|
" (<dexfile>.dump by default), along with the normal disassembly")
|
||||||
@ -459,42 +420,22 @@ public class main {
|
|||||||
" behavior is to stop disassembling and exit once an error is encountered")
|
" behavior is to stop disassembling and exit once an error is encountered")
|
||||||
.create("I");
|
.create("I");
|
||||||
|
|
||||||
Option jumboInstructionsOption = OptionBuilder.withLongOpt("jumbo-instructions")
|
|
||||||
.withDescription("adds support for the jumbo opcodes that were temporarily available around the" +
|
|
||||||
" ics timeframe. Note that support for these opcodes was removed from newer version of" +
|
|
||||||
" dalvik. You shouldn't use this option unless you know the dex file contains these jumbo" +
|
|
||||||
" opcodes.")
|
|
||||||
.create("J");
|
|
||||||
|
|
||||||
Option noDisassemblyOption = OptionBuilder.withLongOpt("no-disassembly")
|
Option noDisassemblyOption = OptionBuilder.withLongOpt("no-disassembly")
|
||||||
.withDescription("suppresses the output of the disassembly")
|
.withDescription("suppresses the output of the disassembly")
|
||||||
.create("N");
|
.create("N");
|
||||||
|
|
||||||
Option writeDexOption = OptionBuilder.withLongOpt("write-dex")
|
|
||||||
.withDescription("additionally rewrites the input dex file to FILE")
|
|
||||||
.hasArg()
|
|
||||||
.withArgName("FILE")
|
|
||||||
.create("W");
|
|
||||||
|
|
||||||
Option sortOption = OptionBuilder.withLongOpt("sort")
|
|
||||||
.withDescription("sort the items in the dex file into a canonical order before dumping/writing")
|
|
||||||
.create("S");
|
|
||||||
|
|
||||||
Option fixSignedRegisterOption = OptionBuilder.withLongOpt("fix-signed-registers")
|
|
||||||
.withDescription("when dumping or rewriting, fix any registers in the debug info that are encoded as" +
|
|
||||||
" a signed value")
|
|
||||||
.create("F");
|
|
||||||
|
|
||||||
Option verifyDexOption = OptionBuilder.withLongOpt("verify")
|
|
||||||
.withDescription("perform bytecode verification")
|
|
||||||
.create("V");
|
|
||||||
|
|
||||||
Option inlineTableOption = OptionBuilder.withLongOpt("inline-table")
|
Option inlineTableOption = OptionBuilder.withLongOpt("inline-table")
|
||||||
.withDescription("specify a file containing a custom inline method table to use for deodexing")
|
.withDescription("specify a file containing a custom inline method table to use for deodexing")
|
||||||
.hasArg()
|
.hasArg()
|
||||||
.withArgName("FILE")
|
.withArgName("FILE")
|
||||||
.create("T");
|
.create("T");
|
||||||
|
|
||||||
|
Option checkPackagePrivateAccess = OptionBuilder.withLongOpt("check-package-private-access")
|
||||||
|
.withDescription("When deodexing, use the new virtual table generation logic that " +
|
||||||
|
"prevents overriding an inaccessible package private method. This is a temporary option " +
|
||||||
|
"that will be removed once this new functionality can be tied to a specific api level.")
|
||||||
|
.create("K");
|
||||||
|
|
||||||
basicOptions.addOption(versionOption);
|
basicOptions.addOption(versionOption);
|
||||||
basicOptions.addOption(helpOption);
|
basicOptions.addOption(helpOption);
|
||||||
basicOptions.addOption(outputDirOption);
|
basicOptions.addOption(outputDirOption);
|
||||||
@ -509,16 +450,13 @@ public class main {
|
|||||||
basicOptions.addOption(codeOffsetOption);
|
basicOptions.addOption(codeOffsetOption);
|
||||||
basicOptions.addOption(noAccessorCommentsOption);
|
basicOptions.addOption(noAccessorCommentsOption);
|
||||||
basicOptions.addOption(apiLevelOption);
|
basicOptions.addOption(apiLevelOption);
|
||||||
|
basicOptions.addOption(jobsOption);
|
||||||
|
|
||||||
debugOptions.addOption(dumpOption);
|
debugOptions.addOption(dumpOption);
|
||||||
debugOptions.addOption(ignoreErrorsOption);
|
debugOptions.addOption(ignoreErrorsOption);
|
||||||
debugOptions.addOption(jumboInstructionsOption);
|
|
||||||
debugOptions.addOption(noDisassemblyOption);
|
debugOptions.addOption(noDisassemblyOption);
|
||||||
debugOptions.addOption(writeDexOption);
|
|
||||||
debugOptions.addOption(sortOption);
|
|
||||||
debugOptions.addOption(fixSignedRegisterOption);
|
|
||||||
debugOptions.addOption(verifyDexOption);
|
|
||||||
debugOptions.addOption(inlineTableOption);
|
debugOptions.addOption(inlineTableOption);
|
||||||
|
debugOptions.addOption(checkPackagePrivateAccess);
|
||||||
|
|
||||||
for (Object option: basicOptions.getOptions()) {
|
for (Object option: basicOptions.getOptions()) {
|
||||||
options.addOption((Option)option);
|
options.addOption((Option)option);
|
||||||
@ -527,4 +465,60 @@ public class main {
|
|||||||
options.addOption((Option)option);
|
options.addOption((Option)option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static List<String> getDefaultBootClassPathForApi(int apiLevel) {
|
||||||
|
if (apiLevel < 9) {
|
||||||
|
return Lists.newArrayList(
|
||||||
|
"/system/framework/core.jar",
|
||||||
|
"/system/framework/ext.jar",
|
||||||
|
"/system/framework/framework.jar",
|
||||||
|
"/system/framework/android.policy.jar",
|
||||||
|
"/system/framework/services.jar");
|
||||||
|
} else if (apiLevel < 12) {
|
||||||
|
return Lists.newArrayList(
|
||||||
|
"/system/framework/core.jar",
|
||||||
|
"/system/framework/bouncycastle.jar",
|
||||||
|
"/system/framework/ext.jar",
|
||||||
|
"/system/framework/framework.jar",
|
||||||
|
"/system/framework/android.policy.jar",
|
||||||
|
"/system/framework/services.jar",
|
||||||
|
"/system/framework/core-junit.jar");
|
||||||
|
} else if (apiLevel < 14) {
|
||||||
|
return Lists.newArrayList(
|
||||||
|
"/system/framework/core.jar",
|
||||||
|
"/system/framework/apache-xml.jar",
|
||||||
|
"/system/framework/bouncycastle.jar",
|
||||||
|
"/system/framework/ext.jar",
|
||||||
|
"/system/framework/framework.jar",
|
||||||
|
"/system/framework/android.policy.jar",
|
||||||
|
"/system/framework/services.jar",
|
||||||
|
"/system/framework/core-junit.jar");
|
||||||
|
} else if (apiLevel < 16) {
|
||||||
|
return Lists.newArrayList(
|
||||||
|
"/system/framework/core.jar",
|
||||||
|
"/system/framework/core-junit.jar",
|
||||||
|
"/system/framework/bouncycastle.jar",
|
||||||
|
"/system/framework/ext.jar",
|
||||||
|
"/system/framework/framework.jar",
|
||||||
|
"/system/framework/android.policy.jar",
|
||||||
|
"/system/framework/services.jar",
|
||||||
|
"/system/framework/apache-xml.jar",
|
||||||
|
"/system/framework/filterfw.jar");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// this is correct as of api 17/4.2.2
|
||||||
|
return Lists.newArrayList(
|
||||||
|
"/system/framework/core.jar",
|
||||||
|
"/system/framework/core-junit.jar",
|
||||||
|
"/system/framework/bouncycastle.jar",
|
||||||
|
"/system/framework/ext.jar",
|
||||||
|
"/system/framework/framework.jar",
|
||||||
|
"/system/framework/telephony-common.jar",
|
||||||
|
"/system/framework/mms-common.jar",
|
||||||
|
"/system/framework/android.policy.jar",
|
||||||
|
"/system/framework/services.jar",
|
||||||
|
"/system/framework/apache-xml.jar");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1 @@
|
|||||||
|
application.version=${version}
|
@ -1 +0,0 @@
|
|||||||
application.version=1.4.2
|
|
@ -1,436 +0,0 @@
|
|||||||
group baksmali;
|
|
||||||
|
|
||||||
smaliFile(AccessFlags, ClassType, SuperType, SourceFile, Interfaces, Annotations, StaticFields,
|
|
||||||
InstanceFields, DirectMethods, VirtualMethods) ::=
|
|
||||||
<<
|
|
||||||
.class <AccessFlags: {<it> }><ClassType>
|
|
||||||
<if(SuperType)>
|
|
||||||
.super <SuperType>
|
|
||||||
<endif>
|
|
||||||
<if(SourceFile)>
|
|
||||||
|
|
||||||
.source "<SourceFile>"
|
|
||||||
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
<if(Interfaces)>
|
|
||||||
|
|
||||||
# interfaces
|
|
||||||
<Interfaces: implement(it); separator="\n">
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
<if(Annotations)>
|
|
||||||
|
|
||||||
|
|
||||||
# annotations
|
|
||||||
<Annotations; separator="\n\n">
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
<if(StaticFields)>
|
|
||||||
|
|
||||||
|
|
||||||
# static fields
|
|
||||||
<StaticFields; separator="\n">
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
<if(InstanceFields)>
|
|
||||||
|
|
||||||
|
|
||||||
# instance fields
|
|
||||||
<InstanceFields; separator="\n">
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
<if(DirectMethods)>
|
|
||||||
|
|
||||||
|
|
||||||
# direct methods
|
|
||||||
<DirectMethods; separator="\n\n">
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
<if(VirtualMethods)>
|
|
||||||
|
|
||||||
|
|
||||||
# virtual methods
|
|
||||||
<VirtualMethods; separator="\n\n">
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
>>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
implement(interface) ::=
|
|
||||||
<<
|
|
||||||
.implements <interface>
|
|
||||||
>>
|
|
||||||
|
|
||||||
|
|
||||||
annotation(Visibility, AnnotationType, Elements) ::=
|
|
||||||
<<
|
|
||||||
.annotation <Visibility> <AnnotationType>
|
|
||||||
<if(Elements)>
|
|
||||||
<Elements; separator="\n">
|
|
||||||
<endif>
|
|
||||||
<if(Elements)>
|
|
||||||
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
.end annotation
|
|
||||||
>>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
field(AccessFlags, FieldName, FieldType, Annotations, InitialValue, Comments) ::=
|
|
||||||
<<
|
|
||||||
<if(Comments)><Comments: {#<it>} ; separator="\n">
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
.field <AccessFlags: {<it> }><FieldName>:<FieldType><if(InitialValue)> = <InitialValue><endif>
|
|
||||||
<if(Annotations)>
|
|
||||||
<Annotations; separator="\n\n">
|
|
||||||
.end field
|
|
||||||
|
|
||||||
<endif>
|
|
||||||
>>
|
|
||||||
|
|
||||||
|
|
||||||
method(AccessFlags, MethodName, Prototype, HasCode, RegistersDirective, RegisterCount, Parameters, Annotations,
|
|
||||||
MethodItems) ::=
|
|
||||||
<<
|
|
||||||
.method <AccessFlags: {<it> }><MethodName><Prototype>
|
|
||||||
<if(HasCode)>
|
|
||||||
<RegistersDirective> <RegisterCount>
|
|
||||||
<if(Parameters)>
|
|
||||||
<Parameters; separator="\n">
|
|
||||||
<endif>
|
|
||||||
<if(Annotations)>
|
|
||||||
<Annotations; separator="\n\n">
|
|
||||||
<endif>
|
|
||||||
|
|
||||||
<MethodItems; separator="\n">
|
|
||||||
<elseif(Annotations)>
|
|
||||||
<Annotations; separator="\n\n">
|
|
||||||
<endif>
|
|
||||||
.end method
|
|
||||||
>>
|
|
||||||
|
|
||||||
Parameter(ParameterName, Annotations) ::=
|
|
||||||
<<
|
|
||||||
.parameter<if(ParameterName)> "<ParameterName>"<endif><if(Annotations)>
|
|
||||||
|
|
||||||
<Annotations; separator="\n\n">
|
|
||||||
.end parameter
|
|
||||||
<endif>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format10t(Opcode, TargetLabel) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <TargetLabel>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format10x(Opcode) ::=
|
|
||||||
<<
|
|
||||||
<Opcode>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format11n(Opcode, RegisterA, Literal) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <Literal>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format11x(Opcode, RegisterA) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format12x(Opcode, RegisterA, RegisterB) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format20t(Opcode, TargetLabel) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <TargetLabel>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format21c(Opcode, RegisterA, Reference) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <Reference>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format21h(Opcode, RegisterA, Literal) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <Literal>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format21s(Opcode, RegisterA, Literal) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <Literal>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format21t(Opcode, RegisterA, TargetLabel) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <TargetLabel>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format22b(Opcode, RegisterA, RegisterB, Literal) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>, <Literal>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format22c(Opcode, RegisterA, RegisterB, Reference) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>, <Reference>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format22cs(Opcode, RegisterA, RegisterB, FieldOffset) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>, field@<FieldOffset>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format22s(Opcode, RegisterA, RegisterB, Literal) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>, <Literal>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format22t(Opcode, RegisterA, RegisterB, TargetLabel) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>, <TargetLabel>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format22x(Opcode, RegisterA, RegisterB) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format23x(Opcode, RegisterA, RegisterB, RegisterC) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>, <RegisterC>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format30t(Opcode, TargetLabel) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <TargetLabel>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format31c(Opcode, RegisterA, Reference) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <Reference>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format31i(Opcode, RegisterA, Literal) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <Literal>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format31t(Opcode, RegisterA, TargetLabel) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <TargetLabel>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format32x(Opcode, RegisterA, RegisterB) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <RegisterB>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format35c(Opcode, Registers, Reference) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> {<Registers; separator=", ">}, <Reference>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format35s(Opcode, Registers, Reference) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> {<Registers; separator=", ">}, <Reference>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format35ms(Opcode, Registers, MethodIndex) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> {<Registers; separator=", ">}, vtable@<MethodIndex>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format3rc(Opcode, StartRegister, LastRegister, Reference) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> {<StartRegister> .. <LastRegister>}, <Reference>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format3rms(Opcode, StartRegister, LastRegister, MethodIndex) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> {<StartRegister> .. <LastRegister>}, vtable@<MethodIndex>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Format51l(Opcode, RegisterA, Literal) ::=
|
|
||||||
<<
|
|
||||||
<Opcode> <RegisterA>, <Literal>
|
|
||||||
>>
|
|
||||||
|
|
||||||
CommentedOutMethodItem(MethodItem) ::=
|
|
||||||
<<
|
|
||||||
#<MethodItem>
|
|
||||||
>>
|
|
||||||
|
|
||||||
UnresolvedNullReference(Opcode, Register, UseInvokeRange, AddGoto) ::=
|
|
||||||
<<
|
|
||||||
<if(UseInvokeRange)>
|
|
||||||
#Replaced unresolvable optimized invoke-*-range-quick instruction
|
|
||||||
#with a generic method call that will throw a NullPointerException
|
|
||||||
invoke-virtual/range {<Register> .. <Register>}, Ljava/lang/Object;->hashCode()I
|
|
||||||
<if(AddGoto)>goto/32 0<endif>
|
|
||||||
<else>
|
|
||||||
#Replaced unresolvable optimized instruction with a throw
|
|
||||||
throw <Register>
|
|
||||||
<endif>
|
|
||||||
>>
|
|
||||||
|
|
||||||
|
|
||||||
ArrayData(Opcode, ElementWidth, Values, Dead) ::=
|
|
||||||
<<
|
|
||||||
<if(Dead)>#<endif>.array-data <ElementWidth>
|
|
||||||
<if(Dead)>
|
|
||||||
<Values: {# <it>}; separator="\n">
|
|
||||||
<else>
|
|
||||||
<Values: { <it>}; separator="\n">
|
|
||||||
<endif>
|
|
||||||
|
|
||||||
<if(Dead)>#<endif>.end array-data
|
|
||||||
>>
|
|
||||||
|
|
||||||
ArrayElement(Bytes) ::=
|
|
||||||
<<
|
|
||||||
<Bytes; format="unsigned",separator=" ">
|
|
||||||
>>
|
|
||||||
|
|
||||||
PackedSwitchData(Opcode, FirstKey, Targets, Dead) ::=
|
|
||||||
<<
|
|
||||||
<if(Dead)>#<endif>.packed-switch <FirstKey>
|
|
||||||
<if(Dead)>
|
|
||||||
<Targets: {# <it>}; separator="\n">
|
|
||||||
<else>
|
|
||||||
<Targets: { <it>}; separator="\n">
|
|
||||||
<endif>
|
|
||||||
|
|
||||||
<if(Dead)>#<endif>.end packed-switch
|
|
||||||
>>
|
|
||||||
|
|
||||||
SparseSwitchData(Opcode, Targets, Dead) ::=
|
|
||||||
<<
|
|
||||||
<if(Dead)>#<endif>.sparse-switch
|
|
||||||
<if(Dead)>
|
|
||||||
<Targets: {# <it.Key> -> <it.Target>}; separator="\n">
|
|
||||||
<else>
|
|
||||||
<Targets: { <it.Key> -> <it.Target>}; separator="\n">
|
|
||||||
<endif>
|
|
||||||
|
|
||||||
<if(Dead)>#<endif>.end sparse-switch
|
|
||||||
>>
|
|
||||||
|
|
||||||
|
|
||||||
Label(Prefix, Suffix) ::=
|
|
||||||
<<
|
|
||||||
:<Prefix><Suffix>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Line(Line) ::=
|
|
||||||
<<
|
|
||||||
.line <Line; format="decimal">
|
|
||||||
>>
|
|
||||||
|
|
||||||
EndPrologue(Prologue) ::=
|
|
||||||
<<
|
|
||||||
.prologue
|
|
||||||
>>
|
|
||||||
|
|
||||||
StartEpilogue(Epilogue) ::=
|
|
||||||
<<
|
|
||||||
.epilogue
|
|
||||||
>>
|
|
||||||
|
|
||||||
StartLocal(Register, Name, Type, Signature) ::=
|
|
||||||
<<
|
|
||||||
.local <Register>, <Name>:<Type><if(Signature)>,"<Signature>"<endif>
|
|
||||||
>>
|
|
||||||
|
|
||||||
EndLocal(Register, Name, Type, Signature) ::=
|
|
||||||
<<
|
|
||||||
.end local <Register> <if(Name)>#<Name>:<Type>,<if(Signature)>, "<Signature>"<endif><endif>
|
|
||||||
>>
|
|
||||||
|
|
||||||
RestartLocal(Register, Name, Type, Signature) ::=
|
|
||||||
<<
|
|
||||||
.restart local <Register> <if(Name)>#<Name>:<Type>,<if(Signature)>, "<Signature>"<endif><endif>
|
|
||||||
>>
|
|
||||||
|
|
||||||
SetFile(FileName) ::=
|
|
||||||
<<
|
|
||||||
.source "<FileName>"
|
|
||||||
>>
|
|
||||||
|
|
||||||
Blank(Blank) ::=
|
|
||||||
<<
|
|
||||||
|
|
||||||
>>
|
|
||||||
|
|
||||||
Catch(ExceptionType, StartLabel, EndLabel, HandlerLabel) ::=
|
|
||||||
<<
|
|
||||||
<if(ExceptionType)>.catch <ExceptionType><else>.catchall<endif> {<StartLabel> .. <EndLabel>} <HandlerLabel>
|
|
||||||
>>
|
|
||||||
|
|
||||||
|
|
||||||
StringReference(EscapedValue) ::=
|
|
||||||
<<
|
|
||||||
"<EscapedValue>"
|
|
||||||
>>
|
|
||||||
|
|
||||||
FieldReference(ContainingClass, FieldName, FieldType) ::=
|
|
||||||
<<
|
|
||||||
<ContainingClass>-><FieldName>:<FieldType>
|
|
||||||
>>
|
|
||||||
|
|
||||||
MethodReference(ContainingClass, MethodName, Prototype) ::=
|
|
||||||
<<
|
|
||||||
<ContainingClass>-><MethodName><Prototype>
|
|
||||||
>>
|
|
||||||
|
|
||||||
TypeReference(TypeDescriptor) ::=
|
|
||||||
<<
|
|
||||||
<TypeDescriptor>
|
|
||||||
>>
|
|
||||||
|
|
||||||
|
|
||||||
SimpleEncodedValue(Value) ::=
|
|
||||||
<<
|
|
||||||
<Value>
|
|
||||||
>>
|
|
||||||
|
|
||||||
EncodedIndexedItemReference(Value) ::=
|
|
||||||
<<
|
|
||||||
<Value>
|
|
||||||
>>
|
|
||||||
|
|
||||||
ArrayEncodedValue(Value) ::=
|
|
||||||
<<
|
|
||||||
{
|
|
||||||
<Value; separator=",\n">
|
|
||||||
}
|
|
||||||
>>
|
|
||||||
|
|
||||||
EnumEncodedValue(Value) ::=
|
|
||||||
<<
|
|
||||||
.enum <Value>
|
|
||||||
>>
|
|
||||||
|
|
||||||
AnnotationEncodedValue(AnnotationType, Elements) ::=
|
|
||||||
<<
|
|
||||||
.subannotation <AnnotationType>
|
|
||||||
<Elements; separator="\n">
|
|
||||||
.end subannotation
|
|
||||||
>>
|
|
||||||
|
|
||||||
AnnotationElement(Name, Value) ::=
|
|
||||||
<<
|
|
||||||
<Name> = <Value>
|
|
||||||
>>
|
|
||||||
|
|
||||||
Comment(Comment) ::=
|
|
||||||
<<
|
|
||||||
#<Comment>
|
|
||||||
>>
|
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import org.jf.baksmali.Adaptors.ClassDefinition;
|
||||||
|
import org.jf.dexlib2.DexFileFactory;
|
||||||
|
import org.jf.dexlib2.analysis.ClassPath;
|
||||||
|
import org.jf.dexlib2.iface.ClassDef;
|
||||||
|
import org.jf.dexlib2.iface.DexFile;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class AnalysisTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ConstructorTest() throws IOException, URISyntaxException {
|
||||||
|
runTest("ConstructorTest", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void RegisterEqualityOnMergeTest() throws IOException, URISyntaxException {
|
||||||
|
runTest("RegisterEqualityOnMergeTest", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void UninitRefIdentityTest() throws IOException, URISyntaxException {
|
||||||
|
runTest("UninitRefIdentityTest", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void MultipleStartInstructionsTest() throws IOException, URISyntaxException {
|
||||||
|
runTest("MultipleStartInstructionsTest", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void DuplicateTest() throws IOException, URISyntaxException {
|
||||||
|
runTest("DuplicateTest", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void LocalTest() throws IOException, URISyntaxException {
|
||||||
|
runTest("LocalTest", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runTest(String test, boolean registerInfo) throws IOException, URISyntaxException {
|
||||||
|
String dexFilePath = String.format("%s%sclasses.dex", test, File.separatorChar);
|
||||||
|
|
||||||
|
DexFile dexFile = DexFileFactory.loadDexFile(findResource(dexFilePath), 15);
|
||||||
|
|
||||||
|
baksmaliOptions options = new baksmaliOptions();
|
||||||
|
if (registerInfo) {
|
||||||
|
options.registerInfo = baksmaliOptions.ALL | baksmaliOptions.FULLMERGE;
|
||||||
|
options.classPath = new ClassPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ClassDef classDef: dexFile.getClasses()) {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
IndentingWriter writer = new IndentingWriter(stringWriter);
|
||||||
|
ClassDefinition classDefinition = new ClassDefinition(options, classDef);
|
||||||
|
classDefinition.writeTo(writer);
|
||||||
|
writer.close();
|
||||||
|
|
||||||
|
String className = classDef.getType();
|
||||||
|
String smaliPath = String.format("%s%s%s.smali", test, File.separatorChar,
|
||||||
|
className.substring(1, className.length() - 1));
|
||||||
|
String smaliContents = readResource(smaliPath);
|
||||||
|
|
||||||
|
Assert.assertEquals(smaliContents, stringWriter.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private File findResource(String resource) throws URISyntaxException {
|
||||||
|
URL resUrl = Resources.getResource(resource);
|
||||||
|
return new File(resUrl.toURI());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private String readResource(String resource) throws URISyntaxException, IOException {
|
||||||
|
URL url = Resources.getResource(resource);
|
||||||
|
return Resources.toString(url, Charsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
.class public LConstructorTest;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# direct methods
|
||||||
|
.method public constructor <init>()V
|
||||||
|
.registers 4
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest;);
|
||||||
|
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest;);
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest;);
|
||||||
|
return-void
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest;);
|
||||||
|
.end method
|
@ -0,0 +1,25 @@
|
|||||||
|
.class public LConstructorTest2;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# direct methods
|
||||||
|
.method public constructor <init>()V
|
||||||
|
.registers 4
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;);
|
||||||
|
if-eqz p0, :cond_3
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;);
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;);
|
||||||
|
nop
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;);
|
||||||
|
|
||||||
|
:cond_3
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;);
|
||||||
|
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest2;);
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest2;);
|
||||||
|
return-void
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest2;);
|
||||||
|
.end method
|
Binary file not shown.
@ -0,0 +1,30 @@
|
|||||||
|
.class public LDuplicateDirectMethods;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# direct methods
|
||||||
|
.method private alah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method private blah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
# duplicate method ignored
|
||||||
|
# .method private blah()V
|
||||||
|
# .registers 1
|
||||||
|
|
||||||
|
# return-void
|
||||||
|
# .end method
|
||||||
|
|
||||||
|
|
||||||
|
.method private clah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
@ -0,0 +1,48 @@
|
|||||||
|
.class public LDuplicateDirectVirtualMethods;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# direct methods
|
||||||
|
.method private blah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
# duplicate method ignored
|
||||||
|
# .method private blah()V
|
||||||
|
# .registers 1
|
||||||
|
|
||||||
|
# return-void
|
||||||
|
# .end method
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# virtual methods
|
||||||
|
.method public alah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
# There is both a direct and virtual method with this signature.
|
||||||
|
# You will need to rename one of these methods, including all references.
|
||||||
|
.method public blah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
# duplicate method ignored
|
||||||
|
# .method public blah()V
|
||||||
|
# .registers 1
|
||||||
|
|
||||||
|
# return-void
|
||||||
|
# .end method
|
||||||
|
|
||||||
|
|
||||||
|
.method public clah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
@ -0,0 +1,13 @@
|
|||||||
|
.class public LDuplicateInstanceFields;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# instance fields
|
||||||
|
.field public alah:I
|
||||||
|
|
||||||
|
.field public blah:I
|
||||||
|
|
||||||
|
# duplicate field ignored
|
||||||
|
# .field public blah:I
|
||||||
|
|
||||||
|
.field public clah:I
|
@ -0,0 +1,13 @@
|
|||||||
|
.class public LDuplicateStaticFields;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# static fields
|
||||||
|
.field public static alah:I
|
||||||
|
|
||||||
|
.field public static blah:I
|
||||||
|
|
||||||
|
# duplicate field ignored
|
||||||
|
# .field public static blah:I
|
||||||
|
|
||||||
|
.field public static clah:I
|
@ -0,0 +1,22 @@
|
|||||||
|
.class public LDuplicateStaticInstanceFields;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# static fields
|
||||||
|
.field public static blah:I
|
||||||
|
|
||||||
|
# duplicate field ignored
|
||||||
|
# .field public static blah:I
|
||||||
|
|
||||||
|
|
||||||
|
# instance fields
|
||||||
|
.field public alah:I
|
||||||
|
|
||||||
|
# There is both a static and instance field with this signature.
|
||||||
|
# You will need to rename one of these fields, including all references.
|
||||||
|
.field public blah:I
|
||||||
|
|
||||||
|
# duplicate field ignored
|
||||||
|
# .field public blah:I
|
||||||
|
|
||||||
|
.field public clah:I
|
@ -0,0 +1,30 @@
|
|||||||
|
.class public LDuplicateVirtualMethods;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# virtual methods
|
||||||
|
.method public alah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public blah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
# duplicate method ignored
|
||||||
|
# .method public blah()V
|
||||||
|
# .registers 1
|
||||||
|
|
||||||
|
# return-void
|
||||||
|
# .end method
|
||||||
|
|
||||||
|
|
||||||
|
.method public clah()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
Binary file not shown.
@ -0,0 +1,22 @@
|
|||||||
|
.class public LDuplicateDirectMethods;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
.method private alah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method private blah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method private blah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method private clah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
@ -0,0 +1,32 @@
|
|||||||
|
.class public LDuplicateDirectVirtualMethods;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
.method public alah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method private blah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method private blah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public blah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public blah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public clah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
@ -0,0 +1,9 @@
|
|||||||
|
.class public LDuplicateInstanceFields;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
.field public alah:I
|
||||||
|
|
||||||
|
.field public blah:I
|
||||||
|
.field public blah:I
|
||||||
|
|
||||||
|
.field public clah:I
|
@ -0,0 +1,9 @@
|
|||||||
|
.class public LDuplicateStaticFields;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
.field public static alah:I
|
||||||
|
|
||||||
|
.field public static blah:I
|
||||||
|
.field public static blah:I
|
||||||
|
|
||||||
|
.field public static clah:I
|
@ -0,0 +1,11 @@
|
|||||||
|
.class public LDuplicateStaticInstanceFields;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
.field public alah:I
|
||||||
|
|
||||||
|
.field public blah:I
|
||||||
|
.field public blah:I
|
||||||
|
.field static public blah:I
|
||||||
|
.field static public blah:I
|
||||||
|
|
||||||
|
.field public clah:I
|
@ -0,0 +1,22 @@
|
|||||||
|
.class public LDuplicateVirtualMethods;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
.method public alah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public blah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public blah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public clah()V
|
||||||
|
.registers 1
|
||||||
|
return-void
|
||||||
|
.end method
|
@ -0,0 +1,3 @@
|
|||||||
|
The test dex file was produced from these smali files, using
|
||||||
|
an old version of smali that doesn't check for field/method
|
||||||
|
duplicates
|
@ -0,0 +1,31 @@
|
|||||||
|
.class public LLocalTest;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# direct methods
|
||||||
|
.method public static method1()V
|
||||||
|
.registers 10
|
||||||
|
|
||||||
|
.local v0, "blah! This local name has some spaces, a colon, even a \nnewline!":I, "some sig info:\nblah."
|
||||||
|
.local v1, "blah! This local name has some spaces, a colon, even a \nnewline!":V, "some sig info:\nblah."
|
||||||
|
.local v2, "blah! This local name has some spaces, a colon, even a \nnewline!":I
|
||||||
|
.local v3, "blah! This local name has some spaces, a colon, even a \nnewline!":V
|
||||||
|
.local v4, null:I, "some sig info:\nblah."
|
||||||
|
.local v5, null:V, "some sig info:\nblah."
|
||||||
|
.local v6, null:I
|
||||||
|
.local v7
|
||||||
|
.local v8
|
||||||
|
.local v9
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public static method2(IJLjava/lang/String;)V
|
||||||
|
.registers 10
|
||||||
|
.param p0, "blah! This local name has some spaces, a colon, even a \nnewline!" # I
|
||||||
|
.param p1 # J
|
||||||
|
.annotation runtime LAnnotationWithValues;
|
||||||
|
.end annotation
|
||||||
|
.end param
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
Binary file not shown.
@ -0,0 +1,46 @@
|
|||||||
|
.class public LMultipleStartInstructionsTest;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# direct methods
|
||||||
|
.method public constructor <init>(Ljava/lang/String;)V
|
||||||
|
.registers 4
|
||||||
|
|
||||||
|
:try_start_0
|
||||||
|
#v0=(Uninit);v1=(Uninit);p0=(UninitThis,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;);
|
||||||
|
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||||
|
#v0=(Uninit);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;);
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;);
|
||||||
|
const-string v0, "blah"
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;);
|
||||||
|
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;);
|
||||||
|
return-void
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;);
|
||||||
|
:try_end_6
|
||||||
|
.catchall {:try_start_0 .. :try_end_6} :catchall_6
|
||||||
|
|
||||||
|
:catchall_6
|
||||||
|
:try_start_6
|
||||||
|
#v0=(Uninit);v1=(Uninit);
|
||||||
|
#p0=(Conflicted):merge{Start:(UninitThis,LMultipleStartInstructionsTest;),0x0:(Reference,LMultipleStartInstructionsTest;)}
|
||||||
|
#p1=(Reference,Ljava/lang/String;);
|
||||||
|
invoke-static {}, LMultipleStartInstructionsTest;->blah()V
|
||||||
|
#v0=(Uninit);v1=(Uninit);p0=(Conflicted);p1=(Reference,Ljava/lang/String;);
|
||||||
|
:try_end_9
|
||||||
|
.catchall {:try_start_6 .. :try_end_9} :catchall_9
|
||||||
|
|
||||||
|
:catchall_9
|
||||||
|
#v0=(Uninit);v1=(Uninit);
|
||||||
|
#p0=(Conflicted):merge{Start:(UninitThis,LMultipleStartInstructionsTest;),0x0:(Reference,LMultipleStartInstructionsTest;),0x6:(Conflicted)}
|
||||||
|
#p1=(Reference,Ljava/lang/String;);
|
||||||
|
return-void
|
||||||
|
#v0=(Uninit);v1=(Uninit);p0=(Conflicted);p1=(Reference,Ljava/lang/String;);
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public static blah()V
|
||||||
|
.registers 0
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
Binary file not shown.
@ -0,0 +1,37 @@
|
|||||||
|
.class public LRegisterEqualityOnMerge;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# direct methods
|
||||||
|
.method public constructor <init>()V
|
||||||
|
.registers 4
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LRegisterEqualityOnMerge;);
|
||||||
|
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
invoke-virtual {p0}, Ljava/lang/Object;->toString()Ljava/lang/String;
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
move-result-object v0
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
if-eqz v0, :cond_d
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
invoke-virtual {p0}, Ljava/lang/Object;->toString()Ljava/lang/String;
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
move-result-object v0
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
|
||||||
|
:cond_d
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
return-void
|
||||||
|
#v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;);
|
||||||
|
.end method
|
Binary file not shown.
@ -0,0 +1,50 @@
|
|||||||
|
.class public LUninitRefIdentityTest;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
|
||||||
|
|
||||||
|
# direct methods
|
||||||
|
.method public constructor <init>()V
|
||||||
|
.registers 4
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LUninitRefIdentityTest;);
|
||||||
|
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
|
||||||
|
#v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
new-instance v0, Ljava/lang/String;
|
||||||
|
#v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
|
||||||
|
#v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
if-eqz v0, :cond_9
|
||||||
|
#v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
|
||||||
|
#v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
new-instance v0, Ljava/lang/String;
|
||||||
|
#v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
|
||||||
|
:cond_9
|
||||||
|
#v0=(Conflicted):merge{0x5:(UninitRef,Ljava/lang/String;),0x7:(UninitRef,Ljava/lang/String;)}
|
||||||
|
#v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
invoke-direct {v0}, Ljava/lang/String;-><init>()V
|
||||||
|
#v0=(Unknown);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
|
||||||
|
#v0=(Unknown);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
return-void
|
||||||
|
#v0=(Unknown);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;);
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public constructor <init>(Ljava/lang/String;)V
|
||||||
|
.registers 2
|
||||||
|
|
||||||
|
#p0=(UninitThis,LUninitRefIdentityTest;);p1=(Reference,Ljava/lang/String;);
|
||||||
|
move-object p1, p0
|
||||||
|
#p0=(UninitThis,LUninitRefIdentityTest;);p1=(UninitThis,LUninitRefIdentityTest;);
|
||||||
|
|
||||||
|
#p0=(UninitThis,LUninitRefIdentityTest;);p1=(UninitThis,LUninitRefIdentityTest;);
|
||||||
|
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||||
|
#p0=(Reference,LUninitRefIdentityTest;);p1=(Reference,LUninitRefIdentityTest;);
|
||||||
|
|
||||||
|
#p0=(Reference,LUninitRefIdentityTest;);p1=(Reference,LUninitRefIdentityTest;);
|
||||||
|
return-void
|
||||||
|
#p0=(Reference,LUninitRefIdentityTest;);p1=(Reference,LUninitRefIdentityTest;);
|
||||||
|
.end method
|
Binary file not shown.
1
brut.apktool.smali/dexlib/.gitignore
vendored
1
brut.apktool.smali/dexlib/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/target
|
|
@ -30,7 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':brut.j.dir')
|
compile project(':util')
|
||||||
compile 'com.google.code.findbugs:jsr305:1.3.9'
|
compile depends.findbugs
|
||||||
compile 'com.google.collections:google-collections:1.0'
|
compile depends.guava
|
||||||
}
|
}
|
@ -30,7 +30,7 @@ package org.jf.dexlib;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.dexlib.Util.Input;
|
import org.jf.dexlib.Util.Input;
|
||||||
import org.jf.dexlib.Util.ReadOnlyArrayList;
|
import org.jf.dexlib.Util.ReadOnlyArrayList;
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ package org.jf.dexlib;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import org.jf.dexlib.Util.*;
|
import org.jf.dexlib.Util.*;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -32,7 +32,7 @@ import org.jf.dexlib.Code.*;
|
|||||||
import org.jf.dexlib.Item;
|
import org.jf.dexlib.Item;
|
||||||
import org.jf.dexlib.ItemType;
|
import org.jf.dexlib.ItemType;
|
||||||
import org.jf.dexlib.MethodIdItem;
|
import org.jf.dexlib.MethodIdItem;
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ package org.jf.dexlib.Code.Analysis;
|
|||||||
|
|
||||||
import org.jf.dexlib.*;
|
import org.jf.dexlib.*;
|
||||||
import org.jf.dexlib.Util.AccessFlags;
|
import org.jf.dexlib.Util.AccessFlags;
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.dexlib.Util.SparseArray;
|
import org.jf.dexlib.Util.SparseArray;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -44,8 +44,6 @@ import static org.jf.dexlib.ClassDataItem.EncodedField;
|
|||||||
import static org.jf.dexlib.ClassDataItem.EncodedMethod;
|
import static org.jf.dexlib.ClassDataItem.EncodedMethod;
|
||||||
|
|
||||||
public class ClassPath {
|
public class ClassPath {
|
||||||
public static boolean dontLoadClassPath = false;
|
|
||||||
|
|
||||||
private static ClassPath theClassPath = null;
|
private static ClassPath theClassPath = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -263,10 +261,6 @@ public class ClassPath {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static ClassDef getClassDef(String classType, boolean createUnresolvedClassDef) {
|
public static ClassDef getClassDef(String classType, boolean createUnresolvedClassDef) {
|
||||||
if (dontLoadClassPath) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassDef classDef = theClassPath.classDefs.get(classType);
|
ClassDef classDef = theClassPath.classDefs.get(classType);
|
||||||
if (classDef == null) {
|
if (classDef == null) {
|
||||||
//if it's an array class, try to create it
|
//if it's an array class, try to create it
|
||||||
@ -543,7 +537,7 @@ public class ClassPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ClassDef getSuperclass() {
|
public ClassDef getSuperclass() {
|
||||||
return theClassPath.javaLangObjectClassDef;
|
throw unresolvedValidationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getClassDepth() {
|
public int getClassDepth() {
|
||||||
@ -599,10 +593,6 @@ public class ClassPath {
|
|||||||
|
|
||||||
private final int classDepth;
|
private final int classDepth;
|
||||||
|
|
||||||
// classes can only be public or package-private. Internally, any private/protected inner class is actually
|
|
||||||
// package-private.
|
|
||||||
private final boolean isPublic;
|
|
||||||
|
|
||||||
private final VirtualMethod[] vtable;
|
private final VirtualMethod[] vtable;
|
||||||
|
|
||||||
//this maps a method name of the form method(III)Ljava/lang/String; to an integer
|
//this maps a method name of the form method(III)Ljava/lang/String; to an integer
|
||||||
@ -645,7 +635,6 @@ public class ClassPath {
|
|||||||
implementedInterfaces.add(ClassPath.getClassDef("Ljava/lang/Cloneable;"));
|
implementedInterfaces.add(ClassPath.getClassDef("Ljava/lang/Cloneable;"));
|
||||||
implementedInterfaces.add(ClassPath.getClassDef("Ljava/io/Serializable;"));
|
implementedInterfaces.add(ClassPath.getClassDef("Ljava/io/Serializable;"));
|
||||||
isInterface = false;
|
isInterface = false;
|
||||||
isPublic = true;
|
|
||||||
|
|
||||||
vtable = superclass.vtable;
|
vtable = superclass.vtable;
|
||||||
methodLookup = superclass.methodLookup;
|
methodLookup = superclass.methodLookup;
|
||||||
@ -663,7 +652,6 @@ public class ClassPath {
|
|||||||
this.superclass = null;
|
this.superclass = null;
|
||||||
implementedInterfaces = null;
|
implementedInterfaces = null;
|
||||||
isInterface = false;
|
isInterface = false;
|
||||||
isPublic = true;
|
|
||||||
vtable = null;
|
vtable = null;
|
||||||
methodLookup = null;
|
methodLookup = null;
|
||||||
instanceFields = null;
|
instanceFields = null;
|
||||||
@ -677,7 +665,6 @@ public class ClassPath {
|
|||||||
this.superclass = ClassPath.getClassDef("Ljava/lang/Object;");
|
this.superclass = ClassPath.getClassDef("Ljava/lang/Object;");
|
||||||
implementedInterfaces = new TreeSet<ClassDef>();
|
implementedInterfaces = new TreeSet<ClassDef>();
|
||||||
isInterface = false;
|
isInterface = false;
|
||||||
isPublic = true;
|
|
||||||
|
|
||||||
vtable = superclass.vtable;
|
vtable = superclass.vtable;
|
||||||
methodLookup = superclass.methodLookup;
|
methodLookup = superclass.methodLookup;
|
||||||
@ -692,7 +679,6 @@ public class ClassPath {
|
|||||||
|
|
||||||
protected ClassDef(UnresolvedClassInfo classInfo) {
|
protected ClassDef(UnresolvedClassInfo classInfo) {
|
||||||
classType = classInfo.classType;
|
classType = classInfo.classType;
|
||||||
isPublic = classInfo.isPublic;
|
|
||||||
isInterface = classInfo.isInterface;
|
isInterface = classInfo.isInterface;
|
||||||
|
|
||||||
superclass = loadSuperclass(classInfo);
|
superclass = loadSuperclass(classInfo);
|
||||||
@ -738,6 +724,14 @@ public class ClassPath {
|
|||||||
return superclass;
|
return superclass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VirtualMethod[] getVtable() {
|
||||||
|
return vtable;
|
||||||
|
}
|
||||||
|
|
||||||
|
SparseArray<FieldDef> getInstanceFields() {
|
||||||
|
return instanceFields;
|
||||||
|
}
|
||||||
|
|
||||||
public int getClassDepth() {
|
public int getClassDepth() {
|
||||||
return classDepth;
|
return classDepth;
|
||||||
}
|
}
|
||||||
@ -746,10 +740,6 @@ public class ClassPath {
|
|||||||
return this.isInterface;
|
return this.isInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPublic() {
|
|
||||||
return this.isPublic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean extendsClass(ClassDef superclassDef) {
|
public boolean extendsClass(ClassDef superclassDef) {
|
||||||
if (superclassDef == null) {
|
if (superclassDef == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -1225,7 +1215,7 @@ public class ClassPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class VirtualMethod {
|
static class VirtualMethod {
|
||||||
public String containingClass;
|
public String containingClass;
|
||||||
public String method;
|
public String method;
|
||||||
public boolean isPackagePrivate;
|
public boolean isPackagePrivate;
|
||||||
@ -1238,7 +1228,6 @@ public class ClassPath {
|
|||||||
private static class UnresolvedClassInfo {
|
private static class UnresolvedClassInfo {
|
||||||
public final String dexFilePath;
|
public final String dexFilePath;
|
||||||
public final String classType;
|
public final String classType;
|
||||||
public final boolean isPublic;
|
|
||||||
public final boolean isInterface;
|
public final boolean isInterface;
|
||||||
public final String superclassType;
|
public final String superclassType;
|
||||||
public final String[] interfaces;
|
public final String[] interfaces;
|
||||||
@ -1252,7 +1241,6 @@ public class ClassPath {
|
|||||||
|
|
||||||
classType = classDefItem.getClassType().getTypeDescriptor();
|
classType = classDefItem.getClassType().getTypeDescriptor();
|
||||||
|
|
||||||
isPublic = (classDefItem.getAccessFlags() & AccessFlags.PUBLIC.getValue()) != 0;
|
|
||||||
isInterface = (classDefItem.getAccessFlags() & AccessFlags.INTERFACE.getValue()) != 0;
|
isInterface = (classDefItem.getAccessFlags() & AccessFlags.INTERFACE.getValue()) != 0;
|
||||||
|
|
||||||
TypeIdItem superclassType = classDefItem.getSuperclass();
|
TypeIdItem superclassType = classDefItem.getSuperclass();
|
||||||
|
@ -64,21 +64,19 @@ public class DeodexUtil {
|
|||||||
return inlineMethodResolver.resolveExecuteInline(instruction);
|
return inlineMethodResolver.resolveExecuteInline(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldIdItem lookupField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
|
public FieldIdItem lookupField(ClassPath.ClassDef classDef, int fieldOffset) {
|
||||||
int fieldOffset) {
|
ClassPath.FieldDef field = classDef.getInstanceField(fieldOffset);
|
||||||
ClassPath.FieldDef field = instanceClass.getInstanceField(fieldOffset);
|
|
||||||
if (field == null) {
|
if (field == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseAndResolveField(accessingClass, instanceClass, field);
|
return parseAndResolveField(classDef, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)");
|
private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)");
|
||||||
|
|
||||||
public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
|
public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef classDef, int methodIndex) {
|
||||||
int methodIndex) {
|
String method = classDef.getVirtualMethod(methodIndex);
|
||||||
String method = instanceClass.getVirtualMethod(methodIndex);
|
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -93,20 +91,20 @@ public class DeodexUtil {
|
|||||||
String methodParams = m.group(2);
|
String methodParams = m.group(2);
|
||||||
String methodRet = m.group(3);
|
String methodRet = m.group(3);
|
||||||
|
|
||||||
if (instanceClass instanceof ClassPath.UnresolvedClassDef) {
|
if (classDef instanceof ClassPath.UnresolvedClassDef) {
|
||||||
//if this is an unresolved class, the only way getVirtualMethod could have found a method is if the virtual
|
//if this is an unresolved class, the only way getVirtualMethod could have found a method is if the virtual
|
||||||
//method being looked up was a method on java.lang.Object.
|
//method being looked up was a method on java.lang.Object.
|
||||||
instanceClass = ClassPath.getClassDef("Ljava/lang/Object;");
|
classDef = ClassPath.getClassDef("Ljava/lang/Object;");
|
||||||
} else if (instanceClass.isInterface()) {
|
} else if (classDef.isInterface()) {
|
||||||
instanceClass = instanceClass.getSuperclass();
|
classDef = classDef.getSuperclass();
|
||||||
assert instanceClass != null;
|
assert classDef != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseAndResolveMethod(accessingClass, instanceClass, methodName, methodParams, methodRet);
|
return parseAndResolveMethod(classDef, methodName, methodParams, methodRet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass,
|
private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef classDef, String methodName, String methodParams,
|
||||||
String methodName, String methodParams, String methodRet) {
|
String methodRet) {
|
||||||
StringIdItem methodNameItem = StringIdItem.lookupStringIdItem(dexFile, methodName);
|
StringIdItem methodNameItem = StringIdItem.lookupStringIdItem(dexFile, methodName);
|
||||||
if (methodNameItem == null) {
|
if (methodNameItem == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -199,14 +197,14 @@ public class DeodexUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassPath.ClassDef methodClassDef = definingClass;
|
ClassPath.ClassDef methodClassDef = classDef;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType());
|
TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType());
|
||||||
|
|
||||||
if (classTypeItem != null) {
|
if (classTypeItem != null) {
|
||||||
MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem);
|
MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem);
|
||||||
if (methodIdItem != null && checkClassAccess(accessingClass, methodClassDef)) {
|
if (methodIdItem != null) {
|
||||||
return methodIdItem;
|
return methodIdItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,28 +214,7 @@ public class DeodexUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkClassAccess(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass) {
|
private FieldIdItem parseAndResolveField(ClassPath.ClassDef classDef, ClassPath.FieldDef field) {
|
||||||
return definingClass.isPublic() ||
|
|
||||||
getPackage(accessingClass.getClassType()).equals(getPackage(definingClass.getClassType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getPackage(String classRef) {
|
|
||||||
int lastSlash = classRef.lastIndexOf('/');
|
|
||||||
if (lastSlash < 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return classRef.substring(1, lastSlash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param accessingClass The class that contains the field reference. I.e. the class being deodexed
|
|
||||||
* @param instanceClass The inferred class type of the object that the field is being accessed on
|
|
||||||
* @param field The field being accessed
|
|
||||||
* @return The FieldIdItem of the resolved field
|
|
||||||
*/
|
|
||||||
private FieldIdItem parseAndResolveField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
|
|
||||||
ClassPath.FieldDef field) {
|
|
||||||
String definingClass = field.definingClass;
|
String definingClass = field.definingClass;
|
||||||
String fieldName = field.name;
|
String fieldName = field.name;
|
||||||
String fieldType = field.type;
|
String fieldType = field.type;
|
||||||
@ -252,7 +229,7 @@ public class DeodexUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassPath.ClassDef fieldClass = instanceClass;
|
ClassPath.ClassDef fieldClass = classDef;
|
||||||
|
|
||||||
ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>();
|
ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>();
|
||||||
parents.add(fieldClass);
|
parents.add(fieldClass);
|
||||||
@ -271,7 +248,7 @@ public class DeodexUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem);
|
FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem);
|
||||||
if (fieldIdItem != null && checkClassAccess(accessingClass, fieldClass)) {
|
if (fieldIdItem != null) {
|
||||||
return fieldIdItem;
|
return fieldIdItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,8 +283,7 @@ public class DeodexUtil {
|
|||||||
private void loadMethod(DeodexUtil deodexUtil) {
|
private void loadMethod(DeodexUtil deodexUtil) {
|
||||||
ClassPath.ClassDef classDef = ClassPath.getClassDef(classType);
|
ClassPath.ClassDef classDef = ClassPath.getClassDef(classType);
|
||||||
|
|
||||||
this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, classDef, methodName, parameters,
|
this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, methodName, parameters, returnType);
|
||||||
returnType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMethodString() {
|
public String getMethodString() {
|
||||||
|
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.dexlib.Code.Analysis;
|
||||||
|
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.apache.commons.cli.*;
|
||||||
|
import org.jf.dexlib.ClassDefItem;
|
||||||
|
import org.jf.dexlib.DexFile;
|
||||||
|
import org.jf.dexlib.Util.SparseArray;
|
||||||
|
import org.jf.util.ConsoleUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class DumpFields {
|
||||||
|
private static final Options options;
|
||||||
|
|
||||||
|
static {
|
||||||
|
options = new Options();
|
||||||
|
buildOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
CommandLineParser parser = new PosixParser();
|
||||||
|
CommandLine commandLine;
|
||||||
|
|
||||||
|
try {
|
||||||
|
commandLine = parser.parse(options, args);
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] remainingArgs = commandLine.getArgs();
|
||||||
|
|
||||||
|
Option[] parsedOptions = commandLine.getOptions();
|
||||||
|
ArrayList<String> bootClassPathDirs = Lists.newArrayList();
|
||||||
|
String outFile = "fields.txt";
|
||||||
|
|
||||||
|
for (int i=0; i<parsedOptions.length; i++) {
|
||||||
|
Option option = parsedOptions[i];
|
||||||
|
String opt = option.getOpt();
|
||||||
|
|
||||||
|
switch (opt.charAt(0)) {
|
||||||
|
case 'd':
|
||||||
|
bootClassPathDirs.add(option.getValue());
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
outFile = option.getValue();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainingArgs.length != 1) {
|
||||||
|
usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String inputDexFileName = remainingArgs[0];
|
||||||
|
|
||||||
|
File dexFileFile = new File(inputDexFileName);
|
||||||
|
if (!dexFileFile.exists()) {
|
||||||
|
System.err.println("Can't find the file " + inputDexFileName);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DexFile dexFile = new DexFile(dexFileFile);
|
||||||
|
String[] bootClassPaths = new String[bootClassPathDirs.size()];
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (String bootClassPathDir: bootClassPathDirs) {
|
||||||
|
bootClassPaths[j++] = bootClassPathDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassPath.InitializeClassPathFromOdex(bootClassPaths, null, inputDexFileName, dexFile, false);
|
||||||
|
FileOutputStream outStream = new FileOutputStream(outFile);
|
||||||
|
|
||||||
|
for (ClassDefItem classDefItem: dexFile.ClassDefsSection.getItems()) {
|
||||||
|
ClassPath.ClassDef classDef = ClassPath.getClassDef(classDefItem.getClassType());
|
||||||
|
SparseArray<ClassPath.FieldDef> fields = classDef.getInstanceFields();
|
||||||
|
String className = "Class " + classDef.getClassType() + " : " + fields.size() + " instance fields\n";
|
||||||
|
outStream.write(className.getBytes());
|
||||||
|
for (int i=0;i<fields.size();i++) {
|
||||||
|
String field = fields.keyAt(i) + ":" + fields.valueAt(i).type + " " + fields.valueAt(i).name + "\n";
|
||||||
|
outStream.write(field.getBytes());
|
||||||
|
}
|
||||||
|
outStream.write("\n".getBytes());
|
||||||
|
}
|
||||||
|
outStream.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
System.out.println("IOException thrown when trying to open a dex file or write out vtables: " + ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the usage message.
|
||||||
|
*/
|
||||||
|
private static void usage() {
|
||||||
|
int consoleWidth = ConsoleUtil.getConsoleWidth();
|
||||||
|
if (consoleWidth <= 0) {
|
||||||
|
consoleWidth = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("java -cp baksmali.jar org.jf.dexlib.Code.Analysis.DumpFields -d path/to/jar/files <dex-file>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void buildOptions() {
|
||||||
|
Option classPathDirOption = OptionBuilder.withLongOpt("bootclasspath-dir")
|
||||||
|
.withDescription("the base folder to look for the bootclasspath files in. Defaults to the current " +
|
||||||
|
"directory")
|
||||||
|
.hasArg()
|
||||||
|
.withArgName("DIR")
|
||||||
|
.create("d");
|
||||||
|
|
||||||
|
Option outputFileOption = OptionBuilder.withLongOpt("out-file")
|
||||||
|
.withDescription("output file")
|
||||||
|
.hasArg()
|
||||||
|
.withArgName("FILE")
|
||||||
|
.create("o");
|
||||||
|
|
||||||
|
options.addOption(classPathDirOption);
|
||||||
|
options.addOption(outputFileOption);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.dexlib.Code.Analysis;
|
||||||
|
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.apache.commons.cli.*;
|
||||||
|
import org.jf.dexlib.ClassDefItem;
|
||||||
|
import org.jf.dexlib.DexFile;
|
||||||
|
import org.jf.util.ConsoleUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class DumpVtables {
|
||||||
|
private static final Options options;
|
||||||
|
|
||||||
|
static {
|
||||||
|
options = new Options();
|
||||||
|
buildOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
CommandLineParser parser = new PosixParser();
|
||||||
|
CommandLine commandLine;
|
||||||
|
|
||||||
|
try {
|
||||||
|
commandLine = parser.parse(options, args);
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] remainingArgs = commandLine.getArgs();
|
||||||
|
|
||||||
|
Option[] parsedOptions = commandLine.getOptions();
|
||||||
|
ArrayList<String> bootClassPathDirs = Lists.newArrayList();
|
||||||
|
String outFile = "vtables.txt";
|
||||||
|
|
||||||
|
for (int i=0; i<parsedOptions.length; i++) {
|
||||||
|
Option option = parsedOptions[i];
|
||||||
|
String opt = option.getOpt();
|
||||||
|
|
||||||
|
switch (opt.charAt(0)) {
|
||||||
|
case 'd':
|
||||||
|
bootClassPathDirs.add(option.getValue());
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
outFile = option.getValue();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainingArgs.length != 1) {
|
||||||
|
usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String inputDexFileName = remainingArgs[0];
|
||||||
|
|
||||||
|
File dexFileFile = new File(inputDexFileName);
|
||||||
|
if (!dexFileFile.exists()) {
|
||||||
|
System.err.println("Can't find the file " + inputDexFileName);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DexFile dexFile = new DexFile(dexFileFile);
|
||||||
|
String[] bootClassPaths = new String[bootClassPathDirs.size()];
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (String bootClassPathDir: bootClassPathDirs) {
|
||||||
|
bootClassPaths[j++] = bootClassPathDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassPath.InitializeClassPathFromOdex(bootClassPaths, null, inputDexFileName, dexFile, false);
|
||||||
|
FileOutputStream outStream = new FileOutputStream(outFile);
|
||||||
|
|
||||||
|
for (ClassDefItem classDefItem: dexFile.ClassDefsSection.getItems()) {
|
||||||
|
ClassPath.ClassDef classDef = ClassPath.getClassDef(classDefItem.getClassType());
|
||||||
|
ClassPath.VirtualMethod[] methods = classDef.getVtable();
|
||||||
|
String className = "Class " + classDef.getClassType() + " extends " + classDef.getSuperclass().getClassType() + " : " + methods.length + " methods\n";
|
||||||
|
outStream.write(className.getBytes());
|
||||||
|
for (int i=0;i<methods.length;i++) {
|
||||||
|
String method = i + ":" + methods[i].containingClass + "->" + methods[i].method + "\n";
|
||||||
|
outStream.write(method.getBytes());
|
||||||
|
}
|
||||||
|
outStream.write("\n".getBytes());
|
||||||
|
}
|
||||||
|
outStream.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
System.out.println("IOException thrown when trying to open a dex file or write out vtables: " + ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the usage message.
|
||||||
|
*/
|
||||||
|
private static void usage() {
|
||||||
|
int consoleWidth = ConsoleUtil.getConsoleWidth();
|
||||||
|
if (consoleWidth <= 0) {
|
||||||
|
consoleWidth = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("java -cp baksmali.jar org.jf.dexlib.Code.Analysis.DumpVtables -d path/to/jar/files <dex-file>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void buildOptions() {
|
||||||
|
Option classPathDirOption = OptionBuilder.withLongOpt("bootclasspath-dir")
|
||||||
|
.withDescription("the base folder to look for the bootclasspath files in. Defaults to the current " +
|
||||||
|
"directory")
|
||||||
|
.hasArg()
|
||||||
|
.withArgName("DIR")
|
||||||
|
.create("d");
|
||||||
|
|
||||||
|
Option outputFileOption = OptionBuilder.withLongOpt("out-file")
|
||||||
|
.withDescription("output file")
|
||||||
|
.hasArg()
|
||||||
|
.withArgName("FILE")
|
||||||
|
.create("o");
|
||||||
|
|
||||||
|
options.addOption(classPathDirOption);
|
||||||
|
options.addOption(outputFileOption);
|
||||||
|
}
|
||||||
|
}
|
@ -32,7 +32,7 @@ import org.jf.dexlib.*;
|
|||||||
import org.jf.dexlib.Code.*;
|
import org.jf.dexlib.Code.*;
|
||||||
import org.jf.dexlib.Code.Format.*;
|
import org.jf.dexlib.Code.Format.*;
|
||||||
import org.jf.dexlib.Util.AccessFlags;
|
import org.jf.dexlib.Util.AccessFlags;
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.dexlib.Util.SparseArray;
|
import org.jf.dexlib.Util.SparseArray;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
@ -703,34 +703,28 @@ public class MethodAnalyzer {
|
|||||||
analyzeConstString(analyzedInstruction);
|
analyzeConstString(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case CONST_CLASS:
|
case CONST_CLASS:
|
||||||
case CONST_CLASS_JUMBO:
|
|
||||||
analyzeConstClass(analyzedInstruction);
|
analyzeConstClass(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case MONITOR_ENTER:
|
case MONITOR_ENTER:
|
||||||
case MONITOR_EXIT:
|
case MONITOR_EXIT:
|
||||||
return true;
|
return true;
|
||||||
case CHECK_CAST:
|
case CHECK_CAST:
|
||||||
case CHECK_CAST_JUMBO:
|
|
||||||
analyzeCheckCast(analyzedInstruction);
|
analyzeCheckCast(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case INSTANCE_OF:
|
case INSTANCE_OF:
|
||||||
case INSTANCE_OF_JUMBO:
|
|
||||||
analyzeInstanceOf(analyzedInstruction);
|
analyzeInstanceOf(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case ARRAY_LENGTH:
|
case ARRAY_LENGTH:
|
||||||
analyzeArrayLength(analyzedInstruction);
|
analyzeArrayLength(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case NEW_INSTANCE:
|
case NEW_INSTANCE:
|
||||||
case NEW_INSTANCE_JUMBO:
|
|
||||||
analyzeNewInstance(analyzedInstruction);
|
analyzeNewInstance(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case NEW_ARRAY:
|
case NEW_ARRAY:
|
||||||
case NEW_ARRAY_JUMBO:
|
|
||||||
analyzeNewArray(analyzedInstruction);
|
analyzeNewArray(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case FILLED_NEW_ARRAY:
|
case FILLED_NEW_ARRAY:
|
||||||
case FILLED_NEW_ARRAY_RANGE:
|
case FILLED_NEW_ARRAY_RANGE:
|
||||||
case FILLED_NEW_ARRAY_JUMBO:
|
|
||||||
return true;
|
return true;
|
||||||
case FILL_ARRAY_DATA:
|
case FILL_ARRAY_DATA:
|
||||||
analyzeArrayDataOrSwitch(analyzedInstruction);
|
analyzeArrayDataOrSwitch(analyzedInstruction);
|
||||||
@ -793,86 +787,58 @@ public class MethodAnalyzer {
|
|||||||
case APUT_OBJECT:
|
case APUT_OBJECT:
|
||||||
return true;
|
return true;
|
||||||
case IGET:
|
case IGET:
|
||||||
case IGET_JUMBO:
|
|
||||||
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Integer);
|
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Integer);
|
||||||
return true;
|
return true;
|
||||||
case IGET_BOOLEAN:
|
case IGET_BOOLEAN:
|
||||||
case IGET_BOOLEAN_JUMBO:
|
|
||||||
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Boolean);
|
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Boolean);
|
||||||
return true;
|
return true;
|
||||||
case IGET_BYTE:
|
case IGET_BYTE:
|
||||||
case IGET_BYTE_JUMBO:
|
|
||||||
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Byte);
|
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Byte);
|
||||||
return true;
|
return true;
|
||||||
case IGET_CHAR:
|
case IGET_CHAR:
|
||||||
case IGET_CHAR_JUMBO:
|
|
||||||
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Char);
|
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Char);
|
||||||
return true;
|
return true;
|
||||||
case IGET_SHORT:
|
case IGET_SHORT:
|
||||||
case IGET_SHORT_JUMBO:
|
|
||||||
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Short);
|
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Short);
|
||||||
return true;
|
return true;
|
||||||
case IGET_WIDE:
|
case IGET_WIDE:
|
||||||
case IGET_WIDE_JUMBO:
|
|
||||||
case IGET_OBJECT:
|
case IGET_OBJECT:
|
||||||
case IGET_OBJECT_JUMBO:
|
|
||||||
analyzeIgetWideObject(analyzedInstruction);
|
analyzeIgetWideObject(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case IPUT:
|
case IPUT:
|
||||||
case IPUT_JUMBO:
|
|
||||||
case IPUT_BOOLEAN:
|
case IPUT_BOOLEAN:
|
||||||
case IPUT_BOOLEAN_JUMBO:
|
|
||||||
case IPUT_BYTE:
|
case IPUT_BYTE:
|
||||||
case IPUT_BYTE_JUMBO:
|
|
||||||
case IPUT_CHAR:
|
case IPUT_CHAR:
|
||||||
case IPUT_CHAR_JUMBO:
|
|
||||||
case IPUT_SHORT:
|
case IPUT_SHORT:
|
||||||
case IPUT_SHORT_JUMBO:
|
|
||||||
case IPUT_WIDE:
|
case IPUT_WIDE:
|
||||||
case IPUT_WIDE_JUMBO:
|
|
||||||
case IPUT_OBJECT:
|
case IPUT_OBJECT:
|
||||||
case IPUT_OBJECT_JUMBO:
|
|
||||||
return true;
|
return true;
|
||||||
case SGET:
|
case SGET:
|
||||||
case SGET_JUMBO:
|
|
||||||
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Integer);
|
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Integer);
|
||||||
return true;
|
return true;
|
||||||
case SGET_BOOLEAN:
|
case SGET_BOOLEAN:
|
||||||
case SGET_BOOLEAN_JUMBO:
|
|
||||||
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Boolean);
|
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Boolean);
|
||||||
return true;
|
return true;
|
||||||
case SGET_BYTE:
|
case SGET_BYTE:
|
||||||
case SGET_BYTE_JUMBO:
|
|
||||||
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Byte);
|
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Byte);
|
||||||
return true;
|
return true;
|
||||||
case SGET_CHAR:
|
case SGET_CHAR:
|
||||||
case SGET_CHAR_JUMBO:
|
|
||||||
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Char);
|
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Char);
|
||||||
return true;
|
return true;
|
||||||
case SGET_SHORT:
|
case SGET_SHORT:
|
||||||
case SGET_SHORT_JUMBO:
|
|
||||||
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Short);
|
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Short);
|
||||||
return true;
|
return true;
|
||||||
case SGET_WIDE:
|
case SGET_WIDE:
|
||||||
case SGET_WIDE_JUMBO:
|
|
||||||
case SGET_OBJECT:
|
case SGET_OBJECT:
|
||||||
case SGET_OBJECT_JUMBO:
|
|
||||||
analyzeSgetWideObject(analyzedInstruction);
|
analyzeSgetWideObject(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case SPUT:
|
case SPUT:
|
||||||
case SPUT_JUMBO:
|
|
||||||
case SPUT_BOOLEAN:
|
case SPUT_BOOLEAN:
|
||||||
case SPUT_BOOLEAN_JUMBO:
|
|
||||||
case SPUT_BYTE:
|
case SPUT_BYTE:
|
||||||
case SPUT_BYTE_JUMBO:
|
|
||||||
case SPUT_CHAR:
|
case SPUT_CHAR:
|
||||||
case SPUT_CHAR_JUMBO:
|
|
||||||
case SPUT_SHORT:
|
case SPUT_SHORT:
|
||||||
case SPUT_SHORT_JUMBO:
|
|
||||||
case SPUT_WIDE:
|
case SPUT_WIDE:
|
||||||
case SPUT_WIDE_JUMBO:
|
|
||||||
case SPUT_OBJECT:
|
case SPUT_OBJECT:
|
||||||
case SPUT_OBJECT_JUMBO:
|
|
||||||
return true;
|
return true;
|
||||||
case INVOKE_VIRTUAL:
|
case INVOKE_VIRTUAL:
|
||||||
case INVOKE_SUPER:
|
case INVOKE_SUPER:
|
||||||
@ -883,18 +849,13 @@ public class MethodAnalyzer {
|
|||||||
case INVOKE_STATIC:
|
case INVOKE_STATIC:
|
||||||
case INVOKE_INTERFACE:
|
case INVOKE_INTERFACE:
|
||||||
case INVOKE_VIRTUAL_RANGE:
|
case INVOKE_VIRTUAL_RANGE:
|
||||||
case INVOKE_VIRTUAL_JUMBO:
|
|
||||||
case INVOKE_SUPER_RANGE:
|
case INVOKE_SUPER_RANGE:
|
||||||
case INVOKE_SUPER_JUMBO:
|
|
||||||
return true;
|
return true;
|
||||||
case INVOKE_DIRECT_RANGE:
|
case INVOKE_DIRECT_RANGE:
|
||||||
case INVOKE_DIRECT_JUMBO:
|
|
||||||
analyzeInvokeDirectRange(analyzedInstruction);
|
analyzeInvokeDirectRange(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case INVOKE_STATIC_RANGE:
|
case INVOKE_STATIC_RANGE:
|
||||||
case INVOKE_STATIC_JUMBO:
|
|
||||||
case INVOKE_INTERFACE_RANGE:
|
case INVOKE_INTERFACE_RANGE:
|
||||||
case INVOKE_INTERFACE_JUMBO:
|
|
||||||
return true;
|
return true;
|
||||||
case NEG_INT:
|
case NEG_INT:
|
||||||
case NOT_INT:
|
case NOT_INT:
|
||||||
@ -1115,23 +1076,6 @@ public class MethodAnalyzer {
|
|||||||
case SPUT_OBJECT_VOLATILE:
|
case SPUT_OBJECT_VOLATILE:
|
||||||
analyzePutGetVolatile(analyzedInstruction);
|
analyzePutGetVolatile(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
case INVOKE_OBJECT_INIT_JUMBO:
|
|
||||||
analyzeInvokeObjectInitJumbo(analyzedInstruction);
|
|
||||||
return true;
|
|
||||||
case IGET_VOLATILE_JUMBO:
|
|
||||||
case IGET_WIDE_VOLATILE_JUMBO:
|
|
||||||
case IGET_OBJECT_VOLATILE_JUMBO:
|
|
||||||
case IPUT_VOLATILE_JUMBO:
|
|
||||||
case IPUT_WIDE_VOLATILE_JUMBO:
|
|
||||||
case IPUT_OBJECT_VOLATILE_JUMBO:
|
|
||||||
case SGET_VOLATILE_JUMBO:
|
|
||||||
case SGET_WIDE_VOLATILE_JUMBO:
|
|
||||||
case SGET_OBJECT_VOLATILE_JUMBO:
|
|
||||||
case SPUT_VOLATILE_JUMBO:
|
|
||||||
case SPUT_WIDE_VOLATILE_JUMBO:
|
|
||||||
case SPUT_OBJECT_VOLATILE_JUMBO:
|
|
||||||
analyzePutGetVolatile(analyzedInstruction);
|
|
||||||
return true;
|
|
||||||
default:
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
return true;
|
return true;
|
||||||
@ -1197,7 +1141,6 @@ public class MethodAnalyzer {
|
|||||||
case CONST_STRING_JUMBO:
|
case CONST_STRING_JUMBO:
|
||||||
return;
|
return;
|
||||||
case CONST_CLASS:
|
case CONST_CLASS:
|
||||||
case CONST_CLASS_JUMBO:
|
|
||||||
verifyConstClass(analyzedInstruction);
|
verifyConstClass(analyzedInstruction);
|
||||||
return;
|
return;
|
||||||
case MONITOR_ENTER:
|
case MONITOR_ENTER:
|
||||||
@ -1205,18 +1148,15 @@ public class MethodAnalyzer {
|
|||||||
verifyMonitor(analyzedInstruction);
|
verifyMonitor(analyzedInstruction);
|
||||||
return;
|
return;
|
||||||
case CHECK_CAST:
|
case CHECK_CAST:
|
||||||
case CHECK_CAST_JUMBO:
|
|
||||||
verifyCheckCast(analyzedInstruction);
|
verifyCheckCast(analyzedInstruction);
|
||||||
return;
|
return;
|
||||||
case INSTANCE_OF:
|
case INSTANCE_OF:
|
||||||
case INSTANCE_OF_JUMBO:
|
|
||||||
verifyInstanceOf(analyzedInstruction);
|
verifyInstanceOf(analyzedInstruction);
|
||||||
return;
|
return;
|
||||||
case ARRAY_LENGTH:
|
case ARRAY_LENGTH:
|
||||||
verifyArrayLength(analyzedInstruction);
|
verifyArrayLength(analyzedInstruction);
|
||||||
return;
|
return;
|
||||||
case NEW_INSTANCE:
|
case NEW_INSTANCE:
|
||||||
case NEW_INSTANCE_JUMBO:
|
|
||||||
verifyNewInstance(analyzedInstruction);
|
verifyNewInstance(analyzedInstruction);
|
||||||
return;
|
return;
|
||||||
case NEW_ARRAY:
|
case NEW_ARRAY:
|
||||||
@ -1626,19 +1566,6 @@ public class MethodAnalyzer {
|
|||||||
case IPUT_OBJECT_VOLATILE:
|
case IPUT_OBJECT_VOLATILE:
|
||||||
case SGET_OBJECT_VOLATILE:
|
case SGET_OBJECT_VOLATILE:
|
||||||
case SPUT_OBJECT_VOLATILE:
|
case SPUT_OBJECT_VOLATILE:
|
||||||
case INVOKE_OBJECT_INIT_JUMBO:
|
|
||||||
case IGET_VOLATILE_JUMBO:
|
|
||||||
case IGET_WIDE_VOLATILE_JUMBO:
|
|
||||||
case IGET_OBJECT_VOLATILE_JUMBO:
|
|
||||||
case IPUT_VOLATILE_JUMBO:
|
|
||||||
case IPUT_WIDE_VOLATILE_JUMBO:
|
|
||||||
case IPUT_OBJECT_VOLATILE_JUMBO:
|
|
||||||
case SGET_VOLATILE_JUMBO:
|
|
||||||
case SGET_WIDE_VOLATILE_JUMBO:
|
|
||||||
case SGET_OBJECT_VOLATILE_JUMBO:
|
|
||||||
case SPUT_VOLATILE_JUMBO:
|
|
||||||
case SPUT_WIDE_VOLATILE_JUMBO:
|
|
||||||
case SPUT_OBJECT_VOLATILE_JUMBO:
|
|
||||||
//TODO: throw validation exception?
|
//TODO: throw validation exception?
|
||||||
default:
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
@ -2434,7 +2361,7 @@ public class MethodAnalyzer {
|
|||||||
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
|
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
|
||||||
assert arrayRegisterType != null;
|
assert arrayRegisterType != null;
|
||||||
|
|
||||||
if (! ClassPath.dontLoadClassPath && arrayRegisterType.category != RegisterType.Category.Null) {
|
if (arrayRegisterType.category != RegisterType.Category.Null) {
|
||||||
assert arrayRegisterType.type != null;
|
assert arrayRegisterType.type != null;
|
||||||
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
|
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
|
||||||
throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
|
throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
|
||||||
@ -2503,7 +2430,7 @@ public class MethodAnalyzer {
|
|||||||
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
|
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
|
||||||
assert arrayRegisterType != null;
|
assert arrayRegisterType != null;
|
||||||
|
|
||||||
if (! ClassPath.dontLoadClassPath && arrayRegisterType.category != RegisterType.Category.Null) {
|
if (arrayRegisterType.category != RegisterType.Category.Null) {
|
||||||
assert arrayRegisterType.type != null;
|
assert arrayRegisterType.type != null;
|
||||||
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
|
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
|
||||||
throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
|
throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
|
||||||
@ -3578,14 +3505,7 @@ public class MethodAnalyzer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassPath.ClassDef accessingClass =
|
FieldIdItem fieldIdItem = deodexUtil.lookupField(objectRegisterType.type, fieldOffset);
|
||||||
ClassPath.getClassDef(this.encodedMethod.method.getContainingClass(), false);
|
|
||||||
if (accessingClass == null) {
|
|
||||||
throw new ExceptionWithContext(String.format("Could not find ClassDef for current class: %s",
|
|
||||||
this.encodedMethod.method.getContainingClass()));
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldIdItem fieldIdItem = deodexUtil.lookupField(accessingClass, objectRegisterType.type, fieldOffset);
|
|
||||||
if (fieldIdItem == null) {
|
if (fieldIdItem == null) {
|
||||||
throw new ValidationException(String.format("Could not resolve the field in class %s at offset %d",
|
throw new ValidationException(String.format("Could not resolve the field in class %s at offset %d",
|
||||||
objectRegisterType.type.getClassType(), fieldOffset));
|
objectRegisterType.type.getClassType(), fieldOffset));
|
||||||
@ -3628,16 +3548,12 @@ public class MethodAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MethodIdItem methodIdItem = null;
|
MethodIdItem methodIdItem = null;
|
||||||
ClassPath.ClassDef accessingClass =
|
|
||||||
ClassPath.getClassDef(this.encodedMethod.method.getContainingClass(), false);
|
|
||||||
if (accessingClass == null) {
|
|
||||||
throw new ExceptionWithContext(String.format("Could not find ClassDef for current class: %s",
|
|
||||||
this.encodedMethod.method.getContainingClass()));
|
|
||||||
}
|
|
||||||
if (isSuper) {
|
if (isSuper) {
|
||||||
if (accessingClass.getSuperclass() != null) {
|
ClassPath.ClassDef classDef = ClassPath.getClassDef(this.encodedMethod.method.getContainingClass(), false);
|
||||||
methodIdItem = deodexUtil.lookupVirtualMethod(accessingClass, accessingClass.getSuperclass(),
|
assert classDef != null;
|
||||||
methodIndex);
|
|
||||||
|
if (classDef.getSuperclass() != null) {
|
||||||
|
methodIdItem = deodexUtil.lookupVirtualMethod(classDef.getSuperclass(), methodIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methodIdItem == null) {
|
if (methodIdItem == null) {
|
||||||
@ -3645,10 +3561,10 @@ public class MethodAnalyzer {
|
|||||||
//of from the superclass (although the superclass method is still what would actually be called).
|
//of from the superclass (although the superclass method is still what would actually be called).
|
||||||
//And so the MethodIdItem for the superclass method may not be in the dex file. Let's try to get the
|
//And so the MethodIdItem for the superclass method may not be in the dex file. Let's try to get the
|
||||||
//MethodIdItem for the method in the current class instead
|
//MethodIdItem for the method in the current class instead
|
||||||
methodIdItem = deodexUtil.lookupVirtualMethod(accessingClass, accessingClass, methodIndex);
|
methodIdItem = deodexUtil.lookupVirtualMethod(classDef, methodIndex);
|
||||||
}
|
}
|
||||||
} else{
|
} else{
|
||||||
methodIdItem = deodexUtil.lookupVirtualMethod(accessingClass, objectRegisterType.type, methodIndex);
|
methodIdItem = deodexUtil.lookupVirtualMethod(objectRegisterType.type, methodIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methodIdItem == null) {
|
if (methodIdItem == null) {
|
||||||
@ -3706,23 +3622,12 @@ public class MethodAnalyzer {
|
|||||||
|
|
||||||
if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) {
|
if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) {
|
||||||
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
|
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
|
||||||
if (analyzedInstruction.instruction.opcode.format == Format.Format21c) {
|
deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(), fieldIdItem);
|
||||||
deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(), fieldIdItem);
|
|
||||||
} else {
|
|
||||||
assert(analyzedInstruction.instruction.opcode.format == Format.Format41c);
|
|
||||||
deodexedInstruction = new Instruction41c(opcode, (byte)instruction.getRegisterA(), fieldIdItem);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
|
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
|
||||||
|
|
||||||
if (analyzedInstruction.instruction.opcode.format == Format.Format22c) {
|
deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
|
||||||
deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
|
(byte)instruction.getRegisterB(), fieldIdItem);
|
||||||
(byte)instruction.getRegisterB(), fieldIdItem);
|
|
||||||
} else {
|
|
||||||
assert(analyzedInstruction.instruction.opcode.format == Format.Format52c);
|
|
||||||
deodexedInstruction = new Instruction52c(opcode, (byte)instruction.getRegisterA(),
|
|
||||||
(byte)instruction.getRegisterB(), fieldIdItem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
|
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
|
||||||
@ -3733,17 +3638,6 @@ public class MethodAnalyzer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void analyzeInvokeObjectInitJumbo(AnalyzedInstruction analyzedInstruction) {
|
|
||||||
Instruction5rc instruction = (Instruction5rc)analyzedInstruction.instruction;
|
|
||||||
|
|
||||||
Instruction5rc deodexedInstruction = new Instruction5rc(Opcode.INVOKE_DIRECT_JUMBO,
|
|
||||||
instruction.getRegCount(), instruction.getStartRegister(), instruction.getReferencedItem());
|
|
||||||
|
|
||||||
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
|
|
||||||
|
|
||||||
analyzeInstruction(analyzedInstruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,
|
private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,
|
||||||
RegisterType.Category instructionCategory) {
|
RegisterType.Category instructionCategory) {
|
||||||
if (arrayFieldCategory == instructionCategory) {
|
if (arrayFieldCategory == instructionCategory) {
|
||||||
|
@ -178,107 +178,6 @@ public class OdexedFieldInstructionMapper {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Opcode[][][][] jumboOpcodeMap = new Opcode[][][][] {
|
|
||||||
//get opcodes
|
|
||||||
new Opcode[][][] {
|
|
||||||
//iget volatile
|
|
||||||
new Opcode[][] {
|
|
||||||
//odexed
|
|
||||||
new Opcode[] {
|
|
||||||
/*Z*/ Opcode.IGET_VOLATILE_JUMBO,
|
|
||||||
/*B*/ Opcode.IGET_VOLATILE_JUMBO,
|
|
||||||
/*S*/ Opcode.IGET_VOLATILE_JUMBO,
|
|
||||||
/*C*/ Opcode.IGET_VOLATILE_JUMBO,
|
|
||||||
/*I,F*/ Opcode.IGET_VOLATILE_JUMBO,
|
|
||||||
/*J,D*/ Opcode.IGET_WIDE_VOLATILE_JUMBO,
|
|
||||||
/*L,[*/ Opcode.IGET_OBJECT_VOLATILE_JUMBO
|
|
||||||
},
|
|
||||||
//deodexed
|
|
||||||
new Opcode[] {
|
|
||||||
/*Z*/ Opcode.IGET_BOOLEAN_JUMBO,
|
|
||||||
/*B*/ Opcode.IGET_BYTE_JUMBO,
|
|
||||||
/*S*/ Opcode.IGET_SHORT_JUMBO,
|
|
||||||
/*C*/ Opcode.IGET_CHAR_JUMBO,
|
|
||||||
/*I,F*/ Opcode.IGET_JUMBO,
|
|
||||||
/*J,D*/ Opcode.IGET_WIDE_JUMBO,
|
|
||||||
/*L,[*/ Opcode.IGET_OBJECT_JUMBO
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//sget volatile
|
|
||||||
new Opcode[][] {
|
|
||||||
//odexed
|
|
||||||
new Opcode[] {
|
|
||||||
/*Z*/ Opcode.SGET_VOLATILE_JUMBO,
|
|
||||||
/*B*/ Opcode.SGET_VOLATILE_JUMBO,
|
|
||||||
/*S*/ Opcode.SGET_VOLATILE_JUMBO,
|
|
||||||
/*C*/ Opcode.SGET_VOLATILE_JUMBO,
|
|
||||||
/*I,F*/ Opcode.SGET_VOLATILE_JUMBO,
|
|
||||||
/*J,D*/ Opcode.SGET_WIDE_VOLATILE_JUMBO,
|
|
||||||
/*L,[*/ Opcode.SGET_OBJECT_VOLATILE_JUMBO
|
|
||||||
},
|
|
||||||
//deodexed
|
|
||||||
new Opcode[] {
|
|
||||||
/*Z*/ Opcode.SGET_BOOLEAN_JUMBO,
|
|
||||||
/*B*/ Opcode.SGET_BYTE_JUMBO,
|
|
||||||
/*S*/ Opcode.SGET_SHORT_JUMBO,
|
|
||||||
/*C*/ Opcode.SGET_CHAR_JUMBO,
|
|
||||||
/*I,F*/ Opcode.SGET_JUMBO,
|
|
||||||
/*J,D*/ Opcode.SGET_WIDE_JUMBO,
|
|
||||||
/*L,[*/ Opcode.SGET_OBJECT_JUMBO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//put opcodes
|
|
||||||
new Opcode[][][] {
|
|
||||||
//iput volatile
|
|
||||||
new Opcode[][] {
|
|
||||||
//odexed
|
|
||||||
new Opcode[] {
|
|
||||||
/*Z*/ Opcode.IPUT_VOLATILE_JUMBO,
|
|
||||||
/*B*/ Opcode.IPUT_VOLATILE_JUMBO,
|
|
||||||
/*S*/ Opcode.IPUT_VOLATILE_JUMBO,
|
|
||||||
/*C*/ Opcode.IPUT_VOLATILE_JUMBO,
|
|
||||||
/*I,F*/ Opcode.IPUT_VOLATILE_JUMBO,
|
|
||||||
/*J,D*/ Opcode.IPUT_WIDE_VOLATILE_JUMBO,
|
|
||||||
/*L,[*/ Opcode.IPUT_OBJECT_VOLATILE_JUMBO
|
|
||||||
},
|
|
||||||
//deodexed
|
|
||||||
new Opcode[] {
|
|
||||||
/*Z*/ Opcode.IPUT_BOOLEAN_JUMBO,
|
|
||||||
/*B*/ Opcode.IPUT_BYTE_JUMBO,
|
|
||||||
/*S*/ Opcode.IPUT_SHORT_JUMBO,
|
|
||||||
/*C*/ Opcode.IPUT_CHAR_JUMBO,
|
|
||||||
/*I,F*/ Opcode.IPUT_JUMBO,
|
|
||||||
/*J,D*/ Opcode.IPUT_WIDE_JUMBO,
|
|
||||||
/*L,[*/ Opcode.IPUT_OBJECT_JUMBO
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//sput volatile
|
|
||||||
new Opcode[][] {
|
|
||||||
//odexed
|
|
||||||
new Opcode[] {
|
|
||||||
/*Z*/ Opcode.SPUT_VOLATILE_JUMBO,
|
|
||||||
/*B*/ Opcode.SPUT_VOLATILE_JUMBO,
|
|
||||||
/*S*/ Opcode.SPUT_VOLATILE_JUMBO,
|
|
||||||
/*C*/ Opcode.SPUT_VOLATILE_JUMBO,
|
|
||||||
/*I,F*/ Opcode.SPUT_VOLATILE_JUMBO,
|
|
||||||
/*J,D*/ Opcode.SPUT_WIDE_VOLATILE_JUMBO,
|
|
||||||
/*L,[*/ Opcode.SPUT_OBJECT_VOLATILE_JUMBO
|
|
||||||
},
|
|
||||||
//deodexed
|
|
||||||
new Opcode[] {
|
|
||||||
/*Z*/ Opcode.SPUT_BOOLEAN_JUMBO,
|
|
||||||
/*B*/ Opcode.SPUT_BYTE_JUMBO,
|
|
||||||
/*S*/ Opcode.SPUT_SHORT_JUMBO,
|
|
||||||
/*C*/ Opcode.SPUT_CHAR_JUMBO,
|
|
||||||
/*I,F*/ Opcode.SPUT_JUMBO,
|
|
||||||
/*J,D*/ Opcode.SPUT_WIDE_JUMBO,
|
|
||||||
/*L,[*/ Opcode.SPUT_OBJECT_JUMBO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int getTypeIndex(char type) {
|
private static int getTypeIndex(char type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'Z':
|
case 'Z':
|
||||||
@ -315,20 +214,14 @@ public class OdexedFieldInstructionMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(String fieldType, Opcode odexedOpcode) {
|
static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(String fieldType, Opcode odexedOpcode) {
|
||||||
boolean jumbo = odexedOpcode.isJumboOpcode();
|
|
||||||
int opcodeType = odexedOpcode.setsRegister()?0:1;
|
int opcodeType = odexedOpcode.setsRegister()?0:1;
|
||||||
int opcodeSubType = getOpcodeSubtype(odexedOpcode);
|
int opcodeSubType = getOpcodeSubtype(odexedOpcode);
|
||||||
int typeIndex = getTypeIndex(fieldType.charAt(0));
|
int typeIndex = getTypeIndex(fieldType.charAt(0));
|
||||||
|
|
||||||
Opcode correctOdexedOpcode, deodexedOpcode;
|
Opcode correctOdexedOpcode, deodexedOpcode;
|
||||||
|
|
||||||
if (jumbo) {
|
correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex];
|
||||||
correctOdexedOpcode = jumboOpcodeMap[opcodeType][opcodeSubType-1][0][typeIndex];
|
deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex];
|
||||||
deodexedOpcode = jumboOpcodeMap[opcodeType][opcodeSubType-1][1][typeIndex];
|
|
||||||
} else {
|
|
||||||
correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex];
|
|
||||||
deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (correctOdexedOpcode != odexedOpcode) {
|
if (correctOdexedOpcode != odexedOpcode) {
|
||||||
throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType,
|
throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType,
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
package org.jf.dexlib.Code.Analysis;
|
package org.jf.dexlib.Code.Analysis;
|
||||||
|
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
public class ValidationException extends ExceptionWithContext {
|
public class ValidationException extends ExceptionWithContext {
|
||||||
private int codeAddress;
|
private int codeAddress;
|
||||||
|
@ -60,10 +60,7 @@ public enum Format {
|
|||||||
Format3rc(Instruction3rc.Factory, 6),
|
Format3rc(Instruction3rc.Factory, 6),
|
||||||
Format3rmi(Instruction3rmi.Factory, 6),
|
Format3rmi(Instruction3rmi.Factory, 6),
|
||||||
Format3rms(Instruction3rms.Factory, 6),
|
Format3rms(Instruction3rms.Factory, 6),
|
||||||
Format41c(Instruction41c.Factory, 8),
|
|
||||||
Format51l(Instruction51l.Factory, 10),
|
Format51l(Instruction51l.Factory, 10),
|
||||||
Format52c(Instruction52c.Factory, 10),
|
|
||||||
Format5rc(Instruction5rc.Factory, 10),
|
|
||||||
ArrayData(null, -1, true),
|
ArrayData(null, -1, true),
|
||||||
PackedSwitchData(null, -1, true),
|
PackedSwitchData(null, -1, true),
|
||||||
SparseSwitchData(null, -1, true),
|
SparseSwitchData(null, -1, true),
|
||||||
|
@ -100,11 +100,7 @@ public class Instruction21c extends InstructionWithReference implements SingleRe
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jumboOpcode.format == Format.Format31c) {
|
return new Instruction31c(jumboOpcode, (short)getRegisterA(), getReferencedItem());
|
||||||
return new Instruction31c(jumboOpcode, (short)getRegisterA(), getReferencedItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Instruction41c(jumboOpcode, getRegisterA(), getReferencedItem());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Factory implements Instruction.InstructionFactory {
|
private static class Factory implements Instruction.InstructionFactory {
|
||||||
|
@ -37,8 +37,7 @@ import org.jf.dexlib.Item;
|
|||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||||
import org.jf.dexlib.Util.NumberUtils;
|
import org.jf.dexlib.Util.NumberUtils;
|
||||||
|
|
||||||
public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction,
|
public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction {
|
||||||
InstructionWithJumboVariant {
|
|
||||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||||
private byte regA;
|
private byte regA;
|
||||||
private byte regB;
|
private byte regB;
|
||||||
@ -89,15 +88,6 @@ public class Instruction22c extends InstructionWithReference implements TwoRegis
|
|||||||
return regB;
|
return regB;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction makeJumbo() {
|
|
||||||
Opcode jumboOpcode = opcode.getJumboOpcode();
|
|
||||||
if (jumboOpcode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Instruction52c(jumboOpcode, getRegisterA(), getRegisterB(), getReferencedItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Factory implements Instruction.InstructionFactory {
|
private static class Factory implements Instruction.InstructionFactory {
|
||||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||||
return new Instruction22c(dexFile, opcode, buffer, bufferIndex);
|
return new Instruction22c(dexFile, opcode, buffer, bufferIndex);
|
||||||
|
@ -41,8 +41,7 @@ import org.jf.dexlib.Util.NumberUtils;
|
|||||||
|
|
||||||
import static org.jf.dexlib.Code.Opcode.*;
|
import static org.jf.dexlib.Code.Opcode.*;
|
||||||
|
|
||||||
public class Instruction3rc extends InstructionWithReference implements RegisterRangeInstruction,
|
public class Instruction3rc extends InstructionWithReference implements RegisterRangeInstruction {
|
||||||
InstructionWithJumboVariant {
|
|
||||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||||
private byte regCount;
|
private byte regCount;
|
||||||
private short startReg;
|
private short startReg;
|
||||||
@ -131,15 +130,6 @@ public class Instruction3rc extends InstructionWithReference implements Register
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction makeJumbo() {
|
|
||||||
Opcode jumboOpcode = opcode.getJumboOpcode();
|
|
||||||
if (jumboOpcode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Instruction5rc(jumboOpcode, getRegCount(), getStartRegister(), getReferencedItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Factory implements Instruction.InstructionFactory {
|
private static class Factory implements Instruction.InstructionFactory {
|
||||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||||
return new Instruction3rc(dexFile, opcode, buffer, bufferIndex);
|
return new Instruction3rc(dexFile, opcode, buffer, bufferIndex);
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011, Google Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above
|
|
||||||
* copyright notice, this list of conditions and the following disclaimer
|
|
||||||
* in the documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
* * Neither the name of Google Inc. nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from
|
|
||||||
* this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jf.dexlib.Code.Format;
|
|
||||||
|
|
||||||
import org.jf.dexlib.Code.Instruction;
|
|
||||||
import org.jf.dexlib.Code.InstructionWithReference;
|
|
||||||
import org.jf.dexlib.Code.Opcode;
|
|
||||||
import org.jf.dexlib.Code.SingleRegisterInstruction;
|
|
||||||
import org.jf.dexlib.DexFile;
|
|
||||||
import org.jf.dexlib.Item;
|
|
||||||
import org.jf.dexlib.TypeIdItem;
|
|
||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
|
||||||
import org.jf.dexlib.Util.NumberUtils;
|
|
||||||
|
|
||||||
public class Instruction41c extends InstructionWithJumboReference implements SingleRegisterInstruction {
|
|
||||||
public static final InstructionFactory Factory = new Factory();
|
|
||||||
private short regA;
|
|
||||||
|
|
||||||
public Instruction41c(Opcode opcode, int regA, Item referencedItem) {
|
|
||||||
super(opcode, referencedItem);
|
|
||||||
|
|
||||||
if (regA >= 1 << 16) {
|
|
||||||
throw new RuntimeException("The register number must be less than v65536");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opcode == Opcode.NEW_INSTANCE_JUMBO) {
|
|
||||||
assert referencedItem instanceof TypeIdItem;
|
|
||||||
if (((TypeIdItem)referencedItem).getTypeDescriptor().charAt(0) != 'L') {
|
|
||||||
throw new RuntimeException("Only class references can be used with the new-instance/jumbo opcode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.regA = (short)regA;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Instruction41c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
|
||||||
super(dexFile, opcode, buffer, bufferIndex);
|
|
||||||
|
|
||||||
if (opcode == Opcode.NEW_INSTANCE_JUMBO &&
|
|
||||||
((TypeIdItem)this.getReferencedItem()).getTypeDescriptor().charAt(0) != 'L') {
|
|
||||||
|
|
||||||
throw new RuntimeException("Only class references can be used with the new-instance/jumbo opcode");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.regA = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
|
|
||||||
out.writeByte(0xFF);
|
|
||||||
out.writeByte(opcode.value);
|
|
||||||
out.writeInt(getReferencedItem().getIndex());
|
|
||||||
out.writeShort(getRegisterA());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Format getFormat() {
|
|
||||||
return Format.Format41c;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRegisterA() {
|
|
||||||
return regA & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Factory implements InstructionFactory {
|
|
||||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
|
||||||
return new Instruction41c(dexFile, opcode, buffer, bufferIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011, Google Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above
|
|
||||||
* copyright notice, this list of conditions and the following disclaimer
|
|
||||||
* in the documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
* * Neither the name of Google Inc. nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from
|
|
||||||
* this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jf.dexlib.Code.Format;
|
|
||||||
|
|
||||||
import org.jf.dexlib.Code.Instruction;
|
|
||||||
import org.jf.dexlib.Code.Opcode;
|
|
||||||
import org.jf.dexlib.Code.TwoRegisterInstruction;
|
|
||||||
import org.jf.dexlib.DexFile;
|
|
||||||
import org.jf.dexlib.Item;
|
|
||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
|
||||||
import org.jf.dexlib.Util.NumberUtils;
|
|
||||||
|
|
||||||
public class Instruction52c extends InstructionWithJumboReference implements TwoRegisterInstruction {
|
|
||||||
public static final InstructionFactory Factory = new Factory();
|
|
||||||
private short regA;
|
|
||||||
private short regB;
|
|
||||||
|
|
||||||
public Instruction52c(Opcode opcode, int regA, int regB, Item referencedItem) {
|
|
||||||
super(opcode, referencedItem);
|
|
||||||
|
|
||||||
if (regA >= 1 << 16) {
|
|
||||||
throw new RuntimeException("The register number must be less than v65536");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (regB >= 1 << 16) {
|
|
||||||
throw new RuntimeException("The register number must be less than v65536");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.regA = (short)regA;
|
|
||||||
this.regB = (short)regB;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Instruction52c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
|
||||||
super(dexFile, opcode, buffer, bufferIndex);
|
|
||||||
|
|
||||||
this.regA = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 6);
|
|
||||||
this.regB = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
|
|
||||||
out.writeByte(0xFF);
|
|
||||||
out.writeByte(opcode.value);
|
|
||||||
out.writeInt(getReferencedItem().getIndex());
|
|
||||||
out.writeShort(getRegisterA());
|
|
||||||
out.writeShort(getRegisterB());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Format getFormat() {
|
|
||||||
return Format.Format52c;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRegisterA() {
|
|
||||||
return regA & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRegisterB() {
|
|
||||||
return regB & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Factory implements InstructionFactory {
|
|
||||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
|
||||||
return new Instruction52c(dexFile, opcode, buffer, bufferIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,133 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011, Google Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above
|
|
||||||
* copyright notice, this list of conditions and the following disclaimer
|
|
||||||
* in the documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
* * Neither the name of Google Inc. nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from
|
|
||||||
* this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jf.dexlib.Code.Format;
|
|
||||||
|
|
||||||
import org.jf.dexlib.Code.Instruction;
|
|
||||||
import org.jf.dexlib.Code.InstructionWithReference;
|
|
||||||
import org.jf.dexlib.Code.Opcode;
|
|
||||||
import org.jf.dexlib.Code.RegisterRangeInstruction;
|
|
||||||
import org.jf.dexlib.DexFile;
|
|
||||||
import org.jf.dexlib.Item;
|
|
||||||
import org.jf.dexlib.MethodIdItem;
|
|
||||||
import org.jf.dexlib.TypeIdItem;
|
|
||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
|
||||||
import org.jf.dexlib.Util.NumberUtils;
|
|
||||||
|
|
||||||
import static org.jf.dexlib.Code.Opcode.*;
|
|
||||||
|
|
||||||
public class Instruction5rc extends InstructionWithJumboReference implements RegisterRangeInstruction {
|
|
||||||
public static final InstructionFactory Factory = new Factory();
|
|
||||||
private short regCount;
|
|
||||||
private short startReg;
|
|
||||||
|
|
||||||
public Instruction5rc(Opcode opcode, int regCount, int startReg, Item referencedItem) {
|
|
||||||
super(opcode, referencedItem);
|
|
||||||
|
|
||||||
if (regCount >= 1 << 16) {
|
|
||||||
throw new RuntimeException("regCount must be less than 65536");
|
|
||||||
}
|
|
||||||
if (regCount < 0) {
|
|
||||||
throw new RuntimeException("regCount cannot be negative");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startReg >= 1 << 16) {
|
|
||||||
throw new RuntimeException("The beginning register of the range must be less than 65536");
|
|
||||||
}
|
|
||||||
if (startReg < 0) {
|
|
||||||
throw new RuntimeException("The beginning register of the range cannot be negative");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.regCount = (short)regCount;
|
|
||||||
this.startReg = (short)startReg;
|
|
||||||
|
|
||||||
checkItem(opcode, referencedItem, regCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Instruction5rc(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
|
||||||
super(dexFile, opcode, buffer, bufferIndex);
|
|
||||||
|
|
||||||
this.regCount = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 6);
|
|
||||||
this.startReg = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 8);
|
|
||||||
|
|
||||||
checkItem(opcode, getReferencedItem(), getRegCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
|
|
||||||
out.writeByte(0xff);
|
|
||||||
out.writeByte(opcode.value);
|
|
||||||
out.writeInt(this.getReferencedItem().getIndex());
|
|
||||||
out.writeShort(regCount);
|
|
||||||
out.writeShort(startReg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Format getFormat() {
|
|
||||||
return Format.Format5rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRegCount() {
|
|
||||||
return regCount & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStartRegister() {
|
|
||||||
return startReg & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkItem(Opcode opcode, Item item, int regCount) {
|
|
||||||
if (opcode == FILLED_NEW_ARRAY_JUMBO) {
|
|
||||||
//check data for filled-new-array/jumbo opcode
|
|
||||||
String type = ((TypeIdItem) item).getTypeDescriptor();
|
|
||||||
if (type.charAt(0) != '[') {
|
|
||||||
throw new RuntimeException("The type must be an array type");
|
|
||||||
}
|
|
||||||
if (type.charAt(1) == 'J' || type.charAt(1) == 'D') {
|
|
||||||
throw new RuntimeException("The type cannot be an array of longs or doubles");
|
|
||||||
}
|
|
||||||
} else if (opcode.value >= INVOKE_VIRTUAL_JUMBO.value && opcode.value <= INVOKE_INTERFACE_JUMBO.value ||
|
|
||||||
opcode == INVOKE_OBJECT_INIT_JUMBO) {
|
|
||||||
//check data for invoke-*/range opcodes
|
|
||||||
MethodIdItem methodIdItem = (MethodIdItem) item;
|
|
||||||
int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount();
|
|
||||||
if (opcode != INVOKE_STATIC_JUMBO) {
|
|
||||||
parameterRegisterCount++;
|
|
||||||
}
|
|
||||||
if (parameterRegisterCount != regCount) {
|
|
||||||
throw new RuntimeException("regCount does not match the number of arguments of the method");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Factory implements InstructionFactory {
|
|
||||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
|
||||||
return new Instruction5rc(dexFile, opcode, buffer, bufferIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -30,8 +30,7 @@ package org.jf.dexlib.Code;
|
|||||||
|
|
||||||
import org.jf.dexlib.Code.Format.*;
|
import org.jf.dexlib.Code.Format.*;
|
||||||
import org.jf.dexlib.DexFile;
|
import org.jf.dexlib.DexFile;
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.dexlib.Util.Hex;
|
|
||||||
|
|
||||||
public class InstructionIterator {
|
public class InstructionIterator {
|
||||||
public static void IterateInstructions(DexFile dexFile, byte[] insns, ProcessInstructionDelegate delegate) {
|
public static void IterateInstructions(DexFile dexFile, byte[] insns, ProcessInstructionDelegate delegate) {
|
||||||
|
@ -62,16 +62,16 @@ public enum Opcode
|
|||||||
CONST_WIDE_HIGH16((short)0x19, "const-wide/high16", ReferenceType.none, Format.Format21h, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
|
CONST_WIDE_HIGH16((short)0x19, "const-wide/high16", ReferenceType.none, Format.Format21h, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
|
||||||
CONST_STRING((short)0x1a, "const-string", ReferenceType.string, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0x1b),
|
CONST_STRING((short)0x1a, "const-string", ReferenceType.string, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0x1b),
|
||||||
CONST_STRING_JUMBO((short)0x1b, "const-string/jumbo", ReferenceType.string, Format.Format31c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
CONST_STRING_JUMBO((short)0x1b, "const-string/jumbo", ReferenceType.string, Format.Format31c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
CONST_CLASS((short)0x1c, "const-class", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff00),
|
CONST_CLASS((short)0x1c, "const-class", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
MONITOR_ENTER((short)0x1d, "monitor-enter", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
MONITOR_ENTER((short)0x1d, "monitor-enter", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
MONITOR_EXIT((short)0x1e, "monitor-exit", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
MONITOR_EXIT((short)0x1e, "monitor-exit", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
CHECK_CAST((short)0x1f, "check-cast", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff01),
|
CHECK_CAST((short)0x1f, "check-cast", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
INSTANCE_OF((short)0x20, "instance-of", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff02),
|
INSTANCE_OF((short)0x20, "instance-of", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
ARRAY_LENGTH((short)0x21, "array-length", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
ARRAY_LENGTH((short)0x21, "array-length", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
NEW_INSTANCE((short)0x22, "new-instance", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff03),
|
NEW_INSTANCE((short)0x22, "new-instance", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
NEW_ARRAY((short)0x23, "new-array", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff04),
|
NEW_ARRAY((short)0x23, "new-array", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
FILLED_NEW_ARRAY((short)0x24, "filled-new-array", ReferenceType.type, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
FILLED_NEW_ARRAY((short)0x24, "filled-new-array", ReferenceType.type, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
FILLED_NEW_ARRAY_RANGE((short)0x25, "filled-new-array/range", ReferenceType.type, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff05),
|
FILLED_NEW_ARRAY_RANGE((short)0x25, "filled-new-array/range", ReferenceType.type, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
FILL_ARRAY_DATA((short)0x26, "fill-array-data", ReferenceType.none, Format.Format31t, Opcode.CAN_CONTINUE),
|
FILL_ARRAY_DATA((short)0x26, "fill-array-data", ReferenceType.none, Format.Format31t, Opcode.CAN_CONTINUE),
|
||||||
THROW((short)0x27, "throw", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW),
|
THROW((short)0x27, "throw", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW),
|
||||||
GOTO((short)0x28, "goto", ReferenceType.none, Format.Format10t),
|
GOTO((short)0x28, "goto", ReferenceType.none, Format.Format10t),
|
||||||
@ -110,44 +110,44 @@ public enum Opcode
|
|||||||
APUT_BYTE((short)0x4f, "aput-byte", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
APUT_BYTE((short)0x4f, "aput-byte", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
APUT_CHAR((short)0x50, "aput-char", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
APUT_CHAR((short)0x50, "aput-char", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
APUT_SHORT((short)0x51, "aput-short", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
APUT_SHORT((short)0x51, "aput-short", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
IGET((short)0x52, "iget", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff06),
|
IGET((short)0x52, "iget", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
IGET_WIDE((short)0x53, "iget-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER, (short)0xff07),
|
IGET_WIDE((short)0x53, "iget-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
|
||||||
IGET_OBJECT((short)0x54, "iget-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff08),
|
IGET_OBJECT((short)0x54, "iget-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
IGET_BOOLEAN((short)0x55, "iget-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff09),
|
IGET_BOOLEAN((short)0x55, "iget-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
IGET_BYTE((short)0x56, "iget-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0a),
|
IGET_BYTE((short)0x56, "iget-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
IGET_CHAR((short)0x57, "iget-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0b),
|
IGET_CHAR((short)0x57, "iget-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
IGET_SHORT((short)0x58, "iget-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0c),
|
IGET_SHORT((short)0x58, "iget-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
IPUT((short)0x59, "iput", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0d),
|
IPUT((short)0x59, "iput", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
IPUT_WIDE((short)0x5a, "iput-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0e),
|
IPUT_WIDE((short)0x5a, "iput-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
IPUT_OBJECT((short)0x5b, "iput-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0f),
|
IPUT_OBJECT((short)0x5b, "iput-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
IPUT_BOOLEAN((short)0x5c, "iput-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff10),
|
IPUT_BOOLEAN((short)0x5c, "iput-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
IPUT_BYTE((short)0x5d, "iput-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff11),
|
IPUT_BYTE((short)0x5d, "iput-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
IPUT_CHAR((short)0x5e, "iput-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff12),
|
IPUT_CHAR((short)0x5e, "iput-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
IPUT_SHORT((short)0x5f, "iput-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff13),
|
IPUT_SHORT((short)0x5f, "iput-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
SGET((short)0x60, "sget", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff14),
|
SGET((short)0x60, "sget", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
SGET_WIDE((short)0x61, "sget-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER, (short)0xff15),
|
SGET_WIDE((short)0x61, "sget-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
|
||||||
SGET_OBJECT((short)0x62, "sget-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff16),
|
SGET_OBJECT((short)0x62, "sget-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
SGET_BOOLEAN((short)0x63, "sget-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff17),
|
SGET_BOOLEAN((short)0x63, "sget-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
SGET_BYTE((short)0x64, "sget-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff18),
|
SGET_BYTE((short)0x64, "sget-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
SGET_CHAR((short)0x65, "sget-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff19),
|
SGET_CHAR((short)0x65, "sget-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
SGET_SHORT((short)0x66, "sget-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff1a),
|
SGET_SHORT((short)0x66, "sget-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
SPUT((short)0x67, "sput", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1b),
|
SPUT((short)0x67, "sput", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
SPUT_WIDE((short)0x68, "sput-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1c),
|
SPUT_WIDE((short)0x68, "sput-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
SPUT_OBJECT((short)0x69, "sput-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1d),
|
SPUT_OBJECT((short)0x69, "sput-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
SPUT_BOOLEAN((short)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1e),
|
SPUT_BOOLEAN((short)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
SPUT_BYTE((short)0x6b, "sput-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1f),
|
SPUT_BYTE((short)0x6b, "sput-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
SPUT_CHAR((short)0x6c, "sput-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff20),
|
SPUT_CHAR((short)0x6c, "sput-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
SPUT_SHORT((short)0x6d, "sput-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff21),
|
SPUT_SHORT((short)0x6d, "sput-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
INVOKE_VIRTUAL((short)0x6e, "invoke-virtual", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
INVOKE_VIRTUAL((short)0x6e, "invoke-virtual", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
INVOKE_SUPER((short)0x6f, "invoke-super", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
INVOKE_SUPER((short)0x6f, "invoke-super", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
INVOKE_DIRECT((short)0x70, "invoke-direct", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
|
INVOKE_DIRECT((short)0x70, "invoke-direct", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
|
||||||
INVOKE_STATIC((short)0x71, "invoke-static", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
INVOKE_STATIC((short)0x71, "invoke-static", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
INVOKE_INTERFACE((short)0x72, "invoke-interface", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
INVOKE_INTERFACE((short)0x72, "invoke-interface", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
INVOKE_VIRTUAL_RANGE((short)0x74, "invoke-virtual/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff22),
|
INVOKE_VIRTUAL_RANGE((short)0x74, "invoke-virtual/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
INVOKE_SUPER_RANGE((short)0x75, "invoke-super/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff23),
|
INVOKE_SUPER_RANGE((short)0x75, "invoke-super/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
INVOKE_DIRECT_RANGE((short)0x76, "invoke-direct/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE, (short)0xff24),
|
INVOKE_DIRECT_RANGE((short)0x76, "invoke-direct/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
|
||||||
INVOKE_STATIC_RANGE((short)0x77, "invoke-static/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff25),
|
INVOKE_STATIC_RANGE((short)0x77, "invoke-static/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
INVOKE_INTERFACE_RANGE((short)0x78, "invoke-interface/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff26),
|
INVOKE_INTERFACE_RANGE((short)0x78, "invoke-interface/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
NEG_INT((short)0x7b, "neg-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
NEG_INT((short)0x7b, "neg-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
NOT_INT((short)0x7c, "not-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
NOT_INT((short)0x7c, "not-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
NEG_LONG((short)0x7d, "neg-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
|
NEG_LONG((short)0x7d, "neg-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
|
||||||
@ -282,61 +282,7 @@ public enum Opcode
|
|||||||
|
|
||||||
IPUT_OBJECT_VOLATILE((short)0xfc, "iput-object-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
IPUT_OBJECT_VOLATILE((short)0xfc, "iput-object-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||||
SGET_OBJECT_VOLATILE((short)0xfd, "sget-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
SGET_OBJECT_VOLATILE((short)0xfd, "sget-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
SPUT_OBJECT_VOLATILE((short)0xfe, "sput-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
SPUT_OBJECT_VOLATILE((short)0xfe, "sput-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE);
|
||||||
|
|
||||||
CONST_CLASS_JUMBO((short)0xff00, "const-class/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
CHECK_CAST_JUMBO((short)0xff01, "check-cast/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
INSTANCE_OF_JUMBO((short)0xff02, "instance-of/jumbo", ReferenceType.type, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
NEW_INSTANCE_JUMBO((short)0xff03, "new-instance/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
NEW_ARRAY_JUMBO((short)0xff04, "new-array/jumbo", ReferenceType.type, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
FILLED_NEW_ARRAY_JUMBO((short)0xff05, "filled-new-array/jumbo", ReferenceType.type, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_JUMBO((short)0xff06, "iget/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_WIDE_JUMBO((short)0xff07, "iget-wide/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_OBJECT_JUMBO((short)0xff08, "iget-object/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_BOOLEAN_JUMBO((short)0xff09, "iget-boolean/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_BYTE_JUMBO((short)0xff0a, "iget-byte/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_CHAR_JUMBO((short)0xff0b, "iget-char/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_SHORT_JUMBO((short)0xff0c, "iget-short/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_JUMBO((short)0xff0d, "iput/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_WIDE_JUMBO((short)0xff0e, "iput-wide/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_OBJECT_JUMBO((short)0xff0f, "iput-object/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_BOOLEAN_JUMBO((short)0xff10, "iput-boolean/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_BYTE_JUMBO((short)0xff11, "iput-byte/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_CHAR_JUMBO((short)0xff12, "iput-char/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_SHORT_JUMBO((short)0xff13, "iput-short/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_JUMBO((short)0xff14, "sget/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_WIDE_JUMBO((short)0xff15, "sget-wide/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_OBJECT_JUMBO((short)0xff16, "sget-object/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_BOOLEAN_JUMBO((short)0xff17, "sget-boolean/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_BYTE_JUMBO((short)0xff18, "sget-byte/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_CHAR_JUMBO((short)0xff19, "sget-char/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_SHORT_JUMBO((short)0xff1a, "sget-short/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_JUMBO((short)0xff1b, "sput/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_WIDE_JUMBO((short)0xff1c, "sput-wide/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_OBJECT_JUMBO((short)0xff1d, "sput-object/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_BOOLEAN_JUMBO((short)0xff1e, "sput-boolean/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_BYTE_JUMBO((short)0xff1f, "sput-byte/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_CHAR_JUMBO((short)0xff20, "sput-char/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_SHORT_JUMBO((short)0xff21, "sput-short/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
INVOKE_VIRTUAL_JUMBO((short)0xff22, "invoke-virtual/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
|
|
||||||
INVOKE_SUPER_JUMBO((short)0xff23, "invoke-super/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
|
|
||||||
INVOKE_DIRECT_JUMBO((short)0xff24, "invoke-direct/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE | Opcode.CAN_INITIALIZE_REFERENCE),
|
|
||||||
INVOKE_STATIC_JUMBO((short)0xff25, "invoke-static/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
|
|
||||||
INVOKE_INTERFACE_JUMBO((short)0xff26, "invoke-interface/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
|
|
||||||
|
|
||||||
INVOKE_OBJECT_INIT_JUMBO((short)0xfff2, "invoke-object-init/jumbo", ReferenceType.method, Format.Format5rc, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE | Opcode.CAN_INITIALIZE_REFERENCE),
|
|
||||||
IGET_VOLATILE_JUMBO((short)0xfff3, "iget-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_WIDE_VOLATILE_JUMBO((short)0xfff4, "iget-wide-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IGET_OBJECT_VOLATILE_JUMBO((short)0xfff5, "iget-object-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_VOLATILE_JUMBO((short)0xfff6, "iput-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_WIDE_VOLATILE_JUMBO((short)0xfff7, "iput-wide-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
IPUT_OBJECT_VOLATILE_JUMBO((short)0xfff8, "iput-object-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_VOLATILE_JUMBO((short)0xfff9, "sget-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_WIDE_VOLATILE_JUMBO((short)0xfffa, "sget-wide-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SGET_OBJECT_VOLATILE_JUMBO((short)0xfffb, "sget-object-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_VOLATILE_JUMBO((short)0xfffc, "sput-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_WIDE_VOLATILE_JUMBO((short)0xfffd, "sput-wide-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
|
|
||||||
SPUT_OBJECT_VOLATILE_JUMBO((short)0xfffe, "sput-object-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE);
|
|
||||||
|
|
||||||
private static Opcode[] opcodesByValue;
|
private static Opcode[] opcodesByValue;
|
||||||
private static Opcode[] expandedOpcodesByValue;
|
private static Opcode[] expandedOpcodesByValue;
|
||||||
@ -426,7 +372,7 @@ public enum Opcode
|
|||||||
* based on the idiosyncrasies of that api level
|
* based on the idiosyncrasies of that api level
|
||||||
* @param apiLevel
|
* @param apiLevel
|
||||||
*/
|
*/
|
||||||
public static void updateMapsForApiLevel(int apiLevel, boolean includeJumbo) {
|
public static void updateMapsForApiLevel(int apiLevel) {
|
||||||
if (apiLevel < 5) {
|
if (apiLevel < 5) {
|
||||||
removeOpcodes(THROW_VERIFICATION_ERROR);
|
removeOpcodes(THROW_VERIFICATION_ERROR);
|
||||||
}
|
}
|
||||||
@ -445,21 +391,6 @@ public enum Opcode
|
|||||||
removeOpcodes(INVOKE_OBJECT_INIT_RANGE);
|
removeOpcodes(INVOKE_OBJECT_INIT_RANGE);
|
||||||
addOpcodes(INVOKE_DIRECT_EMPTY);
|
addOpcodes(INVOKE_DIRECT_EMPTY);
|
||||||
}
|
}
|
||||||
if (apiLevel < 14 || !includeJumbo) {
|
|
||||||
removeOpcodes(CONST_CLASS_JUMBO, CHECK_CAST_JUMBO, INSTANCE_OF_JUMBO, NEW_INSTANCE_JUMBO,
|
|
||||||
NEW_ARRAY_JUMBO, FILLED_NEW_ARRAY_JUMBO, IGET_JUMBO, IGET_WIDE_JUMBO, IGET_OBJECT_JUMBO,
|
|
||||||
IGET_BOOLEAN_JUMBO, IGET_BYTE_JUMBO, IGET_CHAR_JUMBO, IGET_SHORT_JUMBO, IPUT_JUMBO, IPUT_WIDE_JUMBO,
|
|
||||||
IPUT_OBJECT_JUMBO, IPUT_BOOLEAN_JUMBO, IPUT_BYTE_JUMBO, IPUT_CHAR_JUMBO, IPUT_SHORT_JUMBO,
|
|
||||||
SGET_JUMBO, SGET_WIDE_JUMBO, SGET_OBJECT_JUMBO, SGET_BOOLEAN_JUMBO, SGET_BYTE_JUMBO,
|
|
||||||
SGET_CHAR_JUMBO, SGET_SHORT_JUMBO, SPUT_JUMBO, SPUT_WIDE_JUMBO, SPUT_OBJECT_JUMBO,
|
|
||||||
SPUT_BOOLEAN_JUMBO, SPUT_BYTE_JUMBO, SPUT_CHAR_JUMBO, SPUT_SHORT_JUMBO, INVOKE_VIRTUAL_JUMBO,
|
|
||||||
INVOKE_SUPER_JUMBO, INVOKE_DIRECT_JUMBO, INVOKE_STATIC_JUMBO, INVOKE_INTERFACE_JUMBO,
|
|
||||||
INVOKE_OBJECT_INIT_JUMBO, IGET_VOLATILE_JUMBO, IGET_WIDE_VOLATILE_JUMBO,
|
|
||||||
IGET_OBJECT_VOLATILE_JUMBO, IPUT_VOLATILE_JUMBO, IPUT_WIDE_VOLATILE_JUMBO,
|
|
||||||
IPUT_OBJECT_VOLATILE_JUMBO, SGET_VOLATILE_JUMBO, SGET_WIDE_VOLATILE_JUMBO,
|
|
||||||
SGET_OBJECT_VOLATILE_JUMBO, SPUT_VOLATILE_JUMBO, SPUT_WIDE_VOLATILE_JUMBO,
|
|
||||||
SPUT_OBJECT_VOLATILE_JUMBO);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final short value;
|
public final short value;
|
||||||
|
@ -33,6 +33,8 @@ import org.jf.dexlib.Code.*;
|
|||||||
import org.jf.dexlib.Debug.DebugInstructionIterator;
|
import org.jf.dexlib.Debug.DebugInstructionIterator;
|
||||||
import org.jf.dexlib.Debug.DebugOpcode;
|
import org.jf.dexlib.Debug.DebugOpcode;
|
||||||
import org.jf.dexlib.Util.*;
|
import org.jf.dexlib.Util.*;
|
||||||
|
import org.jf.util.AlignmentUtils;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -28,8 +28,10 @@
|
|||||||
|
|
||||||
package org.jf.dexlib;
|
package org.jf.dexlib;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
|
||||||
import org.jf.dexlib.Util.*;
|
import org.jf.dexlib.Util.*;
|
||||||
|
import org.jf.util.AlignmentUtils;
|
||||||
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
import org.jf.util.Hex;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.security.DigestException;
|
import java.security.DigestException;
|
||||||
@ -39,7 +41,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.zip.Adler32;
|
import java.util.zip.Adler32;
|
||||||
import brut.directory.ZipExtFile;
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <h3>Main use cases</h3>
|
* <h3>Main use cases</h3>
|
||||||
@ -287,13 +290,13 @@ public class DexFile
|
|||||||
|
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = null;
|
||||||
Input in = null;
|
Input in = null;
|
||||||
ZipExtFile zipFile = null;
|
ZipFile zipFile = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//do we have a zip file?
|
//do we have a zip file?
|
||||||
if (magic[0] == 0x50 && magic[1] == 0x4B) {
|
if (magic[0] == 0x50 && magic[1] == 0x4B) {
|
||||||
zipFile = new ZipExtFile(file);
|
zipFile = new ZipFile(file);
|
||||||
ZipArchiveEntry zipEntry = zipFile.getEntry("classes.dex");
|
ZipEntry zipEntry = zipFile.getEntry("classes.dex");
|
||||||
if (zipEntry == null) {
|
if (zipEntry == null) {
|
||||||
throw new NoClassesDexException("zip file " + file.getName() + " does not contain a classes.dex " +
|
throw new NoClassesDexException("zip file " + file.getName() + " does not contain a classes.dex " +
|
||||||
"file");
|
"file");
|
||||||
|
@ -33,7 +33,7 @@ import org.jf.dexlib.StringIdItem;
|
|||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||||
import org.jf.dexlib.Util.Input;
|
import org.jf.dexlib.Util.Input;
|
||||||
import org.jf.dexlib.Util.Utf8Utils;
|
import org.jf.util.StringUtils;
|
||||||
|
|
||||||
public class StringEncodedValue extends EncodedValue {
|
public class StringEncodedValue extends EncodedValue {
|
||||||
public final StringIdItem value;
|
public final StringIdItem value;
|
||||||
@ -65,7 +65,7 @@ public class StringEncodedValue extends EncodedValue {
|
|||||||
|
|
||||||
if (out.annotates()) {
|
if (out.annotates()) {
|
||||||
out.annotate(1, "value_type=" + ValueType.VALUE_STRING.name() + ",value_arg=" + (bytes.length - 1));
|
out.annotate(1, "value_type=" + ValueType.VALUE_STRING.name() + ",value_arg=" + (bytes.length - 1));
|
||||||
out.annotate(bytes.length, "value: \"" + Utf8Utils.escapeString(value.getStringValue()) + "\"");
|
out.annotate(bytes.length, "value: \"" + StringUtils.escapeString(value.getStringValue()) + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
out.writeByte(ValueType.VALUE_STRING.value | ((bytes.length - 1) << 5));
|
out.writeByte(ValueType.VALUE_STRING.value | ((bytes.length - 1) << 5));
|
||||||
|
@ -31,7 +31,7 @@ package org.jf.dexlib;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||||
import org.jf.dexlib.Util.Input;
|
import org.jf.dexlib.Util.Input;
|
||||||
import org.jf.dexlib.Util.Utf8Utils;
|
import org.jf.util.StringUtils;
|
||||||
|
|
||||||
public class HeaderItem extends Item<HeaderItem> {
|
public class HeaderItem extends Item<HeaderItem> {
|
||||||
/**
|
/**
|
||||||
@ -182,7 +182,7 @@ public class HeaderItem extends Item<HeaderItem> {
|
|||||||
magicBuilder.append((char)MAGIC_VALUES[magic_index][i]);
|
magicBuilder.append((char)MAGIC_VALUES[magic_index][i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
out.annotate("magic: " + Utf8Utils.escapeString(magicBuilder.toString()));
|
out.annotate("magic: " + StringUtils.escapeString(magicBuilder.toString()));
|
||||||
out.write(MAGIC_VALUES[magic_index]);
|
out.write(MAGIC_VALUES[magic_index]);
|
||||||
|
|
||||||
out.annotate("checksum");
|
out.annotate("checksum");
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
package org.jf.dexlib;
|
package org.jf.dexlib;
|
||||||
|
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.dexlib.Util.Input;
|
import org.jf.dexlib.Util.Input;
|
||||||
|
|
||||||
public class IndexedSection<T extends Item> extends Section<T> {
|
public class IndexedSection<T extends Item> extends Section<T> {
|
||||||
|
@ -29,9 +29,9 @@
|
|||||||
package org.jf.dexlib;
|
package org.jf.dexlib;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import org.jf.dexlib.Util.AlignmentUtils;
|
import org.jf.util.AlignmentUtils;
|
||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.dexlib.Util.Input;
|
import org.jf.dexlib.Util.Input;
|
||||||
|
|
||||||
public abstract class Item<T extends Item> implements Comparable<T> {
|
public abstract class Item<T extends Item> implements Comparable<T> {
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
package org.jf.dexlib;
|
package org.jf.dexlib;
|
||||||
|
|
||||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
import org.jf.dexlib.Util.SparseArray;
|
import org.jf.dexlib.Util.SparseArray;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
package org.jf.dexlib;
|
package org.jf.dexlib;
|
||||||
|
|
||||||
import org.jf.dexlib.Util.AlignmentUtils;
|
import org.jf.util.AlignmentUtils;
|
||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||||
import org.jf.dexlib.Util.Input;
|
import org.jf.dexlib.Util.Input;
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ package org.jf.dexlib;
|
|||||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||||
import org.jf.dexlib.Util.Input;
|
import org.jf.dexlib.Util.Input;
|
||||||
import org.jf.dexlib.Util.Leb128Utils;
|
import org.jf.dexlib.Util.Leb128Utils;
|
||||||
import org.jf.dexlib.Util.Utf8Utils;
|
import org.jf.util.StringUtils;
|
||||||
|
import org.jf.util.Utf8Utils;
|
||||||
|
|
||||||
public class StringDataItem extends Item<StringDataItem> {
|
public class StringDataItem extends Item<StringDataItem> {
|
||||||
private int hashCode = 0;
|
private int hashCode = 0;
|
||||||
@ -103,7 +104,7 @@ public class StringDataItem extends Item<StringDataItem> {
|
|||||||
")");
|
")");
|
||||||
out.writeUnsignedLeb128(stringValue.length());
|
out.writeUnsignedLeb128(stringValue.length());
|
||||||
|
|
||||||
out.annotate(encodedValue.length + 1, "string_data: \"" + Utf8Utils.escapeString(stringValue) + "\"");
|
out.annotate(encodedValue.length + 1, "string_data: \"" + StringUtils.escapeString(stringValue) + "\"");
|
||||||
} else {
|
} else {
|
||||||
out.writeUnsignedLeb128(stringValue.length());
|
out.writeUnsignedLeb128(stringValue.length());
|
||||||
}
|
}
|
||||||
@ -118,7 +119,7 @@ public class StringDataItem extends Item<StringDataItem> {
|
|||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public String getConciseIdentity() {
|
public String getConciseIdentity() {
|
||||||
return "string_data_item: \"" + Utf8Utils.escapeString(getStringValue()) + "\"";
|
return "string_data_item: \"" + StringUtils.escapeString(getStringValue()) + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user