mirror of
https://github.com/revanced/smali.git
synced 2025-05-11 20:04:28 +02:00
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:
parent
ba114e7211
commit
754b3c4dc0
@ -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);
|
||||
|
@ -41,7 +41,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class ClassDefinition {
|
||||
@Nonnull private final ClassDef classDef;
|
||||
@Nonnull public final ClassDef classDef;
|
||||
@Nonnull private final HashSet<String> fieldsSetInStaticConstructor;
|
||||
|
||||
protected boolean validationErrors;
|
||||
@ -95,8 +95,8 @@ public class ClassDefinition {
|
||||
writeAnnotations(writer);
|
||||
writeStaticFields(writer);
|
||||
writeInstanceFields(writer);
|
||||
/*writeDirectMethods(writer);
|
||||
writeVirtualMethods(writer);*/
|
||||
writeDirectMethods(writer);
|
||||
writeVirtualMethods(writer);
|
||||
}
|
||||
|
||||
private void writeClass(IndentingWriter writer) throws IOException {
|
||||
@ -189,6 +189,62 @@ public class ClassDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDirectMethods(IndentingWriter writer) throws IOException {
|
||||
boolean wroteHeader = false;
|
||||
for (Method method: classDef.getMethods()) {
|
||||
int accessFlags = method.getAccessFlags();
|
||||
|
||||
if (AccessFlags.STATIC.isSet(accessFlags) ||
|
||||
AccessFlags.PRIVATE.isSet(accessFlags) ||
|
||||
AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
||||
if (!wroteHeader) {
|
||||
writer.write("\n\n");
|
||||
writer.write("# direct methods");
|
||||
wroteHeader = true;
|
||||
}
|
||||
writer.write('\n');
|
||||
// TODO: detect duplicate methods.
|
||||
// TODO: check for method validation errors
|
||||
|
||||
MethodImplementation methodImpl = method.getImplementation();
|
||||
if (methodImpl == null) {
|
||||
MethodDefinition.writeEmptyMethodTo(writer, method);
|
||||
} else {
|
||||
MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl);
|
||||
methodDefinition.writeTo(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeVirtualMethods(IndentingWriter writer) throws IOException {
|
||||
boolean wroteHeader = false;
|
||||
for (Method method: classDef.getMethods()) {
|
||||
int accessFlags = method.getAccessFlags();
|
||||
|
||||
if (!AccessFlags.STATIC.isSet(accessFlags) &&
|
||||
!AccessFlags.PRIVATE.isSet(accessFlags) &&
|
||||
!AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
||||
if (!wroteHeader) {
|
||||
writer.write("\n\n");
|
||||
writer.write("# virtual methods");
|
||||
wroteHeader = true;
|
||||
}
|
||||
writer.write('\n');
|
||||
// TODO: detect duplicate methods.
|
||||
// TODO: check for method validation errors
|
||||
|
||||
MethodImplementation methodImpl = method.getImplementation();
|
||||
if (methodImpl == null) {
|
||||
MethodDefinition.writeEmptyMethodTo(writer, method);
|
||||
} else {
|
||||
MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl);
|
||||
methodDefinition.writeTo(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: uncomment
|
||||
/*private void writeDirectMethods(IndentingWriter writer) throws IOException {
|
||||
if (classDataItem == null) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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('"');
|
||||
}
|
||||
}
|
@ -28,36 +28,44 @@
|
||||
|
||||
package org.jf.baksmali.Adaptors.Format;
|
||||
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.baksmali.Renderers.LongRenderer;
|
||||
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.jf.baksmali.Renderers.ByteRenderer;
|
||||
import org.jf.dexlib.Code.Format.ArrayDataPseudoInstruction;
|
||||
import org.jf.dexlib.CodeItem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayDataPseudoInstruction> {
|
||||
public ArrayDataMethodItem(CodeItem codeItem, int codeAddress, ArrayDataPseudoInstruction instruction) {
|
||||
super(codeItem, codeAddress, instruction);
|
||||
public class ArrayDataMethodItem extends InstructionMethodItem<ArrayPayload> {
|
||||
public ArrayDataMethodItem(MethodDefinition methodDef, int codeAddress, ArrayPayload instruction) {
|
||||
super(methodDef, codeAddress, instruction);
|
||||
}
|
||||
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writer.write(".array-data 0x");
|
||||
writer.printUnsignedLongAsHex(instruction.getElementWidth());
|
||||
int elementWidth = instruction.getElementWidth();
|
||||
|
||||
writer.write(".array-data ");
|
||||
writer.printSignedIntAsDec(instruction.getElementWidth());
|
||||
writer.write('\n');
|
||||
|
||||
writer.indent(4);
|
||||
Iterator<ArrayDataPseudoInstruction.ArrayElement> iterator = instruction.getElements();
|
||||
while (iterator.hasNext()) {
|
||||
ArrayDataPseudoInstruction.ArrayElement element = iterator.next();
|
||||
|
||||
for (int i=0; i<element.elementWidth; i++) {
|
||||
if (i!=0) {
|
||||
writer.write(' ');
|
||||
}
|
||||
ByteRenderer.writeUnsignedTo(writer, element.buffer[element.bufferIndex+i]);
|
||||
}
|
||||
writer.write('\n');
|
||||
List<Number> elements = instruction.getArrayElements();
|
||||
|
||||
String suffix = "";
|
||||
switch (elementWidth) {
|
||||
case 1:
|
||||
suffix = "t";
|
||||
break;
|
||||
case 2:
|
||||
suffix = "s";
|
||||
break;
|
||||
}
|
||||
|
||||
for (Number number: instruction.getArrayElements()) {
|
||||
LongRenderer.writeSignedIntOrLongTo(writer, number.longValue());
|
||||
writer.write(suffix);
|
||||
writer.write("\n");
|
||||
}
|
||||
writer.deindent(4);
|
||||
writer.write(".end array-data");
|
||||
|
@ -28,26 +28,25 @@
|
||||
|
||||
package org.jf.baksmali.Adaptors.Format;
|
||||
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.baksmali.Adaptors.MethodItem;
|
||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
||||
import org.jf.baksmali.Adaptors.RegisterFormatter;
|
||||
import org.jf.dexlib.Code.Format.Instruction20bc;
|
||||
import org.jf.dexlib.Code.Format.UnknownInstruction;
|
||||
import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.iface.instruction.*;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.jf.baksmali.Renderers.LongRenderer;
|
||||
import org.jf.dexlib.Code.*;
|
||||
import org.jf.dexlib.CodeItem;
|
||||
import org.jf.dexlib.Item;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
|
||||
public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
protected final CodeItem codeItem;
|
||||
protected final T instruction;
|
||||
@Nonnull protected final MethodDefinition methodDef;
|
||||
@Nonnull protected final T instruction;
|
||||
|
||||
public InstructionMethodItem(CodeItem codeItem, int codeAddress, T instruction) {
|
||||
public InstructionMethodItem(@Nonnull MethodDefinition methodDef, int codeAddress, @Nonnull T instruction) {
|
||||
super(codeAddress);
|
||||
this.codeItem = codeItem;
|
||||
this.methodDef = methodDef;
|
||||
this.instruction = instruction;
|
||||
}
|
||||
|
||||
@ -58,7 +57,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
switch (instruction.getFormat()) {
|
||||
switch (instruction.getOpcode().format) {
|
||||
case Format10t:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
@ -91,13 +90,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write(", ");
|
||||
writeSecondRegister(writer);
|
||||
return true;
|
||||
case Format20bc:
|
||||
//TODO: uncomment
|
||||
/*case Format20bc:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeVerificationErrorType(writer);
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
return true;*/
|
||||
case Format20t:
|
||||
case Format30t:
|
||||
writeOpcode(writer);
|
||||
@ -112,7 +112,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
case Format21h:
|
||||
case Format21ih:
|
||||
case Format21lh:
|
||||
case Format21s:
|
||||
case Format31i:
|
||||
case Format51l:
|
||||
@ -149,7 +150,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
case Format22cs:
|
||||
//TODO: uncomment
|
||||
/*case Format22cs:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeFirstRegister(writer);
|
||||
@ -157,7 +159,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeSecondRegister(writer);
|
||||
writer.write(", ");
|
||||
writeFieldOffset(writer);
|
||||
return true;
|
||||
return true;*/
|
||||
case Format22t:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
@ -191,7 +193,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
case Format35mi:
|
||||
//TODO: uncomment
|
||||
/*case Format35mi:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRegisters(writer);
|
||||
@ -204,7 +207,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeInvokeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writeVtableIndex(writer);
|
||||
return true;
|
||||
return true;*/
|
||||
case Format3rc:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
@ -212,7 +215,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write(", ");
|
||||
writeReference(writer);
|
||||
return true;
|
||||
case Format3rmi:
|
||||
//TODO: uncomment
|
||||
/*case Format3rmi:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRangeRegisters(writer);
|
||||
@ -225,14 +229,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeInvokeRangeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writeVtableIndex(writer);
|
||||
return true;
|
||||
return true;*/
|
||||
}
|
||||
assert false;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void writeOpcode(IndentingWriter writer) throws IOException {
|
||||
writer.write(instruction.opcode.name);
|
||||
writer.write(instruction.getOpcode().name);
|
||||
}
|
||||
|
||||
protected void writeTargetLabel(IndentingWriter writer) throws IOException {
|
||||
@ -242,11 +246,11 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
}
|
||||
|
||||
protected void writeRegister(IndentingWriter writer, int registerNumber) throws IOException {
|
||||
RegisterFormatter.writeTo(writer, codeItem, registerNumber);
|
||||
methodDef.registerFormatter.writeTo(writer, registerNumber);
|
||||
}
|
||||
|
||||
protected void writeFirstRegister(IndentingWriter writer) throws IOException {
|
||||
writeRegister(writer, ((SingleRegisterInstruction)instruction).getRegisterA());
|
||||
writeRegister(writer, ((OneRegisterInstruction)instruction).getRegisterA());
|
||||
}
|
||||
|
||||
protected void writeSecondRegister(IndentingWriter writer) throws IOException {
|
||||
@ -254,40 +258,42 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
}
|
||||
|
||||
protected void writeThirdRegister(IndentingWriter writer) throws IOException {
|
||||
writeRegister(writer, ((ThreeRegisterInstruction)instruction).getRegisterC());
|
||||
writeRegister(writer, ((ThreeRegisterInstruction) instruction).getRegisterC());
|
||||
}
|
||||
|
||||
protected void writeInvokeRegisters(IndentingWriter writer) throws IOException {
|
||||
FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction;
|
||||
final int regCount = instruction.getRegCount();
|
||||
final int regCount = instruction.getRegisterCount();
|
||||
|
||||
writer.write('{');
|
||||
switch (regCount) {
|
||||
case 1:
|
||||
writeRegister(writer, instruction.getRegisterD());
|
||||
writeRegister(writer, instruction.getRegisterC());
|
||||
break;
|
||||
case 2:
|
||||
writeRegister(writer, instruction.getRegisterD());
|
||||
writeRegister(writer, instruction.getRegisterC());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterE());
|
||||
writeRegister(writer, instruction.getRegisterD());
|
||||
break;
|
||||
case 3:
|
||||
writeRegister(writer, instruction.getRegisterC());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterD());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterE());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterF());
|
||||
break;
|
||||
case 4:
|
||||
writeRegister(writer, instruction.getRegisterC());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterD());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterE());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterF());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterG());
|
||||
break;
|
||||
case 5:
|
||||
writeRegister(writer, instruction.getRegisterC());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterD());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterE());
|
||||
@ -295,8 +301,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writeRegister(writer, instruction.getRegisterF());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterG());
|
||||
writer.write(", ");
|
||||
writeRegister(writer, instruction.getRegisterA());
|
||||
break;
|
||||
}
|
||||
writer.write('}');
|
||||
@ -305,20 +309,21 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException {
|
||||
RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction;
|
||||
|
||||
int regCount = instruction.getRegCount();
|
||||
int regCount = instruction.getRegisterCount();
|
||||
if (regCount == 0) {
|
||||
writer.write("{}");
|
||||
} else {
|
||||
int startRegister = instruction.getStartRegister();
|
||||
RegisterFormatter.writeRegisterRange(writer, codeItem, startRegister, startRegister+regCount-1);
|
||||
methodDef.registerFormatter.writeRegisterRange(writer, startRegister, startRegister+regCount-1);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeLiteral(IndentingWriter writer) throws IOException {
|
||||
LongRenderer.writeSignedIntOrLongTo(writer, ((LiteralInstruction)instruction).getLiteral());
|
||||
LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral());
|
||||
}
|
||||
|
||||
protected void writeFieldOffset(IndentingWriter writer) throws IOException {
|
||||
//TODO: uncomment
|
||||
/*protected void writeFieldOffset(IndentingWriter writer) throws IOException {
|
||||
writer.write("field@0x");
|
||||
writer.printUnsignedLongAsHex(((OdexedFieldAccess) instruction).getFieldOffset());
|
||||
}
|
||||
@ -331,15 +336,20 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
protected void writeVtableIndex(IndentingWriter writer) throws IOException {
|
||||
writer.write("vtable@0x");
|
||||
writer.printUnsignedLongAsHex(((OdexedInvokeVirtual) instruction).getVtableIndex());
|
||||
}
|
||||
}*/
|
||||
|
||||
protected void writeReference(IndentingWriter writer) throws IOException {
|
||||
Item item = ((InstructionWithReference)instruction).getReferencedItem();
|
||||
ReferenceFormatter.writeReference(writer, item);
|
||||
String reference = ((ReferenceInstruction)instruction).getReference();
|
||||
if (instruction.getOpcode().referenceType == ReferenceType.STRING) {
|
||||
ReferenceFormatter.writeStringReference(writer, reference);
|
||||
} else {
|
||||
writer.write(reference);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
|
||||
//TODO: uncomment
|
||||
/*protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
|
||||
VerificationErrorType validationErrorType = ((Instruction20bc)instruction).getValidationErrorType();
|
||||
writer.write(validationErrorType.getName());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
@ -29,37 +29,36 @@
|
||||
package org.jf.baksmali.Adaptors.Format;
|
||||
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.dexlib.Code.Format.*;
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.OffsetInstruction;
|
||||
import org.jf.dexlib.CodeItem;
|
||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
|
||||
import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload;
|
||||
import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload;
|
||||
|
||||
public class InstructionMethodItemFactory {
|
||||
private InstructionMethodItemFactory() {
|
||||
}
|
||||
|
||||
public static InstructionMethodItem makeInstructionFormatMethodItem(
|
||||
MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress, Instruction instruction) {
|
||||
MethodDefinition methodDef, int codeAddress, Instruction instruction) {
|
||||
|
||||
if (instruction instanceof OffsetInstruction) {
|
||||
return new OffsetInstructionFormatMethodItem(methodDefinition.getLabelCache(), codeItem,
|
||||
codeAddress, (OffsetInstruction)instruction);
|
||||
return new OffsetInstructionFormatMethodItem(methodDef, codeAddress, (OffsetInstruction)instruction);
|
||||
}
|
||||
|
||||
switch (instruction.getFormat()) {
|
||||
case ArrayData:
|
||||
return new ArrayDataMethodItem(codeItem, codeAddress,
|
||||
(ArrayDataPseudoInstruction)instruction);
|
||||
case PackedSwitchData:
|
||||
return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress,
|
||||
(PackedSwitchDataPseudoInstruction)instruction);
|
||||
case SparseSwitchData:
|
||||
return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress,
|
||||
(SparseSwitchDataPseudoInstruction)instruction);
|
||||
case UnresolvedOdexInstruction:
|
||||
switch (instruction.getOpcode().format) {
|
||||
case ArrayPayload:
|
||||
return new ArrayDataMethodItem(methodDef, codeAddress, (ArrayPayload)instruction);
|
||||
case PackedSwitchPayload:
|
||||
return new PackedSwitchMethodItem(methodDef, codeAddress, (PackedSwitchPayload)instruction);
|
||||
case SparseSwitchPayload:
|
||||
return new SparseSwitchMethodItem(methodDef, codeAddress, (SparseSwitchPayload)instruction);
|
||||
//TODO: uncomment
|
||||
/*case UnresolvedOdexInstruction:
|
||||
return new UnresolvedOdexInstructionMethodItem(codeItem, codeAddress,
|
||||
(UnresolvedOdexInstruction)instruction);
|
||||
(UnresolvedOdexInstruction)instruction);*/
|
||||
default:
|
||||
return new InstructionMethodItem<Instruction>(codeItem, codeAddress, instruction);
|
||||
return new InstructionMethodItem<Instruction>(methodDef, codeAddress, instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,22 +30,21 @@ package org.jf.baksmali.Adaptors.Format;
|
||||
|
||||
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.jf.dexlib.Code.OffsetInstruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.CodeItem;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<OffsetInstruction> {
|
||||
protected LabelMethodItem label;
|
||||
|
||||
public OffsetInstructionFormatMethodItem(MethodDefinition.LabelCache labelCache, CodeItem codeItem, int codeAddress,
|
||||
public OffsetInstructionFormatMethodItem(MethodDefinition methodDef, int codeAddress,
|
||||
OffsetInstruction instruction) {
|
||||
super(codeItem, codeAddress, instruction);
|
||||
super(methodDef, codeAddress, instruction);
|
||||
|
||||
label = new LabelMethodItem(codeAddress + instruction.getTargetAddressOffset(), getLabelPrefix());
|
||||
label = labelCache.internLabel(label);
|
||||
label = new LabelMethodItem(codeAddress + instruction.getCodeOffset(), getLabelPrefix());
|
||||
label = methodDef.getLabelCache().internLabel(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -58,7 +57,8 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<Off
|
||||
}
|
||||
|
||||
private String getLabelPrefix() {
|
||||
switch (instruction.getFormat()) {
|
||||
Opcode opcode = instruction.getOpcode();
|
||||
switch (opcode.format) {
|
||||
case Format10t:
|
||||
case Format20t:
|
||||
case Format30t:
|
||||
@ -67,13 +67,13 @@ public class OffsetInstructionFormatMethodItem extends InstructionMethodItem<Off
|
||||
case Format22t:
|
||||
return "cond_";
|
||||
case Format31t:
|
||||
if (instruction.opcode == Opcode.FILL_ARRAY_DATA) {
|
||||
if (opcode == Opcode.FILL_ARRAY_DATA) {
|
||||
return "array_";
|
||||
}
|
||||
if (instruction.opcode == Opcode.PACKED_SWITCH) {
|
||||
if (opcode == Opcode.PACKED_SWITCH) {
|
||||
return "pswitch_data_";
|
||||
}
|
||||
assert instruction.opcode == Opcode.SPARSE_SWITCH;
|
||||
// Opcode.SPARSE_SWITCH;
|
||||
return "sswitch_data_";
|
||||
}
|
||||
|
||||
|
@ -30,55 +30,54 @@ package org.jf.baksmali.Adaptors.Format;
|
||||
|
||||
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
||||
import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.jf.baksmali.Renderers.IntegerRenderer;
|
||||
import org.jf.dexlib.Code.Format.PackedSwitchDataPseudoInstruction;
|
||||
import org.jf.dexlib.CodeItem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDataPseudoInstruction> {
|
||||
public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchPayload> {
|
||||
private final List<PackedSwitchTarget> targets;
|
||||
private final int firstKey;
|
||||
|
||||
public PackedSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress,
|
||||
PackedSwitchDataPseudoInstruction instruction) {
|
||||
super(codeItem, codeAddress, instruction);
|
||||
public PackedSwitchMethodItem(MethodDefinition methodDef, int codeAddress, PackedSwitchPayload instruction) {
|
||||
super(methodDef, codeAddress, instruction);
|
||||
|
||||
int baseCodeAddress = methodDefinition.getPackedSwitchBaseAddress(codeAddress);
|
||||
int baseCodeAddress = methodDef.getPackedSwitchBaseAddress(codeAddress);
|
||||
|
||||
targets = new ArrayList<PackedSwitchTarget>();
|
||||
Iterator<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> iterator = instruction.iterateKeysAndTargets();
|
||||
|
||||
boolean first = true;
|
||||
//TODO: does dalvik allow switc payloads with no cases?
|
||||
int firstKey = 0;
|
||||
if (baseCodeAddress >= 0) {
|
||||
while (iterator.hasNext()) {
|
||||
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
|
||||
PackedSwitchLabelTarget packedSwitchLabelTarget = new PackedSwitchLabelTarget();
|
||||
|
||||
|
||||
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "pswitch_");
|
||||
label = methodDefinition.getLabelCache().internLabel(label);
|
||||
packedSwitchLabelTarget.Target = label;
|
||||
targets.add(packedSwitchLabelTarget);
|
||||
for (SwitchElement switchElement: instruction.getSwitchElements()) {
|
||||
if (first) {
|
||||
firstKey = switchElement.getKey();
|
||||
first = false;
|
||||
}
|
||||
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + switchElement.getOffset(), "pswitch_");
|
||||
targets.add(new PackedSwitchLabelTarget(label));
|
||||
}
|
||||
} else {
|
||||
while (iterator.hasNext()) {
|
||||
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
|
||||
PackedSwitchOffsetTarget packedSwitchOffsetTarget = new PackedSwitchOffsetTarget();
|
||||
|
||||
|
||||
packedSwitchOffsetTarget.Target = target.targetAddressOffset;
|
||||
targets.add(packedSwitchOffsetTarget);
|
||||
for (SwitchElement switchElement: instruction.getSwitchElements()) {
|
||||
if (first) {
|
||||
firstKey = switchElement.getKey();
|
||||
first = false;
|
||||
}
|
||||
targets.add(new PackedSwitchOffsetTarget(switchElement.getOffset()));
|
||||
}
|
||||
}
|
||||
this.firstKey = firstKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writer.write(".packed-switch ");
|
||||
IntegerRenderer.writeTo(writer, instruction.getFirstKey());
|
||||
IntegerRenderer.writeTo(writer, firstKey);
|
||||
writer.indent(4);
|
||||
writer.write('\n');
|
||||
for (PackedSwitchTarget target: targets) {
|
||||
@ -95,19 +94,25 @@ public class PackedSwitchMethodItem extends InstructionMethodItem<PackedSwitchDa
|
||||
}
|
||||
|
||||
private static class PackedSwitchLabelTarget extends PackedSwitchTarget {
|
||||
public LabelMethodItem Target;
|
||||
private final LabelMethodItem target;
|
||||
public PackedSwitchLabelTarget(LabelMethodItem target) {
|
||||
this.target = target;
|
||||
}
|
||||
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
||||
Target.writeTo(writer);
|
||||
target.writeTo(writer);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PackedSwitchOffsetTarget extends PackedSwitchTarget {
|
||||
public int Target;
|
||||
private final int target;
|
||||
public PackedSwitchOffsetTarget(int target) {
|
||||
this.target = target;
|
||||
}
|
||||
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
||||
if (Target >= 0) {
|
||||
if (target >= 0) {
|
||||
writer.write('+');
|
||||
}
|
||||
writer.printSignedIntAsDec(Target);
|
||||
writer.printSignedIntAsDec(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,48 +30,33 @@ package org.jf.baksmali.Adaptors.Format;
|
||||
|
||||
import org.jf.baksmali.Adaptors.LabelMethodItem;
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
||||
import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.jf.baksmali.Renderers.IntegerRenderer;
|
||||
import org.jf.dexlib.Code.Format.SparseSwitchDataPseudoInstruction;
|
||||
import org.jf.dexlib.CodeItem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDataPseudoInstruction> {
|
||||
public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchPayload> {
|
||||
private final List<SparseSwitchTarget> targets;
|
||||
|
||||
public SparseSwitchMethodItem(MethodDefinition methodDefinition, CodeItem codeItem, int codeAddress,
|
||||
SparseSwitchDataPseudoInstruction instruction) {
|
||||
super(codeItem, codeAddress, instruction);
|
||||
public SparseSwitchMethodItem(MethodDefinition methodDef, int codeAddress, SparseSwitchPayload instruction) {
|
||||
super(methodDef, codeAddress, instruction);
|
||||
|
||||
int baseCodeAddress = methodDefinition.getSparseSwitchBaseAddress(codeAddress);
|
||||
int baseCodeAddress = methodDef.getSparseSwitchBaseAddress(codeAddress);
|
||||
|
||||
targets = new ArrayList<SparseSwitchTarget>();
|
||||
Iterator<SparseSwitchDataPseudoInstruction.SparseSwitchTarget> iterator = instruction.iterateKeysAndTargets();
|
||||
if (baseCodeAddress >= 0) {
|
||||
while (iterator.hasNext()) {
|
||||
SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next();
|
||||
SparseSwitchLabelTarget sparseSwitchLabelTarget = new SparseSwitchLabelTarget();
|
||||
sparseSwitchLabelTarget.Key = target.key;
|
||||
|
||||
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + target.targetAddressOffset, "sswitch_");
|
||||
label = methodDefinition.getLabelCache().internLabel(label);
|
||||
sparseSwitchLabelTarget.Target = label;
|
||||
|
||||
targets.add(sparseSwitchLabelTarget);
|
||||
for (SwitchElement switchElement: instruction.getSwitchElements()) {
|
||||
LabelMethodItem label = new LabelMethodItem(baseCodeAddress + switchElement.getOffset(), "sswitch_");
|
||||
targets.add(new SparseSwitchLabelTarget(switchElement.getKey(), label));
|
||||
}
|
||||
} else {
|
||||
//if we couldn't determine a base address, just use relative offsets rather than labels
|
||||
while (iterator.hasNext()) {
|
||||
SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next();
|
||||
SparseSwitchOffsetTarget sparseSwitchOffsetTarget = new SparseSwitchOffsetTarget();
|
||||
sparseSwitchOffsetTarget.Key = target.key;
|
||||
|
||||
sparseSwitchOffsetTarget.Target = target.targetAddressOffset;
|
||||
targets.add(sparseSwitchOffsetTarget);
|
||||
for (SwitchElement switchElement: instruction.getSwitchElements()) {
|
||||
targets.add(new SparseSwitchOffsetTarget(switchElement.getKey(), switchElement.getOffset()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,7 +66,7 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
|
||||
writer.write(".sparse-switch\n");
|
||||
writer.indent(4);
|
||||
for (SparseSwitchTarget target: targets) {
|
||||
IntegerRenderer.writeTo(writer, target.Key);
|
||||
IntegerRenderer.writeTo(writer, target.getKey());
|
||||
writer.write(" -> ");
|
||||
target.writeTargetTo(writer);
|
||||
writer.write('\n');
|
||||
@ -92,24 +77,38 @@ public class SparseSwitchMethodItem extends InstructionMethodItem<SparseSwitchDa
|
||||
}
|
||||
|
||||
private static abstract class SparseSwitchTarget {
|
||||
public int Key;
|
||||
private final int key;
|
||||
public SparseSwitchTarget(int key) {
|
||||
this.key = key;
|
||||
}
|
||||
public int getKey() { return key; }
|
||||
public abstract void writeTargetTo(IndentingWriter writer) throws IOException;
|
||||
}
|
||||
|
||||
private static class SparseSwitchLabelTarget extends SparseSwitchTarget {
|
||||
public LabelMethodItem Target;
|
||||
private final LabelMethodItem target;
|
||||
public SparseSwitchLabelTarget(int key, LabelMethodItem target) {
|
||||
super(key);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
||||
Target.writeTo(writer);
|
||||
target.writeTo(writer);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SparseSwitchOffsetTarget extends SparseSwitchTarget {
|
||||
public int Target;
|
||||
private final int target;
|
||||
public SparseSwitchOffsetTarget(int key, int target) {
|
||||
super(key);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public void writeTargetTo(IndentingWriter writer) throws IOException {
|
||||
if (Target >= 0) {
|
||||
if (target >= 0) {
|
||||
writer.write('+');
|
||||
}
|
||||
writer.printSignedIntAsDec(Target);
|
||||
writer.printSignedIntAsDec(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ import org.jf.dexlib.CodeItem;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<UnresolvedOdexInstruction> {
|
||||
//TODO: uncomment
|
||||
/*public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<UnresolvedOdexInstruction> {
|
||||
public UnresolvedOdexInstructionMethodItem(CodeItem codeItem, int codeAddress, UnresolvedOdexInstruction instruction) {
|
||||
super(codeItem, codeAddress, instruction);
|
||||
}
|
||||
@ -49,4 +50,4 @@ public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem<U
|
||||
writer.write("throw ");
|
||||
writeRegister(writer, instruction.ObjectRegisterNum);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
@ -28,293 +28,228 @@
|
||||
|
||||
package org.jf.baksmali.Adaptors;
|
||||
|
||||
import org.jf.baksmali.Adaptors.Debug.DebugMethodItem;
|
||||
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
|
||||
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
|
||||
import org.jf.dexlib.Code.InstructionWithReference;
|
||||
import org.jf.dexlib2.AccessFlags;
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.iface.*;
|
||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
||||
import org.jf.dexlib2.util.InstructionOffsetMap;
|
||||
import org.jf.dexlib2.util.MethodUtil;
|
||||
import org.jf.dexlib2.util.TypeUtils;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.jf.baksmali.baksmali;
|
||||
import org.jf.dexlib.*;
|
||||
import org.jf.dexlib.Code.Analysis.AnalyzedInstruction;
|
||||
import org.jf.dexlib.Code.Analysis.MethodAnalyzer;
|
||||
import org.jf.dexlib.Code.Analysis.ValidationException;
|
||||
import org.jf.dexlib.Code.Format.Format;
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.OffsetInstruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.Debug.DebugInstructionIterator;
|
||||
import org.jf.dexlib.Util.AccessFlags;
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
import org.jf.dexlib.Util.SparseIntArray;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class MethodDefinition {
|
||||
private final ClassDataItem.EncodedMethod encodedMethod;
|
||||
private MethodAnalyzer methodAnalyzer;
|
||||
@Nonnull public final ClassDefinition classDef;
|
||||
@Nonnull public final Method method;
|
||||
@Nonnull public final MethodImplementation methodImpl;
|
||||
public RegisterFormatter registerFormatter;
|
||||
|
||||
private final LabelCache labelCache = new LabelCache();
|
||||
@Nonnull private final String methodString;
|
||||
|
||||
private final SparseIntArray packedSwitchMap;
|
||||
private final SparseIntArray sparseSwitchMap;
|
||||
private final SparseIntArray instructionMap;
|
||||
@Nonnull private final LabelCache labelCache = new LabelCache();
|
||||
|
||||
public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) {
|
||||
@Nonnull private final SparseIntArray packedSwitchMap;
|
||||
@Nonnull private final SparseIntArray sparseSwitchMap;
|
||||
@Nonnull private final InstructionOffsetMap instructionOffsetMap;
|
||||
|
||||
public MethodDefinition(@Nonnull ClassDefinition classDef, @Nonnull Method method,
|
||||
@Nonnull MethodImplementation methodImpl) {
|
||||
this.classDef = classDef;
|
||||
this.method = method;
|
||||
this.methodImpl = methodImpl;
|
||||
|
||||
this.methodString = MethodUtil.buildFullMethodString(classDef.classDef, method);
|
||||
|
||||
try {
|
||||
this.encodedMethod = encodedMethod;
|
||||
|
||||
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
|
||||
|
||||
if (encodedMethod.codeItem != null) {
|
||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
|
||||
packedSwitchMap = new SparseIntArray(1);
|
||||
sparseSwitchMap = new SparseIntArray(1);
|
||||
instructionMap = new SparseIntArray(instructions.length);
|
||||
packedSwitchMap = new SparseIntArray(0);
|
||||
sparseSwitchMap = new SparseIntArray(0);
|
||||
instructionOffsetMap = new InstructionOffsetMap(methodImpl);
|
||||
|
||||
int currentCodeAddress = 0;
|
||||
for (int i=0; i<instructions.length; i++) {
|
||||
Instruction instruction = instructions[i];
|
||||
if (instruction.opcode == Opcode.PACKED_SWITCH) {
|
||||
packedSwitchMap.append(
|
||||
currentCodeAddress +
|
||||
((OffsetInstruction)instruction).getTargetAddressOffset(),
|
||||
currentCodeAddress);
|
||||
} else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
|
||||
sparseSwitchMap.append(
|
||||
currentCodeAddress +
|
||||
((OffsetInstruction)instruction).getTargetAddressOffset(),
|
||||
currentCodeAddress);
|
||||
}
|
||||
instructionMap.append(currentCodeAddress, i);
|
||||
currentCodeAddress += instruction.getSize(currentCodeAddress);
|
||||
for (int i=0; i<instructions.size(); i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
|
||||
Opcode opcode = instruction.getOpcode();
|
||||
if (opcode == Opcode.PACKED_SWITCH) {
|
||||
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
|
||||
packedSwitchMap.append(codeOffset, targetOffset);
|
||||
} else if (opcode == Opcode.SPARSE_SWITCH) {
|
||||
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
|
||||
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
|
||||
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
|
||||
sparseSwitchMap.append(codeOffset, targetOffset);
|
||||
}
|
||||
} else {
|
||||
packedSwitchMap = null;
|
||||
sparseSwitchMap = null;
|
||||
instructionMap = null;
|
||||
methodAnalyzer = null;
|
||||
}
|
||||
}catch (Exception ex) {
|
||||
throw ExceptionWithContext.withContext(ex, String.format("Error while processing method %s",
|
||||
encodedMethod.method.getMethodString()));
|
||||
throw ExceptionWithContext.withContext(ex, "Error while processing method %s", methodString);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTo(IndentingWriter writer, AnnotationSetItem annotationSet,
|
||||
AnnotationSetRefList parameterAnnotations) throws IOException {
|
||||
final CodeItem codeItem = encodedMethod.codeItem;
|
||||
|
||||
public static void writeEmptyMethodTo(IndentingWriter writer, Method method) throws IOException {
|
||||
writer.write(".method ");
|
||||
writeAccessFlags(writer, encodedMethod);
|
||||
writer.write(encodedMethod.method.getMethodName().getStringValue());
|
||||
writer.write(encodedMethod.method.getPrototype().getPrototypeString());
|
||||
writeAccessFlags(writer, method.getAccessFlags());
|
||||
writer.write(method.getName());
|
||||
writer.write("(");
|
||||
for (MethodParameter parameter: method.getParameters()) {
|
||||
writer.write(parameter.getType());
|
||||
}
|
||||
writer.write(")");
|
||||
writer.write(method.getReturnType());
|
||||
writer.write('\n');
|
||||
|
||||
writer.indent(4);
|
||||
if (codeItem != null) {
|
||||
if (baksmali.useLocalsDirective) {
|
||||
writer.write(".locals ");
|
||||
} else {
|
||||
writer.write(".registers ");
|
||||
}
|
||||
writer.printSignedIntAsDec(getRegisterCount(encodedMethod));
|
||||
writer.write('\n');
|
||||
writeParameters(writer, codeItem, parameterAnnotations);
|
||||
//TODO: uncomment
|
||||
/*if (annotationSet != null) {
|
||||
AnnotationFormatter.writeTo(writer, annotationSet);
|
||||
}*/
|
||||
writeParameters(writer, method.getParameters());
|
||||
AnnotationFormatter.writeTo(writer, method.getAnnotations());
|
||||
writer.deindent(4);
|
||||
writer.write(".end method\n");
|
||||
}
|
||||
|
||||
writer.write('\n');
|
||||
public void writeTo(IndentingWriter writer) throws IOException {
|
||||
int parameterRegisterCount = 0;
|
||||
if (!AccessFlags.STATIC.isSet(method.getAccessFlags())) {
|
||||
parameterRegisterCount++;
|
||||
}
|
||||
|
||||
for (MethodItem methodItem: getMethodItems()) {
|
||||
if (methodItem.writeTo(writer)) {
|
||||
writer.write('\n');
|
||||
}
|
||||
writer.write(".method ");
|
||||
writeAccessFlags(writer, method.getAccessFlags());
|
||||
writer.write(method.getName());
|
||||
writer.write("(");
|
||||
for (MethodParameter parameter: method.getParameters()) {
|
||||
String type = parameter.getType();
|
||||
writer.write(type);
|
||||
parameterRegisterCount++;
|
||||
if (TypeUtils.isWideType(type)) {
|
||||
parameterRegisterCount++;
|
||||
}
|
||||
}
|
||||
writer.write(")");
|
||||
writer.write(method.getReturnType());
|
||||
writer.write('\n');
|
||||
|
||||
writer.indent(4);
|
||||
if (baksmali.useLocalsDirective) {
|
||||
writer.write(".locals ");
|
||||
writer.printSignedIntAsDec(methodImpl.getRegisterCount() - parameterRegisterCount);
|
||||
} else {
|
||||
writeParameters(writer, codeItem, parameterAnnotations);
|
||||
//TODO: uncomment
|
||||
/*if (annotationSet != null) {
|
||||
AnnotationFormatter.writeTo(writer, annotationSet);
|
||||
}*/
|
||||
writer.write(".registers ");
|
||||
writer.printSignedIntAsDec(methodImpl.getRegisterCount());
|
||||
}
|
||||
writer.write('\n');
|
||||
writeParameters(writer, method.getParameters());
|
||||
|
||||
if (registerFormatter == null) {
|
||||
registerFormatter = new RegisterFormatter(methodImpl.getRegisterCount(), parameterRegisterCount);
|
||||
}
|
||||
|
||||
AnnotationFormatter.writeTo(writer, method.getAnnotations());
|
||||
|
||||
writer.write('\n');
|
||||
|
||||
for (MethodItem methodItem: getMethodItems()) {
|
||||
if (methodItem.writeTo(writer)) {
|
||||
writer.write('\n');
|
||||
}
|
||||
}
|
||||
writer.deindent(4);
|
||||
writer.write(".end method\n");
|
||||
}
|
||||
|
||||
private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod)
|
||||
{
|
||||
int totalRegisters = encodedMethod.codeItem.getRegisterCount();
|
||||
if (baksmali.useLocalsDirective) {
|
||||
int parameterRegisters = encodedMethod.method.getPrototype().getParameterRegisterCount();
|
||||
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
|
||||
parameterRegisters++;
|
||||
private int findSwitchPayload(int targetOffset, Opcode type) {
|
||||
int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
|
||||
|
||||
//TODO: does dalvik let you pad with multiple nops?
|
||||
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
|
||||
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
Instruction instruction = instructions.get(targetIndex);
|
||||
if (instruction.getOpcode() != type) {
|
||||
// maybe it's pointing to a NOP padding instruction. Look at the next instruction
|
||||
if (instruction.getOpcode() == Opcode.NOP) {
|
||||
targetIndex += 1;
|
||||
if (targetIndex < instructions.size()) {
|
||||
instruction = instructions.get(targetIndex);
|
||||
if (instruction.getOpcode() == type) {
|
||||
return instructionOffsetMap.getInstructionCodeOffset(targetIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalRegisters - parameterRegisters;
|
||||
throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset);
|
||||
} else {
|
||||
return targetOffset;
|
||||
}
|
||||
return totalRegisters;
|
||||
}
|
||||
|
||||
private static void writeAccessFlags(IndentingWriter writer, ClassDataItem.EncodedMethod encodedMethod)
|
||||
throws IOException {
|
||||
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) {
|
||||
private static void writeAccessFlags(IndentingWriter writer, int accessFlags)
|
||||
throws IOException {
|
||||
for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(accessFlags)) {
|
||||
writer.write(accessFlag.toString());
|
||||
writer.write(' ');
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeParameters(IndentingWriter writer, CodeItem codeItem,
|
||||
AnnotationSetRefList parameterAnnotations) throws IOException {
|
||||
DebugInfoItem debugInfoItem = null;
|
||||
if (baksmali.outputDebugInfo && codeItem != null) {
|
||||
debugInfoItem = codeItem.getDebugInfo();
|
||||
}
|
||||
|
||||
int parameterCount = 0;
|
||||
AnnotationSetItem[] annotations;
|
||||
StringIdItem[] parameterNames = null;
|
||||
|
||||
if (parameterAnnotations != null) {
|
||||
annotations = parameterAnnotations.getAnnotationSets();
|
||||
parameterCount = annotations.length;
|
||||
} else {
|
||||
annotations = new AnnotationSetItem[0];
|
||||
}
|
||||
|
||||
if (debugInfoItem != null) {
|
||||
parameterNames = debugInfoItem.getParameterNames();
|
||||
}
|
||||
if (parameterNames == null) {
|
||||
parameterNames = new StringIdItem[0];
|
||||
}
|
||||
|
||||
if (parameterCount < parameterNames.length) {
|
||||
parameterCount = parameterNames.length;
|
||||
}
|
||||
|
||||
for (int i=0; i<parameterCount; i++) {
|
||||
AnnotationSetItem annotationSet = null;
|
||||
if (i < annotations.length) {
|
||||
annotationSet = annotations[i];
|
||||
private static void writeParameters(IndentingWriter writer,
|
||||
List<? extends MethodParameter> parameters) throws IOException {
|
||||
int registerNumber = 0;
|
||||
for (MethodParameter parameter: parameters) {
|
||||
String parameterType = parameter.getType();
|
||||
String parameterName = parameter.getName();
|
||||
List<? extends Annotation> annotations = parameter.getAnnotations();
|
||||
if (parameterName != null || annotations.size() != 0) {
|
||||
writer.write(".parameter p");
|
||||
writer.printSignedIntAsDec(registerNumber);
|
||||
if (parameterName != null) {
|
||||
writer.write(" ");
|
||||
writer.write(parameterName);
|
||||
}
|
||||
if (annotations.size() > 0) {
|
||||
writer.indent(4);
|
||||
AnnotationFormatter.writeTo(writer, annotations);
|
||||
writer.deindent(4);
|
||||
writer.write(".end parameter\n");
|
||||
} else {
|
||||
writer.write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
StringIdItem parameterName = null;
|
||||
if (i < parameterNames.length) {
|
||||
parameterName = parameterNames[i];
|
||||
registerNumber++;
|
||||
if (TypeUtils.isWideType(parameterType)) {
|
||||
registerNumber++;
|
||||
}
|
||||
|
||||
writer.write(".parameter");
|
||||
|
||||
if (parameterName != null) {
|
||||
writer.write(" \"");
|
||||
writer.write(parameterName.getStringValue());
|
||||
writer.write('"');
|
||||
}
|
||||
|
||||
writer.write('\n');
|
||||
//TODO: uncomment
|
||||
/*if (annotationSet != null) {
|
||||
writer.indent(4);
|
||||
AnnotationFormatter.writeTo(writer, annotationSet);
|
||||
writer.deindent(4);
|
||||
|
||||
writer.write(".end parameter\n");
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
public LabelCache getLabelCache() {
|
||||
@Nonnull public LabelCache getLabelCache() {
|
||||
return labelCache;
|
||||
}
|
||||
|
||||
public ValidationException getValidationException() {
|
||||
if (methodAnalyzer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return methodAnalyzer.getValidationException();
|
||||
public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) {
|
||||
return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1);
|
||||
}
|
||||
|
||||
public int getPackedSwitchBaseAddress(int packedSwitchDataAddress) {
|
||||
int packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress, -1);
|
||||
|
||||
if (packedSwitchBaseAddress == -1) {
|
||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
||||
int index = instructionMap.get(packedSwitchDataAddress);
|
||||
|
||||
if (instructions[index].opcode == Opcode.NOP) {
|
||||
packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress+2, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return packedSwitchBaseAddress;
|
||||
}
|
||||
|
||||
public int getSparseSwitchBaseAddress(int sparseSwitchDataAddress) {
|
||||
int sparseSwitchBaseAddress = this.sparseSwitchMap.get(sparseSwitchDataAddress, -1);
|
||||
|
||||
if (sparseSwitchBaseAddress == -1) {
|
||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
||||
int index = instructionMap.get(sparseSwitchDataAddress);
|
||||
|
||||
if (instructions[index].opcode == Opcode.NOP) {
|
||||
sparseSwitchBaseAddress = this.packedSwitchMap.get(sparseSwitchDataAddress+2, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return sparseSwitchBaseAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param instructions The instructions array for this method
|
||||
* @param instruction The instruction
|
||||
* @return true if the specified instruction is a NOP, and the next instruction is one of the variable sized
|
||||
* switch/array data structures
|
||||
*/
|
||||
private boolean isInstructionPaddingNop(List<AnalyzedInstruction> instructions, AnalyzedInstruction instruction) {
|
||||
if (instruction.getInstruction().opcode != Opcode.NOP ||
|
||||
instruction.getInstruction().getFormat().variableSizeFormat) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (instruction.getInstructionIndex() == instructions.size()-1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AnalyzedInstruction nextInstruction = instructions.get(instruction.getInstructionIndex()+1);
|
||||
if (nextInstruction.getInstruction().getFormat().variableSizeFormat) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean needsAnalyzed() {
|
||||
for (Instruction instruction: encodedMethod.codeItem.getInstructions()) {
|
||||
if (instruction.opcode.odexOnly()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) {
|
||||
return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1);
|
||||
}
|
||||
|
||||
private List<MethodItem> getMethodItems() {
|
||||
ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
|
||||
|
||||
if (encodedMethod.codeItem == null) {
|
||||
return methodItems;
|
||||
}
|
||||
|
||||
if ((baksmali.registerInfo != 0) || baksmali.verify ||
|
||||
(baksmali.deodex && needsAnalyzed())) {
|
||||
addAnalyzedInstructionMethodItems(methodItems);
|
||||
} else {
|
||||
addInstructionMethodItems(methodItems);
|
||||
}
|
||||
//TODO: addAnalyzedInstructionMethodItems
|
||||
addInstructionMethodItems(methodItems);
|
||||
|
||||
addTries(methodItems);
|
||||
if (baksmali.outputDebugInfo) {
|
||||
@ -335,18 +270,18 @@ public class MethodDefinition {
|
||||
}
|
||||
|
||||
private void addInstructionMethodItems(List<MethodItem> methodItems) {
|
||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
|
||||
int currentCodeAddress = 0;
|
||||
for (int i=0; i<instructions.length; i++) {
|
||||
Instruction instruction = instructions[i];
|
||||
for (int i=0; i<instructions.size(); i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
|
||||
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
|
||||
encodedMethod.codeItem, currentCodeAddress, instruction);
|
||||
currentCodeAddress, instruction);
|
||||
|
||||
methodItems.add(methodItem);
|
||||
|
||||
if (i != instructions.length - 1) {
|
||||
if (i != instructions.size() - 1) {
|
||||
methodItems.add(new BlankMethodItem(currentCodeAddress));
|
||||
}
|
||||
|
||||
@ -361,14 +296,16 @@ public class MethodDefinition {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writer.write("#@");
|
||||
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
|
||||
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
|
||||
if (instruction.opcode == Opcode.INVOKE_STATIC || instruction.opcode == Opcode.INVOKE_STATIC_RANGE) {
|
||||
//TODO: uncomment
|
||||
/*if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
|
||||
Opcode opcode = instruction.getOpcode();
|
||||
if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
|
||||
MethodIdItem methodIdItem =
|
||||
(MethodIdItem)((InstructionWithReference) instruction).getReferencedItem();
|
||||
|
||||
@ -380,13 +317,14 @@ public class MethodDefinition {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
currentCodeAddress += instruction.getSize(currentCodeAddress);
|
||||
currentCodeAddress += instruction.getCodeUnits();
|
||||
}
|
||||
}
|
||||
|
||||
private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
|
||||
//TODO: uncomment
|
||||
/*private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
|
||||
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
|
||||
|
||||
methodAnalyzer.analyze();
|
||||
@ -455,20 +393,21 @@ public class MethodDefinition {
|
||||
|
||||
currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
private void addTries(List<MethodItem> methodItems) {
|
||||
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) {
|
||||
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
|
||||
if (tryBlocks.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
||||
int lastInstructionAddress = instructionMap.keyAt(instructionMap.size()-1);
|
||||
int codeSize = lastInstructionAddress + instructions[instructions.length - 1].getSize(lastInstructionAddress);
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
|
||||
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
|
||||
|
||||
for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) {
|
||||
int startAddress = tryItem.getStartCodeAddress();
|
||||
int endAddress = tryItem.getStartCodeAddress() + tryItem.getTryLength();
|
||||
for (TryBlock tryBlock: tryBlocks) {
|
||||
int startAddress = tryBlock.getStartCodeOffset();
|
||||
int endAddress = startAddress + tryBlock.getCodeUnitCount();
|
||||
|
||||
if (startAddress >= codeSize) {
|
||||
throw new RuntimeException(String.format("Try start offset %d is past the end of the code block.",
|
||||
@ -487,142 +426,28 @@ public class MethodDefinition {
|
||||
* the address for that instruction
|
||||
*/
|
||||
|
||||
int lastCoveredIndex = instructionMap.getClosestSmaller(endAddress-1);
|
||||
int lastCoveredAddress = instructionMap.keyAt(lastCoveredIndex);
|
||||
int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false);
|
||||
int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex);
|
||||
|
||||
//add the catch all handler if it exists
|
||||
int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
|
||||
if (catchAllAddress != -1) {
|
||||
if (catchAllAddress >= codeSize) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Catch all handler offset %d is past the end of the code block.", catchAllAddress));
|
||||
}
|
||||
|
||||
CatchMethodItem catchAllMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress, null,
|
||||
startAddress, endAddress, catchAllAddress);
|
||||
methodItems.add(catchAllMethodItem);
|
||||
}
|
||||
|
||||
//add the rest of the handlers
|
||||
for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
|
||||
if (handler.getHandlerAddress() >= codeSize) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Exception handler offset %d is past the end of the code block.", catchAllAddress));
|
||||
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
|
||||
int handlerOffset = handler.getHandlerCodeOffset();
|
||||
if (handlerOffset >= codeSize) {
|
||||
throw new ExceptionWithContext(
|
||||
"Exception handler offset %d is past the end of the code block.", handlerOffset);
|
||||
}
|
||||
|
||||
//use the address from the last covered instruction
|
||||
CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress,
|
||||
handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress());
|
||||
handler.getExceptionType(), startAddress, endAddress, handlerOffset);
|
||||
methodItems.add(catchMethodItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addDebugInfo(final List<MethodItem> methodItems) {
|
||||
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getDebugInfo() == null) {
|
||||
return;
|
||||
for (DebugItem debugItem: methodImpl.getDebugItems()) {
|
||||
methodItems.add(DebugMethodItem.build(registerFormatter, debugItem));
|
||||
}
|
||||
|
||||
final CodeItem codeItem = encodedMethod.codeItem;
|
||||
DebugInfoItem debugInfoItem = codeItem.getDebugInfo();
|
||||
|
||||
DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(),
|
||||
new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() {
|
||||
@Override
|
||||
public void ProcessStartLocal(final int codeAddress, final int length, final int registerNum,
|
||||
final StringIdItem name, final TypeIdItem type) {
|
||||
methodItems.add(new DebugMethodItem(codeAddress, -1) {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writeStartLocal(writer, codeItem, registerNum, name, type, null);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessStartLocalExtended(final int codeAddress, final int length,
|
||||
final int registerNum, final StringIdItem name,
|
||||
final TypeIdItem type, final StringIdItem signature) {
|
||||
methodItems.add(new DebugMethodItem(codeAddress, -1) {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writeStartLocal(writer, codeItem, registerNum, name, type, signature);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessEndLocal(final int codeAddress, final int length, final int registerNum,
|
||||
final StringIdItem name, final TypeIdItem type,
|
||||
final StringIdItem signature) {
|
||||
methodItems.add(new DebugMethodItem(codeAddress, -1) {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writeEndLocal(writer, codeItem, registerNum, name, type, signature);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessRestartLocal(final int codeAddress, final int length, final int registerNum,
|
||||
final StringIdItem name, final TypeIdItem type,
|
||||
final StringIdItem signature) {
|
||||
methodItems.add(new DebugMethodItem(codeAddress, -1) {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writeRestartLocal(writer, codeItem, registerNum, name, type, signature);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessSetPrologueEnd(int codeAddress) {
|
||||
methodItems.add(new DebugMethodItem(codeAddress, -4) {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writeEndPrologue(writer);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessSetEpilogueBegin(int codeAddress) {
|
||||
methodItems.add(new DebugMethodItem(codeAddress, -4) {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writeBeginEpilogue(writer);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) {
|
||||
methodItems.add(new DebugMethodItem(codeAddress, -3) {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writeSetFile(writer, name.getStringValue());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessLineEmit(int codeAddress, final int line) {
|
||||
methodItems.add(new DebugMethodItem(codeAddress, -2) {
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
writeLine(writer, line);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setLabelSequentialNumbers() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
package org.jf.baksmali.Adaptors;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.jf.baksmali.baksmali;
|
||||
import org.jf.dexlib.CodeItem;
|
||||
@ -39,6 +40,13 @@ import java.io.IOException;
|
||||
* This class contains the logic used for formatting registers
|
||||
*/
|
||||
public class RegisterFormatter {
|
||||
public final int registerCount;
|
||||
public final int parameterRegisterCount;
|
||||
|
||||
public RegisterFormatter(int registerCount, int parameterRegisterCount) {
|
||||
this.registerCount = registerCount;
|
||||
this.parameterRegisterCount = parameterRegisterCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the register range value used by Format3rc. If baksmali.noParameterRegisters is true, it will always
|
||||
@ -46,19 +54,11 @@ public class RegisterFormatter {
|
||||
* registers, and if so, use the p<n> format for both. If only the last register is a parameter register, it will
|
||||
* use the v<n> format for both, otherwise it would be confusing to have something like {v20 .. p1}
|
||||
* @param writer the <code>IndentingWriter</code> to write to
|
||||
* @param codeItem the <code>CodeItem</code> that the register is from
|
||||
* @param startRegister the first register in the range
|
||||
* @param lastRegister the last register in the range
|
||||
*/
|
||||
public static void writeRegisterRange(IndentingWriter writer, CodeItem codeItem, int startRegister,
|
||||
int lastRegister) throws IOException {
|
||||
assert lastRegister >= startRegister;
|
||||
|
||||
public void writeRegisterRange(IndentingWriter writer, int startRegister, int lastRegister) throws IOException {
|
||||
if (!baksmali.noParameterRegisters) {
|
||||
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
|
||||
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
|
||||
int registerCount = codeItem.getRegisterCount();
|
||||
|
||||
assert startRegister <= lastRegister;
|
||||
|
||||
if (startRegister >= registerCount - parameterRegisterCount) {
|
||||
@ -83,14 +83,10 @@ public class RegisterFormatter {
|
||||
* and if so, formats it in the p<n> format instead.
|
||||
*
|
||||
* @param writer the <code>IndentingWriter</code> to write to
|
||||
* @param codeItem the <code>CodeItem</code> that the register is from
|
||||
* @param register the register number
|
||||
*/
|
||||
public static void writeTo(IndentingWriter writer, CodeItem codeItem, int register) throws IOException {
|
||||
public void writeTo(IndentingWriter writer, int register) throws IOException {
|
||||
if (!baksmali.noParameterRegisters) {
|
||||
int parameterRegisterCount = codeItem.getParent().method.getPrototype().getParameterRegisterCount()
|
||||
+ (((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue())==0)?1:0);
|
||||
int registerCount = codeItem.getRegisterCount();
|
||||
if (register >= registerCount - parameterRegisterCount) {
|
||||
writer.write('p');
|
||||
writer.printSignedIntAsDec((register - (registerCount - parameterRegisterCount)));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
53
dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java
Normal file
53
dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java
Normal 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();
|
||||
}
|
||||
}
|
39
dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java
Normal file
39
dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java
Normal 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';
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user