Nearly full switch over to dexlib2 in baksmali

No odex handling/register analysis yet, and there are still a few minor
features that haven't been reimplemented yet.

Still lots of bugs :)
This commit is contained in:
Ben Gruver 2012-10-28 13:17:19 -07:00
parent ba114e7211
commit 754b3c4dc0
26 changed files with 1043 additions and 709 deletions

View File

@ -34,13 +34,13 @@ import org.jf.dexlib.TypeIdItem;
import java.io.IOException;
public class CatchMethodItem extends MethodItem {
private final TypeIdItem exceptionType;
private final String exceptionType;
private final LabelMethodItem tryStartLabel;
private final LabelMethodItem tryEndLabel;
private final LabelMethodItem handlerLabel;
public CatchMethodItem(MethodDefinition.LabelCache labelCache, int codeAddress, TypeIdItem exceptionType,
public CatchMethodItem(MethodDefinition.LabelCache labelCache, int codeAddress, String exceptionType,
int startAddress, int endAddress, int handlerAddress) {
super(codeAddress);
this.exceptionType = exceptionType;
@ -81,7 +81,7 @@ public class CatchMethodItem extends MethodItem {
writer.write(".catchall");
} else {
writer.write(".catch ");
ReferenceFormatter.writeTypeReference(writer, exceptionType);
writer.write(exceptionType);
}
writer.write(" {");
tryStartLabel.writeTo(writer);

View File

@ -41,7 +41,7 @@ import java.util.HashSet;
import java.util.List;
public class ClassDefinition {
@Nonnull private final ClassDef classDef;
@Nonnull public final ClassDef classDef;
@Nonnull private final HashSet<String> fieldsSetInStaticConstructor;
protected boolean validationErrors;
@ -95,8 +95,8 @@ public class ClassDefinition {
writeAnnotations(writer);
writeStaticFields(writer);
writeInstanceFields(writer);
/*writeDirectMethods(writer);
writeVirtualMethods(writer);*/
writeDirectMethods(writer);
writeVirtualMethods(writer);
}
private void writeClass(IndentingWriter writer) throws IOException {
@ -189,6 +189,62 @@ public class ClassDefinition {
}
}
private void writeDirectMethods(IndentingWriter writer) throws IOException {
boolean wroteHeader = false;
for (Method method: classDef.getMethods()) {
int accessFlags = method.getAccessFlags();
if (AccessFlags.STATIC.isSet(accessFlags) ||
AccessFlags.PRIVATE.isSet(accessFlags) ||
AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
if (!wroteHeader) {
writer.write("\n\n");
writer.write("# direct methods");
wroteHeader = true;
}
writer.write('\n');
// TODO: detect duplicate methods.
// TODO: check for method validation errors
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl == null) {
MethodDefinition.writeEmptyMethodTo(writer, method);
} else {
MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl);
methodDefinition.writeTo(writer);
}
}
}
}
private void writeVirtualMethods(IndentingWriter writer) throws IOException {
boolean wroteHeader = false;
for (Method method: classDef.getMethods()) {
int accessFlags = method.getAccessFlags();
if (!AccessFlags.STATIC.isSet(accessFlags) &&
!AccessFlags.PRIVATE.isSet(accessFlags) &&
!AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
if (!wroteHeader) {
writer.write("\n\n");
writer.write("# virtual methods");
wroteHeader = true;
}
writer.write('\n');
// TODO: detect duplicate methods.
// TODO: check for method validation errors
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl == null) {
MethodDefinition.writeEmptyMethodTo(writer, method);
} else {
MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl);
methodDefinition.writeTo(writer);
}
}
}
}
//TODO: uncomment
/*private void writeDirectMethods(IndentingWriter writer) throws IOException {
if (classDataItem == null) {

View File

@ -0,0 +1,48 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Debug;
import org.jf.util.IndentingWriter;
import java.io.IOException;
public class BeginEpilogueMethodItem extends DebugMethodItem {
public BeginEpilogueMethodItem(int codeAddress, int sortOrder) {
super(codeAddress, sortOrder);
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".prologue");
return true;
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Debug;
import org.jf.baksmali.Adaptors.MethodItem;
import org.jf.baksmali.Adaptors.RegisterFormatter;
import org.jf.dexlib2.DebugItemType;
import org.jf.dexlib2.iface.debug.*;
import org.jf.util.ExceptionWithContext;
public abstract class DebugMethodItem extends MethodItem {
private final int sortOrder;
protected DebugMethodItem(int codeAddress, int sortOrder) {
super(codeAddress);
this.sortOrder = sortOrder;
}
@Override public double getSortOrder() { return sortOrder; }
public static DebugMethodItem build(RegisterFormatter registerFormatter, DebugItem debugItem) {
int codeAddress = debugItem.getCodeAddress();
switch (debugItem.getDebugItemType()) {
case DebugItemType.START_LOCAL:
return new StartLocalMethodItem(codeAddress, -1, registerFormatter, (StartLocal)debugItem);
case DebugItemType.END_LOCAL:
return new EndLocalMethodItem(codeAddress, -1, registerFormatter, (EndLocal)debugItem);
case DebugItemType.RESTART_LOCAL:
return new RestartLocalMethodItem(codeAddress, -1, registerFormatter, (RestartLocal)debugItem);
case DebugItemType.EPILOGUE_BEGIN:
return new BeginEpilogueMethodItem(codeAddress, -4);
case DebugItemType.PROLOGUE_END:
return new EndPrologueMethodItem(codeAddress, -4);
case DebugItemType.SET_SOURCE_FILE:
return new SetSourceFileMethodItem(codeAddress, -3, (SetSourceFile)debugItem);
case DebugItemType.LINE_NUMBER:
return new LineNumberMethodItem(codeAddress, -2, (LineNumber)debugItem);
default:
throw new ExceptionWithContext("Invalid debug item type: %d", debugItem.getDebugItemType());
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Debug;
import org.jf.baksmali.Adaptors.RegisterFormatter;
import org.jf.dexlib2.iface.debug.EndLocal;
import org.jf.util.IndentingWriter;
import javax.annotation.Nonnull;
import java.io.IOException;
public class EndLocalMethodItem extends DebugMethodItem {
@Nonnull private final EndLocal endLocal;
@Nonnull private final RegisterFormatter registerFormatter;
public EndLocalMethodItem(int codeAddress, int sortOrder, @Nonnull RegisterFormatter registerFormatter,
@Nonnull EndLocal endLocal) {
super(codeAddress, sortOrder);
this.endLocal = endLocal;
this.registerFormatter = registerFormatter;
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".end local ");
registerFormatter.writeTo(writer, endLocal.getRegister());
//TODO: what if name is null, but there is a type?
String name = endLocal.getName();
if (name != null) {
writer.write(" #");
writer.write(name);
writer.write(':');
writer.write(endLocal.getType());
String signature = endLocal.getSignature();
if (signature != null) {
writer.write(",\"");
writer.write(signature);
writer.write('"');
}
}
return true;
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Debug;
import org.jf.util.IndentingWriter;
import java.io.IOException;
public class EndPrologueMethodItem extends DebugMethodItem {
public EndPrologueMethodItem(int codeAddress, int sortOrder) {
super(codeAddress, sortOrder);
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".prologue");
return true;
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Debug;
import org.jf.dexlib2.iface.debug.LineNumber;
import org.jf.util.IndentingWriter;
import javax.annotation.Nonnull;
import java.io.IOException;
public class LineNumberMethodItem extends DebugMethodItem {
private final int lineNumber;
public LineNumberMethodItem(int codeAddress, int sortOrder, @Nonnull LineNumber lineNumber) {
super(codeAddress, sortOrder);
this.lineNumber = lineNumber.getLineNumber();
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".line ");
writer.printSignedIntAsDec(lineNumber);
return true;
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Debug;
import org.jf.baksmali.Adaptors.RegisterFormatter;
import org.jf.dexlib2.iface.debug.RestartLocal;
import org.jf.util.IndentingWriter;
import javax.annotation.Nonnull;
import java.io.IOException;
public class RestartLocalMethodItem extends DebugMethodItem {
@Nonnull private final RestartLocal restartLocal;
@Nonnull private final RegisterFormatter registerFormatter;
public RestartLocalMethodItem(int codeAddress, int sortOrder, @Nonnull RegisterFormatter registerFormatter,
@Nonnull RestartLocal restartLocal) {
super(codeAddress, sortOrder);
this.restartLocal = restartLocal;
this.registerFormatter = registerFormatter;
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".restart local ");
registerFormatter.writeTo(writer, restartLocal.getRegister());
//TODO: what if name is null, but there is a type?
String name = restartLocal.getName();
if (name != null) {
writer.write(" #");
writer.write(name);
writer.write(':');
writer.write(restartLocal.getType());
String signature = restartLocal.getSignature();
if (signature != null) {
writer.write(",\"");
writer.write(signature);
writer.write('"');
}
}
return true;
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Debug;
import org.jf.dexlib2.iface.debug.SetSourceFile;
import org.jf.util.IndentingWriter;
import org.jf.util.StringUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
public class SetSourceFileMethodItem extends DebugMethodItem {
@Nullable private final String sourceFile;
public SetSourceFileMethodItem(int codeAddress, int sortOrder, @Nonnull SetSourceFile setSourceFile) {
super(codeAddress, sortOrder);
this.sourceFile = setSourceFile.getSourceFile();
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
//TODO: make sure smali can handle an empty .source directive
writer.write(".source");
if (sourceFile != null) {
writer.write(" \"");
StringUtils.writeEscapedString(writer, sourceFile);
writer.write('"');
}
return true;
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors.Debug;
import org.jf.baksmali.Adaptors.RegisterFormatter;
import org.jf.dexlib2.iface.debug.StartLocal;
import org.jf.util.IndentingWriter;
import javax.annotation.Nonnull;
import java.io.IOException;
public class StartLocalMethodItem extends DebugMethodItem {
@Nonnull private final StartLocal startLocal;
@Nonnull private final RegisterFormatter registerFormatter;
public StartLocalMethodItem(int codeAddress, int sortOrder, @Nonnull RegisterFormatter registerFormatter,
@Nonnull StartLocal startLocal) {
super(codeAddress, sortOrder);
this.startLocal = startLocal;
this.registerFormatter = registerFormatter;
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".local ");
registerFormatter.writeTo(writer, startLocal.getRegister());
writer.write(", ");
//TODO: what about when name or type is null?
writer.write(startLocal.getName());
writer.write(':');
writer.write(startLocal.getType());
String signature = startLocal.getSignature();
if (signature != null) {
writer.write(",\"");
//TODO: does dalvik require this be in any format? Does it need to be escaped?
writer.write(signature);
writer.write('"');
}
return true;
}
}

View File

@ -1,123 +0,0 @@
/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver (JesusFreke)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors;
import org.jf.util.StringUtils;
import org.jf.util.IndentingWriter;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib.StringIdItem;
import org.jf.dexlib.TypeIdItem;
import java.io.IOException;
public abstract class DebugMethodItem extends MethodItem {
private final double sortOrder;
public DebugMethodItem(int codeAddress, double sortOrder) {
super(codeAddress);
this.sortOrder = sortOrder;
}
public double getSortOrder() {
return sortOrder;
}
protected static void writeLine(IndentingWriter writer, int line) throws IOException {
writer.write(".line ");
writer.printSignedIntAsDec(line);
}
protected static void writeEndPrologue(IndentingWriter writer) throws IOException {
writer.write(".prologue");
}
protected static void writeBeginEpilogue(IndentingWriter writer) throws IOException {
writer.write(".epilogue");
}
protected static void writeStartLocal(IndentingWriter writer, CodeItem codeItem, int register,
StringIdItem name, TypeIdItem type, StringIdItem signature)
throws IOException {
writer.write(".local ");
RegisterFormatter.writeTo(writer, codeItem, register);
writer.write(", ");
writer.write(name.getStringValue());
writer.write(':');
writer.write(type.getTypeDescriptor());
if (signature != null) {
writer.write(",\"");
writer.write(signature.getStringValue());
writer.write('"');
}
}
protected static void writeEndLocal(IndentingWriter writer, CodeItem codeItem, int register, StringIdItem name,
TypeIdItem type, StringIdItem signature) throws IOException {
writer.write(".end local ");
RegisterFormatter.writeTo(writer, codeItem, register);
if (name != null) {
writer.write(" #");
writer.write(name.getStringValue());
writer.write(':');
writer.write(type.getTypeDescriptor());
if (signature != null) {
writer.write(",\"");
writer.write(signature.getStringValue());
writer.write('"');
}
}
}
protected static void writeRestartLocal(IndentingWriter writer, CodeItem codeItem, int register,
StringIdItem name, TypeIdItem type, StringIdItem signature)
throws IOException {
writer.write(".restart local ");
RegisterFormatter.writeTo(writer, codeItem, register);
if (name != null) {
writer.write(" #");
writer.write(name.getStringValue());
writer.write(':');
writer.write(type.getTypeDescriptor());
if (signature != null) {
writer.write(",\"");
writer.write(signature.getStringValue());
writer.write('"');
}
}
}
protected static void writeSetFile(IndentingWriter writer, String fileName) throws IOException {
writer.write(".source \"");
StringUtils.writeEscapedString(writer, fileName);
writer.write('"');
}
}

View File

@ -28,36 +28,44 @@
package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.baksmali.Renderers.LongRenderer;
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
import org.jf.util.IndentingWriter;
import org.jf.baksmali.Renderers.ByteRenderer;
import org.jf.dexlib.Code.Format.ArrayDataPseudoInstruction;
import org.jf.dexlib.CodeItem;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayDataPseudoInstruction> {
public ArrayDataMethodItem(CodeItem codeItem, int codeAddress, ArrayDataPseudoInstruction instruction) {
super(codeItem, codeAddress, instruction);
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayPayload> {
public ArrayDataMethodItem(MethodDefinition methodDef, int codeAddress, ArrayPayload instruction) {
super(methodDef, codeAddress, instruction);
}
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".array-data 0x");
writer.printUnsignedLongAsHex(instruction.getElementWidth());
int elementWidth = instruction.getElementWidth();
writer.write(".array-data ");
writer.printSignedIntAsDec(instruction.getElementWidth());
writer.write('\n');
writer.indent(4);
Iterator<ArrayDataPseudoInstruction.ArrayElement> iterator = instruction.getElements();
while (iterator.hasNext()) {
ArrayDataPseudoInstruction.ArrayElement element = iterator.next();
for (int i=0; i<element.elementWidth; i++) {
if (i!=0) {
writer.write(' ');
}
ByteRenderer.writeUnsignedTo(writer, element.buffer[element.bufferIndex+i]);
}
writer.write('\n');
List<Number> elements = instruction.getArrayElements();
String suffix = "";
switch (elementWidth) {
case 1:
suffix = "t";
break;
case 2:
suffix = "s";
break;
}
for (Number number: instruction.getArrayElements()) {
LongRenderer.writeSignedIntOrLongTo(writer, number.longValue());
writer.write(suffix);
writer.write("\n");
}
writer.deindent(4);
writer.write(".end array-data");

View File

@ -28,26 +28,25 @@
package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.baksmali.Adaptors.MethodItem;
import org.jf.baksmali.Adaptors.ReferenceFormatter;
import org.jf.baksmali.Adaptors.RegisterFormatter;
import org.jf.dexlib.Code.Format.Instruction20bc;
import org.jf.dexlib.Code.Format.UnknownInstruction;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.iface.instruction.*;
import org.jf.util.IndentingWriter;
import org.jf.baksmali.Renderers.LongRenderer;
import org.jf.dexlib.Code.*;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib.Item;
import javax.annotation.Nonnull;
import java.io.IOException;
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
protected final CodeItem codeItem;
protected final T instruction;
@Nonnull protected final MethodDefinition methodDef;
@Nonnull protected final T instruction;
public InstructionMethodItem(CodeItem codeItem, int codeAddress, T instruction) {
public InstructionMethodItem(@Nonnull MethodDefinition methodDef, int codeAddress, @Nonnull T instruction) {
super(codeAddress);
this.codeItem = codeItem;
this.methodDef = methodDef;
this.instruction = instruction;
}
@ -58,7 +57,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
switch (instruction.getFormat()) {
switch (instruction.getOpcode().format) {
case Format10t:
writeOpcode(writer);
writer.write(' ');
@ -91,13 +90,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writer.write(", ");
writeSecondRegister(writer);
return true;
case Format20bc:
//TODO: uncomment
/*case Format20bc:
writeOpcode(writer);
writer.write(' ');
writeVerificationErrorType(writer);
writer.write(", ");
writeReference(writer);
return true;
return true;*/
case Format20t:
case Format30t:
writeOpcode(writer);
@ -112,7 +112,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writer.write(", ");
writeReference(writer);
return true;
case Format21h:
case Format21ih:
case Format21lh:
case Format21s:
case Format31i:
case Format51l:
@ -149,7 +150,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writer.write(", ");
writeReference(writer);
return true;
case Format22cs:
//TODO: uncomment
/*case Format22cs:
writeOpcode(writer);
writer.write(' ');
writeFirstRegister(writer);
@ -157,7 +159,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeSecondRegister(writer);
writer.write(", ");
writeFieldOffset(writer);
return true;
return true;*/
case Format22t:
writeOpcode(writer);
writer.write(' ');
@ -191,7 +193,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writer.write(", ");
writeReference(writer);
return true;
case Format35mi:
//TODO: uncomment
/*case Format35mi:
writeOpcode(writer);
writer.write(' ');
writeInvokeRegisters(writer);
@ -204,7 +207,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeInvokeRegisters(writer);
writer.write(", ");
writeVtableIndex(writer);
return true;
return true;*/
case Format3rc:
writeOpcode(writer);
writer.write(' ');
@ -212,7 +215,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writer.write(", ");
writeReference(writer);
return true;
case Format3rmi:
//TODO: uncomment
/*case Format3rmi:
writeOpcode(writer);
writer.write(' ');
writeInvokeRangeRegisters(writer);
@ -225,14 +229,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeInvokeRangeRegisters(writer);
writer.write(", ");
writeVtableIndex(writer);
return true;
return true;*/
}
assert false;
return false;
}
protected void writeOpcode(IndentingWriter writer) throws IOException {
writer.write(instruction.opcode.name);
writer.write(instruction.getOpcode().name);
}
protected void writeTargetLabel(IndentingWriter writer) throws IOException {
@ -242,11 +246,11 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
}
protected void writeRegister(IndentingWriter writer, int registerNumber) throws IOException {
RegisterFormatter.writeTo(writer, codeItem, registerNumber);
methodDef.registerFormatter.writeTo(writer, registerNumber);
}
protected void writeFirstRegister(IndentingWriter writer) throws IOException {
writeRegister(writer, ((SingleRegisterInstruction)instruction).getRegisterA());
writeRegister(writer, ((OneRegisterInstruction)instruction).getRegisterA());
}
protected void writeSecondRegister(IndentingWriter writer) throws IOException {
@ -254,40 +258,42 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
}
protected void writeThirdRegister(IndentingWriter writer) throws IOException {
writeRegister(writer, ((ThreeRegisterInstruction)instruction).getRegisterC());
writeRegister(writer, ((ThreeRegisterInstruction) instruction).getRegisterC());
}
protected void writeInvokeRegisters(IndentingWriter writer) throws IOException {
FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction;
final int regCount = instruction.getRegCount();
final int regCount = instruction.getRegisterCount();
writer.write('{');
switch (regCount) {
case 1:
writeRegister(writer, instruction.getRegisterD());
writeRegister(writer, instruction.getRegisterC());
break;
case 2:
writeRegister(writer, instruction.getRegisterD());
writeRegister(writer, instruction.getRegisterC());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
writeRegister(writer, instruction.getRegisterD());
break;
case 3:
writeRegister(writer, instruction.getRegisterC());
writer.write(", ");
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
writer.write(", ");
writeRegister(writer, instruction.getRegisterF());
break;
case 4:
writeRegister(writer, instruction.getRegisterC());
writer.write(", ");
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
writer.write(", ");
writeRegister(writer, instruction.getRegisterF());
writer.write(", ");
writeRegister(writer, instruction.getRegisterG());
break;
case 5:
writeRegister(writer, instruction.getRegisterC());
writer.write(", ");
writeRegister(writer, instruction.getRegisterD());
writer.write(", ");
writeRegister(writer, instruction.getRegisterE());
@ -295,8 +301,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeRegister(writer, instruction.getRegisterF());
writer.write(", ");
writeRegister(writer, instruction.getRegisterG());
writer.write(", ");
writeRegister(writer, instruction.getRegisterA());
break;
}
writer.write('}');
@ -305,20 +309,21 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException {
RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction;
int regCount = instruction.getRegCount();
int regCount = instruction.getRegisterCount();
if (regCount == 0) {
writer.write("{}");
} else {
int startRegister = instruction.getStartRegister();
RegisterFormatter.writeRegisterRange(writer, codeItem, startRegister, startRegister+regCount-1);
methodDef.registerFormatter.writeRegisterRange(writer, startRegister, startRegister+regCount-1);
}
}
protected void writeLiteral(IndentingWriter writer) throws IOException {
LongRenderer.writeSignedIntOrLongTo(writer, ((LiteralInstruction)instruction).getLiteral());
LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral());
}
protected void writeFieldOffset(IndentingWriter writer) throws IOException {
//TODO: uncomment
/*protected void writeFieldOffset(IndentingWriter writer) throws IOException {
writer.write("field@0x");
writer.printUnsignedLongAsHex(((OdexedFieldAccess) instruction).getFieldOffset());
}
@ -331,15 +336,20 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
protected void writeVtableIndex(IndentingWriter writer) throws IOException {
writer.write("vtable@0x");
writer.printUnsignedLongAsHex(((OdexedInvokeVirtual) instruction).getVtableIndex());
}
}*/
protected void writeReference(IndentingWriter writer) throws IOException {
Item item = ((InstructionWithReference)instruction).getReferencedItem();
ReferenceFormatter.writeReference(writer, item);
String reference = ((ReferenceInstruction)instruction).getReference();
if (instruction.getOpcode().referenceType == ReferenceType.STRING) {
ReferenceFormatter.writeStringReference(writer, reference);
} else {
writer.write(reference);
}
}
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
//TODO: uncomment
/*protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
VerificationErrorType validationErrorType = ((Instruction20bc)instruction).getValidationErrorType();
writer.write(validationErrorType.getName());
}
}*/
}

View File

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

View File

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

View File

@ -30,55 +30,54 @@ package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.LabelMethodItem;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.dexlib2.iface.instruction.SwitchElement;
import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload;
import org.jf.util.IndentingWriter;
import org.jf.baksmali.Renderers.IntegerRenderer;
import org.jf.dexlib.Code.Format.PackedSwitchDataPseudoInstruction;
import org.jf.dexlib.CodeItem;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDataPseudoInstruction> {
public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchPayload> {
private final List<PackedSwitchTarget> targets;
private final int firstKey;
public PackedSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress,
PackedSwitchDataPseudoInstruction instruction) {
super(codeItem, codeAddress, instruction);
public PackedSwitchMethodItem(MethodDefinition methodDef, int codeAddress, PackedSwitchPayload instruction) {
super(methodDef, codeAddress, instruction);
int baseCodeAddress = methodDefinition.getPackedSwitchBaseAddress(codeAddress);
int baseCodeAddress = methodDef.getPackedSwitchBaseAddress(codeAddress);
targets = new ArrayList<PackedSwitchTarget>();
Iterator<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> iterator = instruction.iterateKeysAndTargets();
boolean first = true;
//TODO: does dalvik allow switc payloads with no cases?
int firstKey = 0;
if (baseCodeAddress >= 0) {
while (iterator.hasNext()) {
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
PackedSwitchLabelTarget packedSwitchLabelTarget = new PackedSwitchLabelTarget();
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "pswitch_");
label = methodDefinition.getLabelCache().internLabel(label);
packedSwitchLabelTarget.Target = label;
targets.add(packedSwitchLabelTarget);
for (SwitchElement switchElement: instruction.getSwitchElements()) {
if (first) {
firstKey = switchElement.getKey();
first = false;
}
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + switchElement.getOffset(), "pswitch_");
targets.add(new PackedSwitchLabelTarget(label));
}
} else {
while (iterator.hasNext()) {
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
PackedSwitchOffsetTarget packedSwitchOffsetTarget = new PackedSwitchOffsetTarget();
packedSwitchOffsetTarget.Target = target.targetAddressOffset;
targets.add(packedSwitchOffsetTarget);
for (SwitchElement switchElement: instruction.getSwitchElements()) {
if (first) {
firstKey = switchElement.getKey();
first = false;
}
targets.add(new PackedSwitchOffsetTarget(switchElement.getOffset()));
}
}
this.firstKey = firstKey;
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".packed-switch ");
IntegerRenderer.writeTo(writer, instruction.getFirstKey());
IntegerRenderer.writeTo(writer, firstKey);
writer.indent(4);
writer.write('\n');
for (PackedSwitchTarget target: targets) {
@ -95,19 +94,25 @@ public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDa
}
private static class PackedSwitchLabelTarget extends PackedSwitchTarget {
public LabelMethodItem Target;
private final LabelMethodItem target;
public PackedSwitchLabelTarget(LabelMethodItem target) {
this.target = target;
}
public void writeTargetTo(IndentingWriter writer) throws IOException {
Target.writeTo(writer);
target.writeTo(writer);
}
}
private static class PackedSwitchOffsetTarget extends PackedSwitchTarget {
public int Target;
private final int target;
public PackedSwitchOffsetTarget(int target) {
this.target = target;
}
public void writeTargetTo(IndentingWriter writer) throws IOException {
if (Target >= 0) {
if (target >= 0) {
writer.write('+');
}
writer.printSignedIntAsDec(Target);
writer.printSignedIntAsDec(target);
}
}
}

View File

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

View File

@ -34,7 +34,8 @@ import org.jf.dexlib.CodeItem;
import java.io.IOException;
public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<UnresolvedOdexInstruction> {
//TODO: uncomment
/*public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<UnresolvedOdexInstruction> {
public UnresolvedOdexInstructionMethodItem(CodeItem codeItem, int codeAddress, UnresolvedOdexInstruction instruction) {
super(codeItem, codeAddress, instruction);
}
@ -49,4 +50,4 @@ public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<U
writer.write("throw ");
writeRegister(writer, instruction.ObjectRegisterNum);
}
}
}*/

View File

@ -28,293 +28,228 @@
package org.jf.baksmali.Adaptors;
import org.jf.baksmali.Adaptors.Debug.DebugMethodItem;
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
import org.jf.dexlib.Code.InstructionWithReference;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
import org.jf.dexlib2.util.InstructionOffsetMap;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.dexlib2.util.TypeUtils;
import org.jf.util.IndentingWriter;
import org.jf.baksmali.baksmali;
import org.jf.dexlib.*;
import org.jf.dexlib.Code.Analysis.AnalyzedInstruction;
import org.jf.dexlib.Code.Analysis.MethodAnalyzer;
import org.jf.dexlib.Code.Analysis.ValidationException;
import org.jf.dexlib.Code.Format.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.OffsetInstruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Debug.DebugInstructionIterator;
import org.jf.dexlib.Util.AccessFlags;
import org.jf.util.ExceptionWithContext;
import org.jf.dexlib.Util.SparseIntArray;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
public class MethodDefinition {
private final ClassDataItem.EncodedMethod encodedMethod;
private MethodAnalyzer methodAnalyzer;
@Nonnull public final ClassDefinition classDef;
@Nonnull public final Method method;
@Nonnull public final MethodImplementation methodImpl;
public RegisterFormatter registerFormatter;
private final LabelCache labelCache = new LabelCache();
@Nonnull private final String methodString;
private final SparseIntArray packedSwitchMap;
private final SparseIntArray sparseSwitchMap;
private final SparseIntArray instructionMap;
@Nonnull private final LabelCache labelCache = new LabelCache();
public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) {
@Nonnull private final SparseIntArray packedSwitchMap;
@Nonnull private final SparseIntArray sparseSwitchMap;
@Nonnull private final InstructionOffsetMap instructionOffsetMap;
public MethodDefinition(@Nonnull ClassDefinition classDef, @Nonnull Method method,
@Nonnull MethodImplementation methodImpl) {
this.classDef = classDef;
this.method = method;
this.methodImpl = methodImpl;
this.methodString = MethodUtil.buildFullMethodString(classDef.classDef, method);
try {
this.encodedMethod = encodedMethod;
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
if (encodedMethod.codeItem != null) {
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
List<? extends Instruction> instructions = methodImpl.getInstructions();
packedSwitchMap = new SparseIntArray(1);
sparseSwitchMap = new SparseIntArray(1);
instructionMap = new SparseIntArray(instructions.length);
packedSwitchMap = new SparseIntArray(0);
sparseSwitchMap = new SparseIntArray(0);
instructionOffsetMap = new InstructionOffsetMap(methodImpl);
int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
if (instruction.opcode == Opcode.PACKED_SWITCH) {
packedSwitchMap.append(
currentCodeAddress +
((OffsetInstruction)instruction).getTargetAddressOffset(),
currentCodeAddress);
} else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
sparseSwitchMap.append(
currentCodeAddress +
((OffsetInstruction)instruction).getTargetAddressOffset(),
currentCodeAddress);
}
instructionMap.append(currentCodeAddress, i);
currentCodeAddress += instruction.getSize(currentCodeAddress);
for (int i=0; i<instructions.size(); i++) {
Instruction instruction = instructions.get(i);
Opcode opcode = instruction.getOpcode();
if (opcode == Opcode.PACKED_SWITCH) {
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
packedSwitchMap.append(codeOffset, targetOffset);
} else if (opcode == Opcode.SPARSE_SWITCH) {
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
sparseSwitchMap.append(codeOffset, targetOffset);
}
} else {
packedSwitchMap = null;
sparseSwitchMap = null;
instructionMap = null;
methodAnalyzer = null;
}
}catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, String.format("Error while processing method %s",
encodedMethod.method.getMethodString()));
throw ExceptionWithContext.withContext(ex, "Error while processing method %s", methodString);
}
}
public void writeTo(IndentingWriter writer, AnnotationSetItem annotationSet,
AnnotationSetRefList parameterAnnotations) throws IOException {
final CodeItem codeItem = encodedMethod.codeItem;
public static void writeEmptyMethodTo(IndentingWriter writer, Method method) throws IOException {
writer.write(".method ");
writeAccessFlags(writer, encodedMethod);
writer.write(encodedMethod.method.getMethodName().getStringValue());
writer.write(encodedMethod.method.getPrototype().getPrototypeString());
writeAccessFlags(writer, method.getAccessFlags());
writer.write(method.getName());
writer.write("(");
for (MethodParameter parameter: method.getParameters()) {
writer.write(parameter.getType());
}
writer.write(")");
writer.write(method.getReturnType());
writer.write('\n');
writer.indent(4);
if (codeItem != null) {
if (baksmali.useLocalsDirective) {
writer.write(".locals ");
} else {
writer.write(".registers ");
}
writer.printSignedIntAsDec(getRegisterCount(encodedMethod));
writer.write('\n');
writeParameters(writer, codeItem, parameterAnnotations);
//TODO: uncomment
/*if (annotationSet != null) {
AnnotationFormatter.writeTo(writer, annotationSet);
}*/
writeParameters(writer, method.getParameters());
AnnotationFormatter.writeTo(writer, method.getAnnotations());
writer.deindent(4);
writer.write(".end method\n");
}
writer.write('\n');
public void writeTo(IndentingWriter writer) throws IOException {
int parameterRegisterCount = 0;
if (!AccessFlags.STATIC.isSet(method.getAccessFlags())) {
parameterRegisterCount++;
}
for (MethodItem methodItem: getMethodItems()) {
if (methodItem.writeTo(writer)) {
writer.write('\n');
}
writer.write(".method ");
writeAccessFlags(writer, method.getAccessFlags());
writer.write(method.getName());
writer.write("(");
for (MethodParameter parameter: method.getParameters()) {
String type = parameter.getType();
writer.write(type);
parameterRegisterCount++;
if (TypeUtils.isWideType(type)) {
parameterRegisterCount++;
}
}
writer.write(")");
writer.write(method.getReturnType());
writer.write('\n');
writer.indent(4);
if (baksmali.useLocalsDirective) {
writer.write(".locals ");
writer.printSignedIntAsDec(methodImpl.getRegisterCount() - parameterRegisterCount);
} else {
writeParameters(writer, codeItem, parameterAnnotations);
//TODO: uncomment
/*if (annotationSet != null) {
AnnotationFormatter.writeTo(writer, annotationSet);
}*/
writer.write(".registers ");
writer.printSignedIntAsDec(methodImpl.getRegisterCount());
}
writer.write('\n');
writeParameters(writer, method.getParameters());
if (registerFormatter == null) {
registerFormatter = new RegisterFormatter(methodImpl.getRegisterCount(), parameterRegisterCount);
}
AnnotationFormatter.writeTo(writer, method.getAnnotations());
writer.write('\n');
for (MethodItem methodItem: getMethodItems()) {
if (methodItem.writeTo(writer)) {
writer.write('\n');
}
}
writer.deindent(4);
writer.write(".end method\n");
}
private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod)
{
int totalRegisters = encodedMethod.codeItem.getRegisterCount();
if (baksmali.useLocalsDirective) {
int parameterRegisters = encodedMethod.method.getPrototype().getParameterRegisterCount();
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
parameterRegisters++;
private int findSwitchPayload(int targetOffset, Opcode type) {
int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
//TODO: does dalvik let you pad with multiple nops?
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
List<? extends Instruction> instructions = methodImpl.getInstructions();
Instruction instruction = instructions.get(targetIndex);
if (instruction.getOpcode() != type) {
// maybe it's pointing to a NOP padding instruction. Look at the next instruction
if (instruction.getOpcode() == Opcode.NOP) {
targetIndex += 1;
if (targetIndex < instructions.size()) {
instruction = instructions.get(targetIndex);
if (instruction.getOpcode() == type) {
return instructionOffsetMap.getInstructionCodeOffset(targetIndex);
}
}
}
return totalRegisters - parameterRegisters;
throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset);
} else {
return targetOffset;
}
return totalRegisters;
}
private static void writeAccessFlags(IndentingWriter writer, ClassDataItem.EncodedMethod encodedMethod)
throws IOException {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) {
private static void writeAccessFlags(IndentingWriter writer, int accessFlags)
throws IOException {
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(accessFlags)) {
writer.write(accessFlag.toString());
writer.write(' ');
}
}
private static void writeParameters(IndentingWriter writer, CodeItem codeItem,
AnnotationSetRefList parameterAnnotations) throws IOException {
DebugInfoItem debugInfoItem = null;
if (baksmali.outputDebugInfo && codeItem != null) {
debugInfoItem = codeItem.getDebugInfo();
}
int parameterCount = 0;
AnnotationSetItem[] annotations;
StringIdItem[] parameterNames = null;
if (parameterAnnotations != null) {
annotations = parameterAnnotations.getAnnotationSets();
parameterCount = annotations.length;
} else {
annotations = new AnnotationSetItem[0];
}
if (debugInfoItem != null) {
parameterNames = debugInfoItem.getParameterNames();
}
if (parameterNames == null) {
parameterNames = new StringIdItem[0];
}
if (parameterCount < parameterNames.length) {
parameterCount = parameterNames.length;
}
for (int i=0; i<parameterCount; i++) {
AnnotationSetItem annotationSet = null;
if (i < annotations.length) {
annotationSet = annotations[i];
private static void writeParameters(IndentingWriter writer,
List<? extends MethodParameter> parameters) throws IOException {
int registerNumber = 0;
for (MethodParameter parameter: parameters) {
String parameterType = parameter.getType();
String parameterName = parameter.getName();
List<? extends Annotation> annotations = parameter.getAnnotations();
if (parameterName != null || annotations.size() != 0) {
writer.write(".parameter p");
writer.printSignedIntAsDec(registerNumber);
if (parameterName != null) {
writer.write(" ");
writer.write(parameterName);
}
if (annotations.size() > 0) {
writer.indent(4);
AnnotationFormatter.writeTo(writer, annotations);
writer.deindent(4);
writer.write(".end parameter\n");
} else {
writer.write("\n");
}
}
StringIdItem parameterName = null;
if (i < parameterNames.length) {
parameterName = parameterNames[i];
registerNumber++;
if (TypeUtils.isWideType(parameterType)) {
registerNumber++;
}
writer.write(".parameter");
if (parameterName != null) {
writer.write(" \"");
writer.write(parameterName.getStringValue());
writer.write('"');
}
writer.write('\n');
//TODO: uncomment
/*if (annotationSet != null) {
writer.indent(4);
AnnotationFormatter.writeTo(writer, annotationSet);
writer.deindent(4);
writer.write(".end parameter\n");
}*/
}
}
public LabelCache getLabelCache() {
@Nonnull public LabelCache getLabelCache() {
return labelCache;
}
public ValidationException getValidationException() {
if (methodAnalyzer == null) {
return null;
}
return methodAnalyzer.getValidationException();
public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) {
return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1);
}
public int getPackedSwitchBaseAddress(int packedSwitchDataAddress) {
int packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress, -1);
if (packedSwitchBaseAddress == -1) {
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
int index = instructionMap.get(packedSwitchDataAddress);
if (instructions[index].opcode == Opcode.NOP) {
packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress+2, -1);
}
}
return packedSwitchBaseAddress;
}
public int getSparseSwitchBaseAddress(int sparseSwitchDataAddress) {
int sparseSwitchBaseAddress = this.sparseSwitchMap.get(sparseSwitchDataAddress, -1);
if (sparseSwitchBaseAddress == -1) {
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
int index = instructionMap.get(sparseSwitchDataAddress);
if (instructions[index].opcode == Opcode.NOP) {
sparseSwitchBaseAddress = this.packedSwitchMap.get(sparseSwitchDataAddress+2, -1);
}
}
return sparseSwitchBaseAddress;
}
/**
* @param instructions The instructions array for this method
* @param instruction The instruction
* @return true if the specified instruction is a NOP, and the next instruction is one of the variable sized
* switch/array data structures
*/
private boolean isInstructionPaddingNop(List<AnalyzedInstruction> instructions, AnalyzedInstruction instruction) {
if (instruction.getInstruction().opcode != Opcode.NOP ||
instruction.getInstruction().getFormat().variableSizeFormat) {
return false;
}
if (instruction.getInstructionIndex() == instructions.size()-1) {
return false;
}
AnalyzedInstruction nextInstruction = instructions.get(instruction.getInstructionIndex()+1);
if (nextInstruction.getInstruction().getFormat().variableSizeFormat) {
return true;
}
return false;
}
private boolean needsAnalyzed() {
for (Instruction instruction: encodedMethod.codeItem.getInstructions()) {
if (instruction.opcode.odexOnly()) {
return true;
}
}
return false;
public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) {
return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1);
}
private List<MethodItem> getMethodItems() {
ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
if (encodedMethod.codeItem == null) {
return methodItems;
}
if ((baksmali.registerInfo != 0) || baksmali.verify ||
(baksmali.deodex && needsAnalyzed())) {
addAnalyzedInstructionMethodItems(methodItems);
} else {
addInstructionMethodItems(methodItems);
}
//TODO: addAnalyzedInstructionMethodItems
addInstructionMethodItems(methodItems);
addTries(methodItems);
if (baksmali.outputDebugInfo) {
@ -335,18 +270,18 @@ public class MethodDefinition {
}
private void addInstructionMethodItems(List<MethodItem> methodItems) {
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
List<? extends Instruction> instructions = methodImpl.getInstructions();
int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
for (int i=0; i<instructions.size(); i++) {
Instruction instruction = instructions.get(i);
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction);
currentCodeAddress, instruction);
methodItems.add(methodItem);
if (i != instructions.length - 1) {
if (i != instructions.size() - 1) {
methodItems.add(new BlankMethodItem(currentCodeAddress));
}
@ -361,14 +296,16 @@ public class MethodDefinition {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write("#@");
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
return true;
}
});
}
if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
if (instruction.opcode == Opcode.INVOKE_STATIC || instruction.opcode == Opcode.INVOKE_STATIC_RANGE) {
//TODO: uncomment
/*if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
Opcode opcode = instruction.getOpcode();
if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
MethodIdItem methodIdItem =
(MethodIdItem)((InstructionWithReference) instruction).getReferencedItem();
@ -380,13 +317,14 @@ public class MethodDefinition {
}
}
}
}
}*/
currentCodeAddress += instruction.getSize(currentCodeAddress);
currentCodeAddress += instruction.getCodeUnits();
}
}
private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
//TODO: uncomment
/*private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
methodAnalyzer.analyze();
@ -455,20 +393,21 @@ public class MethodDefinition {
currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress);
}
}
}*/
private void addTries(List<MethodItem> methodItems) {
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) {
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
if (tryBlocks.size() == 0) {
return;
}
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
int lastInstructionAddress = instructionMap.keyAt(instructionMap.size()-1);
int codeSize = lastInstructionAddress + instructions[instructions.length - 1].getSize(lastInstructionAddress);
List<? extends Instruction> instructions = methodImpl.getInstructions();
int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) {
int startAddress = tryItem.getStartCodeAddress();
int endAddress = tryItem.getStartCodeAddress() + tryItem.getTryLength();
for (TryBlock tryBlock: tryBlocks) {
int startAddress = tryBlock.getStartCodeOffset();
int endAddress = startAddress + tryBlock.getCodeUnitCount();
if (startAddress >= codeSize) {
throw new RuntimeException(String.format("Try start offset %d is past the end of the code block.",
@ -487,142 +426,28 @@ public class MethodDefinition {
* the address for that instruction
*/
int lastCoveredIndex = instructionMap.getClosestSmaller(endAddress-1);
int lastCoveredAddress = instructionMap.keyAt(lastCoveredIndex);
int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false);
int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex);
//add the catch all handler if it exists
int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
if (catchAllAddress != -1) {
if (catchAllAddress >= codeSize) {
throw new RuntimeException(String.format(
"Catch all handler offset %d is past the end of the code block.", catchAllAddress));
}
CatchMethodItem catchAllMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress, null,
startAddress, endAddress, catchAllAddress);
methodItems.add(catchAllMethodItem);
}
//add the rest of the handlers
for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
if (handler.getHandlerAddress() >= codeSize) {
throw new RuntimeException(String.format(
"Exception handler offset %d is past the end of the code block.", catchAllAddress));
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
int handlerOffset = handler.getHandlerCodeOffset();
if (handlerOffset >= codeSize) {
throw new ExceptionWithContext(
"Exception handler offset %d is past the end of the code block.", handlerOffset);
}
//use the address from the last covered instruction
CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress,
handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress());
handler.getExceptionType(), startAddress, endAddress, handlerOffset);
methodItems.add(catchMethodItem);
}
}
}
private void addDebugInfo(final List<MethodItem> methodItems) {
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getDebugInfo() == null) {
return;
for (DebugItem debugItem: methodImpl.getDebugItems()) {
methodItems.add(DebugMethodItem.build(registerFormatter, debugItem));
}
final CodeItem codeItem = encodedMethod.codeItem;
DebugInfoItem debugInfoItem = codeItem.getDebugInfo();
DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(),
new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() {
@Override
public void ProcessStartLocal(final int codeAddress, final int length, final int registerNum,
final StringIdItem name, final TypeIdItem type) {
methodItems.add(new DebugMethodItem(codeAddress, -1) {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writeStartLocal(writer, codeItem, registerNum, name, type, null);
return true;
}
});
}
@Override
public void ProcessStartLocalExtended(final int codeAddress, final int length,
final int registerNum, final StringIdItem name,
final TypeIdItem type, final StringIdItem signature) {
methodItems.add(new DebugMethodItem(codeAddress, -1) {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writeStartLocal(writer, codeItem, registerNum, name, type, signature);
return true;
}
});
}
@Override
public void ProcessEndLocal(final int codeAddress, final int length, final int registerNum,
final StringIdItem name, final TypeIdItem type,
final StringIdItem signature) {
methodItems.add(new DebugMethodItem(codeAddress, -1) {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writeEndLocal(writer, codeItem, registerNum, name, type, signature);
return true;
}
});
}
@Override
public void ProcessRestartLocal(final int codeAddress, final int length, final int registerNum,
final StringIdItem name, final TypeIdItem type,
final StringIdItem signature) {
methodItems.add(new DebugMethodItem(codeAddress, -1) {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writeRestartLocal(writer, codeItem, registerNum, name, type, signature);
return true;
}
});
}
@Override
public void ProcessSetPrologueEnd(int codeAddress) {
methodItems.add(new DebugMethodItem(codeAddress, -4) {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writeEndPrologue(writer);
return true;
}
});
}
@Override
public void ProcessSetEpilogueBegin(int codeAddress) {
methodItems.add(new DebugMethodItem(codeAddress, -4) {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writeBeginEpilogue(writer);
return true;
}
});
}
@Override
public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) {
methodItems.add(new DebugMethodItem(codeAddress, -3) {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writeSetFile(writer, name.getStringValue());
return true;
}
});
}
@Override
public void ProcessLineEmit(int codeAddress, final int line) {
methodItems.add(new DebugMethodItem(codeAddress, -2) {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writeLine(writer, line);
return true;
}
});
}
});
}
private void setLabelSequentialNumbers() {

View File

@ -39,7 +39,8 @@ import org.jf.dexlib.Code.Analysis.RegisterType;
import java.io.IOException;
import java.util.BitSet;
public class PostInstructionRegisterInfoMethodItem extends MethodItem {
//TODO: uncomment
/*public class PostInstructionRegisterInfoMethodItem extends MethodItem {
private final AnalyzedInstruction analyzedInstruction;
private final MethodAnalyzer methodAnalyzer;
@ -108,4 +109,4 @@ public class PostInstructionRegisterInfoMethodItem extends MethodItem {
}
return true;
}
}
}*/

View File

@ -41,7 +41,8 @@ import org.jf.dexlib.Util.AccessFlags;
import java.io.IOException;
import java.util.BitSet;
public class PreInstructionRegisterInfoMethodItem extends MethodItem {
//TODO: uncomment
/*public class PreInstructionRegisterInfoMethodItem extends MethodItem {
private final AnalyzedInstruction analyzedInstruction;
private final MethodAnalyzer methodAnalyzer;
@ -262,4 +263,4 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
}
return true;
}
}
}*/

View File

@ -35,45 +35,9 @@ import org.jf.util.StringUtils;
import java.io.IOException;
public class ReferenceFormatter {
public static void writeReference(IndentingWriter writer, Item item) throws IOException {
switch (item.getItemType()) {
case TYPE_METHOD_ID_ITEM:
writeMethodReference(writer, (MethodIdItem)item);
return;
case TYPE_FIELD_ID_ITEM:
writeFieldReference(writer, (FieldIdItem)item);
return;
case TYPE_STRING_ID_ITEM:
writeStringReference(writer, ((StringIdItem)item).getStringValue());
return;
case TYPE_TYPE_ID_ITEM:
writeTypeReference(writer, (TypeIdItem)item);
return;
}
}
public static void writeMethodReference(IndentingWriter writer, MethodIdItem item) throws IOException {
writer.write(item.getContainingClass().getTypeDescriptor());
writer.write("->");
writer.write(item.getMethodName().getStringValue());
writer.write(item.getPrototype().getPrototypeString());
}
public static void writeFieldReference(IndentingWriter writer, FieldIdItem item) throws IOException {
writer.write(item.getContainingClass().getTypeDescriptor());
writer.write("->");
writer.write(item.getFieldName().getStringValue());
writer.write(':');
writer.write(item.getFieldType().getTypeDescriptor());
}
public static void writeStringReference(IndentingWriter writer, String item) throws IOException {
writer.write('"');
StringUtils.writeEscapedString(writer, item);
writer.write('"');
}
public static void writeTypeReference(IndentingWriter writer, TypeIdItem item) throws IOException {
writer.write(item.getTypeDescriptor());
}
}

View File

@ -28,6 +28,7 @@
package org.jf.baksmali.Adaptors;
import com.google.common.base.Preconditions;
import org.jf.util.IndentingWriter;
import org.jf.baksmali.baksmali;
import org.jf.dexlib.CodeItem;
@ -39,6 +40,13 @@ import java.io.IOException;
* This class contains the logic used for formatting registers
*/
public class RegisterFormatter {
public final int registerCount;
public final int parameterRegisterCount;
public RegisterFormatter(int registerCount, int parameterRegisterCount) {
this.registerCount = registerCount;
this.parameterRegisterCount = parameterRegisterCount;
}
/**
* Write out the register range value used by Format3rc. If baksmali.noParameterRegisters is true, it will always
@ -46,19 +54,11 @@ public class RegisterFormatter {
* registers, and if so, use the p<n> format for both. If only the last register is a parameter register, it will
* use the v<n> format for both, otherwise it would be confusing to have something like {v20 .. p1}
* @param writer the <code>IndentingWriter</code> to write to
* @param codeItem the <code>CodeItem</code> that the register is from
* @param startRegister the first register in the range
* @param lastRegister the last register in the range
*/
public static void writeRegisterRange(IndentingWriter writer, CodeItem codeItem, int startRegister,
int lastRegister) throws IOException {
assert lastRegister >= startRegister;
public void writeRegisterRange(IndentingWriter writer, int startRegister, int lastRegister) throws IOException {
if (!baksmali.noParameterRegisters) {
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
int registerCount = codeItem.getRegisterCount();
assert startRegister <= lastRegister;
if (startRegister >= registerCount - parameterRegisterCount) {
@ -83,14 +83,10 @@ public class RegisterFormatter {
* and if so, formats it in the p<n> format instead.
*
* @param writer the <code>IndentingWriter</code> to write to
* @param codeItem the <code>CodeItem</code> that the register is from
* @param register the register number
*/
public static void writeTo(IndentingWriter writer, CodeItem codeItem, int register) throws IOException {
public void writeTo(IndentingWriter writer, int register) throws IOException {
if (!baksmali.noParameterRegisters) {
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
int registerCount = codeItem.getRegisterCount();
if (register >= registerCount - parameterRegisterCount) {
writer.write('p');
writer.printSignedIntAsDec((register - (registerCount - parameterRegisterCount)));

View File

@ -34,7 +34,8 @@ import org.jf.util.IndentingWriter;
import java.io.IOException;
public class SyntheticAccessCommentMethodItem extends MethodItem {
//TODO: uncomment
/*public class SyntheticAccessCommentMethodItem extends MethodItem {
private final AccessedMember accessedMember;
public SyntheticAccessCommentMethodItem(AccessedMember accessedMember, int codeAddress) {
@ -59,4 +60,4 @@ public class SyntheticAccessCommentMethodItem extends MethodItem {
ReferenceFormatter.writeReference(writer, accessedMember.accessedMember);
return true;
}
}
}*/

View File

@ -0,0 +1,53 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.util;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodParameter;
public class MethodUtil {
public static String buildFullMethodString(ClassDef classDef, Method method) {
//TODO: consider using a cached thread-local StringBuilder
StringBuilder sb = new StringBuilder();
sb.append(classDef.getName());
sb.append("->");
sb.append(method.getName());
sb.append("(");
for (MethodParameter methodParameter: method.getParameters()) {
sb.append(methodParameter.getType());
}
sb.append(")");
sb.append(method.getReturnType());
return sb.toString();
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.util;
public class TypeUtils {
public static boolean isWideType(String type) {
char c = type.charAt(0);
return c == 'J' || c == 'D';
}
}