Update to smali 2b5

This commit is contained in:
Connor Tumbleson 2013-06-20 08:03:20 -05:00
parent 115db91fab
commit 007a6d45a2
596 changed files with 54475 additions and 5112 deletions

View File

@ -1 +0,0 @@
/target

View File

@ -29,11 +29,19 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
configurations {
proguard
}
dependencies {
compile project(':brut.apktool.smali:util')
compile project(':brut.apktool.smali:dexlib')
compile 'commons-cli:commons-cli:1.2'
compile 'com.google.code.findbugs:jsr305:1.3.9'
compile project(':util')
compile project(':dexlib2')
compile depends.commons_cli
compile depends.guava
testCompile depends.junit
proguard depends.proguard
}
processResources.inputs.property('version', version)
@ -46,4 +54,28 @@ jar {
manifest {
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)

View File

@ -29,35 +29,36 @@
package org.jf.baksmali.Adaptors;
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.dexlib.AnnotationItem;
import org.jf.dexlib.AnnotationSetItem;
import java.io.IOException;
import java.util.Collection;
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;
for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
for (Annotation annotation: annotations) {
if (!first) {
writer.write('\n');
}
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(annotationItem.getVisibility().visibility);
writer.write(AnnotationVisibility.getVisibility(annotation.getVisibility()));
writer.write(' ');
ReferenceFormatter.writeTypeReference(writer, annotationItem.getEncodedAnnotation().annotationType);
writer.write(annotation.getType());
writer.write('\n');
AnnotationEncodedValueAdaptor.writeElementsTo(writer, annotationItem.getEncodedAnnotation());
AnnotationEncodedValueAdaptor.writeElementsTo(writer, annotation.getElements());
writer.write(".end annotation\n");
}

View File

@ -28,33 +28,36 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.baksmaliOptions;
import org.jf.util.IndentingWriter;
import org.jf.dexlib.TypeIdItem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
public class CatchMethodItem extends MethodItem {
private final TypeIdItem exceptionType;
private final String exceptionType;
private final LabelMethodItem tryStartLabel;
private final LabelMethodItem tryEndLabel;
private final LabelMethodItem handlerLabel;
public CatchMethodItem(MethodDefinition.LabelCache labelCache, int codeAddress, TypeIdItem exceptionType,
int startAddress, int endAddress, int handlerAddress) {
public CatchMethodItem(@Nonnull baksmaliOptions options, @Nonnull MethodDefinition.LabelCache labelCache,
int codeAddress, @Nullable String exceptionType, int startAddress, int endAddress,
int handlerAddress) {
super(codeAddress);
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
//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) {
handlerLabel = labelCache.internLabel(new LabelMethodItem(handlerAddress, "catchall_"));
handlerLabel = labelCache.internLabel(new LabelMethodItem(options, handlerAddress, "catchall_"));
} 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");
} else {
writer.write(".catch ");
ReferenceFormatter.writeTypeReference(writer, exceptionType);
writer.write(exceptionType);
}
writer.write(" {");
tryStartLabel.writeTo(writer);

View File

@ -28,81 +28,69 @@
package org.jf.baksmali.Adaptors;
import org.jf.dexlib.Util.Utf8Utils;
import org.jf.util.CommentingIndentingWriter;
import com.google.common.collect.Lists;
import org.jf.baksmali.baksmaliOptions;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
import org.jf.dexlib2.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.dexlib.*;
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 org.jf.util.StringUtils;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.List;
import java.util.*;
public class ClassDefinition {
private ClassDefItem classDefItem;
@Nullable
private ClassDataItem classDataItem;
private SparseArray<FieldIdItem> fieldsSetInStaticConstructor;
@Nonnull public final baksmaliOptions options;
@Nonnull public final ClassDef classDef;
@Nonnull private final HashSet<String> fieldsSetInStaticConstructor;
protected boolean validationErrors;
public ClassDefinition(ClassDefItem classDefItem) {
this.classDefItem = classDefItem;
this.classDataItem = classDefItem.getClassData();
findFieldsSetInStaticConstructor();
public ClassDefinition(@Nonnull baksmaliOptions options, @Nonnull ClassDef classDef) {
this.options = options;
this.classDef = classDef;
fieldsSetInStaticConstructor = findFieldsSetInStaticConstructor();
}
public boolean hadValidationErrors() {
return validationErrors;
}
private void findFieldsSetInStaticConstructor() {
fieldsSetInStaticConstructor = new SparseArray<FieldIdItem>();
@Nonnull
private HashSet<String> findFieldsSetInStaticConstructor() {
HashSet<String> fieldsSetInStaticConstructor = new HashSet<String>();
if (classDataItem == null) {
return;
}
for (ClassDataItem.EncodedMethod directMethod: classDataItem.getDirectMethods()) {
if (directMethod.method.getMethodName().getStringValue().equals("<clinit>") &&
directMethod.codeItem != null) {
for (Instruction instruction: directMethod.codeItem.getInstructions()) {
switch (instruction.opcode) {
case SPUT:
case SPUT_BOOLEAN:
case SPUT_BYTE:
case SPUT_CHAR:
case SPUT_OBJECT:
case SPUT_SHORT:
case SPUT_WIDE: {
Instruction21c ins = (Instruction21c)instruction;
FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem();
fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem);
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;
for (Method method: classDef.getDirectMethods()) {
if (method.getName().equals("<clinit>")) {
MethodImplementation impl = method.getImplementation();
if (impl != null) {
for (Instruction instruction: impl.getInstructions()) {
switch (instruction.getOpcode()) {
case SPUT:
case SPUT_BOOLEAN:
case SPUT_BYTE:
case SPUT_CHAR:
case SPUT_OBJECT:
case SPUT_SHORT:
case SPUT_WIDE: {
Instruction21c ins = (Instruction21c)instruction;
FieldReference fieldRef = (FieldReference)ins.getReference();
if (fieldRef.getDefiningClass().equals((classDef.getType()))) {
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
}
break;
}
}
}
}
}
}
return fieldsSetInStaticConstructor;
}
public void writeTo(IndentingWriter writer) throws IOException {
@ -111,238 +99,219 @@ public class ClassDefinition {
writeSourceFile(writer);
writeInterfaces(writer);
writeAnnotations(writer);
writeStaticFields(writer);
writeInstanceFields(writer);
writeDirectMethods(writer);
writeVirtualMethods(writer);
Set<String> staticFields = writeStaticFields(writer);
writeInstanceFields(writer, staticFields);
Set<String> directMethods = writeDirectMethods(writer);
writeVirtualMethods(writer, directMethods);
}
private void writeClass(IndentingWriter writer) throws IOException {
writer.write(".class ");
writeAccessFlags(writer);
writer.write(classDefItem.getClassType().getTypeDescriptor());
writer.write(classDef.getType());
writer.write('\n');
}
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(' ');
}
}
private void writeSuper(IndentingWriter writer) throws IOException {
TypeIdItem superClass = classDefItem.getSuperclass();
String superClass = classDef.getSuperclass();
if (superClass != null) {
writer.write(".super ");
writer.write(superClass.getTypeDescriptor());
writer.write(superClass);
writer.write('\n');
}
}
private void writeSourceFile(IndentingWriter writer) throws IOException {
StringIdItem sourceFile = classDefItem.getSourceFile();
String sourceFile = classDef.getSourceFile();
if (sourceFile != null) {
writer.write(".source \"");
Utf8Utils.writeEscapedString(writer, sourceFile.getStringValue());
StringUtils.writeEscapedString(writer, sourceFile);
writer.write("\"\n");
}
}
private void writeInterfaces(IndentingWriter writer) throws IOException {
TypeListItem interfaceList = classDefItem.getInterfaces();
if (interfaceList == null) {
return;
}
List<String> interfaces = Lists.newArrayList(classDef.getInterfaces());
Collections.sort(interfaces);
List<TypeIdItem> interfaces = interfaceList.getTypes();
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());
if (interfaces.size() != 0) {
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 {
AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations();
if (annotationDirectory == null) {
return;
Collection<? extends Annotation> classAnnotations = classDef.getAnnotations();
if (classAnnotations.size() != 0) {
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 {
if (classDataItem == null) {
return;
}
//if classDataItem is not null, then classDefItem won't be null either
assert(classDefItem != null);
private Set<String> writeStaticFields(IndentingWriter writer) throws IOException {
boolean wroteHeader = false;
Set<String> writtenFields = new HashSet<String>();
EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers();
EncodedValue[] staticInitializers;
if (encodedStaticInitializers != null) {
staticInitializers = encodedStaticInitializers.getEncodedArray().values;
Iterable<? extends Field> staticFields;
if (classDef instanceof DexBackedClassDef) {
staticFields = ((DexBackedClassDef)classDef).getStaticFields(false);
} else {
staticInitializers = new EncodedValue[0];
staticFields = classDef.getStaticFields();
}
List<ClassDataItem.EncodedField> encodedFields = classDataItem.getStaticFields();
if (encodedFields.size() == 0) {
return;
for (Field field: staticFields) {
if (!wroteHeader) {
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");
writer.write("# static fields\n");
for (int i=0; i<encodedFields.size(); i++) {
if (i > 0) {
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);
for (Field field: instanceFields) {
if (!wroteHeader) {
writer.write("\n\n");
writer.write("# instance fields");
wroteHeader = true;
}
writer.write('\n');
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 static field %s, Ignoring.",
classDefItem.getClassType().getTypeDescriptor(), field.field.getShortFieldString()));
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));
} 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");
}
boolean setInStaticConstructor =
fieldsSetInStaticConstructor.get(field.field.getIndex()) != null;
FieldDefinition.writeTo(fieldWriter, field, encodedValue, fieldAnnotations, setInStaticConstructor);
FieldDefinition.writeTo(fieldWriter, field, false);
}
}
private void writeInstanceFields(IndentingWriter writer) throws IOException {
if (classDataItem == null) {
return;
private Set<String> writeDirectMethods(IndentingWriter writer) throws IOException {
boolean wroteHeader = false;
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();
if (encodedFields.size() == 0) {
return;
}
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');
for (Method method: directMethods) {
if (!wroteHeader) {
writer.write("\n\n");
writer.write("# direct methods");
wroteHeader = true;
}
writer.write('\n');
AnnotationSetItem fieldAnnotations = null;
AnnotationDirectoryItem annotations = classDefItem.getAnnotations();
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);
}
// TODO: check for method validation errors
String methodString = ReferenceUtil.getShortMethodDescriptor(method);
IndentingWriter methodWriter = writer;
// the encoded methods are sorted, so we just have to compare with the previous one to detect duplicates
if (i > 0 && method.equals(methods.get(i-1))) {
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()));
if (!writtenMethods.add(methodString)) {
writer.write("# duplicate method ignored\n");
methodWriter = new CommentingIndentingWriter(writer);
}
MethodDefinition methodDefinition = new MethodDefinition(method);
methodDefinition.writeTo(methodWriter, methodAnnotations, parameterAnnotations);
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl == null) {
MethodDefinition.writeEmptyMethodTo(methodWriter, method);
} else {
MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl);
methodDefinition.writeTo(methodWriter);
}
}
return writtenMethods;
}
ValidationException validationException = methodDefinition.getValidationException();
if (validationException != null) {
System.err.println(String.format("Error while disassembling method %s. Continuing.",
method.method.getMethodString()));
validationException.printStackTrace(System.err);
this.validationErrors = true;
private void writeVirtualMethods(IndentingWriter writer, Set<String> directMethods) throws IOException {
boolean wroteHeader = false;
Set<String> writtenMethods = new HashSet<String>();
Iterable<? extends Method> virtualMethods;
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);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012, Google Inc.
* Copyright 2013, Google Inc.
* All rights reserved.
*
* 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.
*/
package org.jf.util;
package org.jf.baksmali.Adaptors;
import org.jf.util.IndentingWriter;
import java.io.IOException;
import java.io.Writer;
public class CommentingIndentingWriter extends IndentingWriter {
private final String commentStr;
public CommentingIndentingWriter(Writer writer, String commentStr) {
public CommentingIndentingWriter(Writer writer) {
super(writer);
this.commentStr = commentStr;
}
protected void writeLineStart() throws IOException {
writer.write(commentStr);
@Override protected void writeIndent() throws IOException {
writer.write("# ");
super.writeIndent();
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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('"');
}
}

View File

@ -28,32 +28,32 @@
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.dexlib.EncodedValue.AnnotationEncodedSubValue;
import java.io.IOException;
import java.util.Collection;
public abstract class AnnotationEncodedValueAdaptor {
public static void writeTo(IndentingWriter writer, AnnotationEncodedSubValue encodedAnnotation)
public static void writeTo(IndentingWriter writer, AnnotationEncodedValue annotationEncodedValue)
throws IOException {
writer.write(".subannotation ");
ReferenceFormatter.writeTypeReference(writer, encodedAnnotation.annotationType);
writer.write(annotationEncodedValue.getType());
writer.write('\n');
writeElementsTo(writer, encodedAnnotation);
writeElementsTo(writer, annotationEncodedValue.getElements());
writer.write(".end subannotation");
}
public static void writeElementsTo(IndentingWriter writer, AnnotationEncodedSubValue encodedAnnotation)
throws IOException {
public static void writeElementsTo(IndentingWriter writer,
Collection<? extends AnnotationElement> annotationElements) throws IOException {
writer.indent(4);
for (int i=0; i<encodedAnnotation.names.length; i++) {
writer.write(encodedAnnotation.names[i].getStringValue());
for (AnnotationElement annotationElement: annotationElements) {
writer.write(annotationElement.getName());
writer.write(" = ");
EncodedValueAdaptor.writeTo(writer, encodedAnnotation.values[i]);
EncodedValueAdaptor.writeTo(writer, annotationElement.getValue());
writer.write('\n');
}
writer.deindent(4);

View File

@ -29,16 +29,17 @@
package org.jf.baksmali.Adaptors.EncodedValue;
import org.jf.util.IndentingWriter;
import org.jf.dexlib.EncodedValue.ArrayEncodedValue;
import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.iface.value.EncodedValue;
import java.io.IOException;
import java.util.Collection;
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('{');
EncodedValue[] values = encodedArray.values;
if (values == null || values.length == 0) {
Collection<? extends EncodedValue> values = arrayEncodedValue.getValue();
if (values.size() == 0) {
writer.write('}');
return;
}
@ -46,7 +47,7 @@ public class ArrayEncodedValueAdaptor {
writer.write('\n');
writer.indent(4);
boolean first = true;
for (EncodedValue encodedValue: encodedArray.values) {
for (EncodedValue encodedValue: values) {
if (!first) {
writer.write(",\n");
}

View File

@ -29,62 +29,65 @@
package org.jf.baksmali.Adaptors.EncodedValue;
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.baksmali.Renderers.*;
import org.jf.dexlib.EncodedValue.*;
import java.io.IOException;
public abstract class EncodedValueAdaptor {
public static void writeTo(IndentingWriter writer, EncodedValue encodedValue) throws IOException {
switch (encodedValue.getValueType()) {
case VALUE_ANNOTATION:
case ValueType.ANNOTATION:
AnnotationEncodedValueAdaptor.writeTo(writer, (AnnotationEncodedValue)encodedValue);
return;
case VALUE_ARRAY:
case ValueType.ARRAY:
ArrayEncodedValueAdaptor.writeTo(writer, (ArrayEncodedValue)encodedValue);
return;
case VALUE_BOOLEAN:
BooleanRenderer.writeTo(writer, ((BooleanEncodedValue)encodedValue).value);
case ValueType.BOOLEAN:
BooleanRenderer.writeTo(writer, ((BooleanEncodedValue)encodedValue).getValue());
return;
case VALUE_BYTE:
ByteRenderer.writeTo(writer, ((ByteEncodedValue)encodedValue).value);
case ValueType.BYTE:
ByteRenderer.writeTo(writer, ((ByteEncodedValue)encodedValue).getValue());
return;
case VALUE_CHAR:
CharRenderer.writeTo(writer, ((CharEncodedValue)encodedValue).value);
case ValueType.CHAR:
CharRenderer.writeTo(writer, ((CharEncodedValue)encodedValue).getValue());
return;
case VALUE_DOUBLE:
DoubleRenderer.writeTo(writer, ((DoubleEncodedValue)encodedValue).value);
case ValueType.DOUBLE:
DoubleRenderer.writeTo(writer, ((DoubleEncodedValue)encodedValue).getValue());
return;
case VALUE_ENUM:
EnumEncodedValueAdaptor.writeTo(writer, ((EnumEncodedValue)encodedValue).value);
case ValueType.ENUM:
writer.write(".enum ");
ReferenceUtil.writeFieldDescriptor(writer, ((EnumEncodedValue)encodedValue).getValue());
return;
case VALUE_FIELD:
ReferenceFormatter.writeFieldReference(writer, ((FieldEncodedValue)encodedValue).value);
case ValueType.FIELD:
ReferenceUtil.writeFieldDescriptor(writer, ((FieldEncodedValue)encodedValue).getValue());
return;
case VALUE_FLOAT:
FloatRenderer.writeTo(writer, ((FloatEncodedValue)encodedValue).value);
case ValueType.FLOAT:
FloatRenderer.writeTo(writer, ((FloatEncodedValue)encodedValue).getValue());
return;
case VALUE_INT:
IntegerRenderer.writeTo(writer, ((IntEncodedValue)encodedValue).value);
case ValueType.INT:
IntegerRenderer.writeTo(writer, ((IntEncodedValue)encodedValue).getValue());
return;
case VALUE_LONG:
LongRenderer.writeTo(writer, ((LongEncodedValue)encodedValue).value);
case ValueType.LONG:
LongRenderer.writeTo(writer, ((LongEncodedValue)encodedValue).getValue());
return;
case VALUE_METHOD:
ReferenceFormatter.writeMethodReference(writer, ((MethodEncodedValue)encodedValue).value);
case ValueType.METHOD:
ReferenceUtil.writeMethodDescriptor(writer, ((MethodEncodedValue)encodedValue).getValue());
return;
case VALUE_NULL:
case ValueType.NULL:
writer.write("null");
return;
case VALUE_SHORT:
ShortRenderer.writeTo(writer, ((ShortEncodedValue)encodedValue).value);
case ValueType.SHORT:
ShortRenderer.writeTo(writer, ((ShortEncodedValue)encodedValue).getValue());
return;
case VALUE_STRING:
ReferenceFormatter.writeStringReference(writer, ((StringEncodedValue)encodedValue).value);
case ValueType.STRING:
ReferenceFormatter.writeStringReference(writer, ((StringEncodedValue)encodedValue).getValue());
return;
case VALUE_TYPE:
ReferenceFormatter.writeTypeReference(writer, ((TypeEncodedValue)encodedValue).value);
case ValueType.TYPE:
writer.write(((TypeEncodedValue)encodedValue).getValue());
}
}
}

View File

@ -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);
}
}

View File

@ -28,11 +28,15 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.baksmaliOptions;
import javax.annotation.Nonnull;
public class EndTryLabelMethodItem extends LabelMethodItem {
private int endTryAddress;
public EndTryLabelMethodItem(int codeAddress, int endTryAddress) {
super(codeAddress, "try_end_");
public EndTryLabelMethodItem(@Nonnull baksmaliOptions options, int codeAddress, int endTryAddress) {
super(options, codeAddress, "try_end_");
this.endTryAddress = endTryAddress;
}

View File

@ -29,40 +29,39 @@
package org.jf.baksmali.Adaptors;
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.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.util.Collection;
public class FieldDefinition {
public static void writeTo(IndentingWriter writer, ClassDataItem.EncodedField encodedField,
EncodedValue initialValue, AnnotationSetItem annotationSet,
boolean setInStaticConstructor) throws IOException {
String fieldTypeDescriptor = encodedField.field.getFieldType().getTypeDescriptor();
public static void writeTo(IndentingWriter writer, Field field, boolean setInStaticConstructor) throws IOException {
EncodedValue initialValue = field.getInitialValue();
int accessFlags = field.getAccessFlags();
if (setInStaticConstructor &&
encodedField.isStatic() &&
(encodedField.accessFlags & AccessFlags.FINAL.getValue()) != 0 &&
initialValue != null &&
(
//it's a primitive type, or it's an array/reference type and the initial value isn't null
fieldTypeDescriptor.length() == 1 ||
initialValue != NullEncodedValue.NullValue
)) {
writer.write("#the value of this static final field might be set in the static constructor\n");
AccessFlags.STATIC.isSet(accessFlags) &&
AccessFlags.FINAL.isSet(accessFlags) &&
initialValue != null) {
if (!EncodedValueUtils.isDefaultValue(initialValue)) {
writer.write("# The value of this static final field might be set in the static constructor\n");
} else {
// don't write out the default initial value for static final fields that get set in the static
// constructor
initialValue = null;
}
}
writer.write(".field ");
writeAccessFlags(writer, encodedField);
writer.write(encodedField.field.getFieldName().getStringValue());
writeAccessFlags(writer, field.getAccessFlags());
writer.write(field.getName());
writer.write(':');
writer.write(encodedField.field.getFieldType().getTypeDescriptor());
writer.write(field.getType());
if (initialValue != null) {
writer.write(" = ");
EncodedValueAdaptor.writeTo(writer, initialValue);
@ -70,17 +69,17 @@ public class FieldDefinition {
writer.write('\n');
if (annotationSet != null) {
Collection<? extends Annotation> annotations = field.getAnnotations();
if (annotations.size() > 0) {
writer.indent(4);
AnnotationFormatter.writeTo(writer, annotationSet);
AnnotationFormatter.writeTo(writer, annotations);
writer.deindent(4);
writer.write(".end field\n");
}
}
private static void writeAccessFlags(IndentingWriter writer, ClassDataItem.EncodedField encodedField)
throws IOException {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForField(encodedField.accessFlags)) {
private static void writeAccessFlags(IndentingWriter writer, int accessFlags) throws IOException {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForField(accessFlags)) {
writer.write(accessFlag.toString());
writer.write(' ');
}

View File

@ -28,36 +28,44 @@
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.baksmali.Renderers.ByteRenderer;
import org.jf.dexlib.Code.Format.ArrayDataPseudoInstruction;
import org.jf.dexlib.CodeItem;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayDataPseudoInstruction> {
public ArrayDataMethodItem(CodeItem codeItem, int codeAddress, ArrayDataPseudoInstruction instruction) {
super(codeItem, codeAddress, instruction);
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayPayload> {
public ArrayDataMethodItem(MethodDefinition methodDef, int codeAddress, ArrayPayload instruction) {
super(methodDef, codeAddress, instruction);
}
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".array-data 0x");
writer.printUnsignedLongAsHex(instruction.getElementWidth());
int elementWidth = instruction.getElementWidth();
writer.write(".array-data ");
writer.printSignedIntAsDec(instruction.getElementWidth());
writer.write('\n');
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++) {
if (i!=0) {
writer.write(' ');
}
ByteRenderer.writeUnsignedTo(writer, element.buffer[element.bufferIndex+i]);
}
writer.write('\n');
List<Number> elements = instruction.getArrayElements();
String suffix = "";
switch (elementWidth) {
case 1:
suffix = "t";
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.write(".end array-data");

View File

@ -28,26 +28,26 @@
package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.baksmali.Adaptors.MethodItem;
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.dexlib.Code.*;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib.Item;
import org.jf.dexlib2.VerificationError;
import org.jf.dexlib2.iface.instruction.*;
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;
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
protected final CodeItem codeItem;
protected final T instruction;
@Nonnull protected final MethodDefinition methodDef;
@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);
this.codeItem = codeItem;
this.methodDef = methodDef;
this.instruction = instruction;
}
@ -58,7 +58,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
switch (instruction.getFormat()) {
switch (instruction.getOpcode().format) {
case Format10t:
writeOpcode(writer);
writer.write(' ');
@ -67,7 +67,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
case Format10x:
if (instruction instanceof UnknownInstruction) {
writer.write("#unknown opcode: 0x");
writer.printUnsignedLongAsHex(((UnknownInstruction) instruction).getOriginalOpcode() & 0xFFFF);
writer.printUnsignedLongAsHex(((UnknownInstruction)instruction).getOriginalOpcode());
writer.write('\n');
}
writeOpcode(writer);
@ -106,14 +106,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
return true;
case Format21c:
case Format31c:
case Format41c:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeReference(writer);
return true;
case Format21h:
case Format21ih:
case Format21lh:
case Format21s:
case Format31i:
case Format51l:
@ -142,7 +142,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeLiteral(writer);
return true;
case Format22c:
case Format52c:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
@ -208,7 +207,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeVtableIndex(writer);
return true;
case Format3rc:
case Format5rc:
writeOpcode(writer);
writer.write(' ');
writeInvokeRangeRegisters(writer);
@ -235,21 +233,21 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
}
protected void writeOpcode(IndentingWriter writer) throws IOException {
writer.write(instruction.opcode.name);
writer.write(instruction.getOpcode().name);
}
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
throw new RuntimeException();
}
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 {
writeRegister(writer, ((SingleRegisterInstruction)instruction).getRegisterA());
writeRegister(writer, ((OneRegisterInstruction)instruction).getRegisterA());
}
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 {
writeRegister(writer, ((ThreeRegisterInstruction)instruction).getRegisterC());
writeRegister(writer, ((ThreeRegisterInstruction) instruction).getRegisterC());
}
protected void writeInvokeRegisters(IndentingWriter writer) throws IOException {
FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction;
final int regCount = instruction.getRegCount();
final int regCount = instruction.getRegisterCount();
writer.write('{');
switch (regCount) {
case 1:
writeRegister(writer, instruction.getRegisterD());
writeRegister(writer, instruction.getRegisterC());
break;
case 2:
writeRegister(writer, instruction.getRegisterD());
writeRegister(writer, instruction.getRegisterC());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
writeRegister(writer, instruction.getRegisterD());
break;
case 3:
writeRegister(writer, instruction.getRegisterC());
writer.write(", ");
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
writer.write(", ");
writeRegister(writer, instruction.getRegisterF());
break;
case 4:
writeRegister(writer, instruction.getRegisterC());
writer.write(", ");
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
writer.write(", ");
writeRegister(writer, instruction.getRegisterF());
writer.write(", ");
writeRegister(writer, instruction.getRegisterG());
break;
case 5:
writeRegister(writer, instruction.getRegisterC());
writer.write(", ");
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
@ -298,8 +298,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeRegister(writer, instruction.getRegisterF());
writer.write(", ");
writeRegister(writer, instruction.getRegisterG());
writer.write(", ");
writeRegister(writer, instruction.getRegisterA());
break;
}
writer.write('}');
@ -308,41 +306,42 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException {
RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction;
int regCount = instruction.getRegCount();
int regCount = instruction.getRegisterCount();
if (regCount == 0) {
writer.write("{}");
} else {
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 {
LongRenderer.writeSignedIntOrLongTo(writer, ((LiteralInstruction)instruction).getLiteral());
LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral());
}
protected void writeFieldOffset(IndentingWriter writer) throws IOException {
writer.write("field@0x");
writer.printUnsignedLongAsHex(((OdexedFieldAccess) instruction).getFieldOffset());
writer.printUnsignedLongAsHex(((FieldOffsetInstruction)instruction).getFieldOffset());
}
protected void writeInlineIndex(IndentingWriter writer) throws IOException {
writer.write("inline@0x");
writer.printUnsignedLongAsHex(((OdexedInvokeInline) instruction).getInlineIndex());
writer.write("inline@");
writer.printSignedIntAsDec(((InlineIndexInstruction)instruction).getInlineIndex());
}
protected void writeVtableIndex(IndentingWriter writer) throws IOException {
writer.write("vtable@0x");
writer.printUnsignedLongAsHex(((OdexedInvokeVirtual) instruction).getVtableIndex());
writer.write("vtable@");
writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex());
}
protected void writeReference(IndentingWriter writer) throws IOException {
Item item = ((InstructionWithReference)instruction).getReferencedItem();
ReferenceFormatter.writeReference(writer, item);
ReferenceFormatter.writeReference(writer, instruction.getOpcode().referenceType,
((ReferenceInstruction)instruction).getReference());
}
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
VerificationErrorType validationErrorType = ((Instruction20bc)instruction).getValidationErrorType();
writer.write(validationErrorType.getName());
int verificationError = ((Instruction20bc)instruction).getVerificationError();
writer.write(VerificationError.getVerificationErrorName(verificationError));
}
}

View File

@ -29,37 +29,39 @@
package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.dexlib.Code.Format.*;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.OffsetInstruction;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib2.analysis.UnresolvedOdexInstruction;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
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 {
private InstructionMethodItemFactory() {
}
public static InstructionMethodItem makeInstructionFormatMethodItem(
MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, Instruction instruction) {
MethodDefinition methodDef, int codeAddress, Instruction instruction) {
if (instruction instanceof OffsetInstruction) {
return new OffsetInstructionFormatMethodItem(methodDefinition.getLabelCache(), codeItem,
codeAddress, (OffsetInstruction)instruction);
return new OffsetInstructionFormatMethodItem(methodDef.classDef.options, methodDef, codeAddress,
(OffsetInstruction)instruction);
}
switch (instruction.getFormat()) {
case ArrayData:
return new ArrayDataMethodItem(codeItem, codeAddress,
(ArrayDataPseudoInstruction)instruction);
case PackedSwitchData:
return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress,
(PackedSwitchDataPseudoInstruction)instruction);
case SparseSwitchData:
return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress,
(SparseSwitchDataPseudoInstruction)instruction);
case UnresolvedOdexInstruction:
return new UnresolvedOdexInstructionMethodItem(codeItem, codeAddress,
(UnresolvedOdexInstruction)instruction);
if (instruction instanceof UnresolvedOdexInstruction) {
return new UnresolvedOdexInstructionMethodItem(methodDef, codeAddress,
(UnresolvedOdexInstruction)instruction);
}
switch (instruction.getOpcode().format) {
case ArrayPayload:
return new ArrayDataMethodItem(methodDef, codeAddress, (ArrayPayload)instruction);
case PackedSwitchPayload:
return new PackedSwitchMethodItem(methodDef, codeAddress, (PackedSwitchPayload)instruction);
case SparseSwitchPayload:
return new SparseSwitchMethodItem(methodDef, codeAddress, (SparseSwitchPayload)instruction);
default:
return new InstructionMethodItem<Instruction>(codeItem, codeAddress, instruction);
return new InstructionMethodItem<Instruction>(methodDef, codeAddress, instruction);
}
}
}

View File

@ -30,22 +30,23 @@ package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.LabelMethodItem;
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.dexlib.Code.OffsetInstruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.CodeItem;
import javax.annotation.Nonnull;
import java.io.IOException;
public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<OffsetInstruction> {
protected LabelMethodItem label;
public OffsetInstructionFormatMethodItem(MethodDefinition.LabelCache labelCache, CodeItem codeItem, int codeAddress,
OffsetInstruction instruction) {
super(codeItem, codeAddress, instruction);
public OffsetInstructionFormatMethodItem(@Nonnull baksmaliOptions options, @Nonnull MethodDefinition methodDef,
int codeAddress, OffsetInstruction instruction) {
super(methodDef, codeAddress, instruction);
label = new LabelMethodItem(codeAddress + instruction.getTargetAddressOffset(), getLabelPrefix());
label = labelCache.internLabel(label);
label = new LabelMethodItem(options, codeAddress + instruction.getCodeOffset(), getLabelPrefix());
label = methodDef.getLabelCache().internLabel(label);
}
@Override
@ -58,7 +59,8 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<Off
}
private String getLabelPrefix() {
switch (instruction.getFormat()) {
Opcode opcode = instruction.getOpcode();
switch (opcode.format) {
case Format10t:
case Format20t:
case Format30t:
@ -67,13 +69,13 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<Off
case Format22t:
return "cond_";
case Format31t:
if (instruction.opcode == Opcode.FILL_ARRAY_DATA) {
if (opcode == Opcode.FILL_ARRAY_DATA) {
return "array_";
}
if (instruction.opcode == Opcode.PACKED_SWITCH) {
if (opcode == Opcode.PACKED_SWITCH) {
return "pswitch_data_";
}
assert instruction.opcode == Opcode.SPARSE_SWITCH;
// Opcode.SPARSE_SWITCH;
return "sswitch_data_";
}

View File

@ -30,55 +30,56 @@ package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.LabelMethodItem;
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.baksmali.Renderers.IntegerRenderer;
import org.jf.dexlib.Code.Format.PackedSwitchDataPseudoInstruction;
import org.jf.dexlib.CodeItem;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDataPseudoInstruction> {
public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchPayload> {
private final List<PackedSwitchTarget> targets;
private final int firstKey;
public PackedSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress,
PackedSwitchDataPseudoInstruction instruction) {
super(codeItem, codeAddress, instruction);
public PackedSwitchMethodItem(MethodDefinition methodDef, int codeAddress, PackedSwitchPayload instruction) {
super(methodDef, codeAddress, instruction);
int baseCodeAddress = methodDefinition.getPackedSwitchBaseAddress(codeAddress);
int baseCodeAddress = methodDef.getPackedSwitchBaseAddress(codeAddress);
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) {
while (iterator.hasNext()) {
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
PackedSwitchLabelTarget packedSwitchLabelTarget = new PackedSwitchLabelTarget();
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "pswitch_");
label = methodDefinition.getLabelCache().internLabel(label);
packedSwitchLabelTarget.Target = label;
targets.add(packedSwitchLabelTarget);
for (SwitchElement switchElement: instruction.getSwitchElements()) {
if (first) {
firstKey = switchElement.getKey();
first = false;
}
LabelMethodItem label = methodDef.getLabelCache().internLabel(
new LabelMethodItem(methodDef.classDef.options, baseCodeAddress + switchElement.getOffset(),
"pswitch_"));
targets.add(new PackedSwitchLabelTarget(label));
}
} else {
while (iterator.hasNext()) {
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
PackedSwitchOffsetTarget packedSwitchOffsetTarget = new PackedSwitchOffsetTarget();
packedSwitchOffsetTarget.Target = target.targetAddressOffset;
targets.add(packedSwitchOffsetTarget);
for (SwitchElement switchElement: instruction.getSwitchElements()) {
if (first) {
firstKey = switchElement.getKey();
first = false;
}
targets.add(new PackedSwitchOffsetTarget(switchElement.getOffset()));
}
}
this.firstKey = firstKey;
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".packed-switch ");
IntegerRenderer.writeTo(writer, instruction.getFirstKey());
IntegerRenderer.writeTo(writer, firstKey);
writer.indent(4);
writer.write('\n');
for (PackedSwitchTarget target: targets) {
@ -95,19 +96,25 @@ public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDa
}
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 {
Target.writeTo(writer);
target.writeTo(writer);
}
}
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 {
if (Target >= 0) {
if (target >= 0) {
writer.write('+');
}
writer.printSignedIntAsDec(Target);
writer.printSignedIntAsDec(target);
}
}
}

View File

@ -30,48 +30,35 @@ package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.LabelMethodItem;
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.baksmali.Renderers.IntegerRenderer;
import org.jf.dexlib.Code.Format.SparseSwitchDataPseudoInstruction;
import org.jf.dexlib.CodeItem;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDataPseudoInstruction> {
public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchPayload> {
private final List<SparseSwitchTarget> targets;
public SparseSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress,
SparseSwitchDataPseudoInstruction instruction) {
super(codeItem, codeAddress, instruction);
public SparseSwitchMethodItem(MethodDefinition methodDef, int codeAddress, SparseSwitchPayload instruction) {
super(methodDef, codeAddress, instruction);
int baseCodeAddress = methodDefinition.getSparseSwitchBaseAddress(codeAddress);
int baseCodeAddress = methodDef.getSparseSwitchBaseAddress(codeAddress);
targets = new ArrayList<SparseSwitchTarget>();
Iterator<SparseSwitchDataPseudoInstruction.SparseSwitchTarget> iterator = instruction.iterateKeysAndTargets();
if (baseCodeAddress >= 0) {
while (iterator.hasNext()) {
SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next();
SparseSwitchLabelTarget sparseSwitchLabelTarget = new SparseSwitchLabelTarget();
sparseSwitchLabelTarget.Key = target.key;
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "sswitch_");
label = methodDefinition.getLabelCache().internLabel(label);
sparseSwitchLabelTarget.Target = label;
targets.add(sparseSwitchLabelTarget);
for (SwitchElement switchElement: instruction.getSwitchElements()) {
LabelMethodItem label = methodDef.getLabelCache().internLabel(
new LabelMethodItem( methodDef.classDef.options, baseCodeAddress + switchElement.getOffset(),
"sswitch_"));
targets.add(new SparseSwitchLabelTarget(switchElement.getKey(), label));
}
} else {
//if we couldn't determine a base address, just use relative offsets rather than labels
while (iterator.hasNext()) {
SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next();
SparseSwitchOffsetTarget sparseSwitchOffsetTarget = new SparseSwitchOffsetTarget();
sparseSwitchOffsetTarget.Key = target.key;
sparseSwitchOffsetTarget.Target = target.targetAddressOffset;
targets.add(sparseSwitchOffsetTarget);
for (SwitchElement switchElement: instruction.getSwitchElements()) {
targets.add(new SparseSwitchOffsetTarget(switchElement.getKey(), switchElement.getOffset()));
}
}
}
@ -81,7 +68,7 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
writer.write(".sparse-switch\n");
writer.indent(4);
for (SparseSwitchTarget target: targets) {
IntegerRenderer.writeTo(writer, target.Key);
IntegerRenderer.writeTo(writer, target.getKey());
writer.write(" -> ");
target.writeTargetTo(writer);
writer.write('\n');
@ -92,24 +79,38 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
}
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;
}
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 {
Target.writeTo(writer);
target.writeTo(writer);
}
}
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 {
if (Target >= 0) {
if (target >= 0) {
writer.write('+');
}
writer.printSignedIntAsDec(Target);
writer.printSignedIntAsDec(target);
}
}
}

View File

@ -28,15 +28,17 @@
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.dexlib.Code.Format.UnresolvedOdexInstruction;
import org.jf.dexlib.CodeItem;
import javax.annotation.Nonnull;
import java.io.IOException;
public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<UnresolvedOdexInstruction> {
public UnresolvedOdexInstructionMethodItem(CodeItem codeItem, int codeAddress, UnresolvedOdexInstruction instruction) {
super(codeItem, codeAddress, instruction);
public UnresolvedOdexInstructionMethodItem(@Nonnull MethodDefinition methodDef, int codeAddress,
@Nonnull UnresolvedOdexInstruction instruction) {
super(methodDef, codeAddress, instruction);
}
public boolean writeTo(IndentingWriter writer) throws IOException {
@ -47,6 +49,6 @@ public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<U
private void writeThrowTo(IndentingWriter writer) throws IOException {
writer.write("#Replaced unresolvable odex instruction with a throw\n");
writer.write("throw ");
writeRegister(writer, instruction.ObjectRegisterNum);
writeRegister(writer, instruction.objectRegisterNum);
}
}

View File

@ -28,17 +28,20 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.baksmaliOptions;
import org.jf.util.IndentingWriter;
import org.jf.baksmali.baksmali;
import javax.annotation.Nonnull;
import java.io.IOException;
public class LabelMethodItem extends MethodItem {
private final baksmaliOptions options;
private final String labelPrefix;
private int labelSequence;
public LabelMethodItem(int codeAddress, String labelPrefix) {
public LabelMethodItem(@Nonnull baksmaliOptions options, int codeAddress, @Nonnull String labelPrefix) {
super(codeAddress);
this.options = options;
this.labelPrefix = labelPrefix;
}
@ -73,7 +76,7 @@ public class LabelMethodItem extends MethodItem {
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(':');
writer.write(labelPrefix);
if (baksmali.useSequentialLabels) {
if (options.useSequentialLabels) {
writer.printUnsignedLongAsHex(labelSequence);
} else {
writer.printUnsignedLongAsHex(this.getLabelAddress());

View File

@ -28,297 +28,256 @@
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.dexlib.Code.Analysis.SyntheticAccessorResolver;
import org.jf.dexlib.Code.InstructionWithReference;
import org.jf.dexlib2.AccessFlags;
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.baksmali.baksmali;
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 org.jf.util.SparseIntArray;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
public class MethodDefinition {
private final ClassDataItem.EncodedMethod encodedMethod;
private MethodAnalyzer methodAnalyzer;
@Nonnull public final ClassDefinition classDef;
@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;
private final SparseIntArray sparseSwitchMap;
private final SparseIntArray instructionMap;
public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) {
@Nonnull private final SparseIntArray packedSwitchMap;
@Nonnull private final SparseIntArray sparseSwitchMap;
@Nonnull private final InstructionOffsetMap instructionOffsetMap;
public MethodDefinition(@Nonnull ClassDefinition classDef, @Nonnull Method method,
@Nonnull MethodImplementation methodImpl) {
this.classDef = classDef;
this.method = method;
this.methodImpl = methodImpl;
try {
this.encodedMethod = encodedMethod;
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
if (encodedMethod.codeItem != null) {
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
instructions = ImmutableList.copyOf(methodImpl.getInstructions());
methodParameters = ImmutableList.copyOf(method.getParameters());
packedSwitchMap = new SparseIntArray(1);
sparseSwitchMap = new SparseIntArray(1);
instructionMap = new SparseIntArray(instructions.length);
packedSwitchMap = new SparseIntArray(0);
sparseSwitchMap = new SparseIntArray(0);
instructionOffsetMap = new InstructionOffsetMap(instructions);
int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
if (instruction.opcode == Opcode.PACKED_SWITCH) {
packedSwitchMap.append(
currentCodeAddress +
((OffsetInstruction)instruction).getTargetAddressOffset(),
currentCodeAddress);
} else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
sparseSwitchMap.append(
currentCodeAddress +
((OffsetInstruction)instruction).getTargetAddressOffset(),
currentCodeAddress);
}
instructionMap.append(currentCodeAddress, i);
currentCodeAddress += instruction.getSize(currentCodeAddress);
for (int i=0; i<instructions.size(); i++) {
Instruction instruction = instructions.get(i);
Opcode opcode = instruction.getOpcode();
if (opcode == Opcode.PACKED_SWITCH) {
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
packedSwitchMap.append(targetOffset, codeOffset);
} else if (opcode == Opcode.SPARSE_SWITCH) {
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
sparseSwitchMap.append(targetOffset, codeOffset);
}
} else {
packedSwitchMap = null;
sparseSwitchMap = null;
instructionMap = null;
methodAnalyzer = null;
}
}catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, String.format("Error while processing method %s",
encodedMethod.method.getMethodString()));
String methodString;
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,
AnnotationSetRefList parameterAnnotations) throws IOException {
final CodeItem codeItem = encodedMethod.codeItem;
public static void writeEmptyMethodTo(IndentingWriter writer, Method method) throws IOException {
writer.write(".method ");
writeAccessFlags(writer, encodedMethod);
writer.write(encodedMethod.method.getMethodName().getStringValue());
writer.write(encodedMethod.method.getPrototype().getPrototypeString());
writeAccessFlags(writer, method.getAccessFlags());
writer.write(method.getName());
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.indent(4);
if (codeItem != null) {
if (baksmali.useLocalsDirective) {
writer.write(".locals ");
} else {
writer.write(".registers ");
}
writer.printSignedIntAsDec(getRegisterCount(encodedMethod));
writer.write('\n');
writeParameters(writer, codeItem, parameterAnnotations);
if (annotationSet != null) {
AnnotationFormatter.writeTo(writer, annotationSet);
}
writeParameters(writer, method, methodParameters);
AnnotationFormatter.writeTo(writer, method.getAnnotations());
writer.deindent(4);
writer.write(".end method\n");
}
writer.write('\n');
public void writeTo(IndentingWriter writer) throws IOException {
int parameterRegisterCount = 0;
if (!AccessFlags.STATIC.isSet(method.getAccessFlags())) {
parameterRegisterCount++;
}
for (MethodItem methodItem: getMethodItems()) {
if (methodItem.writeTo(writer)) {
writer.write('\n');
}
writer.write(".method ");
writeAccessFlags(writer, method.getAccessFlags());
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 {
writeParameters(writer, codeItem, parameterAnnotations);
if (annotationSet != null) {
AnnotationFormatter.writeTo(writer, annotationSet);
writer.write(".registers ");
writer.printSignedIntAsDec(methodImpl.getRegisterCount());
}
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.write(".end method\n");
}
private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod)
{
int totalRegisters = encodedMethod.codeItem.getRegisterCount();
if (baksmali.useLocalsDirective) {
int parameterRegisters = encodedMethod.method.getPrototype().getParameterRegisterCount();
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
parameterRegisters++;
private int findSwitchPayload(int targetOffset, Opcode type) {
int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
//TODO: does dalvik let you pad with multiple nops?
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
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)
throws IOException {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) {
private static void writeAccessFlags(IndentingWriter writer, int accessFlags)
throws IOException {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(accessFlags)) {
writer.write(accessFlag.toString());
writer.write(' ');
}
}
private static void writeParameters(IndentingWriter writer, CodeItem codeItem,
AnnotationSetRefList parameterAnnotations) throws IOException {
DebugInfoItem debugInfoItem = null;
if (baksmali.outputDebugInfo && codeItem != null) {
debugInfoItem = codeItem.getDebugInfo();
}
private static void writeParameters(IndentingWriter writer, Method method,
List<? extends MethodParameter> parameters) throws IOException {
boolean isStatic = AccessFlags.STATIC.isSet(method.getAccessFlags());
int registerNumber = isStatic?0:1;
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;
AnnotationSetItem[] annotations;
StringIdItem[] parameterNames = null;
if (parameterAnnotations != null) {
annotations = parameterAnnotations.getAnnotationSets();
parameterCount = annotations.length;
} else {
annotations = new AnnotationSetItem[0];
}
if (debugInfoItem != null) {
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];
if (parameterName != null) {
writer.write(", ");
ReferenceFormatter.writeStringReference(writer, parameterName);
}
writer.write(" # ");
writer.write(parameterType);
writer.write("\n");
if (annotations.size() > 0) {
writer.indent(4);
AnnotationFormatter.writeTo(writer, annotations);
writer.deindent(4);
writer.write(".end param\n");
}
}
StringIdItem parameterName = null;
if (i < parameterNames.length) {
parameterName = parameterNames[i];
}
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");
registerNumber++;
if (TypeUtils.isWideType(parameterType)) {
registerNumber++;
}
}
}
public LabelCache getLabelCache() {
@Nonnull public LabelCache getLabelCache() {
return labelCache;
}
public ValidationException getValidationException() {
if (methodAnalyzer == null) {
return null;
}
return methodAnalyzer.getValidationException();
public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) {
return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1);
}
public int getPackedSwitchBaseAddress(int packedSwitchDataAddress) {
int packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress, -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;
public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) {
return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1);
}
private List<MethodItem> getMethodItems() {
ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
if (encodedMethod.codeItem == null) {
return methodItems;
}
if ((baksmali.registerInfo != 0) || baksmali.verify ||
(baksmali.deodex && needsAnalyzed())) {
if ((classDef.options.registerInfo != 0) || (classDef.options.deodex && needsAnalyzed())) {
addAnalyzedInstructionMethodItems(methodItems);
} else {
addInstructionMethodItems(methodItems);
}
addTries(methodItems);
if (baksmali.outputDebugInfo) {
if (classDef.options.outputDebugInfo) {
addDebugInfo(methodItems);
}
if (baksmali.useSequentialLabels) {
if (classDef.options.useSequentialLabels) {
setLabelSequentialNumbers();
}
@ -331,23 +290,30 @@ public class MethodDefinition {
return methodItems;
}
private void addInstructionMethodItems(List<MethodItem> methodItems) {
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
private boolean needsAnalyzed() {
for (Instruction instruction: methodImpl.getInstructions()) {
if (instruction.getOpcode().odexOnly()) {
return true;
}
}
return false;
}
private void addInstructionMethodItems(List<MethodItem> methodItems) {
int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
for (int i=0; i<instructions.size(); i++) {
Instruction instruction = instructions.get(i);
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction);
currentCodeAddress, instruction);
methodItems.add(methodItem);
if (i != instructions.length - 1) {
if (i != instructions.size() - 1) {
methodItems.add(new BlankMethodItem(currentCodeAddress));
}
if (baksmali.addCodeOffsets) {
if (classDef.options.addCodeOffsets) {
methodItems.add(new MethodItem(currentCodeAddress) {
@Override
@ -358,20 +324,22 @@ public class MethodDefinition {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write("#@");
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
return true;
}
});
}
if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
if (instruction.opcode == Opcode.INVOKE_STATIC || instruction.opcode == Opcode.INVOKE_STATIC_RANGE) {
MethodIdItem methodIdItem =
(MethodIdItem)((InstructionWithReference) instruction).getReferencedItem();
if (!classDef.options.noAccessorComments && (instruction instanceof ReferenceInstruction)) {
Opcode opcode = instruction.getOpcode();
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodIdItem)) {
if (opcode.referenceType == ReferenceType.METHOD) {
MethodReference methodReference =
(MethodReference)((ReferenceInstruction)instruction).getReference();
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
SyntheticAccessorResolver.AccessedMember accessedMember =
baksmali.syntheticAccessorResolver.getAccessedMember(methodIdItem);
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
if (accessedMember != null) {
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) {
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classDef.options.classPath, method,
classDef.options.inlineResolver);
methodAnalyzer.analyze();
ValidationException validationException = methodAnalyzer.getValidationException();
if (validationException != null) {
AnalysisException analysisException = methodAnalyzer.getAnalysisException();
if (analysisException != null) {
// TODO: need to keep track of whether any errors occurred, so we can exit with a non-zero result
methodItems.add(new CommentMethodItem(
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE));
} else if (baksmali.verify) {
methodAnalyzer.verify();
validationException = methodAnalyzer.getValidationException();
if (validationException != null) {
methodItems.add(new CommentMethodItem(
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE));
}
String.format("AnalysisException: %s", analysisException.getMessage()),
analysisException.codeAddress, Integer.MIN_VALUE));
analysisException.printStackTrace(System.err);
}
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
List<AnalyzedInstruction> instructions = methodAnalyzer.getAnalyzedInstructions();
int currentCodeAddress = 0;
for (int i=0; i<instructions.size(); i++) {
AnalyzedInstruction instruction = instructions.get(i);
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction.getInstruction());
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(
this, currentCodeAddress, instruction.getInstruction());
methodItems.add(methodItem);
if (instruction.getInstruction().getFormat() == Format.UnresolvedOdexInstruction) {
if (instruction.getInstruction().getOpcode().format == Format.UnresolvedOdexInstruction) {
methodItems.add(new CommentedOutMethodItem(
InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction.getOriginalInstruction())));
InstructionMethodItemFactory.makeInstructionFormatMethodItem(
this, currentCodeAddress, instruction.getOriginalInstruction())));
}
if (i != instructions.size() - 1) {
methodItems.add(new BlankMethodItem(currentCodeAddress));
}
if (baksmali.addCodeOffsets) {
if (classDef.options.addCodeOffsets) {
methodItems.add(new MethodItem(currentCodeAddress) {
@Override
@ -436,36 +396,38 @@ public class MethodDefinition {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write("#@");
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
return true;
}
});
}
if (baksmali.registerInfo != 0 && !instruction.getInstruction().getFormat().variableSizeFormat) {
if (classDef.options.registerInfo != 0 &&
!instruction.getInstruction().getOpcode().format.isPayloadFormat) {
methodItems.add(
new PreInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
new PreInstructionRegisterInfoMethodItem(classDef.options.registerInfo,
methodAnalyzer, registerFormatter, instruction, currentCodeAddress));
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) {
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) {
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = methodImpl.getTryBlocks();
if (tryBlocks.size() == 0) {
return;
}
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
int lastInstructionAddress = instructionMap.keyAt(instructionMap.size()-1);
int codeSize = lastInstructionAddress + instructions[instructions.length - 1].getSize(lastInstructionAddress);
int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) {
int startAddress = tryItem.getStartCodeAddress();
int endAddress = tryItem.getStartCodeAddress() + tryItem.getTryLength();
for (TryBlock<? extends ExceptionHandler> tryBlock: tryBlocks) {
int startAddress = tryBlock.getStartCodeAddress();
int endAddress = startAddress + tryBlock.getCodeUnitCount();
if (startAddress >= codeSize) {
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
*/
int lastCoveredIndex = instructionMap.getClosestSmaller(endAddress-1);
int lastCoveredAddress = instructionMap.keyAt(lastCoveredIndex);
int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false);
int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex);
//add the catch all handler if it exists
int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
if (catchAllAddress != -1) {
if (catchAllAddress >= codeSize) {
throw new RuntimeException(String.format(
"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));
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
int handlerAddress = handler.getHandlerCodeAddress();
if (handlerAddress >= codeSize) {
throw new ExceptionWithContext(
"Exception handler offset %d is past the end of the code block.", handlerAddress);
}
//use the address from the last covered instruction
CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress,
handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress());
CatchMethodItem catchMethodItem = new CatchMethodItem(classDef.options, labelCache, lastCoveredAddress,
handler.getExceptionType(), startAddress, endAddress, handlerAddress);
methodItems.add(catchMethodItem);
}
}
}
private void addDebugInfo(final List<MethodItem> methodItems) {
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getDebugInfo() == null) {
return;
for (DebugItem debugItem: methodImpl.getDebugItems()) {
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() {

View File

@ -28,26 +28,25 @@
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.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.util.BitSet;
public class PostInstructionRegisterInfoMethodItem extends MethodItem {
private final AnalyzedInstruction analyzedInstruction;
private final MethodAnalyzer methodAnalyzer;
@Nonnull private final RegisterFormatter registerFormatter;
@Nonnull private final AnalyzedInstruction analyzedInstruction;
public PostInstructionRegisterInfoMethodItem(AnalyzedInstruction analyzedInstruction, MethodAnalyzer methodAnalyzer,
int codeAddress) {
public PostInstructionRegisterInfoMethodItem(@Nonnull RegisterFormatter registerFormatter,
@Nonnull AnalyzedInstruction analyzedInstruction,
int codeAddress) {
super(codeAddress);
this.registerFormatter = registerFormatter;
this.analyzedInstruction = analyzedInstruction;
this.methodAnalyzer = methodAnalyzer;
}
@Override
@ -57,16 +56,16 @@ public class PostInstructionRegisterInfoMethodItem extends MethodItem {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
int registerInfo = baksmali.registerInfo;
int registerInfo = registerFormatter.options.registerInfo;
int registerCount = analyzedInstruction.getRegisterCount();
BitSet registers = new BitSet(registerCount);
if ((registerInfo & main.ALL) != 0) {
if ((registerInfo & baksmaliOptions.ALL) != 0) {
registers.set(0, registerCount);
} else {
if ((registerInfo & main.ALLPOST) != 0) {
if ((registerInfo & baksmaliOptions.ALLPOST) != 0) {
registers.set(0, registerCount);
} else if ((registerInfo & main.DEST) != 0) {
} else if ((registerInfo & baksmaliOptions.DEST) != 0) {
addDestRegs(registers, registerCount);
}
}
@ -76,16 +75,14 @@ public class PostInstructionRegisterInfoMethodItem extends MethodItem {
private void addDestRegs(BitSet printPostRegister, int registerCount) {
for (int registerNum=0; registerNum<registerCount; registerNum++) {
if (analyzedInstruction.getPreInstructionRegisterType(registerNum) !=
analyzedInstruction.getPostInstructionRegisterType(registerNum)) {
if (!analyzedInstruction.getPreInstructionRegisterType(registerNum).equals(
analyzedInstruction.getPostInstructionRegisterType(registerNum))) {
printPostRegister.set(registerNum);
}
}
}
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers) throws IOException {
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
int registerNum = registers.nextSetBit(0);
if (registerNum < 0) {
return false;
@ -93,17 +90,11 @@ public class PostInstructionRegisterInfoMethodItem extends MethodItem {
writer.write('#');
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum);
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
registerFormatter.writeTo(writer, registerNum);
writer.write('=');
if (registerType == null) {
writer.write("null");
} else {
registerType.writeTo(writer);
}
registerType.writeTo(writer);
writer.write(';');
}
return true;

View File

@ -28,30 +28,33 @@
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.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.util.BitSet;
public class PreInstructionRegisterInfoMethodItem extends MethodItem {
private static AnalyzedInstruction lastInstruction;
private final AnalyzedInstruction analyzedInstruction;
private final MethodAnalyzer methodAnalyzer;
private final int registerInfo;
@Nonnull private final MethodAnalyzer methodAnalyzer;
@Nonnull private final RegisterFormatter registerFormatter;
@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) {
super(codeAddress);
this.analyzedInstruction = analyzedInstruction;
this.registerInfo = registerInfo;
this.methodAnalyzer = methodAnalyzer;
this.registerFormatter = registerFormatter;
this.analyzedInstruction = analyzedInstruction;
}
@Override
@ -61,39 +64,44 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
int registerInfo = baksmali.registerInfo;
int registerCount = analyzedInstruction.getRegisterCount();
BitSet registers = new BitSet(registerCount);
BitSet mergeRegisters = null;
if ((registerInfo & main.ALL) != 0) {
if ((registerInfo & baksmaliOptions.ALL) != 0) {
registers.set(0, registerCount);
} else {
if ((registerInfo & main.ALLPRE) != 0) {
if ((registerInfo & baksmaliOptions.ALLPRE) != 0) {
registers.set(0, registerCount);
} else {
if ((registerInfo & main.ARGS) != 0) {
if ((registerInfo & baksmaliOptions.ARGS) != 0) {
addArgsRegs(registers);
}
if ((registerInfo & main.DIFFPRE) != 0) {
addDiffRegs(registers);
}
if ((registerInfo & main.MERGE) != 0) {
addMergeRegs(registers, registerCount);
} else if ((registerInfo & main.FULLMERGE) != 0 &&
if ((registerInfo & baksmaliOptions.MERGE) != 0) {
if (analyzedInstruction.isBeginningInstruction()) {
addParamRegs(registers, registerCount);
}
mergeRegisters = new BitSet(registerCount);
addMergeRegs(mergeRegisters, registerCount);
} else if ((registerInfo & baksmaliOptions.FULLMERGE) != 0 &&
(analyzedInstruction.isBeginningInstruction())) {
addParamRegs(registers, registerCount);
}
}
}
boolean printedSomething = false;
if ((registerInfo & main.FULLMERGE) != 0) {
printedSomething = writeFullMergeRegs(writer, registers, registerCount);
if ((registerInfo & baksmaliOptions.FULLMERGE) != 0) {
if (mergeRegisters == null) {
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 printedSomething;
return writeRegisterInfo(writer, registers, mergeRegisters);
}
private void addArgsRegs(BitSet registers) {
@ -101,25 +109,25 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getStartRegister(),
instruction.getStartRegister() + instruction.getRegCount());
instruction.getStartRegister() + instruction.getRegisterCount());
} else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) {
FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction();
int regCount = instruction.getRegCount();
int regCount = instruction.getRegisterCount();
switch (regCount) {
case 5:
registers.set(instruction.getRegisterA());
//fall through
case 4:
registers.set(instruction.getRegisterG());
//fall through
case 3:
case 4:
registers.set(instruction.getRegisterF());
//fall through
case 2:
case 3:
registers.set(instruction.getRegisterE());
//fall through
case 1:
case 2:
registers.set(instruction.getRegisterD());
//fall through
case 1:
registers.set(instruction.getRegisterC());
}
} else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction();
@ -130,30 +138,13 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getRegisterA());
registers.set(instruction.getRegisterB());
} else if (analyzedInstruction.getInstruction() instanceof SingleRegisterInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.getInstruction();
} else if (analyzedInstruction.getInstruction() instanceof OneRegisterInstruction) {
OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.getInstruction();
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) {
if (analyzedInstruction.isBeginningInstruction()) {
addParamRegs(registers, registerCount);
}
if (analyzedInstruction.getPredecessorCount() <= 1) {
//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
@ -165,118 +156,86 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
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);
continue;
}
}
}
}
private void addParamRegs(BitSet registers, int registerCount) {
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
int parameterRegisterCount = encodedMethod.method.getPrototype().getParameterRegisterCount();
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
parameterRegisterCount++;
}
int parameterRegisterCount = methodAnalyzer.getParamRegisterCount();
registers.set(registerCount-parameterRegisterCount, registerCount);
}
private boolean writeFullMergeRegs(IndentingWriter writer, BitSet registers, int registerCount)
throws IOException {
if (analyzedInstruction.getPredecessorCount() <= 1) {
return false;
}
private void writeFullMerge(IndentingWriter writer, int registerNum) throws IOException {
registerFormatter.writeTo(writer, registerNum);
writer.write('=');
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++) {
RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
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 (!first) {
writer.write(',');
}
if (!addRegister) {
continue;
}
if (firstRegister) {
firstRegister = false;
if (predecessor.getInstructionIndex() == -1) {
//the fake "StartOfMethod" instruction
writer.write("Start:");
} else {
writer.write('\n');
writer.write("0x");
writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor));
writer.write(':');
}
predecessorRegisterType.writeTo(writer);
writer.write('#');
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);
first = false;
}
return !firstRegister;
writer.write('}');
}
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers,
boolean addNewline) throws IOException {
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
BitSet fullMergeRegisters) throws IOException {
boolean firstRegister = true;
boolean previousWasFullMerge = false;
int registerNum = registers.nextSetBit(0);
if (registerNum < 0) {
return false;
}
if (addNewline) {
writer.write('\n');
}
writer.write('#');
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
writer.write('=');
if (registerType == null) {
writer.write("null");
boolean fullMerge = fullMergeRegisters!=null && fullMergeRegisters.get(registerNum);
if (fullMerge) {
if (!firstRegister) {
writer.write('\n');
writer.write('#');
}
writeFullMerge(writer, registerNum);
previousWasFullMerge = true;
} else {
if (previousWasFullMerge) {
writer.write('\n');
writer.write('#');
previousWasFullMerge = false;
}
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
registerFormatter.writeTo(writer, registerNum);
writer.write('=');
registerType.writeTo(writer);
writer.write(';');
}
writer.write(';');
firstRegister = false;
}
return true;
}

View File

@ -28,52 +28,35 @@
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.dexlib.*;
import org.jf.dexlib.Util.Utf8Utils;
import org.jf.util.StringUtils;
import java.io.IOException;
public class ReferenceFormatter {
public static void writeReference(IndentingWriter writer, Item item) throws IOException {
switch (item.getItemType()) {
case TYPE_METHOD_ID_ITEM:
writeMethodReference(writer, (MethodIdItem)item);
public static void writeStringReference(IndentingWriter writer, String item) throws IOException {
writer.write('"');
StringUtils.writeEscapedString(writer, 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;
case TYPE_FIELD_ID_ITEM:
writeFieldReference(writer, (FieldIdItem)item);
case ReferenceType.TYPE:
writer.write(((TypeReference)reference).getType());
return;
case TYPE_STRING_ID_ITEM:
writeStringReference(writer, (StringIdItem)item);
return;
case TYPE_TYPE_ID_ITEM:
writeTypeReference(writer, (TypeIdItem)item);
case ReferenceType.METHOD:
ReferenceUtil.writeMethodDescriptor(writer, (MethodReference)reference);
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());
}
}

View File

@ -28,17 +28,25 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.baksmaliOptions;
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;
/**
* This class contains the logic used for formatting registers
*/
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
@ -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
* 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 codeItem the <code>CodeItem</code> that the register is from
* @param startRegister the first register in the range
* @param lastRegister the last register in the range
*/
public static void writeRegisterRange(IndentingWriter writer, CodeItem codeItem, int startRegister,
int lastRegister) throws IOException {
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();
public void writeRegisterRange(IndentingWriter writer, int startRegister, int lastRegister) throws IOException {
if (!options.noParameterRegisters) {
assert startRegister <= lastRegister;
if (startRegister >= registerCount - parameterRegisterCount) {
@ -83,14 +83,10 @@ public class RegisterFormatter {
* and if so, formats it in the p<n> format instead.
*
* @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
*/
public static void writeTo(IndentingWriter writer, CodeItem codeItem, int register) throws IOException {
if (!baksmali.noParameterRegisters) {
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
int registerCount = codeItem.getRegisterCount();
public void writeTo(IndentingWriter writer, int register) throws IOException {
if (!options.noParameterRegisters) {
if (register >= registerCount - parameterRegisterCount) {
writer.write('p');
writer.printSignedIntAsDec((register - (registerCount - parameterRegisterCount)));

View File

@ -28,16 +28,17 @@
package org.jf.baksmali.Adaptors;
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
import static org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver.AccessedMember;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.util.SyntheticAccessorResolver;
import org.jf.util.ExceptionWithContext;
import org.jf.util.IndentingWriter;
import java.io.IOException;
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);
this.accessedMember = accessedMember;
}
@ -48,15 +49,73 @@ public class SyntheticAccessCommentMethodItem extends MethodItem {
}
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write('#');
if (accessedMember.accessedMemberType == SyntheticAccessorResolver.METHOD) {
writer.write("calls: ");
} else if (accessedMember.accessedMemberType == SyntheticAccessorResolver.GETTER) {
writer.write("getter for: ");
} else {
writer.write("setter for: ");
writer.write("# ");
switch (accessedMember.accessedMemberType) {
case SyntheticAccessorResolver.METHOD:
writer.write("invokes: ");
break;
case SyntheticAccessorResolver.GETTER:
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;
}
}

View File

@ -29,14 +29,14 @@
package org.jf.baksmali.Renderers;
import org.jf.util.IndentingWriter;
import org.jf.dexlib.Util.Utf8Utils;
import org.jf.util.StringUtils;
import java.io.IOException;
public class CharRenderer {
public static void writeTo(IndentingWriter writer, char val) throws IOException {
writer.write('\'');
Utf8Utils.writeEscapedChar(writer, val);
StringUtils.writeEscapedChar(writer, val);
writer.write('\'');
}
}

View File

@ -28,83 +28,37 @@
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.dexlib.ClassDefItem;
import org.jf.dexlib.Code.Analysis.*;
import org.jf.dexlib.DexFile;
import org.jf.dexlib2.analysis.ClassPath;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.util.SyntheticAccessorResolver;
import org.jf.util.ClassFileNameHandler;
import org.jf.util.IndentingWriter;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.List;
import java.util.concurrent.*;
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 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) {
public static boolean disassembleDexFile(DexFile dexFile, final baksmaliOptions options) {
if (options.registerInfo != 0 || options.deodex) {
try {
String[] extraBootClassPathArray = null;
if (extraBootClassPath != null && extraBootClassPath.length() > 0) {
assert extraBootClassPath.charAt(0) == ':';
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);
Iterable<String> extraClassPathEntries;
if (options.extraClassPathEntries != null) {
extraClassPathEntries = options.extraClassPathEntries;
} else {
String[] bootClassPathArray = null;
if (bootClassPath != null) {
bootClassPathArray = bootClassPath.split(":");
}
ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray,
dexFilePath, dexFile, checkPackagePrivateAccess);
extraClassPathEntries = ImmutableList.of();
}
if (inlineTable != null) {
inlineResolver = new CustomInlineMethodResolver(inlineTable);
}
options.classPath = ClassPath.fromClassPath(options.bootClassPathDirs,
Iterables.concat(options.bootClassPathEntries, extraClassPathEntries), dexFile,
options.apiLevel);
} catch (Exception ex) {
System.err.println("\n\nError occured while loading boot class path files. Aborting.");
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.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);
}
}
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
//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
//may still change of course
ArrayList<ClassDefItem> classDefItems = new ArrayList<ClassDefItem>(dexFile.ClassDefsSection.getItems());
Collections.sort(classDefItems, new Comparator<ClassDefItem>() {
public int compare(ClassDefItem classDefItem1, ClassDefItem classDefItem2) {
return classDefItem1.getClassType().getTypeDescriptor().compareTo(classDefItem1.getClassType().getTypeDescriptor());
}
});
List<? extends ClassDef> classDefs = Ordering.natural().sortedCopy(dexFile.getClasses());
ClassFileNameHandler fileNameHandler = new ClassFileNameHandler(outputDirectoryFile, ".smali");
if (!options.noAccessorComments) {
options.syntheticAccessorResolver = new SyntheticAccessorResolver(classDefs);
}
for (ClassDefItem classDefItem: classDefItems) {
/**
* 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 '/'
*/
final ClassFileNameHandler fileNameHandler = new ClassFileNameHandler(outputDirectoryFile, ".smali");
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
if (classDescriptor.charAt(0) != 'L' ||
classDescriptor.charAt(classDescriptor.length()-1) != ';') {
System.err.println("Unrecognized class descriptor - " + classDescriptor + " - skipping class");
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;
}
for (final ClassDef classDef: classDefs) {
tasks.add(executor.submit(new Callable<Boolean>() {
@Override public Boolean call() throws Exception {
return disassembleClass(classDef, fileNameHandler, options);
}
}));
}
if (!smaliFile.exists()){
if (!smaliFile.createNewFile()) {
System.err.println("Unable to create file " + smaliFile.toString() + " - skipping class");
continue;
boolean errorOccurred = false;
for (Future<Boolean> task: tasks) {
while(true) {
try {
if (!task.get()) {
errorOccurred = true;
}
} catch (InterruptedException ex) {
continue;
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
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);
break;
}
}
executor.shutdown();
return !errorOccurred;
}
private static final Pattern extJarPattern = Pattern.compile("(?:^|\\\\|/)ext.(?:jar|odex)$");
private static boolean isExtJar(String dexFilePath) {
Matcher m = extJarPattern.matcher(dexFilePath);
return m.find();
private static boolean disassembleClass(ClassDef classDef, ClassFileNameHandler fileNameHandler,
baksmaliOptions options) {
/**
* 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;
}
}

View File

@ -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(":")));
}
}

View File

@ -28,79 +28,43 @@
package org.jf.baksmali;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.ByteArrayAnnotatedOutput;
import org.jf.dexlib2.Opcodes;
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.IOException;
import java.io.Writer;
public class dump {
public static void dump(DexFile dexFile, String dumpFileName, String outputDexFileName, boolean sort)
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();
public static void dump(DexBackedDexFile dexFile, String dumpFileName, int apiLevel) throws IOException {
if (dumpFileName != null) {
out.enableAnnotations(120, true);
}
dexFile.place();
dexFile.writeTo(out);
//write the dump
if (dumpFileName != null) {
out.finishAnnotating();
FileWriter writer = null;
Writer writer = null;
try {
writer = new FileWriter(dumpFileName);
out.writeAnnotationsTo(writer);
writer = new BufferedWriter(new FileWriter(dumpFileName));
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) {
System.err.println("\n\nThere was an error while dumping the dex file to " + dumpFileName);
ex.printStackTrace();
System.err.println("There was an error while dumping the dex file to " + dumpFileName);
ex.printStackTrace(System.err);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException ex) {
System.err.println("\n\nThere was an error while closing the dump file " + dumpFileName);
ex.printStackTrace();
}
}
}
}
//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();
System.err.println("There was an error while closing the dump file " + dumpFileName);
ex.printStackTrace(System.err);
}
}
}

View File

@ -28,16 +28,20 @@
package org.jf.baksmali;
import com.google.common.collect.Lists;
import org.apache.commons.cli.*;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.DexFile;
import org.jf.dexlib2.DexFileFactory;
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.SmaliHelpFormatter;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
@ -50,16 +54,6 @@ public class main {
private static final Options debugOptions;
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 {
options = new Options();
basicOptions = new Options();
@ -67,14 +61,19 @@ public class main {
buildOptions();
InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties");
Properties properties = new Properties();
String version = "(unknown)";
try {
properties.load(templateStream);
version = properties.getProperty("application.version");
} catch (IOException ex) {
if (templateStream != null) {
Properties properties = new Properties();
String version = "(unknown)";
try {
properties.load(templateStream);
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!
*/
public static void main(String[] args) {
public static void main(String[] args) throws IOException {
Locale locale = new Locale("en", "US");
Locale.setDefault(locale);
@ -100,43 +99,18 @@ public class main {
return;
}
baksmaliOptions options = new baksmaliOptions();
boolean disassemble = true;
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 outputDexFileName = null;
String inputDexFileName = null;
String bootClassPath = null;
StringBuffer extraBootClassPathEntries = new StringBuffer();
List<String> bootClassPathDirs = new ArrayList<String>();
bootClassPathDirs.add(".");
String inlineTable = null;
boolean jumboInstructions = false;
boolean setBootClassPath = false;
String[] remainingArgs = commandLine.getArgs();
Option[] clOptions = commandLine.getOptions();
Option[] options = commandLine.getOptions();
for (int i=0; i<options.length; i++) {
Option option = options[i];
for (int i=0; i<clOptions.length; i++) {
Option option = clOptions[i];
String opt = option.getOpt();
switch (opt.charAt(0)) {
@ -144,8 +118,8 @@ public class main {
version();
return;
case '?':
while (++i < options.length) {
if (options[i].getOpt().charAt(0) == '?') {
while (++i < clOptions.length) {
if (clOptions[i].getOpt().charAt(0) == '?') {
usage(true);
return;
}
@ -153,109 +127,96 @@ public class main {
usage(false);
return;
case 'o':
outputDirectory = commandLine.getOptionValue("o");
options.outputDirectory = commandLine.getOptionValue("o");
break;
case 'p':
noParameterRegisters = true;
options.noParameterRegisters = true;
break;
case 'l':
useLocalsDirective = true;
options.useLocalsDirective = true;
break;
case 's':
useSequentialLabels = true;
options.useSequentialLabels = true;
break;
case 'b':
outputDebugInfo = false;
options.outputDebugInfo = false;
break;
case 'd':
bootClassPathDirs.add(option.getValue());
options.bootClassPathDirs.add(option.getValue());
break;
case 'f':
addCodeOffsets = true;
options.addCodeOffsets = true;
break;
case 'r':
String[] values = commandLine.getOptionValues('r');
int registerInfo = 0;
if (values == null || values.length == 0) {
registerInfo = ARGS | DEST;
registerInfo = baksmaliOptions.ARGS | baksmaliOptions.DEST;
} else {
for (String value: values) {
if (value.equalsIgnoreCase("ALL")) {
registerInfo |= ALL;
registerInfo |= baksmaliOptions.ALL;
} else if (value.equalsIgnoreCase("ALLPRE")) {
registerInfo |= ALLPRE;
registerInfo |= baksmaliOptions.ALLPRE;
} else if (value.equalsIgnoreCase("ALLPOST")) {
registerInfo |= ALLPOST;
registerInfo |= baksmaliOptions.ALLPOST;
} else if (value.equalsIgnoreCase("ARGS")) {
registerInfo |= ARGS;
registerInfo |= baksmaliOptions.ARGS;
} else if (value.equalsIgnoreCase("DEST")) {
registerInfo |= DEST;
registerInfo |= baksmaliOptions.DEST;
} else if (value.equalsIgnoreCase("MERGE")) {
registerInfo |= MERGE;
registerInfo |= baksmaliOptions.MERGE;
} else if (value.equalsIgnoreCase("FULLMERGE")) {
registerInfo |= FULLMERGE;
registerInfo |= baksmaliOptions.FULLMERGE;
} else {
usage();
return;
}
}
if ((registerInfo & FULLMERGE) != 0) {
registerInfo &= ~MERGE;
if ((registerInfo & baksmaliOptions.FULLMERGE) != 0) {
registerInfo &= ~baksmaliOptions.MERGE;
}
}
options.registerInfo = registerInfo;
break;
case 'c':
String bcp = commandLine.getOptionValue("c");
if (bcp != null && bcp.charAt(0) == ':') {
extraBootClassPathEntries.append(bcp);
options.addExtraClassPath(bcp);
} else {
bootClassPath = bcp;
setBootClassPath = true;
options.setBootClassPath(bcp);
}
break;
case 'x':
deodex = true;
options.deodex = true;
break;
case 'm':
noAccessorComments = true;
options.noAccessorComments = true;
break;
case 'a':
apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
if (apiLevel >= 17) {
checkPackagePrivateAccess = true;
}
options.apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
break;
case 'j':
options.jobs = Integer.parseInt(commandLine.getOptionValue("j"));
break;
case 'N':
disassemble = false;
break;
case 'D':
doDump = true;
dumpFileName = commandLine.getOptionValue("D", inputDexFileName + ".dump");
dumpFileName = commandLine.getOptionValue("D");
break;
case 'I':
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;
options.ignoreErrors = true;
break;
case 'T':
inlineTable = commandLine.getOptionValue("T");
options.inlineResolver = new CustomInlineMethodResolver(options.classPath, new File(commandLine.getOptionValue("T")));
break;
case 'K':
checkPackagePrivateAccess = true;
options.checkPackagePrivateAccess = true;
break;
default:
assert false;
@ -267,68 +228,60 @@ public class main {
return;
}
inputDexFileName = remainingArgs[0];
try {
File dexFileFile = new File(inputDexFileName);
if (!dexFileFile.exists()) {
System.err.println("Can't find the file " + inputDexFileName);
System.exit(1);
if (options.jobs <= 0) {
options.jobs = Runtime.getRuntime().availableProcessors();
if (options.jobs > 6) {
options.jobs = 6;
}
}
Opcode.updateMapsForApiLevel(apiLevel, jumboInstructions);
String inputDexFileName = remainingArgs[0];
//Read in and parse the dex file
DexFile dexFile = new DexFile(dexFileFile, !fixRegisters, false);
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();
File dexFileFile = new File(inputDexFileName);
if (!dexFileFile.exists()) {
System.err.println("Can't find the file " + inputDexFileName);
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);
}
}
@ -363,6 +316,7 @@ public class main {
System.exit(0);
}
@SuppressWarnings("AccessStaticViaInstance")
private static void buildOptions() {
Option versionOption = OptionBuilder.withLongOpt("version")
.withDescription("prints the version then exits")
@ -441,11 +395,18 @@ public class main {
Option apiLevelOption = OptionBuilder.withLongOpt("api-level")
.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()
.withArgName("API_LEVEL")
.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")
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
" (<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")
.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")
.withDescription("suppresses the output of the disassembly")
.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")
.withDescription("specify a file containing a custom inline method table to use for deodexing")
.hasArg()
.withArgName("FILE")
.create("T");
Option checkPackagePrivateAccess = OptionBuilder.withLongOpt("check-package-private-access")
.withDescription("When deodexing, use the new virtual table generation logic that " +
"prevents overriding an inaccessible package private method. This is a temporary option " +
"that will be removed once this new functionality can be tied to a specific api level.")
.create("K");
basicOptions.addOption(versionOption);
basicOptions.addOption(helpOption);
basicOptions.addOption(outputDirOption);
@ -509,16 +450,13 @@ public class main {
basicOptions.addOption(codeOffsetOption);
basicOptions.addOption(noAccessorCommentsOption);
basicOptions.addOption(apiLevelOption);
basicOptions.addOption(jobsOption);
debugOptions.addOption(dumpOption);
debugOptions.addOption(ignoreErrorsOption);
debugOptions.addOption(jumboInstructionsOption);
debugOptions.addOption(noDisassemblyOption);
debugOptions.addOption(writeDexOption);
debugOptions.addOption(sortOption);
debugOptions.addOption(fixSignedRegisterOption);
debugOptions.addOption(verifyDexOption);
debugOptions.addOption(inlineTableOption);
debugOptions.addOption(checkPackagePrivateAccess);
for (Object option: basicOptions.getOptions()) {
options.addOption((Option)option);
@ -527,4 +465,60 @@ public class main {
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");
}
}
}

View File

@ -0,0 +1 @@
application.version=${version}

View File

@ -1 +0,0 @@
application.version=1.4.2

View File

@ -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>
>>

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
/target

View File

@ -30,7 +30,7 @@
*/
dependencies {
compile project(':brut.j.dir')
compile 'com.google.code.findbugs:jsr305:1.3.9'
compile 'com.google.collections:google-collections:1.0'
compile project(':util')
compile depends.findbugs
compile depends.guava
}

View File

@ -30,7 +30,7 @@ package org.jf.dexlib;
import com.google.common.base.Preconditions;
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.ReadOnlyArrayList;

View File

@ -30,6 +30,7 @@ package org.jf.dexlib;
import com.google.common.base.Preconditions;
import org.jf.dexlib.Util.*;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

View File

@ -32,7 +32,7 @@ import org.jf.dexlib.Code.*;
import org.jf.dexlib.Item;
import org.jf.dexlib.ItemType;
import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.util.ExceptionWithContext;
import java.util.*;

View File

@ -30,7 +30,7 @@ package org.jf.dexlib.Code.Analysis;
import org.jf.dexlib.*;
import org.jf.dexlib.Util.AccessFlags;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.util.ExceptionWithContext;
import org.jf.dexlib.Util.SparseArray;
import javax.annotation.Nonnull;
@ -44,8 +44,6 @@ import static org.jf.dexlib.ClassDataItem.EncodedField;
import static org.jf.dexlib.ClassDataItem.EncodedMethod;
public class ClassPath {
public static boolean dontLoadClassPath = false;
private static ClassPath theClassPath = null;
/**
@ -263,10 +261,6 @@ public class ClassPath {
@Nonnull
public static ClassDef getClassDef(String classType, boolean createUnresolvedClassDef) {
if (dontLoadClassPath) {
return null;
}
ClassDef classDef = theClassPath.classDefs.get(classType);
if (classDef == null) {
//if it's an array class, try to create it
@ -543,7 +537,7 @@ public class ClassPath {
}
public ClassDef getSuperclass() {
return theClassPath.javaLangObjectClassDef;
throw unresolvedValidationException();
}
public int getClassDepth() {
@ -599,10 +593,6 @@ public class ClassPath {
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;
//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/io/Serializable;"));
isInterface = false;
isPublic = true;
vtable = superclass.vtable;
methodLookup = superclass.methodLookup;
@ -663,7 +652,6 @@ public class ClassPath {
this.superclass = null;
implementedInterfaces = null;
isInterface = false;
isPublic = true;
vtable = null;
methodLookup = null;
instanceFields = null;
@ -677,7 +665,6 @@ public class ClassPath {
this.superclass = ClassPath.getClassDef("Ljava/lang/Object;");
implementedInterfaces = new TreeSet<ClassDef>();
isInterface = false;
isPublic = true;
vtable = superclass.vtable;
methodLookup = superclass.methodLookup;
@ -692,7 +679,6 @@ public class ClassPath {
protected ClassDef(UnresolvedClassInfo classInfo) {
classType = classInfo.classType;
isPublic = classInfo.isPublic;
isInterface = classInfo.isInterface;
superclass = loadSuperclass(classInfo);
@ -738,6 +724,14 @@ public class ClassPath {
return superclass;
}
VirtualMethod[] getVtable() {
return vtable;
}
SparseArray<FieldDef> getInstanceFields() {
return instanceFields;
}
public int getClassDepth() {
return classDepth;
}
@ -746,10 +740,6 @@ public class ClassPath {
return this.isInterface;
}
public boolean isPublic() {
return this.isPublic;
}
public boolean extendsClass(ClassDef superclassDef) {
if (superclassDef == null) {
return false;
@ -1225,7 +1215,7 @@ public class ClassPath {
}
}
private static class VirtualMethod {
static class VirtualMethod {
public String containingClass;
public String method;
public boolean isPackagePrivate;
@ -1238,7 +1228,6 @@ public class ClassPath {
private static class UnresolvedClassInfo {
public final String dexFilePath;
public final String classType;
public final boolean isPublic;
public final boolean isInterface;
public final String superclassType;
public final String[] interfaces;
@ -1252,7 +1241,6 @@ public class ClassPath {
classType = classDefItem.getClassType().getTypeDescriptor();
isPublic = (classDefItem.getAccessFlags() & AccessFlags.PUBLIC.getValue()) != 0;
isInterface = (classDefItem.getAccessFlags() & AccessFlags.INTERFACE.getValue()) != 0;
TypeIdItem superclassType = classDefItem.getSuperclass();

View File

@ -64,21 +64,19 @@ public class DeodexUtil {
return inlineMethodResolver.resolveExecuteInline(instruction);
}
public FieldIdItem lookupField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
int fieldOffset) {
ClassPath.FieldDef field = instanceClass.getInstanceField(fieldOffset);
public FieldIdItem lookupField(ClassPath.ClassDef classDef, int fieldOffset) {
ClassPath.FieldDef field = classDef.getInstanceField(fieldOffset);
if (field == null) {
return null;
}
return parseAndResolveField(accessingClass, instanceClass, field);
return parseAndResolveField(classDef, field);
}
private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)");
public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
int methodIndex) {
String method = instanceClass.getVirtualMethod(methodIndex);
public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef classDef, int methodIndex) {
String method = classDef.getVirtualMethod(methodIndex);
if (method == null) {
return null;
}
@ -93,20 +91,20 @@ public class DeodexUtil {
String methodParams = m.group(2);
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
//method being looked up was a method on java.lang.Object.
instanceClass = ClassPath.getClassDef("Ljava/lang/Object;");
} else if (instanceClass.isInterface()) {
instanceClass = instanceClass.getSuperclass();
assert instanceClass != null;
classDef = ClassPath.getClassDef("Ljava/lang/Object;");
} else if (classDef.isInterface()) {
classDef = classDef.getSuperclass();
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,
String methodName, String methodParams, String methodRet) {
private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef classDef, String methodName, String methodParams,
String methodRet) {
StringIdItem methodNameItem = StringIdItem.lookupStringIdItem(dexFile, methodName);
if (methodNameItem == null) {
return null;
@ -199,14 +197,14 @@ public class DeodexUtil {
return null;
}
ClassPath.ClassDef methodClassDef = definingClass;
ClassPath.ClassDef methodClassDef = classDef;
do {
TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType());
if (classTypeItem != null) {
MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem);
if (methodIdItem != null && checkClassAccess(accessingClass, methodClassDef)) {
if (methodIdItem != null) {
return methodIdItem;
}
}
@ -216,28 +214,7 @@ public class DeodexUtil {
return null;
}
private static boolean checkClassAccess(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass) {
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) {
private FieldIdItem parseAndResolveField(ClassPath.ClassDef classDef, ClassPath.FieldDef field) {
String definingClass = field.definingClass;
String fieldName = field.name;
String fieldType = field.type;
@ -252,7 +229,7 @@ public class DeodexUtil {
return null;
}
ClassPath.ClassDef fieldClass = instanceClass;
ClassPath.ClassDef fieldClass = classDef;
ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>();
parents.add(fieldClass);
@ -271,7 +248,7 @@ public class DeodexUtil {
}
FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem);
if (fieldIdItem != null && checkClassAccess(accessingClass, fieldClass)) {
if (fieldIdItem != null) {
return fieldIdItem;
}
}
@ -306,8 +283,7 @@ public class DeodexUtil {
private void loadMethod(DeodexUtil deodexUtil) {
ClassPath.ClassDef classDef = ClassPath.getClassDef(classType);
this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, classDef, methodName, parameters,
returnType);
this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, methodName, parameters, returnType);
}
public String getMethodString() {

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -32,7 +32,7 @@ import org.jf.dexlib.*;
import org.jf.dexlib.Code.*;
import org.jf.dexlib.Code.Format.*;
import org.jf.dexlib.Util.AccessFlags;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.util.ExceptionWithContext;
import org.jf.dexlib.Util.SparseArray;
import java.util.BitSet;
@ -703,34 +703,28 @@ public class MethodAnalyzer {
analyzeConstString(analyzedInstruction);
return true;
case CONST_CLASS:
case CONST_CLASS_JUMBO:
analyzeConstClass(analyzedInstruction);
return true;
case MONITOR_ENTER:
case MONITOR_EXIT:
return true;
case CHECK_CAST:
case CHECK_CAST_JUMBO:
analyzeCheckCast(analyzedInstruction);
return true;
case INSTANCE_OF:
case INSTANCE_OF_JUMBO:
analyzeInstanceOf(analyzedInstruction);
return true;
case ARRAY_LENGTH:
analyzeArrayLength(analyzedInstruction);
return true;
case NEW_INSTANCE:
case NEW_INSTANCE_JUMBO:
analyzeNewInstance(analyzedInstruction);
return true;
case NEW_ARRAY:
case NEW_ARRAY_JUMBO:
analyzeNewArray(analyzedInstruction);
return true;
case FILLED_NEW_ARRAY:
case FILLED_NEW_ARRAY_RANGE:
case FILLED_NEW_ARRAY_JUMBO:
return true;
case FILL_ARRAY_DATA:
analyzeArrayDataOrSwitch(analyzedInstruction);
@ -793,86 +787,58 @@ public class MethodAnalyzer {
case APUT_OBJECT:
return true;
case IGET:
case IGET_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Integer);
return true;
case IGET_BOOLEAN:
case IGET_BOOLEAN_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Boolean);
return true;
case IGET_BYTE:
case IGET_BYTE_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Byte);
return true;
case IGET_CHAR:
case IGET_CHAR_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Char);
return true;
case IGET_SHORT:
case IGET_SHORT_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Short);
return true;
case IGET_WIDE:
case IGET_WIDE_JUMBO:
case IGET_OBJECT:
case IGET_OBJECT_JUMBO:
analyzeIgetWideObject(analyzedInstruction);
return true;
case IPUT:
case IPUT_JUMBO:
case IPUT_BOOLEAN:
case IPUT_BOOLEAN_JUMBO:
case IPUT_BYTE:
case IPUT_BYTE_JUMBO:
case IPUT_CHAR:
case IPUT_CHAR_JUMBO:
case IPUT_SHORT:
case IPUT_SHORT_JUMBO:
case IPUT_WIDE:
case IPUT_WIDE_JUMBO:
case IPUT_OBJECT:
case IPUT_OBJECT_JUMBO:
return true;
case SGET:
case SGET_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Integer);
return true;
case SGET_BOOLEAN:
case SGET_BOOLEAN_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Boolean);
return true;
case SGET_BYTE:
case SGET_BYTE_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Byte);
return true;
case SGET_CHAR:
case SGET_CHAR_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Char);
return true;
case SGET_SHORT:
case SGET_SHORT_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Short);
return true;
case SGET_WIDE:
case SGET_WIDE_JUMBO:
case SGET_OBJECT:
case SGET_OBJECT_JUMBO:
analyzeSgetWideObject(analyzedInstruction);
return true;
case SPUT:
case SPUT_JUMBO:
case SPUT_BOOLEAN:
case SPUT_BOOLEAN_JUMBO:
case SPUT_BYTE:
case SPUT_BYTE_JUMBO:
case SPUT_CHAR:
case SPUT_CHAR_JUMBO:
case SPUT_SHORT:
case SPUT_SHORT_JUMBO:
case SPUT_WIDE:
case SPUT_WIDE_JUMBO:
case SPUT_OBJECT:
case SPUT_OBJECT_JUMBO:
return true;
case INVOKE_VIRTUAL:
case INVOKE_SUPER:
@ -883,18 +849,13 @@ public class MethodAnalyzer {
case INVOKE_STATIC:
case INVOKE_INTERFACE:
case INVOKE_VIRTUAL_RANGE:
case INVOKE_VIRTUAL_JUMBO:
case INVOKE_SUPER_RANGE:
case INVOKE_SUPER_JUMBO:
return true;
case INVOKE_DIRECT_RANGE:
case INVOKE_DIRECT_JUMBO:
analyzeInvokeDirectRange(analyzedInstruction);
return true;
case INVOKE_STATIC_RANGE:
case INVOKE_STATIC_JUMBO:
case INVOKE_INTERFACE_RANGE:
case INVOKE_INTERFACE_JUMBO:
return true;
case NEG_INT:
case NOT_INT:
@ -1115,23 +1076,6 @@ public class MethodAnalyzer {
case SPUT_OBJECT_VOLATILE:
analyzePutGetVolatile(analyzedInstruction);
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:
assert false;
return true;
@ -1197,7 +1141,6 @@ public class MethodAnalyzer {
case CONST_STRING_JUMBO:
return;
case CONST_CLASS:
case CONST_CLASS_JUMBO:
verifyConstClass(analyzedInstruction);
return;
case MONITOR_ENTER:
@ -1205,18 +1148,15 @@ public class MethodAnalyzer {
verifyMonitor(analyzedInstruction);
return;
case CHECK_CAST:
case CHECK_CAST_JUMBO:
verifyCheckCast(analyzedInstruction);
return;
case INSTANCE_OF:
case INSTANCE_OF_JUMBO:
verifyInstanceOf(analyzedInstruction);
return;
case ARRAY_LENGTH:
verifyArrayLength(analyzedInstruction);
return;
case NEW_INSTANCE:
case NEW_INSTANCE_JUMBO:
verifyNewInstance(analyzedInstruction);
return;
case NEW_ARRAY:
@ -1626,19 +1566,6 @@ public class MethodAnalyzer {
case IPUT_OBJECT_VOLATILE:
case SGET_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?
default:
assert false;
@ -2434,7 +2361,7 @@ public class MethodAnalyzer {
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert arrayRegisterType != null;
if (! ClassPath.dontLoadClassPath && arrayRegisterType.category != RegisterType.Category.Null) {
if (arrayRegisterType.category != RegisterType.Category.Null) {
assert arrayRegisterType.type != null;
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
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());
assert arrayRegisterType != null;
if (! ClassPath.dontLoadClassPath && arrayRegisterType.category != RegisterType.Category.Null) {
if (arrayRegisterType.category != RegisterType.Category.Null) {
assert arrayRegisterType.type != null;
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
@ -3578,14 +3505,7 @@ public class MethodAnalyzer {
return false;
}
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()));
}
FieldIdItem fieldIdItem = deodexUtil.lookupField(accessingClass, objectRegisterType.type, fieldOffset);
FieldIdItem fieldIdItem = deodexUtil.lookupField(objectRegisterType.type, fieldOffset);
if (fieldIdItem == null) {
throw new ValidationException(String.format("Could not resolve the field in class %s at offset %d",
objectRegisterType.type.getClassType(), fieldOffset));
@ -3628,16 +3548,12 @@ public class MethodAnalyzer {
}
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 (accessingClass.getSuperclass() != null) {
methodIdItem = deodexUtil.lookupVirtualMethod(accessingClass, accessingClass.getSuperclass(),
methodIndex);
ClassPath.ClassDef classDef = ClassPath.getClassDef(this.encodedMethod.method.getContainingClass(), false);
assert classDef != null;
if (classDef.getSuperclass() != null) {
methodIdItem = deodexUtil.lookupVirtualMethod(classDef.getSuperclass(), methodIndex);
}
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).
//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 = deodexUtil.lookupVirtualMethod(accessingClass, accessingClass, methodIndex);
methodIdItem = deodexUtil.lookupVirtualMethod(classDef, methodIndex);
}
} else{
methodIdItem = deodexUtil.lookupVirtualMethod(accessingClass, objectRegisterType.type, methodIndex);
methodIdItem = deodexUtil.lookupVirtualMethod(objectRegisterType.type, methodIndex);
}
if (methodIdItem == null) {
@ -3706,23 +3622,12 @@ public class MethodAnalyzer {
if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
if (analyzedInstruction.instruction.opcode.format == Format.Format21c) {
deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(), fieldIdItem);
} else {
assert(analyzedInstruction.instruction.opcode.format == Format.Format41c);
deodexedInstruction = new Instruction41c(opcode, (byte)instruction.getRegisterA(), fieldIdItem);
}
deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(), fieldIdItem);
} else {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
if (analyzedInstruction.instruction.opcode.format == Format.Format22c) {
deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
(byte)instruction.getRegisterB(), fieldIdItem);
} else {
assert(analyzedInstruction.instruction.opcode.format == Format.Format52c);
deodexedInstruction = new Instruction52c(opcode, (byte)instruction.getRegisterA(),
(byte)instruction.getRegisterB(), fieldIdItem);
}
deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
(byte)instruction.getRegisterB(), fieldIdItem);
}
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
@ -3733,17 +3638,6 @@ public class MethodAnalyzer {
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,
RegisterType.Category instructionCategory) {
if (arrayFieldCategory == instructionCategory) {

View File

@ -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) {
switch (type) {
case 'Z':
@ -315,20 +214,14 @@ public class OdexedFieldInstructionMapper {
}
static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(String fieldType, Opcode odexedOpcode) {
boolean jumbo = odexedOpcode.isJumboOpcode();
int opcodeType = odexedOpcode.setsRegister()?0:1;
int opcodeSubType = getOpcodeSubtype(odexedOpcode);
int typeIndex = getTypeIndex(fieldType.charAt(0));
Opcode correctOdexedOpcode, deodexedOpcode;
if (jumbo) {
correctOdexedOpcode = jumboOpcodeMap[opcodeType][opcodeSubType-1][0][typeIndex];
deodexedOpcode = jumboOpcodeMap[opcodeType][opcodeSubType-1][1][typeIndex];
} else {
correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex];
deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex];
}
correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex];
deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex];
if (correctOdexedOpcode != odexedOpcode) {
throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType,

View File

@ -28,7 +28,7 @@
package org.jf.dexlib.Code.Analysis;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.util.ExceptionWithContext;
public class ValidationException extends ExceptionWithContext {
private int codeAddress;

View File

@ -60,10 +60,7 @@ public enum Format {
Format3rc(Instruction3rc.Factory, 6),
Format3rmi(Instruction3rmi.Factory, 6),
Format3rms(Instruction3rms.Factory, 6),
Format41c(Instruction41c.Factory, 8),
Format51l(Instruction51l.Factory, 10),
Format52c(Instruction52c.Factory, 10),
Format5rc(Instruction5rc.Factory, 10),
ArrayData(null, -1, true),
PackedSwitchData(null, -1, true),
SparseSwitchData(null, -1, true),

View File

@ -100,11 +100,7 @@ public class Instruction21c extends InstructionWithReference implements SingleRe
return null;
}
if (jumboOpcode.format == Format.Format31c) {
return new Instruction31c(jumboOpcode, (short)getRegisterA(), getReferencedItem());
}
return new Instruction41c(jumboOpcode, getRegisterA(), getReferencedItem());
return new Instruction31c(jumboOpcode, (short)getRegisterA(), getReferencedItem());
}
private static class Factory implements Instruction.InstructionFactory {

View File

@ -37,8 +37,7 @@ import org.jf.dexlib.Item;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.NumberUtils;
public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction,
InstructionWithJumboVariant {
public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction {
public static final Instruction.InstructionFactory Factory = new Factory();
private byte regA;
private byte regB;
@ -89,15 +88,6 @@ public class Instruction22c extends InstructionWithReference implements TwoRegis
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 {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
return new Instruction22c(dexFile, opcode, buffer, bufferIndex);

View File

@ -41,8 +41,7 @@ import org.jf.dexlib.Util.NumberUtils;
import static org.jf.dexlib.Code.Opcode.*;
public class Instruction3rc extends InstructionWithReference implements RegisterRangeInstruction,
InstructionWithJumboVariant {
public class Instruction3rc extends InstructionWithReference implements RegisterRangeInstruction {
public static final Instruction.InstructionFactory Factory = new Factory();
private byte regCount;
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 {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
return new Instruction3rc(dexFile, opcode, buffer, bufferIndex);

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -30,8 +30,7 @@ package org.jf.dexlib.Code;
import org.jf.dexlib.Code.Format.*;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.dexlib.Util.Hex;
import org.jf.util.ExceptionWithContext;
public class InstructionIterator {
public static void IterateInstructions(DexFile dexFile, byte[] insns, ProcessInstructionDelegate delegate) {

View File

@ -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_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_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_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),
INSTANCE_OF((short)0x20, "instance-of", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff02),
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),
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_ARRAY((short)0x23, "new-array", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff04),
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),
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),
THROW((short)0x27, "throw", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW),
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_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),
IGET((short)0x52, "iget", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff06),
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_OBJECT((short)0x54, "iget-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff08),
IGET_BOOLEAN((short)0x55, "iget-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff09),
IGET_BYTE((short)0x56, "iget-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0a),
IGET_CHAR((short)0x57, "iget-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0b),
IGET_SHORT((short)0x58, "iget-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0c),
IPUT((short)0x59, "iput", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0d),
IPUT_WIDE((short)0x5a, "iput-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0e),
IPUT_OBJECT((short)0x5b, "iput-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0f),
IPUT_BOOLEAN((short)0x5c, "iput-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff10),
IPUT_BYTE((short)0x5d, "iput-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff11),
IPUT_CHAR((short)0x5e, "iput-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff12),
IPUT_SHORT((short)0x5f, "iput-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff13),
SGET((short)0x60, "sget", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff14),
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_OBJECT((short)0x62, "sget-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff16),
SGET_BOOLEAN((short)0x63, "sget-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff17),
SGET_BYTE((short)0x64, "sget-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff18),
SGET_CHAR((short)0x65, "sget-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff19),
SGET_SHORT((short)0x66, "sget-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff1a),
SPUT((short)0x67, "sput", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1b),
SPUT_WIDE((short)0x68, "sput-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1c),
SPUT_OBJECT((short)0x69, "sput-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1d),
SPUT_BOOLEAN((short)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1e),
SPUT_BYTE((short)0x6b, "sput-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1f),
SPUT_CHAR((short)0x6c, "sput-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff20),
SPUT_SHORT((short)0x6d, "sput-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff21),
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),
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),
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),
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),
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),
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),
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),
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),
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),
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),
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),
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),
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),
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),
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_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_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_SUPER_RANGE((short)0x75, "invoke-super/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff23),
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_STATIC_RANGE((short)0x77, "invoke-static/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff25),
INVOKE_INTERFACE_RANGE((short)0x78, "invoke-interface/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff26),
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),
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),
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),
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),
@ -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),
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),
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);
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);
private static Opcode[] opcodesByValue;
private static Opcode[] expandedOpcodesByValue;
@ -426,7 +372,7 @@ public enum Opcode
* based on the idiosyncrasies of that api level
* @param apiLevel
*/
public static void updateMapsForApiLevel(int apiLevel, boolean includeJumbo) {
public static void updateMapsForApiLevel(int apiLevel) {
if (apiLevel < 5) {
removeOpcodes(THROW_VERIFICATION_ERROR);
}
@ -445,21 +391,6 @@ public enum Opcode
removeOpcodes(INVOKE_OBJECT_INIT_RANGE);
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;

View File

@ -33,6 +33,8 @@ import org.jf.dexlib.Code.*;
import org.jf.dexlib.Debug.DebugInstructionIterator;
import org.jf.dexlib.Debug.DebugOpcode;
import org.jf.dexlib.Util.*;
import org.jf.util.AlignmentUtils;
import org.jf.util.ExceptionWithContext;
import java.util.ArrayList;
import java.util.List;

View File

@ -28,8 +28,10 @@
package org.jf.dexlib;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
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.security.DigestException;
@ -39,7 +41,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.zip.Adler32;
import brut.directory.ZipExtFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* <h3>Main use cases</h3>
@ -287,13 +290,13 @@ public class DexFile
InputStream inputStream = null;
Input in = null;
ZipExtFile zipFile = null;
ZipFile zipFile = null;
try {
//do we have a zip file?
if (magic[0] == 0x50 && magic[1] == 0x4B) {
zipFile = new ZipExtFile(file);
ZipArchiveEntry zipEntry = zipFile.getEntry("classes.dex");
zipFile = new ZipFile(file);
ZipEntry zipEntry = zipFile.getEntry("classes.dex");
if (zipEntry == null) {
throw new NoClassesDexException("zip file " + file.getName() + " does not contain a classes.dex " +
"file");

View File

@ -33,7 +33,7 @@ import org.jf.dexlib.StringIdItem;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.EncodedValueUtils;
import org.jf.dexlib.Util.Input;
import org.jf.dexlib.Util.Utf8Utils;
import org.jf.util.StringUtils;
public class StringEncodedValue extends EncodedValue {
public final StringIdItem value;
@ -65,7 +65,7 @@ public class StringEncodedValue extends EncodedValue {
if (out.annotates()) {
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));

View File

@ -31,7 +31,7 @@ package org.jf.dexlib;
import com.google.common.base.Preconditions;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.Input;
import org.jf.dexlib.Util.Utf8Utils;
import org.jf.util.StringUtils;
public class HeaderItem extends Item<HeaderItem> {
/**
@ -182,7 +182,7 @@ public class HeaderItem extends Item<HeaderItem> {
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.annotate("checksum");

View File

@ -28,7 +28,7 @@
package org.jf.dexlib;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.util.ExceptionWithContext;
import org.jf.dexlib.Util.Input;
public class IndexedSection<T extends Item> extends Section<T> {

View File

@ -29,9 +29,9 @@
package org.jf.dexlib;
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.ExceptionWithContext;
import org.jf.util.ExceptionWithContext;
import org.jf.dexlib.Util.Input;
public abstract class Item<T extends Item> implements Comparable<T> {

View File

@ -28,7 +28,7 @@
package org.jf.dexlib;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.util.ExceptionWithContext;
import org.jf.dexlib.Util.SparseArray;
import java.util.List;

View File

@ -28,7 +28,7 @@
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.Input;

View File

@ -31,7 +31,8 @@ package org.jf.dexlib;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.Input;
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> {
private int hashCode = 0;
@ -103,7 +104,7 @@ public class StringDataItem extends Item<StringDataItem> {
")");
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 {
out.writeUnsignedLeb128(stringValue.length());
}
@ -118,7 +119,7 @@ public class StringDataItem extends Item<StringDataItem> {
/** {@inheritDoc} */
public String getConciseIdentity() {
return "string_data_item: \"" + Utf8Utils.escapeString(getStringValue()) + "\"";
return "string_data_item: \"" + StringUtils.escapeString(getStringValue()) + "\"";
}
/** {@inheritDoc} */

Some files were not shown because too many files have changed in this diff Show More