diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/CatchMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/CatchMethodItem.java index 2c5541f4..ca766558 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/CatchMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/CatchMethodItem.java @@ -34,13 +34,13 @@ import org.jf.dexlib.TypeIdItem; import java.io.IOException; public class CatchMethodItem extends MethodItem { - private final TypeIdItem exceptionType; + private final String exceptionType; private final LabelMethodItem tryStartLabel; private final LabelMethodItem tryEndLabel; private final LabelMethodItem handlerLabel; - public CatchMethodItem(MethodDefinition.LabelCache labelCache, int codeAddress, TypeIdItem exceptionType, + public CatchMethodItem(MethodDefinition.LabelCache labelCache, int codeAddress, String exceptionType, int startAddress, int endAddress, int handlerAddress) { super(codeAddress); this.exceptionType = exceptionType; @@ -81,7 +81,7 @@ public class CatchMethodItem extends MethodItem { writer.write(".catchall"); } else { writer.write(".catch "); - ReferenceFormatter.writeTypeReference(writer, exceptionType); + writer.write(exceptionType); } writer.write(" {"); tryStartLabel.writeTo(writer); diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java index c6778c2b..d9543847 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java @@ -41,7 +41,7 @@ import java.util.HashSet; import java.util.List; public class ClassDefinition { - @Nonnull private final ClassDef classDef; + @Nonnull public final ClassDef classDef; @Nonnull private final HashSet fieldsSetInStaticConstructor; protected boolean validationErrors; @@ -95,8 +95,8 @@ public class ClassDefinition { writeAnnotations(writer); writeStaticFields(writer); writeInstanceFields(writer); - /*writeDirectMethods(writer); - writeVirtualMethods(writer);*/ + writeDirectMethods(writer); + writeVirtualMethods(writer); } private void writeClass(IndentingWriter writer) throws IOException { @@ -189,6 +189,62 @@ public class ClassDefinition { } } + private void writeDirectMethods(IndentingWriter writer) throws IOException { + boolean wroteHeader = false; + for (Method method: classDef.getMethods()) { + int accessFlags = method.getAccessFlags(); + + if (AccessFlags.STATIC.isSet(accessFlags) || + AccessFlags.PRIVATE.isSet(accessFlags) || + AccessFlags.CONSTRUCTOR.isSet(accessFlags)) { + if (!wroteHeader) { + writer.write("\n\n"); + writer.write("# direct methods"); + wroteHeader = true; + } + writer.write('\n'); + // TODO: detect duplicate methods. + // TODO: check for method validation errors + + MethodImplementation methodImpl = method.getImplementation(); + if (methodImpl == null) { + MethodDefinition.writeEmptyMethodTo(writer, method); + } else { + MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl); + methodDefinition.writeTo(writer); + } + } + } + } + + private void writeVirtualMethods(IndentingWriter writer) throws IOException { + boolean wroteHeader = false; + for (Method method: classDef.getMethods()) { + int accessFlags = method.getAccessFlags(); + + if (!AccessFlags.STATIC.isSet(accessFlags) && + !AccessFlags.PRIVATE.isSet(accessFlags) && + !AccessFlags.CONSTRUCTOR.isSet(accessFlags)) { + if (!wroteHeader) { + writer.write("\n\n"); + writer.write("# virtual methods"); + wroteHeader = true; + } + writer.write('\n'); + // TODO: detect duplicate methods. + // TODO: check for method validation errors + + MethodImplementation methodImpl = method.getImplementation(); + if (methodImpl == null) { + MethodDefinition.writeEmptyMethodTo(writer, method); + } else { + MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl); + methodDefinition.writeTo(writer); + } + } + } + } + //TODO: uncomment /*private void writeDirectMethods(IndentingWriter writer) throws IOException { if (classDataItem == null) { diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/BeginEpilogueMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/BeginEpilogueMethodItem.java new file mode 100644 index 00000000..a1294fcb --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/BeginEpilogueMethodItem.java @@ -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; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/DebugMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/DebugMethodItem.java new file mode 100644 index 00000000..86d30f97 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/DebugMethodItem.java @@ -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()); + } + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndLocalMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndLocalMethodItem.java new file mode 100644 index 00000000..5f68259d --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndLocalMethodItem.java @@ -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; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndPrologueMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndPrologueMethodItem.java new file mode 100644 index 00000000..369c38fd --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndPrologueMethodItem.java @@ -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; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LineNumberMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LineNumberMethodItem.java new file mode 100644 index 00000000..96dbd8d9 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LineNumberMethodItem.java @@ -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; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/RestartLocalMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/RestartLocalMethodItem.java new file mode 100644 index 00000000..7f3d397a --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/RestartLocalMethodItem.java @@ -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; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/SetSourceFileMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/SetSourceFileMethodItem.java new file mode 100644 index 00000000..f28c42b3 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/SetSourceFileMethodItem.java @@ -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; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/StartLocalMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/StartLocalMethodItem.java new file mode 100644 index 00000000..c276abf0 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/StartLocalMethodItem.java @@ -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; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/DebugMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/DebugMethodItem.java deleted file mode 100644 index c611268f..00000000 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/DebugMethodItem.java +++ /dev/null @@ -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('"'); - } -} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java index 3595b388..d61b32ab 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java @@ -28,36 +28,44 @@ package org.jf.baksmali.Adaptors.Format; +import org.jf.baksmali.Adaptors.MethodDefinition; +import org.jf.baksmali.Renderers.LongRenderer; +import org.jf.dexlib2.iface.instruction.formats.ArrayPayload; import org.jf.util.IndentingWriter; -import org.jf.baksmali.Renderers.ByteRenderer; -import org.jf.dexlib.Code.Format.ArrayDataPseudoInstruction; -import org.jf.dexlib.CodeItem; import java.io.IOException; -import java.util.Iterator; +import java.util.List; -public class ArrayDataMethodItem extends InstructionMethodItem { - public ArrayDataMethodItem(CodeItem codeItem, int codeAddress, ArrayDataPseudoInstruction instruction) { - super(codeItem, codeAddress, instruction); +public class ArrayDataMethodItem extends InstructionMethodItem { + public ArrayDataMethodItem(MethodDefinition methodDef, int codeAddress, ArrayPayload instruction) { + super(methodDef, codeAddress, instruction); } public boolean writeTo(IndentingWriter writer) throws IOException { - writer.write(".array-data 0x"); - writer.printUnsignedLongAsHex(instruction.getElementWidth()); + int elementWidth = instruction.getElementWidth(); + + writer.write(".array-data "); + writer.printSignedIntAsDec(instruction.getElementWidth()); writer.write('\n'); writer.indent(4); - Iterator iterator = instruction.getElements(); - while (iterator.hasNext()) { - ArrayDataPseudoInstruction.ArrayElement element = iterator.next(); - for (int i=0; i elements = instruction.getArrayElements(); + + String suffix = ""; + switch (elementWidth) { + case 1: + suffix = "t"; + break; + case 2: + suffix = "s"; + break; + } + + for (Number number: instruction.getArrayElements()) { + LongRenderer.writeSignedIntOrLongTo(writer, number.longValue()); + writer.write(suffix); + writer.write("\n"); } writer.deindent(4); writer.write(".end array-data"); diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java index 643c3224..30127730 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java @@ -28,26 +28,25 @@ package org.jf.baksmali.Adaptors.Format; +import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.baksmali.Adaptors.MethodItem; import org.jf.baksmali.Adaptors.ReferenceFormatter; -import org.jf.baksmali.Adaptors.RegisterFormatter; -import org.jf.dexlib.Code.Format.Instruction20bc; import org.jf.dexlib.Code.Format.UnknownInstruction; +import org.jf.dexlib2.ReferenceType; +import org.jf.dexlib2.iface.instruction.*; import org.jf.util.IndentingWriter; import org.jf.baksmali.Renderers.LongRenderer; -import org.jf.dexlib.Code.*; -import org.jf.dexlib.CodeItem; -import org.jf.dexlib.Item; +import javax.annotation.Nonnull; import java.io.IOException; public class InstructionMethodItem extends MethodItem { - protected final CodeItem codeItem; - protected final T instruction; + @Nonnull protected final MethodDefinition methodDef; + @Nonnull protected final T instruction; - public InstructionMethodItem(CodeItem codeItem, int codeAddress, T instruction) { + public InstructionMethodItem(@Nonnull MethodDefinition methodDef, int codeAddress, @Nonnull T instruction) { super(codeAddress); - this.codeItem = codeItem; + this.methodDef = methodDef; this.instruction = instruction; } @@ -58,7 +57,7 @@ public class InstructionMethodItem extends MethodItem { @Override public boolean writeTo(IndentingWriter writer) throws IOException { - switch (instruction.getFormat()) { + switch (instruction.getOpcode().format) { case Format10t: writeOpcode(writer); writer.write(' '); @@ -91,13 +90,14 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeSecondRegister(writer); return true; - case Format20bc: + //TODO: uncomment + /*case Format20bc: writeOpcode(writer); writer.write(' '); writeVerificationErrorType(writer); writer.write(", "); writeReference(writer); - return true; + return true;*/ case Format20t: case Format30t: writeOpcode(writer); @@ -112,7 +112,8 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeReference(writer); return true; - case Format21h: + case Format21ih: + case Format21lh: case Format21s: case Format31i: case Format51l: @@ -149,7 +150,8 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeReference(writer); return true; - case Format22cs: + //TODO: uncomment + /*case Format22cs: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); @@ -157,7 +159,7 @@ public class InstructionMethodItem extends MethodItem { writeSecondRegister(writer); writer.write(", "); writeFieldOffset(writer); - return true; + return true;*/ case Format22t: writeOpcode(writer); writer.write(' '); @@ -191,7 +193,8 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeReference(writer); return true; - case Format35mi: + //TODO: uncomment + /*case Format35mi: writeOpcode(writer); writer.write(' '); writeInvokeRegisters(writer); @@ -204,7 +207,7 @@ public class InstructionMethodItem extends MethodItem { writeInvokeRegisters(writer); writer.write(", "); writeVtableIndex(writer); - return true; + return true;*/ case Format3rc: writeOpcode(writer); writer.write(' '); @@ -212,7 +215,8 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeReference(writer); return true; - case Format3rmi: + //TODO: uncomment + /*case Format3rmi: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); @@ -225,14 +229,14 @@ public class InstructionMethodItem extends MethodItem { writeInvokeRangeRegisters(writer); writer.write(", "); writeVtableIndex(writer); - return true; + return true;*/ } assert false; return false; } protected void writeOpcode(IndentingWriter writer) throws IOException { - writer.write(instruction.opcode.name); + writer.write(instruction.getOpcode().name); } protected void writeTargetLabel(IndentingWriter writer) throws IOException { @@ -242,11 +246,11 @@ public class InstructionMethodItem extends MethodItem { } protected void writeRegister(IndentingWriter writer, int registerNumber) throws IOException { - RegisterFormatter.writeTo(writer, codeItem, registerNumber); + methodDef.registerFormatter.writeTo(writer, registerNumber); } protected void writeFirstRegister(IndentingWriter writer) throws IOException { - writeRegister(writer, ((SingleRegisterInstruction)instruction).getRegisterA()); + writeRegister(writer, ((OneRegisterInstruction)instruction).getRegisterA()); } protected void writeSecondRegister(IndentingWriter writer) throws IOException { @@ -254,40 +258,42 @@ public class InstructionMethodItem extends MethodItem { } protected void writeThirdRegister(IndentingWriter writer) throws IOException { - writeRegister(writer, ((ThreeRegisterInstruction)instruction).getRegisterC()); + writeRegister(writer, ((ThreeRegisterInstruction) instruction).getRegisterC()); } protected void writeInvokeRegisters(IndentingWriter writer) throws IOException { FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction; - final int regCount = instruction.getRegCount(); + final int regCount = instruction.getRegisterCount(); writer.write('{'); switch (regCount) { case 1: - writeRegister(writer, instruction.getRegisterD()); + writeRegister(writer, instruction.getRegisterC()); break; case 2: - writeRegister(writer, instruction.getRegisterD()); + writeRegister(writer, instruction.getRegisterC()); writer.write(", "); - writeRegister(writer, instruction.getRegisterE()); + writeRegister(writer, instruction.getRegisterD()); break; case 3: + writeRegister(writer, instruction.getRegisterC()); + writer.write(", "); writeRegister(writer, instruction.getRegisterD()); writer.write(", "); writeRegister(writer, instruction.getRegisterE()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterF()); break; case 4: + writeRegister(writer, instruction.getRegisterC()); + writer.write(", "); writeRegister(writer, instruction.getRegisterD()); writer.write(", "); writeRegister(writer, instruction.getRegisterE()); writer.write(", "); writeRegister(writer, instruction.getRegisterF()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterG()); break; case 5: + writeRegister(writer, instruction.getRegisterC()); + writer.write(", "); writeRegister(writer, instruction.getRegisterD()); writer.write(", "); writeRegister(writer, instruction.getRegisterE()); @@ -295,8 +301,6 @@ public class InstructionMethodItem extends MethodItem { writeRegister(writer, instruction.getRegisterF()); writer.write(", "); writeRegister(writer, instruction.getRegisterG()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterA()); break; } writer.write('}'); @@ -305,20 +309,21 @@ public class InstructionMethodItem extends MethodItem { protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException { RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction; - int regCount = instruction.getRegCount(); + int regCount = instruction.getRegisterCount(); if (regCount == 0) { writer.write("{}"); } else { int startRegister = instruction.getStartRegister(); - RegisterFormatter.writeRegisterRange(writer, codeItem, startRegister, startRegister+regCount-1); + methodDef.registerFormatter.writeRegisterRange(writer, startRegister, startRegister+regCount-1); } } protected void writeLiteral(IndentingWriter writer) throws IOException { - LongRenderer.writeSignedIntOrLongTo(writer, ((LiteralInstruction)instruction).getLiteral()); + LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral()); } - protected void writeFieldOffset(IndentingWriter writer) throws IOException { + //TODO: uncomment + /*protected void writeFieldOffset(IndentingWriter writer) throws IOException { writer.write("field@0x"); writer.printUnsignedLongAsHex(((OdexedFieldAccess) instruction).getFieldOffset()); } @@ -331,15 +336,20 @@ public class InstructionMethodItem extends MethodItem { protected void writeVtableIndex(IndentingWriter writer) throws IOException { writer.write("vtable@0x"); writer.printUnsignedLongAsHex(((OdexedInvokeVirtual) instruction).getVtableIndex()); - } + }*/ protected void writeReference(IndentingWriter writer) throws IOException { - Item item = ((InstructionWithReference)instruction).getReferencedItem(); - ReferenceFormatter.writeReference(writer, item); + String reference = ((ReferenceInstruction)instruction).getReference(); + if (instruction.getOpcode().referenceType == ReferenceType.STRING) { + ReferenceFormatter.writeStringReference(writer, reference); + } else { + writer.write(reference); + } } - protected void writeVerificationErrorType(IndentingWriter writer) throws IOException { + //TODO: uncomment + /*protected void writeVerificationErrorType(IndentingWriter writer) throws IOException { VerificationErrorType validationErrorType = ((Instruction20bc)instruction).getValidationErrorType(); writer.write(validationErrorType.getName()); - } + }*/ } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItemFactory.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItemFactory.java index 772d7311..54fdda10 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItemFactory.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItemFactory.java @@ -29,37 +29,36 @@ package org.jf.baksmali.Adaptors.Format; import org.jf.baksmali.Adaptors.MethodDefinition; -import org.jf.dexlib.Code.Format.*; -import org.jf.dexlib.Code.Instruction; -import org.jf.dexlib.Code.OffsetInstruction; -import org.jf.dexlib.CodeItem; +import org.jf.dexlib2.iface.instruction.Instruction; +import org.jf.dexlib2.iface.instruction.OffsetInstruction; +import org.jf.dexlib2.iface.instruction.formats.ArrayPayload; +import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload; +import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload; public class InstructionMethodItemFactory { private InstructionMethodItemFactory() { } public static InstructionMethodItem makeInstructionFormatMethodItem( - MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, Instruction instruction) { + MethodDefinition methodDef, int codeAddress, Instruction instruction) { + if (instruction instanceof OffsetInstruction) { - return new OffsetInstructionFormatMethodItem(methodDefinition.getLabelCache(), codeItem, - codeAddress, (OffsetInstruction)instruction); + return new OffsetInstructionFormatMethodItem(methodDef, codeAddress, (OffsetInstruction)instruction); } - switch (instruction.getFormat()) { - case ArrayData: - return new ArrayDataMethodItem(codeItem, codeAddress, - (ArrayDataPseudoInstruction)instruction); - case PackedSwitchData: - return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress, - (PackedSwitchDataPseudoInstruction)instruction); - case SparseSwitchData: - return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress, - (SparseSwitchDataPseudoInstruction)instruction); - case UnresolvedOdexInstruction: + switch (instruction.getOpcode().format) { + case ArrayPayload: + return new ArrayDataMethodItem(methodDef, codeAddress, (ArrayPayload)instruction); + case PackedSwitchPayload: + return new PackedSwitchMethodItem(methodDef, codeAddress, (PackedSwitchPayload)instruction); + case SparseSwitchPayload: + return new SparseSwitchMethodItem(methodDef, codeAddress, (SparseSwitchPayload)instruction); + //TODO: uncomment + /*case UnresolvedOdexInstruction: return new UnresolvedOdexInstructionMethodItem(codeItem, codeAddress, - (UnresolvedOdexInstruction)instruction); + (UnresolvedOdexInstruction)instruction);*/ default: - return new InstructionMethodItem(codeItem, codeAddress, instruction); + return new InstructionMethodItem(methodDef, codeAddress, instruction); } } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/OffsetInstructionFormatMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/OffsetInstructionFormatMethodItem.java index d4edf3d0..1bd867fd 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/OffsetInstructionFormatMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/OffsetInstructionFormatMethodItem.java @@ -30,22 +30,21 @@ package org.jf.baksmali.Adaptors.Format; import org.jf.baksmali.Adaptors.LabelMethodItem; import org.jf.baksmali.Adaptors.MethodDefinition; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.iface.instruction.OffsetInstruction; import org.jf.util.IndentingWriter; -import org.jf.dexlib.Code.OffsetInstruction; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.CodeItem; import java.io.IOException; public class OffsetInstructionFormatMethodItem extends InstructionMethodItem { protected LabelMethodItem label; - public OffsetInstructionFormatMethodItem(MethodDefinition.LabelCache labelCache, CodeItem codeItem, int codeAddress, + public OffsetInstructionFormatMethodItem(MethodDefinition methodDef, int codeAddress, OffsetInstruction instruction) { - super(codeItem, codeAddress, instruction); + super(methodDef, codeAddress, instruction); - label = new LabelMethodItem(codeAddress + instruction.getTargetAddressOffset(), getLabelPrefix()); - label = labelCache.internLabel(label); + label = new LabelMethodItem(codeAddress + instruction.getCodeOffset(), getLabelPrefix()); + label = methodDef.getLabelCache().internLabel(label); } @Override @@ -58,7 +57,8 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem { +public class PackedSwitchMethodItem extends InstructionMethodItem { private final List targets; + private final int firstKey; - public PackedSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, - PackedSwitchDataPseudoInstruction instruction) { - super(codeItem, codeAddress, instruction); + public PackedSwitchMethodItem(MethodDefinition methodDef, int codeAddress, PackedSwitchPayload instruction) { + super(methodDef, codeAddress, instruction); - int baseCodeAddress = methodDefinition.getPackedSwitchBaseAddress(codeAddress); + int baseCodeAddress = methodDef.getPackedSwitchBaseAddress(codeAddress); targets = new ArrayList(); - Iterator iterator = instruction.iterateKeysAndTargets(); + boolean first = true; + //TODO: does dalvik allow switc payloads with no cases? + int firstKey = 0; if (baseCodeAddress >= 0) { - while (iterator.hasNext()) { - PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next(); - PackedSwitchLabelTarget packedSwitchLabelTarget = new PackedSwitchLabelTarget(); - - - LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "pswitch_"); - label = methodDefinition.getLabelCache().internLabel(label); - packedSwitchLabelTarget.Target = label; - targets.add(packedSwitchLabelTarget); + for (SwitchElement switchElement: instruction.getSwitchElements()) { + if (first) { + firstKey = switchElement.getKey(); + first = false; + } + LabelMethodItem label = new LabelMethodItem(baseCodeAddress + switchElement.getOffset(), "pswitch_"); + targets.add(new PackedSwitchLabelTarget(label)); } } else { - while (iterator.hasNext()) { - PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next(); - PackedSwitchOffsetTarget packedSwitchOffsetTarget = new PackedSwitchOffsetTarget(); - - - packedSwitchOffsetTarget.Target = target.targetAddressOffset; - targets.add(packedSwitchOffsetTarget); + for (SwitchElement switchElement: instruction.getSwitchElements()) { + if (first) { + firstKey = switchElement.getKey(); + first = false; + } + targets.add(new PackedSwitchOffsetTarget(switchElement.getOffset())); } } + this.firstKey = firstKey; } @Override public boolean writeTo(IndentingWriter writer) throws IOException { writer.write(".packed-switch "); - IntegerRenderer.writeTo(writer, instruction.getFirstKey()); + IntegerRenderer.writeTo(writer, firstKey); writer.indent(4); writer.write('\n'); for (PackedSwitchTarget target: targets) { @@ -95,19 +94,25 @@ public class PackedSwitchMethodItem extends InstructionMethodItem= 0) { + if (target >= 0) { writer.write('+'); } - writer.printSignedIntAsDec(Target); + writer.printSignedIntAsDec(target); } } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/SparseSwitchMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/SparseSwitchMethodItem.java index 46f49dc2..caa1268c 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/SparseSwitchMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/SparseSwitchMethodItem.java @@ -30,48 +30,33 @@ package org.jf.baksmali.Adaptors.Format; import org.jf.baksmali.Adaptors.LabelMethodItem; import org.jf.baksmali.Adaptors.MethodDefinition; +import org.jf.dexlib2.iface.instruction.SwitchElement; +import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload; import org.jf.util.IndentingWriter; import org.jf.baksmali.Renderers.IntegerRenderer; -import org.jf.dexlib.Code.Format.SparseSwitchDataPseudoInstruction; -import org.jf.dexlib.CodeItem; import java.io.IOException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -public class SparseSwitchMethodItem extends InstructionMethodItem { +public class SparseSwitchMethodItem extends InstructionMethodItem { private final List targets; - public SparseSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, - SparseSwitchDataPseudoInstruction instruction) { - super(codeItem, codeAddress, instruction); + public SparseSwitchMethodItem(MethodDefinition methodDef, int codeAddress, SparseSwitchPayload instruction) { + super(methodDef, codeAddress, instruction); - int baseCodeAddress = methodDefinition.getSparseSwitchBaseAddress(codeAddress); + int baseCodeAddress = methodDef.getSparseSwitchBaseAddress(codeAddress); targets = new ArrayList(); - Iterator iterator = instruction.iterateKeysAndTargets(); if (baseCodeAddress >= 0) { - while (iterator.hasNext()) { - SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next(); - SparseSwitchLabelTarget sparseSwitchLabelTarget = new SparseSwitchLabelTarget(); - sparseSwitchLabelTarget.Key = target.key; - - LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "sswitch_"); - label = methodDefinition.getLabelCache().internLabel(label); - sparseSwitchLabelTarget.Target = label; - - targets.add(sparseSwitchLabelTarget); + for (SwitchElement switchElement: instruction.getSwitchElements()) { + LabelMethodItem label = new LabelMethodItem(baseCodeAddress + switchElement.getOffset(), "sswitch_"); + targets.add(new SparseSwitchLabelTarget(switchElement.getKey(), label)); } } else { //if we couldn't determine a base address, just use relative offsets rather than labels - while (iterator.hasNext()) { - SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next(); - SparseSwitchOffsetTarget sparseSwitchOffsetTarget = new SparseSwitchOffsetTarget(); - sparseSwitchOffsetTarget.Key = target.key; - - sparseSwitchOffsetTarget.Target = target.targetAddressOffset; - targets.add(sparseSwitchOffsetTarget); + for (SwitchElement switchElement: instruction.getSwitchElements()) { + targets.add(new SparseSwitchOffsetTarget(switchElement.getKey(), switchElement.getOffset())); } } } @@ -81,7 +66,7 @@ public class SparseSwitchMethodItem extends InstructionMethodItem "); target.writeTargetTo(writer); writer.write('\n'); @@ -92,24 +77,38 @@ public class SparseSwitchMethodItem extends InstructionMethodItem= 0) { + if (target >= 0) { writer.write('+'); } - writer.printSignedIntAsDec(Target); + writer.printSignedIntAsDec(target); } } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedOdexInstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedOdexInstructionMethodItem.java index 5451a203..e257ad63 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedOdexInstructionMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedOdexInstructionMethodItem.java @@ -34,7 +34,8 @@ import org.jf.dexlib.CodeItem; import java.io.IOException; -public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem { +//TODO: uncomment +/*public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem { public UnresolvedOdexInstructionMethodItem(CodeItem codeItem, int codeAddress, UnresolvedOdexInstruction instruction) { super(codeItem, codeAddress, instruction); } @@ -49,4 +50,4 @@ public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem instructions = methodImpl.getInstructions(); - packedSwitchMap = new SparseIntArray(1); - sparseSwitchMap = new SparseIntArray(1); - instructionMap = new SparseIntArray(instructions.length); + packedSwitchMap = new SparseIntArray(0); + sparseSwitchMap = new SparseIntArray(0); + instructionOffsetMap = new InstructionOffsetMap(methodImpl); - int currentCodeAddress = 0; - for (int i=0; i instructions = methodImpl.getInstructions(); + Instruction instruction = instructions.get(targetIndex); + if (instruction.getOpcode() != type) { + // maybe it's pointing to a NOP padding instruction. Look at the next instruction + if (instruction.getOpcode() == Opcode.NOP) { + targetIndex += 1; + if (targetIndex < instructions.size()) { + instruction = instructions.get(targetIndex); + if (instruction.getOpcode() == type) { + return instructionOffsetMap.getInstructionCodeOffset(targetIndex); + } + } } - return totalRegisters - parameterRegisters; + throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset); + } else { + return targetOffset; } - return totalRegisters; } - private static void writeAccessFlags(IndentingWriter writer, ClassDataItem.EncodedMethod encodedMethod) - throws IOException { - for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) { + private static void writeAccessFlags(IndentingWriter writer, int accessFlags) + throws IOException { + for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(accessFlags)) { writer.write(accessFlag.toString()); writer.write(' '); } } - private static void writeParameters(IndentingWriter writer, CodeItem codeItem, - AnnotationSetRefList parameterAnnotations) throws IOException { - DebugInfoItem debugInfoItem = null; - if (baksmali.outputDebugInfo && codeItem != null) { - debugInfoItem = codeItem.getDebugInfo(); - } - - int parameterCount = 0; - AnnotationSetItem[] annotations; - StringIdItem[] parameterNames = null; - - if (parameterAnnotations != null) { - annotations = parameterAnnotations.getAnnotationSets(); - parameterCount = annotations.length; - } else { - annotations = new AnnotationSetItem[0]; - } - - if (debugInfoItem != null) { - parameterNames = debugInfoItem.getParameterNames(); - } - if (parameterNames == null) { - parameterNames = new StringIdItem[0]; - } - - if (parameterCount < parameterNames.length) { - parameterCount = parameterNames.length; - } - - for (int i=0; i parameters) throws IOException { + int registerNumber = 0; + for (MethodParameter parameter: parameters) { + String parameterType = parameter.getType(); + String parameterName = parameter.getName(); + List annotations = parameter.getAnnotations(); + if (parameterName != null || annotations.size() != 0) { + writer.write(".parameter p"); + writer.printSignedIntAsDec(registerNumber); + if (parameterName != null) { + writer.write(" "); + writer.write(parameterName); + } + if (annotations.size() > 0) { + writer.indent(4); + AnnotationFormatter.writeTo(writer, annotations); + writer.deindent(4); + writer.write(".end parameter\n"); + } else { + writer.write("\n"); + } } - StringIdItem parameterName = null; - if (i < parameterNames.length) { - parameterName = parameterNames[i]; + registerNumber++; + if (TypeUtils.isWideType(parameterType)) { + registerNumber++; } - - writer.write(".parameter"); - - if (parameterName != null) { - writer.write(" \""); - writer.write(parameterName.getStringValue()); - writer.write('"'); - } - - writer.write('\n'); - //TODO: uncomment - /*if (annotationSet != null) { - writer.indent(4); - AnnotationFormatter.writeTo(writer, annotationSet); - writer.deindent(4); - - writer.write(".end parameter\n"); - }*/ } } - public LabelCache getLabelCache() { + @Nonnull public LabelCache getLabelCache() { return labelCache; } - public ValidationException getValidationException() { - if (methodAnalyzer == null) { - return null; - } - - return methodAnalyzer.getValidationException(); + public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) { + return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1); } - public int getPackedSwitchBaseAddress(int packedSwitchDataAddress) { - int packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress, -1); - - if (packedSwitchBaseAddress == -1) { - Instruction[] instructions = encodedMethod.codeItem.getInstructions(); - int index = instructionMap.get(packedSwitchDataAddress); - - if (instructions[index].opcode == Opcode.NOP) { - packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress+2, -1); - } - } - - return packedSwitchBaseAddress; - } - - public int getSparseSwitchBaseAddress(int sparseSwitchDataAddress) { - int sparseSwitchBaseAddress = this.sparseSwitchMap.get(sparseSwitchDataAddress, -1); - - if (sparseSwitchBaseAddress == -1) { - Instruction[] instructions = encodedMethod.codeItem.getInstructions(); - int index = instructionMap.get(sparseSwitchDataAddress); - - if (instructions[index].opcode == Opcode.NOP) { - sparseSwitchBaseAddress = this.packedSwitchMap.get(sparseSwitchDataAddress+2, -1); - } - } - - return sparseSwitchBaseAddress; - } - - /** - * @param instructions The instructions array for this method - * @param instruction The instruction - * @return true if the specified instruction is a NOP, and the next instruction is one of the variable sized - * switch/array data structures - */ - private boolean isInstructionPaddingNop(List instructions, AnalyzedInstruction instruction) { - if (instruction.getInstruction().opcode != Opcode.NOP || - instruction.getInstruction().getFormat().variableSizeFormat) { - - return false; - } - - if (instruction.getInstructionIndex() == instructions.size()-1) { - return false; - } - - AnalyzedInstruction nextInstruction = instructions.get(instruction.getInstructionIndex()+1); - if (nextInstruction.getInstruction().getFormat().variableSizeFormat) { - return true; - } - return false; - } - - private boolean needsAnalyzed() { - for (Instruction instruction: encodedMethod.codeItem.getInstructions()) { - if (instruction.opcode.odexOnly()) { - return true; - } - } - return false; + public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) { + return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1); } private List getMethodItems() { ArrayList methodItems = new ArrayList(); - if (encodedMethod.codeItem == null) { - return methodItems; - } - - if ((baksmali.registerInfo != 0) || baksmali.verify || - (baksmali.deodex && needsAnalyzed())) { - addAnalyzedInstructionMethodItems(methodItems); - } else { - addInstructionMethodItems(methodItems); - } + //TODO: addAnalyzedInstructionMethodItems + addInstructionMethodItems(methodItems); addTries(methodItems); if (baksmali.outputDebugInfo) { @@ -335,18 +270,18 @@ public class MethodDefinition { } private void addInstructionMethodItems(List methodItems) { - Instruction[] instructions = encodedMethod.codeItem.getInstructions(); + List instructions = methodImpl.getInstructions(); int currentCodeAddress = 0; - for (int i=0; i methodItems) { + //TODO: uncomment + /*private void addAnalyzedInstructionMethodItems(List methodItems) { methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver); methodAnalyzer.analyze(); @@ -455,20 +393,21 @@ public class MethodDefinition { currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress); } - } + }*/ private void addTries(List methodItems) { - if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) { + List tryBlocks = methodImpl.getTryBlocks(); + if (tryBlocks.size() == 0) { return; } - Instruction[] instructions = encodedMethod.codeItem.getInstructions(); - int lastInstructionAddress = instructionMap.keyAt(instructionMap.size()-1); - int codeSize = lastInstructionAddress + instructions[instructions.length - 1].getSize(lastInstructionAddress); + List instructions = methodImpl.getInstructions(); + int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1); + int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits(); - for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) { - int startAddress = tryItem.getStartCodeAddress(); - int endAddress = tryItem.getStartCodeAddress() + tryItem.getTryLength(); + for (TryBlock tryBlock: tryBlocks) { + int startAddress = tryBlock.getStartCodeOffset(); + int endAddress = startAddress + tryBlock.getCodeUnitCount(); if (startAddress >= codeSize) { throw new RuntimeException(String.format("Try start offset %d is past the end of the code block.", @@ -487,142 +426,28 @@ public class MethodDefinition { * the address for that instruction */ - int lastCoveredIndex = instructionMap.getClosestSmaller(endAddress-1); - int lastCoveredAddress = instructionMap.keyAt(lastCoveredIndex); + int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false); + int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex); - //add the catch all handler if it exists - int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress(); - if (catchAllAddress != -1) { - if (catchAllAddress >= codeSize) { - throw new RuntimeException(String.format( - "Catch all handler offset %d is past the end of the code block.", catchAllAddress)); - } - - CatchMethodItem catchAllMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress, null, - startAddress, endAddress, catchAllAddress); - methodItems.add(catchAllMethodItem); - } - - //add the rest of the handlers - for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) { - if (handler.getHandlerAddress() >= codeSize) { - throw new RuntimeException(String.format( - "Exception handler offset %d is past the end of the code block.", catchAllAddress)); + for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) { + int handlerOffset = handler.getHandlerCodeOffset(); + if (handlerOffset >= codeSize) { + throw new ExceptionWithContext( + "Exception handler offset %d is past the end of the code block.", handlerOffset); } //use the address from the last covered instruction CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress, - handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress()); + handler.getExceptionType(), startAddress, endAddress, handlerOffset); methodItems.add(catchMethodItem); } } } private void addDebugInfo(final List methodItems) { - if (encodedMethod.codeItem == null || encodedMethod.codeItem.getDebugInfo() == null) { - return; + for (DebugItem debugItem: methodImpl.getDebugItems()) { + methodItems.add(DebugMethodItem.build(registerFormatter, debugItem)); } - - final CodeItem codeItem = encodedMethod.codeItem; - DebugInfoItem debugInfoItem = codeItem.getDebugInfo(); - - DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(), - new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() { - @Override - public void ProcessStartLocal(final int codeAddress, final int length, final int registerNum, - final StringIdItem name, final TypeIdItem type) { - methodItems.add(new DebugMethodItem(codeAddress, -1) { - @Override - public boolean writeTo(IndentingWriter writer) throws IOException { - writeStartLocal(writer, codeItem, registerNum, name, type, null); - return true; - } - }); - } - - @Override - public void ProcessStartLocalExtended(final int codeAddress, final int length, - final int registerNum, final StringIdItem name, - final TypeIdItem type, final StringIdItem signature) { - methodItems.add(new DebugMethodItem(codeAddress, -1) { - @Override - public boolean writeTo(IndentingWriter writer) throws IOException { - writeStartLocal(writer, codeItem, registerNum, name, type, signature); - return true; - } - }); - } - - @Override - public void ProcessEndLocal(final int codeAddress, final int length, final int registerNum, - final StringIdItem name, final TypeIdItem type, - final StringIdItem signature) { - methodItems.add(new DebugMethodItem(codeAddress, -1) { - @Override - public boolean writeTo(IndentingWriter writer) throws IOException { - writeEndLocal(writer, codeItem, registerNum, name, type, signature); - return true; - } - }); - } - - @Override - public void ProcessRestartLocal(final int codeAddress, final int length, final int registerNum, - final StringIdItem name, final TypeIdItem type, - final StringIdItem signature) { - methodItems.add(new DebugMethodItem(codeAddress, -1) { - @Override - public boolean writeTo(IndentingWriter writer) throws IOException { - writeRestartLocal(writer, codeItem, registerNum, name, type, signature); - return true; - } - }); - } - - @Override - public void ProcessSetPrologueEnd(int codeAddress) { - methodItems.add(new DebugMethodItem(codeAddress, -4) { - @Override - public boolean writeTo(IndentingWriter writer) throws IOException { - writeEndPrologue(writer); - return true; - } - }); - } - - @Override - public void ProcessSetEpilogueBegin(int codeAddress) { - methodItems.add(new DebugMethodItem(codeAddress, -4) { - @Override - public boolean writeTo(IndentingWriter writer) throws IOException { - writeBeginEpilogue(writer); - return true; - } - }); - } - - @Override - public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) { - methodItems.add(new DebugMethodItem(codeAddress, -3) { - @Override - public boolean writeTo(IndentingWriter writer) throws IOException { - writeSetFile(writer, name.getStringValue()); - return true; - } - }); - } - - @Override - public void ProcessLineEmit(int codeAddress, final int line) { - methodItems.add(new DebugMethodItem(codeAddress, -2) { - @Override - public boolean writeTo(IndentingWriter writer) throws IOException { - writeLine(writer, line); - return true; - } - }); - } - }); } private void setLabelSequentialNumbers() { diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PostInstructionRegisterInfoMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PostInstructionRegisterInfoMethodItem.java index d4179603..c067aa4a 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PostInstructionRegisterInfoMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PostInstructionRegisterInfoMethodItem.java @@ -39,7 +39,8 @@ import org.jf.dexlib.Code.Analysis.RegisterType; import java.io.IOException; import java.util.BitSet; -public class PostInstructionRegisterInfoMethodItem extends MethodItem { +//TODO: uncomment +/*public class PostInstructionRegisterInfoMethodItem extends MethodItem { private final AnalyzedInstruction analyzedInstruction; private final MethodAnalyzer methodAnalyzer; @@ -108,4 +109,4 @@ public class PostInstructionRegisterInfoMethodItem extends MethodItem { } return true; } -} +}*/ diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java index ab99f436..fa3c3d3c 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java @@ -41,7 +41,8 @@ import org.jf.dexlib.Util.AccessFlags; import java.io.IOException; import java.util.BitSet; -public class PreInstructionRegisterInfoMethodItem extends MethodItem { +//TODO: uncomment +/*public class PreInstructionRegisterInfoMethodItem extends MethodItem { private final AnalyzedInstruction analyzedInstruction; private final MethodAnalyzer methodAnalyzer; @@ -262,4 +263,4 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem { } return true; } -} +}*/ diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java index 317fc8c1..92bbc095 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java @@ -35,45 +35,9 @@ import org.jf.util.StringUtils; import java.io.IOException; public class ReferenceFormatter { - public static void writeReference(IndentingWriter writer, Item item) throws IOException { - switch (item.getItemType()) { - case TYPE_METHOD_ID_ITEM: - writeMethodReference(writer, (MethodIdItem)item); - return; - case TYPE_FIELD_ID_ITEM: - writeFieldReference(writer, (FieldIdItem)item); - return; - case TYPE_STRING_ID_ITEM: - writeStringReference(writer, ((StringIdItem)item).getStringValue()); - return; - case TYPE_TYPE_ID_ITEM: - writeTypeReference(writer, (TypeIdItem)item); - return; - } - } - - public static void writeMethodReference(IndentingWriter writer, MethodIdItem item) throws IOException { - writer.write(item.getContainingClass().getTypeDescriptor()); - writer.write("->"); - writer.write(item.getMethodName().getStringValue()); - writer.write(item.getPrototype().getPrototypeString()); - } - - public static void writeFieldReference(IndentingWriter writer, FieldIdItem item) throws IOException { - writer.write(item.getContainingClass().getTypeDescriptor()); - writer.write("->"); - writer.write(item.getFieldName().getStringValue()); - writer.write(':'); - writer.write(item.getFieldType().getTypeDescriptor()); - } - public static void writeStringReference(IndentingWriter writer, String item) throws IOException { writer.write('"'); StringUtils.writeEscapedString(writer, item); writer.write('"'); } - - public static void writeTypeReference(IndentingWriter writer, TypeIdItem item) throws IOException { - writer.write(item.getTypeDescriptor()); - } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java index 35c620d5..28717b92 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java @@ -28,6 +28,7 @@ package org.jf.baksmali.Adaptors; +import com.google.common.base.Preconditions; import org.jf.util.IndentingWriter; import org.jf.baksmali.baksmali; import org.jf.dexlib.CodeItem; @@ -39,6 +40,13 @@ import java.io.IOException; * This class contains the logic used for formatting registers */ public class RegisterFormatter { + public final int registerCount; + public final int parameterRegisterCount; + + public RegisterFormatter(int registerCount, int parameterRegisterCount) { + this.registerCount = registerCount; + this.parameterRegisterCount = parameterRegisterCount; + } /** * Write out the register range value used by Format3rc. If baksmali.noParameterRegisters is true, it will always @@ -46,19 +54,11 @@ public class RegisterFormatter { * registers, and if so, use the p format for both. If only the last register is a parameter register, it will * use the v format for both, otherwise it would be confusing to have something like {v20 .. p1} * @param writer the IndentingWriter to write to - * @param codeItem the CodeItem that the register is from * @param startRegister the first register in the range * @param lastRegister the last register in the range */ - public static void writeRegisterRange(IndentingWriter writer, CodeItem codeItem, int startRegister, - int lastRegister) throws IOException { - assert lastRegister >= startRegister; - + public void writeRegisterRange(IndentingWriter writer, int startRegister, int lastRegister) throws IOException { if (!baksmali.noParameterRegisters) { - int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount() - + (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0); - int registerCount = codeItem.getRegisterCount(); - assert startRegister <= lastRegister; if (startRegister >= registerCount - parameterRegisterCount) { @@ -83,14 +83,10 @@ public class RegisterFormatter { * and if so, formats it in the p format instead. * * @param writer the IndentingWriter to write to - * @param codeItem the CodeItem that the register is from * @param register the register number */ - public static void writeTo(IndentingWriter writer, CodeItem codeItem, int register) throws IOException { + public void writeTo(IndentingWriter writer, int register) throws IOException { if (!baksmali.noParameterRegisters) { - int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount() - + (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0); - int registerCount = codeItem.getRegisterCount(); if (register >= registerCount - parameterRegisterCount) { writer.write('p'); writer.printSignedIntAsDec((register - (registerCount - parameterRegisterCount))); diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/SyntheticAccessCommentMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/SyntheticAccessCommentMethodItem.java index 1a30e08e..5e6cded0 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/SyntheticAccessCommentMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/SyntheticAccessCommentMethodItem.java @@ -34,7 +34,8 @@ import org.jf.util.IndentingWriter; import java.io.IOException; -public class SyntheticAccessCommentMethodItem extends MethodItem { +//TODO: uncomment +/*public class SyntheticAccessCommentMethodItem extends MethodItem { private final AccessedMember accessedMember; public SyntheticAccessCommentMethodItem(AccessedMember accessedMember, int codeAddress) { @@ -59,4 +60,4 @@ public class SyntheticAccessCommentMethodItem extends MethodItem { ReferenceFormatter.writeReference(writer, accessedMember.accessedMember); return true; } -} +}*/ diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java b/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java new file mode 100644 index 00000000..14e54be8 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java @@ -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(); + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java b/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java new file mode 100644 index 00000000..dbc88879 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java @@ -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'; + } +}