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

View File

@ -41,7 +41,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
public class ClassDefinition { public class ClassDefinition {
@Nonnull private final ClassDef classDef; @Nonnull public final ClassDef classDef;
@Nonnull private final HashSet<String> fieldsSetInStaticConstructor; @Nonnull private final HashSet<String> fieldsSetInStaticConstructor;
protected boolean validationErrors; protected boolean validationErrors;
@ -95,8 +95,8 @@ public class ClassDefinition {
writeAnnotations(writer); writeAnnotations(writer);
writeStaticFields(writer); writeStaticFields(writer);
writeInstanceFields(writer); writeInstanceFields(writer);
/*writeDirectMethods(writer); writeDirectMethods(writer);
writeVirtualMethods(writer);*/ writeVirtualMethods(writer);
} }
private void writeClass(IndentingWriter writer) throws IOException { 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 //TODO: uncomment
/*private void writeDirectMethods(IndentingWriter writer) throws IOException { /*private void writeDirectMethods(IndentingWriter writer) throws IOException {
if (classDataItem == null) { 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; package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.baksmali.Renderers.LongRenderer;
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
import org.jf.util.IndentingWriter; import org.jf.util.IndentingWriter;
import org.jf.baksmali.Renderers.ByteRenderer;
import org.jf.dexlib.Code.Format.ArrayDataPseudoInstruction;
import org.jf.dexlib.CodeItem;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.List;
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayDataPseudoInstruction> { public class ArrayDataMethodItem extends InstructionMethodItem<ArrayPayload> {
public ArrayDataMethodItem(CodeItem codeItem, int codeAddress, ArrayDataPseudoInstruction instruction) { public ArrayDataMethodItem(MethodDefinition methodDef, int codeAddress, ArrayPayload instruction) {
super(codeItem, codeAddress, instruction); super(methodDef, codeAddress, instruction);
} }
public boolean writeTo(IndentingWriter writer) throws IOException { public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write(".array-data 0x"); int elementWidth = instruction.getElementWidth();
writer.printUnsignedLongAsHex(instruction.getElementWidth());
writer.write(".array-data ");
writer.printSignedIntAsDec(instruction.getElementWidth());
writer.write('\n'); writer.write('\n');
writer.indent(4); writer.indent(4);
Iterator<ArrayDataPseudoInstruction.ArrayElement> iterator = instruction.getElements();
while (iterator.hasNext()) {
ArrayDataPseudoInstruction.ArrayElement element = iterator.next();
for (int i=0; i<element.elementWidth; i++) { List<Number> elements = instruction.getArrayElements();
if (i!=0) {
writer.write(' '); String suffix = "";
} switch (elementWidth) {
ByteRenderer.writeUnsignedTo(writer, element.buffer[element.bufferIndex+i]); case 1:
} suffix = "t";
writer.write('\n'); break;
case 2:
suffix = "s";
break;
}
for (Number number: instruction.getArrayElements()) {
LongRenderer.writeSignedIntOrLongTo(writer, number.longValue());
writer.write(suffix);
writer.write("\n");
} }
writer.deindent(4); writer.deindent(4);
writer.write(".end array-data"); writer.write(".end array-data");

View File

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

View File

@ -29,37 +29,36 @@
package org.jf.baksmali.Adaptors.Format; package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.dexlib.Code.Format.*; import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib.Code.Instruction; import org.jf.dexlib2.iface.instruction.OffsetInstruction;
import org.jf.dexlib.Code.OffsetInstruction; import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
import org.jf.dexlib.CodeItem; import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload;
import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload;
public class InstructionMethodItemFactory { public class InstructionMethodItemFactory {
private InstructionMethodItemFactory() { private InstructionMethodItemFactory() {
} }
public static InstructionMethodItem makeInstructionFormatMethodItem( public static InstructionMethodItem makeInstructionFormatMethodItem(
MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, Instruction instruction) { MethodDefinition methodDef, int codeAddress, Instruction instruction) {
if (instruction instanceof OffsetInstruction) { if (instruction instanceof OffsetInstruction) {
return new OffsetInstructionFormatMethodItem(methodDefinition.getLabelCache(), codeItem, return new OffsetInstructionFormatMethodItem(methodDef, codeAddress, (OffsetInstruction)instruction);
codeAddress, (OffsetInstruction)instruction);
} }
switch (instruction.getFormat()) { switch (instruction.getOpcode().format) {
case ArrayData: case ArrayPayload:
return new ArrayDataMethodItem(codeItem, codeAddress, return new ArrayDataMethodItem(methodDef, codeAddress, (ArrayPayload)instruction);
(ArrayDataPseudoInstruction)instruction); case PackedSwitchPayload:
case PackedSwitchData: return new PackedSwitchMethodItem(methodDef, codeAddress, (PackedSwitchPayload)instruction);
return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress, case SparseSwitchPayload:
(PackedSwitchDataPseudoInstruction)instruction); return new SparseSwitchMethodItem(methodDef, codeAddress, (SparseSwitchPayload)instruction);
case SparseSwitchData: //TODO: uncomment
return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress, /*case UnresolvedOdexInstruction:
(SparseSwitchDataPseudoInstruction)instruction);
case UnresolvedOdexInstruction:
return new UnresolvedOdexInstructionMethodItem(codeItem, codeAddress, return new UnresolvedOdexInstructionMethodItem(codeItem, codeAddress,
(UnresolvedOdexInstruction)instruction); (UnresolvedOdexInstruction)instruction);*/
default: 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.LabelMethodItem;
import org.jf.baksmali.Adaptors.MethodDefinition; 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.util.IndentingWriter;
import org.jf.dexlib.Code.OffsetInstruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.CodeItem;
import java.io.IOException; import java.io.IOException;
public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<OffsetInstruction> { public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<OffsetInstruction> {
protected LabelMethodItem label; protected LabelMethodItem label;
public OffsetInstructionFormatMethodItem(MethodDefinition.LabelCache labelCache, CodeItem codeItem, int codeAddress, public OffsetInstructionFormatMethodItem(MethodDefinition methodDef, int codeAddress,
OffsetInstruction instruction) { OffsetInstruction instruction) {
super(codeItem, codeAddress, instruction); super(methodDef, codeAddress, instruction);
label = new LabelMethodItem(codeAddress + instruction.getTargetAddressOffset(), getLabelPrefix()); label = new LabelMethodItem(codeAddress + instruction.getCodeOffset(), getLabelPrefix());
label = labelCache.internLabel(label); label = methodDef.getLabelCache().internLabel(label);
} }
@Override @Override
@ -58,7 +57,8 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<Off
} }
private String getLabelPrefix() { private String getLabelPrefix() {
switch (instruction.getFormat()) { Opcode opcode = instruction.getOpcode();
switch (opcode.format) {
case Format10t: case Format10t:
case Format20t: case Format20t:
case Format30t: case Format30t:
@ -67,13 +67,13 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<Off
case Format22t: case Format22t:
return "cond_"; return "cond_";
case Format31t: case Format31t:
if (instruction.opcode == Opcode.FILL_ARRAY_DATA) { if (opcode == Opcode.FILL_ARRAY_DATA) {
return "array_"; return "array_";
} }
if (instruction.opcode == Opcode.PACKED_SWITCH) { if (opcode == Opcode.PACKED_SWITCH) {
return "pswitch_data_"; return "pswitch_data_";
} }
assert instruction.opcode == Opcode.SPARSE_SWITCH; // Opcode.SPARSE_SWITCH;
return "sswitch_data_"; return "sswitch_data_";
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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