Refactor dexlib so that the output is generated directly, instead of using the StringTemplate library

git-svn-id: https://smali.googlecode.com/svn/trunk@681 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2010-04-03 23:01:17 +00:00
parent a7139f6586
commit 6eae34831f
51 changed files with 1836 additions and 1345 deletions

View File

@ -73,18 +73,9 @@
<directory>src/main/resources/properties</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources/templates</directory>
<filtering>false</filtering>
</resource>
</resources>
</build>
<dependencies>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>3.2</version>
</dependency>
<dependency>
<groupId>org.jf</groupId>
<artifactId>dexlib</artifactId>

View File

@ -28,21 +28,37 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.AnnotationItem;
import org.jf.baksmali.Adaptors.EncodedValue.AnnotationEncodedValueAdaptor;
import org.jf.baksmali.Adaptors.Reference.TypeReference;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import org.jf.dexlib.AnnotationSetItem;
import java.util.List;
import java.io.IOException;
public class AnnotationAdaptor {
public static StringTemplate createTemplate(StringTemplateGroup stg, AnnotationItem annotationItem) {
StringTemplate template = stg.getInstanceOf("annotation");
template.setAttribute("Visibility", annotationItem.getVisibility().name().toLowerCase());
AnnotationEncodedValueAdaptor.setAttributesForAnnotation(template, annotationItem.getEncodedAnnotation());
public class AnnotationFormatter {
return template;
public static void writeTo(IndentingPrintWriter writer, AnnotationSetItem annotationSet) throws IOException {
boolean first = true;
for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
if (!first) {
writer.println();
}
first = false;
writeTo(writer, annotationItem);
}
}
public static void writeTo(IndentingPrintWriter writer, AnnotationItem annotationItem) throws IOException {
writer.write(".annotation ");
writer.write(annotationItem.getVisibility().visibility);
writer.write(' ');
ReferenceFormatter.writeTypeReference(writer, annotationItem.getEncodedAnnotation().annotationType);
writer.println();
AnnotationEncodedValueAdaptor.writeElementsTo(writer, annotationItem.getEncodedAnnotation());
writer.println(".end annotation");
}
}

View File

@ -28,26 +28,21 @@
package org.jf.baksmali.Adaptors;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import org.jf.baksmali.IndentingPrintWriter;
//a "spacer" between instructions
public class BlankMethodItem extends MethodItem {
private static StringTemplate template;
public BlankMethodItem(StringTemplateGroup stg, int codeAddress) {
public BlankMethodItem(int codeAddress) {
super(codeAddress);
if (template == null) {
template = stg.getInstanceOf("Blank");
}
}
public double getSortOrder() {
return Integer.MAX_VALUE;
}
@Override
public String toString() {
return template.toString();
public boolean writeTo(IndentingPrintWriter writer) {
//we didn't technically print something, but returning true indicates that a newline should be printed
//after this method item, which is the intended functionality
return true;
}
}

View File

@ -28,36 +28,32 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.TypeIdItem;
import org.jf.baksmali.Adaptors.Reference.TypeReference;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
public class CatchMethodItem extends MethodItem {
private final StringTemplateGroup stg;
private final TypeIdItem exceptionType;
private final LabelMethodItem tryStartLabel;
private final LabelMethodItem tryEndLabel;
private final LabelMethodItem handlerLabel;
public CatchMethodItem(MethodDefinition.LabelCache labelCache, int codeAddress, StringTemplateGroup stg,
TypeIdItem exceptionType, int startAddress, int endAddress, int handlerAddress) {
public CatchMethodItem(MethodDefinition.LabelCache labelCache, int codeAddress, TypeIdItem exceptionType,
int startAddress, int endAddress, int handlerAddress) {
super(codeAddress);
this.stg = stg;
this.exceptionType = exceptionType;
tryStartLabel = labelCache.internLabel(new LabelMethodItem(startAddress, stg, "try_start_"));
tryStartLabel = labelCache.internLabel(new LabelMethodItem(startAddress, "try_start_"));
tryStartLabel.setUncommented();
//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, stg, endAddress));
tryEndLabel = labelCache.internLabel(new EndTryLabelMethodItem(codeAddress, endAddress));
tryEndLabel.setUncommented();
if (exceptionType == null) {
handlerLabel = labelCache.internLabel(new LabelMethodItem(handlerAddress, stg, "catchall_"));
handlerLabel = labelCache.internLabel(new LabelMethodItem(handlerAddress, "catchall_"));
} else {
handlerLabel = labelCache.internLabel(new LabelMethodItem(handlerAddress, stg, "catch_"));
handlerLabel = labelCache.internLabel(new LabelMethodItem(handlerAddress, "catch_"));
}
handlerLabel.setUncommented();
}
@ -79,19 +75,20 @@ public class CatchMethodItem extends MethodItem {
return 102;
}
protected String getTemplateName() {
return "Catch";
}
@Override
public String toString() {
StringTemplate template = stg.getInstanceOf(getTemplateName());
if (exceptionType != null) {
template.setAttribute("ExceptionType", TypeReference.createTemplate(stg, exceptionType));
public boolean writeTo(IndentingPrintWriter writer) {
if (exceptionType == null) {
writer.write(".catchall");
} else {
writer.write(".catch ");
ReferenceFormatter.writeTypeReference(writer, exceptionType);
}
template.setAttribute("StartLabel", tryStartLabel);
template.setAttribute("EndLabel", tryEndLabel);
template.setAttribute("HandlerLabel", handlerLabel);
return template.toString();
writer.write(" {");
tryStartLabel.writeTo(writer);
writer.write(" .. ");
tryEndLabel.writeTo(writer);
writer.write("} ");
handlerLabel.writeTo(writer);
return true;
}
}

View File

@ -28,6 +28,7 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.Code.Analysis.ValidationException;
import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.*;
@ -35,13 +36,11 @@ import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Format.Instruction21c;
import org.jf.dexlib.Util.AccessFlags;
import org.jf.dexlib.Util.SparseArray;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import java.util.*;
import java.io.IOException;
import java.util.List;
public class ClassDefinition {
private StringTemplateGroup stg;
private ClassDefItem classDefItem;
private ClassDataItem classDataItem;
@ -53,31 +52,13 @@ public class ClassDefinition {
protected boolean validationErrors;
public ClassDefinition(StringTemplateGroup stg, ClassDefItem classDefItem) {
this.stg = stg;
public ClassDefinition(ClassDefItem classDefItem) {
this.classDefItem = classDefItem;
this.classDataItem = classDefItem.getClassData();
buildAnnotationMaps();
findFieldsSetInStaticConstructor();
}
public StringTemplate createTemplate() {
StringTemplate template = stg.getInstanceOf("smaliFile");
template.setAttribute("AccessFlags", getAccessFlags());
template.setAttribute("ClassType", classDefItem.getClassType().getTypeDescriptor());
template.setAttribute("SuperType", getSuperType());
template.setAttribute("SourceFile", getSourceFile());
template.setAttribute("Interfaces", getInterfaces());
template.setAttribute("Annotations", getAnnotations());
template.setAttribute("StaticFields", getStaticFields());
template.setAttribute("InstanceFields", getInstanceFields());
template.setAttribute("DirectMethods", getDirectMethods());
template.setAttribute("VirtualMethods", getVirtualMethods());
return template;
}
public boolean hadValidationErrors() {
return validationErrors;
}
@ -143,149 +124,212 @@ public class ClassDefinition {
}
}
private List<String> getAccessFlags() {
List<String> accessFlags = new ArrayList<String>();
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) {
accessFlags.add(accessFlag.toString());
}
return accessFlags;
public void writeTo(IndentingPrintWriter writer) throws IOException {
writeClass(writer);
writeSuper(writer);
writeSourceFile(writer);
writeInterfaces(writer);
writeAnnotations(writer);
writeStaticFields(writer);
writeInstanceFields(writer);
writeDirectMethods(writer);
writeVirtualMethods(writer);
return ;
}
private void writeClass(IndentingPrintWriter writer) {
writer.write(".class ");
writeAccessFlags(writer);
writer.println(classDefItem.getClassType().getTypeDescriptor());
}
private String getSuperType() {
private void writeAccessFlags(IndentingPrintWriter writer) {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) {
writer.write(accessFlag.toString());
writer.write(' ');
}
}
private void writeSuper(IndentingPrintWriter writer) {
TypeIdItem superClass = classDefItem.getSuperclass();
if (superClass != null) {
return superClass.getTypeDescriptor();
writer.write(".super ");
writer.println(superClass.getTypeDescriptor());
}
return null;
}
private String getSourceFile() {
private void writeSourceFile(IndentingPrintWriter writer) {
StringIdItem sourceFile = classDefItem.getSourceFile();
if (sourceFile == null) {
return null;
if (sourceFile != null) {
writer.write(".source \"");
writer.print(sourceFile.getStringValue());
writer.println('"');
}
return classDefItem.getSourceFile().getStringValue();
}
private List<String> getInterfaces() {
List<String> interfaces = new ArrayList<String>();
private void writeInterfaces(IndentingPrintWriter writer) {
TypeListItem interfaceList = classDefItem.getInterfaces();
if (interfaceList != null) {
for (TypeIdItem typeIdItem: interfaceList.getTypes()) {
interfaces.add(typeIdItem.getTypeDescriptor());
}
if (interfaceList == null) {
return;
}
return interfaces;
List<TypeIdItem> interfaces = interfaceList.getTypes();
if (interfaces == null || interfaces.size() == 0) {
return;
}
writer.println();
writer.println("# interfaces");
for (TypeIdItem typeIdItem: interfaceList.getTypes()) {
writer.write(".implements ");
writer.println(typeIdItem.getTypeDescriptor());
}
}
private List<StringTemplate> getAnnotations() {
private void writeAnnotations(IndentingPrintWriter writer) throws IOException {
AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations();
if (annotationDirectory == null) {
return null;
return;
}
AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations();
if (annotationSet == null) {
return null;
return;
}
List<StringTemplate> annotations = new ArrayList<StringTemplate>();
for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
annotations.add(AnnotationAdaptor.createTemplate(stg, annotationItem));
}
return annotations;
writer.println();
writer.println();
writer.println("# annotations");
AnnotationFormatter.writeTo(writer, annotationSet);
}
private List<StringTemplate> getStaticFields() {
List<StringTemplate> staticFields = new ArrayList<StringTemplate>();
if (classDataItem != null) {
//if classDataItem is not null, then classDefItem won't be null either
assert(classDefItem != null);
EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers();
EncodedValue[] staticInitializers;
if (encodedStaticInitializers != null) {
staticInitializers = encodedStaticInitializers.getEncodedArray().values;
} else {
staticInitializers = new EncodedValue[0];
}
int i=0;
for (ClassDataItem.EncodedField field: classDataItem.getStaticFields()) {
EncodedValue encodedValue = null;
if (i < staticInitializers.length) {
encodedValue = staticInitializers[i];
}
AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex());
boolean setInStaticConstructor =
fieldsSetInStaticConstructor.get(field.field.getIndex()) != null;
staticFields.add(FieldDefinition.createTemplate(stg, field, encodedValue, annotationSet,
setInStaticConstructor));
i++;
}
}
return staticFields;
}
private List<StringTemplate> getInstanceFields() {
List<StringTemplate> instanceFields = new ArrayList<StringTemplate>();
if (classDataItem != null) {
for (ClassDataItem.EncodedField field: classDataItem.getInstanceFields()) {
AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex());
instanceFields.add(FieldDefinition.createTemplate(stg, field, annotationSet));
}
}
return instanceFields;
}
private List<StringTemplate> getDirectMethods() {
private void writeStaticFields(IndentingPrintWriter writer) throws IOException {
if (classDataItem == null) {
return null;
return;
}
//if classDataItem is not null, then classDefItem won't be null either
assert(classDefItem != null);
EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers();
EncodedValue[] staticInitializers;
if (encodedStaticInitializers != null) {
staticInitializers = encodedStaticInitializers.getEncodedArray().values;
} else {
staticInitializers = new EncodedValue[0];
}
return getTemplatesForMethods(classDataItem.getDirectMethods());
ClassDataItem.EncodedField[] encodedFields = classDataItem.getStaticFields();
if (encodedFields == null || encodedFields.length == 0) {
return;
}
writer.println();
writer.println();
writer.println("# static fields");
boolean first = true;
for (int i=0; i<encodedFields.length; i++) {
if (!first) {
writer.println();
}
first = false;
ClassDataItem.EncodedField field = encodedFields[i];
EncodedValue encodedValue = null;
if (i < staticInitializers.length) {
encodedValue = staticInitializers[i];
}
AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex());
boolean setInStaticConstructor =
fieldsSetInStaticConstructor.get(field.field.getIndex()) != null;
FieldDefinition.writeTo(writer, field, encodedValue, annotationSet, setInStaticConstructor);
}
}
private List<StringTemplate> getVirtualMethods() {
private void writeInstanceFields(IndentingPrintWriter writer) throws IOException {
if (classDataItem == null) {
return null;
return;
}
return getTemplatesForMethods(classDataItem.getVirtualMethods());
ClassDataItem.EncodedField[] encodedFields = classDataItem.getInstanceFields();
if (encodedFields == null || encodedFields.length == 0) {
return;
}
writer.println();
writer.println();
writer.println("# instance fields");
boolean first = true;
for (ClassDataItem.EncodedField field: classDataItem.getInstanceFields()) {
if (!first) {
writer.println();
}
first = false;
AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex());
FieldDefinition.writeTo(writer, field, null, annotationSet, false);
}
}
private List<StringTemplate> getTemplatesForMethods(ClassDataItem.EncodedMethod[] methods) {
List<StringTemplate> methodTemplates = new ArrayList<StringTemplate>();
private void writeDirectMethods(IndentingPrintWriter writer) throws IOException {
if (classDataItem == null) {
return;
}
ClassDataItem.EncodedMethod[] directMethods = classDataItem.getDirectMethods();
if (directMethods == null || directMethods.length == 0) {
return;
}
writer.println();
writer.println();
writer.println("# direct methods");
writeMethods(writer, directMethods);
}
private void writeVirtualMethods(IndentingPrintWriter writer) throws IOException {
if (classDataItem == null) {
return;
}
ClassDataItem.EncodedMethod[] virtualMethods = classDataItem.getVirtualMethods();
if (virtualMethods == null || virtualMethods.length == 0) {
return;
}
writer.println();
writer.println();
writer.println("# virtual methods");
writeMethods(writer, virtualMethods);
}
private void writeMethods(IndentingPrintWriter writer, ClassDataItem.EncodedMethod[] methods) throws IOException {
boolean first = true;
for (ClassDataItem.EncodedMethod method: methods) {
if (!first) {
writer.println();
}
first = false;
AnnotationSetItem annotationSet = methodAnnotationsMap.get(method.method.getIndex());
AnnotationSetRefList parameterAnnotationList = parameterAnnotationsMap.get(method.method.getIndex());
MethodDefinition methodDefinition = new MethodDefinition(stg, method);
MethodDefinition methodDefinition = new MethodDefinition(method);
methodDefinition.writeTo(writer, annotationSet, parameterAnnotationList);
methodTemplates.add(methodDefinition.createTemplate(annotationSet, parameterAnnotationList));
ValidationException validationException = methodDefinition.getValidationException();
if (validationException != null) {
//System.err.println(validationException.toString());
validationException.printStackTrace(System.err);
this.validationErrors = true;
}
}
return methodTemplates;
}
}

View File

@ -28,17 +28,16 @@
package org.jf.baksmali.Adaptors;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.IndentingPrintWriter;
public class CommentMethodItem extends MethodItem {
private final StringTemplate template;
//private final StringTemplate template;
private final String comment;
private final double sortOrder;
public CommentMethodItem(StringTemplateGroup stg, String comment, int codeAddress, double sortOrder) {
public CommentMethodItem(String comment, int codeAddress, double sortOrder) {
super(codeAddress);
template = stg.getInstanceOf("Comment");
template.setAttribute("Comment", comment);
this.comment = comment;
this.sortOrder = sortOrder;
}
@ -46,8 +45,9 @@ public class CommentMethodItem extends MethodItem {
return sortOrder;
}
@Override
public String toString() {
return template.toString();
public boolean writeTo(IndentingPrintWriter writer) {
writer.write('#');
writer.write(comment);
return true;
}
}

View File

@ -28,16 +28,15 @@
package org.jf.baksmali.Adaptors;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.IndentingPrintWriter;
import java.io.IOException;
public class CommentedOutMethodItem extends MethodItem {
private final StringTemplateGroup stg;
private final MethodItem commentedOutMethodItem;
public CommentedOutMethodItem(StringTemplateGroup stg, MethodItem commentedOutMethodItem) {
public CommentedOutMethodItem(MethodItem commentedOutMethodItem) {
super(commentedOutMethodItem.getCodeAddress());
this.stg = stg;
this.commentedOutMethodItem = commentedOutMethodItem;
}
@ -45,10 +44,9 @@ public class CommentedOutMethodItem extends MethodItem {
return commentedOutMethodItem.getSortOrder() + .001;
}
@Override
public String toString() {
StringTemplate template = stg.getInstanceOf("CommentedOutMethodItem");
template.setAttribute("MethodItem", commentedOutMethodItem);
return template.toString();
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
writer.write('#');
commentedOutMethodItem.writeTo(writer);
return true;
}
}

View File

@ -28,18 +28,16 @@
package org.jf.baksmali.Adaptors;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib.StringIdItem;
import org.jf.dexlib.TypeIdItem;
public class DebugMethodItem extends MethodItem {
private final StringTemplateGroup stg;
private final String templateName;
public abstract class DebugMethodItem extends MethodItem {
private final double sortOrder;
public DebugMethodItem(int codeAddress, StringTemplateGroup stg, String templateName, double sortOrder) {
public DebugMethodItem(int codeAddress, double sortOrder) {
super(codeAddress);
this.stg = stg;
this.templateName = templateName;
this.sortOrder = sortOrder;
}
@ -47,14 +45,74 @@ public class DebugMethodItem extends MethodItem {
return sortOrder;
}
@Override
public String toString() {
StringTemplate template = stg.getInstanceOf(templateName);
setAttributes(template);
return template.toString();
protected static void writeLine(IndentingPrintWriter writer, int line) {
writer.write(".line ");
writer.print(line);
}
protected void setAttributes(StringTemplate template)
{
protected static void writeEndPrologue(IndentingPrintWriter writer) {
writer.write(".prologue");
}
protected static void writeBeginEpilogue(IndentingPrintWriter writer) {
writer.write(".epilogue");
}
protected static void writeStartLocal(IndentingPrintWriter writer, CodeItem codeItem, int register,
StringIdItem name, TypeIdItem type, StringIdItem signature) {
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(IndentingPrintWriter writer, CodeItem codeItem, int register, StringIdItem name,
TypeIdItem type, StringIdItem signature) {
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(IndentingPrintWriter writer, CodeItem codeItem, int register,
StringIdItem name, TypeIdItem type, StringIdItem signature) {
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(IndentingPrintWriter writer, String fileName) {
writer.write(".source \"");
writer.write(fileName);
writer.write('"');
}
}

View File

@ -28,50 +28,34 @@
package org.jf.baksmali.Adaptors.EncodedValue;
import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.baksmali.Adaptors.ReferenceFormatter;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue;
import org.jf.dexlib.StringIdItem;
import org.jf.baksmali.Adaptors.Reference.TypeReference;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
public abstract class AnnotationEncodedValueAdaptor {
public static StringTemplate createTemplate(StringTemplateGroup stg, AnnotationEncodedSubValue encodedAnnotation) {
StringTemplate template = stg.getInstanceOf("AnnotationEncodedValue");
template.setAttribute("AnnotationType", TypeReference.createTemplate(stg, encodedAnnotation.annotationType));
template.setAttribute("Elements", getElements(stg, encodedAnnotation));
return template;
public static void writeTo(IndentingPrintWriter writer, AnnotationEncodedSubValue encodedAnnotation)
throws IOException {
writer.write(".subannotation ");
ReferenceFormatter.writeTypeReference(writer, encodedAnnotation.annotationType);
writer.println();
writeElementsTo(writer, encodedAnnotation);
writer.write(".end subannotation");
}
public static void setAttributesForAnnotation(StringTemplate template,
AnnotationEncodedSubValue encodedAnnotation) {
template.setAttribute("AnnotationType", TypeReference.createTemplate(template.getGroup(),
encodedAnnotation.annotationType));
template.setAttribute("Elements", getElements(template.getGroup(), encodedAnnotation));
}
private static List<String> getElements(StringTemplateGroup stg,
AnnotationEncodedSubValue encodedAnnotation) {
List<String> elements = new ArrayList<String>();
public static void writeElementsTo(IndentingPrintWriter writer, AnnotationEncodedSubValue encodedAnnotation)
throws IOException {
writer.indent(4);
for (int i=0; i<encodedAnnotation.names.length; i++) {
elements.add(AnnotationElementAdaptor.toString(stg, encodedAnnotation.names[i], encodedAnnotation.values[i]));
}
return elements;
}
private static class AnnotationElementAdaptor {
public static String toString(StringTemplateGroup stg, StringIdItem name, EncodedValue value) {
StringTemplate template = stg.getInstanceOf("AnnotationElement");
template.setAttribute("Name", name);
template.setAttribute("Value", EncodedValueAdaptor.create(stg, value));
return template.toString();
writer.write(encodedAnnotation.names[i].getStringValue());
writer.write(" = ");
EncodedValueAdaptor.writeTo(writer, encodedAnnotation.values[i]);
writer.println();
}
writer.deindent(4);
}
}

View File

@ -28,27 +28,34 @@
package org.jf.baksmali.Adaptors.EncodedValue;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.EncodedValue.ArrayEncodedValue;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
public class ArrayEncodedValueAdaptor {
public static StringTemplate createTemplate(StringTemplateGroup stg, ArrayEncodedValue encodedArray) {
StringTemplate template = stg.getInstanceOf("ArrayEncodedValue");
template.setAttribute("Value", getValue(stg, encodedArray));
return template;
}
private static List<StringTemplate> getValue(StringTemplateGroup stg, ArrayEncodedValue encodedArray) {
List<StringTemplate> encodedValues = new ArrayList<StringTemplate>();
for (EncodedValue encodedValue: encodedArray.values) {
encodedValues.add(EncodedValueAdaptor.create(stg, encodedValue));
public static void writeTo(IndentingPrintWriter writer, ArrayEncodedValue encodedArray) throws IOException {
writer.print('{');
EncodedValue[] values = encodedArray.values;
if (values == null || values.length == 0) {
writer.print('}');
return;
}
return encodedValues;
writer.println();
writer.indent(4);
boolean first = true;
for (EncodedValue encodedValue: encodedArray.values) {
if (!first) {
writer.println(',');
}
first = false;
EncodedValueAdaptor.writeTo(writer, encodedValue);
}
writer.deindent(4);
writer.println();
writer.print('}');
}
}

View File

@ -1,41 +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.Reference.Reference;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
public class EncodedIndexedItemAdaptor {
public static StringTemplate createTemplate(StringTemplateGroup stg, StringTemplate reference) {
StringTemplate template = stg.getInstanceOf("EncodedIndexedItemReference");
template.setAttribute("Value", reference);
return template;
}
}

View File

@ -28,52 +28,63 @@
package org.jf.baksmali.Adaptors.EncodedValue;
import org.jf.baksmali.Adaptors.ReferenceFormatter;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.baksmali.Renderers.*;
import org.jf.dexlib.EncodedValue.*;
import org.jf.baksmali.Adaptors.Reference.*;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import java.io.IOException;
public abstract class EncodedValueAdaptor {
public static StringTemplate create(StringTemplateGroup stg, EncodedValue encodedValue) {
public static void writeTo(IndentingPrintWriter writer, EncodedValue encodedValue) throws IOException {
switch (encodedValue.getValueType()) {
case VALUE_ANNOTATION:
return AnnotationEncodedValueAdaptor.createTemplate(stg, (AnnotationEncodedValue)encodedValue);
AnnotationEncodedValueAdaptor.writeTo(writer, (AnnotationEncodedValue)encodedValue);
return;
case VALUE_ARRAY:
return ArrayEncodedValueAdaptor.createTemplate(stg, (ArrayEncodedValue)encodedValue);
ArrayEncodedValueAdaptor.writeTo(writer, (ArrayEncodedValue)encodedValue);
return;
case VALUE_BOOLEAN:
return SimpleEncodedValueAdaptor.createTemplate(stg, ((BooleanEncodedValue)encodedValue).value);
BooleanRenderer.writeTo(writer, ((BooleanEncodedValue)encodedValue).value);
return;
case VALUE_BYTE:
return SimpleEncodedValueAdaptor.createTemplate(stg, ((ByteEncodedValue)encodedValue).value);
ByteRenderer.writeTo(writer, ((ByteEncodedValue)encodedValue).value);
return;
case VALUE_CHAR:
return SimpleEncodedValueAdaptor.createTemplate(stg, ((CharEncodedValue)encodedValue).value);
CharRenderer.writeTo(writer, ((CharEncodedValue)encodedValue).value);
return;
case VALUE_DOUBLE:
return SimpleEncodedValueAdaptor.createTemplate(stg, ((DoubleEncodedValue)encodedValue).value);
DoubleRenderer.writeTo(writer, ((DoubleEncodedValue)encodedValue).value);
return;
case VALUE_ENUM:
return EnumEncodedValueAdaptor.createTemplate(stg,
FieldReference.createTemplate(stg, ((EnumEncodedValue)encodedValue).value));
EnumEncodedValueAdaptor.writeTo(writer, ((EnumEncodedValue)encodedValue).value);
return;
case VALUE_FIELD:
return EncodedIndexedItemAdaptor.createTemplate(stg, FieldReference.createTemplate(stg,
((FieldEncodedValue)encodedValue).value));
ReferenceFormatter.writeFieldReference(writer, ((FieldEncodedValue)encodedValue).value);
return;
case VALUE_FLOAT:
return SimpleEncodedValueAdaptor.createTemplate(stg, ((FloatEncodedValue)encodedValue).value);
FloatRenderer.writeTo(writer, ((FloatEncodedValue)encodedValue).value);
return;
case VALUE_INT:
return SimpleEncodedValueAdaptor.createTemplate(stg, ((IntEncodedValue)encodedValue).value);
IntegerRenderer.writeTo(writer, ((IntEncodedValue)encodedValue).value);
return;
case VALUE_LONG:
return SimpleEncodedValueAdaptor.createTemplate(stg, ((LongEncodedValue)encodedValue).value);
LongRenderer.writeTo(writer, ((LongEncodedValue)encodedValue).value);
return;
case VALUE_METHOD:
return EncodedIndexedItemAdaptor.createTemplate(stg, MethodReference.createTemplate(stg,
((MethodEncodedValue)encodedValue).value));
ReferenceFormatter.writeMethodReference(writer, ((MethodEncodedValue)encodedValue).value);
return;
case VALUE_NULL:
return SimpleEncodedValueAdaptor.createTemplate(stg, "null");
writer.write("null");
return;
case VALUE_SHORT:
return SimpleEncodedValueAdaptor.createTemplate(stg, ((ShortEncodedValue)encodedValue).value);
ShortRenderer.writeTo(writer, ((ShortEncodedValue)encodedValue).value);
return;
case VALUE_STRING:
return EncodedIndexedItemAdaptor.createTemplate(stg, StringReference.createTemplate(stg,
((StringEncodedValue)encodedValue).value));
ReferenceFormatter.writeStringReference(writer, ((StringEncodedValue)encodedValue).value);
return;
case VALUE_TYPE:
return EncodedIndexedItemAdaptor.createTemplate(stg, TypeReference.createTemplate(stg,
((TypeEncodedValue)encodedValue).value));
ReferenceFormatter.writeTypeReference(writer, ((TypeEncodedValue)encodedValue).value);
}
return null;
}
}

View File

@ -28,14 +28,15 @@
package org.jf.baksmali.Adaptors.EncodedValue;
import org.jf.baksmali.Adaptors.Reference.FieldReference;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.Adaptors.ReferenceFormatter;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.FieldIdItem;
import java.io.IOException;
public class EnumEncodedValueAdaptor {
public static StringTemplate createTemplate(StringTemplateGroup stg, StringTemplate fieldReference) {
StringTemplate template = stg.getInstanceOf("EnumEncodedValue");
template.setAttribute("Value", fieldReference);
return template;
public static void writeTo(IndentingPrintWriter writer, FieldIdItem item) throws IOException {
writer.write(".enum ");
ReferenceFormatter.writeFieldReference(writer, item);
}
}

View File

@ -28,13 +28,11 @@
package org.jf.baksmali.Adaptors;
import org.antlr.stringtemplate.StringTemplateGroup;
public class EndTryLabelMethodItem extends LabelMethodItem {
private int endTryAddress;
public EndTryLabelMethodItem(int codeAddress, StringTemplateGroup stg, int endTryAddress) {
super(codeAddress, stg, "try_end_");
public EndTryLabelMethodItem(int codeAddress, int endTryAddress) {
super(codeAddress, "try_end_");
this.endTryAddress = endTryAddress;
}
@ -43,7 +41,7 @@ public class EndTryLabelMethodItem extends LabelMethodItem {
return 101;
}
public String getLabelAddress() {
return Integer.toHexString(endTryAddress);
public int getLabelAddress() {
return endTryAddress;
}
}

View File

@ -29,31 +29,22 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.Adaptors.EncodedValue.EncodedValueAdaptor;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.ClassDataItem;
import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.EncodedValue.NullEncodedValue;
import org.jf.dexlib.AnnotationSetItem;
import org.jf.dexlib.AnnotationItem;
import org.jf.dexlib.Util.AccessFlags;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
public class FieldDefinition {
public static StringTemplate createTemplate(StringTemplateGroup stg, ClassDataItem.EncodedField encodedField,
public static void writeTo(IndentingPrintWriter writer, ClassDataItem.EncodedField encodedField,
EncodedValue initialValue, AnnotationSetItem annotationSet,
boolean setInStaticConstructor) {
StringTemplate template = stg.getInstanceOf("field");
boolean setInStaticConstructor) throws IOException {
String fieldTypeDescriptor = encodedField.field.getFieldType().getTypeDescriptor();
template.setAttribute("AccessFlags", getAccessFlags(encodedField));
template.setAttribute("FieldName", encodedField.field.getFieldName().getStringValue());
template.setAttribute("FieldType", encodedField.field.getFieldType().getTypeDescriptor());
template.setAttribute("Annotations", getAnnotations(stg, annotationSet));
if (setInStaticConstructor &&
encodedField.isStatic() &&
(encodedField.accessFlags & AccessFlags.FINAL.getValue()) != 0 &&
@ -64,44 +55,33 @@ public class FieldDefinition {
initialValue != NullEncodedValue.NullValue
)) {
template.setAttribute("Comments",
new String[]{"the value of this static final field might be set in the static constructor"});
} else {
template.setAttribute("Comments", null);
writer.println("#the value of this static final field might be set in the static constructor");
}
writer.write(".field ");
writeAccessFlags(writer, encodedField);
writer.write(encodedField.field.getFieldName().getStringValue());
writer.write(':');
writer.write(encodedField.field.getFieldType().getTypeDescriptor());
if (initialValue != null) {
template.setAttribute("InitialValue", EncodedValueAdaptor.create(stg, initialValue));
writer.write(" = ");
EncodedValueAdaptor.writeTo(writer, initialValue);
}
return template;
writer.println();
if (annotationSet != null) {
writer.indent(4);
AnnotationFormatter.writeTo(writer, annotationSet);
writer.deindent(4);
writer.println(".end field");
}
}
public static StringTemplate createTemplate(StringTemplateGroup stg, ClassDataItem.EncodedField encodedField,
AnnotationSetItem annotationSet) {
return createTemplate(stg, encodedField, null, annotationSet, false);
}
private static List<String> getAccessFlags(ClassDataItem.EncodedField encodedField) {
List<String> accessFlags = new ArrayList<String>();
private static void writeAccessFlags(IndentingPrintWriter writer, ClassDataItem.EncodedField encodedField) {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForField(encodedField.accessFlags)) {
accessFlags.add(accessFlag.toString());
writer.write(accessFlag.toString());
writer.write(' ');
}
return accessFlags;
}
private static List<StringTemplate> getAnnotations(StringTemplateGroup stg, AnnotationSetItem annotationSet) {
if (annotationSet == null) {
return null;
}
List<StringTemplate> annotationAdaptors = new ArrayList<StringTemplate>();
for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
annotationAdaptors.add(AnnotationAdaptor.createTemplate(stg, annotationItem));
}
return annotationAdaptors;
}
}

View File

@ -28,40 +28,64 @@
package org.jf.baksmali.Adaptors.Format;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.IndentingPrintWriter;
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;
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayDataPseudoInstruction> {
private final boolean dead;
public ArrayDataMethodItem(CodeItem codeItem, int codeAddress, boolean dead, StringTemplateGroup stg,
public ArrayDataMethodItem(CodeItem codeItem, int codeAddress, boolean dead,
ArrayDataPseudoInstruction instruction) {
super(codeItem, codeAddress, stg, instruction);
super(codeItem, codeAddress, instruction);
this.dead = dead;
}
protected void setAttributes(StringTemplate template) {
template.setAttribute("ElementWidth", instruction.getElementWidth());
template.setAttribute("Dead", dead);
setValuesAttribute(template);
}
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
if (dead) {
writer.print("#.array-data 0x");
writer.printLongAsHex(instruction.getElementWidth());
writer.println();
private void setValuesAttribute(StringTemplate parentTemplate) {
Iterator<ArrayDataPseudoInstruction.ArrayElement> iterator = instruction.getElements();
while (iterator.hasNext()) {
ArrayDataPseudoInstruction.ArrayElement element = iterator.next();
Iterator<ArrayDataPseudoInstruction.ArrayElement> iterator = instruction.getElements();
while (iterator.hasNext()) {
ArrayDataPseudoInstruction.ArrayElement element = iterator.next();
StringTemplate template = parentTemplate.getGroup().getInstanceOf("ArrayElement");
for (int i = element.bufferIndex; i < element.bufferIndex + element.elementWidth; i++) {
template.setAttribute("Bytes", (Byte)element.buffer[i]);
writer.write("# ");
for (int i=0; i<element.elementWidth; i++) {
if (i!=0) {
writer.write(' ');
}
ByteRenderer.writeUnsignedTo(writer, element.buffer[element.bufferIndex+i]);
}
writer.println();
}
writer.print("#.end array-data");
} else {
writer.print(".array-data 0x");
writer.printLongAsHex(instruction.getElementWidth());
writer.println();
parentTemplate.setAttribute("Values", template);
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.println();
}
writer.deindent(4);
writer.print(".end array-data");
}
return true;
}
}

View File

@ -28,25 +28,23 @@
package org.jf.baksmali.Adaptors.Format;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.Adaptors.MethodItem;
import org.jf.baksmali.Adaptors.Reference.Reference;
import org.jf.baksmali.Adaptors.ReferenceFormatter;
import org.jf.baksmali.Adaptors.RegisterFormatter;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.baksmali.Renderers.LongRenderer;
import org.jf.dexlib.*;
import org.jf.dexlib.Code.*;
import org.jf.dexlib.CodeItem;
import java.util.LinkedList;
import java.io.IOException;
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
protected final CodeItem codeItem;
protected final StringTemplateGroup stg;
protected final T instruction;
public InstructionMethodItem(CodeItem codeItem, int codeAddress, StringTemplateGroup stg, T instruction) {
public InstructionMethodItem(CodeItem codeItem, int codeAddress, T instruction) {
super(codeAddress);
this.codeItem = codeItem;
this.stg = stg;
this.instruction = instruction;
}
@ -55,125 +53,255 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
return 100;
}
protected String formatRegister(int register) {
return RegisterFormatter.formatRegister(codeItem, register);
}
@Override
public String toString() {
StringTemplate template = stg.getInstanceOf(instruction.getFormat().name());
template.setAttribute("Opcode", instruction.opcode.name);
setAttributes(template);
return template.toString();
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
switch (instruction.getFormat()) {
case Format10t:
writeOpcode(writer);
writer.write(' ');
writeTargetLabel(writer);
return true;
case Format10x:
writeOpcode(writer);
return true;
case Format11n:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeLiteral(writer);
return true;
case Format11x:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
return true;
case Format12x:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeSecondRegister(writer);
return true;
case Format20t:
case Format30t:
writeOpcode(writer);
writer.write(' ');
writeTargetLabel(writer);
return true;
case Format21c:
case Format31c:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeReference(writer);
return true;
case Format21h:
case Format21s:
case Format31i:
case Format51l:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeLiteral(writer);
return true;
case Format21t:
case Format31t:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeTargetLabel(writer);
return true;
case Format22b:
case Format22s:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeSecondRegister(writer);
writer.write(", ");
writeLiteral(writer);
return true;
case Format22c:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeSecondRegister(writer);
writer.write(", ");
writeReference(writer);
return true;
case Format22cs:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeSecondRegister(writer);
writer.write(", ");
writeFieldOffset(writer);
return true;
case Format22t:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeSecondRegister(writer);
writer.write(", ");
writeTargetLabel(writer);
return true;
case Format22x:
case Format32x:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeSecondRegister(writer);
return true;
case Format23x:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
writer.write(", ");
writeSecondRegister(writer);
writer.write(", ");
writeThirdRegister(writer);
return true;
case Format35c:
case Format35s:
writeOpcode(writer);
writer.write(' ');
writeInvokeRegisters(writer);
writer.write(", ");
writeReference(writer);
return true;
case Format35ms:
writeOpcode(writer);
writer.write(' ');
writeInvokeRegisters(writer);
writer.write(", ");
writeVtableIndex(writer);
return true;
case Format3rc:
writeOpcode(writer);
writer.write(' ');
writeInvokeRangeRegisters(writer);
writer.write(", ");
writeReference(writer);
return true;
case Format3rms:
writeOpcode(writer);
writer.write(' ');
writeInvokeRangeRegisters(writer);
writer.write(", ");
writeVtableIndex(writer);
return true;
}
assert false;
return false;
}
protected void setAttributes(StringTemplate template) {
if (instruction instanceof LiteralInstruction) {
setLiteralAttributes((LiteralInstruction)instruction, template);
}
if (instruction instanceof SingleRegisterInstruction) {
setSingleRegisterAttributes((SingleRegisterInstruction)instruction, template);
}
if (instruction instanceof FiveRegisterInstruction) {
setFiveRegisterAttributes((FiveRegisterInstruction)instruction, template);
}
if (instruction instanceof RegisterRangeInstruction) {
setRegisterRangeAttributes((RegisterRangeInstruction)instruction, template);
}
if (instruction instanceof InstructionWithReference) {
setInstructionWithReferenceAttributes((InstructionWithReference)instruction, template);
}
if (instruction instanceof OdexedInvokeVirtual) {
setOdexedInvokeVirtualAttributes((OdexedInvokeVirtual)instruction, template);
}
if (instruction instanceof OdexedFieldAccess) {
setOdexedFieldAccessAttributes((OdexedFieldAccess)instruction, template);
}
protected void writeOpcode(IndentingPrintWriter writer) throws IOException {
writer.write(instruction.opcode.name);
}
private void setLiteralAttributes(LiteralInstruction instruction, StringTemplate template) {
long literal = instruction.getLiteral();
//TODO: do we really need to check and cast it to an int?
if (literal <= Integer.MAX_VALUE && literal >= Integer.MIN_VALUE) {
template.setAttribute("Literal", (int)literal);
} else {
template.setAttribute("Literal", literal);
}
protected void writeTargetLabel(IndentingPrintWriter writer) throws IOException {
//this method is overrided by OffsetInstructionMethodItem, and should only be called for the formats that
//have a target
throw new RuntimeException();
}
private void setSingleRegisterAttributes(SingleRegisterInstruction instruction, StringTemplate template) {
template.setAttribute("RegisterA", formatRegister(instruction.getRegisterA()));
if (instruction instanceof TwoRegisterInstruction) {
setTwoRegisterAttributes((TwoRegisterInstruction)instruction, template);
}
protected void writeRegister(IndentingPrintWriter writer, int registerNumber) throws IOException {
RegisterFormatter.writeTo(writer, codeItem, registerNumber);
}
private void setTwoRegisterAttributes(TwoRegisterInstruction instruction, StringTemplate template) {
template.setAttribute("RegisterB", formatRegister(instruction.getRegisterB()));
if (instruction instanceof ThreeRegisterInstruction) {
setThreeRegisterAttributes((ThreeRegisterInstruction)instruction, template);
}
protected void writeFirstRegister(IndentingPrintWriter writer) throws IOException {
writeRegister(writer, ((SingleRegisterInstruction)instruction).getRegisterA());
}
private void setThreeRegisterAttributes(ThreeRegisterInstruction instruction, StringTemplate template) {
template.setAttribute("RegisterC", formatRegister(instruction.getRegisterC()));
protected void writeSecondRegister(IndentingPrintWriter writer) throws IOException {
writeRegister(writer, ((TwoRegisterInstruction)instruction).getRegisterB());
}
private void setFiveRegisterAttributes(FiveRegisterInstruction instruction, StringTemplate template) {
switch (instruction.getRegCount()) {
protected void writeThirdRegister(IndentingPrintWriter writer) throws IOException {
writeRegister(writer, ((ThreeRegisterInstruction)instruction).getRegisterC());
}
protected void writeInvokeRegisters(IndentingPrintWriter writer) throws IOException {
FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction;
final int regCount = instruction.getRegCount();
writer.write('{');
switch (regCount) {
case 1:
template.setAttribute("Registers", formatRegister(instruction.getRegisterD()));
return;
writeRegister(writer, instruction.getRegisterD());
break;
case 2:
template.setAttribute("Registers", formatRegister(instruction.getRegisterD()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterE()));
return;
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
break;
case 3:
template.setAttribute("Registers", formatRegister(instruction.getRegisterD()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterE()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterF()));
return;
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
writer.write(", ");
writeRegister(writer, instruction.getRegisterF());
break;
case 4:
template.setAttribute("Registers", formatRegister(instruction.getRegisterD()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterE()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterF()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterG()));
return;
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:
template.setAttribute("Registers", formatRegister(instruction.getRegisterD()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterE()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterF()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterG()));
template.setAttribute("Registers", formatRegister(instruction.getRegisterA()));
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
writer.write(", ");
writeRegister(writer, instruction.getRegisterF());
writer.write(", ");
writeRegister(writer, instruction.getRegisterG());
writer.write(", ");
writeRegister(writer, instruction.getRegisterA());
break;
}
writer.write('}');
}
protected void writeInvokeRangeRegisters(IndentingPrintWriter writer) throws IOException {
RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction;
int regCount = instruction.getRegCount();
if (regCount == 0) {
writer.write("{}");
} else {
int startRegister = instruction.getStartRegister();
RegisterFormatter.writeRegisterRange(writer, codeItem, startRegister, startRegister+regCount-1);
}
}
private void setRegisterRangeAttributes(RegisterRangeInstruction instruction, StringTemplate template) {
String[] registers = RegisterFormatter.formatFormat3rcRegisters(codeItem, instruction.getStartRegister(),
instruction.getStartRegister() + instruction.getRegCount() - 1);
template.setAttribute("StartRegister", registers[0]);
template.setAttribute("LastRegister", registers[1]);
protected void writeLiteral(IndentingPrintWriter writer) throws IOException {
LongRenderer.writeSignedIntOrLongTo(writer, ((LiteralInstruction)instruction).getLiteral());
}
private void setInstructionWithReferenceAttributes(InstructionWithReference instruction, StringTemplate template) {
template.setAttribute("Reference", Reference.createReference(template.getGroup(),
instruction.getReferencedItem()));
protected void writeFieldOffset(IndentingPrintWriter writer) throws IOException {
writer.write("field@0x");
writer.printLongAsHex(((OdexedFieldAccess)instruction).getFieldOffset());
}
private void setOdexedInvokeVirtualAttributes(OdexedInvokeVirtual instruction, StringTemplate template) {
template.setAttribute("MethodIndex", instruction.getMethodIndex());
protected void writeVtableIndex(IndentingPrintWriter writer) throws IOException {
writer.write("vtable@0x");
writer.printLongAsHex(((OdexedInvokeVirtual)instruction).getMethodIndex());
}
private void setOdexedFieldAccessAttributes(OdexedFieldAccess instruction, StringTemplate template) {
template.setAttribute("FieldOffset", instruction.getFieldOffset());
protected void writeReference(IndentingPrintWriter writer) throws IOException {
Item item = ((InstructionWithReference)instruction).getReferencedItem();
ReferenceFormatter.writeReference(writer, item);
}
}

View File

@ -28,9 +28,7 @@
package org.jf.baksmali.Adaptors.Format;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.dexlib.Code.Analysis.AnalyzedInstruction;
import org.jf.dexlib.Code.Format.*;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.OffsetInstruction;
@ -43,29 +41,28 @@ public class InstructionMethodItemFactory {
public static InstructionMethodItem makeInstructionFormatMethodItem(MethodDefinition methodDefinition,
CodeItem codeItem,
int codeAddress, boolean dead,
StringTemplateGroup stg,
Instruction instruction,
boolean isLastInstruction) {
if (instruction instanceof OffsetInstruction) {
return new OffsetInstructionFormatMethodItem(methodDefinition.getLabelCache(), codeItem, codeAddress, stg,
return new OffsetInstructionFormatMethodItem(methodDefinition.getLabelCache(), codeItem, codeAddress,
instruction);
}
switch (instruction.getFormat()) {
case ArrayData:
return new ArrayDataMethodItem(codeItem, codeAddress, dead, stg,
return new ArrayDataMethodItem(codeItem, codeAddress, dead,
(ArrayDataPseudoInstruction)instruction);
case PackedSwitchData:
return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress, dead, stg,
return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress, dead,
(PackedSwitchDataPseudoInstruction)instruction);
case SparseSwitchData:
return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress, dead, stg,
return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress, dead,
(SparseSwitchDataPseudoInstruction)instruction);
case UnresolvedNullReference:
return new UnresolvedNullReferenceMethodItem(codeItem, codeAddress, stg,
return new UnresolvedNullReferenceMethodItem(codeItem, codeAddress,
(UnresolvedNullReference)instruction, isLastInstruction);
default:
return new InstructionMethodItem(codeItem, codeAddress, stg, instruction);
return new InstructionMethodItem(codeItem, codeAddress, instruction);
}
}
}

View File

@ -28,31 +28,32 @@
package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.OffsetInstruction;
import org.jf.baksmali.Adaptors.LabelMethodItem;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import java.io.IOException;
public class OffsetInstructionFormatMethodItem<T extends Instruction & OffsetInstruction>
extends InstructionMethodItem<T> {
protected LabelMethodItem label;
public OffsetInstructionFormatMethodItem(MethodDefinition.LabelCache labelCache, CodeItem codeItem, int codeAddress,
StringTemplateGroup stg, T instruction) {
super(codeItem, codeAddress, stg, instruction);
T instruction) {
super(codeItem, codeAddress, instruction);
label = new LabelMethodItem(codeAddress + instruction.getTargetAddressOffset(), stg, getLabelPrefix());
label = new LabelMethodItem(codeAddress + instruction.getTargetAddressOffset(), getLabelPrefix());
label = labelCache.internLabel(label);
label.setUncommented();
}
protected void setAttributes(StringTemplate template) {
template.setAttribute("TargetLabel", label);
super.setAttributes(template);
@Override
protected void writeTargetLabel(IndentingPrintWriter writer) throws IOException {
label.writeTo(writer);
}
public LabelMethodItem getLabel() {

View File

@ -28,13 +28,14 @@
package org.jf.baksmali.Adaptors.Format;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.baksmali.Renderers.IntegerRenderer;
import org.jf.dexlib.Code.Format.PackedSwitchDataPseudoInstruction;
import org.jf.dexlib.CodeItem;
import org.jf.baksmali.Adaptors.LabelMethodItem;
import org.jf.baksmali.Adaptors.MethodDefinition;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@ -45,8 +46,8 @@ public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDa
private final boolean dead;
public PackedSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, boolean dead,
StringTemplateGroup stg, PackedSwitchDataPseudoInstruction instruction) {
super(codeItem, codeAddress, stg, instruction);
PackedSwitchDataPseudoInstruction instruction) {
super(codeItem, codeAddress, instruction);
int baseCodeAddress = methodDefinition.getPackedSwitchBaseAddress(codeAddress);
@ -54,7 +55,7 @@ public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDa
Iterator<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> iterator = instruction.iterateKeysAndTargets();
while (iterator.hasNext()) {
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, stg, "pswitch_");
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "pswitch_");
label = methodDefinition.getLabelCache().internLabel(label);
labels.add(label);
label.setUncommented();
@ -63,10 +64,31 @@ public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDa
this.dead = dead;
}
protected void setAttributes(StringTemplate template) {
template.setAttribute("FirstKey", instruction.getFirstKey());
template.setAttribute("Targets", labels);
template.setAttribute("Dead", dead);
@Override
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
if (dead) {
writer.write("'#.packed-switch ");
IntegerRenderer.writeTo(writer, instruction.getFirstKey());
writer.println();
for (LabelMethodItem label: labels) {
writer.write("# ");
label.writeTo(writer);
writer.println();
}
writer.write("#.end packed-switch");
} else {
writer.write(".packed-switch ");
IntegerRenderer.writeTo(writer, instruction.getFirstKey());
writer.indent(4);
writer.println();
for (LabelMethodItem label: labels) {
label.writeTo(writer);
writer.println();
}
writer.deindent(4);
writer.write(".end packed-switch");
}
return true;
}
public Iterator<LabelMethodItem> iterator() {

View File

@ -28,13 +28,14 @@
package org.jf.baksmali.Adaptors.Format;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.baksmali.Renderers.IntegerRenderer;
import org.jf.dexlib.Code.Format.SparseSwitchDataPseudoInstruction;
import org.jf.dexlib.CodeItem;
import org.jf.baksmali.Adaptors.LabelMethodItem;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@ -45,8 +46,8 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
private final boolean dead;
public SparseSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, boolean dead,
StringTemplateGroup stg, SparseSwitchDataPseudoInstruction instruction) {
super(codeItem, codeAddress, stg, instruction);
SparseSwitchDataPseudoInstruction instruction) {
super(codeItem, codeAddress, instruction);
int baseCodeAddress = methodDefinition.getSparseSwitchBaseAddress(codeAddress);
@ -57,7 +58,7 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
SparseSwitchTarget sparseSwitchTarget = new SparseSwitchTarget();
sparseSwitchTarget.Key = target.key;
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, stg, "sswitch_");
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "sswitch_");
label = methodDefinition.getLabelCache().internLabel(label);
sparseSwitchTarget.Target = label;
label.setUncommented();
@ -68,9 +69,30 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
this.dead = dead;
}
protected void setAttributes(StringTemplate template) {
template.setAttribute("Targets", targets);
template.setAttribute("Dead", dead);
@Override
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
if (dead) {
writer.println("#.sparse-switch");
for (SparseSwitchTarget target: targets) {
IntegerRenderer.writeTo(writer, target.Key);
writer.write(" -> ");
target.Target.writeTo(writer);
writer.println();
}
writer.write("#.end sparse-switch");
} else {
writer.println(".sparse-switch");
writer.indent(4);
for (SparseSwitchTarget target: targets) {
IntegerRenderer.writeTo(writer, target.Key);
writer.write(" -> ");
target.Target.writeTo(writer);
writer.println();
}
writer.deindent(4);
writer.write(".end sparse-switch");
}
return true;
}
public Iterator<LabelMethodItem> iterator() {

View File

@ -28,31 +28,51 @@
package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.Code.Format.UnresolvedNullReference;
import org.jf.dexlib.CodeItem;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import java.io.IOException;
public class UnresolvedNullReferenceMethodItem extends InstructionMethodItem<UnresolvedNullReference> {
public final boolean isLastInstruction;
public UnresolvedNullReferenceMethodItem(CodeItem codeItem, int codeAddress, StringTemplateGroup stg,
UnresolvedNullReference instruction, boolean isLastInstruction) {
super(codeItem, codeAddress, stg, instruction);
public UnresolvedNullReferenceMethodItem(CodeItem codeItem, int codeAddress, UnresolvedNullReference instruction,
boolean isLastInstruction) {
super(codeItem, codeAddress, instruction);
this.isLastInstruction = isLastInstruction;
}
protected void setAttributes(StringTemplate template) {
template.setAttribute("Register", formatRegister(instruction.ObjectRegisterNum));
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
switch (instruction.OriginalInstruction.opcode)
{
case INVOKE_VIRTUAL_QUICK_RANGE:
case INVOKE_SUPER_QUICK_RANGE:
template.setAttribute("UseInvokeRange", 1);
if (isLastInstruction) {
template.setAttribute("AddGoto", 1);
}
writeInvokeRangeTo(writer);
return true;
default:
writeThrowTo(writer);
return true;
}
}
private void writeInvokeRangeTo(IndentingPrintWriter writer) throws IOException {
writer.println("#Replaced unresolvable optimized invoke-*-range-quick instruction");
writer.println("#with a generic method call that will throw a NullPointerException");
writer.write("invoke-virtual/range {");
writeRegister(writer, instruction.ObjectRegisterNum);
writer.write(" .. ");
writeRegister(writer, instruction.ObjectRegisterNum);
writer.write("}, Ljava/lang/Object;->hashCode()I");
if (isLastInstruction) {
writer.println();
writer.write("goto/32 0");
}
}
private void writeThrowTo(IndentingPrintWriter writer) throws IOException {
writer.println("#Replaced unresolvable optimized instruction with a throw");
writer.write("throw ");
writeRegister(writer, instruction.ObjectRegisterNum);
}
}

View File

@ -28,19 +28,16 @@
package org.jf.baksmali.Adaptors;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.baksmali.baksmali;
public class LabelMethodItem extends MethodItem {
private final StringTemplateGroup stg;
private final String labelPrefix;
private int labelSequence;
private boolean isCommentedOut = true;
public LabelMethodItem(int codeAddress, StringTemplateGroup stg, String labelPrefix) {
public LabelMethodItem(int codeAddress, String labelPrefix) {
super(codeAddress);
this.stg = stg;
this.labelPrefix = labelPrefix;
}
@ -79,24 +76,24 @@ public class LabelMethodItem extends MethodItem {
return this.compareTo((MethodItem)o) == 0;
}
@Override
public String toString() {
StringTemplate template = stg.getInstanceOf("Label");
template.setAttribute("Prefix", labelPrefix);
public boolean writeTo(IndentingPrintWriter writer) {
writer.write(':');
writer.write(labelPrefix);
if (baksmali.useSequentialLabels) {
template.setAttribute("Suffix", Integer.toHexString(labelSequence));
writer.printLongAsHex(labelSequence);
} else {
template.setAttribute("Suffix", getLabelAddress());
writer.printLongAsHex(this.getLabelAddress());
}
return template.toString();
return true;
}
public String getLabelPrefix() {
return labelPrefix;
}
public String getLabelAddress() {
return Integer.toHexString(this.getCodeAddress());
public int getLabelAddress() {
return this.getCodeAddress();
}
public int getLabelSequence() {

View File

@ -1,60 +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.TypeIdItem;
import org.jf.dexlib.StringIdItem;
import org.jf.dexlib.CodeItem;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
public class LocalDebugMethodItem extends DebugMethodItem {
private final String register;
private final String name;
private final String type;
private final String signature;
public LocalDebugMethodItem(CodeItem codeItem, int codeAddress, StringTemplateGroup stg, String templateName,
double sortOrder, int register, StringIdItem name, TypeIdItem type,
StringIdItem signature) {
super(codeAddress, stg, templateName, sortOrder);
this.register = RegisterFormatter.formatRegister(codeItem, register);
this.name = name==null?null:name.getStringValue();
this.type = type==null?null:type.getTypeDescriptor();
this.signature = signature==null?null:signature.getStringValue();
}
@Override
protected void setAttributes(StringTemplate template) {
template.setAttribute("Register", register);
template.setAttribute("Name", name);
template.setAttribute("Type", type);
template.setAttribute("Signature", signature);
}
}

View File

@ -29,27 +29,24 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.Adaptors.Format.*;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.baksmali.Renderers.IntegerRenderer;
import org.jf.baksmali.baksmali;
import org.jf.baksmali.main;
import org.jf.dexlib.*;
import org.jf.dexlib.Code.*;
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.Analysis.ValidationException;
import org.jf.dexlib.Code.Format.Format;
import org.jf.dexlib.Debug.DebugInstructionIterator;
import org.jf.dexlib.Util.AccessFlags;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.dexlib.Util.Hex;
import org.jf.dexlib.Util.SparseIntArray;
import java.io.IOException;
import java.util.*;
git
public class MethodDefinition {
private final StringTemplateGroup stg;
private final ClassDataItem.EncodedMethod encodedMethod;
private final MethodAnalyzer methodAnalyzer;
@ -59,13 +56,10 @@ public class MethodDefinition {
private final SparseIntArray sparseSwitchMap;
private final SparseIntArray instructionMap;
private final int registerCount;
public MethodDefinition(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod) {
public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) {
try {
this.stg = stg;
this.encodedMethod = encodedMethod;
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
@ -78,8 +72,6 @@ public class MethodDefinition {
sparseSwitchMap = new SparseIntArray(1);
instructionMap = new SparseIntArray(instructions.size());
registerCount = encodedMethod.codeItem.getRegisterCount();
int currentCodeAddress = 0;
for (int i=0; i<instructions.size(); i++) {
AnalyzedInstruction instruction = instructions.get(i);
@ -100,7 +92,6 @@ public class MethodDefinition {
sparseSwitchMap = null;
instructionMap = null;
methodAnalyzer = null;
registerCount = 0;
}
}catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, String.format("Error while processing method %s",
@ -108,24 +99,42 @@ public class MethodDefinition {
}
}
public StringTemplate createTemplate(AnnotationSetItem annotationSet,
AnnotationSetRefList parameterAnnotations) {
public void writeTo(IndentingPrintWriter writer, AnnotationSetItem annotationSet,
AnnotationSetRefList parameterAnnotations) throws IOException {
final CodeItem codeItem = encodedMethod.codeItem;
CodeItem codeItem = encodedMethod.codeItem;
writer.write(".method ");
writeAccessFlags(writer, encodedMethod);
writer.write(encodedMethod.method.getMethodName().getStringValue());
writer.println(encodedMethod.method.getPrototype().getPrototypeString());
StringTemplate template = stg.getInstanceOf("method");
writer.indent(4);
if (codeItem != null) {
if (baksmali.useLocalsDirective) {
writer.write(".locals ");
} else {
writer.write(".registers ");
}
writer.println(getRegisterCount(encodedMethod));
writeParameters(writer, codeItem, parameterAnnotations);
if (annotationSet != null) {
AnnotationFormatter.writeTo(writer, annotationSet);
}
template.setAttribute("AccessFlags", getAccessFlags(encodedMethod));
template.setAttribute("MethodName", encodedMethod.method.getMethodName().getStringValue());
template.setAttribute("Prototype", encodedMethod.method.getPrototype().getPrototypeString());
template.setAttribute("HasCode", codeItem != null);
template.setAttribute("RegistersDirective", baksmali.useLocalsDirective?".locals":".registers");
template.setAttribute("RegisterCount", codeItem==null?"0":Integer.toString(getRegisterCount(encodedMethod)));
template.setAttribute("Parameters", getParameters(stg, codeItem, parameterAnnotations));
template.setAttribute("Annotations", getAnnotations(stg, annotationSet));
template.setAttribute("MethodItems", getMethodItems());
writer.println();
return template;
for (MethodItem methodItem: getMethodItems()) {
if (methodItem.writeTo(writer)) {
writer.write('\n');
}
}
} else {
if (annotationSet != null) {
AnnotationFormatter.writeTo(writer, annotationSet);
}
}
writer.deindent(4);
writer.println(".end method");
}
private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod)
@ -141,65 +150,70 @@ public class MethodDefinition {
return totalRegisters;
}
private static List<String> getAccessFlags(ClassDataItem.EncodedMethod encodedMethod) {
List<String> accessFlags = new ArrayList<String>();
private static void writeAccessFlags(IndentingPrintWriter writer, ClassDataItem.EncodedMethod encodedMethod) {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) {
accessFlags.add(accessFlag.toString());
writer.write(accessFlag.toString());
writer.write(' ');
}
return accessFlags;
}
private static List<StringTemplate> getParameters(StringTemplateGroup stg, CodeItem codeItem,
AnnotationSetRefList parameterAnnotations) {
private static void writeParameters(IndentingPrintWriter writer, CodeItem codeItem,
AnnotationSetRefList parameterAnnotations) throws IOException {
DebugInfoItem debugInfoItem = null;
if (baksmali.outputDebugInfo && codeItem != null) {
debugInfoItem = codeItem.getDebugInfo();
}
int parameterCount = 0;
AnnotationSetItem[] annotations;
StringIdItem[] parameterNames = null;
List<AnnotationSetItem> annotations = new ArrayList<AnnotationSetItem>();
if (parameterAnnotations != null) {
AnnotationSetItem[] _annotations = parameterAnnotations.getAnnotationSets();
if (_annotations != null) {
annotations.addAll(Arrays.asList(_annotations));
}
parameterCount = annotations.size();
annotations = parameterAnnotations.getAnnotationSets();
parameterCount = annotations.length;
} else {
annotations = new AnnotationSetItem[0];
}
List<String> parameterNames = new ArrayList<String>();
if (debugInfoItem != null) {
StringIdItem[] _parameterNames = debugInfoItem.getParameterNames();
if (_parameterNames != null) {
for (StringIdItem parameterName: _parameterNames) {
parameterNames.add(parameterName==null?null:parameterName.getStringValue());
}
}
if (parameterCount < parameterNames.size()) {
parameterCount = parameterNames.size();
}
parameterNames = debugInfoItem.getParameterNames();
}
if (parameterNames == null) {
parameterNames = new StringIdItem[0];
}
if (parameterCount < parameterNames.length) {
parameterCount = parameterNames.length;
}
List<StringTemplate> parameters = new ArrayList<StringTemplate>();
for (int i=0; i<parameterCount; i++) {
AnnotationSetItem annotationSet = null;
if (i < annotations.size()) {
annotationSet = annotations.get(i);
if (i < annotations.length) {
annotationSet = annotations[i];
}
String parameterName = null;
if (i < parameterNames.size()) {
parameterName = parameterNames.get(i);
StringIdItem parameterName = null;
if (i < parameterNames.length) {
parameterName = parameterNames[i];
}
parameters.add(ParameterAdaptor.createTemplate(stg, parameterName, annotationSet));
writer.write(".parameter");
if (parameterName != null) {
writer.write('"');
writer.write(parameterName.getStringValue());
writer.write('"');
}
writer.println();
if (annotationSet != null) {
writer.indent(4);
AnnotationFormatter.writeTo(writer, annotationSet);
writer.deindent(4);
writer.println(".end parameter");
}
}
return parameters;
}
public LabelCache getLabelCache() {
@ -236,19 +250,6 @@ public class MethodDefinition {
return sparseSwitchBaseAddress;
}
private static List<StringTemplate> getAnnotations(StringTemplateGroup stg, AnnotationSetItem annotationSet) {
if (annotationSet == null) {
return null;
}
List<StringTemplate> annotationAdaptors = new ArrayList<StringTemplate>();
for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
annotationAdaptors.add(AnnotationAdaptor.createTemplate(stg, annotationItem));
}
return annotationAdaptors;
}
/**
* @param instructions The instructions array for this method
* @param instruction The instruction
@ -285,7 +286,7 @@ public class MethodDefinition {
ValidationException validationException = methodAnalyzer.getValidationException();
if (validationException != null) {
methodItems.add(new CommentMethodItem(stg,
methodItems.add(new CommentMethodItem(
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE));
} else if (baksmali.verify) {
@ -293,7 +294,7 @@ public class MethodDefinition {
validationException = methodAnalyzer.getValidationException();
if (validationException != null) {
methodItems.add(new CommentMethodItem(stg,
methodItems.add(new CommentMethodItem(
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE));
}
@ -312,9 +313,6 @@ public class MethodDefinition {
}
}
BitSet printPreRegister = new BitSet(registerCount);
BitSet printPostRegister = new BitSet(registerCount);
boolean lastIsUnreachable = false;
int currentCodeAddress = 0;
@ -322,24 +320,22 @@ public class MethodDefinition {
AnalyzedInstruction instruction = instructions.get(i);
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction.isDead(), stg, instruction.getInstruction(),
encodedMethod.codeItem, currentCodeAddress, instruction.isDead(), instruction.getInstruction(),
instruction == lastInstruction);
boolean addedInstruction = false;
if (instruction.isDead() && !instruction.getInstruction().getFormat().variableSizeFormat) {
methodItems.add(new CommentedOutMethodItem(stg, methodItem));
methodItems.add(new CommentedOutMethodItem(methodItem));
lastIsUnreachable = false;
addedInstruction = true;
} else if ( instruction.getPredecessorCount() == 0 &&
!instruction.getInstruction().getFormat().variableSizeFormat &&
!isInstructionPaddingNop(instructions, instruction)) {
if (!lastIsUnreachable) {
methodItems.add(
new CommentMethodItem(stg, "Unreachable code", currentCodeAddress, Double.MIN_VALUE));
new CommentMethodItem("Unreachable code", currentCodeAddress, Double.MIN_VALUE));
}
methodItems.add(new CommentedOutMethodItem(stg, methodItem));
methodItems.add(new CommentedOutMethodItem(methodItem));
lastIsUnreachable = true;
} else {
methodItems.add(methodItem);
@ -347,67 +343,39 @@ public class MethodDefinition {
}
if (instruction.getInstruction().getFormat() == Format.UnresolvedNullReference) {
methodItems.add(new CommentedOutMethodItem(stg,
methodItems.add(new CommentedOutMethodItem(
InstructionMethodItemFactory.makeInstructionFormatMethodItem(this, encodedMethod.codeItem,
currentCodeAddress, instruction.isDead(), stg, instruction.getOriginalInstruction(),
currentCodeAddress, instruction.isDead(), instruction.getOriginalInstruction(),
false)));
}
if (i != instructions.size() - 1) {
methodItems.add(new BlankMethodItem(stg, currentCodeAddress));
methodItems.add(new BlankMethodItem(currentCodeAddress));
}
if (baksmali.addCodeOffsets) {
methodItems.add(new CommentMethodItem(stg, String.format("@%x", currentCodeAddress),
currentCodeAddress, -1000));
methodItems.add(new MethodItem(currentCodeAddress) {
@Override
public double getSortOrder() {
return -1000;
}
@Override
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
writer.write("#@");
IntegerRenderer.writeUnsignedTo(writer, codeAddress);
return true;
}
});
}
if (baksmali.registerInfo != 0 && !instruction.getInstruction().getFormat().variableSizeFormat) {
printPreRegister.clear();
printPostRegister.clear();
methodItems.add(
new PreInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
if ((baksmali.registerInfo & main.ALL) != 0) {
printPreRegister.set(0, registerCount);
printPostRegister.set(0, registerCount);
} else {
if ((baksmali.registerInfo & main.ALLPRE) != 0) {
printPreRegister.set(0, registerCount);
} else {
if ((baksmali.registerInfo & main.ARGS) != 0) {
addArgsRegs(printPreRegister, instruction);
}
if ((baksmali.registerInfo & main.MERGE) != 0) {
addMergeRegs(printPreRegister, instruction);
} else if ((baksmali.registerInfo & main.FULLMERGE) != 0 &&
(i == 0 || instruction.isBeginningInstruction())) {
addParamRegs(printPreRegister);
}
}
if ((baksmali.registerInfo & main.ALLPOST) != 0) {
printPostRegister.set(0, registerCount);
} else if ((baksmali.registerInfo & main.DEST) != 0) {
addDestRegs(printPostRegister, instruction);
}
}
if ((baksmali.registerInfo & main.FULLMERGE) != 0) {
addFullMergeRegs(printPreRegister, methodItems, methodAnalyzer, instruction, currentCodeAddress);
}
if (!printPreRegister.isEmpty()) {
String comment = getPreInstructionRegisterString(instruction, printPreRegister);
if (comment != null && comment.length() > 0) {
methodItems.add(new CommentMethodItem(stg, comment, currentCodeAddress, 99.9));
}
}
if (!printPostRegister.isEmpty()) {
String comment = getPostInstructionRegisterString(instruction, printPostRegister);
if (comment != null && comment.length() > 0) {
methodItems.add(new CommentMethodItem(stg, comment, currentCodeAddress, 100.1));
}
}
methodItems.add(
new PostInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
}
currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress);
@ -423,7 +391,7 @@ public class MethodDefinition {
for (LabelMethodItem labelMethodItem: labelCache.getLabels()) {
if (labelMethodItem.isCommentedOut()) {
methodItems.add(new CommentedOutMethodItem(stg, labelMethodItem));
methodItems.add(new CommentedOutMethodItem(labelMethodItem));
} else {
methodItems.add(labelMethodItem);
}
@ -434,188 +402,6 @@ public class MethodDefinition {
return methodItems;
}
private void addArgsRegs(BitSet printPreRegister, AnalyzedInstruction analyzedInstruction) {
if (analyzedInstruction.getInstruction() instanceof RegisterRangeInstruction) {
RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction();
printPreRegister.set(instruction.getStartRegister(),
instruction.getStartRegister() + instruction.getRegCount());
} else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) {
FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction();
int regCount = instruction.getRegCount();
switch (regCount) {
case 5:
printPreRegister.set(instruction.getRegisterA());
//fall through
case 4:
printPreRegister.set(instruction.getRegisterG());
//fall through
case 3:
printPreRegister.set(instruction.getRegisterF());
//fall through
case 2:
printPreRegister.set(instruction.getRegisterE());
//fall through
case 1:
printPreRegister.set(instruction.getRegisterD());
}
} else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction();
printPreRegister.set(instruction.getRegisterA());
printPreRegister.set(instruction.getRegisterB());
printPreRegister.set(instruction.getRegisterC());
} else if (analyzedInstruction.getInstruction() instanceof TwoRegisterInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction();
printPreRegister.set(instruction.getRegisterA());
printPreRegister.set(instruction.getRegisterB());
} else if (analyzedInstruction.getInstruction() instanceof SingleRegisterInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.getInstruction();
printPreRegister.set(instruction.getRegisterA());
}
}
private void addFullMergeRegs(BitSet printPreRegister, List<MethodItem> methodItems, MethodAnalyzer methodAnalyzer,
AnalyzedInstruction instruction, int currentCodeAddress) {
if (instruction.getPredecessorCount() <= 1) {
return;
}
StringBuffer sb = new StringBuffer();
for (int registerNum=0; registerNum<registerCount; registerNum++) {
sb.setLength(0);
sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem, registerNum));
sb.append('=');
sb.append(instruction.getPreInstructionRegisterType(registerNum));
sb.append(":merge{");
RegisterType mergedRegisterType = null;
boolean addRegister = false;
boolean first = true;
for (AnalyzedInstruction predecessor: instruction.getPredecessors()) {
RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
if (!first) {
if (!addRegister) {
sb.append(',');
if (mergedRegisterType != predecessorRegisterType) {
addRegister = true;
}
mergedRegisterType = mergedRegisterType.merge(predecessorRegisterType);
}
} else {
mergedRegisterType = predecessorRegisterType;
}
if (predecessor.getInstructionIndex() == -1) {
//the fake "StartOfMethod" instruction
sb.append("Start:");
} else {
sb.append("0x");
sb.append(Integer.toHexString(methodAnalyzer.getInstructionAddress(predecessor)));
sb.append(':');
}
sb.append(predecessorRegisterType.toString());
first = false;
}
if (!addRegister) {
continue;
}
sb.append("}");
methodItems.add(new CommentMethodItem(stg, sb.toString(), currentCodeAddress, 99.8));
printPreRegister.clear(registerNum);
}
}
private void addMergeRegs(BitSet printPreRegister, AnalyzedInstruction instruction) {
if (instruction.isBeginningInstruction()) {
addParamRegs(printPreRegister);
}
if (instruction.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
//post-instruction registers
return;
}
for (int registerNum=0; registerNum<registerCount; registerNum++) {
RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum);
for (AnalyzedInstruction predecessor: instruction.getPredecessors()) {
if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) {
printPreRegister.set(registerNum);
continue;
}
}
}
}
private void addParamRegs(BitSet printPreRegister) {
int registerCount = encodedMethod.codeItem.getRegisterCount();
int parameterRegisterCount = encodedMethod.method.getPrototype().getParameterRegisterCount();
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
parameterRegisterCount++;
}
printPreRegister.set(registerCount-parameterRegisterCount, registerCount);
}
private void addDestRegs(BitSet printPostRegister, AnalyzedInstruction analyzedInstruction) {
for (int registerNum=0; registerNum<registerCount; registerNum++) {
if (analyzedInstruction.getPreInstructionRegisterType(registerNum) !=
analyzedInstruction.getPostInstructionRegisterType(registerNum)) {
printPostRegister.set(registerNum);
}
}
}
private String getPreInstructionRegisterString(AnalyzedInstruction instruction, BitSet registers) {
StringBuilder sb = new StringBuilder();
for (int registerNum = registers.nextSetBit(0); registerNum >= 0;
registerNum = registers.nextSetBit(registerNum + 1)) {
RegisterType registerType = instruction.getPreInstructionRegisterType(registerNum);
sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem,registerNum));
sb.append("=");
if (registerType == null) {
sb.append("null");
} else {
sb.append(registerType.toString());
}
sb.append(";");
}
return sb.toString();
}
private String getPostInstructionRegisterString(AnalyzedInstruction instruction, BitSet registers) {
StringBuilder sb = new StringBuilder();
for (int registerNum = registers.nextSetBit(0); registerNum >= 0;
registerNum = registers.nextSetBit(registerNum + 1)) {
RegisterType registerType = instruction.getPostInstructionRegisterType(registerNum);
sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem,registerNum));
sb.append("=");
if (registerType == null) {
sb.append("null");
} else {
sb.append(registerType.toString());
}
sb.append(";");
}
return sb.toString();
}
private void addTries(List<MethodItem> methodItems) {
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) {
return;
@ -667,7 +453,7 @@ public class MethodDefinition {
//add the catch all handler if it exists
int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
if (catchAllAddress != -1) {
CatchMethodItem catchAllMethodItem = new CatchMethodItem(labelCache, lastInstructionAddress, stg, null,
CatchMethodItem catchAllMethodItem = new CatchMethodItem(labelCache, lastInstructionAddress, null,
startAddress, endAddress, catchAllAddress);
methodItems.add(catchAllMethodItem);
}
@ -675,7 +461,7 @@ public class MethodDefinition {
//add the rest of the handlers
for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
//use the address from the last covered instruction
CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastInstructionAddress, stg,
CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastInstructionAddress,
handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress());
methodItems.add(catchMethodItem);
}
@ -693,61 +479,97 @@ public class MethodDefinition {
DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(),
new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() {
@Override
public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
TypeIdItem type) {
methodItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal",
-1, registerNum, name, type, null));
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(IndentingPrintWriter writer) throws IOException {
writeStartLocal(writer, codeItem, registerNum, name, type, null);
return true;
}
});
}
@Override
public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum,
StringIdItem name, TypeIdItem type,
StringIdItem signature) {
methodItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal",
-1, registerNum, name, type, signature));
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(IndentingPrintWriter writer) throws IOException {
writeStartLocal(writer, codeItem, registerNum, name, type, signature);
return true;
}
});
}
@Override
public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name,
TypeIdItem type, StringIdItem signature) {
methodItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "EndLocal", -1,
registerNum, name, type, signature));
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(IndentingPrintWriter writer) throws IOException {
writeEndLocal(writer, codeItem, registerNum, name, type, signature);
return true;
}
});
}
@Override
public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
TypeIdItem type, StringIdItem signature) {
methodItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "RestartLocal", -1,
registerNum, name, type, signature));
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(IndentingPrintWriter writer) throws IOException {
writeRestartLocal(writer, codeItem, registerNum, name, type, signature);
return true;
}
});
}
@Override
public void ProcessSetPrologueEnd(int codeAddress) {
methodItems.add(new DebugMethodItem(codeAddress, stg, "EndPrologue", -4));
methodItems.add(new DebugMethodItem(codeAddress, -4) {
@Override
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
writeEndPrologue(writer);
return true;
}
});
}
@Override
public void ProcessSetEpilogueBegin(int codeAddress) {
methodItems.add(new DebugMethodItem(codeAddress, stg, "StartEpilogue", -4));
methodItems.add(new DebugMethodItem(codeAddress, -4) {
@Override
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
writeBeginEpilogue(writer);
return true;
}
});
}
@Override
public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) {
methodItems.add(new DebugMethodItem(codeAddress, stg, "SetFile", -3) {
methodItems.add(new DebugMethodItem(codeAddress, -3) {
@Override
protected void setAttributes(StringTemplate template) {
template.setAttribute("FileName", name.getStringValue());
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
writeSetFile(writer, name.getStringValue());
return true;
}
});
}
@Override
public void ProcessLineEmit(int codeAddress, final int line) {
methodItems.add(new DebugMethodItem(codeAddress, stg, "Line", -2) {
@Override
protected void setAttributes(StringTemplate template) {
template.setAttribute("Line", line);
}
methodItems.add(new DebugMethodItem(codeAddress, -2) {
@Override
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
writeLine(writer, line);
return true;
}
});
}
});

View File

@ -28,6 +28,10 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.IndentingPrintWriter;
import java.io.IOException;
public abstract class MethodItem implements Comparable<MethodItem> {
protected final int codeAddress;
@ -50,4 +54,6 @@ public abstract class MethodItem implements Comparable<MethodItem> {
}
return result;
}
public abstract boolean writeTo(IndentingPrintWriter writer) throws IOException;
}

View File

@ -1,61 +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.AnnotationSetItem;
import org.jf.dexlib.AnnotationItem;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import java.util.List;
import java.util.ArrayList;
public class ParameterAdaptor {
public static StringTemplate createTemplate(StringTemplateGroup stg, String parameterName,
AnnotationSetItem parameterAnnotations) {
StringTemplate template = stg.getInstanceOf("Parameter");
template.setAttribute("ParameterName", parameterName);
template.setAttribute("Annotations", getAnnotations(stg, parameterAnnotations));
return template;
}
private static List<StringTemplate> getAnnotations(StringTemplateGroup stg,
AnnotationSetItem parameterAnnotations) {
if (parameterAnnotations == null) {
return null;
}
List<StringTemplate> annotations = new ArrayList<StringTemplate>();
for (AnnotationItem annotationItem: parameterAnnotations.getAnnotations()) {
annotations.add(AnnotationAdaptor.createTemplate(stg, annotationItem));
}
return annotations;
}
}

View File

@ -0,0 +1,111 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver
* 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.baksmali.IndentingPrintWriter;
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 java.io.IOException;
import java.util.BitSet;
public class PostInstructionRegisterInfoMethodItem extends MethodItem {
private final AnalyzedInstruction analyzedInstruction;
private final MethodAnalyzer methodAnalyzer;
public PostInstructionRegisterInfoMethodItem(AnalyzedInstruction analyzedInstruction, MethodAnalyzer methodAnalyzer,
int codeAddress) {
super(codeAddress);
this.analyzedInstruction = analyzedInstruction;
this.methodAnalyzer = methodAnalyzer;
}
@Override
public double getSortOrder() {
return 100.1;
}
@Override
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
int registerInfo = baksmali.registerInfo;
int registerCount = analyzedInstruction.getRegisterCount();
BitSet registers = new BitSet(registerCount);
if ((registerInfo & main.ALL) != 0) {
registers.set(0, registerCount);
} else {
if ((registerInfo & main.ALLPOST) != 0) {
registers.set(0, registerCount);
} else if ((registerInfo & main.DEST) != 0) {
addDestRegs(registers, registerCount);
}
}
return writeRegisterInfo(writer, registers);
}
private void addDestRegs(BitSet printPostRegister, int registerCount) {
for (int registerNum=0; registerNum<registerCount; registerNum++) {
if (analyzedInstruction.getPreInstructionRegisterType(registerNum) !=
analyzedInstruction.getPostInstructionRegisterType(registerNum)) {
printPostRegister.set(registerNum);
}
}
}
private boolean writeRegisterInfo(IndentingPrintWriter writer, BitSet registers) throws IOException {
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
int registerNum = registers.nextSetBit(0);
if (registerNum < 0) {
return false;
}
writer.write('#');
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum);
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
writer.write('=');
if (registerType == null) {
writer.write("null");
} else {
registerType.writeTo(writer);
}
writer.write(';');
}
return true;
}
}

View File

@ -0,0 +1,265 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver
* 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.baksmali.IndentingPrintWriter;
import org.jf.baksmali.baksmali;
import org.jf.baksmali.main;
import org.jf.dexlib.ClassDataItem;
import org.jf.dexlib.Code.*;
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.Util.AccessFlags;
import java.io.IOException;
import java.util.BitSet;
public class PreInstructionRegisterInfoMethodItem extends MethodItem {
private final AnalyzedInstruction analyzedInstruction;
private final MethodAnalyzer methodAnalyzer;
public PreInstructionRegisterInfoMethodItem(AnalyzedInstruction analyzedInstruction, MethodAnalyzer methodAnalyzer,
int codeAddress) {
super(codeAddress);
this.analyzedInstruction = analyzedInstruction;
this.methodAnalyzer = methodAnalyzer;
}
@Override
public double getSortOrder() {
return 99.9;
}
@Override
public boolean writeTo(IndentingPrintWriter writer) throws IOException {
int registerInfo = baksmali.registerInfo;
int registerCount = analyzedInstruction.getRegisterCount();
BitSet registers = new BitSet(registerCount);
if ((registerInfo & main.ALL) != 0) {
registers.set(0, registerCount);
} else {
if ((registerInfo & main.ALLPRE) != 0) {
registers.set(0, registerCount);
} else {
if ((registerInfo & main.ARGS) != 0) {
addArgsRegs(registers);
}
if ((registerInfo & main.MERGE) != 0) {
addMergeRegs(registers, registerCount);
} else if ((registerInfo & main.FULLMERGE) != 0 &&
(analyzedInstruction.isBeginningInstruction())) {
addParamRegs(registers, registerCount);
}
}
}
boolean printedSomething = false;
if ((registerInfo & main.FULLMERGE) != 0) {
printedSomething = writeFullMergeRegs(writer, registers, registerCount);
}
printedSomething |= writeRegisterInfo(writer, registers, printedSomething);
return printedSomething;
}
private void addArgsRegs(BitSet registers) {
if (analyzedInstruction.getInstruction() instanceof RegisterRangeInstruction) {
RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getStartRegister(),
instruction.getStartRegister() + instruction.getRegCount());
} else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) {
FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction();
int regCount = instruction.getRegCount();
switch (regCount) {
case 5:
registers.set(instruction.getRegisterA());
//fall through
case 4:
registers.set(instruction.getRegisterG());
//fall through
case 3:
registers.set(instruction.getRegisterF());
//fall through
case 2:
registers.set(instruction.getRegisterE());
//fall through
case 1:
registers.set(instruction.getRegisterD());
}
} else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getRegisterA());
registers.set(instruction.getRegisterB());
registers.set(instruction.getRegisterC());
} else if (analyzedInstruction.getInstruction() instanceof TwoRegisterInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getRegisterA());
registers.set(instruction.getRegisterB());
} else if (analyzedInstruction.getInstruction() instanceof SingleRegisterInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getRegisterA());
}
}
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
//post-instruction registers
return;
}
for (int registerNum=0; registerNum<registerCount; registerNum++) {
RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
if (predecessor.getPostInstructionRegisterType(registerNum) != 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++;
}
registers.set(registerCount-parameterRegisterCount, registerCount);
}
private boolean writeFullMergeRegs(IndentingPrintWriter writer, BitSet registers, int registerCount)
throws IOException {
if (analyzedInstruction.getPredecessorCount() <= 1) {
return false;
}
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
boolean firstRegister = true;
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 (!addRegister) {
continue;
}
if (firstRegister) {
firstRegister = false;
} else {
writer.println();
}
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.printLongAsHex(methodAnalyzer.getInstructionAddress(predecessor));
writer.write(':');
}
predecessorRegisterType.writeTo(writer);
first = false;
}
writer.write('}');
registers.clear(registerNum);
}
return !firstRegister;
}
private boolean writeRegisterInfo(IndentingPrintWriter writer, BitSet registers,
boolean addNewline) throws IOException {
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
int registerNum = registers.nextSetBit(0);
if (registerNum < 0) {
return false;
}
if (addNewline) {
writer.println();
}
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");
} else {
registerType.writeTo(writer);
}
writer.write(';');
}
return true;
}
}

View File

@ -1,43 +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.Reference;
import org.jf.dexlib.MethodIdItem;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
public class MethodReference {
public static StringTemplate createTemplate(StringTemplateGroup stg, MethodIdItem item) {
StringTemplate template = stg.getInstanceOf("MethodReference");
template.setAttribute("ContainingClass", item.getContainingClass().getTypeDescriptor());
template.setAttribute("MethodName", item.getMethodName().getStringValue());
template.setAttribute("Prototype", item.getPrototype().getPrototypeString());
return template;
}
}

View File

@ -1,49 +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.Reference;
import org.jf.dexlib.*;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
public abstract class Reference {
public static StringTemplate createReference(StringTemplateGroup stg, Item item) {
switch (item.getItemType()) {
case TYPE_METHOD_ID_ITEM:
return MethodReference.createTemplate(stg, (MethodIdItem)item);
case TYPE_FIELD_ID_ITEM:
return FieldReference.createTemplate(stg, (FieldIdItem)item);
case TYPE_STRING_ID_ITEM:
return StringReference.createTemplate(stg, (StringIdItem)item);
case TYPE_TYPE_ID_ITEM:
return TypeReference.createTemplate(stg, (TypeIdItem)item);
}
return null;
}
}

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.Reference;
import org.jf.dexlib.StringIdItem;
import org.jf.dexlib.Util.Utf8Utils;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
public class StringReference {
public static StringTemplate createTemplate(StringTemplateGroup stg, StringIdItem item) {
StringTemplate template = stg.getInstanceOf("StringReference");
template.setAttribute("EscapedValue", Utf8Utils.escapeString(item.getStringValue()));
return template;
}
}

View File

@ -1,41 +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.Reference;
import org.jf.dexlib.TypeIdItem;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
public class TypeReference {
public static StringTemplate createTemplate(StringTemplateGroup stg, TypeIdItem item) {
StringTemplate template = stg.getInstanceOf("TypeReference");
template.setAttribute("TypeDescriptor", item.getTypeDescriptor());
return template;
}
}

View File

@ -0,0 +1,79 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver
* 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.baksmali.IndentingPrintWriter;
import org.jf.dexlib.*;
import org.jf.dexlib.Util.Utf8Utils;
import java.io.IOException;
public class ReferenceFormatter {
public static void writeReference(IndentingPrintWriter writer, Item item) throws IOException {
switch (item.getItemType()) {
case TYPE_METHOD_ID_ITEM:
writeMethodReference(writer, (MethodIdItem)item);
return;
case TYPE_FIELD_ID_ITEM:
writeFieldReference(writer, (FieldIdItem)item);
return;
case TYPE_STRING_ID_ITEM:
writeStringReference(writer, (StringIdItem)item);
return;
case TYPE_TYPE_ID_ITEM:
writeTypeReference(writer, (TypeIdItem)item);
return;
}
}
public static void writeMethodReference(IndentingPrintWriter writer, MethodIdItem item) {
writer.write(item.getContainingClass().getTypeDescriptor());
writer.write("->");
writer.write(item.getMethodName().getStringValue());
writer.write(item.getPrototype().getPrototypeString());
}
public static void writeFieldReference(IndentingPrintWriter writer, FieldIdItem item) {
writer.write(item.getContainingClass().getTypeDescriptor());
writer.write("->");
writer.write(item.getFieldName().getStringValue());
writer.write(':');
writer.write(item.getFieldType().getTypeDescriptor());
}
public static void writeStringReference(IndentingPrintWriter writer, StringIdItem item) throws IOException {
writer.write('"');
Utf8Utils.writeEscapedString(writer, item.getStringValue());
writer.write('"');
}
public static void writeTypeReference(IndentingPrintWriter writer, TypeIdItem item) {
writer.write(item.getTypeDescriptor());
}
}

View File

@ -28,6 +28,7 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib.Util.AccessFlags;
import org.jf.baksmali.baksmali;
@ -38,15 +39,19 @@ import org.jf.baksmali.baksmali;
public class RegisterFormatter {
/**
* This method is used (only) by format 3rc (the format that uses a range of regsiters like {v1 .. v10}) to format
* it's registers. If both registers are parameter registers, they will be formatted as such, otherwise they will
* both be formatted as normal registers
* @param codeItem
* @param startRegister
* @param lastRegister
* @return an array of 2 strings containing the formatted registers
* Write out the register range value used by Format3rc. If baksmali.noParameterRegisters is true, it will always
* output the registers in the v<n> format. But if false, then it will check if *both* registers are parameter
* 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>IndentingPrintWriter</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 String[] formatFormat3rcRegisters(CodeItem codeItem, int startRegister, int lastRegister) {
public static void writeRegisterRange(IndentingPrintWriter writer, CodeItem codeItem, int startRegister,
int lastRegister) {
assert lastRegister >= startRegister;
if (!baksmali.noParameterRegisters) {
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
@ -55,32 +60,42 @@ public class RegisterFormatter {
assert startRegister <= lastRegister;
if (startRegister >= registerCount - parameterRegisterCount) {
return new String[] {"p" + (startRegister - (registerCount - parameterRegisterCount)),
"p" + (lastRegister - (registerCount - parameterRegisterCount))};
writer.write("{p");
writer.print(startRegister - (registerCount - parameterRegisterCount));
writer.write(" .. p");
writer.print(lastRegister - (registerCount - parameterRegisterCount));
writer.write('}');
return;
}
}
return new String[] {"v" + startRegister,
"v" + lastRegister};
writer.write("{v");
writer.print(startRegister);
writer.write(" .. v");
writer.print(lastRegister);
writer.write('}');
}
/**
* Formats a register with the appropriate format - with either the normal v<n> format or the p<n> parameter format.
* Writes a register with the appropriate format. If baksmali.noParameterRegisters is true, then it will always
* output a register in the v<n> format. If false, then it determines if the register is a parameter register,
* and if so, formats it in the p<n> format instead.
*
* It uses the register and parameter information from the give <code>CodeItem</code> to determine if the given
* register is a normal or parameter register.
* @param codeItem
* @param register
* @return The formatted register
* @param writer the <code>IndentingPrintWriter</code> to write to
* @param codeItem the <code>CodeItem</code> that the register is from
* @param register the register number
*/
public static String formatRegister(CodeItem codeItem, int register) {
public static void writeTo(IndentingPrintWriter writer, CodeItem codeItem, int register) {
if (!baksmali.noParameterRegisters) {
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
int registerCount = codeItem.getRegisterCount();
if (register >= registerCount - parameterRegisterCount) {
return "p" + (register - (registerCount - parameterRegisterCount));
writer.write('p');
writer.print((register - (registerCount - parameterRegisterCount)));
return;
}
}
return "v" + register;
writer.write('v');
writer.print(register);
}
}

View File

@ -1,6 +1,6 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver (JesusFreke)
* Copyright (c) 2010 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -26,18 +26,48 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Reference;
package org.jf.baksmali;
import org.jf.dexlib.FieldIdItem;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import java.io.PrintWriter;
public class FieldReference {
public static StringTemplate createTemplate(StringTemplateGroup stg, FieldIdItem item) {
StringTemplate template = stg.getInstanceOf("FieldReference");
template.setAttribute("ContainingClass", item.getContainingClass().getTypeDescriptor());
template.setAttribute("FieldName", item.getFieldName().getStringValue());
template.setAttribute("FieldType", item.getFieldType().getTypeDescriptor());
return template;
public class IndentingPrintWriter extends PrintWriter {
private IndentingWriter writer;
private final char[] buffer = new char[16];
public IndentingPrintWriter(IndentingWriter writer) {
super(writer);
this.writer = writer;
}
public IndentingPrintWriter(IndentingWriter writer, boolean autoFlush) {
super(writer, autoFlush);
}
public void indent(int indentAmount) {
writer.indent(indentAmount);
}
public void deindent(int indentAmount) {
writer.deindent(indentAmount);
}
public void printLongAsHex(long l) {
//synchronized(lock) {
int i=0;
do {
int digit = (int)(l & 15);
if (digit < 10) {
buffer[i++] = (char)(digit + '0');
} else {
buffer[i++] = (char)((digit - 10) + 'a');
}
l >>>= 4;
} while (l != 0);
while (i>0) {
write(buffer[--i]);
}
//}
}
}

View File

@ -0,0 +1,148 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver
* 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;
import java.io.IOException;
import java.io.Writer;
public class IndentingWriter extends Writer {
private final Writer writer;
private int indentLevel = 0;
private boolean beginningOfLine;
protected IndentingWriter(Writer writer) {
this.writer = writer;
}
@Override
public void write(int chr) throws IOException {
//synchronized(lock) {
if (chr == '\n') {
writer.write(chr);
beginningOfLine = true;
} else {
if (beginningOfLine) {
for (int i=0; i<indentLevel; i++) {
writer.write(' ');
}
}
beginningOfLine = false;
writer.write(chr);
}
//}
}
@Override
public void write(char[] chars) throws IOException {
//synchronized(lock) {
for (char chr: chars) {
write(chr);
}
//}
}
@Override
public void write(char[] chars, int start, int len) throws IOException {
//synchronized(lock) {
len = start+len;
while (start < len) {
write(chars[start++]);
}
//}
}
@Override
public void write(String s) throws IOException {
//synchronized (lock) {
for (int i=0; i<s.length(); i++) {
write(s.charAt(i));
}
//}
}
@Override
public void write(String str, int start, int len) throws IOException {
//synchronized(lock) {
len = start+len;
while (start < len) {
write(str.charAt(start++));
}
//}
}
@Override
public Writer append(CharSequence charSequence) throws IOException {
write(charSequence.toString());
return this;
}
@Override
public Writer append(CharSequence charSequence, int start, int len) throws IOException {
write(charSequence.subSequence(start, len).toString());
return this;
}
@Override
public Writer append(char c) throws IOException {
write(c);
return this;
}
@Override
public void flush() throws IOException {
//synchronized(lock) {
writer.flush();
//}
}
@Override
public void close() throws IOException {
//synchronized(lock) {
writer.close();
//}
}
public void indent(int indentAmount) {
//synchronized(lock) {
this.indentLevel += indentAmount;
if (indentLevel < 0) {
indentLevel = 0;
}
//}
}
public void deindent(int indentAmount) {
//synchronized(lock) {
this.indentLevel -= indentAmount;
if (indentLevel < 0) {
indentLevel = 0;
}
//}
}
}

View File

@ -1,6 +1,6 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver (JesusFreke)
* Copyright (c) 2010 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -28,15 +28,14 @@
package org.jf.baksmali.Renderers;
import org.antlr.stringtemplate.AttributeRenderer;
import org.jf.dexlib.StringIdItem;
import org.jf.baksmali.IndentingPrintWriter;
public class StringIdItemRenderer implements AttributeRenderer {
public String toString(Object o) {
return ((StringIdItem)o).getStringValue();
}
public String toString(Object o, String s) {
return toString(o);
public class BooleanRenderer {
public static void writeTo(IndentingPrintWriter writer, boolean val) {
if (val) {
writer.write("true");
} else {
writer.write("false");
}
}
}

View File

@ -28,22 +28,24 @@
package org.jf.baksmali.Renderers;
import org.antlr.stringtemplate.AttributeRenderer;
import org.jf.baksmali.IndentingPrintWriter;
public class ByteRenderer implements AttributeRenderer {
public String toString(Object o) {
Byte b = (Byte)o;
if (b < 0) {
return "-0x" + Integer.toHexString(-1 * b) + "t";
public class ByteRenderer {
public static void writeTo(IndentingPrintWriter writer, byte val) {
if (val<0) {
writer.write("-0x");
writer.printLongAsHex(-val);
writer.write('t');
} else {
writer.write("0x");
writer.printLongAsHex(val);
writer.write('t');
}
return "0x" + Integer.toHexString(b) + "t";
}
public String toString(Object o, String s) {
if (s.equals("unsigned")) {
Byte b = (Byte)o;
return "0x" + Integer.toHexString(b & 0xFF) + "t";
}
return toString(o);
public static void writeUnsignedTo(IndentingPrintWriter writer, byte val) {
writer.write("0x");
writer.printLongAsHex(val & 0xFF);
writer.write('t');
}
}

View File

@ -28,15 +28,15 @@
package org.jf.baksmali.Renderers;
import org.antlr.stringtemplate.AttributeRenderer;
import org.jf.baksmali.IndentingPrintWriter;
import org.jf.dexlib.Util.Utf8Utils;
public class CharRenderer implements AttributeRenderer {
public String toString(Object o) {
return "'" + Utf8Utils.escapeString(o.toString()) + "'";
}
import java.io.IOException;
public String toString(Object o, String s) {
return toString(o);
public class CharRenderer {
public static void writeTo(IndentingPrintWriter writer, char val) throws IOException {
writer.write('\'');
Utf8Utils.writeEscapedChar(writer, val);
writer.write('\'');
}
}

View File

@ -1,6 +1,6 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver (JesusFreke)
* Copyright (c) 2010 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -26,15 +26,12 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.EncodedValue;
package org.jf.baksmali.Renderers;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
import org.jf.baksmali.IndentingPrintWriter;
public class SimpleEncodedValueAdaptor {
public static StringTemplate createTemplate(StringTemplateGroup stg, Object value) {
StringTemplate template = stg.getInstanceOf("SimpleEncodedValue");
template.setAttribute("Value", value);
return template;
public class DoubleRenderer {
public static void writeTo(IndentingPrintWriter writer, double val) {
writer.print(val);
}
}

View File

@ -28,14 +28,11 @@
package org.jf.baksmali.Renderers;
import org.antlr.stringtemplate.AttributeRenderer;
import org.jf.baksmali.IndentingPrintWriter;
public class FloatRenderer implements AttributeRenderer {
public String toString(Object o) {
return Float.toString((Float)o) + "f";
}
public String toString(Object o, String s) {
return toString(o);
public class FloatRenderer {
public static void writeTo(IndentingPrintWriter writer, float val) {
writer.print(val);
writer.write('f');
}
}

View File

@ -28,23 +28,21 @@
package org.jf.baksmali.Renderers;
import org.antlr.stringtemplate.AttributeRenderer;
import org.jf.baksmali.IndentingPrintWriter;
public class IntegerRenderer implements AttributeRenderer {
public String toString(Object o) {
Integer i = (Integer)o;
if (i < 0) {
return "-0x" + Integer.toHexString(-1 * i);
public class IntegerRenderer {
public static void writeTo(IndentingPrintWriter writer, int val) {
if (val<0) {
writer.write("-0x");
writer.printLongAsHex(-((long)val));
} else {
writer.write("0x");
writer.printLongAsHex(val);
}
return "0x" + Integer.toHexString((Integer)o);
}
public String toString(Object o, String s) {
if (s.equals("decimal")) {
return Integer.toString((Integer)o);
} else if (s.equals("barehex")) {
return Integer.toHexString((Integer)o);
}
return toString(o);
public static void writeUnsignedTo(IndentingPrintWriter writer, int val) {
writer.write("0x");
writer.printLongAsHex(val & 0xFFFFFFFF);
}
}

View File

@ -28,18 +28,34 @@
package org.jf.baksmali.Renderers;
import org.antlr.stringtemplate.AttributeRenderer;
import org.jf.baksmali.IndentingPrintWriter;
public class LongRenderer implements AttributeRenderer {
public String toString(Object o) {
Long l = (Long)o;
if (l < 0) {
return "-0x" + Long.toHexString(-1 * l) + "L";
public class LongRenderer {
public static void writeTo(IndentingPrintWriter writer, long val) {
if (val<0) {
writer.write("-0x");
writer.printLongAsHex(-val);
writer.write('L');
} else {
writer.write("0x");
writer.printLongAsHex(val);
writer.write('L');
}
return "0x" + Long.toHexString(l) + "L";
}
public String toString(Object o, String s) {
return toString(o);
public static void writeSignedIntOrLongTo(IndentingPrintWriter writer, long val) {
if (val<0) {
writer.write("-0x");
writer.printLongAsHex(-val);
if (val < Integer.MIN_VALUE) {
writer.write('L');
}
} else {
writer.write("0x");
writer.printLongAsHex(val);
if (val > Integer.MAX_VALUE) {
writer.write('L');
}
}
}
}

View File

@ -28,18 +28,18 @@
package org.jf.baksmali.Renderers;
import org.antlr.stringtemplate.AttributeRenderer;
import org.jf.baksmali.IndentingPrintWriter;
public class ShortRenderer implements AttributeRenderer {
public String toString(Object o) {
Short s = (Short)o;
if (s < 0) {
return "-0x" + Integer.toHexString(-1 * s) + "s";
public class ShortRenderer {
public static void writeTo(IndentingPrintWriter writer, short val) {
if (val < 0) {
writer.write("-0x");
writer.printLongAsHex(-val);
writer.write('s');
} else {
writer.write("0x");
writer.printLongAsHex(val);
writer.write('s');
}
return "0x" + Integer.toHexString(s) + "s";
}
public String toString(Object o, String s) {
return toString(o);
}
}

View File

@ -28,8 +28,6 @@
package org.jf.baksmali;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.jf.baksmali.Adaptors.ClassDefinition;
import org.jf.baksmali.Renderers.*;
import org.jf.dexlib.Code.Analysis.ClassPath;
@ -107,18 +105,6 @@ public class baksmali {
}
}
//load and initialize the templates
InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("templates/baksmali.stg");
StringTemplateGroup templates = new StringTemplateGroup(new InputStreamReader(templateStream));
templates.registerRenderer(Long.class, new LongRenderer());
templates.registerRenderer(Integer.class, new IntegerRenderer());
templates.registerRenderer(Short.class, new ShortRenderer());
templates.registerRenderer(Byte.class, new ByteRenderer());
templates.registerRenderer(Float.class, new FloatRenderer());
templates.registerRenderer(Character.class, new CharRenderer());
templates.registerRenderer(StringIdItem.class, new StringIdItemRenderer());
for (ClassDefItem classDefItem: dexFile.ClassDefsSection.getItems()) {
/**
* The path for the disassembly file is based on the package name
@ -154,15 +140,10 @@ public class baksmali {
File smaliFile = new File(smaliPath.toString());
//create and initialize the top level string template
ClassDefinition classDefinition = new ClassDefinition(templates, classDefItem);
StringTemplate smaliFileST = classDefinition.createTemplate();
//generate the disassembly
String output = smaliFileST.toString();
ClassDefinition classDefinition = new ClassDefinition(classDefItem);
//write the disassembly
FileWriter writer = null;
Writer writer = null;
try
{
File smaliParent = smaliFile.getParentFile();
@ -180,8 +161,10 @@ public class baksmali {
}
}
writer = new FileWriter(smaliFile);
writer.write(output);
BufferedWriter bufWriter = new BufferedWriter(new FileWriter(smaliFile));
writer = new IndentingPrintWriter(new IndentingWriter(bufWriter));
classDefinition.writeTo((IndentingPrintWriter)writer);
} catch (Exception ex) {
System.err.println("\n\nError occured while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class");
ex.printStackTrace();

View File

@ -30,8 +30,6 @@ package org.jf.baksmali;
import org.apache.commons.cli.*;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.OdexDependencies;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.util.*;
import java.io.File;

View File

@ -31,13 +31,15 @@ package org.jf.dexlib;
import org.jf.dexlib.Util.ExceptionWithContext;
public enum AnnotationVisibility {
BUILD((byte)0),
RUNTIME((byte)1),
SYSTEM((byte)2);
BUILD((byte)0, "build"),
RUNTIME((byte)1, "runtime"),
SYSTEM((byte)2, "system");
public final byte value;
private AnnotationVisibility(byte value) {
public final String visibility;
private AnnotationVisibility(byte value, String visibility) {
this.value = value;
this.visibility = visibility;
}
public static AnnotationVisibility fromByte(byte value) {

View File

@ -354,6 +354,10 @@ public class MethodAnalyzer {
return instructions.getValues();
}
public ClassDataItem.EncodedMethod getMethod() {
return this.encodedMethod;
}
public ValidationException getValidationException() {
return validationException;
}

View File

@ -30,6 +30,9 @@ package org.jf.dexlib.Code.Analysis;
import org.jf.dexlib.TypeIdItem;
import static org.jf.dexlib.Code.Analysis.ClassPath.ClassDef;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
public class RegisterType {
@ -54,6 +57,16 @@ public class RegisterType {
return "(" + category.name() + (type==null?"":("," + type.getClassType())) + ")";
}
public void writeTo(Writer writer) throws IOException {
writer.write('(');
writer.write(category.name());
if (type != null) {
writer.write(',');
writer.write(type.getClassType());
}
writer.write(')');
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -16,6 +16,9 @@
package org.jf.dexlib.Util;
import java.io.IOException;
import java.io.Writer;
/**
* Constants of type <code>CONSTANT_Utf8_info</code>.
*/
@ -166,6 +169,55 @@ public final class Utf8Utils {
" at offset " + Hex.u4(offset));
}
public static void writeEscapedChar(Writer writer, char c) throws IOException {
if ((c >= ' ') && (c < 0x7f)) {
if ((c == '\'') || (c == '\"') || (c == '\\')) {
writer.write('\\');
}
writer.write(c);
return;
} else if (c <= 0x7f) {
switch (c) {
case '\n': writer.write("\\n"); return;
case '\r': writer.write("\\r"); return;
case '\t': writer.write("\\t"); return;
}
}
writer.write("\\u");
writer.write(Character.forDigit(c >> 12, 16));
writer.write(Character.forDigit((c >> 8) & 0x0f, 16));
writer.write(Character.forDigit((c >> 4) & 0x0f, 16));
writer.write(Character.forDigit(c & 0x0f, 16));
}
public static void writeEscapedString(Writer writer, String value) throws IOException {
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if ((c >= ' ') && (c < 0x7f)) {
if ((c == '\'') || (c == '\"') || (c == '\\')) {
writer.write('\\');
}
writer.write(c);
continue;
} else if (c <= 0x7f) {
switch (c) {
case '\n': writer.write("\\n"); continue;
case '\r': writer.write("\\r"); continue;
case '\t': writer.write("\\t"); continue;
}
}
writer.write("\\u");
writer.write(Character.forDigit(c >> 12, 16));
writer.write(Character.forDigit((c >> 8) & 0x0f, 16));
writer.write(Character.forDigit((c >> 4) & 0x0f, 16));
writer.write(Character.forDigit(c & 0x0f, 16));
}
}
public static String escapeString(String value) {
int len = value.length();
StringBuilder sb = new StringBuilder(len * 3 / 2);