smali-2.2.6/000077500000000000000000000000001342202223400126205ustar00rootroot00000000000000smali-2.2.6/.gitignore000066400000000000000000000002341342202223400146070ustar00rootroot00000000000000/.gradle /baksmali/build /dexlib/build /dexlib2/build /dexlib2/accessorTestGenerator/build /smali/build /util/build /smalidea/build *.iml *.ipr *.iws .idea smali-2.2.6/NOTICE000066400000000000000000000121271342202223400135270ustar00rootroot00000000000000The majority of smali/baksmali is written and copyrighted by me (Ben Gruver) and released under the following license: ******************************************************************************* 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. ******************************************************************************* Unless otherwise stated in the code/commit message, any changes with the committer of bgruv@google.com or wkal@google.com is copyrighted by Google Inc. and released under the following license: ******************************************************************************* Copyright 2011, 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. ******************************************************************************* Various portions of the code are taken from the Android Open Source Project, and are used in accordance with the following license: ******************************************************************************* Copyright (C) 2007 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ******************************************************************************* Some parts of the smalidea plugin are based on code from the IDEA project, per the following license ******************************************************************************* Copyright 2000-2014 JetBrains s.r.o. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************smali-2.2.6/README.md000066400000000000000000000024041342202223400140770ustar00rootroot00000000000000### About smali/baksmali is an assembler/disassembler for the dex format used by dalvik, Android's Java VM implementation. The syntax is loosely based on Jasmin's/dedexer's syntax, and supports the full functionality of the dex format (annotations, debug info, line info, etc.) Downloads are at https://bitbucket.org/JesusFreke/smali/downloads/. If you are interested in submitting a patch, feel free to send me a pull request here. See [the wiki](https://github.com/JesusFreke/smali/wiki) for more info/news/release notes/etc. #### Support - [github Issue tracker](https://github.com/JesusFreke/smali/issues) - For any bugs/issues/feature requests - [#smali on freenode](http://webchat.freenode.net/?channels=smali) - Free free to drop by and ask a question. Don't expect an instant response, but if you hang around someone will respond. #### Some useful links for getting started with smali - [Official dex bytecode reference](https://source.android.com/devices/tech/dalvik/dalvik-bytecode.html) - [Registers wiki page](https://github.com/JesusFreke/smali/wiki/Registers) - [Types, Methods and Fields wiki page](https://github.com/JesusFreke/smali/wiki/TypesMethodsAndFields) - [Official dex format reference](https://source.android.com/devices/tech/dalvik/dex-format.html) smali-2.2.6/baksmali/000077500000000000000000000000001342202223400144035ustar00rootroot00000000000000smali-2.2.6/baksmali/build.gradle000066400000000000000000000074311342202223400166670ustar00rootroot00000000000000/* * 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. */ buildscript { repositories { mavenCentral() } dependencies { classpath depends.proguard_gradle } } dependencies { compile project(':util') compile project(':dexlib2') compile depends.guava compile depends.jcommander testCompile depends.junit testCompile project(':smali') } processResources.inputs.property('version', version) processResources.expand('version': version) // Build a separate jar that contains all dependencies task fatJar(type: Jar) { from sourceSets.main.output from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } classifier = 'fat' manifest { attributes('Main-Class': 'org.jf.baksmali.Main') } doLast { if (!System.getProperty('os.name').toLowerCase().contains('windows')) { ant.symlink(link: file("${destinationDir}/baksmali.jar"), resource: archivePath, overwrite: true) } } } tasks.getByPath('build').dependsOn(fatJar) uploadArchives { repositories.mavenDeployer { pom.project { description 'baksmali is a disassembler for dalvik bytecode' scm { url 'https://github.com/JesusFreke/smali/tree/master/baksmali' } } } } task proguard(type: proguard.gradle.ProGuardTask, dependsOn: fatJar) { def outFile = fatJar.destinationDir.getPath() + '/' + fatJar.baseName + '-' + fatJar.version + '-small' + '.' + fatJar.extension injars fatJar.archivePath outjars outFile libraryjars "${System.properties['java.home']}/lib/rt.jar" dontobfuscate dontoptimize keep 'public class org.jf.baksmali.Main { public static void main(java.lang.String[]); }' keep 'public class org.jf.util.jcommander.ColonParameterSplitter' keep 'class com.beust.jcommander.** { *; }' keepclassmembers 'enum * { public static **[] values(); public static ** valueOf(java.lang.String); }' dontwarn 'com.google.common.**' dontnote 'com.google.common.**' } tasks.getByPath(':release').dependsOn(proguard) task fastbuild(dependsOn: build) { } task fb(dependsOn: fastbuild) { } tasks.getByPath('javadoc').onlyIf({ !gradle.taskGraph.hasTask(fastbuild) }) tasks.getByPath('test').onlyIf({ !gradle.taskGraph.hasTask(fastbuild) })smali-2.2.6/baksmali/src/000077500000000000000000000000001342202223400151725ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/000077500000000000000000000000001342202223400161165ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/000077500000000000000000000000001342202223400170375ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/000077500000000000000000000000001342202223400176265ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/000077500000000000000000000000001342202223400202255ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/000077500000000000000000000000001342202223400220105ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/000077500000000000000000000000001342202223400235655ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/AnnotationFormatter.java000066400000000000000000000056131342202223400304330ustar00rootroot00000000000000/* * [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.baksmali.Adaptors.EncodedValue.AnnotationEncodedValueAdaptor; import org.jf.dexlib2.AnnotationVisibility; import org.jf.dexlib2.iface.Annotation; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; import java.util.Collection; public class AnnotationFormatter { public static void writeTo(@Nonnull IndentingWriter writer, @Nonnull Collection annotations, @Nullable String containingClass) throws IOException { boolean first = true; for (Annotation annotation: annotations) { if (!first) { writer.write('\n'); } first = false; writeTo(writer, annotation, containingClass); } } public static void writeTo(@Nonnull IndentingWriter writer, @Nonnull Annotation annotation, @Nullable String containingClass) throws IOException { writer.write(".annotation "); writer.write(AnnotationVisibility.getVisibility(annotation.getVisibility())); writer.write(' '); writer.write(annotation.getType()); writer.write('\n'); AnnotationEncodedValueAdaptor.writeElementsTo(writer, annotation.getElements(), containingClass); writer.write(".end annotation\n"); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/BlankMethodItem.java000066400000000000000000000040361342202223400274420ustar00rootroot00000000000000/* * [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.IndentingWriter; //a "spacer" between instructions public class BlankMethodItem extends MethodItem { public BlankMethodItem(int codeAddress) { super(codeAddress); } public double getSortOrder() { return Integer.MAX_VALUE; } public boolean writeTo(IndentingWriter writer) { //we didn't technically print something, but returning true indicates that a newline should be printed //after this method item, which is the intended functionality return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/CatchMethodItem.java000066400000000000000000000073151342202223400274400ustar00rootroot00000000000000/* * [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.baksmali.BaksmaliOptions; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; public class CatchMethodItem extends MethodItem { private final String exceptionType; private final LabelMethodItem tryStartLabel; private final LabelMethodItem tryEndLabel; private final LabelMethodItem handlerLabel; public CatchMethodItem(@Nonnull BaksmaliOptions options, @Nonnull MethodDefinition.LabelCache labelCache, int codeAddress, @Nullable String exceptionType, int startAddress, int endAddress, int handlerAddress) { super(codeAddress); this.exceptionType = exceptionType; tryStartLabel = labelCache.internLabel(new LabelMethodItem(options, startAddress, "try_start_")); //use the address from the last covered instruction, but make the label //name refer to the address of the next instruction tryEndLabel = labelCache.internLabel(new EndTryLabelMethodItem(options, codeAddress, endAddress)); if (exceptionType == null) { handlerLabel = labelCache.internLabel(new LabelMethodItem(options, handlerAddress, "catchall_")); } else { handlerLabel = labelCache.internLabel(new LabelMethodItem(options, handlerAddress, "catch_")); } } public LabelMethodItem getTryStartLabel() { return tryStartLabel; } public LabelMethodItem getTryEndLabel() { return tryEndLabel; } public LabelMethodItem getHandlerLabel() { return handlerLabel; } public double getSortOrder() { //sort after instruction and end_try label return 102; } @Override public boolean writeTo(IndentingWriter writer) throws IOException { if (exceptionType == null) { writer.write(".catchall"); } else { writer.write(".catch "); writer.write(exceptionType); } writer.write(" {"); tryStartLabel.writeTo(writer); writer.write(" .. "); tryEndLabel.writeTo(writer); writer.write("} "); handlerLabel.writeTo(writer); return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java000066400000000000000000000333631342202223400275160ustar00rootroot00000000000000/* * [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.baksmali.BaksmaliOptions; import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.dexbacked.DexBackedClassDef; import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex; import org.jf.dexlib2.iface.*; import org.jf.dexlib2.iface.instruction.Instruction; import org.jf.dexlib2.iface.instruction.formats.Instruction21c; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.util.IndentingWriter; import org.jf.util.StringUtils; import javax.annotation.Nonnull; import java.io.IOException; import java.util.*; public class ClassDefinition { @Nonnull public final BaksmaliOptions options; @Nonnull public final ClassDef classDef; @Nonnull private final HashSet fieldsSetInStaticConstructor; protected boolean validationErrors; public ClassDefinition(@Nonnull BaksmaliOptions options, @Nonnull ClassDef classDef) { this.options = options; this.classDef = classDef; fieldsSetInStaticConstructor = findFieldsSetInStaticConstructor(classDef); } public boolean hadValidationErrors() { return validationErrors; } @Nonnull private static HashSet findFieldsSetInStaticConstructor(@Nonnull ClassDef classDef) { HashSet fieldsSetInStaticConstructor = new HashSet(); for (Method method: classDef.getDirectMethods()) { if (method.getName().equals("")) { MethodImplementation impl = method.getImplementation(); if (impl != null) { for (Instruction instruction: impl.getInstructions()) { switch (instruction.getOpcode()) { case SPUT: case SPUT_BOOLEAN: case SPUT_BYTE: case SPUT_CHAR: case SPUT_OBJECT: case SPUT_SHORT: case SPUT_WIDE: { Instruction21c ins = (Instruction21c)instruction; FieldReference fieldRef = null; try { fieldRef = (FieldReference)ins.getReference(); } catch (InvalidItemIndex ex) { // just ignore it for now. We'll deal with it later, when processing the instructions // themselves } if (fieldRef != null && fieldRef.getDefiningClass().equals((classDef.getType()))) { fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef)); } break; } } } } } } return fieldsSetInStaticConstructor; } public void writeTo(IndentingWriter writer) throws IOException { writeClass(writer); writeSuper(writer); writeSourceFile(writer); writeInterfaces(writer); writeAnnotations(writer); Set staticFields = writeStaticFields(writer); writeInstanceFields(writer, staticFields); Set directMethods = writeDirectMethods(writer); writeVirtualMethods(writer, directMethods); } private void writeClass(IndentingWriter writer) throws IOException { writer.write(".class "); writeAccessFlags(writer); writer.write(classDef.getType()); writer.write('\n'); } private void writeAccessFlags(IndentingWriter writer) throws IOException { for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDef.getAccessFlags())) { writer.write(accessFlag.toString()); writer.write(' '); } } private void writeSuper(IndentingWriter writer) throws IOException { String superClass = classDef.getSuperclass(); if (superClass != null) { writer.write(".super "); writer.write(superClass); writer.write('\n'); } } private void writeSourceFile(IndentingWriter writer) throws IOException { String sourceFile = classDef.getSourceFile(); if (sourceFile != null) { writer.write(".source \""); StringUtils.writeEscapedString(writer, sourceFile); writer.write("\"\n"); } } private void writeInterfaces(IndentingWriter writer) throws IOException { List interfaces = classDef.getInterfaces(); if (interfaces.size() != 0) { writer.write('\n'); writer.write("# interfaces\n"); for (String interfaceName: interfaces) { writer.write(".implements "); writer.write(interfaceName); writer.write('\n'); } } } private void writeAnnotations(IndentingWriter writer) throws IOException { Collection classAnnotations = classDef.getAnnotations(); if (classAnnotations.size() != 0) { writer.write("\n\n"); writer.write("# annotations\n"); String containingClass = null; if (options.implicitReferences) { containingClass = classDef.getType(); } AnnotationFormatter.writeTo(writer, classAnnotations, containingClass); } } private Set writeStaticFields(IndentingWriter writer) throws IOException { boolean wroteHeader = false; Set writtenFields = new HashSet(); Iterable staticFields; if (classDef instanceof DexBackedClassDef) { staticFields = ((DexBackedClassDef)classDef).getStaticFields(false); } else { staticFields = classDef.getStaticFields(); } for (Field field: staticFields) { if (!wroteHeader) { writer.write("\n\n"); writer.write("# static fields"); wroteHeader = true; } writer.write('\n'); boolean setInStaticConstructor; IndentingWriter fieldWriter = writer; String fieldString = ReferenceUtil.getShortFieldDescriptor(field); if (!writtenFields.add(fieldString)) { writer.write("# duplicate field ignored\n"); fieldWriter = new CommentingIndentingWriter(writer); System.err.println(String.format("Ignoring duplicate field: %s->%s", classDef.getType(), fieldString)); setInStaticConstructor = false; } else { setInStaticConstructor = fieldsSetInStaticConstructor.contains(fieldString); } FieldDefinition.writeTo(options, fieldWriter, field, setInStaticConstructor); } return writtenFields; } private void writeInstanceFields(IndentingWriter writer, Set staticFields) throws IOException { boolean wroteHeader = false; Set writtenFields = new HashSet(); Iterable instanceFields; if (classDef instanceof DexBackedClassDef) { instanceFields = ((DexBackedClassDef)classDef).getInstanceFields(false); } else { instanceFields = classDef.getInstanceFields(); } for (Field field: instanceFields) { if (!wroteHeader) { writer.write("\n\n"); writer.write("# instance fields"); wroteHeader = true; } writer.write('\n'); IndentingWriter fieldWriter = writer; String fieldString = ReferenceUtil.getShortFieldDescriptor(field); if (!writtenFields.add(fieldString)) { writer.write("# duplicate field ignored\n"); fieldWriter = new CommentingIndentingWriter(writer); System.err.println(String.format("Ignoring duplicate field: %s->%s", classDef.getType(), fieldString)); } else if (staticFields.contains(fieldString)) { System.err.println(String.format("Duplicate static+instance field found: %s->%s", classDef.getType(), fieldString)); System.err.println("You will need to rename one of these fields, including all references."); writer.write("# There is both a static and instance field with this signature.\n" + "# You will need to rename one of these fields, including all references.\n"); } FieldDefinition.writeTo(options, fieldWriter, field, false); } } private Set writeDirectMethods(IndentingWriter writer) throws IOException { boolean wroteHeader = false; Set writtenMethods = new HashSet(); Iterable directMethods; if (classDef instanceof DexBackedClassDef) { directMethods = ((DexBackedClassDef)classDef).getDirectMethods(false); } else { directMethods = classDef.getDirectMethods(); } for (Method method: directMethods) { if (!wroteHeader) { writer.write("\n\n"); writer.write("# direct methods"); wroteHeader = true; } writer.write('\n'); // TODO: check for method validation errors String methodString = ReferenceUtil.getMethodDescriptor(method, true); IndentingWriter methodWriter = writer; if (!writtenMethods.add(methodString)) { writer.write("# duplicate method ignored\n"); methodWriter = new CommentingIndentingWriter(writer); } MethodImplementation methodImpl = method.getImplementation(); if (methodImpl == null) { MethodDefinition.writeEmptyMethodTo(methodWriter, method, options); } else { MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl); methodDefinition.writeTo(methodWriter); } } return writtenMethods; } private void writeVirtualMethods(IndentingWriter writer, Set directMethods) throws IOException { boolean wroteHeader = false; Set writtenMethods = new HashSet(); Iterable virtualMethods; if (classDef instanceof DexBackedClassDef) { virtualMethods = ((DexBackedClassDef)classDef).getVirtualMethods(false); } else { virtualMethods = classDef.getVirtualMethods(); } for (Method method: virtualMethods) { if (!wroteHeader) { writer.write("\n\n"); writer.write("# virtual methods"); wroteHeader = true; } writer.write('\n'); // TODO: check for method validation errors String methodString = ReferenceUtil.getMethodDescriptor(method, true); IndentingWriter methodWriter = writer; if (!writtenMethods.add(methodString)) { writer.write("# duplicate method ignored\n"); methodWriter = new CommentingIndentingWriter(writer); } else if (directMethods.contains(methodString)) { writer.write("# There is both a direct and virtual method with this signature.\n" + "# You will need to rename one of these methods, including all references.\n"); System.err.println(String.format("Duplicate direct+virtual method found: %s->%s", classDef.getType(), methodString)); System.err.println("You will need to rename one of these methods, including all references."); } MethodImplementation methodImpl = method.getImplementation(); if (methodImpl == null) { MethodDefinition.writeEmptyMethodTo(methodWriter, method, options); } else { MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl); methodDefinition.writeTo(methodWriter); } } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentMethodItem.java000066400000000000000000000042071342202223400300150ustar00rootroot00000000000000/* * [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.IndentingWriter; import java.io.IOException; public class CommentMethodItem extends MethodItem { //private final StringTemplate template; private final String comment; private final double sortOrder; public CommentMethodItem(String comment, int codeAddress, double sortOrder) { super(codeAddress); this.comment = comment; this.sortOrder = sortOrder; } public double getSortOrder() { return sortOrder; } public boolean writeTo(IndentingWriter writer) throws IOException { writer.write('#'); writer.write(comment); return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentedOutMethodItem.java000066400000000000000000000042151342202223400310150ustar00rootroot00000000000000/* * [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.IndentingWriter; import java.io.IOException; public class CommentedOutMethodItem extends MethodItem { private final MethodItem commentedOutMethodItem; public CommentedOutMethodItem(MethodItem commentedOutMethodItem) { super(commentedOutMethodItem.getCodeAddress()); this.commentedOutMethodItem = commentedOutMethodItem; } public double getSortOrder() { return commentedOutMethodItem.getSortOrder() + .001; } public boolean writeTo(IndentingWriter writer) throws IOException { writer.write('#'); commentedOutMethodItem.writeTo(writer); return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentingIndentingWriter.java000066400000000000000000000036561342202223400315770ustar00rootroot00000000000000/* * Copyright 2013, 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; import org.jf.util.IndentingWriter; import java.io.IOException; import java.io.Writer; public class CommentingIndentingWriter extends IndentingWriter { public CommentingIndentingWriter(Writer writer) { super(writer); } @Override protected void writeIndent() throws IOException { writer.write("# "); super.writeIndent(); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/000077500000000000000000000000001342202223400246135ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/BeginEpilogueMethodItem.java000066400000000000000000000037171342202223400321640ustar00rootroot00000000000000/* * 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; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/DebugMethodItem.java000066400000000000000000000065341342202223400304740ustar00rootroot00000000000000/* * 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()); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndLocalMethodItem.java000066400000000000000000000053671342202223400311320ustar00rootroot00000000000000/* * 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()); String name = endLocal.getName(); String type = endLocal.getType(); String signature = endLocal.getSignature(); if (name != null || type != null || signature != null) { writer.write(" # "); LocalFormatter.writeLocal(writer, name, type, signature); } return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/EndPrologueMethodItem.java000066400000000000000000000037131342202223400316650ustar00rootroot00000000000000/* * 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; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LineNumberMethodItem.java000066400000000000000000000043001342202223400314730ustar00rootroot00000000000000/* * 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.printUnsignedIntAsDec(lineNumber); return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/LocalFormatter.java000066400000000000000000000054541342202223400304040ustar00rootroot00000000000000/* * Copyright 2013, 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.ReferenceFormatter; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; public class LocalFormatter { /** * Writes out the given local info * * The written string will be something like: * * "localVar":Ljava/lang/String;, "SomeSignature" * "localVar":Ljava/lang/String; * "localVar":V, "SomeSignature" * null:Ljava/lang/String;, "SomeSignature" * null:V, "SomeSignature" * * One of name, type or signature must be non-null */ public static void writeLocal(@Nonnull IndentingWriter writer, @Nullable String name, @Nullable String type, @Nullable String signature) throws IOException { if (name != null) { ReferenceFormatter.writeStringReference(writer, name); } else { writer.write("null"); } writer.write(':'); if (type != null) { writer.write(type); } else { writer.write("V"); } if (signature != null) { writer.write(", "); ReferenceFormatter.writeStringReference(writer, signature); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/RestartLocalMethodItem.java000066400000000000000000000054551342202223400320460ustar00rootroot00000000000000/* * 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()); String name = restartLocal.getName(); String type = restartLocal.getType(); String signature = restartLocal.getSignature(); if (name != null || type != null || signature != null) { writer.write(" # "); LocalFormatter.writeLocal(writer, name, type, signature); } return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/SetSourceFileMethodItem.java000066400000000000000000000046351342202223400321620ustar00rootroot00000000000000/* * 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 { writer.write(".source"); if (sourceFile != null) { writer.write(" \""); StringUtils.writeEscapedString(writer, sourceFile); writer.write('"'); } return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Debug/StartLocalMethodItem.java000066400000000000000000000054121342202223400315100ustar00rootroot00000000000000/* * 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()); String name = startLocal.getName(); String type = startLocal.getType(); String signature = startLocal.getSignature(); if (name != null || type != null || signature != null) { writer.write(", "); LocalFormatter.writeLocal(writer, name, type, signature); } return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/000077500000000000000000000000001342202223400261235ustar00rootroot00000000000000AnnotationEncodedValueAdaptor.java000066400000000000000000000057001342202223400346150ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/* * [The "BSD licence"] * Copyright (c) 2010 Ben Gruver (JesusFreke) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Adaptors.EncodedValue; import org.jf.dexlib2.iface.AnnotationElement; import org.jf.dexlib2.iface.value.AnnotationEncodedValue; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; import java.util.Collection; public abstract class AnnotationEncodedValueAdaptor { public static void writeTo(@Nonnull IndentingWriter writer, @Nonnull AnnotationEncodedValue annotationEncodedValue, @Nullable String containingClass) throws IOException { writer.write(".subannotation "); writer.write(annotationEncodedValue.getType()); writer.write('\n'); writeElementsTo(writer, annotationEncodedValue.getElements(), containingClass); writer.write(".end subannotation"); } public static void writeElementsTo(@Nonnull IndentingWriter writer, @Nonnull Collection annotationElements, @Nullable String containingClass) throws IOException { writer.indent(4); for (AnnotationElement annotationElement: annotationElements) { writer.write(annotationElement.getName()); writer.write(" = "); EncodedValueAdaptor.writeTo(writer, annotationElement.getValue(), containingClass); writer.write('\n'); } writer.deindent(4); } } ArrayEncodedValueAdaptor.java000066400000000000000000000051671342202223400335700ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/* * [The "BSD licence"] * Copyright (c) 2010 Ben Gruver (JesusFreke) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Adaptors.EncodedValue; import org.jf.dexlib2.iface.value.ArrayEncodedValue; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; import java.util.Collection; public class ArrayEncodedValueAdaptor { public static void writeTo(@Nonnull IndentingWriter writer, @Nonnull ArrayEncodedValue arrayEncodedValue, @Nullable String containingClass) throws IOException { writer.write('{'); Collection values = arrayEncodedValue.getValue(); if (values.size() == 0) { writer.write('}'); return; } writer.write('\n'); writer.indent(4); boolean first = true; for (EncodedValue encodedValue: values) { if (!first) { writer.write(",\n"); } first = false; EncodedValueAdaptor.writeTo(writer, encodedValue, containingClass); } writer.deindent(4); writer.write("\n}"); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java000066400000000000000000000141061342202223400326410ustar00rootroot00000000000000/* * [The "BSD licence"] * Copyright (c) 2010 Ben Gruver (JesusFreke) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Adaptors.EncodedValue; import org.jf.baksmali.Adaptors.ReferenceFormatter; import org.jf.baksmali.Renderers.*; import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.*; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; public abstract class EncodedValueAdaptor { public static void writeTo(@Nonnull IndentingWriter writer, @Nonnull EncodedValue encodedValue, @Nullable String containingClass) throws IOException { switch (encodedValue.getValueType()) { case ValueType.ANNOTATION: AnnotationEncodedValueAdaptor.writeTo(writer, (AnnotationEncodedValue)encodedValue, containingClass); return; case ValueType.ARRAY: ArrayEncodedValueAdaptor.writeTo(writer, (ArrayEncodedValue)encodedValue, containingClass); return; case ValueType.BOOLEAN: BooleanRenderer.writeTo(writer, ((BooleanEncodedValue)encodedValue).getValue()); return; case ValueType.BYTE: ByteRenderer.writeTo(writer, ((ByteEncodedValue)encodedValue).getValue()); return; case ValueType.CHAR: CharRenderer.writeTo(writer, ((CharEncodedValue)encodedValue).getValue()); return; case ValueType.DOUBLE: DoubleRenderer.writeTo(writer, ((DoubleEncodedValue)encodedValue).getValue()); return; case ValueType.ENUM: EnumEncodedValue enumEncodedValue = (EnumEncodedValue)encodedValue; boolean useImplicitReference = false; if (enumEncodedValue.getValue().getDefiningClass().equals(containingClass)) { useImplicitReference = true; } writer.write(".enum "); ReferenceUtil.writeFieldDescriptor(writer, enumEncodedValue.getValue(), useImplicitReference); return; case ValueType.FIELD: FieldEncodedValue fieldEncodedValue = (FieldEncodedValue)encodedValue; useImplicitReference = false; if (fieldEncodedValue.getValue().getDefiningClass().equals(containingClass)) { useImplicitReference = true; } ReferenceUtil.writeFieldDescriptor(writer, fieldEncodedValue.getValue(), useImplicitReference); return; case ValueType.FLOAT: FloatRenderer.writeTo(writer, ((FloatEncodedValue)encodedValue).getValue()); return; case ValueType.INT: IntegerRenderer.writeTo(writer, ((IntEncodedValue)encodedValue).getValue()); return; case ValueType.LONG: LongRenderer.writeTo(writer, ((LongEncodedValue)encodedValue).getValue()); return; case ValueType.METHOD: MethodEncodedValue methodEncodedValue = (MethodEncodedValue)encodedValue; useImplicitReference = false; if (methodEncodedValue.getValue().getDefiningClass().equals(containingClass)) { useImplicitReference = true; } ReferenceUtil.writeMethodDescriptor(writer, methodEncodedValue.getValue(), useImplicitReference); return; case ValueType.NULL: writer.write("null"); return; case ValueType.SHORT: ShortRenderer.writeTo(writer, ((ShortEncodedValue)encodedValue).getValue()); return; case ValueType.STRING: ReferenceFormatter.writeStringReference(writer, ((StringEncodedValue)encodedValue).getValue()); return; case ValueType.TYPE: writer.write(((TypeEncodedValue)encodedValue).getValue()); return; case ValueType.METHOD_TYPE: ReferenceFormatter.writeReference(writer, ReferenceType.METHOD_PROTO, ((MethodTypeEncodedValue)encodedValue).getValue()); return; case ValueType.METHOD_HANDLE: ReferenceFormatter.writeReference(writer, ReferenceType.METHOD_HANDLE, ((MethodHandleEncodedValue)encodedValue).getValue()); return; default: throw new IllegalArgumentException("Unknown encoded value type: " + encodedValue.getValueType()); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/EndTryLabelMethodItem.java000066400000000000000000000040721342202223400305600ustar00rootroot00000000000000/* * [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.baksmali.BaksmaliOptions; import javax.annotation.Nonnull; public class EndTryLabelMethodItem extends LabelMethodItem { private int endTryAddress; public EndTryLabelMethodItem(@Nonnull BaksmaliOptions options, int codeAddress, int endTryAddress) { super(options, codeAddress, "try_end_"); this.endTryAddress = endTryAddress; } public double getSortOrder() { //sort after instruction, but before catch directive return 101; } public int getLabelAddress() { return endTryAddress; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/FieldDefinition.java000066400000000000000000000101241342202223400274620ustar00rootroot00000000000000/* * [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.baksmali.Adaptors.EncodedValue.EncodedValueAdaptor; import org.jf.baksmali.BaksmaliOptions; import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Field; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.util.EncodedValueUtils; import org.jf.util.IndentingWriter; import java.io.IOException; import java.util.Collection; public class FieldDefinition { public static void writeTo(BaksmaliOptions options, IndentingWriter writer, Field field, boolean setInStaticConstructor) throws IOException { EncodedValue initialValue = field.getInitialValue(); int accessFlags = field.getAccessFlags(); if (setInStaticConstructor && AccessFlags.STATIC.isSet(accessFlags) && AccessFlags.FINAL.isSet(accessFlags) && initialValue != null) { if (!EncodedValueUtils.isDefaultValue(initialValue)) { writer.write("# The value of this static final field might be set in the static constructor\n"); } else { // don't write out the default initial value for static final fields that get set in the static // constructor initialValue = null; } } writer.write(".field "); writeAccessFlags(writer, field.getAccessFlags()); writer.write(field.getName()); writer.write(':'); writer.write(field.getType()); if (initialValue != null) { writer.write(" = "); String containingClass = null; if (options.implicitReferences) { containingClass = field.getDefiningClass(); } EncodedValueAdaptor.writeTo(writer, initialValue, containingClass); } writer.write('\n'); Collection annotations = field.getAnnotations(); if (annotations.size() > 0) { writer.indent(4); String containingClass = null; if (options.implicitReferences) { containingClass = field.getDefiningClass(); } AnnotationFormatter.writeTo(writer, annotations, containingClass); writer.deindent(4); writer.write(".end field\n"); } } private static void writeAccessFlags(IndentingWriter writer, int accessFlags) throws IOException { for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForField(accessFlags)) { writer.write(accessFlag.toString()); writer.write(' '); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/000077500000000000000000000000001342202223400250155ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java000066400000000000000000000063061342202223400315150ustar00rootroot00000000000000/* * [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.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 java.io.IOException; import java.util.List; public class ArrayDataMethodItem extends InstructionMethodItem { public ArrayDataMethodItem(MethodDefinition methodDef, int codeAddress, ArrayPayload instruction) { super(methodDef, codeAddress, instruction); } public boolean writeTo(IndentingWriter writer) throws IOException { int elementWidth = instruction.getElementWidth(); writer.write(".array-data "); writer.printSignedIntAsDec(instruction.getElementWidth()); writer.write('\n'); writer.indent(4); List elements = instruction.getArrayElements(); String suffix = ""; switch (elementWidth) { case 1: suffix = "t"; break; case 2: suffix = "s"; break; } for (Number number: elements) { LongRenderer.writeSignedIntOrLongTo(writer, number.longValue()); writer.write(suffix); if (elementWidth == 8) { writeCommentIfLikelyDouble(writer, number.longValue()); } else if (elementWidth == 4) { int value = number.intValue(); boolean isResourceId = writeCommentIfResourceId(writer, value); if (!isResourceId) writeCommentIfLikelyFloat(writer, value); } writer.write("\n"); } writer.deindent(4); writer.write(".end array-data"); return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java000066400000000000000000000570021342202223400321650ustar00rootroot00000000000000/* * [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.Format; import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.baksmali.Adaptors.MethodDefinition.InvalidSwitchPayload; import org.jf.baksmali.Adaptors.MethodItem; import org.jf.baksmali.Adaptors.ReferenceFormatter; import org.jf.baksmali.Renderers.LongRenderer; import org.jf.baksmali.BaksmaliOptions; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.VerificationError; import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex; import org.jf.dexlib2.iface.instruction.*; import org.jf.dexlib2.iface.instruction.formats.Instruction20bc; import org.jf.dexlib2.iface.instruction.formats.Instruction31t; import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction; import org.jf.dexlib2.iface.reference.CallSiteReference; import org.jf.dexlib2.iface.reference.Reference; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.util.ExceptionWithContext; import org.jf.util.IndentingWriter; import org.jf.util.NumberUtils; import javax.annotation.Nonnull; import java.io.IOException; import java.util.Map; public class InstructionMethodItem extends MethodItem { @Nonnull protected final MethodDefinition methodDef; @Nonnull protected final T instruction; public InstructionMethodItem(@Nonnull MethodDefinition methodDef, int codeAddress, @Nonnull T instruction) { super(codeAddress); this.methodDef = methodDef; this.instruction = instruction; } public double getSortOrder() { //instructions should appear after everything except an "end try" label and .catch directive return 100; } private boolean isAllowedOdex(@Nonnull Opcode opcode) { BaksmaliOptions options = methodDef.classDef.options; if (options.allowOdex) { return true; } if (methodDef.classDef.options.apiLevel >= 14) { return false; } return opcode.isVolatileFieldAccessor() || opcode == Opcode.THROW_VERIFICATION_ERROR; } private String writeInvalidItemIndex(InvalidItemIndex ex, int type, IndentingWriter writer) throws IOException { writer.write("#"); writer.write(ex.getMessage()); writer.write("\n"); return String.format("%s@%d", ReferenceType.toString(type), ex.getInvalidIndex()); } private interface Writable { void writeTo(IndentingWriter writer) throws IOException; } @Override public boolean writeTo(IndentingWriter writer) throws IOException { Opcode opcode = instruction.getOpcode(); String verificationErrorName = null; Writable referenceWritable = null; Writable referenceWritable2 = null; boolean commentOutInstruction = false; if (instruction instanceof Instruction20bc) { int verificationError = ((Instruction20bc)instruction).getVerificationError(); verificationErrorName = VerificationError.getVerificationErrorName(verificationError); if (verificationErrorName == null) { writer.write("#was invalid verification error type: "); writer.printSignedIntAsDec(verificationError); writer.write("\n"); verificationErrorName = "generic-error"; } } if (instruction instanceof ReferenceInstruction) { ReferenceInstruction referenceInstruction = (ReferenceInstruction)instruction; final String classContext; if (methodDef.classDef.options.implicitReferences) { classContext = methodDef.method.getDefiningClass(); } else { classContext = null; } try { Reference reference = referenceInstruction.getReference(); if (reference instanceof CallSiteReference) { referenceWritable = indentingWriter -> { ReferenceFormatter.writeCallSiteReference(indentingWriter, (CallSiteReference)reference); }; } else { referenceWritable = indentingWriter -> { indentingWriter.write(ReferenceUtil.getReferenceString(reference, classContext)); }; } } catch (InvalidItemIndex ex) { commentOutInstruction = true; String referenceString = writeInvalidItemIndex(ex, referenceInstruction.getReferenceType(), writer); referenceWritable = indentingWriter -> writer.write(referenceString); } catch (ReferenceType.InvalidReferenceTypeException ex) { writer.write("#invalid reference type: "); writer.printSignedIntAsDec(ex.getReferenceType()); commentOutInstruction = true; referenceWritable = indentingWriter -> writer.write("invalid_reference"); } if (instruction instanceof DualReferenceInstruction) { DualReferenceInstruction dualReferenceInstruction = (DualReferenceInstruction) instruction; try { Reference reference2 = dualReferenceInstruction.getReference2(); referenceWritable2 = indentingWriter -> { indentingWriter.write(ReferenceUtil.getReferenceString(reference2, classContext)); }; } catch (InvalidItemIndex ex) { commentOutInstruction = true; String referenceString = writeInvalidItemIndex(ex, dualReferenceInstruction.getReferenceType2(), writer); referenceWritable2 = indentingWriter -> indentingWriter.write(referenceString); } catch (ReferenceType.InvalidReferenceTypeException ex) { writer.write("#invalid reference type: "); writer.printSignedIntAsDec(ex.getReferenceType()); commentOutInstruction = true; referenceWritable2 = indentingWriter -> indentingWriter.write("invalid reference"); } } } if (instruction instanceof Instruction31t) { boolean validPayload = true; switch (instruction.getOpcode()) { case PACKED_SWITCH: int baseAddress = methodDef.getPackedSwitchBaseAddress( this.codeAddress + ((Instruction31t)instruction).getCodeOffset()); if (baseAddress == -1) { validPayload = false; } break; case SPARSE_SWITCH: baseAddress = methodDef.getSparseSwitchBaseAddress( this.codeAddress + ((Instruction31t)instruction).getCodeOffset()); if (baseAddress == -1) { validPayload = false; } break; case FILL_ARRAY_DATA: try { methodDef.findPayloadOffset(this.codeAddress + ((Instruction31t)instruction).getCodeOffset(), Opcode.ARRAY_PAYLOAD); } catch (InvalidSwitchPayload ex) { validPayload = false; } break; default: throw new ExceptionWithContext("Invalid 31t opcode: %s", instruction.getOpcode()); } if (!validPayload) { writer.write("#invalid payload reference\n"); commentOutInstruction = true; } } if (opcode.odexOnly()) { if (!isAllowedOdex(opcode)) { writer.write("#disallowed odex opcode\n"); commentOutInstruction = true; } } if (commentOutInstruction) { writer.write("#"); } switch (instruction.getOpcode().format) { case Format10t: writeOpcode(writer); writer.write(' '); writeTargetLabel(writer); break; case Format10x: if (instruction instanceof UnknownInstruction) { writer.write("#unknown opcode: 0x"); writer.printUnsignedLongAsHex(((UnknownInstruction)instruction).getOriginalOpcode()); writer.write('\n'); } writeOpcode(writer); break; case Format11n: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeLiteral(writer); break; case Format11x: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); break; case Format12x: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); break; case Format20bc: writeOpcode(writer); writer.write(' '); writer.write(verificationErrorName); writer.write(", "); referenceWritable.writeTo(writer); break; case Format20t: case Format30t: writeOpcode(writer); writer.write(' '); writeTargetLabel(writer); break; case Format21c: case Format31c: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); referenceWritable.writeTo(writer); break; case Format21ih: case Format21lh: case Format21s: case Format31i: case Format51l: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeLiteral(writer); if (instruction.getOpcode().setsWideRegister()) { writeCommentIfLikelyDouble(writer); } else { boolean isResourceId = writeCommentIfResourceId(writer); if (!isResourceId) writeCommentIfLikelyFloat(writer); } break; case Format21t: case Format31t: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeTargetLabel(writer); break; case Format22b: case Format22s: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writeLiteral(writer); break; case Format22c: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); referenceWritable.writeTo(writer); break; case Format22cs: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writeFieldOffset(writer); break; case Format22t: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writeTargetLabel(writer); break; case Format22x: case Format32x: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); break; case Format23x: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writeThirdRegister(writer); break; case Format35c: writeOpcode(writer); writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); referenceWritable.writeTo(writer); break; case Format35mi: writeOpcode(writer); writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); writeInlineIndex(writer); break; case Format35ms: writeOpcode(writer); writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); writeVtableIndex(writer); break; case Format3rc: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); referenceWritable.writeTo(writer); break; case Format3rmi: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); writeInlineIndex(writer); break; case Format3rms: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); writeVtableIndex(writer); break; case Format45cc: writeOpcode(writer); writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); referenceWritable.writeTo(writer); writer.write(", "); referenceWritable2.writeTo(writer); break; case Format4rcc: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); referenceWritable.writeTo(writer); writer.write(", "); referenceWritable2.writeTo(writer); break; default: assert false; return false; } if (commentOutInstruction) { writer.write("\nnop"); } return true; } protected void writeOpcode(IndentingWriter writer) throws IOException { writer.write(instruction.getOpcode().name); } protected void writeTargetLabel(IndentingWriter writer) throws IOException { //this method is overridden by OffsetInstructionMethodItem, and should only be called for the formats that //have a target throw new RuntimeException(); } protected void writeRegister(IndentingWriter writer, int registerNumber) throws IOException { methodDef.registerFormatter.writeTo(writer, registerNumber); } protected void writeFirstRegister(IndentingWriter writer) throws IOException { writeRegister(writer, ((OneRegisterInstruction)instruction).getRegisterA()); } protected void writeSecondRegister(IndentingWriter writer) throws IOException { writeRegister(writer, ((TwoRegisterInstruction)instruction).getRegisterB()); } protected void writeThirdRegister(IndentingWriter writer) throws IOException { writeRegister(writer, ((ThreeRegisterInstruction) instruction).getRegisterC()); } protected void writeInvokeRegisters(IndentingWriter writer) throws IOException { FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction; final int regCount = instruction.getRegisterCount(); writer.write('{'); switch (regCount) { case 1: writeRegister(writer, instruction.getRegisterC()); break; case 2: writeRegister(writer, instruction.getRegisterC()); writer.write(", "); writeRegister(writer, instruction.getRegisterD()); break; case 3: writeRegister(writer, instruction.getRegisterC()); writer.write(", "); writeRegister(writer, instruction.getRegisterD()); writer.write(", "); writeRegister(writer, instruction.getRegisterE()); 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()); break; case 5: 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; } writer.write('}'); } protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException { RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction; int regCount = instruction.getRegisterCount(); if (regCount == 0) { writer.write("{}"); } else { int startRegister = instruction.getStartRegister(); methodDef.registerFormatter.writeRegisterRange(writer, startRegister, startRegister+regCount-1); } } protected void writeLiteral(IndentingWriter writer) throws IOException { LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral()); } protected void writeCommentIfLikelyFloat(IndentingWriter writer) throws IOException { writeCommentIfLikelyFloat(writer, ((NarrowLiteralInstruction)instruction).getNarrowLiteral()); } protected void writeCommentIfLikelyFloat(IndentingWriter writer, int val) throws IOException { if (NumberUtils.isLikelyFloat(val)) { writer.write(" # "); float fval = Float.intBitsToFloat(val); if (fval == Float.POSITIVE_INFINITY) writer.write("Float.POSITIVE_INFINITY"); else if (fval == Float.NEGATIVE_INFINITY) writer.write("Float.NEGATIVE_INFINITY"); else if (Float.isNaN(fval)) writer.write("Float.NaN"); else if (fval == Float.MAX_VALUE) writer.write("Float.MAX_VALUE"); else if (fval == (float)Math.PI) writer.write("(float)Math.PI"); else if (fval == (float)Math.E) writer.write("(float)Math.E"); else { writer.write(Float.toString(fval)); writer.write('f'); } } } protected void writeCommentIfLikelyDouble(IndentingWriter writer) throws IOException { writeCommentIfLikelyDouble(writer, ((WideLiteralInstruction)instruction).getWideLiteral()); } protected void writeCommentIfLikelyDouble(IndentingWriter writer, long val) throws IOException { if (NumberUtils.isLikelyDouble(val)) { writer.write(" # "); double dval = Double.longBitsToDouble(val); if (dval == Double.POSITIVE_INFINITY) writer.write("Double.POSITIVE_INFINITY"); else if (dval == Double.NEGATIVE_INFINITY) writer.write("Double.NEGATIVE_INFINITY"); else if (Double.isNaN(dval)) writer.write("Double.NaN"); else if (dval == Double.MAX_VALUE) writer.write("Double.MAX_VALUE"); else if (dval == Math.PI) writer.write("Math.PI"); else if (dval == Math.E) writer.write("Math.E"); else writer.write(Double.toString(dval)); } } protected boolean writeCommentIfResourceId(IndentingWriter writer) throws IOException { return writeCommentIfResourceId(writer, ((NarrowLiteralInstruction)instruction).getNarrowLiteral()); } protected boolean writeCommentIfResourceId(IndentingWriter writer, int val) throws IOException { Map resourceIds = methodDef.classDef.options.resourceIds; String resource = resourceIds.get(Integer.valueOf(val)); if (resource != null) { writer.write(" # "); writer.write(resource); return true; } return false; } protected void writeFieldOffset(IndentingWriter writer) throws IOException { writer.write("field@0x"); writer.printUnsignedLongAsHex(((FieldOffsetInstruction)instruction).getFieldOffset()); } protected void writeInlineIndex(IndentingWriter writer) throws IOException { writer.write("inline@"); writer.printSignedIntAsDec(((InlineIndexInstruction)instruction).getInlineIndex()); } protected void writeVtableIndex(IndentingWriter writer) throws IOException { writer.write("vtable@"); writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex()); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItemFactory.java000066400000000000000000000063201342202223400335120ustar00rootroot00000000000000/* * [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.Format; import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.dexlib2.analysis.UnresolvedOdexInstruction; 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 methodDef, int codeAddress, Instruction instruction) { if (instruction instanceof OffsetInstruction) { return new OffsetInstructionFormatMethodItem(methodDef.classDef.options, methodDef, codeAddress, (OffsetInstruction)instruction); } if (instruction instanceof UnresolvedOdexInstruction) { return new UnresolvedOdexInstructionMethodItem(methodDef, codeAddress, (UnresolvedOdexInstruction)instruction); } 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); default: return new InstructionMethodItem(methodDef, codeAddress, instruction); } } } OffsetInstructionFormatMethodItem.java000066400000000000000000000064531342202223400344320ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/* * [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.Format; import org.jf.baksmali.Adaptors.LabelMethodItem; import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.baksmali.BaksmaliOptions; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.iface.instruction.OffsetInstruction; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import java.io.IOException; public class OffsetInstructionFormatMethodItem extends InstructionMethodItem { protected LabelMethodItem label; public OffsetInstructionFormatMethodItem(@Nonnull BaksmaliOptions options, @Nonnull MethodDefinition methodDef, int codeAddress, OffsetInstruction instruction) { super(methodDef, codeAddress, instruction); label = new LabelMethodItem(options, codeAddress + instruction.getCodeOffset(), getLabelPrefix()); label = methodDef.getLabelCache().internLabel(label); } @Override protected void writeTargetLabel(IndentingWriter writer) throws IOException { label.writeTo(writer); } public LabelMethodItem getLabel() { return label; } private String getLabelPrefix() { Opcode opcode = instruction.getOpcode(); switch (opcode.format) { case Format10t: case Format20t: case Format30t: return "goto_"; case Format21t: case Format22t: return "cond_"; case Format31t: if (opcode == Opcode.FILL_ARRAY_DATA) { return "array_"; } if (opcode == Opcode.PACKED_SWITCH) { return "pswitch_data_"; } // Opcode.SPARSE_SWITCH; return "sswitch_data_"; } assert false; return null; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/PackedSwitchMethodItem.java000066400000000000000000000122271342202223400322150ustar00rootroot00000000000000/* * [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.Format; import org.jf.baksmali.Adaptors.CommentingIndentingWriter; 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 java.io.IOException; import java.util.ArrayList; import java.util.List; public class PackedSwitchMethodItem extends InstructionMethodItem { private final List targets; private final int firstKey; // Whether this sparse switch instruction should be commented out because it is never referenced private boolean commentedOut; public PackedSwitchMethodItem(MethodDefinition methodDef, int codeAddress, PackedSwitchPayload instruction) { super(methodDef, codeAddress, instruction); int baseCodeAddress = methodDef.getPackedSwitchBaseAddress(codeAddress); targets = new ArrayList(); boolean first = true; int firstKey = 0; if (baseCodeAddress >= 0) { for (SwitchElement switchElement: instruction.getSwitchElements()) { if (first) { firstKey = switchElement.getKey(); first = false; } LabelMethodItem label = methodDef.getLabelCache().internLabel( new LabelMethodItem(methodDef.classDef.options, baseCodeAddress + switchElement.getOffset(), "pswitch_")); targets.add(new PackedSwitchLabelTarget(label)); } } else { commentedOut = true; 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 { if (commentedOut) { writer = new CommentingIndentingWriter(writer); } writer.write(".packed-switch "); IntegerRenderer.writeTo(writer, firstKey); writer.indent(4); writer.write('\n'); int key = firstKey; for (PackedSwitchTarget target: targets) { target.writeTargetTo(writer); writeCommentIfResourceId(writer, key); writer.write('\n'); key++; } writer.deindent(4); writer.write(".end packed-switch"); return true; } private static abstract class PackedSwitchTarget { public abstract void writeTargetTo(IndentingWriter writer) throws IOException; } private static class PackedSwitchLabelTarget extends PackedSwitchTarget { private final LabelMethodItem target; public PackedSwitchLabelTarget(LabelMethodItem target) { this.target = target; } public void writeTargetTo(IndentingWriter writer) throws IOException { target.writeTo(writer); } } private static class PackedSwitchOffsetTarget extends PackedSwitchTarget { private final int target; public PackedSwitchOffsetTarget(int target) { this.target = target; } public void writeTargetTo(IndentingWriter writer) throws IOException { if (target >= 0) { writer.write('+'); } writer.printSignedIntAsDec(target); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/SparseSwitchMethodItem.java000066400000000000000000000121611342202223400322600ustar00rootroot00000000000000/* * [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.Format; import org.jf.baksmali.Adaptors.CommentingIndentingWriter; 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 java.io.IOException; import java.util.ArrayList; import java.util.List; public class SparseSwitchMethodItem extends InstructionMethodItem { private final List targets; // Whether this sparse switch instruction should be commented out because it is never referenced private boolean commentedOut; public SparseSwitchMethodItem(MethodDefinition methodDef, int codeAddress, SparseSwitchPayload instruction) { super(methodDef, codeAddress, instruction); int baseCodeAddress = methodDef.getSparseSwitchBaseAddress(codeAddress); targets = new ArrayList(); if (baseCodeAddress >= 0) { for (SwitchElement switchElement: instruction.getSwitchElements()) { LabelMethodItem label = methodDef.getLabelCache().internLabel( new LabelMethodItem( methodDef.classDef.options, baseCodeAddress + switchElement.getOffset(), "sswitch_")); targets.add(new SparseSwitchLabelTarget(switchElement.getKey(), label)); } } else { commentedOut = true; //if we couldn't determine a base address, just use relative offsets rather than labels for (SwitchElement switchElement: instruction.getSwitchElements()) { targets.add(new SparseSwitchOffsetTarget(switchElement.getKey(), switchElement.getOffset())); } } } @Override public boolean writeTo(IndentingWriter writer) throws IOException { if (commentedOut) { writer = new CommentingIndentingWriter(writer); } writer.write(".sparse-switch\n"); writer.indent(4); for (SparseSwitchTarget target: targets) { IntegerRenderer.writeTo(writer, target.getKey()); writer.write(" -> "); target.writeTargetTo(writer); writeCommentIfResourceId(writer, target.getKey()); writer.write('\n'); } writer.deindent(4); writer.write(".end sparse-switch"); return true; } private static abstract class SparseSwitchTarget { 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 { 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); } } private static class SparseSwitchOffsetTarget extends SparseSwitchTarget { 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) { writer.write('+'); } writer.printSignedIntAsDec(target); } } } UnresolvedOdexInstructionMethodItem.java000066400000000000000000000047071342202223400350010ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/* * [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.Format; import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.dexlib2.analysis.UnresolvedOdexInstruction; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import java.io.IOException; public class UnresolvedOdexInstructionMethodItem extends InstructionMethodItem { public UnresolvedOdexInstructionMethodItem(@Nonnull MethodDefinition methodDef, int codeAddress, @Nonnull UnresolvedOdexInstruction instruction) { super(methodDef, codeAddress, instruction); } public boolean writeTo(IndentingWriter writer) throws IOException { writeThrowTo(writer); return true; } private void writeThrowTo(IndentingWriter writer) throws IOException { writer.write("#Replaced unresolvable odex instruction with a throw\n"); writer.write("throw "); writeRegister(writer, instruction.objectRegisterNum); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/LabelMethodItem.java000066400000000000000000000065741342202223400274430ustar00rootroot00000000000000/* * [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.baksmali.BaksmaliOptions; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import java.io.IOException; public class LabelMethodItem extends MethodItem { private final BaksmaliOptions options; private final String labelPrefix; private int labelSequence; public LabelMethodItem(@Nonnull BaksmaliOptions options, int codeAddress, @Nonnull String labelPrefix) { super(codeAddress); this.options = options; this.labelPrefix = labelPrefix; } public double getSortOrder() { return 0; } public int compareTo(MethodItem methodItem) { int result = super.compareTo(methodItem); if (result == 0) { if (methodItem instanceof LabelMethodItem) { result = labelPrefix.compareTo(((LabelMethodItem)methodItem).labelPrefix); } } return result; } public int hashCode() { //force it to call equals when two labels are at the same address return getCodeAddress(); } public boolean equals(Object o) { if (!(o instanceof LabelMethodItem)) { return false; } return this.compareTo((MethodItem)o) == 0; } public boolean writeTo(IndentingWriter writer) throws IOException { writer.write(':'); writer.write(labelPrefix); if (options.sequentialLabels) { writer.printUnsignedLongAsHex(labelSequence); } else { writer.printUnsignedLongAsHex(this.getLabelAddress()); } return true; } public String getLabelPrefix() { return labelPrefix; } public int getLabelAddress() { return this.getCodeAddress(); } public int getLabelSequence() { return labelSequence; } public void setLabelSequence(int labelSequence) { this.labelSequence = labelSequence; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java000066400000000000000000000657761342202223400277060ustar00rootroot00000000000000/* * [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 com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.jf.baksmali.Adaptors.Debug.DebugMethodItem; import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory; import org.jf.baksmali.BaksmaliOptions; import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.Format; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.analysis.AnalysisException; import org.jf.dexlib2.analysis.AnalyzedInstruction; import org.jf.dexlib2.analysis.MethodAnalyzer; import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex; 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.iface.instruction.ReferenceInstruction; import org.jf.dexlib2.iface.instruction.formats.Instruction31t; import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.immutable.instruction.ImmutableInstruction31t; import org.jf.dexlib2.util.InstructionOffsetMap; import org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.dexlib2.util.SyntheticAccessorResolver; import org.jf.dexlib2.util.SyntheticAccessorResolver.AccessedMember; import org.jf.dexlib2.util.TypeUtils; import org.jf.util.ExceptionWithContext; import org.jf.util.IndentingWriter; import org.jf.util.SparseIntArray; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; import java.util.*; public class MethodDefinition { @Nonnull public final ClassDefinition classDef; @Nonnull public final Method method; @Nonnull public final MethodImplementation methodImpl; @Nonnull public final ImmutableList instructions; @Nonnull public final List effectiveInstructions; @Nonnull public final ImmutableList methodParameters; public RegisterFormatter registerFormatter; @Nonnull private final LabelCache labelCache = new LabelCache(); @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; try { //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh. instructions = ImmutableList.copyOf(methodImpl.getInstructions()); methodParameters = ImmutableList.copyOf(method.getParameters()); effectiveInstructions = Lists.newArrayList(instructions); packedSwitchMap = new SparseIntArray(0); sparseSwitchMap = new SparseIntArray(0); instructionOffsetMap = new InstructionOffsetMap(instructions); int endOffset = instructionOffsetMap.getInstructionCodeOffset(instructions.size()-1) + instructions.get(instructions.size()-1).getCodeUnits(); for (int i=0; i methodParameters = ImmutableList.copyOf(method.getParameters()); for (MethodParameter parameter: methodParameters) { writer.write(parameter.getType()); } writer.write(")"); writer.write(method.getReturnType()); writer.write('\n'); writer.indent(4); writeParameters(writer, method, methodParameters, options); String containingClass = null; if (options.implicitReferences) { containingClass = method.getDefiningClass(); } AnnotationFormatter.writeTo(writer, method.getAnnotations(), containingClass); writer.deindent(4); writer.write(".end method\n"); } public void writeTo(IndentingWriter writer) throws IOException { int parameterRegisterCount = 0; if (!AccessFlags.STATIC.isSet(method.getAccessFlags())) { parameterRegisterCount++; } writer.write(".method "); writeAccessFlags(writer, method.getAccessFlags()); writer.write(method.getName()); writer.write("("); for (MethodParameter parameter: methodParameters) { 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 (classDef.options.localsDirective) { writer.write(".locals "); writer.printSignedIntAsDec(methodImpl.getRegisterCount() - parameterRegisterCount); } else { writer.write(".registers "); writer.printSignedIntAsDec(methodImpl.getRegisterCount()); } writer.write('\n'); writeParameters(writer, method, methodParameters, classDef.options); if (registerFormatter == null) { registerFormatter = new RegisterFormatter(classDef.options, methodImpl.getRegisterCount(), parameterRegisterCount); } String containingClass = null; if (classDef.options.implicitReferences) { containingClass = method.getDefiningClass(); } AnnotationFormatter.writeTo(writer, method.getAnnotations(), containingClass); writer.write('\n'); List methodItems = getMethodItems(); for (MethodItem methodItem: methodItems) { if (methodItem.writeTo(writer)) { writer.write('\n'); } } writer.deindent(4); writer.write(".end method\n"); } public Instruction findSwitchPayload(int targetOffset, Opcode type) { int targetIndex; try { targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset); } catch (InvalidInstructionOffset ex) { throw new InvalidSwitchPayload(targetOffset); } //TODO: does dalvik let you pad with multiple nops? //TODO: does dalvik let a switch instruction point to a non-payload instruction? 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 instruction; } } } throw new InvalidSwitchPayload(targetOffset); } else { return instruction; } } public int findPayloadOffset(int targetOffset, Opcode type) { int targetIndex; try { targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset); } catch (InvalidInstructionOffset ex) { throw new InvalidSwitchPayload(targetOffset); } //TODO: does dalvik let you pad with multiple nops? //TODO: does dalvik let a switch instruction point to a non-payload instruction? 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); } } } throw new InvalidSwitchPayload(targetOffset); } else { return targetOffset; } } 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, Method method, List parameters, BaksmaliOptions options) throws IOException { boolean isStatic = AccessFlags.STATIC.isSet(method.getAccessFlags()); int registerNumber = isStatic?0:1; for (MethodParameter parameter: parameters) { String parameterType = parameter.getType(); String parameterName = parameter.getName(); Collection annotations = parameter.getAnnotations(); if ((options.debugInfo && parameterName != null) || annotations.size() != 0) { writer.write(".param p"); writer.printSignedIntAsDec(registerNumber); if (parameterName != null && options.debugInfo) { writer.write(", "); ReferenceFormatter.writeStringReference(writer, parameterName); } writer.write(" # "); writer.write(parameterType); writer.write("\n"); if (annotations.size() > 0) { writer.indent(4); String containingClass = null; if (options.implicitReferences) { containingClass = method.getDefiningClass(); } AnnotationFormatter.writeTo(writer, annotations, containingClass); writer.deindent(4); writer.write(".end param\n"); } } registerNumber++; if (TypeUtils.isWideType(parameterType)) { registerNumber++; } } } @Nonnull public LabelCache getLabelCache() { return labelCache; } public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) { return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1); } public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) { return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1); } private List getMethodItems() { ArrayList methodItems = new ArrayList(); if ((classDef.options.registerInfo != 0) || (classDef.options.normalizeVirtualMethods) || (classDef.options.deodex && needsAnalyzed())) { addAnalyzedInstructionMethodItems(methodItems); } else { addInstructionMethodItems(methodItems); } addTries(methodItems); if (classDef.options.debugInfo) { addDebugInfo(methodItems); } if (classDef.options.sequentialLabels) { setLabelSequentialNumbers(); } for (LabelMethodItem labelMethodItem: labelCache.getLabels()) { methodItems.add(labelMethodItem); } Collections.sort(methodItems); return methodItems; } private boolean needsAnalyzed() { for (Instruction instruction: methodImpl.getInstructions()) { if (instruction.getOpcode().odexOnly()) { return true; } } return false; } private void addInstructionMethodItems(List methodItems) { int currentCodeAddress = 0; for (int i=0; i methodItems) { MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classDef.options.classPath, method, classDef.options.inlineResolver, classDef.options.normalizeVirtualMethods); AnalysisException analysisException = methodAnalyzer.getAnalysisException(); if (analysisException != null) { // TODO: need to keep track of whether any errors occurred, so we can exit with a non-zero result methodItems.add(new CommentMethodItem( String.format("AnalysisException: %s", analysisException.getMessage()), analysisException.codeAddress, Integer.MIN_VALUE)); analysisException.printStackTrace(System.err); } List instructions = methodAnalyzer.getAnalyzedInstructions(); int currentCodeAddress = 0; for (int i=0; i methodItems) { List> tryBlocks = methodImpl.getTryBlocks(); if (tryBlocks.size() == 0) { return; } int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1); int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits(); for (TryBlock tryBlock: tryBlocks) { int startAddress = tryBlock.getStartCodeAddress(); 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.", startAddress)); } // Note: not >=. endAddress == codeSize is valid, when the try covers the last instruction if (endAddress > codeSize) { throw new RuntimeException(String.format("Try end offset %d is past the end of the code block.", endAddress)); } /** * The end address points to the address immediately after the end of the last * instruction that the try block covers. We want the .catch directive and end_try * label to be associated with the last covered instruction, so we need to get * the address for that instruction */ int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false); int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex); for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) { int handlerAddress = handler.getHandlerCodeAddress(); if (handlerAddress >= codeSize) { throw new ExceptionWithContext( "Exception handler offset %d is past the end of the code block.", handlerAddress); } //use the address from the last covered instruction CatchMethodItem catchMethodItem = new CatchMethodItem(classDef.options, labelCache, lastCoveredAddress, handler.getExceptionType(), startAddress, endAddress, handlerAddress); methodItems.add(catchMethodItem); } } } private void addDebugInfo(final List methodItems) { for (DebugItem debugItem: methodImpl.getDebugItems()) { methodItems.add(DebugMethodItem.build(registerFormatter, debugItem)); } } private void setLabelSequentialNumbers() { HashMap nextLabelSequenceByType = new HashMap(); ArrayList sortedLabels = new ArrayList(labelCache.getLabels()); //sort the labels by their location in the method Collections.sort(sortedLabels); for (LabelMethodItem labelMethodItem: sortedLabels) { Integer labelSequence = nextLabelSequenceByType.get(labelMethodItem.getLabelPrefix()); if (labelSequence == null) { labelSequence = 0; } labelMethodItem.setLabelSequence(labelSequence); nextLabelSequenceByType.put(labelMethodItem.getLabelPrefix(), labelSequence + 1); } } @Nullable private String getContainingClassForImplicitReference() { if (classDef.options.implicitReferences) { return classDef.classDef.getType(); } return null; } public static class LabelCache { protected HashMap labels = new HashMap(); public LabelCache() { } public LabelMethodItem internLabel(LabelMethodItem labelMethodItem) { LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem); if (internedLabelMethodItem != null) { return internedLabelMethodItem; } labels.put(labelMethodItem, labelMethodItem); return labelMethodItem; } public Collection getLabels() { return labels.values(); } } public static class InvalidSwitchPayload extends ExceptionWithContext { private final int payloadOffset; public InvalidSwitchPayload(int payloadOffset) { super("No switch payload at offset: %d", payloadOffset); this.payloadOffset = payloadOffset; } public int getPayloadOffset() { return payloadOffset; } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodItem.java000066400000000000000000000045211342202223400264710ustar00rootroot00000000000000/* * [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.IndentingWriter; import java.io.IOException; public abstract class MethodItem implements Comparable { protected final int codeAddress; protected MethodItem(int codeAddress) { this.codeAddress = codeAddress; } public int getCodeAddress() { return codeAddress; } //return an arbitrary double that determines how this item will be sorted with others at the same address public abstract double getSortOrder(); public int compareTo(MethodItem methodItem) { int result = ((Integer) codeAddress).compareTo(methodItem.codeAddress); if (result == 0){ return ((Double)getSortOrder()).compareTo(methodItem.getSortOrder()); } return result; } public abstract boolean writeTo(IndentingWriter writer) throws IOException; } PostInstructionRegisterInfoMethodItem.java000066400000000000000000000102261342202223400340420ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/* * [The "BSD licence"] * Copyright (c) 2010 Ben Gruver * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Adaptors; import org.jf.baksmali.BaksmaliOptions; import org.jf.dexlib2.analysis.AnalyzedInstruction; import org.jf.dexlib2.analysis.RegisterType; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import java.io.IOException; import java.util.BitSet; public class PostInstructionRegisterInfoMethodItem extends MethodItem { @Nonnull private final RegisterFormatter registerFormatter; @Nonnull private final AnalyzedInstruction analyzedInstruction; public PostInstructionRegisterInfoMethodItem(@Nonnull RegisterFormatter registerFormatter, @Nonnull AnalyzedInstruction analyzedInstruction, int codeAddress) { super(codeAddress); this.registerFormatter = registerFormatter; this.analyzedInstruction = analyzedInstruction; } @Override public double getSortOrder() { return 100.1; } @Override public boolean writeTo(IndentingWriter writer) throws IOException { int registerInfo = registerFormatter.options.registerInfo; int registerCount = analyzedInstruction.getRegisterCount(); BitSet registers = new BitSet(registerCount); if ((registerInfo & BaksmaliOptions.ALL) != 0) { registers.set(0, registerCount); } else { if ((registerInfo & BaksmaliOptions.ALLPOST) != 0) { registers.set(0, registerCount); } else if ((registerInfo & BaksmaliOptions.DEST) != 0) { addDestRegs(registers, registerCount); } } return writeRegisterInfo(writer, registers); } private void addDestRegs(BitSet printPostRegister, int registerCount) { for (int registerNum=0; registerNum= 0; registerNum = registers.nextSetBit(registerNum + 1)) { RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum); registerFormatter.writeTo(writer, registerNum); writer.write('='); registerType.writeTo(writer); writer.write(';'); } return true; } } PreInstructionRegisterInfoMethodItem.java000066400000000000000000000250071342202223400336460ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/* * [The "BSD licence"] * Copyright (c) 2010 Ben Gruver * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Adaptors; import org.jf.baksmali.BaksmaliOptions; import org.jf.dexlib2.analysis.AnalyzedInstruction; import org.jf.dexlib2.analysis.MethodAnalyzer; import org.jf.dexlib2.analysis.RegisterType; import org.jf.dexlib2.iface.instruction.*; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import java.io.IOException; import java.util.BitSet; public class PreInstructionRegisterInfoMethodItem extends MethodItem { private final int registerInfo; @Nonnull private final MethodAnalyzer methodAnalyzer; @Nonnull private final RegisterFormatter registerFormatter; @Nonnull private final AnalyzedInstruction analyzedInstruction; public PreInstructionRegisterInfoMethodItem(int registerInfo, @Nonnull MethodAnalyzer methodAnalyzer, @Nonnull RegisterFormatter registerFormatter, @Nonnull AnalyzedInstruction analyzedInstruction, int codeAddress) { super(codeAddress); this.registerInfo = registerInfo; this.methodAnalyzer = methodAnalyzer; this.registerFormatter = registerFormatter; this.analyzedInstruction = analyzedInstruction; } @Override public double getSortOrder() { return 99.9; } @Override public boolean writeTo(IndentingWriter writer) throws IOException { int registerCount = analyzedInstruction.getRegisterCount(); BitSet registers = new BitSet(registerCount); BitSet mergeRegisters = null; if ((registerInfo & BaksmaliOptions.ALL) != 0) { registers.set(0, registerCount); } else { if ((registerInfo & BaksmaliOptions.ALLPRE) != 0) { registers.set(0, registerCount); } else { if ((registerInfo & BaksmaliOptions.ARGS) != 0) { addArgsRegs(registers); } if ((registerInfo & BaksmaliOptions.MERGE) != 0) { if (analyzedInstruction.isBeginningInstruction()) { addParamRegs(registers, registerCount); } mergeRegisters = new BitSet(registerCount); addMergeRegs(mergeRegisters, registerCount); } else if ((registerInfo & BaksmaliOptions.FULLMERGE) != 0 && (analyzedInstruction.isBeginningInstruction())) { addParamRegs(registers, registerCount); } } } if ((registerInfo & BaksmaliOptions.FULLMERGE) != 0) { if (mergeRegisters == null) { mergeRegisters = new BitSet(registerCount); addMergeRegs(mergeRegisters, registerCount); } registers.or(mergeRegisters); } else if (mergeRegisters != null) { registers.or(mergeRegisters); mergeRegisters = null; } return writeRegisterInfo(writer, registers, mergeRegisters); } private void addArgsRegs(BitSet registers) { if (analyzedInstruction.getInstruction() instanceof RegisterRangeInstruction) { RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction(); registers.set(instruction.getStartRegister(), instruction.getStartRegister() + instruction.getRegisterCount()); } else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) { FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction(); int regCount = instruction.getRegisterCount(); switch (regCount) { case 5: registers.set(instruction.getRegisterG()); //fall through case 4: registers.set(instruction.getRegisterF()); //fall through case 3: registers.set(instruction.getRegisterE()); //fall through case 2: registers.set(instruction.getRegisterD()); //fall through case 1: registers.set(instruction.getRegisterC()); } } else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction(); registers.set(instruction.getRegisterA()); registers.set(instruction.getRegisterB()); registers.set(instruction.getRegisterC()); } else if (analyzedInstruction.getInstruction() instanceof TwoRegisterInstruction) { TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction(); registers.set(instruction.getRegisterA()); registers.set(instruction.getRegisterB()); } else if (analyzedInstruction.getInstruction() instanceof OneRegisterInstruction) { OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.getInstruction(); registers.set(instruction.getRegisterA()); } } private void addMergeRegs(BitSet registers, int registerCount) { if (analyzedInstruction.getPredecessorCount() <= 1) { //in the common case of an instruction that only has a single predecessor which is the previous //instruction, the pre-instruction registers will always match the previous instruction's //post-instruction registers return; } for (int registerNum=0; registerNum= 0; registerNum = registers.nextSetBit(registerNum + 1)) { boolean fullMerge = fullMergeRegisters!=null && fullMergeRegisters.get(registerNum); if (fullMerge) { if (!firstRegister) { writer.write('\n'); writer.write('#'); } writeFullMerge(writer, registerNum); previousWasFullMerge = true; } else { if (previousWasFullMerge) { writer.write('\n'); writer.write('#'); previousWasFullMerge = false; } RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum); registerFormatter.writeTo(writer, registerNum); writer.write('='); registerType.writeTo(writer); writer.write(';'); } firstRegister = false; } return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java000066400000000000000000000111221342202223400302070ustar00rootroot00000000000000/* * [The "BSD licence"] * Copyright (c) 2010 Ben Gruver * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Adaptors; import org.jf.baksmali.Adaptors.EncodedValue.EncodedValueAdaptor; import org.jf.dexlib2.MethodHandleType; import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.iface.reference.*; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.util.IndentingWriter; import org.jf.util.StringUtils; import java.io.IOException; public class ReferenceFormatter { public static void writeStringReference(IndentingWriter writer, String item) throws IOException { writer.write('"'); StringUtils.writeEscapedString(writer, item); writer.write('"'); } public static void writeCallSiteReference(IndentingWriter writer, CallSiteReference callSite) throws IOException { writer.write(callSite.getName()); writer.write('('); writer.write('"'); StringUtils.writeEscapedString(writer, callSite.getMethodName()); writer.write("\", "); writeReference(writer, ReferenceType.METHOD_PROTO, callSite.getMethodProto()); for (EncodedValue encodedValue : callSite.getExtraArguments()) { writer.write(", "); EncodedValueAdaptor.writeTo(writer, encodedValue, null); } writer.write(")@"); MethodHandleReference methodHandle = callSite.getMethodHandle(); if (methodHandle.getMethodHandleType() != MethodHandleType.INVOKE_STATIC) { throw new IllegalArgumentException("The linker method handle for a call site must be of type invoke-static"); } writeReference(writer, ReferenceType.METHOD, callSite.getMethodHandle().getMemberReference()); } public static void writeReference(IndentingWriter writer, int referenceType, Reference reference) throws IOException { switch (referenceType) { case ReferenceType.STRING: writeStringReference(writer, ((StringReference)reference).getString()); return; case ReferenceType.TYPE: writer.write(((TypeReference)reference).getType()); return; case ReferenceType.METHOD: ReferenceUtil.writeMethodDescriptor(writer, (MethodReference)reference); return; case ReferenceType.FIELD: ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference); return; case ReferenceType.METHOD_PROTO: ReferenceUtil.writeMethodProtoDescriptor(writer, (MethodProtoReference)reference); return; case ReferenceType.METHOD_HANDLE: ReferenceUtil.writeMethodHandle(writer, (MethodHandleReference)reference); return; case ReferenceType.CALL_SITE: // We can't use ReferenceUtil.writeCallSite here, because it doesn't write encoded values out in the // exact format we need here. writeCallSiteReference(writer, (CallSiteReference)reference); return; default: throw new IllegalStateException("Unknown reference type"); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/RegisterFormatter.java000066400000000000000000000106771342202223400301130ustar00rootroot00000000000000/* * [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.baksmali.BaksmaliOptions; import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import java.io.IOException; /** * This class contains the logic used for formatting registers */ public class RegisterFormatter { @Nonnull public final BaksmaliOptions options; public final int registerCount; public final int parameterRegisterCount; public RegisterFormatter(@Nonnull BaksmaliOptions options, int registerCount, int parameterRegisterCount) { this.options = options; this.registerCount = registerCount; this.parameterRegisterCount = parameterRegisterCount; } /** * Write out the register range value used by Format3rc. If baksmali.noParameterRegisters is true, it will always * output the registers in the v format. But if false, then it will check if *both* registers are parameter * registers, and if so, use the p format for both. If only the last register is a parameter register, it will * use the v format for both, otherwise it would be confusing to have something like {v20 .. p1} * @param writer the IndentingWriter to write to * @param startRegister the first register in the range * @param lastRegister the last register in the range */ public void writeRegisterRange(IndentingWriter writer, int startRegister, int lastRegister) throws IOException { if (options.parameterRegisters) { assert startRegister <= lastRegister; if (startRegister >= registerCount - parameterRegisterCount) { writer.write("{p"); writer.printSignedIntAsDec(startRegister - (registerCount - parameterRegisterCount)); writer.write(" .. p"); writer.printSignedIntAsDec(lastRegister - (registerCount - parameterRegisterCount)); writer.write('}'); return; } } writer.write("{v"); writer.printSignedIntAsDec(startRegister); writer.write(" .. v"); writer.printSignedIntAsDec(lastRegister); writer.write('}'); } /** * Writes a register with the appropriate format. If baksmali.noParameterRegisters is true, then it will always * output a register in the v format. If false, then it determines if the register is a parameter register, * and if so, formats it in the p format instead. * * @param writer the IndentingWriter to write to * @param register the register number */ public void writeTo(IndentingWriter writer, int register) throws IOException { if (options.parameterRegisters) { if (register >= registerCount - parameterRegisterCount) { writer.write('p'); writer.printSignedIntAsDec((register - (registerCount - parameterRegisterCount))); return; } } writer.write('v'); writer.printSignedIntAsDec(register); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Adaptors/SyntheticAccessCommentMethodItem.java000066400000000000000000000121451342202223400330320ustar00rootroot00000000000000/* * [The "BSD licence"] * Copyright (c) 2011 Ben Gruver * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Adaptors; import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.util.SyntheticAccessorResolver; import org.jf.util.ExceptionWithContext; import org.jf.util.IndentingWriter; import java.io.IOException; public class SyntheticAccessCommentMethodItem extends MethodItem { private final SyntheticAccessorResolver.AccessedMember accessedMember; public SyntheticAccessCommentMethodItem(SyntheticAccessorResolver.AccessedMember accessedMember, int codeAddress) { super(codeAddress); this.accessedMember = accessedMember; } public double getSortOrder() { //just before the pre-instruction register information, if any return 99.8; } public boolean writeTo(IndentingWriter writer) throws IOException { writer.write("# "); switch (accessedMember.accessedMemberType) { case SyntheticAccessorResolver.METHOD: writer.write("invokes: "); break; case SyntheticAccessorResolver.GETTER: writer.write("getter for: "); break; case SyntheticAccessorResolver.SETTER: writer.write("setter for: "); break; case SyntheticAccessorResolver.PREFIX_INCREMENT: writer.write("++operator for: "); break; case SyntheticAccessorResolver.POSTFIX_INCREMENT: writer.write("operator++ for: "); break; case SyntheticAccessorResolver.PREFIX_DECREMENT: writer.write("--operator for: "); break; case SyntheticAccessorResolver.POSTFIX_DECREMENT: writer.write("operator-- for: "); break; case SyntheticAccessorResolver.ADD_ASSIGNMENT: writer.write("+= operator for: "); break; case SyntheticAccessorResolver.SUB_ASSIGNMENT: writer.write("-= operator for: "); break; case SyntheticAccessorResolver.MUL_ASSIGNMENT: writer.write("*= operator for: "); break; case SyntheticAccessorResolver.DIV_ASSIGNMENT: writer.write("/= operator for: "); break; case SyntheticAccessorResolver.REM_ASSIGNMENT: writer.write("%= operator for: "); break; case SyntheticAccessorResolver.AND_ASSIGNMENT: writer.write("&= operator for: "); break; case SyntheticAccessorResolver.OR_ASSIGNMENT: writer.write("|= operator for: "); break; case SyntheticAccessorResolver.XOR_ASSIGNMENT: writer.write("^= operator for: "); break; case SyntheticAccessorResolver.SHL_ASSIGNMENT: writer.write("<<= operator for: "); break; case SyntheticAccessorResolver.SHR_ASSIGNMENT: writer.write(">>= operator for: "); break; case SyntheticAccessorResolver.USHR_ASSIGNMENT: writer.write(">>>= operator for: "); break; default: throw new ExceptionWithContext("Unknown access type: %d", accessedMember.accessedMemberType); } int referenceType; if (accessedMember.accessedMemberType == SyntheticAccessorResolver.METHOD) { referenceType = ReferenceType.METHOD; } else { referenceType = ReferenceType.FIELD; } ReferenceFormatter.writeReference(writer, referenceType, accessedMember.accessedMember); return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/AnalysisArguments.java000066400000000000000000000163671342202223400263410ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.Parameter; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.jf.dexlib2.analysis.ClassPath; import org.jf.dexlib2.analysis.ClassPathResolver; import org.jf.dexlib2.dexbacked.OatFile.OatDexFile; import org.jf.dexlib2.iface.DexFile; import org.jf.util.jcommander.ColonParameterSplitter; import org.jf.util.jcommander.ExtendedParameter; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.util.List; import static org.jf.dexlib2.analysis.ClassPath.NOT_ART; public class AnalysisArguments { @Parameter(names = {"-b", "--bootclasspath", "--bcp"}, description = "A colon separated list of the files to include in the bootclasspath when analyzing the " + "dex file. If not specified, baksmali will attempt to choose an " + "appropriate default. When analyzing oat files, this can simply be the path to the device's " + "boot.oat file. A single empty string can be used to specify that an empty bootclasspath should " + "be used. (e.g. --bootclasspath \"\") See baksmali help classpath for more information.", splitter = ColonParameterSplitter.class) @ExtendedParameter(argumentNames = "classpath") public List bootClassPath = null; @Parameter(names = {"-c", "--classpath", "--cp"}, description = "A colon separated list of additional files to include in the classpath when analyzing the " + "dex file. These will be added to the classpath after any bootclasspath entries.", splitter = ColonParameterSplitter.class) @ExtendedParameter(argumentNames = "classpath") public List classPath = Lists.newArrayList(); @Parameter(names = {"-d", "--classpath-dir", "--cpd", "--dir"}, description = "A directory to search for classpath files. This option can be used multiple times to " + "specify multiple directories to search. They will be searched in the order they are provided.") @ExtendedParameter(argumentNames = "dir") public List classPathDirectories = null; public static class CheckPackagePrivateArgument { @Parameter(names = {"--check-package-private-access", "--package-private", "--checkpp", "--pp"}, description = "Use the package-private access check when calculating vtable indexes. This is enabled " + "by default for oat files. For odex files, this is only needed for odexes from 4.2.0. It " + "was reverted in 4.2.1.") public boolean checkPackagePrivateAccess = false; } @Nonnull public ClassPath loadClassPathForDexFile(@Nonnull File dexFileDir, @Nonnull DexFile dexFile, boolean checkPackagePrivateAccess) throws IOException { return loadClassPathForDexFile(dexFileDir, dexFile, checkPackagePrivateAccess, NOT_ART); } @Nonnull public ClassPath loadClassPathForDexFile(@Nonnull File dexFileDir, @Nonnull DexFile dexFile, boolean checkPackagePrivateAccess, int oatVersion) throws IOException { ClassPathResolver resolver; // By default, oatVersion should be NOT_ART, and we'll automatically set it if dexFile is an oat file. In some // cases the caller may choose to override the oat version, in which case we should use the given oat version // regardless of the actual version of the oat file if (oatVersion == NOT_ART) { if (dexFile instanceof OatDexFile) { checkPackagePrivateAccess = true; oatVersion = ((OatDexFile)dexFile).getContainer().getOatVersion(); } } else { // this should always be true for ART checkPackagePrivateAccess = true; } if (classPathDirectories == null || classPathDirectories.size() == 0) { classPathDirectories = Lists.newArrayList(dexFileDir.getPath()); } List filteredClassPathDirectories = Lists.newArrayList(); if (classPathDirectories != null) { for (String dir: classPathDirectories) { File file = new File(dir); if (!file.exists()) { System.err.println(String.format("Warning: directory %s does not exist. Ignoring.", dir)); } else if (!file.isDirectory()) { System.err.println(String.format("Warning: %s is not a directory. Ignoring.", dir)); } else { filteredClassPathDirectories.add(dir); } } } if (bootClassPath == null) { // TODO: we should be able to get the api from the Opcodes object associated with the dexFile.. // except that the oat version -> api mapping doesn't fully work yet resolver = new ClassPathResolver(filteredClassPathDirectories, classPath, dexFile); } else if (bootClassPath.size() == 1 && bootClassPath.get(0).length() == 0) { // --bootclasspath "" is a special case, denoting that no bootclasspath should be used resolver = new ClassPathResolver( ImmutableList.of(), ImmutableList.of(), classPath, dexFile); } else { resolver = new ClassPathResolver(filteredClassPathDirectories, bootClassPath, classPath, dexFile); } if (oatVersion == 0 && dexFile instanceof OatDexFile) { oatVersion = ((OatDexFile)dexFile).getContainer().getOatVersion(); } return new ClassPath(resolver.getResolvedClassProviders(), checkPackagePrivateAccess, oatVersion); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Baksmali.java000066400000000000000000000161111342202223400243760ustar00rootroot00000000000000/* * [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; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; import org.jf.baksmali.Adaptors.ClassDefinition; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.DexFile; import org.jf.util.ClassFileNameHandler; import org.jf.util.IndentingWriter; import javax.annotation.Nullable; import java.io.*; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.*; public class Baksmali { public static boolean disassembleDexFile(DexFile dexFile, File outputDir, int jobs, final BaksmaliOptions options) { return disassembleDexFile(dexFile, outputDir, jobs, options, null); } public static boolean disassembleDexFile(DexFile dexFile, File outputDir, int jobs, final BaksmaliOptions options, @Nullable List classes) { //sort the classes, so that if we're on a case-insensitive file system and need to handle classes with file //name collisions, then we'll use the same name for each class, if the dex file goes through multiple //baksmali/smali cycles for some reason. If a class with a colliding name is added or removed, the filenames //may still change of course List classDefs = Ordering.natural().sortedCopy(dexFile.getClasses()); final ClassFileNameHandler fileNameHandler = new ClassFileNameHandler(outputDir, ".smali"); ExecutorService executor = Executors.newFixedThreadPool(jobs); List> tasks = Lists.newArrayList(); Set classSet = null; if (classes != null) { classSet = new HashSet(classes); } for (final ClassDef classDef: classDefs) { if (classSet != null && !classSet.contains(classDef.getType())) { continue; } tasks.add(executor.submit(new Callable() { @Override public Boolean call() throws Exception { return disassembleClass(classDef, fileNameHandler, options); } })); } boolean errorOccurred = false; try { for (Future task: tasks) { while(true) { try { if (!task.get()) { errorOccurred = true; } } catch (InterruptedException ex) { continue; } catch (ExecutionException ex) { throw new RuntimeException(ex); } break; } } } finally { executor.shutdown(); } return !errorOccurred; } private static boolean disassembleClass(ClassDef classDef, ClassFileNameHandler fileNameHandler, BaksmaliOptions options) { /** * The path for the disassembly file is based on the package name * The class descriptor will look something like: * Ljava/lang/Object; * Where the there is leading 'L' and a trailing ';', and the parts of the * package name are separated by '/' */ String classDescriptor = classDef.getType(); //validate that the descriptor is formatted like we expect if (classDescriptor.charAt(0) != 'L' || classDescriptor.charAt(classDescriptor.length()-1) != ';') { System.err.println("Unrecognized class descriptor - " + classDescriptor + " - skipping class"); return false; } File smaliFile = fileNameHandler.getUniqueFilenameForClass(classDescriptor); //create and initialize the top level string template ClassDefinition classDefinition = new ClassDefinition(options, classDef); //write the disassembly Writer writer = null; try { File smaliParent = smaliFile.getParentFile(); if (!smaliParent.exists()) { if (!smaliParent.mkdirs()) { // check again, it's likely it was created in a different thread if (!smaliParent.exists()) { System.err.println("Unable to create directory " + smaliParent.toString() + " - skipping class"); return false; } } } if (!smaliFile.exists()){ if (!smaliFile.createNewFile()) { System.err.println("Unable to create file " + smaliFile.toString() + " - skipping class"); return false; } } BufferedWriter bufWriter = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(smaliFile), "UTF8")); writer = new IndentingWriter(bufWriter); classDefinition.writeTo((IndentingWriter)writer); } catch (Exception ex) { System.err.println("\n\nError occurred while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class"); ex.printStackTrace(); // noinspection ResultOfMethodCallIgnored smaliFile.delete(); return false; } finally { if (writer != null) { try { writer.close(); } catch (Throwable ex) { System.err.println("\n\nError occurred while closing file " + smaliFile.toString()); ex.printStackTrace(); } } } return true; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/BaksmaliOptions.java000066400000000000000000000110561342202223400257550ustar00rootroot00000000000000/* * Copyright 2013, 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; import org.jf.dexlib2.analysis.ClassPath; import org.jf.dexlib2.analysis.InlineMethodResolver; import org.jf.dexlib2.util.SyntheticAccessorResolver; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class BaksmaliOptions { public int apiLevel = 15; public boolean parameterRegisters = true; public boolean localsDirective = false; public boolean sequentialLabels = false; public boolean debugInfo = true; public boolean codeOffsets = false; public boolean accessorComments = true; public boolean allowOdex = false; public boolean deodex = false; public boolean implicitReferences = false; public boolean normalizeVirtualMethods = false; // register info values public static final int ALL = 1; public static final int ALLPRE = 2; public static final int ALLPOST = 4; public static final int ARGS = 8; public static final int DEST = 16; public static final int MERGE = 32; public static final int FULLMERGE = 64; public int registerInfo = 0; public Map resourceIds = new HashMap(); public InlineMethodResolver inlineResolver = null; public ClassPath classPath = null; public SyntheticAccessorResolver syntheticAccessorResolver = null; /** * Load the resource ids from a set of public.xml files. * * @param resourceFiles A map of resource prefixes -> public.xml files */ public void loadResourceIds(Map resourceFiles) throws SAXException, IOException { for (Map.Entry entry: resourceFiles.entrySet()) { try { SAXParser saxp = SAXParserFactory.newInstance().newSAXParser(); final String prefix = entry.getKey(); saxp.parse(entry.getValue(), new DefaultHandler() { @Override public void startElement(String uri, String localName, String qName, Attributes attr) throws SAXException { if (qName.equals("public")) { String resourceType = attr.getValue("type"); String resourceName = attr.getValue("name").replace('.', '_'); Integer resourceId = Integer.decode(attr.getValue("id")); String qualifiedResourceName = String.format("%s.%s.%s", prefix, resourceType, resourceName); resourceIds.put(resourceId, qualifiedResourceName); } } }); } catch (ParserConfigurationException ex) { throw new RuntimeException(ex); } } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/DeodexCommand.java000066400000000000000000000106121342202223400253620ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.beust.jcommander.ParametersDelegate; import org.jf.baksmali.AnalysisArguments.CheckPackagePrivateArgument; import org.jf.dexlib2.analysis.CustomInlineMethodResolver; import org.jf.dexlib2.analysis.InlineMethodResolver; import org.jf.dexlib2.dexbacked.DexBackedOdexFile; import org.jf.util.jcommander.ExtendedParameter; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.util.List; @Parameters(commandDescription = "Deodexes an odex/oat file") @ExtendedParameters( commandName = "deodex", commandAliases = { "de", "x" }) public class DeodexCommand extends DisassembleCommand { @ParametersDelegate protected CheckPackagePrivateArgument checkPackagePrivateArgument = new CheckPackagePrivateArgument(); @Parameter(names = {"--inline-table", "--inline", "--it"}, description = "Specify a file containing a custom inline method table to use. See the " + "\"deodexerant\" tool in the smali github repository to dump the inline method table from a " + "device that uses dalvik.") @ExtendedParameter(argumentNames = "file") private String inlineTable; public DeodexCommand(@Nonnull List commandAncestors) { super(commandAncestors); } @Override protected BaksmaliOptions getOptions() { BaksmaliOptions options = super.getOptions(); options.deodex = true; if (dexFile instanceof DexBackedOdexFile) { if (inlineTable == null) { options.inlineResolver = InlineMethodResolver.createInlineMethodResolver( ((DexBackedOdexFile)dexFile).getOdexVersion()); } else { File inlineTableFile = new File(inlineTable); if (!inlineTableFile.exists()) { System.err.println(String.format("Could not find file: %s", inlineTable)); System.exit(-1); } try { options.inlineResolver = new CustomInlineMethodResolver(options.classPath, inlineTableFile); } catch (IOException ex) { System.err.println(String.format("Error while reading file: %s", inlineTableFile)); ex.printStackTrace(System.err); System.exit(-1); } } } return options; } @Override protected boolean shouldCheckPackagePrivateAccess() { return checkPackagePrivateArgument.checkPackagePrivateAccess; } @Override protected boolean needsClassPath() { return true; } @Override protected boolean showDeodexWarning() { return false; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/DexInputCommand.java000066400000000000000000000147571342202223400257300ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.google.common.base.Strings; import com.google.common.collect.Lists; import org.jf.dexlib2.DexFileFactory; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.util.jcommander.Command; import org.jf.util.jcommander.ExtendedParameter; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.util.List; /** * This class implements common functionality for commands that need to load a dex file based on * command line input */ public abstract class DexInputCommand extends Command { @Parameter(names = {"-a", "--api"}, description = "The numeric api level of the file being disassembled.") @ExtendedParameter(argumentNames = "api") public int apiLevel = -1; @Parameter(description = "A dex/apk/oat/odex file. For apk or oat files that contain multiple dex " + "files, you can specify the specific entry to use as if the apk/oat file was a directory. " + "e.g. \"app.apk/classes2.dex\". For more information, see \"baksmali help input\".") @ExtendedParameter(argumentNames = "file") protected List inputList = Lists.newArrayList(); protected File inputFile; protected String inputEntry; protected DexBackedDexFile dexFile; public DexInputCommand(@Nonnull List commandAncestors) { super(commandAncestors); } /** * Parses a dex file input from the user and loads the given dex file. * * In some cases, the input file can contain multiple dex files. If this is the case, you can refer to a specific * dex file with a slash, followed by the entry name, optionally in quotes. * * If the entry name is enclosed in quotes, then it will strip the first and last quote and look for an entry with * exactly that name. Otherwise, it will perform a partial filename match against the entry to find any candidates. * If there is a single matching candidate, it will be used. Otherwise, an error will be generated. * * For example, to refer to the "/system/framework/framework.jar:classes2.dex" entry within the * "framework/arm/framework.oat" oat file, you could use any of: * * framework/arm/framework.oat/"/system/framework/framework.jar:classes2.dex" * framework/arm/framework.oat/system/framework/framework.jar:classes2.dex * framework/arm/framework.oat/framework/framework.jar:classes2.dex * framework/arm/framework.oat/framework.jar:classes2.dex * framework/arm/framework.oat/classes2.dex * * The last option is the easiest, but only works if the oat file doesn't contain another entry with the * "classes2.dex" name. e.g. "/system/framework/blah.jar:classes2.dex" * * It's technically possible (although unlikely) for an oat file to contain 2 entries like: * /system/framework/framework.jar:classes2.dex * system/framework/framework.jar:classes2.dex * * In this case, the "framework/arm/framework.oat/system/framework/framework.jar:classes2.dex" syntax will generate * an error because both entries match the partial entry name. Instead, you could use the following for the * first and second entry respectively: * * framework/arm/framework.oat/"/system/framework/framework.jar:classes2.dex" * framework/arm/framework.oat/"system/framework/framework.jar:classes2.dex" * * @param input The name of a dex, apk, odex or oat file/entry. */ protected void loadDexFile(@Nonnull String input) { File file = new File(input); while (file != null && !file.exists()) { file = file.getParentFile(); } if (file == null || !file.exists() || file.isDirectory()) { System.err.println("Can't find file: " + input); System.exit(1); } inputFile = file; String dexEntry = null; if (file.getPath().length() < input.length()) { dexEntry = input.substring(file.getPath().length() + 1); } Opcodes opcodes = null; if (apiLevel != -1) { opcodes = Opcodes.forApi(apiLevel); } if (!Strings.isNullOrEmpty(dexEntry)) { boolean exactMatch = false; if (dexEntry.length() > 2 && dexEntry.charAt(0) == '"' && dexEntry.charAt(dexEntry.length() - 1) == '"') { dexEntry = dexEntry.substring(1, dexEntry.length() - 1); exactMatch = true; } inputEntry = dexEntry; try { dexFile = DexFileFactory.loadDexEntry(file, dexEntry, exactMatch, opcodes); } catch (IOException ex) { throw new RuntimeException(ex); } } else { try { dexFile = DexFileFactory.loadDexFile(file, opcodes); } catch (IOException ex) { throw new RuntimeException(ex); } } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/DisassembleCommand.java000066400000000000000000000315721342202223400264150ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.beust.jcommander.ParametersDelegate; import com.beust.jcommander.validators.PositiveInteger; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.jf.dexlib2.util.SyntheticAccessorResolver; import org.jf.util.ConsoleUtil; import org.jf.util.StringWrapper; import org.jf.util.jcommander.ExtendedParameter; import org.jf.util.jcommander.ExtendedParameters; import org.xml.sax.SAXException; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; @Parameters(commandDescription = "Disassembles a dex file.") @ExtendedParameters( commandName = "disassemble", commandAliases = { "dis", "d" }) public class DisassembleCommand extends DexInputCommand { @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Show usage information for this command.") private boolean help; @ParametersDelegate protected AnalysisArguments analysisArguments = new AnalysisArguments(); @Parameter(names = {"--debug-info", "--di"}, arity = 1, description = "Whether to include debug information in the output (.local, .param, .line, etc.). True " + "by default, use --debug-info=false to disable.") @ExtendedParameter(argumentNames = "boolean") private boolean debugInfo = true; @Parameter(names = {"--code-offsets", "--offsets", "--off"}, description = "Add a comment before each instruction with it's code offset within the method.") private boolean codeOffsets = false; @Parameter(names = {"--resolve-resources", "--rr"}, arity = 2, description = "This will attempt to find any resource id references within the bytecode and add a " + "comment with the name of the resource being referenced. The parameter accepts 2 values:" + "an arbitrary resource prefix and the path to a public.xml file. For example: " + "--resolve-resources android.R framework/res/values/public.xml. This option can be specified " + "multiple times to provide resources from multiple packages.") @ExtendedParameter(argumentNames = {"resource prefix", "public.xml file"}) private List resourceIdFiles = Lists.newArrayList(); @Parameter(names = {"-j", "--jobs"}, description = "The number of threads to use. Defaults to the number of cores available.", validateWith = PositiveInteger.class) @ExtendedParameter(argumentNames = "n") private int jobs = Runtime.getRuntime().availableProcessors(); @Parameter(names = {"-l", "--use-locals"}, description = "When disassembling, output the .locals directive with the number of non-parameter " + "registers instead of the .registers directive with the total number of registers.") private boolean localsDirective = false; @Parameter(names = {"--accessor-comments", "--ac"}, arity = 1, description = "Generate helper comments for synthetic accessors. True by default, use " + "--accessor-comments=false to disable.") @ExtendedParameter(argumentNames = "boolean") private boolean accessorComments = true; @Parameter(names = {"--normalize-virtual-methods", "--norm", "--nvm"}, description = "Normalize virtual method references to use the base class where the method is " + "originally declared.") private boolean normalizeVirtualMethods = false; @Parameter(names = {"-o", "--output"}, description = "The directory to write the disassembled files to.") @ExtendedParameter(argumentNames = "dir") private String outputDir = "out"; @Parameter(names = {"--parameter-registers", "--preg", "--pr"}, arity = 1, description = "Use the pNN syntax for registers that refer to a method parameter on method entry. True " + "by default, use --parameter-registers=false to disable.") @ExtendedParameter(argumentNames = "boolean") private boolean parameterRegisters = true; @Parameter(names = {"-r", "--register-info"}, description = "Add comments before/after each instruction with information about register types. " + "The value is a comma-separated list of any of ALL, ALLPRE, ALLPOST, ARGS, DEST, MERGE and " + "FULLMERGE. See \"baksmali help register-info\" for more information.") @ExtendedParameter(argumentNames = "register info specifier") private List registerInfoTypes = Lists.newArrayList(); @Parameter(names = {"--sequential-labels", "--seq", "--sl"}, description = "Create label names using a sequential numbering scheme per label type, rather than " + "using the bytecode address.") private boolean sequentialLabels = false; @Parameter(names = {"--implicit-references", "--implicit", "--ir"}, description = "Use implicit method and field references (without the class name) for methods and " + "fields from the current class.") private boolean implicitReferences = false; @Parameter(names = "--allow-odex-opcodes", description = "Allows odex opcodes to be disassembled, even if the result won't be able to be reassembled.") private boolean allowOdex = false; @Parameter(names = "--classes", description = "A comma separated list of classes. Only disassemble these classes") @ExtendedParameter(argumentNames = "classes") private List classes = null; public DisassembleCommand(@Nonnull List commandAncestors) { super(commandAncestors); } public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); loadDexFile(input); if (showDeodexWarning() && dexFile.hasOdexOpcodes()) { StringWrapper.printWrappedString(System.err, "Warning: You are disassembling an odex/oat file without deodexing it. You won't be able to " + "re-assemble the results unless you deodex it. See \"baksmali help deodex\"", ConsoleUtil.getConsoleWidth()); } File outputDirectoryFile = new File(outputDir); if (!outputDirectoryFile.exists()) { if (!outputDirectoryFile.mkdirs()) { System.err.println("Can't create the output directory " + outputDir); System.exit(-1); } } if (analysisArguments.classPathDirectories == null || analysisArguments.classPathDirectories.isEmpty()) { analysisArguments.classPathDirectories = Lists.newArrayList(inputFile.getAbsoluteFile().getParent()); } if (!Baksmali.disassembleDexFile(dexFile, outputDirectoryFile, jobs, getOptions(), classes)) { System.exit(-1); } } protected boolean needsClassPath() { return !registerInfoTypes.isEmpty() || normalizeVirtualMethods; } protected boolean shouldCheckPackagePrivateAccess() { return false; } protected boolean showDeodexWarning() { return true; } protected BaksmaliOptions getOptions() { if (dexFile == null) { throw new IllegalStateException("You must call loadDexFile first"); } final BaksmaliOptions options = new BaksmaliOptions(); if (needsClassPath()) { try { options.classPath = analysisArguments.loadClassPathForDexFile( inputFile.getAbsoluteFile().getParentFile(), dexFile, shouldCheckPackagePrivateAccess()); } catch (Exception ex) { System.err.println("\n\nError occurred while loading class path files. Aborting."); ex.printStackTrace(System.err); System.exit(-1); } } if (!resourceIdFiles.isEmpty()) { Map resourceFiles = Maps.newHashMap(); assert (resourceIdFiles.size() % 2) == 0; for (int i=0; i commandAncestors) { super(commandAncestors); } public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); loadDexFile(input); try { dump(dexFile, System.out); } catch (IOException ex) { System.err.println("There was an error while dumping the dex file"); ex.printStackTrace(System.err); } } /** * Writes an annotated hex dump of the given dex file to output. * * @param dexFile The dex file to dump * @param output An OutputStream to write the annotated hex dump to. The caller is responsible for closing this * when needed. * * @throws IOException */ public static void dump(@Nonnull DexBackedDexFile dexFile, @Nonnull OutputStream output) throws IOException { Writer writer = new BufferedWriter(new OutputStreamWriter(output)); try { int consoleWidth = ConsoleUtil.getConsoleWidth(); if (consoleWidth <= 0) { consoleWidth = 120; } RawDexFile rawDexFile = new RawDexFile(dexFile.getOpcodes(), dexFile); DexAnnotator annotator = new DexAnnotator(rawDexFile, consoleWidth); annotator.writeAnnotations(writer); } finally { writer.close(); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/HelpCommand.java000066400000000000000000000307021342202223400250440ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.collect.Lists; import org.jf.util.ConsoleUtil; import org.jf.util.StringWrapper; import org.jf.util.jcommander.*; import javax.annotation.Nonnull; import java.util.List; @Parameters(commandDescription = "Shows usage information") @ExtendedParameters( commandName = "help", commandAliases = "h") public class HelpCommand extends Command { public HelpCommand(@Nonnull List commandAncestors) { super(commandAncestors); } @Parameter(description = "If specified, show the detailed usage information for the given commands") @ExtendedParameter(argumentNames = "commands") private List commands = Lists.newArrayList(); public void run() { JCommander parentJc = commandAncestors.get(commandAncestors.size() - 1); if (commands == null || commands.isEmpty()) { System.out.println(new HelpFormatter() .width(ConsoleUtil.getConsoleWidth()) .format(commandAncestors)); } else { boolean printedHelp = false; for (String cmd : commands) { if (cmd.equals("register-info")) { printedHelp = true; String registerInfoHelp = "The --register-info parameter will cause baksmali to generate " + "comments before and after every instruction containing register type " + "information about some subset of registers. This parameter accepts a comma-separated list" + "of values specifying which registers and how much information to include.\n" + " ALL: all pre- and post-instruction registers\n" + " ALLPRE: all pre-instruction registers\n" + " ALLPOST: all post-instruction registers\n" + " ARGS: any pre-instruction registers used as arguments to the instruction\n" + " DEST: the post-instruction register used as the output of the instruction\n" + " MERGE: any pre-instruction register that has been merged from multiple " + "incoming code paths\n" + " FULLMERGE: an extended version of MERGE that also includes a list of all " + "the register types from incoming code paths that were merged"; Iterable lines = StringWrapper.wrapStringOnBreaks(registerInfoHelp, ConsoleUtil.getConsoleWidth()); for (String line : lines) { System.out.println(line); } } else if (cmd.equals("input")) { printedHelp = true; String registerInfoHelp = "Apks and oat files can contain multiple dex files. In order to " + "specify a particular dex file, the basic syntax is to treat the apk/oat file as a " + "directory. For example, to load the \"classes2.dex\" entry from \"app.apk\", you can " + "use \"app.apk/classes2.dex\".\n" + "\n" + "For ease of use, you can also specify a partial path to the dex file to load. For " + "example, to load a entry named \"/system/framework/framework.jar:classes2.dex\" from " + "\"framework.oat\", you can use any of the following:\n" + "\"framework.oat/classes2.dex\"\n" + "\"framework.oat/framework.jar:classes2.dex\"\n" + "\"framework.oat/framework/framework.jar:classes2.dex\"\n" + "\"framework.oat/system/framework/framework.jar:classes2.dex\"\n" + "\n" + "In some rare cases, an oat file could have entries that can't be differentiated with " + "the above syntax. For example \"/blah/blah.dex\" and \"blah/blah.dex\". In this case, " + "the \"blah.oat/blah/blah.dex\" would match both entries and generate an error. To get " + "around this, you can add double quotes around the entry name to specify an exact entry " + "name. E.g. blah.oat/\"/blah/blah.dex\" or blah.oat/\"blah/blah.dex\" respectively."; Iterable lines = StringWrapper.wrapStringOnBreaks(registerInfoHelp, ConsoleUtil.getConsoleWidth()); for (String line : lines) { System.out.println(line); } } else if (cmd.equals("classpath")) { printedHelp = true; String registerInfoHelp = "When deodexing odex/oat files or when using the --register-info " + "option, baksmali needs to load all classes from the framework files on the device " + "in order to fully understand the class hierarchy. There are several options that " + "control how baksmali finds and loads the classpath entries.\n" + "\n"+ "L+ devices (ART):\n" + "When deodexing or disassembling a file from an L+ device using ART, you generally " + "just need to specify the path to the boot.oat file via the --bootclasspath/-b " + "parameter. On pre-N devices, the boot.oat file is self-contained and no other files are " + "needed. In N, boot.oat was split into multiple files. In this case, the other " + "files should be in the same directory as the boot.oat file, but you still only need to " + "specify the boot.oat file in the --bootclasspath/-b option. The other files will be " + "automatically loaded from the same directory.\n" + "\n" + "Pre-L devices (dalvik):\n" + "When deodexing odex files from a pre-L device using dalvik, you " + "generally just need to specify the path to a directory containing the framework files " + "from the device via the --classpath-dir/-d option. odex files contain a list of " + "framework files they depend on and baksmali will search for these dependencies in the " + "directory that you specify.\n" + "\n" + "Dex files don't contain a list of dependencies like odex files, so when disassembling a " + "dex file using the --register-info option, and using the framework files from a " + "pre-L device, baksmali will attempt to use a reasonable default list of classpath files " + "based on the api level set via the -a option. If this default list is incorrect, you " + "can override the classpath using the --bootclasspath/-b option. This option accepts a " + "colon separated list of classpath entries. Each entry can be specified in a few " + "different ways.\n" + " - A simple filename like \"framework.jar\"\n" + " - A device path like \"/system/framework/framework.jar\"\n" + " - A local relative or absolute path like \"/tmp/framework/framework.jar\"\n" + "When using the first or second formats, you should also specify the directory " + "containing the framework files via the --classpath-dir/-d option. When using the third " + "format, this option is not needed.\n" + "It's worth noting that the second format matches the format used by Android for the " + "BOOTCLASSPATH environment variable, so you can simply grab the value of that variable " + "from the device and use it as-is.\n" + "\n" + "Examples:\n" + " For an M device:\n" + " adb pull /system/framework/arm/boot.oat /tmp/boot.oat\n" + " baksmali deodex blah.oat -b /tmp/boot.oat\n" + " For an N+ device:\n" + " adb pull /system/framework/arm /tmp/framework\n" + " baksmali deodex blah.oat -b /tmp/framework/boot.oat\n" + " For a pre-L device:\n" + " adb pull /system/framework /tmp/framework\n" + " baksmali deodex blah.odex -d /tmp/framework\n" + " Using the BOOTCLASSPATH on a pre-L device:\n" + " adb pull /system/framework /tmp/framework\n" + " export BOOTCLASSPATH=`adb shell \"echo \\\\$BOOTCLASPATH\"`\n" + " baksmali disassemble --register-info ARGS,DEST blah.apk -b $BOOTCLASSPATH -d " + "/tmp/framework"; Iterable lines = StringWrapper.wrapStringOnBreaks(registerInfoHelp, ConsoleUtil.getConsoleWidth()); for (String line : lines) { System.out.println(line); } } else { JCommander command = ExtendedCommands.getSubcommand(parentJc, cmd); if (command == null) { System.err.println("No such command: " + cmd); } else { printedHelp = true; System.out.println(new HelpFormatter() .width(ConsoleUtil.getConsoleWidth()) .format(((Command)command.getObjects().get(0)).getCommandHierarchy())); } } } if (!printedHelp) { System.out.println(new HelpFormatter() .width(ConsoleUtil.getConsoleWidth()) .format(commandAncestors)); } } } @Parameters(hidden = true) @ExtendedParameters(commandName = "hlep") public static class HlepCommand extends HelpCommand { public HlepCommand(@Nonnull List commandAncestors) { super(commandAncestors); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListClassesCommand.java000066400000000000000000000053731342202223400264130ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import org.jf.dexlib2.iface.ClassDef; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.util.List; @Parameters(commandDescription = "Lists the classes in a dex file.") @ExtendedParameters( commandName = "classes", commandAliases = { "class", "c" }) public class ListClassesCommand extends DexInputCommand { @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Show usage information") private boolean help; public ListClassesCommand(@Nonnull List commandAncestors) { super(commandAncestors); } @Override public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); loadDexFile(input); for (ClassDef classDef: dexFile.getClasses()) { System.out.println(classDef.getType()); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListCommand.java000066400000000000000000000072431342202223400250730ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import org.jf.baksmali.ListHelpCommand.ListHlepCommand; import org.jf.util.jcommander.Command; import org.jf.util.jcommander.ExtendedCommands; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.util.List; @Parameters(commandDescription = "Lists various objects in a dex file.") @ExtendedParameters( commandName = "list", commandAliases = "l") public class ListCommand extends Command { @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Show usage information") private boolean help; public ListCommand(@Nonnull List commandAncestors) { super(commandAncestors); } @Override protected void setupCommand(JCommander jc) { List hierarchy = getCommandHierarchy(); ExtendedCommands.addExtendedCommand(jc, new ListStringsCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListMethodsCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListFieldsCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListTypesCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListClassesCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListDexCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListVtablesCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListFieldOffsetsCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListDependenciesCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListHelpCommand(hierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListHlepCommand(hierarchy)); } @Override public void run() { JCommander jc = getJCommander(); if (help || jc.getParsedCommand() == null) { usage(); return; } Command command = (Command)jc.getCommands().get(jc.getParsedCommand()).getObjects().get(0); command.run(); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListDependenciesCommand.java000066400000000000000000000104661342202223400274030ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.collect.Lists; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.DexBackedOdexFile; import org.jf.dexlib2.dexbacked.OatFile; import org.jf.util.jcommander.Command; import org.jf.util.jcommander.ExtendedParameter; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.io.*; import java.util.List; @Parameters(commandDescription = "Lists the stored dependencies in an odex/oat file.") @ExtendedParameters( commandName = "dependencies", commandAliases = { "deps", "dep" }) public class ListDependenciesCommand extends Command { @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Show usage information") private boolean help; @Parameter(description = "An oat/odex file") @ExtendedParameter(argumentNames = "file") private List inputList = Lists.newArrayList(); public ListDependenciesCommand(@Nonnull List commandAncestors) { super(commandAncestors); } @Override public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); InputStream inputStream = null; try { inputStream = new BufferedInputStream(new FileInputStream(input)); } catch (FileNotFoundException ex) { System.err.println("Could not find file: " + input); System.exit(-1); } try { OatFile oatFile = OatFile.fromInputStream(inputStream); for (String entry: oatFile.getBootClassPath()) { System.out.println(entry); } return; } catch (OatFile.NotAnOatFileException ex) { // ignore } catch (IOException ex) { throw new RuntimeException(ex); } try { DexBackedOdexFile odexFile = DexBackedOdexFile.fromInputStream(Opcodes.getDefault(), inputStream); for (String entry: odexFile.getDependencies()) { System.out.println(entry); } return; } catch (IOException ex) { throw new RuntimeException(ex); } catch (DexBackedOdexFile.NotAnOdexFile ex) { // handled below } catch (DexBackedDexFile.NotADexFile ex) { // handled below } System.err.println(input + " is not an odex or oat file."); System.exit(-1); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListDexCommand.java000066400000000000000000000072071342202223400255340ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.collect.Lists; import org.jf.dexlib2.DexFileFactory; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.iface.MultiDexContainer; import org.jf.util.jcommander.Command; import org.jf.util.jcommander.ExtendedParameter; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.util.List; @Parameters(commandDescription = "Lists the dex files in an apk/oat file.") @ExtendedParameters( commandName = "dex", commandAliases = "d") public class ListDexCommand extends Command { @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Show usage information") private boolean help; @Parameter(description = "An apk or oat file.") @ExtendedParameter(argumentNames = "file") private List inputList = Lists.newArrayList(); public ListDexCommand(@Nonnull List commandAncestors) { super(commandAncestors); } @Override public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); File file = new File(input); if (!file.exists()) { System.err.println(String.format("Could not find the file: %s", input)); System.exit(-1); } List entries; try { MultiDexContainer container = DexFileFactory.loadDexContainer(file, Opcodes.getDefault()); entries = container.getDexEntryNames(); } catch (IOException ex) { throw new RuntimeException(ex); } for (String entry: entries) { System.out.println(entry); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListFieldOffsetsCommand.java000066400000000000000000000110371342202223400273650ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.beust.jcommander.ParametersDelegate; import org.jf.dexlib2.analysis.ClassProto; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.util.SparseArray; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.io.IOException; import java.util.List; @Parameters(commandDescription = "Lists the instance field offsets for classes in a dex file.") @ExtendedParameters( commandName = "fieldoffsets", commandAliases = { "fieldoffset", "fo" }) public class ListFieldOffsetsCommand extends DexInputCommand { @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Show usage information") private boolean help; @ParametersDelegate private AnalysisArguments analysisArguments = new AnalysisArguments(); public ListFieldOffsetsCommand(@Nonnull List commandAncestors) { super(commandAncestors); } @Override public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); loadDexFile(input); BaksmaliOptions options = getOptions(); try { for (ClassDef classDef: dexFile.getClasses()) { ClassProto classProto = (ClassProto) options.classPath.getClass(classDef); SparseArray fields = classProto.getInstanceFields(); String className = "Class " + classDef.getType() + " : " + fields.size() + " instance fields\n"; System.out.write(className.getBytes()); for (int i=0;i commandAncestors) { super(commandAncestors, ReferenceType.FIELD); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListHelpCommand.java000066400000000000000000000073021342202223400257000ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.collect.Iterables; import org.jf.util.ConsoleUtil; import org.jf.util.jcommander.*; import javax.annotation.Nonnull; import java.util.List; @Parameters(commandDescription = "Shows usage information") @ExtendedParameters( commandName = "help", commandAliases = "h") public class ListHelpCommand extends Command { @Parameter(description = "If specified, show the detailed usage information for the given commands") @ExtendedParameter(argumentNames = "commands") private List commands; public ListHelpCommand(@Nonnull List commandAncestors) { super(commandAncestors); } public void run() { if (commands == null || commands.isEmpty()) { System.out.println(new HelpFormatter() .width(ConsoleUtil.getConsoleWidth()) .format(commandAncestors)); } else { boolean printedHelp = false; JCommander parentJc = Iterables.getLast(commandAncestors); for (String cmd : commands) { JCommander command = ExtendedCommands.getSubcommand(parentJc, cmd); if (command == null) { System.err.println("No such command: " + cmd); } else { printedHelp = true; System.out.println(new HelpFormatter() .width(ConsoleUtil.getConsoleWidth()) .format(((Command)command.getObjects().get(0)).getCommandHierarchy())); } } if (!printedHelp) { System.out.println(new HelpFormatter() .width(ConsoleUtil.getConsoleWidth()) .format(commandAncestors)); } } } @Parameters(hidden = true) @ExtendedParameters(commandName = "hlep") public static class ListHlepCommand extends ListHelpCommand { public ListHlepCommand(@Nonnull List commandAncestors) { super(commandAncestors); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListMethodsCommand.java000066400000000000000000000042051342202223400264120ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameters; import org.jf.dexlib2.ReferenceType; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.util.List; @Parameters(commandDescription = "Lists the methods in a dex file's method table.") @ExtendedParameters( commandName = "methods", commandAliases = { "method", "m" }) public class ListMethodsCommand extends ListReferencesCommand { public ListMethodsCommand(@Nonnull List commandAncestors) { super(commandAncestors, ReferenceType.METHOD); } }smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListReferencesCommand.java000066400000000000000000000053171342202223400270750ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import org.jf.dexlib2.iface.reference.Reference; import org.jf.dexlib2.util.ReferenceUtil; import javax.annotation.Nonnull; import java.util.List; public abstract class ListReferencesCommand extends DexInputCommand { private final int referenceType; @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Show usage information") private boolean help; public ListReferencesCommand(@Nonnull List commandAncestors, int referenceType) { super(commandAncestors); this.referenceType = referenceType; } @Override public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); loadDexFile(input); for (Reference reference: dexFile.getReferences(referenceType)) { System.out.println(ReferenceUtil.getReferenceString(reference)); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListStringsCommand.java000066400000000000000000000042141342202223400264400ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameters; import org.jf.dexlib2.ReferenceType; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.util.List; @Parameters(commandDescription = "Lists the strings in a dex file's string table.") @ExtendedParameters( commandName = "strings", commandAliases = { "string", "str", "s" }) public class ListStringsCommand extends ListReferencesCommand { public ListStringsCommand(@Nonnull List commandAncestors) { super(commandAncestors, ReferenceType.STRING); } }smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListTypesCommand.java000066400000000000000000000041731342202223400261170ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameters; import org.jf.dexlib2.ReferenceType; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.util.List; @Parameters(commandDescription = "Lists the type ids in a dex file's type table.") @ExtendedParameters( commandName = "types", commandAliases = { "type", "t" }) public class ListTypesCommand extends ListReferencesCommand { public ListTypesCommand(@Nonnull List commandAncestors) { super(commandAncestors, ReferenceType.TYPE); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/ListVtablesCommand.java000066400000000000000000000137571342202223400264230ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.beust.jcommander.ParametersDelegate; import org.jf.baksmali.AnalysisArguments.CheckPackagePrivateArgument; import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.analysis.ClassProto; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.Method; import org.jf.util.jcommander.ExtendedParameter; import org.jf.util.jcommander.ExtendedParameters; import javax.annotation.Nonnull; import java.io.IOException; import java.util.List; @Parameters(commandDescription = "Lists the virtual method tables for classes in a dex file.") @ExtendedParameters( commandName = "vtables", commandAliases = { "vtable", "v" }) public class ListVtablesCommand extends DexInputCommand { @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Show usage information") private boolean help; @ParametersDelegate private AnalysisArguments analysisArguments = new AnalysisArguments(); @ParametersDelegate private CheckPackagePrivateArgument checkPackagePrivateArgument = new CheckPackagePrivateArgument(); @Parameter(names = "--classes", description = "A comma separated list of classes. Only print the vtable for these classes") @ExtendedParameter(argumentNames = "classes") private List classes = null; @Parameter(names = "--override-oat-version", description = "Uses a classpath for the given oat version, regardless of the actual oat version. This " + "can be used, e.g. to list vtables from a dex file, as if they were in an oat file of the given " + "version.") private int oatVersion = 0; public ListVtablesCommand(@Nonnull List commandAncestors) { super(commandAncestors); } @Override public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); loadDexFile(input); BaksmaliOptions options = getOptions(); if (options == null) { return; } try { if (classes != null && !classes.isEmpty()) { for (String cls: classes) { listClassVtable((ClassProto)options.classPath.getClass(cls)); } return; } for (ClassDef classDef : dexFile.getClasses()) { if (!AccessFlags.INTERFACE.isSet(classDef.getAccessFlags())) { listClassVtable((ClassProto)options.classPath.getClass(classDef)); } } } catch (IOException ex) { throw new RuntimeException(ex); } } private void listClassVtable(ClassProto classProto) throws IOException { List methods = classProto.getVtable(); String className = "Class " + classProto.getType() + " extends " + classProto.getSuperclass() + " : " + methods.size() + " methods\n"; System.out.write(className.getBytes()); for (int i = 0; i < methods.size(); i++) { Method method = methods.get(i); String methodString = i + ":" + method.getDefiningClass() + "->" + method.getName() + "("; for (CharSequence parameter : method.getParameterTypes()) { methodString += parameter; } methodString += ")" + method.getReturnType() + "\n"; System.out.write(methodString.getBytes()); } System.out.write("\n".getBytes()); } protected BaksmaliOptions getOptions() { if (dexFile == null) { throw new IllegalStateException("You must call loadDexFile first"); } final BaksmaliOptions options = new BaksmaliOptions(); options.apiLevel = apiLevel; try { options.classPath = analysisArguments.loadClassPathForDexFile(inputFile.getAbsoluteFile().getParentFile(), dexFile, checkPackagePrivateArgument.checkPackagePrivateAccess, oatVersion); } catch (Exception ex) { System.err.println("Error occurred while loading class path files."); ex.printStackTrace(System.err); return null; } return options; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Main.java000066400000000000000000000113161342202223400235410ustar00rootroot00000000000000/* * Copyright 2016, 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; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.google.common.collect.Lists; import org.jf.baksmali.HelpCommand.HlepCommand; import org.jf.util.jcommander.Command; import org.jf.util.jcommander.ExtendedCommands; import org.jf.util.jcommander.ExtendedParameters; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Properties; @ExtendedParameters( includeParametersInUsage = true, commandName = "baksmali", postfixDescription = "See baksmali help for more information about a specific command") public class Main extends Command { public static final String VERSION = loadVersion(); @Parameter(names = {"--help", "-h", "-?"}, help = true, description = "Show usage information") private boolean help; @Parameter(names = {"--version", "-v"}, help = true, description = "Print the version of baksmali and then exit") public boolean version; private JCommander jc; public Main() { super(Lists.newArrayList()); } @Override public void run() { } @Override protected JCommander getJCommander() { return jc; } public static void main(String[] args) { Main main = new Main(); JCommander jc = new JCommander(main); main.jc = jc; jc.setProgramName("baksmali"); List commandHierarchy = main.getCommandHierarchy(); ExtendedCommands.addExtendedCommand(jc, new DisassembleCommand(commandHierarchy)); ExtendedCommands.addExtendedCommand(jc, new DeodexCommand(commandHierarchy)); ExtendedCommands.addExtendedCommand(jc, new DumpCommand(commandHierarchy)); ExtendedCommands.addExtendedCommand(jc, new HelpCommand(commandHierarchy)); ExtendedCommands.addExtendedCommand(jc, new HlepCommand(commandHierarchy)); ExtendedCommands.addExtendedCommand(jc, new ListCommand(commandHierarchy)); jc.parse(args); if (main.version) { version(); } if (jc.getParsedCommand() == null || main.help) { main.usage(); return; } Command command = (Command)jc.getCommands().get(jc.getParsedCommand()).getObjects().get(0); command.run(); } protected static void version() { System.out.println("baksmali " + VERSION + " (http://smali.org)"); System.out.println("Copyright (C) 2010 Ben Gruver (JesusFreke@JesusFreke.com)"); System.out.println("BSD license (http://www.opensource.org/licenses/bsd-license.php)"); System.exit(0); } private static String loadVersion() { InputStream propertiesStream = Baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties"); String version = "[unknown version]"; if (propertiesStream != null) { Properties properties = new Properties(); try { properties.load(propertiesStream); version = properties.getProperty("application.version"); } catch (IOException ex) { // ignore } } return version; } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/000077500000000000000000000000001342202223400237415ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/BooleanRenderer.java000066400000000000000000000034521342202223400276560ustar00rootroot00000000000000/* * [The "BSD licence"] * Copyright (c) 2010 Ben Gruver * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Renderers; import org.jf.util.IndentingWriter; import java.io.IOException; public class BooleanRenderer { public static void writeTo(IndentingWriter writer, boolean val) throws IOException { if (val) { writer.write("true"); } else { writer.write("false"); } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/ByteRenderer.java000066400000000000000000000042361342202223400272030ustar00rootroot00000000000000/* * [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.Renderers; import org.jf.util.IndentingWriter; import java.io.IOException; public class ByteRenderer { public static void writeTo(IndentingWriter writer, byte val) throws IOException { if (val<0) { writer.write("-0x"); writer.printUnsignedLongAsHex(-val); writer.write('t'); } else { writer.write("0x"); writer.printUnsignedLongAsHex(val); writer.write('t'); } } public static void writeUnsignedTo(IndentingWriter writer, byte val) throws IOException { writer.write("0x"); writer.printUnsignedLongAsHex(val & 0xFF); writer.write('t'); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/CharRenderer.java000066400000000000000000000035111342202223400271500ustar00rootroot00000000000000/* * [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.Renderers; import org.jf.util.IndentingWriter; import org.jf.util.StringUtils; import java.io.IOException; public class CharRenderer { public static void writeTo(IndentingWriter writer, char val) throws IOException { writer.write('\''); StringUtils.writeEscapedChar(writer, val); writer.write('\''); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/DoubleRenderer.java000066400000000000000000000033411342202223400275060ustar00rootroot00000000000000/* * [The "BSD licence"] * Copyright (c) 2010 Ben Gruver * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.baksmali.Renderers; import org.jf.util.IndentingWriter; import java.io.IOException; public class DoubleRenderer { public static void writeTo(IndentingWriter writer, double val) throws IOException { writer.write(Double.toString(val)); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/FloatRenderer.java000066400000000000000000000034061342202223400273430ustar00rootroot00000000000000/* * [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.Renderers; import org.jf.util.IndentingWriter; import java.io.IOException; public class FloatRenderer { public static void writeTo(IndentingWriter writer, float val) throws IOException { writer.write(Float.toString(val)); writer.write('f'); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/IntegerRenderer.java000066400000000000000000000041251342202223400276720ustar00rootroot00000000000000/* * [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.Renderers; import org.jf.util.IndentingWriter; import java.io.IOException; public class IntegerRenderer { public static void writeTo(IndentingWriter writer, int val) throws IOException { if (val<0) { writer.write("-0x"); writer.printUnsignedLongAsHex(-((long) val)); } else { writer.write("0x"); writer.printUnsignedLongAsHex(val); } } public static void writeUnsignedTo(IndentingWriter writer, int val) throws IOException { writer.write("0x"); writer.printUnsignedLongAsHex(val & 0xFFFFFFFFL); } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/LongRenderer.java000066400000000000000000000047041342202223400271770ustar00rootroot00000000000000/* * [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.Renderers; import org.jf.util.IndentingWriter; import java.io.IOException; public class LongRenderer { public static void writeTo(IndentingWriter writer, long val) throws IOException { if (val<0) { writer.write("-0x"); writer.printUnsignedLongAsHex(-val); writer.write('L'); } else { writer.write("0x"); writer.printUnsignedLongAsHex(val); writer.write('L'); } } public static void writeSignedIntOrLongTo(IndentingWriter writer, long val) throws IOException { if (val<0) { writer.write("-0x"); writer.printUnsignedLongAsHex(-val); if (val < Integer.MIN_VALUE) { writer.write('L'); } } else { writer.write("0x"); writer.printUnsignedLongAsHex(val); if (val > Integer.MAX_VALUE) { writer.write('L'); } } } } smali-2.2.6/baksmali/src/main/java/org/jf/baksmali/Renderers/ShortRenderer.java000066400000000000000000000037221342202223400273760ustar00rootroot00000000000000/* * [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.Renderers; import org.jf.util.IndentingWriter; import java.io.IOException; public class ShortRenderer { public static void writeTo(IndentingWriter writer, short val) throws IOException { if (val < 0) { writer.write("-0x"); writer.printUnsignedLongAsHex(-val); writer.write('s'); } else { writer.write("0x"); writer.printUnsignedLongAsHex(val); writer.write('s'); } } } smali-2.2.6/baksmali/src/main/resources/000077500000000000000000000000001342202223400201305ustar00rootroot00000000000000smali-2.2.6/baksmali/src/main/resources/baksmali.properties000066400000000000000000000000361342202223400240300ustar00rootroot00000000000000application.version=${version}smali-2.2.6/baksmali/src/test/000077500000000000000000000000001342202223400161515ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/java/000077500000000000000000000000001342202223400170725ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/java/org/000077500000000000000000000000001342202223400176615ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/java/org/jf/000077500000000000000000000000001342202223400202605ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/000077500000000000000000000000001342202223400220435ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java000066400000000000000000000123631342202223400253360ustar00rootroot00000000000000/* * Copyright 2013, 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; import com.google.common.base.Charsets; import com.google.common.io.Resources; import junit.framework.Assert; import org.jf.baksmali.Adaptors.ClassDefinition; import org.jf.dexlib2.DexFileFactory; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.analysis.ClassPath; import org.jf.dexlib2.analysis.ClassProvider; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.DexFile; import org.jf.util.IndentingWriter; import org.junit.Test; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; public class AnalysisTest { @Test public void ConstructorTest() throws IOException, URISyntaxException { runTest("ConstructorTest", true); } @Test public void RegisterEqualityOnMergeTest() throws IOException, URISyntaxException { runTest("RegisterEqualityOnMergeTest", true); } @Test public void UninitRefIdentityTest() throws IOException, URISyntaxException { runTest("UninitRefIdentityTest", true); } @Test public void InstanceOfTest() throws IOException, URISyntaxException { runTest("InstanceOfTest", true, true); } @Test public void MultipleStartInstructionsTest() throws IOException, URISyntaxException { runTest("MultipleStartInstructionsTest", true); } @Test public void DuplicateTest() throws IOException, URISyntaxException { runTest("DuplicateTest", false); } @Test public void LocalTest() throws IOException, URISyntaxException { runTest("LocalTest", false); } public void runTest(String test, boolean registerInfo) throws IOException, URISyntaxException { runTest(test, registerInfo, false); } public void runTest(String test, boolean registerInfo, boolean isArt) throws IOException, URISyntaxException { String dexFilePath = String.format("%s%sclasses.dex", test, File.separatorChar); DexFile dexFile = DexFileFactory.loadDexFile(findResource(dexFilePath), Opcodes.getDefault()); BaksmaliOptions options = new BaksmaliOptions(); if (registerInfo) { options.registerInfo = BaksmaliOptions.ALL | BaksmaliOptions.FULLMERGE; if (isArt) { options.classPath = new ClassPath(new ArrayList(), true, 56); } else { options.classPath = new ClassPath(); } } options.implicitReferences = false; for (ClassDef classDef: dexFile.getClasses()) { StringWriter stringWriter = new StringWriter(); IndentingWriter writer = new IndentingWriter(stringWriter); ClassDefinition classDefinition = new ClassDefinition(options, classDef); classDefinition.writeTo(writer); writer.close(); String className = classDef.getType(); String smaliPath = String.format("%s%s%s.smali", test, File.separatorChar, className.substring(1, className.length() - 1)); String smaliContents = readResource(smaliPath); Assert.assertEquals(BaksmaliTestUtils.normalizeWhitespace(smaliContents), BaksmaliTestUtils.normalizeWhitespace((stringWriter.toString()))); } } @Nonnull private File findResource(String resource) throws URISyntaxException { URL resUrl = Resources.getResource(resource); return new File(resUrl.toURI()); } @Nonnull private String readResource(String resource) throws URISyntaxException, IOException { URL url = Resources.getResource(resource); return Resources.toString(url, Charsets.UTF_8); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/BaksmaliTestUtils.java000066400000000000000000000160041342202223400263130ustar00rootroot00000000000000/* * Copyright 2015, 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; import com.google.common.io.ByteStreams; import junit.framework.Assert; import org.antlr.runtime.RecognitionException; import org.jf.baksmali.Adaptors.ClassDefinition; import org.jf.dexlib2.iface.ClassDef; import org.jf.smali.SmaliTestUtils; import org.jf.util.IndentingWriter; import org.junit.Test; import javax.annotation.Nonnull; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.util.regex.Matcher; import java.util.regex.Pattern; public class BaksmaliTestUtils { private static String newline = System.getProperty("line.separator"); public static void assertSmaliCompiledEquals(String source, String expected, BaksmaliOptions options, boolean stripComments) throws IOException, RecognitionException { ClassDef classDef = SmaliTestUtils.compileSmali(source, options.apiLevel); // Remove unnecessary whitespace and optionally strip all comments from smali file String normalizedActual = getNormalizedSmali(classDef, options, stripComments); String normalizedExpected = normalizeSmali(expected, stripComments); // Assert that normalized strings are now equal Assert.assertEquals(normalizedExpected, normalizedActual); } public static void assertSmaliCompiledEquals(String source, String expected, BaksmaliOptions options) throws IOException, RecognitionException { assertSmaliCompiledEquals(source, expected, options, false); } public static void assertSmaliCompiledEquals(String source, String expected) throws IOException, RecognitionException { BaksmaliOptions options = new BaksmaliOptions(); assertSmaliCompiledEquals(source, expected, options); } @Nonnull public static String normalizeSmali(@Nonnull String smaliText, boolean stripComments) { if (stripComments) { smaliText = stripComments(smaliText); } return normalizeWhitespace(smaliText); } @Nonnull public static String getNormalizedSmali(@Nonnull ClassDef classDef, @Nonnull BaksmaliOptions options, boolean stripComments) throws IOException { StringWriter stringWriter = new StringWriter(); IndentingWriter writer = new IndentingWriter(stringWriter); ClassDefinition classDefinition = new ClassDefinition(options, classDef); classDefinition.writeTo(writer); writer.close(); return normalizeSmali(stringWriter.toString(), stripComments); } @Nonnull public static byte[] readResourceBytesFully(@Nonnull String fileName) throws IOException { InputStream smaliStream = RoundtripTest.class.getClassLoader(). getResourceAsStream(fileName); if (smaliStream == null) { org.junit.Assert.fail("Could not load " + fileName); } return ByteStreams.toByteArray(smaliStream); } @Nonnull public static String readResourceFully(@Nonnull String fileName) throws IOException { return readResourceFully(fileName, "UTF-8"); } @Nonnull public static String readResourceFully(@Nonnull String fileName, @Nonnull String encoding) throws IOException { return new String(readResourceBytesFully(fileName), encoding); } @Nonnull public static String normalizeNewlines(@Nonnull String source) { return normalizeNewlines(source, newline); } @Nonnull public static String normalizeNewlines(@Nonnull String source, String newlineValue) { return source.replace("\r", "").replace("\n", newlineValue); } @Nonnull public static String normalizeWhitespace(@Nonnull String source) { // Go to native system new lines so that ^/$ work correctly source = normalizeNewlines(source); // Remove all suffix/prefix whitespace Pattern pattern = Pattern.compile("((^[ \t]+)|([ \t]+$))", Pattern.MULTILINE); Matcher matcher = pattern.matcher(source); source = matcher.replaceAll(""); // Remove all empty lines Pattern pattern2 = Pattern.compile("^\r?\n?", Pattern.MULTILINE); Matcher matcher2 = pattern2.matcher(source); source = matcher2.replaceAll(""); // Remove a trailing new line, if present Pattern pattern3 = Pattern.compile("\r?\n?$"); Matcher matcher3 = pattern3.matcher(source); source = matcher3.replaceAll(""); // Go back to unix-style \n newlines source = normalizeNewlines(source, "\n"); return source; } @Nonnull public static String stripComments(@Nonnull String source) { Pattern pattern = Pattern.compile("#(.*)"); Matcher matcher = pattern.matcher(source); return matcher.replaceAll(""); } @Test public void testStripComments() { Assert.assertEquals("", stripComments("#world")); Assert.assertEquals("hello", stripComments("hello#world")); Assert.assertEquals("multi\nline", stripComments("multi#hello world\nline#world")); } @Test public void testNormalizeWhitespace() { Assert.assertEquals("", normalizeWhitespace(" ")); Assert.assertEquals("hello", normalizeWhitespace("hello ")); Assert.assertEquals("hello", normalizeWhitespace(" hello")); Assert.assertEquals("hello", normalizeWhitespace(" hello ")); Assert.assertEquals("hello\nworld", normalizeWhitespace("hello \n \n world")); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/DexTest.java000066400000000000000000000056661342202223400243030ustar00rootroot00000000000000/* * Copyright 2015, 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; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.junit.Assert; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; /** * A base test class for performing a test using a dex file as input */ /** * A base test class for performing a disassembly on a dex file and verifying the results * * The test accepts a single-class dex file as input. By default, the input dex file should be a resource at * [testDir]/[testName]Input.dex */ public abstract class DexTest { protected final String testDir; protected DexTest(@Nonnull String testDir) { this.testDir = testDir; } protected DexTest() { this.testDir = this.getClass().getSimpleName(); } @Nonnull protected String getInputFilename(@Nonnull String testName) { return String.format("%s%s%sInput.dex", testDir, File.separatorChar, testName); } @Nonnull protected DexBackedDexFile getInputDexFile(@Nonnull String testName, @Nonnull BaksmaliOptions options) { try { // Load file from resources as a stream byte[] inputBytes = BaksmaliTestUtils.readResourceBytesFully(getInputFilename(testName)); return new DexBackedDexFile(Opcodes.forApi(options.apiLevel), inputBytes); } catch (IOException ex) { Assert.fail(); } return null; } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java000066400000000000000000000065321342202223400260330ustar00rootroot00000000000000/* * Copyright 2015, 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; import com.google.common.collect.Iterables; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.iface.ClassDef; import org.junit.Assert; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; /** * A base test class for performing a disassembly on a dex file and verifying the results * * The test accepts a single-class dex file as input, disassembles it, and verifies that * the result equals a known-good output smali file. * * By default, the input and output files should be resources at [testDir]/[testName]Input.dex * and [testDir]/[testName]Output.smali respectively */ public class DisassemblyTest extends DexTest { @Nonnull protected String getOutputFilename(@Nonnull String testName) { return String.format("%s%s%sOutput.smali", testDir, File.separatorChar, testName); } protected void runTest(@Nonnull String testName) { runTest(testName, new BaksmaliOptions()); } protected void runTest(@Nonnull String testName, @Nonnull BaksmaliOptions options) { try { DexBackedDexFile inputDex = getInputDexFile(testName, options); Assert.assertEquals(1, inputDex.getClassCount()); ClassDef inputClass = Iterables.getFirst(inputDex.getClasses(), null); Assert.assertNotNull(inputClass); String input = BaksmaliTestUtils.getNormalizedSmali(inputClass, options, true); String output = BaksmaliTestUtils.readResourceFully(getOutputFilename(testName)); output = BaksmaliTestUtils.normalizeSmali(output, true); // Run smali, baksmali, and then compare strings are equal (minus comments/whitespace) Assert.assertEquals(output, input); } catch (IOException ex) { Assert.fail(); } } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/FieldGapOrderTest.java000066400000000000000000000065301342202223400262210ustar00rootroot00000000000000/* * Copyright 2015, 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; import com.google.common.collect.Lists; import org.jf.dexlib2.analysis.ClassPath; import org.jf.dexlib2.analysis.ClassProto; import org.jf.dexlib2.analysis.DexClassProvider; import org.jf.dexlib2.iface.DexFile; import org.junit.Assert; import org.junit.Test; public class FieldGapOrderTest extends DexTest { @Test public void testOldOrder() { DexFile dexFile = getInputDexFile("FieldGapOrder", new BaksmaliOptions()); Assert.assertEquals(3, dexFile.getClasses().size()); ClassPath classPath = new ClassPath(Lists.newArrayList(new DexClassProvider(dexFile)), false, 66); ClassProto classProto = (ClassProto)classPath.getClass("LGapOrder;"); Assert.assertEquals("r1", classProto.getFieldByOffset(12).getName()); Assert.assertEquals("r2", classProto.getFieldByOffset(16).getName()); Assert.assertEquals("d", classProto.getFieldByOffset(24).getName()); Assert.assertEquals("s", classProto.getFieldByOffset(36).getName()); Assert.assertEquals("i", classProto.getFieldByOffset(32).getName()); } @Test public void testNewOrder() { DexFile dexFile = getInputDexFile("FieldGapOrder", new BaksmaliOptions()); Assert.assertEquals(3, dexFile.getClasses().size()); ClassPath classPath = new ClassPath(Lists.newArrayList(new DexClassProvider(dexFile)), false, 67); ClassProto classProto = (ClassProto)classPath.getClass("LGapOrder;"); Assert.assertEquals("s", classProto.getFieldByOffset(10).getName()); Assert.assertEquals("r1", classProto.getFieldByOffset(12).getName()); Assert.assertEquals("r2", classProto.getFieldByOffset(16).getName()); Assert.assertEquals("i", classProto.getFieldByOffset(20).getName()); Assert.assertEquals("d", classProto.getFieldByOffset(24).getName()); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/IdenticalRoundtripTest.java000066400000000000000000000045211342202223400273530ustar00rootroot00000000000000/* * Copyright 2015, 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; import javax.annotation.Nonnull; import java.io.File; /** * A base test class for performing a roundtrip assembly/disassembly where the input and output * should be identical. * * By default, the input/output file should be a resource at [testDir]/[testName].smali */ public abstract class IdenticalRoundtripTest extends RoundtripTest { public IdenticalRoundtripTest(@Nonnull String testDir) { super(testDir); } public IdenticalRoundtripTest() { } @Nonnull @Override protected String getInputFilename(@Nonnull String testName) { return String.format("%s%s%s.smali", testDir, File.separatorChar, testName); } @Nonnull @Override protected String getOutputFilename(@Nonnull String testName) { return getInputFilename(testName); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/ImplicitReferenceTest.java000066400000000000000000000267711342202223400271540ustar00rootroot00000000000000/* * Copyright 2014, 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; import org.antlr.runtime.RecognitionException; import org.junit.Test; import java.io.IOException; public class ImplicitReferenceTest { @Test public void testImplicitMethodReferences() throws IOException, RecognitionException { String source = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + ".method public static main([Ljava/lang/String;)V\n" + " .registers 1\n" + " invoke-static {p0}, LHelloWorld;->toString()V\n" + " invoke-static {p0}, LHelloWorld;->V()V\n" + " invoke-static {p0}, LHelloWorld;->I()V\n" + " return-void\n" + ".end method"; String expected = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + "# direct methods\n" + ".method public static main([Ljava/lang/String;)V\n" + ".registers 1\n" + "invoke-static {p0}, toString()V\n" + "invoke-static {p0}, V()V\n" + "invoke-static {p0}, I()V\n" + "return-void\n" + ".end method\n"; BaksmaliOptions options = new BaksmaliOptions(); options.implicitReferences = true; BaksmaliTestUtils.assertSmaliCompiledEquals(source, expected, options); } @Test public void testExplicitMethodReferences() throws IOException, RecognitionException { String source = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + ".method public static main([Ljava/lang/String;)V\n" + " .registers 1\n" + " invoke-static {p0}, LHelloWorld;->toString()V\n" + " invoke-static {p0}, LHelloWorld;->V()V\n" + " invoke-static {p0}, LHelloWorld;->I()V\n" + " return-void\n" + ".end method"; String expected = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + "# direct methods\n" + ".method public static main([Ljava/lang/String;)V\n" + " .registers 1\n" + " invoke-static {p0}, LHelloWorld;->toString()V\n" + " invoke-static {p0}, LHelloWorld;->V()V\n" + " invoke-static {p0}, LHelloWorld;->I()V\n" + " return-void\n" + ".end method\n"; BaksmaliOptions options = new BaksmaliOptions(); options.implicitReferences = false; BaksmaliTestUtils.assertSmaliCompiledEquals(source, expected, options); } @Test public void testImplicitMethodLiterals() throws IOException, RecognitionException { String source = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + ".field public static field1:Ljava/lang/reflect/Method; = LHelloWorld;->toString()V\n" + ".field public static field2:Ljava/lang/reflect/Method; = LHelloWorld;->V()V\n" + ".field public static field3:Ljava/lang/reflect/Method; = LHelloWorld;->I()V\n" + ".field public static field4:Ljava/lang/Class; = I"; String expected = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + "# static fields\n" + ".field public static field1:Ljava/lang/reflect/Method; = toString()V\n" + ".field public static field2:Ljava/lang/reflect/Method; = V()V\n" + ".field public static field3:Ljava/lang/reflect/Method; = I()V\n" + ".field public static field4:Ljava/lang/Class; = I\n"; BaksmaliOptions options = new BaksmaliOptions(); options.implicitReferences = true; BaksmaliTestUtils.assertSmaliCompiledEquals(source, expected, options); } @Test public void testExplicitMethodLiterals() throws IOException, RecognitionException { String source = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + ".field public static field1:Ljava/lang/reflect/Method; = LHelloWorld;->toString()V\n" + ".field public static field2:Ljava/lang/reflect/Method; = LHelloWorld;->V()V\n" + ".field public static field3:Ljava/lang/reflect/Method; = LHelloWorld;->I()V\n" + ".field public static field4:Ljava/lang/Class; = I"; String expected = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + "# static fields\n" + ".field public static field1:Ljava/lang/reflect/Method; = LHelloWorld;->toString()V\n" + ".field public static field2:Ljava/lang/reflect/Method; = LHelloWorld;->V()V\n" + ".field public static field3:Ljava/lang/reflect/Method; = LHelloWorld;->I()V\n" + ".field public static field4:Ljava/lang/Class; = I\n"; BaksmaliOptions options = new BaksmaliOptions(); options.implicitReferences = false; BaksmaliTestUtils.assertSmaliCompiledEquals(source, expected, options); } @Test public void testImplicitFieldReferences() throws IOException, RecognitionException { String source = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + ".method public static main([Ljava/lang/String;)V\n" + " .registers 1\n" + " sget v0, LHelloWorld;->someField:I\n" + " sget v0, LHelloWorld;->I:I\n" + " sget v0, LHelloWorld;->V:I\n" + " return-void\n" + ".end method"; String expected = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + "# direct methods\n" + ".method public static main([Ljava/lang/String;)V\n" + " .registers 1\n" + " sget p0, someField:I\n" + " sget p0, I:I\n" + " sget p0, V:I\n" + " return-void\n" + ".end method\n"; BaksmaliOptions options = new BaksmaliOptions(); options.implicitReferences = true; BaksmaliTestUtils.assertSmaliCompiledEquals(source, expected, options); } @Test public void testExplicitFieldReferences() throws IOException, RecognitionException { String source = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + ".method public static main([Ljava/lang/String;)V\n" + " .registers 1\n" + " sget v0, LHelloWorld;->someField:I\n" + " sget v0, LHelloWorld;->I:I\n" + " sget v0, LHelloWorld;->V:I\n" + " return-void\n" + ".end method"; String expected = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + "# direct methods\n" + ".method public static main([Ljava/lang/String;)V\n" + " .registers 1\n" + " sget p0, LHelloWorld;->someField:I\n" + " sget p0, LHelloWorld;->I:I\n" + " sget p0, LHelloWorld;->V:I\n" + " return-void\n" + ".end method\n"; BaksmaliOptions options = new BaksmaliOptions(); options.implicitReferences = false; BaksmaliTestUtils.assertSmaliCompiledEquals(source, expected, options); } @Test public void testImplicitFieldLiterals() throws IOException, RecognitionException { String source = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + ".field public static field1:Ljava/lang/reflect/Field; = LHelloWorld;->someField:I\n" + ".field public static field2:Ljava/lang/reflect/Field; = LHelloWorld;->V:I\n" + ".field public static field3:Ljava/lang/reflect/Field; = LHelloWorld;->I:I"; String expected = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + "# static fields\n" + ".field public static field1:Ljava/lang/reflect/Field; = someField:I\n" + ".field public static field2:Ljava/lang/reflect/Field; = V:I\n" + ".field public static field3:Ljava/lang/reflect/Field; = I:I\n"; BaksmaliOptions options = new BaksmaliOptions(); options.implicitReferences = true; BaksmaliTestUtils.assertSmaliCompiledEquals(source, expected, options); } @Test public void testExplicitFieldLiterals() throws IOException, RecognitionException { String source = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + ".field public static field1:Ljava/lang/reflect/Field; = LHelloWorld;->someField:I\n" + ".field public static field2:Ljava/lang/reflect/Field; = LHelloWorld;->V:I\n" + ".field public static field3:Ljava/lang/reflect/Field; = LHelloWorld;->I:I"; String expected = "" + ".class public LHelloWorld;\n" + ".super Ljava/lang/Object;\n" + "# static fields\n" + ".field public static field1:Ljava/lang/reflect/Field; = LHelloWorld;->someField:I\n" + ".field public static field2:Ljava/lang/reflect/Field; = LHelloWorld;->V:I\n" + ".field public static field3:Ljava/lang/reflect/Field; = LHelloWorld;->I:I\n"; BaksmaliOptions options = new BaksmaliOptions(); options.implicitReferences = false; BaksmaliTestUtils.assertSmaliCompiledEquals(source, expected, options); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/InstructionRoundtripTest.java000066400000000000000000000040261342202223400300000ustar00rootroot00000000000000/* * Copyright 2018, 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; import org.junit.Test; public class InstructionRoundtripTest extends IdenticalRoundtripTest { @Test public void testConstMethodHandle() { BaksmaliOptions options = new BaksmaliOptions(); options.apiLevel = 28; runTest("ConstMethodHandle", options); } @Test public void testConstMethodType() { BaksmaliOptions options = new BaksmaliOptions(); options.apiLevel = 28; runTest("ConstMethodType", options); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/InterfaceOrderTest.java000066400000000000000000000034021342202223400264410ustar00rootroot00000000000000/* * Copyright 2015, 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; import org.junit.Test; public class InterfaceOrderTest extends IdenticalRoundtripTest { @Test public void testInterfaceOrder() { runTest("InterfaceOrder", new BaksmaliOptions()); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/InvokeCustomTest.java000066400000000000000000000035061342202223400262000ustar00rootroot00000000000000/* * Copyright 2018, 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; import org.junit.Test; public class InvokeCustomTest extends IdenticalRoundtripTest { @Test public void testInvokeCustom() { BaksmaliOptions options = new BaksmaliOptions(); options.apiLevel = 26; runTest("InvokeCustom", options); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/LargeLocalTest.java000066400000000000000000000040121342202223400255500ustar00rootroot00000000000000/* * Copyright 2016, 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; import org.junit.Test; /** * Test for a bug related to debug items that refer to a register that's outside the expected range for a method */ public class LargeLocalTest extends IdenticalRoundtripTest { @Test public void testLargeEndLocal() { runTest("LargeEndLocal"); } @Test public void testLargeRestartLocal() { runTest("LargeRestartLocal"); } @Test public void testLargeStartLocal() { runTest("LargeStartLocal"); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/ManyRegistersTest.java000066400000000000000000000033511342202223400263440ustar00rootroot00000000000000/* * Copyright 2015, 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; import org.junit.Test; public class ManyRegistersTest extends IdenticalRoundtripTest { @Test public void testManyRegisters() { runTest("ManyRegisters"); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/MultiSwitchTest.java000066400000000000000000000033341342202223400260250ustar00rootroot00000000000000/* * Copyright 2015, 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; import org.junit.Test; public class MultiSwitchTest extends DisassemblyTest { @Test public void testMultiSwitch() { runTest("MultiSwitch"); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/ParamListMethodNameTest.java000066400000000000000000000033731342202223400274120ustar00rootroot00000000000000/* * Copyright 2015, 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; import org.junit.Test; public class ParamListMethodNameTest extends IdenticalRoundtripTest { @Test public void testParamListMethodName() { runTest("ParamListMethodName"); } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/RoundtripTest.java000066400000000000000000000072711342202223400255430ustar00rootroot00000000000000/* * Copyright 2015, 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; import org.antlr.runtime.RecognitionException; import org.junit.Assert; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; /** * A base test class for performing a roundtrip assembly/disassembly * * The test accepts a smali file as input, performs a smali -> dex -> smali roundtrip, and * verifies that the result equals a known-good output smali file. * * By default, the input and output files should be resources at [testDir]/[testName]Input.smali * and [testDir]/[testName]Output.smali respectively */ public abstract class RoundtripTest { protected final String testDir; protected RoundtripTest(@Nonnull String testDir) { this.testDir = testDir; } protected RoundtripTest() { this.testDir = this.getClass().getSimpleName(); } @Nonnull protected String getInputFilename(@Nonnull String testName) { return String.format("%s%s%sInput.smali", testDir, File.separatorChar, testName); } @Nonnull protected String getOutputFilename(@Nonnull String testName) { return String.format("%s%s%sOutput.smali", testDir, File.separatorChar, testName); } protected void runTest(@Nonnull String testName) { runTest(testName, new BaksmaliOptions()); } protected void runTest(@Nonnull String testName, @Nonnull BaksmaliOptions options) { try { // Load file from resources as a stream String inputFilename = getInputFilename(testName); String input = BaksmaliTestUtils.readResourceFully(getInputFilename(testName)); String output; if (getOutputFilename(testName).equals(inputFilename)) { output = input; } else { output = BaksmaliTestUtils.readResourceFully(getOutputFilename(testName)); } // Run smali, baksmali, and then compare strings are equal (minus comments/whitespace) BaksmaliTestUtils.assertSmaliCompiledEquals(input, output, options, true); } catch (IOException ex) { Assert.fail(); } catch (RecognitionException ex) { Assert.fail(); } } } smali-2.2.6/baksmali/src/test/java/org/jf/baksmali/SwitchTest.java000066400000000000000000000033501342202223400250100ustar00rootroot00000000000000/* * Copyright 2015, 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; import org.junit.Test; public class SwitchTest extends RoundtripTest { @Test public void testUnorderedSparseSwitch() { runTest("UnorderedSparseSwitch"); } } smali-2.2.6/baksmali/src/test/resources/000077500000000000000000000000001342202223400201635ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/ConstructorTest/000077500000000000000000000000001342202223400233505ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/ConstructorTest/ConstructorTest.smali000066400000000000000000000010041342202223400275570ustar00rootroot00000000000000.class public LConstructorTest; .super Ljava/lang/Object; # direct methods .method public constructor ()V .registers 4 #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest;); invoke-direct {p0}, Ljava/lang/Object;->()V #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest;); #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest;); return-void #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest;); .end method smali-2.2.6/baksmali/src/test/resources/ConstructorTest/ConstructorTest2.smali000066400000000000000000000015521342202223400276510ustar00rootroot00000000000000.class public LConstructorTest2; .super Ljava/lang/Object; # direct methods .method public constructor ()V .registers 4 #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;); if-eqz p0, :cond_3 #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;); #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;); nop #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;); :cond_3 #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LConstructorTest2;); invoke-direct {p0}, Ljava/lang/Object;->()V #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest2;); #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest2;); return-void #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LConstructorTest2;); .end method smali-2.2.6/baksmali/src/test/resources/ConstructorTest/classes.dex000066400000000000000000000010101342202223400254770ustar00rootroot00000000000000dex 035E=žq;º-•‡kPˆî{,‹öÙgÇVØÞpxV4Œp„” ¸ø[0cDXÿÿÿÿvÿÿÿÿ€8ppLConstructorTest2;Ljava/lang/Object;VLConstructorTest;€ø€˜ p„” ¸ ø 0 vŒsmali-2.2.6/baksmali/src/test/resources/DuplicateTest/000077500000000000000000000000001342202223400227355ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/DuplicateTest/DuplicateDirectMethods.smali000066400000000000000000000006221342202223400303550ustar00rootroot00000000000000.class public LDuplicateDirectMethods; .super Ljava/lang/Object; # direct methods .method private alah()V .registers 1 return-void .end method .method private blah()V .registers 1 return-void .end method # duplicate method ignored # .method private blah()V # .registers 1 # return-void # .end method .method private clah()V .registers 1 return-void .end method smali-2.2.6/baksmali/src/test/resources/DuplicateTest/DuplicateDirectVirtualMethods.smali000066400000000000000000000013441342202223400317260ustar00rootroot00000000000000.class public LDuplicateDirectVirtualMethods; .super Ljava/lang/Object; # direct methods .method private blah()V .registers 1 return-void .end method # duplicate method ignored # .method private blah()V # .registers 1 # return-void # .end method # virtual methods .method public alah()V .registers 1 return-void .end method # There is both a direct and virtual method with this signature. # You will need to rename one of these methods, including all references. .method public blah()V .registers 1 return-void .end method # duplicate method ignored # .method public blah()V # .registers 1 # return-void # .end method .method public clah()V .registers 1 return-void .end method smali-2.2.6/baksmali/src/test/resources/DuplicateTest/DuplicateInstanceFields.smali000066400000000000000000000003111342202223400305050ustar00rootroot00000000000000.class public LDuplicateInstanceFields; .super Ljava/lang/Object; # instance fields .field public alah:I .field public blah:I # duplicate field ignored # .field public blah:I .field public clah:I smali-2.2.6/baksmali/src/test/resources/DuplicateTest/DuplicateStaticFields.smali000066400000000000000000000003411342202223400301730ustar00rootroot00000000000000.class public LDuplicateStaticFields; .super Ljava/lang/Object; # static fields .field public static alah:I .field public static blah:I # duplicate field ignored # .field public static blah:I .field public static clah:I smali-2.2.6/baksmali/src/test/resources/DuplicateTest/DuplicateStaticInstanceFields.smali000066400000000000000000000007001342202223400316570ustar00rootroot00000000000000.class public LDuplicateStaticInstanceFields; .super Ljava/lang/Object; # static fields .field public static blah:I # duplicate field ignored # .field public static blah:I # instance fields .field public alah:I # There is both a static and instance field with this signature. # You will need to rename one of these fields, including all references. .field public blah:I # duplicate field ignored # .field public blah:I .field public clah:I smali-2.2.6/baksmali/src/test/resources/DuplicateTest/DuplicateVirtualMethods.smali000066400000000000000000000006201342202223400305670ustar00rootroot00000000000000.class public LDuplicateVirtualMethods; .super Ljava/lang/Object; # virtual methods .method public alah()V .registers 1 return-void .end method .method public blah()V .registers 1 return-void .end method # duplicate method ignored # .method public blah()V # .registers 1 # return-void # .end method .method public clah()V .registers 1 return-void .end method smali-2.2.6/baksmali/src/test/resources/DuplicateTest/classes.dex000066400000000000000000000024041342202223400250740ustar00rootroot00000000000000dex 035 ¦–œ'ÓºáÅ÷0Ûhðj´ëþýpxV4| p  Ä Ð `ä µ6yš¸ÑòPdgms                  ÿÿÿÿ ÿÿÿÿ!ÿÿÿÿ=ÿÿÿÿIÿÿÿÿUÿÿÿÿeLDuplicateDirectMethods;Ljava/lang/Object;ValahblahclahLDuplicateDirectVirtualMethods;LDuplicateInstanceFields;ILDuplicateStaticFields;LDuplicateStaticInstanceFields;LDuplicateVirtualMethods; ´ÈÜ„˜ð¬ÀÔ    èü¤  p  Ä Ð `   6  |smali-2.2.6/baksmali/src/test/resources/DuplicateTest/src/000077500000000000000000000000001342202223400235245ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/DuplicateTest/src/DuplicateDirectMethods.smali000066400000000000000000000005301342202223400311420ustar00rootroot00000000000000.class public LDuplicateDirectMethods; .super Ljava/lang/Object; .method private alah()V .registers 1 return-void .end method .method private blah()V .registers 1 return-void .end method .method private blah()V .registers 1 return-void .end method .method private clah()V .registers 1 return-void .end methodsmali-2.2.6/baksmali/src/test/resources/DuplicateTest/src/DuplicateDirectVirtualMethods.smali000066400000000000000000000007471342202223400325230ustar00rootroot00000000000000.class public LDuplicateDirectVirtualMethods; .super Ljava/lang/Object; .method public alah()V .registers 1 return-void .end method .method private blah()V .registers 1 return-void .end method .method private blah()V .registers 1 return-void .end method .method public blah()V .registers 1 return-void .end method .method public blah()V .registers 1 return-void .end method .method public clah()V .registers 1 return-void .end methodsmali-2.2.6/baksmali/src/test/resources/DuplicateTest/src/DuplicateInstanceFields.smali000066400000000000000000000002301342202223400312740ustar00rootroot00000000000000.class public LDuplicateInstanceFields; .super Ljava/lang/Object; .field public alah:I .field public blah:I .field public blah:I .field public clah:Ismali-2.2.6/baksmali/src/test/resources/DuplicateTest/src/DuplicateStaticFields.smali000066400000000000000000000002621342202223400307640ustar00rootroot00000000000000.class public LDuplicateStaticFields; .super Ljava/lang/Object; .field public static alah:I .field public static blah:I .field public static blah:I .field public static clah:Ismali-2.2.6/baksmali/src/test/resources/DuplicateTest/src/DuplicateStaticInstanceFields.smali000066400000000000000000000003261342202223400324520ustar00rootroot00000000000000.class public LDuplicateStaticInstanceFields; .super Ljava/lang/Object; .field public alah:I .field public blah:I .field public blah:I .field static public blah:I .field static public blah:I .field public clah:Ismali-2.2.6/baksmali/src/test/resources/DuplicateTest/src/DuplicateVirtualMethods.smali000066400000000000000000000005251342202223400313620ustar00rootroot00000000000000.class public LDuplicateVirtualMethods; .super Ljava/lang/Object; .method public alah()V .registers 1 return-void .end method .method public blah()V .registers 1 return-void .end method .method public blah()V .registers 1 return-void .end method .method public clah()V .registers 1 return-void .end methodsmali-2.2.6/baksmali/src/test/resources/DuplicateTest/src/README000066400000000000000000000002031342202223400243770ustar00rootroot00000000000000The test dex file was produced from these smali files, using an old version of smali that doesn't check for field/method duplicatessmali-2.2.6/baksmali/src/test/resources/FieldGapOrderTest/000077500000000000000000000000001342202223400234725ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/FieldGapOrderTest/FieldGapOrderInput.dex000066400000000000000000000014741342202223400276710ustar00rootroot00000000000000dex 035XžÂƒÎ‡XQšûRH;jmƒ’¼;û<pxV4¨pÀàì,D˜¤¤¬¯²ÁÔ×ãó #*37;   ÿÿÿÿ |…‘BD GapOrder.javaGapOrderBase.javaI LGapOrder;LGapOrderBase;Ljava/lang/Object; Object.javaSVbdiklassmonitorr1r2s@pEp‚€€ä€€Ì pÀàì,D ¤ @ L |¨smali-2.2.6/baksmali/src/test/resources/InstanceOfTest/000077500000000000000000000000001342202223400230545ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/InstanceOfTest/InstanceOfTest.smali000066400000000000000000000123541342202223400270010ustar00rootroot00000000000000.class public LInstanceOfTest; .super Ljava/lang/Object; # virtual methods .method public testInstanceOfEqz(Ljava/lang/Object;)I .registers 3 #v0=(Uninit);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); instance-of v0, p1, Ljava/lang/String; #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); if-eqz v0, :cond_9 #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Unknown); #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); invoke-virtual {p1}, Ljava/lang/String;->length()I #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); move-result v0 #v0=(Integer);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); #v0=(Integer);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); return v0 #v0=(Integer);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); :cond_9 #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); const v0, -0x1 #v0=(Byte);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); #v0=(Byte);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); return v0 #v0=(Byte);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); .end method .method public testInstanceOfNez(Ljava/lang/Object;)I .registers 3 #v0=(Uninit);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); instance-of v0, p1, Ljava/lang/String; #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); if-nez v0, :cond_8 #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Unknown); #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); const v0, -0x1 #v0=(Byte);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); #v0=(Byte);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); return v0 #v0=(Byte);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); :cond_8 #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); invoke-virtual {p1}, Ljava/lang/String;->length()I #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); #v0=(Boolean);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); move-result v0 #v0=(Integer);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); #v0=(Integer);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); return v0 #v0=(Integer);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/String;); .end method .method public testRegisterAlias(Ljava/lang/Object;)I .registers 4 #v0=(Uninit);v1=(Uninit);p0=(Reference,LInstanceOfTest;);p1=(Reference,Ljava/lang/Object;); move-object p0, p1 #v0=(Uninit);v1=(Uninit);p0=(Reference,Ljava/lang/Object;);p1=(Reference,Ljava/lang/Object;); #v0=(Uninit);v1=(Uninit);p0=(Reference,Ljava/lang/Object;);p1=(Reference,Ljava/lang/Object;); instance-of v0, p0, Ljava/lang/String; #v0=(Boolean);v1=(Uninit);p0=(Reference,Ljava/lang/Object;);p1=(Reference,Ljava/lang/Object;); #v0=(Boolean);v1=(Uninit);p0=(Reference,Ljava/lang/Object;);p1=(Reference,Ljava/lang/Object;); if-eqz v0, :cond_f #v0=(Boolean);v1=(Uninit);p0=(Unknown);p1=(Unknown); :cond_5 #v0=(Integer):merge{0x3:(Boolean),0xc:(Integer)} #v1=(Conflicted):merge{0x3:(Uninit),0xc:(Null)} #p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); invoke-virtual {p1}, Ljava/lang/String;->length()I #v0=(Integer);v1=(Conflicted);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); #v0=(Integer);v1=(Conflicted);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); move-result v0 #v0=(Integer);v1=(Conflicted);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); #v0=(Integer);v1=(Conflicted);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); const v1, 0x0 #v0=(Integer);v1=(Null);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); #v0=(Integer);v1=(Null);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); if-le v0, v1, :cond_5 #v0=(Integer);v1=(Null);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); #v0=(Integer);v1=(Null);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); return v0 #v0=(Integer);v1=(Null);p0=(Reference,Ljava/lang/String;);p1=(Reference,Ljava/lang/String;); :cond_f #v0=(Boolean);v1=(Uninit);p0=(Reference,Ljava/lang/Object;);p1=(Reference,Ljava/lang/Object;); const v0, -0x1 #v0=(Byte);v1=(Uninit);p0=(Reference,Ljava/lang/Object;);p1=(Reference,Ljava/lang/Object;); #v0=(Byte);v1=(Uninit);p0=(Reference,Ljava/lang/Object;);p1=(Reference,Ljava/lang/Object;); return v0 #v0=(Byte);v1=(Uninit);p0=(Reference,Ljava/lang/Object;);p1=(Reference,Ljava/lang/Object;); .end method smali-2.2.6/baksmali/src/test/resources/InstanceOfTest/classes.dex000066400000000000000000000013041342202223400252110ustar00rootroot00000000000000dex 035Æcl¤ÙLÞ­›²‹¢hþnŸðØåáð2ÄpxV40 p”¤¼ÜÈüüÿ)=EXk€ÿÿÿÿIILLInstanceOfTest;Ljava/lang/Object;Ljava/lang/String;lengthtestInstanceOfEqztestInstanceOfNeztestRegisterAlias 8n ÿÿÿÿ 9ÿÿÿÿn 2 8 n 7ùÿÿÿÿÿ¼è  p”¤¼Ü ü€ˆ  0smali-2.2.6/baksmali/src/test/resources/InstructionRoundtripTest/000077500000000000000000000000001342202223400252535ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/InstructionRoundtripTest/ConstMethodHandle.smali000066400000000000000000000015341342202223400316500ustar00rootroot00000000000000.class LConstMethodHandle; .super Ljava/lang/Object; # static fields .field public static staticField:Ljava/lang/Object; # instance fields .field public instanceField:Ljava/lang/Object; # direct methods .method public static constMethodHandle()V .registers 15 const-method-handle v0, invoke-static@Ljava/lang/Integer;->toString(I)Ljava/lang/String; const-method-handle v0, invoke-instance@Ljava/lang/Integer;->toString()Ljava/lang/String; const-method-handle v0, static-put@LConstMethodHandle;->instanceField:Ljava/lang/Object; const-method-handle v0, static-put@LConstMethodHandle;->instanceField:Ljava/lang/Object; const-method-handle v0, static-put@LConstMethodHandle;->staticField:Ljava/lang/Object; const-method-handle v0, static-put@LConstMethodHandle;->staticField:Ljava/lang/Object; return-void .end method smali-2.2.6/baksmali/src/test/resources/InstructionRoundtripTest/ConstMethodType.smali000066400000000000000000000006531342202223400313770ustar00rootroot00000000000000.class LConstMethodType; .super Ljava/lang/Object; # static fields .field public static staticField:Ljava/lang/Object; # instance fields .field public instanceField:Ljava/lang/Object; # direct methods .method public static constMethodHandle()V .registers 15 const-method-type v0, ()V const-method-type v0, (II)I const-method-type v0, (Ljava/lang/String;)Ljava/lang/String; return-void .end method smali-2.2.6/baksmali/src/test/resources/InterfaceOrderTest/000077500000000000000000000000001342202223400237175ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/InterfaceOrderTest/InterfaceOrder.smali000066400000000000000000000014071342202223400276440ustar00rootroot00000000000000.class public LInterfaceOrder; .super Ljava/lang/Object; # Note how these two interfaces are not in alphabetical order .implements Ljava/io/Serializable; .implements Ljava/util/EventListener; .implements Ljava/lang/Runnable; .implements Ljava/io/Flushable; .implements Ljava/lang/Clonable; .implements Ljava/util/Observer; .implements Ljava/io/Closeable; # direct methods .method public constructor ()V .registers 1 return-void .end method .method public close()V .registers 1 return-void .end method .method public flush()V .registers 1 return-void .end method .method public run()V .registers 1 return-void .end method .method public update(Ljava/util/Observable;Ljava/lang/Object;)V .registers 3 return-void .end method smali-2.2.6/baksmali/src/test/resources/InvokeCustomTest/000077500000000000000000000000001342202223400234515ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/InvokeCustomTest/InvokeCustom.smali000066400000000000000000000026221342202223400271300ustar00rootroot00000000000000.class LInvokeCustom; .super Ljava/lang/Object; # direct methods .method public static invokeCustom([Ljava/lang/String;)V .registers 15 new-instance v0, LCustom; invoke-direct {v0}, LCustom;->()V const-string v1, "Arg to doSomething" invoke-custom {v0, v1}, call_site_1("doSomething", (LCustom;Ljava/lang/String;)Ljava/lang/String;, "just testing")@LBootstrapLinker;->normalLink(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite; move-result-object v2 sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v4, "got back - " invoke-virtual {v3, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V invoke-custom {v0, v1}, call_site_0("doSomething", (LCustom;Ljava/lang/String;)Ljava/lang/String;, "just testing")@LBootstrapLinker;->backwardsLink(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite; move-result-object v2 sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v4, "got back - " invoke-virtual {v3, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V .end method smali-2.2.6/baksmali/src/test/resources/LargeLocalTest/000077500000000000000000000000001342202223400230305ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/LargeLocalTest/LargeEndLocal.smali000066400000000000000000000002731342202223400265150ustar00rootroot00000000000000.class LLargeRestartLocal; .super Ljava/lang/Object; # virtual methods .method public static main([Ljava/lang/String;)V .registers 2 .end local p99 return-void .end method smali-2.2.6/baksmali/src/test/resources/LargeLocalTest/LargeRestartLocal.smali000066400000000000000000000002731342202223400274330ustar00rootroot00000000000000.class LLargeEndLocal; .super Ljava/lang/Object; # virtual methods .method public static main([Ljava/lang/String;)V .registers 2 .restart local p99 return-void .end method smali-2.2.6/baksmali/src/test/resources/LargeLocalTest/LargeStartLocal.smali000066400000000000000000000002771342202223400271100ustar00rootroot00000000000000.class LLargeStartLocal; .super Ljava/lang/Object; # virtual methods .method public static main([Ljava/lang/String;)V .registers 2 .local p99, "blah":I return-void .end method smali-2.2.6/baksmali/src/test/resources/LocalTest/000077500000000000000000000000001342202223400220555ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/LocalTest/LocalTest.smali000066400000000000000000000017511342202223400250020ustar00rootroot00000000000000.class public LLocalTest; .super Ljava/lang/Object; # direct methods .method public static method1()V .registers 10 .local v0, "blah! This local name has some spaces, a colon, even a \nnewline!":I, "some sig info:\nblah." .local v1, "blah! This local name has some spaces, a colon, even a \nnewline!":V, "some sig info:\nblah." .local v2, "blah! This local name has some spaces, a colon, even a \nnewline!":I .local v3, "blah! This local name has some spaces, a colon, even a \nnewline!":V .local v4, null:I, "some sig info:\nblah." .local v5, null:V, "some sig info:\nblah." .local v6, null:I .local v7 .local v8 .local v9 return-void .end method .method public static method2(IJLjava/lang/String;)V .registers 10 .param p0, "blah! This local name has some spaces, a colon, even a \nnewline!" # I .param p1 # J .annotation runtime LAnnotationWithValues; .end annotation .end param return-void .end method smali-2.2.6/baksmali/src/test/resources/LocalTest/classes.dex000066400000000000000000000015001342202223400242100ustar00rootroot00000000000000dex 035jµÏ$éH°Æì7.$W™4œp“Ä0<pxV4x p ¼Ôä8 "/CWZ`¢«´ÌÐ  ÌÿÿÿÿôjIJLAnnotationWithValues; LLocalTest;Ljava/lang/Object;Ljava/lang/String;VVIJL@blah! This local name has some spaces, a colon, even a newline!method1method2some sig info: blah.Úàè          ; Ä Ø p ¼Ôä Ì Úàè ô   D jx|smali-2.2.6/baksmali/src/test/resources/ManyRegistersTest/000077500000000000000000000000001342202223400236175ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/ManyRegistersTest/ManyRegisters.smali000066400000000000000000000002021342202223400274340ustar00rootroot00000000000000.class LManyRegisters; .super Ljava/lang/Object; .method public manyRegisters()V .registers 65535 return-void .end methodsmali-2.2.6/baksmali/src/test/resources/MultiSwitchTest/000077500000000000000000000000001342202223400232775ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.dex000066400000000000000000000011501342202223400272720ustar00rootroot00000000000000dex 035õB‰;aõ¯Çi¹²u²û 0ÁÅ+WìhpxV4ìpˆ” °˜П|‹°³ÈÝ  +(+  & ,(,  c LMultiSwitch;Ljava/lang/Object;Format31t.smaliVmulti-packed-switchmulti-sparse-switchР pˆ” ° Ð | Ýìsmali-2.2.6/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.smali000066400000000000000000000024061342202223400276240ustar00rootroot00000000000000.class public LMultiSwitch; .super Ljava/lang/Object; .source "Format31t.smali" .method public multi-packed-switch()V .registers 1 const p0, 0xc packed-switch p0, :pswitch_data_12 goto :goto_b :pswitch_7 return-void :pswitch_8 return-void :pswitch_9 return-void :pswitch_a return-void :goto_b packed-switch p0, :pswitch_data_12 nop return-void :pswitch_f return-void :pswitch_10 return-void :pswitch_11 return-void :pswitch_12 :pswitch_data_12 .packed-switch 0xa :pswitch_7 :pswitch_8 :pswitch_9 :pswitch_a .end packed-switch .end method .method public multi-sparse-switch()V .registers 1 const p0, 0xd sparse-switch p0, :sswitch_data_12 goto :goto_b :sswitch_7 return-void :sswitch_8 return-void :sswitch_9 return-void :sswitch_a return-void :goto_b sparse-switch p0, :sswitch_data_12 nop return-void :sswitch_f return-void :sswitch_10 return-void :sswitch_11 return-void :sswitch_12 :sswitch_data_12 .sparse-switch 0xa -> :sswitch_7 0xf -> :sswitch_9 0x14 -> :sswitch_8 0x63 -> :sswitch_a .end sparse-switch .end methodsmali-2.2.6/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchOutput.smali000066400000000000000000000032211342202223400300210ustar00rootroot00000000000000.class public LMultiSwitch; .super Ljava/lang/Object; .source "Format31t.smali" # virtual methods .method public multi-packed-switch()V .registers 1 const p0, 0xc packed-switch p0, :pswitch_data_14 goto :goto_b :pswitch_7 return-void :pswitch_8 return-void :pswitch_9 return-void :pswitch_a return-void :goto_b packed-switch p0, :pswitch_data_20 nop :pswitch_f return-void :pswitch_10 return-void :pswitch_11 return-void :pswitch_12 return-void nop :pswitch_data_14 .packed-switch 0xa :pswitch_7 :pswitch_8 :pswitch_9 :pswitch_a .end packed-switch :pswitch_data_20 .packed-switch 0xa :pswitch_f :pswitch_10 :pswitch_11 :pswitch_12 .end packed-switch .end method .method public multi-sparse-switch()V .registers 1 const p0, 0xd sparse-switch p0, :sswitch_data_14 goto :goto_b :sswitch_7 return-void :sswitch_8 return-void :sswitch_9 return-void :sswitch_a return-void :goto_b sparse-switch p0, :sswitch_data_26 nop :sswitch_f return-void :sswitch_10 return-void :sswitch_11 return-void :sswitch_12 return-void nop :sswitch_data_14 .sparse-switch 0xa -> :sswitch_7 0xf -> :sswitch_9 0x14 -> :sswitch_8 0x63 -> :sswitch_a .end sparse-switch :sswitch_data_26 .sparse-switch 0xa -> :sswitch_f 0xf -> :sswitch_11 0x14 -> :sswitch_10 0x63 -> :sswitch_12 .end sparse-switch .end method smali-2.2.6/baksmali/src/test/resources/MultipleStartInstructionsTest/000077500000000000000000000000001342202223400262615ustar00rootroot00000000000000MultipleStartInstructionsTest.smali000066400000000000000000000036301342202223400353310ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/MultipleStartInstructionsTest.class public LMultipleStartInstructionsTest; .super Ljava/lang/Object; # direct methods .method public constructor (Ljava/lang/String;)V .registers 4 :try_start_0 #v0=(Uninit);v1=(Uninit);p0=(UninitThis,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;); invoke-direct {p0}, Ljava/lang/Object;->()V #v0=(Uninit);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;); #v0=(Uninit);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;); const-string v0, "blah" #v0=(Reference,Ljava/lang/String;);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;); #v0=(Reference,Ljava/lang/String;);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;); return-void #v0=(Reference,Ljava/lang/String;);v1=(Uninit);p0=(Reference,LMultipleStartInstructionsTest;);p1=(Reference,Ljava/lang/String;); :try_end_6 .catchall {:try_start_0 .. :try_end_6} :catchall_6 :catchall_6 :try_start_6 #v0=(Uninit);v1=(Uninit); #p0=(Conflicted):merge{Start:(UninitThis,LMultipleStartInstructionsTest;),0x0:(Reference,LMultipleStartInstructionsTest;)} #p1=(Reference,Ljava/lang/String;); invoke-static {}, LMultipleStartInstructionsTest;->blah()V #v0=(Uninit);v1=(Uninit);p0=(Conflicted);p1=(Reference,Ljava/lang/String;); :try_end_9 .catchall {:try_start_6 .. :try_end_9} :catchall_9 :catchall_9 #v0=(Uninit);v1=(Uninit); #p0=(Conflicted):merge{Start:(UninitThis,LMultipleStartInstructionsTest;),0x0:(Reference,LMultipleStartInstructionsTest;),0x6:(Conflicted)} #p1=(Reference,Ljava/lang/String;); return-void #v0=(Uninit);v1=(Uninit);p0=(Conflicted);p1=(Reference,Ljava/lang/String;); .end method .method public static blah()V .registers 0 return-void .end method smali-2.2.6/baksmali/src/test/resources/MultipleStartInstructionsTest/classes.dex000066400000000000000000000010701342202223400304160ustar00rootroot00000000000000dex 035vDA3b“.¢Êƒ¡r☢ݣ¦øªÿ8pxV4°pŒœ´ÌLì’BczwŽš<ÿÿÿÿ  pq LMultipleStartInstructionsTest;Ljava/lang/Object;VLjava/lang/String;VLblah€ì ¨ pŒœ´Ì ì< B  °smali-2.2.6/baksmali/src/test/resources/ParamListMethodNameTest/000077500000000000000000000000001342202223400246615ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/ParamListMethodNameTest/ParamListMethodName.smali000066400000000000000000000001221342202223400315410ustar00rootroot00000000000000.class Lblah; .super Ljava/lang/Object; .method public abstract II()V .end methodsmali-2.2.6/baksmali/src/test/resources/RegisterEqualityOnMergeTest/000077500000000000000000000000001342202223400256025ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/RegisterEqualityOnMergeTest/RegisterEqualityOnMerge.smali000066400000000000000000000034401342202223400334110ustar00rootroot00000000000000.class public LRegisterEqualityOnMerge; .super Ljava/lang/Object; # direct methods .method public constructor ()V .registers 4 #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LRegisterEqualityOnMerge;); invoke-direct {p0}, Ljava/lang/Object;->()V #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); invoke-virtual {p0}, Ljava/lang/Object;->toString()Ljava/lang/String; #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); move-result-object v0 #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); if-eqz v0, :cond_d #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); invoke-virtual {p0}, Ljava/lang/Object;->toString()Ljava/lang/String; #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); move-result-object v0 #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); :cond_d #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); return-void #v0=(Reference,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LRegisterEqualityOnMerge;); .end method smali-2.2.6/baksmali/src/test/resources/RegisterEqualityOnMergeTest/classes.dex000066400000000000000000000007741342202223400277510ustar00rootroot00000000000000dex 035¼?šÂÊ æ& ¤m¾¼¬5{°?}º¶ÂüpxV4€pŒœ´ÌìJf3RGiÿÿÿÿspn 8n LRegisterEqualityOnMerge;Ljava/lang/Object;VLjava/lang/String;LtoString€ì pŒœ´Ì ì  s€smali-2.2.6/baksmali/src/test/resources/SwitchTest/000077500000000000000000000000001342202223400222645ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/SwitchTest/UnorderedSparseSwitchInput.smali000066400000000000000000000010051342202223400306160ustar00rootroot00000000000000.class public LUnorderedSparseSwitch; .super Ljava/lang/Object; .method public static test_sparse-switch()V .registers 1 const v0, 13 sparse-switch v0, :SparseSwitch :Label10 return-void :Label20 return-void :Label15 return-void :Label13 return-void :Label99 return-void # Note: unordered keys :SparseSwitch .sparse-switch 10 -> :Label10 20 -> :Label20 15 -> :Label15 99 -> :Label99 13 -> :Label13 .end sparse-switch .end methodsmali-2.2.6/baksmali/src/test/resources/SwitchTest/UnorderedSparseSwitchOutput.smali000066400000000000000000000007171342202223400310300ustar00rootroot00000000000000.class public LUnorderedSparseSwitch; .super Ljava/lang/Object; .method public static test_sparse-switch()V .registers 1 const v0, 0xd sparse-switch v0, :sswitch_data_c :sswitch_6 return-void :sswitch_7 return-void :sswitch_8 return-void :sswitch_9 return-void :sswitch_a return-void nop # Note: ordered keys :sswitch_data_c .sparse-switch 0xa -> :sswitch_6 0xd -> :sswitch_9 0xf -> :sswitch_8 0x14 -> :sswitch_7 0x63 -> :sswitch_a .end sparse-switch .end methodsmali-2.2.6/baksmali/src/test/resources/UninitRefIdentityTest/000077500000000000000000000000001342202223400244405ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/resources/UninitRefIdentityTest/UninitRefIdentityTest.smali000066400000000000000000000116761342202223400317570ustar00rootroot00000000000000.class public LUninitRefIdentityTest; .super Ljava/lang/Object; # direct methods .method public constructor ()V .registers 4 #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(UninitThis,LUninitRefIdentityTest;); invoke-direct {p0}, Ljava/lang/Object;->()V #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); #v0=(Uninit);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); new-instance v0, Ljava/lang/String; #v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); #v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); if-eqz v0, :cond_9 #v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); #v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); new-instance v0, Ljava/lang/String; #v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); :cond_9 #v0=(Conflicted):merge{0x5:(UninitRef,Ljava/lang/String;),0x7:(UninitRef,Ljava/lang/String;)} #v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); invoke-direct {v0}, Ljava/lang/String;->()V #v0=(Conflicted);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); #v0=(Conflicted);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); return-void #v0=(Conflicted);v1=(Uninit);v2=(Uninit);p0=(Reference,LUninitRefIdentityTest;); .end method .method public constructor (I)V .registers 2 #p0=(UninitThis,LUninitRefIdentityTest;);p1=(Integer); move-object p1, p0 #p0=(UninitThis,LUninitRefIdentityTest;);p1=(UninitThis,LUninitRefIdentityTest;); #p0=(UninitThis,LUninitRefIdentityTest;);p1=(UninitThis,LUninitRefIdentityTest;); invoke-direct {p1}, Ljava/lang/Object;->()V #p0=(Reference,LUninitRefIdentityTest;);p1=(Reference,LUninitRefIdentityTest;); :cond_4 #p0=(Reference,LUninitRefIdentityTest;); #p1=(Reference,LUninitRefIdentityTest;):merge{0x1:(Reference,LUninitRefIdentityTest;),0x7:(Null)} const p1, 0x0 #p0=(Reference,LUninitRefIdentityTest;);p1=(Null); #p0=(Reference,LUninitRefIdentityTest;);p1=(Null); if-nez p1, :cond_4 #p0=(Reference,LUninitRefIdentityTest;);p1=(Null); #p0=(Reference,LUninitRefIdentityTest;);p1=(Null); return-void #p0=(Reference,LUninitRefIdentityTest;);p1=(Null); .end method .method public constructor (Ljava/lang/String;)V .registers 2 #p0=(UninitThis,LUninitRefIdentityTest;);p1=(Reference,Ljava/lang/String;); move-object p1, p0 #p0=(UninitThis,LUninitRefIdentityTest;);p1=(UninitThis,LUninitRefIdentityTest;); #p0=(UninitThis,LUninitRefIdentityTest;);p1=(UninitThis,LUninitRefIdentityTest;); invoke-direct {p0}, Ljava/lang/Object;->()V #p0=(Reference,LUninitRefIdentityTest;);p1=(Reference,LUninitRefIdentityTest;); #p0=(Reference,LUninitRefIdentityTest;);p1=(Reference,LUninitRefIdentityTest;); return-void #p0=(Reference,LUninitRefIdentityTest;);p1=(Reference,LUninitRefIdentityTest;); .end method # virtual methods .method public overlappingInits()V .registers 3 #v0=(Uninit);v1=(Uninit);p0=(Reference,LUninitRefIdentityTest;); new-instance v0, Ljava/lang/String; #v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);p0=(Reference,LUninitRefIdentityTest;); #v0=(UninitRef,Ljava/lang/String;);v1=(Uninit);p0=(Reference,LUninitRefIdentityTest;); new-instance v1, Ljava/lang/String; #v0=(UninitRef,Ljava/lang/String;);v1=(UninitRef,Ljava/lang/String;);p0=(Reference,LUninitRefIdentityTest;); #v0=(UninitRef,Ljava/lang/String;);v1=(UninitRef,Ljava/lang/String;);p0=(Reference,LUninitRefIdentityTest;); new-instance p0, Ljava/lang/String; #v0=(UninitRef,Ljava/lang/String;);v1=(UninitRef,Ljava/lang/String;);p0=(UninitRef,Ljava/lang/String;); #v0=(UninitRef,Ljava/lang/String;);v1=(UninitRef,Ljava/lang/String;);p0=(UninitRef,Ljava/lang/String;); invoke-direct {p0}, Ljava/lang/String;->()V #v0=(UninitRef,Ljava/lang/String;);v1=(UninitRef,Ljava/lang/String;);p0=(Reference,Ljava/lang/String;); #v0=(UninitRef,Ljava/lang/String;);v1=(UninitRef,Ljava/lang/String;);p0=(Reference,Ljava/lang/String;); invoke-direct {v1}, Ljava/lang/String;->()V #v0=(UninitRef,Ljava/lang/String;);v1=(Reference,Ljava/lang/String;);p0=(Reference,Ljava/lang/String;); #v0=(UninitRef,Ljava/lang/String;);v1=(Reference,Ljava/lang/String;);p0=(Reference,Ljava/lang/String;); invoke-direct {v0}, Ljava/lang/String;->()V #v0=(Reference,Ljava/lang/String;);v1=(Reference,Ljava/lang/String;);p0=(Reference,Ljava/lang/String;); #v0=(Reference,Ljava/lang/String;);v1=(Reference,Ljava/lang/String;);p0=(Reference,Ljava/lang/String;); return-void #v0=(Reference,Ljava/lang/String;);v1=(Reference,Ljava/lang/String;);p0=(Reference,Ljava/lang/String;); .end method smali-2.2.6/baksmali/src/test/resources/UninitRefIdentityTest/classes.dex000066400000000000000000000013541342202223400266020ustar00rootroot00000000000000dex 035ŽNÏ×IbÖjdx“1~\^Éóv5’:R”ìpxV4X p”¨ÌüÐ$'@Thkosˆÿÿÿÿ<ILUninitRefIdentityTest;Ljava/lang/Object;Ljava/lang/String;VVIVLoverlappingInits p"8"p p9ýÿp"""ppp€ €Ì€ðŒ  p”¨Ìü ˆ˜   <Xsmali-2.2.6/baksmali/src/test/smali/000077500000000000000000000000001342202223400172565ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/smali/baksmali_test_class.smali000066400000000000000000000114111342202223400243120ustar00rootroot00000000000000.class public Lbaksmali/test/class; .super Ljava/lang/Object; .source "baksmali_test_class.smali" .implements Lsome/interface; .implements Lsome/other/interface; .annotation build Lsome/annotation; value1 = "test" value2 = .subannotation Lsome/annotation; value1 = "test2" value2 = Lsome/enum; .end subannotation .end annotation .annotation system Lsome/annotation; .end annotation .field public static aStaticFieldWithoutAnInitializer:I .field public static longStaticField:J = 0x300000000L .field public static longNegStaticField:J = -0x300000000L .field public static intStaticField:I = 0x70000000 .field public static intNegStaticField:I = -500 .field public static shortStaticField:S = 500s .field public static shortNegStaticField:S = -500s .field public static byteStaticField:B = 123t .field public static byteNegStaticField:B = 0xAAt .field public static floatStaticField:F = 3.1415926f .field public static doubleStaticField:D = 3.141592653589793 .field public static charStaticField:C = 'a' .field public static charEscapedStaticField:C = '\n' .field public static boolTrueStaticField:Z = true .field public static boolFalseStaticField:Z = false .field public static typeStaticField:Ljava/lang/Class; = Lbaksmali/test/class; .field public static stringStaticField:Ljava/lang/String; = "test" .field public static stringEscapedStaticField:Ljava/lang/String; = "test\ntest" .field public static fieldStaticField:Ljava/lang/reflect/Field; = Lbaksmali/test/class;->fieldStaticField:Ljava/lang/reflect/Field; .field public static methodStaticField:Ljava/lang/reflect/Method; = Lbaksmali/test/class;->teshMethod(ILjava/lang/String;)Ljava/lang/String; .field public static arrayStaticField:[I = {1, 2, 3, {1, 2, 3, 4}} .field public static enumStaticField:Lsome/enum; = .enum Lsome/enum;->someEnumValue:Lsome/enum; .field public static annotationStaticField:Lsome/annotation; = .subannotation Lsome/annotation; value1 = "test" value2 = .subannotation Lsome/annotation; value1 = "test2" value2 = Lsome/enum; .end subannotation .end subannotation .field public static staticFieldWithAnnotation:I .annotation runtime La/field/annotation; this = "is" a = "test" .end annotation .annotation runtime Lorg/junit/Test; .end annotation .end field .field public instanceField:Ljava/lang/String; .method public constructor ()V .registers 1 invoke-direct {p0}, Ljava/lang/Object;->()V return-void .end method .method public testMethod(ILjava/lang/String;)Ljava/lang/String; .registers 3 .annotation runtime Lorg/junit/Test; .end annotation .annotation system Lyet/another/annotation; somevalue = 1234 anothervalue = 3.14159 .end annotation const-string v0, "testing\n123" goto switch: sget v0, Lbaksmali/test/class;->staticField:I switch: packed-switch v0, pswitch: try_start: const/4 v0, 7 const v0, 10 nop try_end: .catch Ljava/lang/Exception; {try_start: .. try_end:} handler: .catchall {try_start: .. try_end:} handler2: handler: Label10: Label11: Label12: Label13: return-object v0 .array-data 4 1 2 3 4 5 6 200 .end array-data pswitch: .packed-switch 10 Label10: Label11: Label12: Label13: .end packed-switch handler2: return-void .end method .method public abstract testMethod2()V .annotation runtime Lsome/annotation; subannotation = .subannotation Lsome/other/annotation; value = "value" .end subannotation .end annotation .annotation runtime Lorg/junit/Test; .end annotation .end method .method public tryTest()V .registers 1 handler: nop try_start: const/4 v0, 7 const v0, 10 nop try_end: .catch Ljava/lang/Exception; {try_start: .. try_end:} handler: .end method .method public debugTest(IIIII)V .registers 10 .parameter "Blah" .parameter .parameter "BlahWithAnnotations" .annotation runtime Lsome/annotation; something = "some value" somethingelse = 1234 .end annotation .annotation runtime La/second/annotation; .end annotation .end parameter .parameter .annotation runtime Lsome/annotation; something = "some value" somethingelse = 1234 .end annotation .end parameter .parameter "LastParam" .prologue nop nop .source "somefile.java" .line 101 nop .line 50 .local v0, aNumber:I const v0, 1234 .end local v0 .source "someotherfile.java" .line 900 const-string v0, "1234" .restart local v0 const v0, 6789 .end local v0 .epilogue .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test1/000077500000000000000000000000001342202223400216465ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/smali/deodex_test1/main.smali000066400000000000000000000043641342202223400236300ustar00rootroot00000000000000.class public Lmain; .super Ljava/lang/Object; .method public static main([Ljava/lang/String;)V .registers 3 :here4 const v0, 0 :here3 new-instance v2, Lsuperclass; invoke-direct {v2}, Lsuperclass;->()V if-eqz v0, :here #this is the unresolvable instruction. v0 is always null, #and this will always throw an exception. It should be #replaced with throw v0. invoke-virtual {v0}, Lrandomclass;->getSuperclass()Lsuperclass; move-result-object v1 if-eqz v0, :here #this would normally be deodexable, except that it follows #the above un-deodexeable instruction, which prevents the #propagation of any register information. It can never be #reached, and should be replaced with throw v2 invoke-virtual {v2}, Lsuperclass;->somemethod()V #another odexed instruction that uses the result of the #first unresolveable odex instruction. This should #be replaced with throw v1 invoke-virtual {v1}, Lsuperclass;->somemethod()V :here #and we're back to the non-dead code invoke-virtual {v2}, Lsuperclass;->somemethod()V if-nez v0, :here3 return-void .end method .method public static FirstInstructionTest(Lrandomclass;)V .registers 1 :try_start invoke-virtual/range {p0}, Lrandomclass;->getSuperclass()Lsuperclass; return-void :try_end .catch Ljava/lang/Exception; {:try_start .. :try_end} :handler :handler :inner_try_start #this tests that the parameter register types are correctly propagated to the exception handlers, in the #case that the first instruction of the method can throw an exception and is in a try black invoke-virtual/range {p0}, Lrandomclass;->getSuperclass()Lsuperclass; return-void :inner_try_end .catch Ljava/lang/Exception; {:inner_try_start .. :inner_try_end} :inner_handler :inner_handler #this additionally tests that the register types are propagated recursively, in the case that the first #instruction in the exception handler can also throw an exception, and is covered by a try block invoke-virtual/range {p0}, Lrandomclass;->getSuperclass()Lsuperclass; return-void .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test1/randomclass.smali000066400000000000000000000005601342202223400252040ustar00rootroot00000000000000.class public Lrandomclass; .super Ljava/lang/Object; .method public constructor ()V .registers 1 invoke-direct {p0}, Ljava/lang/Object;->()V return-void .end method .method public getSuperclass()Lsuperclass; .registers 2 new-instance v0, Lsuperclass; invoke-direct {v0}, Lsuperclass;->()V return-object v0 .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test1/subclass.smali000066400000000000000000000006741342202223400245230ustar00rootroot00000000000000.class public Lsubclass; .super Lsuperclass; .method public constructor ()V .registers 1 invoke-direct {p0}, Lsuperclass;->()V return-void .end method .method public somemethod()V .registers 2 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "subclass.somemethod" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V return-void .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test1/superclass.smali000066400000000000000000000007141342202223400250630ustar00rootroot00000000000000.class public Lsuperclass; .super Ljava/lang/Object; .method public constructor ()V .registers 1 invoke-direct {p0}, Ljava/lang/Object;->()V return-void .end method .method public somemethod()V .registers 2 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "superclass.somemethod" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V return-void .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test2/000077500000000000000000000000001342202223400216475ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/smali/deodex_test2/app_classes/000077500000000000000000000000001342202223400241445ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/smali/deodex_test2/app_classes/main.smali000066400000000000000000000015171342202223400261230ustar00rootroot00000000000000.class public Lmain; .super Ljava/lang/Object; .method public static main([Ljava/lang/String;)V .registers 6 const v2, 0 const v3, 1 const v4, 0 new-array v1, v3, [Lsubclass1; new-instance v0, Lsubclass1; invoke-direct {v0}, Lsubclass1;->()V aput-object v0, v1, v4 goto :here2 :here const v2, 1 :here2 #this is tricky, because it has to merge two array types, [Lsubclass1; and [Lsubclass2 #which should result in [Lsuperclass;. However, this dex file won't have a reference #to [Lsuperclass; aget-object v5, v1, v4 invoke-virtual {v5}, Lsupersuperclass;->somemethod()V new-array v1, v3, [Lsubclass2; new-instance v0, Lsubclass2; invoke-direct {v0}, Lsubclass2;->()V aput-object v0, v1, v4 if-eqz v2, :here return-void .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test2/bootclass_classes/000077500000000000000000000000001342202223400253555ustar00rootroot00000000000000smali-2.2.6/baksmali/src/test/smali/deodex_test2/bootclass_classes/randomclass.smali000066400000000000000000000005601342202223400307130ustar00rootroot00000000000000.class public Lrandomclass; .super Ljava/lang/Object; .method public constructor ()V .registers 1 invoke-direct {p0}, Ljava/lang/Object;->()V return-void .end method .method public getSuperclass()Lsuperclass; .registers 2 new-instance v0, Lsuperclass; invoke-direct {v0}, Lsuperclass;->()V return-object v0 .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test2/bootclass_classes/subclass1.smali000066400000000000000000000006761342202223400303150ustar00rootroot00000000000000.class public Lsubclass1; .super Lsuperclass; .method public constructor ()V .registers 1 invoke-direct {p0}, Lsuperclass;->()V return-void .end method .method public somemethod()V .registers 2 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "subclass1.somemethod" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V return-void .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test2/bootclass_classes/subclass2.smali000066400000000000000000000006761342202223400303160ustar00rootroot00000000000000.class public Lsubclass2; .super Lsuperclass; .method public constructor ()V .registers 1 invoke-direct {p0}, Lsuperclass;->()V return-void .end method .method public somemethod()V .registers 2 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "subclass2.somemethod" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V return-void .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test2/bootclass_classes/superclass.smali000066400000000000000000000007121342202223400305700ustar00rootroot00000000000000.class public Lsuperclass; .super Lsupersuperclass; .method public constructor ()V .registers 1 invoke-direct {p0}, Lsupersuperclass;->()V return-void .end method .method public somemethod()V .registers 2 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "superclass.somemethod" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V return-void .end methodsmali-2.2.6/baksmali/src/test/smali/deodex_test2/bootclass_classes/supersuperclass.smali000066400000000000000000000007261342202223400316540ustar00rootroot00000000000000.class public Lsupersuperclass; .super Ljava/lang/Object; .method public constructor ()V .registers 1 invoke-direct {p0}, Ljava/lang/Object;->()V return-void .end method .method public somemethod()V .registers 2 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "supersuperclass.somemethod" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V return-void .end methodsmali-2.2.6/build.gradle000066400000000000000000000145431342202223400151060ustar00rootroot00000000000000/* * 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. */ apply plugin: 'idea' version = '2.2.6' def jcommanderVersion = '' if (!('release' in gradle.startParameter.taskNames)) { // we compile against 1.48 normally, to match what's in AOSP, but switch to a newer version // for release, because it has some fixes required when running on Android jcommanderVersion = 'com.beust:jcommander:1.48' def versionSuffix try { def git = org.eclipse.jgit.api.Git.open(file('.')) def head = git.getRepository().getRef('HEAD') versionSuffix = head.getObjectId().abbreviate(8).name() if (!git.status().call().clean) { versionSuffix += '-dirty' } } catch (Exception) { // In case we can't get the commit for some reason, // just use -dev versionSuffix = 'dev' } version += "-${versionSuffix}" } else { jcommanderVersion = 'com.beust:jcommander:1.64' } // Note: please don't use this. This is strictly for the official releases // that are posted on, e.g. the bitbucket download page. task release() { } task(install).doLast { println "Installing version: ${version}" } // The projects that get pushed to maven def maven_release_projects = ['smali', 'baksmali', 'dexlib2', 'util'] subprojects { apply plugin: 'java' apply plugin: 'idea' if (JavaVersion.current().isJava8Compatible()) { allprojects { tasks.withType(Javadoc) { options.addStringOption('Xdoclint:none', '-quiet') } } } version = parent.version ext { depends = [ guava: 'com.google.guava:guava:18.0', findbugs: 'com.google.code.findbugs:jsr305:1.3.9', junit: 'junit:junit:4.6', mockito: 'org.mockito:mockito-core:1.10.19', antlr_runtime: 'org.antlr:antlr-runtime:3.5.2', antlr: 'org.antlr:antlr:3.5.2', stringtemplate: 'org.antlr:stringtemplate:3.2.1', jflex_plugin: 'org.xbib.gradle.plugin:gradle-plugin-jflex:1.1.0', proguard_gradle: 'net.sf.proguard:proguard-gradle:5.2.1', dx: 'com.google.android.tools:dx:1.7', gson: 'com.google.code.gson:gson:2.3.1', jcommander: jcommanderVersion ] } repositories { mavenCentral() } if (project.name in maven_release_projects) { apply plugin: 'maven' apply plugin: 'signing' group = 'org.smali' task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from 'build/docs/javadoc' } task sourcesJar(type: Jar) { classifier = 'sources' from sourceSets.main.allJava } artifacts { archives javadocJar archives sourcesJar } signing { required { gradle.taskGraph.hasTask('uploadArchives') } sign configurations.archives } uploadArchives { repositories.mavenDeployer { configuration = configurations.archives beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } if (rootProject.hasProperty('sonatypeUsername') && rootProject.hasProperty('sonatypePassword')) { repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') { authentication(userName: sonatypeUsername, password: sonatypePassword) } } pom.artifactId = project.name pom.project { name project.name url 'http://smali.org' packaging 'jar' licenses { license { name 'The BSD 3-Clause License' url 'http://opensource.org/licenses/BSD-3-Clause' distribution 'repo' } } scm { connection 'scm:git:git://github.com/JesusFreke/smali.git' developerConnection 'scm:git:git@github.com:JesusFreke/smali.git' } developers { developer { id 'jesusfreke' name 'Ben Gruver' email 'jesusfreke@jesusfreke.com' } } } } } tasks.getByPath(':release').dependsOn(uploadArchives) } } buildscript { repositories { mavenCentral() } dependencies { classpath 'org.eclipse.jgit:org.eclipse.jgit:2.0.0.201206130900-r' } } task wrapper(type: Wrapper) { gradleVersion = '4.6' distributionType = Wrapper.DistributionType.ALL } smali-2.2.6/deodexerant/000077500000000000000000000000001342202223400151225ustar00rootroot00000000000000smali-2.2.6/deodexerant/Android.mk000066400000000000000000000033541342202223400170400ustar00rootroot00000000000000# Copyright 2011, 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. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := deodexerant LOCAL_SRC_FILES:= deodexerant.c LOCAL_SHARED_LIBRARIES := libdl LOCAL_MODULE_TAGS := optional LOCAL_LDFLAGS := -Wl,--hash-style=sysv include $(BUILD_EXECUTABLE) smali-2.2.6/deodexerant/README000066400000000000000000000016271342202223400160100ustar00rootroot00000000000000usage: adb push deodexerant /data/local adb shell chmod +x /data/local/deodexerant adb shell /data/local/deodexerant > inline.txt deodexerant is a binary that runs on a device and dumps out dalvik's inline method table. This can be used in cases where a particular built of dalvik has a non-standard inline method table for whatever reason. The output from this tool is intended to be used with the -T option for baksmali deodexerant is intended to be build within the AOSP build system. Assuming you have $MYDROID set to the root of the AOSP source tree, and $SMALI set to the root of the smali source tree, 1. mkdir -p $MYDROID/external/deodexerant 2. cp -r $SMALI/deodexerant $MYDROID/dalvik/deodexerant 3. cd $MYDROID 3. source build/envsetup.sh 4. lunch generic-eng 5. make deodexerant If all goes well, you should now have a deodexerant binary at: $MYDROID/out/target/product/generic/system/bin/deodexerant smali-2.2.6/deodexerant/deodexerant.c000066400000000000000000000062451342202223400175770ustar00rootroot00000000000000/* * Copyright 2011, 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. */ #include #include typedef struct InlineOperation { void * func; const char* classDescriptor; const char* methodName; const char* methodSignature; } InlineOperation; typedef const InlineOperation* (*dvmGetInlineOpsTablePtr)(); typedef int (*dvmGetInlineOpsTableLengthPtr)(); void main(int argc, char **argv) { int i; void *libdvm = dlopen("libdvm.so", RTLD_LAZY); if (libdvm == NULL) { printf("Failed to load libdvm: %s\n", dlerror()); return; } dvmGetInlineOpsTablePtr dvmGetInlineOpsTable = dlsym(libdvm, "dvmGetInlineOpsTable"); if (dvmGetInlineOpsTable == NULL) { // clear the error, and retry with the c++ mangled name dlerror(); dvmGetInlineOpsTable = dlsym(libdvm, "_Z20dvmGetInlineOpsTablev"); } if (dvmGetInlineOpsTable == NULL) { printf("Failed to load dvmGetInlineOpsTable: %s\n", dlerror()); dlclose(libdvm); return; } dvmGetInlineOpsTableLengthPtr dvmGetInlineOpsTableLength = dlsym(libdvm, "dvmGetInlineOpsTableLength"); if (dvmGetInlineOpsTableLength == NULL) { // clear the error, and retry with the c++ mangled name dlerror(); dvmGetInlineOpsTableLength = dlsym(libdvm, "_Z26dvmGetInlineOpsTableLengthv"); } if (dvmGetInlineOpsTableLength == NULL) { printf("Failed to load dvmGetInlineOpsTableLength: %s\n", dlerror()); dlclose(libdvm); return; } const InlineOperation *inlineTable = dvmGetInlineOpsTable(); int length = dvmGetInlineOpsTableLength(); for (i=0; i%s%s\n", item->classDescriptor, item->methodName, item->methodSignature); } dlclose(libdvm); return; }smali-2.2.6/dexlib2/000077500000000000000000000000001342202223400141515ustar00rootroot00000000000000smali-2.2.6/dexlib2/OatVersions.txt000066400000000000000000000136751342202223400172020ustar00rootroot000000000000007642cfc90fc9c3ebfd8e3b5041915705c93b5cf0 - 56 - first version with all stability fixes needed for deodexing 14691c5e786e8c2c5734f687e4c96217340771be - 57 1558b577907b613864e98f05862543557263e864 - 58 f3251d12dfa387493dbde4c4148a633802f5f7e3 - 59 706cae36209932f258b2fe2e396f31d2dd7d585e - 58 (revert of f3251d12) d7cbf8a6629942e7bd315ffae7e1c77b082f3e11 - 60 - return-void-barrier -> return-void-no-barrier 1412dfa4adcd511902e510fa0c948b168ab5840c - 61 (re-commit of f3251d12) 9d6bf69ad3012a9d843268fdd5325b6719b6d5f2 - 62 - classpath list was added 0de1133ba600f299b3d67938f650720d9f859eb2 - 63 07785bb98dc8bbe192970e0f4c2cafd338a8dc68 - 64 fa2c054b28d4b540c1b3651401a7a091282a015f - 65 7070ccd8b6439477eafeea7ed3736645d78e003f - 64 (revert of fa2c054b) 7bf2b4f1d08050f80782217febac55c8cfc5e4ef - 65 (re-commit of fa2c054b) 0b71357fb52be9bb06d35396a3042b4381b01041 - 66 fab6788358dfb64e5c370611ddbbbffab0ed0553 - 67 - Change in FieldGap priority queue ordering 1aee900d5a0b3a8d78725a7551356bda0d8554e1 - 68 54b62480636ae846d705fc180c7bd6cd08ec1e42 - 69 6e2d5747d00697a25251d25dd33b953e54709507 - 68 (revert of 54b62480) 0747466fca310eedea5fc49e37d54f240a0b3c0f - 69 (re-commit of 54b62480) 501fd635a557645ab05f893c56e1f358e21bab82 - 70 99170c636dfae4908b102347cfe9f92bad1881cc - 71 3cfa4d05afa76e19ca99ec964b535a15c73683f0 - 72 - default methods d9786b0e5be23ea0258405165098b4216579209c - 73 - fast class lookup table a4f1220c1518074db18ca1044e9201492975750b - 74 625a64aad13905d8a2454bf3cc0e874487b110d5 - 75 - bootclasspath list was added - class offsets moved out to a separate table 919f5536182890d2e03f59b961acf8f7c836ff61 - 74 (revert of 625a64aa) 9bdf108885a27ba05fae8501725649574d7c491b - 75 (re-commit of 625a64aa) a62d2f04a6ecf804f8a78e722a6ca8ccb2dfa931 - 76 845e5064580bd37ad5014f7aa0d078be7265464d - 75 (revert of a62d2f04) 29d38e77c553c6cf71fc4dafe2d22b4e3f814872 - 76 (re-commit of 845e5064) d1537b569b6cd18297c5e02d13cdd588c4366c51 - 77 61b28a17d9b6e8e998103646e98e4a9772e11927 - 78 9d07e3d128ccfa0ef7670feadd424a825e447d1d - 79 952e1e3710158982941fc70326e9fddc3021235d - 80 013e3f33495dcc31dba19c9de128d23ed441d7d3 - 81 87f3fcbd0db352157fc59148e94647ef21b73bce - 82 02b75806a80f8b75c3d6ba2ff97c995117630f36 - 83 4359e61927866c254bc2d701e3ea4c48de10b79c - 84 d549c28cfbddba945cb88857bcca3dce1414fb29 - 85 952dbb19cd094b8bfb01dbb33e0878db429e499a - 86 239d6eaff0cbb5c4c0139f7053a012758799f186 - 87 - introduction of vdex files 77d9dd75d5d4a22ad1235f9a08d2cfbf2f0ae6fa - 89 af1e2990cd1406a0fb7cba1d2e208208e950e413 - 90 9fd8c60cdff7b28a89bb97fd90ae9d0f37cf8f8b - 91 6beced4c017826f7c449f12fac7fa42403657f2b - 92 58c3f6a0d15a4340c0a11ab7fbc8c4b990c64b77 - 93 5923b5238091d9cd65f988fc059deb4fbb2e7f08 - 94 2b615ba29c4dfcf54aaf44955f2eac60f5080b2e - 95 f7aaacd97881c6924b8212c7f8fe4a4c8721ef53 - 94 (revert of 2b615ba) 0d3998b5ff619364acf47bec0b541e7a49bd6fe7 - 95 (re-commit of 2b615ba) ac141397dc29189ad2b2df41f8d4312246beec60 - 96 1998cd02603197f2acdc0734397a6d48b2f59b80 - 97 e71b35446985835363a4508646cf7b1121bd95a3 - 98 39cee66a8ddf0254626c9591662cf87e4a1cedc4 - 99 cc99df230feb46ba717252f002d0cc2da6828421 - 100 fee255039e30c1c3dfc70c426c3d176221c3cdf9 - 99 (revert of cc99df23) e761bccf9f0d884cc4d4ec104568cef968296492 - 100 (re-commit of cc99df23) 8d91ac31ccb92557e434d89ffade3372466e1af5 - 101 fd3161acfbe82c54ef49958f0ccc62511f224f91 - 102 a2f526f889be06f96ea59624c9dfb1223b3839f3 - 103 b048cb74b742b03eb6dd5f1d6dd49e559f730b36 - 104 12f1b99775bbf7dd82d0a897587ab6ed0e75ee22 - 105 ec7862283dd49f5a58d0ac45960ce27c2f7671b8 - 106 45aa598cd1773f5eb1705dec13bea059238e054d - 107 d16363a93053de0f32252c7897d839a46aff14ae - 108 1a20b6801f2432a42b906f0de01e7e9586526aec - 109 575d3e60c68b5cf481b615dde4a16283507b19ed - 110 85c0f2ac03417f5125bc2ff1dab8109859c67d5c - 111 5812e20ff7cbc8efa0b8d7486ada2f58840a6ad5 - 111 b7ea3799c15b0090bb690e18ac1b5b0fddbdeee8 - 112 - version bump for missing bump in commits - 3228908337fdfe851223f8ae374538de25cb5ad1 - 5812e20ff7cbc8efa0b8d7486ada2f58840a6ad5 d776ff08e07494327716f0d2ea1a774b2ebfbca9 - 113 bfb80d25eaeb7a604d5dd25a370e3869e96a33ab - 114 1aea3510b8dd0c512cec61c91c5ef1f1e5d53d64 - 115 6374c58f2ea403b3a05fb27376110fe4d0fc8e3f - 114 (revert of 1aea3510) 0b66d6174bf1f6023f9d36dda8538490b79c2e9f - 113 (revert of bfb80d25) 8d6768d47b66a688d35399d524ad5a5450e9d9d4 - 114 (i don't even) f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3b - 115 (115 again. heck if I know what's going on) cbcedbf9382bc773713cd3552ed96f417bf1daeb - 116 051071718085ce807a2e7c55278a8d723e238e86 - 116 1595815c2a914a78df7dfb6f0082f47d4e82bb36 - 117 f4f2daafb38c9c07ea74044a0fb89a2a19288b7a - 118 6bc7774426cc0b6bbab5566fa62b3c509455e583 - 119 88d329a698ba186aeb1f1ef8794355512ada84a9 - 120 612ff540cd3329935351f05923358cf29b9c9b44 - 121 c83dd7bfde2171c879efb92a31a363505385ffb9 - 122 eee1c0ec2b08a6be642b329dc2fe885391127da3 - 123 f977691961b5a49a074a535fcb29a5ad4a318974 - 124 2665bc8159698429f20a08f814e63c434910d608 - 124 88abba2b0cb0151d89e16da3e64025878dc2f142 - 125 99cdddaf8e5bc6b31d0eb375755ec4071a9fb527 - 125 c137cb03a90b9fd5a7d0ec7dd9b250db82ca88ef - 126 0eb882bfc5d260e8014c26adfda11602065aa5d8 - 127 - The oat_dex_files_offset field is added to the OatHeader class in art/runtime/oat.h. - The method_bss_mapping field is added to the OatDexFile class in art/runtime/oat_file.h. 7b0648aa7cb4b7a58e73bf353e031dfe4553d9d7 - 128 0cb172874481f736c6b7c491dd621166cc25561b - 129 a308a327884920cbb1e3e62964c4b5a01c29af8c - 130 (changed kMultiDexSeparator from ':' to '!') 4147fcc43c2ee019a06e55384985e3eaf82dcb8c - 131 75c5ed6e75f70002db5fa7c609137c04dd2bdf40 - 131 - The dex_layout_sections field is added to OatDexFile class in art/runtime/oat_file.h. - They did some kind of rebase or something so this commit is not in the master branch anymore. - Only indication is that they cherry picked some things from this commit for oat 132. 120aa286ab6adf3e76a31bc61fb4e583e5158d71 - 132 - The commit containing cherry picked changes from commit 75c5ed6e. - No other noteable changes to the Oat format. smali-2.2.6/dexlib2/VdexVersions.txt000066400000000000000000000007411342202223400173530ustar00rootroot000000000000007b49e6cade09bc65b3b5f22d45fc9d0a7184e4f2 - 0 - introduction of vdex files 5d5a36bddbc008cd52a3207aa2b31177c47f9a49 - 0 - verifier deps 4acefd33064d37b41ca55c3c9355345a20e5f9c2 - 0 - quickening info f54e5df37cb42d9a83fc54b375da5ef335d604a9 - 1 - dex file count + dex location checksum 7498105ec7497bae2ba9f1a697da9efa0c979654 - 2 - verify profile 3eba863e41d531340392d9ec64e17963ac898d81 - 3 97fa9928c07d3e0ee631235e9619fb0f8949ed7a - 4 6e54f78c7c1e01c1a91a458c6e51cca1c7d13ad4 - 5 smali-2.2.6/dexlib2/accessorTestGenerator/000077500000000000000000000000001342202223400204625ustar00rootroot00000000000000smali-2.2.6/dexlib2/accessorTestGenerator/build.gradle000066400000000000000000000033561342202223400227500ustar00rootroot00000000000000/* * 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. */ dependencies { compile project(':util') compile 'com.google.code.findbugs:jsr305:1.3.9' compile 'com.google.guava:guava:13.0.1' compile 'org.antlr:ST4:4.0.7' testCompile 'junit:junit:4.6' }smali-2.2.6/dexlib2/accessorTestGenerator/src/000077500000000000000000000000001342202223400212515ustar00rootroot00000000000000smali-2.2.6/dexlib2/accessorTestGenerator/src/main/000077500000000000000000000000001342202223400221755ustar00rootroot00000000000000smali-2.2.6/dexlib2/accessorTestGenerator/src/main/java/000077500000000000000000000000001342202223400231165ustar00rootroot00000000000000smali-2.2.6/dexlib2/accessorTestGenerator/src/main/java/org/000077500000000000000000000000001342202223400237055ustar00rootroot00000000000000smali-2.2.6/dexlib2/accessorTestGenerator/src/main/java/org/jf/000077500000000000000000000000001342202223400243045ustar00rootroot00000000000000smali-2.2.6/dexlib2/accessorTestGenerator/src/main/java/org/jf/dexlib2/000077500000000000000000000000001342202223400256355ustar00rootroot00000000000000smali-2.2.6/dexlib2/accessorTestGenerator/src/main/java/org/jf/dexlib2/AccessorTestGenerator.java000066400000000000000000000131711342202223400327540ustar00rootroot00000000000000/* * 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; import org.stringtemplate.v4.*; import java.io.*; import java.net.URL; public class AccessorTestGenerator { private static class UnaryOperation { public final String name; public UnaryOperation(String name) { this.name = name; } } private static class BinaryOperation { public final String name; public final String[] inputTypes; public BinaryOperation(String name, String[] inputTypes) { this.name = name; this.inputTypes = inputTypes; } } private static class TypeDef { public final String name; public final UnaryOperation[] unaryOperations; public final BinaryOperation[] binaryOperations; public TypeDef(String name, UnaryOperation[] unaryOperations, BinaryOperation[] binaryOperations) { this.name = name; this.unaryOperations = unaryOperations; this.binaryOperations = binaryOperations; } } private static final UnaryOperation[] unaryOperations = new UnaryOperation[] { new UnaryOperation("preinc"), new UnaryOperation("postinc"), new UnaryOperation("predec"), new UnaryOperation("postdec") }; private static final String[] booleanInputs = new String[] {"boolean"}; private static final String[] integralInputs = new String[] {"int", "long"}; private static final String[] allInputs = new String[] {"int", "float", "long", "double"}; private static final BinaryOperation[] booleanOperations = new BinaryOperation[] { new BinaryOperation("and", booleanInputs), new BinaryOperation("or", booleanInputs), new BinaryOperation("xor", booleanInputs), }; private static final BinaryOperation[] floatOperations = new BinaryOperation[] { new BinaryOperation("add", allInputs), new BinaryOperation("sub", allInputs), new BinaryOperation("mul", allInputs), new BinaryOperation("div", allInputs), new BinaryOperation("rem", allInputs), }; private static final BinaryOperation[] integralOperations = new BinaryOperation[] { new BinaryOperation("add", allInputs), new BinaryOperation("sub", allInputs), new BinaryOperation("mul", allInputs), new BinaryOperation("div", allInputs), new BinaryOperation("rem", allInputs), new BinaryOperation("and", integralInputs), new BinaryOperation("or", integralInputs), new BinaryOperation("xor", integralInputs), new BinaryOperation("shl", integralInputs), new BinaryOperation("shr", integralInputs), new BinaryOperation("ushr", integralInputs), }; private static final TypeDef[] types = new TypeDef[] { new TypeDef("boolean", new UnaryOperation[0], booleanOperations), new TypeDef("byte", unaryOperations, integralOperations), new TypeDef("char", unaryOperations, integralOperations), new TypeDef("short", unaryOperations, integralOperations), new TypeDef("int", unaryOperations, integralOperations), new TypeDef("long", unaryOperations, integralOperations), new TypeDef("float", unaryOperations, floatOperations), new TypeDef("double", unaryOperations, floatOperations), }; public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: java org.jf.dexlib2.AccessorTestGenerator "); } URL stgUrl = AccessorTestGenerator.class.getClassLoader().getResource("AccessorTest.stg"); STGroupFile stg = new STGroupFile(stgUrl, "utf-8", '<', '>'); ST fileSt = stg.getInstanceOf("file"); fileSt.add("types", types); PrintWriter w = null; try { w = new PrintWriter(new BufferedWriter(new FileWriter(args[0]))); w.print(fileSt.render()); } finally { if (w != null) { w.close(); } } } } smali-2.2.6/dexlib2/accessorTestGenerator/src/main/resources/000077500000000000000000000000001342202223400242075ustar00rootroot00000000000000smali-2.2.6/dexlib2/accessorTestGenerator/src/main/resources/AccessorTest.stg000066400000000000000000000064021342202223400273320ustar00rootroot00000000000000decl(type, name, value) ::= " ;" init(v) ::= " = " field_decl(type) ::= "private _val;" preinc_template(type) ::= "++_val;" postinc_template(type) ::= "_val++;" predec_template(type) ::= "--_val;" postdec_template(type) ::= "_val--;" add_template(type) ::= "_val += val;" sub_template(type) ::= "_val -= val;" mul_template(type) ::= "_val *= val;" div_template(type) ::= "_val /= val;" rem_template(type) ::= "_val %= val;" and_template(type) ::= "_val &= val;" or_template(type) ::= "_val |= val;" xor_template(type) ::= "_val ^= val;" shl_template(type) ::= "_val \<\<= val;" shr_template(type) ::= "_val >>= val;" ushr_template(type) ::= "_val >>>= val;" operation_template_name(operation) ::= "_template" binary_method(input, type, binary_operation) ::= << public void _( val) { <(operation_template_name(binary_operation))(type)> } >> binary_methods(binary_operation, type) ::= << >> unary_method(unary_operation, type) ::= << public void _() { <(operation_template_name(unary_operation))(type)> } >> type_methods(type) ::= << <[type.unaryOperations:unary_method(type), type.binaryOperations:binary_methods(type)];separator="\n\n"> >> file(types) ::= << /* * 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; public class AccessorTypes { private class Accessors { } } >> smali-2.2.6/dexlib2/build.gradle000066400000000000000000000071171342202223400164360ustar00rootroot00000000000000/* * 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. */ ext.testAccessorOutputDir = file("${buildDir}/generated-src/accessorTest/java") ext.testAccessorOutputFile = file("${testAccessorOutputDir}/org/jf/dexlib2/AccessorTypes.java") sourceSets { accessorTest { java { srcDir testAccessorOutputDir } } } configurations { accessorTestGenerator dx } dependencies { compile depends.findbugs compile depends.guava testCompile depends.junit testCompile depends.mockito accessorTestGenerator project('accessorTestGenerator') dx depends.dx } // You must manually execute this task to regenerate SyntheticAccessorFSM.java, after modifying the ragel file // e.g. ./gradlew ragel task ragel(type:Exec) { workingDir = 'src/main/ragel' commandLine 'ragel', '-J', '-o', file('src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java'), 'SyntheticAccessorFSM.rl' } task generateAccessorTestSource(type: JavaExec) { file(testAccessorOutputFile.parent).mkdirs() outputs.dir file(testAccessorOutputDir) classpath = configurations.accessorTestGenerator main = 'org.jf.dexlib2.AccessorTestGenerator' args testAccessorOutputFile } compileAccessorTestJava.dependsOn(generateAccessorTestSource) // You must manually execute this task to regenerate src/test/resources/accessorTest.dex task generateAccessorTestDex(type: JavaExec, dependsOn: compileAccessorTestJava) { def outputDex = file('src/test/resources/accessorTest.dex') file(outputDex.parent).mkdirs() inputs.dir(project.sourceSets.accessorTest.output.classesDir) outputs.file outputDex main 'com.android.dx.command.Main' classpath = configurations.dx args '--dex' args '--no-strict' args "--output=${outputDex}" args sourceSets.accessorTest.output.classesDir } uploadArchives { repositories.mavenDeployer { pom.project { description 'dexlib2 is a library for reading/modifying/writing Android dex files' scm { url 'https://github.com/JesusFreke/smali/tree/master/dexlib2' } } } }smali-2.2.6/dexlib2/src/000077500000000000000000000000001342202223400147405ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/000077500000000000000000000000001342202223400156645ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/000077500000000000000000000000001342202223400166055ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/000077500000000000000000000000001342202223400173745ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/000077500000000000000000000000001342202223400177735ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/000077500000000000000000000000001342202223400213245ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/AccessFlags.java000066400000000000000000000154471342202223400243600ustar00rootroot00000000000000/* * 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; import java.util.HashMap; public enum AccessFlags { PUBLIC(0x1, "public", true, true, true), PRIVATE(0x2, "private", true, true, true), PROTECTED(0x4, "protected", true, true, true), STATIC(0x8, "static", true, true, true), FINAL(0x10, "final", true, true, true), SYNCHRONIZED(0x20, "synchronized", false, true, false), VOLATILE(0x40, "volatile", false, false, true), BRIDGE(0x40, "bridge", false, true, false), TRANSIENT(0x80, "transient", false, false, true), VARARGS(0x80, "varargs", false, true, false), NATIVE(0x100, "native", false, true, false), INTERFACE(0x200, "interface", true, false, false), ABSTRACT(0x400, "abstract", true, true, false), STRICTFP(0x800, "strictfp", false, true, false), SYNTHETIC(0x1000, "synthetic", true, true, true), ANNOTATION(0x2000, "annotation", true, false, false), ENUM(0x4000, "enum", true, false, true), CONSTRUCTOR(0x10000, "constructor", false, true, false), DECLARED_SYNCHRONIZED(0x20000, "declared-synchronized", false, true, false); private int value; private String accessFlagName; private boolean validForClass; private boolean validForMethod; private boolean validForField; //cache the array of all AccessFlags, because .values() allocates a new array for every call private final static AccessFlags[] allFlags; private static HashMap accessFlagsByName; static { allFlags = AccessFlags.values(); accessFlagsByName = new HashMap(); for (AccessFlags accessFlag: allFlags) { accessFlagsByName.put(accessFlag.accessFlagName, accessFlag); } } private AccessFlags(int value, String accessFlagName, boolean validForClass, boolean validForMethod, boolean validForField) { this.value = value; this.accessFlagName = accessFlagName; this.validForClass = validForClass; this.validForMethod = validForMethod; this.validForField = validForField; } public boolean isSet(int accessFlags) { return (this.value & accessFlags) != 0; } public static AccessFlags[] getAccessFlagsForClass(int accessFlagValue) { int size = 0; for (AccessFlags accessFlag: allFlags) { if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) { size++; } } AccessFlags[] accessFlags = new AccessFlags[size]; int accessFlagsPosition = 0; for (AccessFlags accessFlag: allFlags) { if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) { accessFlags[accessFlagsPosition++] = accessFlag; } } return accessFlags; } private static String formatAccessFlags(AccessFlags[] accessFlags) { int size = 0; for (AccessFlags accessFlag: accessFlags) { size += accessFlag.toString().length() + 1; } StringBuilder sb = new StringBuilder(size); for (AccessFlags accessFlag: accessFlags) { sb.append(accessFlag.toString()); sb.append(" "); } if (accessFlags.length > 0) { sb.delete(sb.length() - 1, sb.length()); } return sb.toString(); } public static String formatAccessFlagsForClass(int accessFlagValue) { return formatAccessFlags(getAccessFlagsForClass(accessFlagValue)); } public static AccessFlags[] getAccessFlagsForMethod(int accessFlagValue) { int size = 0; for (AccessFlags accessFlag: allFlags) { if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) { size++; } } AccessFlags[] accessFlags = new AccessFlags[size]; int accessFlagsPosition = 0; for (AccessFlags accessFlag: allFlags) { if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) { accessFlags[accessFlagsPosition++] = accessFlag; } } return accessFlags; } public static String formatAccessFlagsForMethod(int accessFlagValue) { return formatAccessFlags(getAccessFlagsForMethod(accessFlagValue)); } public static AccessFlags[] getAccessFlagsForField(int accessFlagValue) { int size = 0; for (AccessFlags accessFlag: allFlags) { if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) { size++; } } AccessFlags[] accessFlags = new AccessFlags[size]; int accessFlagsPosition = 0; for (AccessFlags accessFlag: allFlags) { if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) { accessFlags[accessFlagsPosition++] = accessFlag; } } return accessFlags; } public static String formatAccessFlagsForField(int accessFlagValue) { return formatAccessFlags(getAccessFlagsForField(accessFlagValue)); } public static AccessFlags getAccessFlag(String accessFlag) { return accessFlagsByName.get(accessFlag); } public int getValue() { return value; } public String toString() { return accessFlagName; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/AnnotationVisibility.java000066400000000000000000000050701342202223400263530ustar00rootroot00000000000000/* * 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; import org.jf.util.ExceptionWithContext; public final class AnnotationVisibility { public static final int BUILD = 0; public static final int RUNTIME = 1; public static final int SYSTEM = 2; private static String[] NAMES = new String[] {"build", "runtime", "system"}; public static String getVisibility(int visibility) { if (visibility < 0 || visibility >= NAMES.length) { throw new ExceptionWithContext("Invalid annotation visibility %d", visibility); } return NAMES[visibility]; } public static int getVisibility(String visibility) { visibility = visibility.toLowerCase(); if (visibility.equals("build")) { return BUILD; } if (visibility.equals("runtime")) { return RUNTIME; } if (visibility.equals("system")) { return SYSTEM; } throw new ExceptionWithContext("Invalid annotation visibility: %s", visibility); } private AnnotationVisibility() {} } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/DebugItemType.java000066400000000000000000000044671342202223400247110ustar00rootroot00000000000000/* * 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; public final class DebugItemType { // The debug items that directly correspond with one of the dexlib2.iface.debug interfaces public static final int START_LOCAL = 0x03; public static final int END_LOCAL = 0x05; public static final int RESTART_LOCAL = 0x06; public static final int PROLOGUE_END = 0x07; public static final int EPILOGUE_BEGIN = 0x08; public static final int SET_SOURCE_FILE = 0x09; public static final int LINE_NUMBER = 0x0a; // Other items, which are typically handled internally public static final int END_SEQUENCE = 0x00; public static final int ADVANCE_PC = 0x01; public static final int ADVANCE_LINE = 0x02; public static final int START_LOCAL_EXTENDED = 0x04; private DebugItemType() {} } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java000066400000000000000000000507641342202223400250530ustar00rootroot00000000000000/* * 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; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.io.ByteStreams; import com.google.common.io.Files; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.DexBackedDexFile.NotADexFile; import org.jf.dexlib2.dexbacked.DexBackedOdexFile; import org.jf.dexlib2.dexbacked.OatFile; import org.jf.dexlib2.dexbacked.OatFile.NotAnOatFileException; import org.jf.dexlib2.dexbacked.OatFile.OatDexFile; import org.jf.dexlib2.dexbacked.OatFile.VdexProvider; import org.jf.dexlib2.dexbacked.ZipDexContainer; import org.jf.dexlib2.dexbacked.ZipDexContainer.NotAZipFileException; import org.jf.dexlib2.iface.DexFile; import org.jf.dexlib2.iface.MultiDexContainer; import org.jf.dexlib2.writer.pool.DexPool; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.*; import java.util.List; public final class DexFileFactory { @Nonnull public static DexBackedDexFile loadDexFile(@Nonnull String path, @Nullable Opcodes opcodes) throws IOException { return loadDexFile(new File(path), opcodes); } /** * Loads a dex/apk/odex/oat file. * * For oat files with multiple dex files, the first will be opened. For zip/apk files, the "classes.dex" entry * will be opened. * * @param file The file to open * @param opcodes The set of opcodes to use * @return A DexBackedDexFile for the given file * * @throws UnsupportedOatVersionException If file refers to an unsupported oat file * @throws DexFileNotFoundException If file does not exist, if file is a zip file but does not have a "classes.dex" * entry, or if file is an oat file that has no dex entries. * @throws UnsupportedFileTypeException If file is not a valid dex/zip/odex/oat file, or if the "classes.dex" entry * in a zip file is not a valid dex file */ @Nonnull public static DexBackedDexFile loadDexFile(@Nonnull File file, @Nullable Opcodes opcodes) throws IOException { if (!file.exists()) { throw new DexFileNotFoundException("%s does not exist", file.getName()); } try { ZipDexContainer container = new ZipDexContainer(file, opcodes); return new DexEntryFinder(file.getPath(), container).findEntry("classes.dex", true); } catch (NotAZipFileException ex) { // eat it and continue } InputStream inputStream = new BufferedInputStream(new FileInputStream(file)); try { try { return DexBackedDexFile.fromInputStream(opcodes, inputStream); } catch (DexBackedDexFile.NotADexFile ex) { // just eat it } try { return DexBackedOdexFile.fromInputStream(opcodes, inputStream); } catch (DexBackedOdexFile.NotAnOdexFile ex) { // just eat it } // Note: DexBackedDexFile.fromInputStream and DexBackedOdexFile.fromInputStream will reset inputStream // back to the same position, if they fails OatFile oatFile = null; try { oatFile = OatFile.fromInputStream(inputStream, new FilenameVdexProvider(file)); } catch (NotAnOatFileException ex) { // just eat it } if (oatFile != null) { if (oatFile.isSupportedVersion() == OatFile.UNSUPPORTED) { throw new UnsupportedOatVersionException(oatFile); } List oatDexFiles = oatFile.getDexFiles(); if (oatDexFiles.size() == 0) { throw new DexFileNotFoundException("Oat file %s contains no dex files", file.getName()); } return oatDexFiles.get(0); } } finally { inputStream.close(); } throw new UnsupportedFileTypeException("%s is not an apk, dex, odex or oat file.", file.getPath()); } /** * Loads a dex entry from a container format (zip/oat) * * This has two modes of operation, depending on the exactMatch parameter. When exactMatch is true, it will only * load an entry whose name exactly matches that provided by the dexEntry parameter. * * When exactMatch is false, then it will search for any entry that dexEntry is a path suffix of. "path suffix" * meaning all the path components in dexEntry must fully match the corresponding path components in the entry name, * but some path components at the beginning of entry name can be missing. * * For example, if an oat file contains a "/system/framework/framework.jar:classes2.dex" entry, then the following * will match (not an exhaustive list): * * "/system/framework/framework.jar:classes2.dex" * "system/framework/framework.jar:classes2.dex" * "framework/framework.jar:classes2.dex" * "framework.jar:classes2.dex" * "classes2.dex" * * Note that partial path components specifically don't match. So something like "work/framework.jar:classes2.dex" * would not match. * * If dexEntry contains an initial slash, it will be ignored for purposes of this suffix match -- but not when * performing an exact match. * * If multiple entries match the given dexEntry, a MultipleMatchingDexEntriesException will be thrown * * @param file The container file. This must be either a zip (apk) file or an oat file. * @param dexEntry The name of the entry to load. This can either be the exact entry name, if exactMatch is true, * or it can be a path suffix. * @param exactMatch If true, dexE * @param opcodes The set of opcodes to use * @return A DexBackedDexFile for the given entry * * @throws UnsupportedOatVersionException If file refers to an unsupported oat file * @throws DexFileNotFoundException If the file does not exist, or if no matching entry could be found * @throws UnsupportedFileTypeException If file is not a valid zip/oat file, or if the matching entry is not a * valid dex file * @throws MultipleMatchingDexEntriesException If multiple entries match the given dexEntry */ public static DexBackedDexFile loadDexEntry(@Nonnull File file, @Nonnull String dexEntry, boolean exactMatch, @Nullable Opcodes opcodes) throws IOException { if (!file.exists()) { throw new DexFileNotFoundException("Container file %s does not exist", file.getName()); } try { ZipDexContainer container = new ZipDexContainer(file, opcodes); return new DexEntryFinder(file.getPath(), container).findEntry(dexEntry, exactMatch); } catch (NotAZipFileException ex) { // eat it and continue } InputStream inputStream = new BufferedInputStream(new FileInputStream(file)); try { OatFile oatFile = null; try { oatFile = OatFile.fromInputStream(inputStream, new FilenameVdexProvider(file)); } catch (NotAnOatFileException ex) { // just eat it } if (oatFile != null) { if (oatFile.isSupportedVersion() == OatFile.UNSUPPORTED) { throw new UnsupportedOatVersionException(oatFile); } List oatDexFiles = oatFile.getDexFiles(); if (oatDexFiles.size() == 0) { throw new DexFileNotFoundException("Oat file %s contains no dex files", file.getName()); } return new DexEntryFinder(file.getPath(), oatFile).findEntry(dexEntry, exactMatch); } } finally { inputStream.close(); } throw new UnsupportedFileTypeException("%s is not an apk or oat file.", file.getPath()); } /** * Loads a file containing 1 or more dex files * * If the given file is a dex or odex file, it will return a MultiDexContainer containing that single entry. * Otherwise, for an oat or zip file, it will return an OatFile or ZipDexContainer respectively. * * @param file The file to open * @param opcodes The set of opcodes to use * @return A MultiDexContainer * @throws DexFileNotFoundException If the given file does not exist * @throws UnsupportedFileTypeException If the given file is not a valid dex/zip/odex/oat file */ public static MultiDexContainer loadDexContainer( @Nonnull File file, @Nullable final Opcodes opcodes) throws IOException { if (!file.exists()) { throw new DexFileNotFoundException("%s does not exist", file.getName()); } ZipDexContainer zipDexContainer = new ZipDexContainer(file, opcodes); if (zipDexContainer.isZipFile()) { return zipDexContainer; } InputStream inputStream = new BufferedInputStream(new FileInputStream(file)); try { try { DexBackedDexFile dexFile = DexBackedDexFile.fromInputStream(opcodes, inputStream); return new SingletonMultiDexContainer(file.getPath(), dexFile); } catch (DexBackedDexFile.NotADexFile ex) { // just eat it } try { DexBackedOdexFile odexFile = DexBackedOdexFile.fromInputStream(opcodes, inputStream); return new SingletonMultiDexContainer(file.getPath(), odexFile); } catch (DexBackedOdexFile.NotAnOdexFile ex) { // just eat it } // Note: DexBackedDexFile.fromInputStream and DexBackedOdexFile.fromInputStream will reset inputStream // back to the same position, if they fails OatFile oatFile = null; try { oatFile = OatFile.fromInputStream(inputStream, new FilenameVdexProvider(file)); } catch (NotAnOatFileException ex) { // just eat it } if (oatFile != null) { // TODO: we should support loading earlier oat files, just not deodexing them if (oatFile.isSupportedVersion() == OatFile.UNSUPPORTED) { throw new UnsupportedOatVersionException(oatFile); } return oatFile; } } finally { inputStream.close(); } throw new UnsupportedFileTypeException("%s is not an apk, dex, odex or oat file.", file.getPath()); } /** * Writes a DexFile out to disk * * @param path The path to write the dex file to * @param dexFile a DexFile to write */ public static void writeDexFile(@Nonnull String path, @Nonnull DexFile dexFile) throws IOException { DexPool.writeTo(path, dexFile); } private DexFileFactory() {} public static class DexFileNotFoundException extends ExceptionWithContext { public DexFileNotFoundException(@Nullable String message, Object... formatArgs) { super(message, formatArgs); } } public static class UnsupportedOatVersionException extends ExceptionWithContext { @Nonnull public final OatFile oatFile; public UnsupportedOatVersionException(@Nonnull OatFile oatFile) { super("Unsupported oat version: %d", oatFile.getOatVersion()); this.oatFile = oatFile; } } public static class MultipleMatchingDexEntriesException extends ExceptionWithContext { public MultipleMatchingDexEntriesException(@Nonnull String message, Object... formatArgs) { super(String.format(message, formatArgs)); } } public static class UnsupportedFileTypeException extends ExceptionWithContext { public UnsupportedFileTypeException(@Nonnull String message, Object... formatArgs) { super(String.format(message, formatArgs)); } } /** * Matches two entries fully, ignoring any initial slash, if any */ private static boolean fullEntryMatch(@Nonnull String entry, @Nonnull String targetEntry) { if (entry.equals(targetEntry)) { return true; } if (entry.charAt(0) == '/') { entry = entry.substring(1); } if (targetEntry.charAt(0) == '/') { targetEntry = targetEntry.substring(1); } return entry.equals(targetEntry); } /** * Performs a partial match against entry and targetEntry. * * This is considered a partial match if targetEntry is a suffix of entry, and if the suffix starts * on a path "part" (ignoring the initial separator, if any). Both '/' and ':' are considered separators for this. * * So entry="/blah/blah/something.dex" and targetEntry="lah/something.dex" shouldn't match, but * both targetEntry="blah/something.dex" and "/blah/something.dex" should match. */ private static boolean partialEntryMatch(String entry, String targetEntry) { if (entry.equals(targetEntry)) { return true; } if (!entry.endsWith(targetEntry)) { return false; } // Make sure the first matching part is a full entry. We don't want to match "/blah/blah/something.dex" with // "lah/something.dex", but both "/blah/something.dex" and "blah/something.dex" should match char precedingChar = entry.charAt(entry.length() - targetEntry.length() - 1); char firstTargetChar = targetEntry.charAt(0); // This is a device path, so we should always use the linux separator '/', rather than the current platform's // separator return firstTargetChar == ':' || firstTargetChar == '/' || precedingChar == ':' || precedingChar == '/'; } protected static class DexEntryFinder { private final String filename; private final MultiDexContainer dexContainer; public DexEntryFinder(@Nonnull String filename, @Nonnull MultiDexContainer dexContainer) { this.filename = filename; this.dexContainer = dexContainer; } @Nonnull public DexBackedDexFile findEntry(@Nonnull String targetEntry, boolean exactMatch) throws IOException { if (exactMatch) { try { DexBackedDexFile dexFile = dexContainer.getEntry(targetEntry); if (dexFile == null) { throw new DexFileNotFoundException("Could not find entry %s in %s.", targetEntry, filename); } return dexFile; } catch (NotADexFile ex) { throw new UnsupportedFileTypeException("Entry %s in %s is not a dex file", targetEntry, filename); } } // find all full and partial matches List fullMatches = Lists.newArrayList(); List fullEntries = Lists.newArrayList(); List partialMatches = Lists.newArrayList(); List partialEntries = Lists.newArrayList(); for (String entry: dexContainer.getDexEntryNames()) { if (fullEntryMatch(entry, targetEntry)) { // We want to grab all full matches, regardless of whether they're actually a dex file. fullMatches.add(entry); fullEntries.add(dexContainer.getEntry(entry)); } else if (partialEntryMatch(entry, targetEntry)) { partialMatches.add(entry); partialEntries.add(dexContainer.getEntry(entry)); } } // full matches always take priority if (fullEntries.size() == 1) { try { DexBackedDexFile dexFile = fullEntries.get(0); assert dexFile != null; return dexFile; } catch (NotADexFile ex) { throw new UnsupportedFileTypeException("Entry %s in %s is not a dex file", fullMatches.get(0), filename); } } if (fullEntries.size() > 1) { // This should be quite rare. This would only happen if an oat file has two entries that differ // only by an initial path separator. e.g. "/blah/blah.dex" and "blah/blah.dex" throw new MultipleMatchingDexEntriesException(String.format( "Multiple entries in %s match %s: %s", filename, targetEntry, Joiner.on(", ").join(fullMatches))); } if (partialEntries.size() == 0) { throw new DexFileNotFoundException("Could not find a dex entry in %s matching %s", filename, targetEntry); } if (partialEntries.size() > 1) { throw new MultipleMatchingDexEntriesException(String.format( "Multiple dex entries in %s match %s: %s", filename, targetEntry, Joiner.on(", ").join(partialMatches))); } return partialEntries.get(0); } } private static class SingletonMultiDexContainer implements MultiDexContainer { private final String entryName; private final DexBackedDexFile dexFile; public SingletonMultiDexContainer(@Nonnull String entryName, @Nonnull DexBackedDexFile dexFile) { this.entryName = entryName; this.dexFile = dexFile; } @Nonnull @Override public List getDexEntryNames() throws IOException { return ImmutableList.of(entryName); } @Nullable @Override public DexBackedDexFile getEntry(@Nonnull String entryName) throws IOException { if (entryName.equals(this.entryName)) { return dexFile; } return null; } } public static class FilenameVdexProvider implements VdexProvider { private final File vdexFile; @Nullable private byte[] buf = null; private boolean loadedVdex = false; public FilenameVdexProvider(File oatFile) { File oatParent = oatFile.getAbsoluteFile().getParentFile(); String baseName = Files.getNameWithoutExtension(oatFile.getAbsolutePath()); vdexFile = new File(oatParent, baseName + ".vdex"); } @Nullable @Override public byte[] getVdex() { if (!loadedVdex) { if (vdexFile.exists()) { try { buf = ByteStreams.toByteArray(new FileInputStream(vdexFile)); } catch (FileNotFoundException e) { buf = null; } catch (IOException ex) { throw new RuntimeException(ex); } } loadedVdex = true; } return buf; } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/Format.java000066400000000000000000000050761342202223400234270ustar00rootroot00000000000000/* * 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; public enum Format { Format10t(2), Format10x(2), Format11n(2), Format11x(2), Format12x(2), Format20bc(4), Format20t(4), Format21c(4), Format21ih(4), Format21lh(4), Format21s(4), Format21t(4), Format22b(4), Format22c(4), Format22cs(4), Format22s(4), Format22t(4), Format22x(4), Format23x(4), Format30t(6), Format31c(6), Format31i(6), Format31t(6), Format32x(6), Format35c(6), Format35mi(6), Format35ms(6), Format3rc(6), Format3rmi(6), Format3rms(6), Format45cc(8), Format4rcc(8), Format51l(10), ArrayPayload(-1, true), PackedSwitchPayload(-1, true), SparseSwitchPayload(-1, true), UnresolvedOdexInstruction(-1); public final int size; public final boolean isPayloadFormat; private Format(int size) { this(size, false); } private Format(int size, boolean isPayloadFormat) { this.size = size; this.isPayloadFormat = isPayloadFormat; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/MethodHandleType.java000066400000000000000000000076751342202223400254040ustar00rootroot00000000000000/* * Copyright 2018, 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; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; public class MethodHandleType { public static final int STATIC_PUT = 0; public static final int STATIC_GET = 1; public static final int INSTANCE_PUT = 2; public static final int INSTANCE_GET = 3; public static final int INVOKE_STATIC = 4; public static final int INVOKE_INSTANCE = 5; public static final int INVOKE_CONSTRUCTOR = 6; public static final int INVOKE_DIRECT = 7; public static final int INVOKE_INTERFACE = 8; private static final BiMap methodHandleTypeNames = new ImmutableBiMap.Builder() .put(STATIC_PUT, "static-put") .put(STATIC_GET, "static-get") .put(INSTANCE_PUT, "instance-put") .put(INSTANCE_GET, "instance-get") .put(INVOKE_STATIC, "invoke-static") .put(INVOKE_INSTANCE, "invoke-instance") .put(INVOKE_CONSTRUCTOR, "invoke-constructor") .put(INVOKE_DIRECT, "invoke-direct") .put(INVOKE_INTERFACE, "invoke-interface") .build(); @Nonnull public static String toString(int methodHandleType) { String val = methodHandleTypeNames.get(methodHandleType); if (val == null) { throw new InvalidMethodHandleTypeException(methodHandleType); } return val; } public static int getMethodHandleType(String methodHandleType) { Integer ret = methodHandleTypeNames.inverse().get(methodHandleType); if (ret == null) { throw new ExceptionWithContext("Invalid method handle type: %s", methodHandleType); } return ret; } public static class InvalidMethodHandleTypeException extends ExceptionWithContext { private final int methodHandleType; public InvalidMethodHandleTypeException(int methodHandleType) { super("Invalid method handle type: %d", methodHandleType); this.methodHandleType = methodHandleType; } public InvalidMethodHandleTypeException(int methodHandleType, String message, Object... formatArgs) { super(message, formatArgs); this.methodHandleType = methodHandleType; } public int getMethodHandleType() { return methodHandleType; } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java000066400000000000000000001330351342202223400234050ustar00rootroot00000000000000/* * 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; import com.google.common.collect.ImmutableRangeMap; import com.google.common.collect.Lists; import com.google.common.collect.Range; import com.google.common.collect.RangeMap; import javax.annotation.Nonnull; import java.util.List; public enum Opcode { NOP(0x00, "nop", ReferenceType.NONE, Format.Format10x, Opcode.CAN_CONTINUE), MOVE(0x01, "move", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MOVE_FROM16(0x02, "move/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MOVE_16(0x03, "move/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MOVE_WIDE(0x04, "move-wide", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), MOVE_WIDE_FROM16(0x05, "move-wide/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), MOVE_WIDE_16(0x06, "move-wide/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), MOVE_OBJECT(0x07, "move-object", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MOVE_OBJECT_FROM16(0x08, "move-object/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MOVE_OBJECT_16(0x09, "move-object/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MOVE_RESULT(0x0a, "move-result", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MOVE_RESULT_WIDE(0x0b, "move-result-wide", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), MOVE_RESULT_OBJECT(0x0c, "move-result-object", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MOVE_EXCEPTION(0x0d, "move-exception", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), RETURN_VOID(0x0e, "return-void", ReferenceType.NONE, Format.Format10x), RETURN(0x0f, "return", ReferenceType.NONE, Format.Format11x), RETURN_WIDE(0x10, "return-wide", ReferenceType.NONE, Format.Format11x), RETURN_OBJECT(0x11, "return-object", ReferenceType.NONE, Format.Format11x), CONST_4(0x12, "const/4", ReferenceType.NONE, Format.Format11n, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST_16(0x13, "const/16", ReferenceType.NONE, Format.Format21s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST(0x14, "const", ReferenceType.NONE, Format.Format31i, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST_HIGH16(0x15, "const/high16", ReferenceType.NONE, Format.Format21ih, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST_WIDE_16(0x16, "const-wide/16", ReferenceType.NONE, Format.Format21s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), CONST_WIDE_32(0x17, "const-wide/32", ReferenceType.NONE, Format.Format31i, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), CONST_WIDE(0x18, "const-wide", ReferenceType.NONE, Format.Format51l, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), CONST_WIDE_HIGH16(0x19, "const-wide/high16", ReferenceType.NONE, Format.Format21lh, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), CONST_STRING(0x1a, "const-string", ReferenceType.STRING, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST_STRING_JUMBO(0x1b, "const-string/jumbo", ReferenceType.STRING, Format.Format31c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST_CLASS(0x1c, "const-class", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MONITOR_ENTER(0x1d, "monitor-enter", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), MONITOR_EXIT(0x1e, "monitor-exit", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), CHECK_CAST(0x1f, "check-cast", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), INSTANCE_OF(0x20, "instance-of", ReferenceType.TYPE, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), ARRAY_LENGTH(0x21, "array-length", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NEW_INSTANCE(0x22, "new-instance", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NEW_ARRAY(0x23, "new-array", ReferenceType.TYPE, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), FILLED_NEW_ARRAY(0x24, "filled-new-array", ReferenceType.TYPE, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), FILLED_NEW_ARRAY_RANGE(0x25, "filled-new-array/range", ReferenceType.TYPE, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), FILL_ARRAY_DATA(0x26, "fill-array-data", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE), THROW(0x27, "throw", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW), GOTO(0x28, "goto", ReferenceType.NONE, Format.Format10t), GOTO_16(0x29, "goto/16", ReferenceType.NONE, Format.Format20t), GOTO_32(0x2a, "goto/32", ReferenceType.NONE, Format.Format30t), PACKED_SWITCH(0x2b, "packed-switch", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE), SPARSE_SWITCH(0x2c, "sparse-switch", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE), CMPL_FLOAT(0x2d, "cmpl-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CMPG_FLOAT(0x2e, "cmpg-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CMPL_DOUBLE(0x2f, "cmpl-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CMPG_DOUBLE(0x30, "cmpg-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CMP_LONG(0x31, "cmp-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IF_EQ(0x32, "if-eq", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE), IF_NE(0x33, "if-ne", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE), IF_LT(0x34, "if-lt", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE), IF_GE(0x35, "if-ge", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE), IF_GT(0x36, "if-gt", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE), IF_LE(0x37, "if-le", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE), IF_EQZ(0x38, "if-eqz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE), IF_NEZ(0x39, "if-nez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE), IF_LTZ(0x3a, "if-ltz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE), IF_GEZ(0x3b, "if-gez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE), IF_GTZ(0x3c, "if-gtz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE), IF_LEZ(0x3d, "if-lez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE), AGET(0x44, "aget", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AGET_WIDE(0x45, "aget-wide", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), AGET_OBJECT(0x46, "aget-object", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AGET_BOOLEAN(0x47, "aget-boolean", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AGET_BYTE(0x48, "aget-byte", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AGET_CHAR(0x49, "aget-char", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AGET_SHORT(0x4a, "aget-short", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), APUT(0x4b, "aput", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_WIDE(0x4c, "aput-wide", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_OBJECT(0x4d, "aput-object", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_BOOLEAN(0x4e, "aput-boolean", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_BYTE(0x4f, "aput-byte", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_CHAR(0x50, "aput-char", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_SHORT(0x51, "aput-short", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IGET(0x52, "iget", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_WIDE(0x53, "iget-wide", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), IGET_OBJECT(0x54, "iget-object", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_BOOLEAN(0x55, "iget-boolean", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_BYTE(0x56, "iget-byte", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_CHAR(0x57, "iget-char", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_SHORT(0x58, "iget-short", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IPUT(0x59, "iput", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_WIDE(0x5a, "iput-wide", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_OBJECT(0x5b, "iput-object", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_BOOLEAN(0x5c, "iput-boolean", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_BYTE(0x5d, "iput-byte", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_CHAR(0x5e, "iput-char", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_SHORT(0x5f, "iput-short", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SGET(0x60, "sget", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SGET_WIDE(0x61, "sget-wide", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SGET_OBJECT(0x62, "sget-object", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SGET_BOOLEAN(0x63, "sget-boolean", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SGET_BYTE(0x64, "sget-byte", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SGET_CHAR(0x65, "sget-char", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SGET_SHORT(0x66, "sget-short", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SPUT(0x67, "sput", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), SPUT_WIDE(0x68, "sput-wide", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), SPUT_OBJECT(0x69, "sput-object", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), SPUT_BOOLEAN(0x6a, "sput-boolean", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), SPUT_BYTE(0x6b, "sput-byte", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), SPUT_CHAR(0x6c, "sput-char", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), SPUT_SHORT(0x6d, "sput-short", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), INVOKE_VIRTUAL(0x6e, "invoke-virtual", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER(0x6f, "invoke-super", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_DIRECT(0x70, "invoke-direct", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE), INVOKE_STATIC(0x71, "invoke-static", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_INTERFACE(0x72, "invoke-interface", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_VIRTUAL_RANGE(0x74, "invoke-virtual/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER_RANGE(0x75, "invoke-super/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_DIRECT_RANGE(0x76, "invoke-direct/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE), INVOKE_STATIC_RANGE(0x77, "invoke-static/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_INTERFACE_RANGE(0x78, "invoke-interface/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), NEG_INT(0x7b, "neg-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NOT_INT(0x7c, "not-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NEG_LONG(0x7d, "neg-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), NOT_LONG(0x7e, "not-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), NEG_FLOAT(0x7f, "neg-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NEG_DOUBLE(0x80, "neg-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), INT_TO_LONG(0x81, "int-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), INT_TO_FLOAT(0x82, "int-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), INT_TO_DOUBLE(0x83, "int-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), LONG_TO_INT(0x84, "long-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), LONG_TO_FLOAT(0x85, "long-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), LONG_TO_DOUBLE(0x86, "long-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), FLOAT_TO_INT(0x87, "float-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), FLOAT_TO_LONG(0x88, "float-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), FLOAT_TO_DOUBLE(0x89, "float-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), DOUBLE_TO_INT(0x8a, "double-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), DOUBLE_TO_LONG(0x8b, "double-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), DOUBLE_TO_FLOAT(0x8c, "double-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), INT_TO_BYTE(0x8d, "int-to-byte", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), INT_TO_CHAR(0x8e, "int-to-char", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), INT_TO_SHORT(0x8f, "int-to-short", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), ADD_INT(0x90, "add-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SUB_INT(0x91, "sub-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MUL_INT(0x92, "mul-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), DIV_INT(0x93, "div-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), REM_INT(0x94, "rem-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AND_INT(0x95, "and-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), OR_INT(0x96, "or-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), XOR_INT(0x97, "xor-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SHL_INT(0x98, "shl-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SHR_INT(0x99, "shr-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), USHR_INT(0x9a, "ushr-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), ADD_LONG(0x9b, "add-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SUB_LONG(0x9c, "sub-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), MUL_LONG(0x9d, "mul-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), DIV_LONG(0x9e, "div-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), REM_LONG(0x9f, "rem-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), AND_LONG(0xa0, "and-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), OR_LONG(0xa1, "or-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), XOR_LONG(0xa2, "xor-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SHL_LONG(0xa3, "shl-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SHR_LONG(0xa4, "shr-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), USHR_LONG(0xa5, "ushr-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), ADD_FLOAT(0xa6, "add-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SUB_FLOAT(0xa7, "sub-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MUL_FLOAT(0xa8, "mul-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), DIV_FLOAT(0xa9, "div-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), REM_FLOAT(0xaa, "rem-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), ADD_DOUBLE(0xab, "add-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SUB_DOUBLE(0xac, "sub-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), MUL_DOUBLE(0xad, "mul-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), DIV_DOUBLE(0xae, "div-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), REM_DOUBLE(0xaf, "rem-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), ADD_INT_2ADDR(0xb0, "add-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SUB_INT_2ADDR(0xb1, "sub-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MUL_INT_2ADDR(0xb2, "mul-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), DIV_INT_2ADDR(0xb3, "div-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), REM_INT_2ADDR(0xb4, "rem-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AND_INT_2ADDR(0xb5, "and-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), OR_INT_2ADDR(0xb6, "or-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), XOR_INT_2ADDR(0xb7, "xor-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SHL_INT_2ADDR(0xb8, "shl-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SHR_INT_2ADDR(0xb9, "shr-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), USHR_INT_2ADDR(0xba, "ushr-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), ADD_LONG_2ADDR(0xbb, "add-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SUB_LONG_2ADDR(0xbc, "sub-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), MUL_LONG_2ADDR(0xbd, "mul-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), DIV_LONG_2ADDR(0xbe, "div-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), REM_LONG_2ADDR(0xbf, "rem-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), AND_LONG_2ADDR(0xc0, "and-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), OR_LONG_2ADDR(0xc1, "or-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), XOR_LONG_2ADDR(0xc2, "xor-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SHL_LONG_2ADDR(0xc3, "shl-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SHR_LONG_2ADDR(0xc4, "shr-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), USHR_LONG_2ADDR(0xc5, "ushr-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), ADD_FLOAT_2ADDR(0xc6, "add-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SUB_FLOAT_2ADDR(0xc7, "sub-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MUL_FLOAT_2ADDR(0xc8, "mul-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), DIV_FLOAT_2ADDR(0xc9, "div-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), REM_FLOAT_2ADDR(0xca, "rem-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), ADD_DOUBLE_2ADDR(0xcb, "add-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SUB_DOUBLE_2ADDR(0xcc, "sub-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), MUL_DOUBLE_2ADDR(0xcd, "mul-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), DIV_DOUBLE_2ADDR(0xce, "div-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), REM_DOUBLE_2ADDR(0xcf, "rem-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), ADD_INT_LIT16(0xd0, "add-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), RSUB_INT(0xd1, "rsub-int", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MUL_INT_LIT16(0xd2, "mul-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), DIV_INT_LIT16(0xd3, "div-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), REM_INT_LIT16(0xd4, "rem-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AND_INT_LIT16(0xd5, "and-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), OR_INT_LIT16(0xd6, "or-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), XOR_INT_LIT16(0xd7, "xor-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), ADD_INT_LIT8(0xd8, "add-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), RSUB_INT_LIT8(0xd9, "rsub-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), MUL_INT_LIT8(0xda, "mul-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), DIV_INT_LIT8(0xdb, "div-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), REM_INT_LIT8(0xdc, "rem-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), AND_INT_LIT8(0xdd, "and-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), OR_INT_LIT8(0xde, "or-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), XOR_INT_LIT8(0xdf, "xor-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SHL_INT_LIT8(0xe0, "shl-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SHR_INT_LIT8(0xe1, "shr-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), USHR_INT_LIT8(0xe2, "ushr-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_VOLATILE(firstApi(0xe3, 9), "iget-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IPUT_VOLATILE(firstApi(0xe4, 9), "iput-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SGET_VOLATILE(firstApi(0xe5, 9), "sget-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SPUT_VOLATILE(firstApi(0xe6, 9), "sput-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), IGET_OBJECT_VOLATILE(firstApi(0xe7, 9), "iget-object-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_WIDE_VOLATILE(firstApi(0xe8, 9), "iget-wide-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), IPUT_WIDE_VOLATILE(firstApi(0xe9, 9), "iput-wide-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SGET_WIDE_VOLATILE(firstApi(0xea, 9), "sget-wide-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SPUT_WIDE_VOLATILE(firstApi(0xeb, 9), "sput-wide-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), THROW_VERIFICATION_ERROR(firstApi(0xed, 5), "throw-verification-error", ReferenceType.NONE, Format.Format20bc, Opcode.ODEX_ONLY | Opcode.CAN_THROW), EXECUTE_INLINE(allApis(0xee), "execute-inline", ReferenceType.NONE, Format.Format35mi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), EXECUTE_INLINE_RANGE(firstApi(0xef, 8), "execute-inline/range", ReferenceType.NONE, Format.Format3rmi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_DIRECT_EMPTY(lastApi(0xf0, 13), "invoke-direct-empty", ReferenceType.METHOD, Format.Format35c, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE), INVOKE_OBJECT_INIT_RANGE(firstApi(0xf0, 14), "invoke-object-init/range", ReferenceType.METHOD, Format.Format3rc, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE), RETURN_VOID_BARRIER(combine(firstApi(0xf1, 11), lastArtVersion(0x73, 59)), "return-void-barrier", ReferenceType.NONE, Format.Format10x, Opcode.ODEX_ONLY), RETURN_VOID_NO_BARRIER(firstArtVersion(0x73, 60), "return-void-no-barrier", ReferenceType.NONE, Format.Format10x, Opcode.ODEX_ONLY), IGET_QUICK(combine(allApis(0xf2), allArtVersions(0xe3)), "iget-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_WIDE_QUICK(combine(allApis(0xf3), allArtVersions(0xe4)), "iget-wide-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), IGET_OBJECT_QUICK(combine(allApis(0xf4), allArtVersions(0xe5)), "iget-object-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IPUT_QUICK(combine(allApis(0xf5), allArtVersions(0xe6)), "iput-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_WIDE_QUICK(combine(allApis(0xf6), allArtVersions(0xe7)), "iput-wide-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_OBJECT_QUICK(combine(allApis(0xf7), allArtVersions(0xe8)), "iput-object-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_BOOLEAN_QUICK(allArtVersions(0xeb), "iput-boolean-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.QUICK_FIELD_ACCESSOR), IPUT_BYTE_QUICK(allArtVersions(0xec), "iput-byte-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.QUICK_FIELD_ACCESSOR), IPUT_CHAR_QUICK(allArtVersions(0xed), "iput-char-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.QUICK_FIELD_ACCESSOR), IPUT_SHORT_QUICK(allArtVersions(0xee), "iput-short-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.QUICK_FIELD_ACCESSOR), IGET_BOOLEAN_QUICK(allArtVersions(0xef), "iget-boolean-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_BYTE_QUICK(allArtVersions(0xf0), "iget-byte-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_CHAR_QUICK(allArtVersions(0xf1), "iget-char-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_SHORT_QUICK(allArtVersions(0xf2), "iget-short-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), INVOKE_VIRTUAL_QUICK(combine(allApis(0xf8), allArtVersions(0xe9)), "invoke-virtual-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_VIRTUAL_QUICK_RANGE(combine(allApis(0xf9), allArtVersions(0xea)), "invoke-virtual-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER_QUICK(lastApi(0xfa, 25), "invoke-super-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER_QUICK_RANGE(lastApi(0xfb, 25), "invoke-super-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), IPUT_OBJECT_VOLATILE(firstApi(0xfc, 9), "iput-object-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SGET_OBJECT_VOLATILE(firstApi(0xfd, 9), "sget-object-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR), SPUT_OBJECT_VOLATILE(betweenApi(0xfe, 9, 19), "sput-object-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR), PACKED_SWITCH_PAYLOAD(0x100, "packed-switch-payload", ReferenceType.NONE, Format.PackedSwitchPayload, 0), SPARSE_SWITCH_PAYLOAD(0x200, "sparse-switch-payload", ReferenceType.NONE, Format.SparseSwitchPayload, 0), ARRAY_PAYLOAD(0x300, "array-payload", ReferenceType.NONE, Format.ArrayPayload, 0), INVOKE_POLYMORPHIC(firstArtVersion(0xfa, 87), "invoke-polymorphic", ReferenceType.METHOD, ReferenceType.METHOD_PROTO, Format.Format45cc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_POLYMORPHIC_RANGE(firstArtVersion(0xfb, 87), "invoke-polymorphic/range", ReferenceType.METHOD, ReferenceType.METHOD_PROTO, Format.Format4rcc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_CUSTOM(firstArtVersion(0xfc, 111), "invoke-custom", ReferenceType.CALL_SITE, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_CUSTOM_RANGE(firstArtVersion(0xfd, 111), "invoke-custom/range", ReferenceType.CALL_SITE, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), CONST_METHOD_HANDLE(firstArtVersion(0xfe, 134), "const-method-handle", ReferenceType.METHOD_HANDLE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST_METHOD_TYPE(firstArtVersion(0xff, 134), "const-method-type", ReferenceType.METHOD_PROTO, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER); //if the instruction can throw an exception public static final int CAN_THROW = 0x1; //if the instruction is an odex only instruction public static final int ODEX_ONLY = 0x2; //if execution can continue to the next instruction public static final int CAN_CONTINUE = 0x4; //if the instruction sets the "hidden" result register public static final int SETS_RESULT = 0x8; //if the instruction sets the value of it's first register public static final int SETS_REGISTER = 0x10; //if the instruction sets the value of it's first register to a wide type public static final int SETS_WIDE_REGISTER = 0x20; //if the instruction is an iget-quick/iput-quick instruction public static final int QUICK_FIELD_ACCESSOR = 0x40; //if the instruction is a *get-volatile/*put-volatile instruction public static final int VOLATILE_FIELD_ACCESSOR = 0x80; //if the instruction is a static sget-*/sput-*instruction public static final int STATIC_FIELD_ACCESSOR = 0x100; //if the instruction is a jumbo instruction public static final int JUMBO_OPCODE = 0x200; //if the instruction can initialize an uninitialized object reference public static final int CAN_INITIALIZE_REFERENCE = 0x400; private static final int ALL_APIS = 0xFFFF0000; private static int minApi(int api) { return 0xFFFF0000 | (api & 0xFFFF); } private static int maxApi(int api) { return api << 16; } // values and minApis provide a mapping of api -> bytecode value. // the apis in minApis are guaranteed to be public final RangeMap apiToValueMap; public final RangeMap artVersionToValueMap; public final String name; public final int referenceType; public final Format format; public final int flags; public final int referenceType2; Opcode(int opcodeValue, String opcodeName, int referenceType, Format format) { this(opcodeValue, opcodeName, referenceType, format, 0); } Opcode(int opcodeValue, String opcodeName, int referenceType, Format format, int flags) { this(allVersions(opcodeValue), opcodeName, referenceType, format, flags); } Opcode(List versionConstraints, String opcodeName, int referenceType, Format format, int flags) { this(versionConstraints, opcodeName, referenceType, -1, format, flags); } Opcode(List versionConstraints, String opcodeName, int referenceType, int referenceType2, Format format, int flags) { ImmutableRangeMap.Builder apiToValueBuilder = ImmutableRangeMap.builder(); ImmutableRangeMap.Builder artVersionToValueBuilder = ImmutableRangeMap.builder(); for (VersionConstraint versionConstraint : versionConstraints) { if (!versionConstraint.apiRange.isEmpty()) { apiToValueBuilder.put(versionConstraint.apiRange, (short)versionConstraint.opcodeValue); } if (!versionConstraint.artVersionRange.isEmpty()) { artVersionToValueBuilder.put(versionConstraint.artVersionRange, (short)versionConstraint.opcodeValue); } } this.apiToValueMap = apiToValueBuilder.build(); this.artVersionToValueMap = artVersionToValueBuilder.build(); this.name = opcodeName; this.referenceType = referenceType; this.referenceType2 = referenceType2; this.format = format; this.flags = flags; } private static List firstApi(int opcodeValue, int api) { return Lists.newArrayList(new VersionConstraint(Range.atLeast(api), Range.openClosed(0, 0), opcodeValue)); } private static List lastApi(int opcodeValue, int api) { return Lists.newArrayList(new VersionConstraint(Range.atMost(api), Range.openClosed(0, 0), opcodeValue)); } private static List betweenApi(int opcodeValue, int minApi, int maxApi) { return Lists.newArrayList(new VersionConstraint(Range.closed(minApi, maxApi), Range.openClosed(0, 0), opcodeValue)); } private static List firstArtVersion(int opcodeValue, int artVersion) { return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.atLeast(artVersion), opcodeValue)); } private static List lastArtVersion(int opcodeValue, int artVersion) { return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.atMost(artVersion), opcodeValue)); } private static List allVersions(int opcodeValue) { return Lists.newArrayList(new VersionConstraint(Range.all(), Range.all(), opcodeValue)); } private static List allApis(int opcodeValue) { return Lists.newArrayList(new VersionConstraint(Range.all(), Range.openClosed(0, 0), opcodeValue)); } private static List allArtVersions(int opcodeValue) { return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.all(), opcodeValue)); } @SuppressWarnings("unchecked") private static List combine(List... versionConstraints) { List combinedList = Lists.newArrayList(); for (List versionConstraintList: versionConstraints) { combinedList.addAll(versionConstraintList); } return combinedList; } public final boolean canThrow() { return (flags & CAN_THROW) != 0; } public final boolean odexOnly() { return (flags & ODEX_ONLY) != 0; } public final boolean canContinue() { return (flags & CAN_CONTINUE) != 0; } public final boolean setsResult() { return (flags & SETS_RESULT) != 0; } public final boolean setsRegister() { return (flags & SETS_REGISTER) != 0; } public final boolean setsWideRegister() { return (flags & SETS_WIDE_REGISTER) != 0; } public final boolean isQuickFieldaccessor() { return (flags & QUICK_FIELD_ACCESSOR) != 0; } public final boolean isVolatileFieldAccessor() { return (flags & VOLATILE_FIELD_ACCESSOR) != 0; } public final boolean isStaticFieldAccessor() { return (flags & STATIC_FIELD_ACCESSOR) != 0; } public final boolean isJumboOpcode() { return (flags & JUMBO_OPCODE) != 0; } public final boolean canInitializeReference() { return (flags & CAN_INITIALIZE_REFERENCE) != 0; } private static class VersionConstraint { @Nonnull public final Range apiRange; @Nonnull public final Range artVersionRange; public final int opcodeValue; public VersionConstraint(@Nonnull Range apiRange, @Nonnull Range artVersionRange, int opcodeValue) { this.apiRange = apiRange; this.artVersionRange = artVersionRange; this.opcodeValue = opcodeValue; } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java000066400000000000000000000123601342202223400235650ustar00rootroot00000000000000/* * Copyright 2013, 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; import com.google.common.collect.Maps; import com.google.common.collect.RangeMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.EnumMap; import java.util.HashMap; import static org.jf.dexlib2.VersionMap.NO_VERSION; import static org.jf.dexlib2.VersionMap.mapApiToArtVersion; import static org.jf.dexlib2.VersionMap.mapArtVersionToApi; public class Opcodes { /** * Either the api level for dalvik opcodes, or the art version for art opcodes */ public final int api; public final int artVersion; @Nonnull private final Opcode[] opcodesByValue = new Opcode[256]; @Nonnull private final EnumMap opcodeValues; @Nonnull private final HashMap opcodesByName; @Nonnull public static Opcodes forApi(int api) { return new Opcodes(api, NO_VERSION); } @Nonnull public static Opcodes forArtVersion(int artVersion) { return new Opcodes(NO_VERSION, artVersion); } @Nonnull public static Opcodes forDexVersion(int dexVersion) { int api = VersionMap.mapDexVersionToApi(dexVersion); if (api == NO_VERSION) { throw new RuntimeException("Unsupported dex version " + dexVersion); } return new Opcodes(api, NO_VERSION); } /** * @return a default Opcodes instance for when the exact Opcodes to use doesn't matter or isn't known */ @Nonnull public static Opcodes getDefault() { // The last pre-art api return forApi(20); } private Opcodes(int api, int artVersion) { if (api >= 21) { this.api = api; this.artVersion = mapApiToArtVersion(api); } else if (artVersion >= 0 && artVersion < 39) { this.api = mapArtVersionToApi(artVersion); this.artVersion = artVersion; } else { this.api = api; this.artVersion = artVersion; } opcodeValues = new EnumMap(Opcode.class); opcodesByName = Maps.newHashMap(); int version; if (isArt()) { version = this.artVersion; } else { version = this.api; } for (Opcode opcode: Opcode.values()) { RangeMap versionToValueMap; if (isArt()) { versionToValueMap = opcode.artVersionToValueMap; } else { versionToValueMap = opcode.apiToValueMap; } Short opcodeValue = versionToValueMap.get(version); if (opcodeValue != null) { if (!opcode.format.isPayloadFormat) { opcodesByValue[opcodeValue] = opcode; } opcodeValues.put(opcode, opcodeValue); opcodesByName.put(opcode.name.toLowerCase(), opcode); } } } @Nullable public Opcode getOpcodeByName(@Nonnull String opcodeName) { return opcodesByName.get(opcodeName.toLowerCase()); } @Nullable public Opcode getOpcodeByValue(int opcodeValue) { switch (opcodeValue) { case 0x100: return Opcode.PACKED_SWITCH_PAYLOAD; case 0x200: return Opcode.SPARSE_SWITCH_PAYLOAD; case 0x300: return Opcode.ARRAY_PAYLOAD; default: if (opcodeValue >= 0 && opcodeValue < opcodesByValue.length) { return opcodesByValue[opcodeValue]; } return null; } } @Nullable public Short getOpcodeValue(@Nonnull Opcode opcode) { return opcodeValues.get(opcode); } public boolean isArt() { return artVersion != NO_VERSION; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java000066400000000000000000000106011342202223400247250ustar00rootroot00000000000000/* * 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; import org.jf.dexlib2.iface.reference.*; import org.jf.util.ExceptionWithContext; public final class ReferenceType { public static final int STRING = 0; public static final int TYPE = 1; public static final int FIELD = 2; public static final int METHOD = 3; public static final int METHOD_PROTO = 4; public static final int CALL_SITE = 5; public static final int METHOD_HANDLE = 6; public static final int NONE = 7; public static String toString(int referenceType) { switch (referenceType) { case STRING: return "string"; case TYPE: return "type"; case FIELD: return "field"; case METHOD: return "method"; case METHOD_PROTO: return "method_proto"; case CALL_SITE: return "call_site"; case METHOD_HANDLE: return "method_handle"; default: throw new InvalidReferenceTypeException(referenceType); } } public static int getReferenceType(Reference reference) { if (reference instanceof StringReference) { return STRING; } else if (reference instanceof TypeReference) { return TYPE; } else if (reference instanceof FieldReference) { return FIELD; } else if (reference instanceof MethodReference) { return METHOD; } else if (reference instanceof MethodProtoReference) { return METHOD_PROTO; } else if (reference instanceof CallSiteReference) { return CALL_SITE; } else if (reference instanceof MethodHandleReference) { return METHOD_HANDLE; } else { throw new IllegalStateException("Invalid reference"); } } /** * Validate a specific reference type. Note that the NONE placeholder is specifically not considered valid here. * * @throws InvalidReferenceTypeException */ public static void validateReferenceType(int referenceType) { if (referenceType < 0 || referenceType > 4) { throw new InvalidReferenceTypeException(referenceType); } } public static class InvalidReferenceTypeException extends ExceptionWithContext { private final int referenceType; public InvalidReferenceTypeException(int referenceType) { super("Invalid reference type: %d", referenceType); this.referenceType = referenceType; } public InvalidReferenceTypeException(int referenceType, String message, Object... formatArgs) { super(message, formatArgs); this.referenceType = referenceType; } public int getReferenceType() { return referenceType; } } private ReferenceType() {} }smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/ValueType.java000066400000000000000000000071441342202223400241130ustar00rootroot00000000000000/* * 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; public final class ValueType { public static final int BYTE = 0x00; public static final int SHORT = 0x02; public static final int CHAR = 0x03; public static final int INT = 0x04; public static final int LONG = 0x06; public static final int FLOAT = 0x10; public static final int DOUBLE = 0x11; public static final int METHOD_TYPE = 0x15; public static final int METHOD_HANDLE = 0x16; public static final int STRING = 0x17; public static final int TYPE = 0x18; public static final int FIELD = 0x19; public static final int METHOD = 0x1a; public static final int ENUM = 0x1b; public static final int ARRAY = 0x1c; public static final int ANNOTATION = 0x1d; public static final int NULL = 0x1e; public static final int BOOLEAN = 0x1f; private ValueType() {} public static String getValueTypeName(int valueType) { switch (valueType) { case BYTE: return "byte"; case SHORT: return "short"; case CHAR: return "char"; case INT: return "int"; case LONG: return "long"; case FLOAT: return "float"; case DOUBLE: return "double"; case METHOD_TYPE: return "method_type"; case METHOD_HANDLE: return "method_handle"; case STRING: return "string"; case TYPE: return "type"; case FIELD: return "field"; case METHOD: return "method"; case ENUM: return "enum"; case ARRAY: return "array"; case ANNOTATION: return "annotation"; case NULL: return "null"; case BOOLEAN: return "boolean"; default: throw new IllegalArgumentException("Unknown encoded value type: " + valueType); } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/VerificationError.java000066400000000000000000000104051342202223400256230ustar00rootroot00000000000000/* * Copyright 2013, 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; import com.google.common.collect.Maps; import org.jf.util.ExceptionWithContext; import javax.annotation.Nullable; import java.util.HashMap; public class VerificationError { public static final int GENERIC = 1; public static final int NO_SUCH_CLASS = 2; public static final int NO_SUCH_FIELD = 3; public static final int NO_SUCH_METHOD = 4; public static final int ILLEGAL_CLASS_ACCESS = 5; public static final int ILLEGAL_FIELD_ACCESS = 6; public static final int ILLEGAL_METHOD_ACCESS = 7; public static final int CLASS_CHANGE_ERROR = 8; public static final int INSTANTIATION_ERROR = 9; private static final HashMap verificationErrorNames = Maps.newHashMap(); static { verificationErrorNames.put("generic-error", GENERIC); verificationErrorNames.put("no-such-class", NO_SUCH_CLASS); verificationErrorNames.put("no-such-field", NO_SUCH_FIELD); verificationErrorNames.put("no-such-method", NO_SUCH_METHOD); verificationErrorNames.put("illegal-class-access", ILLEGAL_CLASS_ACCESS); verificationErrorNames.put("illegal-field-access", ILLEGAL_FIELD_ACCESS); verificationErrorNames.put("illegal-method-access", ILLEGAL_METHOD_ACCESS); verificationErrorNames.put("class-change-error", CLASS_CHANGE_ERROR); verificationErrorNames.put("instantiation-error", INSTANTIATION_ERROR); } @Nullable public static String getVerificationErrorName(int verificationError) { switch (verificationError) { case GENERIC: return "generic-error"; case NO_SUCH_CLASS: return "no-such-class"; case NO_SUCH_FIELD: return "no-such-field"; case NO_SUCH_METHOD: return "no-such-method"; case ILLEGAL_CLASS_ACCESS: return "illegal-class-access"; case ILLEGAL_FIELD_ACCESS: return "illegal-field-access"; case ILLEGAL_METHOD_ACCESS: return "illegal-method-access"; case CLASS_CHANGE_ERROR: return "class-change-error"; case INSTANTIATION_ERROR: return "instantiation-error"; default: return null; } } public static int getVerificationError(String verificationError) { Integer ret = verificationErrorNames.get(verificationError); if (ret == null) { throw new ExceptionWithContext("Invalid verification error: %s", verificationError); } return ret; } public static boolean isValidVerificationError(int verificationError) { return verificationError > 0 && verificationError < 10; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/VersionMap.java000066400000000000000000000067431342202223400242640ustar00rootroot00000000000000/* * Copyright 2015, 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; public class VersionMap { public static final int NO_VERSION = -1; public static int mapDexVersionToApi(int dexVersion) { switch (dexVersion) { case 35: return 23; case 37: return 25; case 38: return 27; case 39: return 28; default: return NO_VERSION; } } public static int mapApiToDexVersion(int api) { if (api <= 23) { return 35; } if (api <= 25) { return 37; } if (api <= 27) { return 38; } return 39; } public static int mapArtVersionToApi(int artVersion) { // 144 is the current version in the master branch of AOSP as of 2018-05-22 if (artVersion >= 144) { return 28; } if (artVersion >= 131) { return 27; } if (artVersion >= 124) { return 26; } if (artVersion >= 79) { return 24; } if (artVersion >= 64) { return 23; } if (artVersion >= 45) { return 22; } if (artVersion >= 39) { return 21; } return 19; } public static int mapApiToArtVersion(int api) { if (api < 19) { return NO_VERSION; } switch (api) { case 19: case 20: return 7; case 21: return 39; case 22: return 45; case 23: return 64; case 24: case 25: return 79; case 26: return 124; case 27: return 131; default: // 144 is the current version in the master branch of AOSP as of 2018-05-22 return 144; } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/000077500000000000000000000000001342202223400231475ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalysisException.java000066400000000000000000000040111342202223400274500ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import org.jf.util.ExceptionWithContext; public class AnalysisException extends ExceptionWithContext { public int codeAddress; public AnalysisException(Throwable cause) { super(cause); } public AnalysisException(Throwable cause, String message, Object... formatArgs) { super(cause, message, formatArgs); } public AnalysisException(String message, Object... formatArgs) { super(message, formatArgs); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java000066400000000000000000000752371342202223400300410ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import com.google.common.base.Objects; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.iface.instruction.*; import org.jf.dexlib2.iface.instruction.formats.Instruction22c; import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.reference.Reference; import org.jf.dexlib2.iface.reference.TypeReference; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; public class AnalyzedInstruction implements Comparable { /** * The MethodAnalyzer containing this instruction */ @Nonnull protected final MethodAnalyzer methodAnalyzer; /** * The actual instruction */ @Nonnull protected Instruction instruction; /** * The index of the instruction, where the first instruction in the method is at index 0, and so on */ protected final int instructionIndex; /** * Instructions that can pass on execution to this one during normal execution */ @Nonnull protected final TreeSet predecessors = new TreeSet(); /** * Instructions that can execution could pass on to next during normal execution */ @Nonnull protected final LinkedList successors = new LinkedList(); /** * This contains the register types *before* the instruction has executed */ @Nonnull protected final RegisterType[] preRegisterMap; /** * This contains the register types *after* the instruction has executed */ @Nonnull protected final RegisterType[] postRegisterMap; /** * This contains optional register type overrides for register types from predecessors */ @Nullable protected Map predecessorRegisterOverrides = null; /** * When deodexing, we might need to deodex this instruction multiple times, when we merge in new register * information. When this happens, we need to restore the original (odexed) instruction, so we can deodex it again */ protected final Instruction originalInstruction; public AnalyzedInstruction(@Nonnull MethodAnalyzer methodAnalyzer, @Nonnull Instruction instruction, int instructionIndex, int registerCount) { this.methodAnalyzer = methodAnalyzer; this.instruction = instruction; this.originalInstruction = instruction; this.instructionIndex = instructionIndex; this.postRegisterMap = new RegisterType[registerCount]; this.preRegisterMap = new RegisterType[registerCount]; RegisterType unknown = RegisterType.getRegisterType(RegisterType.UNKNOWN, null); for (int i=0; i getPredecessors() { return Collections.unmodifiableSortedSet(predecessors); } public RegisterType getPredecessorRegisterType(@Nonnull AnalyzedInstruction predecessor, int registerNumber) { if (predecessorRegisterOverrides != null) { RegisterType override = predecessorRegisterOverrides.get( new PredecessorOverrideKey(predecessor, registerNumber)); if (override != null) { return override; } } return predecessor.postRegisterMap[registerNumber]; } protected boolean addPredecessor(AnalyzedInstruction predecessor) { return predecessors.add(predecessor); } protected void addSuccessor(AnalyzedInstruction successor) { successors.add(successor); } protected void setDeodexedInstruction(Instruction instruction) { assert originalInstruction.getOpcode().odexOnly(); this.instruction = instruction; } protected void restoreOdexedInstruction() { assert originalInstruction.getOpcode().odexOnly(); instruction = originalInstruction; } @Nonnull public List getSuccessors() { return Collections.unmodifiableList(successors); } @Nonnull public Instruction getInstruction() { return instruction; } @Nonnull public Instruction getOriginalInstruction() { return originalInstruction; } /** * Is this instruction a "beginning instruction". A beginning instruction is defined to be an instruction * that can be the first successfully executed instruction in the method. The first instruction is always a * beginning instruction. If the first instruction can throw an exception, and is covered by a try block, then * the first instruction of any exception handler for that try block is also a beginning instruction. And likewise, * if any of those instructions can throw an exception and are covered by try blocks, the first instruction of the * corresponding exception handler is a beginning instruction, etc. * * To determine this, we simply check if the first predecessor is the fake "StartOfMethod" instruction, which has * an instruction index of -1. * @return a boolean value indicating whether this instruction is a beginning instruction */ public boolean isBeginningInstruction() { //if this instruction has no predecessors, it is either the fake "StartOfMethod" instruction or it is an //unreachable instruction. if (predecessors.size() == 0) { return false; } return predecessors.first().instructionIndex == -1; } /* * Merges the given register type into the specified pre-instruction register, and also sets the post-instruction * register type accordingly if it isn't a destination register for this instruction * @param registerNumber Which register to set * @param registerType The register type * @returns true If the post-instruction register type was changed. This might be false if either the specified * register is a destination register for this instruction, or if the pre-instruction register type didn't change * after merging in the given register type */ protected boolean mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions, boolean override) { assert registerNumber >= 0 && registerNumber < postRegisterMap.length; assert registerType != null; RegisterType oldRegisterType = preRegisterMap[registerNumber]; RegisterType mergedRegisterType; if (override) { mergedRegisterType = getMergedPreRegisterTypeFromPredecessors(registerNumber); } else { mergedRegisterType = oldRegisterType.merge(registerType); } if (mergedRegisterType.equals(oldRegisterType)) { return false; } preRegisterMap[registerNumber] = mergedRegisterType; verifiedInstructions.clear(instructionIndex); if (!setsRegister(registerNumber)) { postRegisterMap[registerNumber] = mergedRegisterType; return true; } return false; } /** * Iterates over the predecessors of this instruction, and merges all the post-instruction register types for the * given register. Any dead, unreachable, or odexed predecessor is ignored. This takes into account any overridden * predecessor register types * * @param registerNumber the register number * @return The register type resulting from merging the post-instruction register types from all predecessors */ @Nonnull protected RegisterType getMergedPreRegisterTypeFromPredecessors(int registerNumber) { RegisterType mergedRegisterType = null; for (AnalyzedInstruction predecessor: predecessors) { RegisterType predecessorRegisterType = getPredecessorRegisterType(predecessor, registerNumber); if (predecessorRegisterType != null) { if (mergedRegisterType == null) { mergedRegisterType = predecessorRegisterType; } else { mergedRegisterType = predecessorRegisterType.merge(mergedRegisterType); } } } if (mergedRegisterType == null) { // This is a start-of-method or unreachable instruction. throw new IllegalStateException(); } return mergedRegisterType; } /** * Sets the "post-instruction" register type as indicated. * @param registerNumber Which register to set * @param registerType The "post-instruction" register type * @return true if the given register type is different than the existing post-instruction register type */ protected boolean setPostRegisterType(int registerNumber, RegisterType registerType) { assert registerNumber >= 0 && registerNumber < postRegisterMap.length; assert registerType != null; RegisterType oldRegisterType = postRegisterMap[registerNumber]; if (oldRegisterType.equals(registerType)) { return false; } postRegisterMap[registerNumber] = registerType; return true; } /** * Adds an override for a register type from a predecessor. * * This is used to set the register type for only one branch from a conditional jump. * * @param predecessor Which predecessor is being overridden * @param registerNumber The register number of the register being overridden * @param registerType The overridden register type * @param verifiedInstructions A bit vector of instructions that have been verified * * @return true if the post-instruction register type for this instruction changed as a result of this override */ protected boolean overridePredecessorRegisterType(@Nonnull AnalyzedInstruction predecessor, int registerNumber, @Nonnull RegisterType registerType, BitSet verifiedInstructions) { if (predecessorRegisterOverrides == null) { predecessorRegisterOverrides = Maps.newHashMap(); } predecessorRegisterOverrides.put(new PredecessorOverrideKey(predecessor, registerNumber), registerType); RegisterType mergedType = getMergedPreRegisterTypeFromPredecessors(registerNumber); if (preRegisterMap[registerNumber].equals(mergedType)) { return false; } preRegisterMap[registerNumber] = mergedType; verifiedInstructions.clear(instructionIndex); if (!setsRegister(registerNumber)) { if (!postRegisterMap[registerNumber].equals(mergedType)) { postRegisterMap[registerNumber] = mergedType; return true; } } return false; } public boolean isInvokeInit() { if (!instruction.getOpcode().canInitializeReference()) { return false; } ReferenceInstruction instruction = (ReferenceInstruction)this.instruction; Reference reference = instruction.getReference(); if (reference instanceof MethodReference) { return ((MethodReference)reference).getName().equals(""); } return false; } /** * Determines if this instruction sets the given register, or alters its type * * @param registerNumber The register to check * @return true if this instruction sets the given register or alters its type */ public boolean setsRegister(int registerNumber) { // This method could be implemented by calling getSetRegisters and checking if registerNumber is in the result // However, this is a frequently called method, and this is a more efficient implementation, because it doesn't // allocate a new list, and it can potentially exit earlier if (isInvokeInit()) { // When constructing a new object, the register type will be an uninitialized reference after the // new-instance instruction, but becomes an initialized reference once the method is called. So even // though invoke instructions don't normally change any registers, calling an method will change the // type of its object register. If the uninitialized reference has been copied to other registers, they will // be initialized as well, so we need to check for that too int destinationRegister; if (instruction instanceof FiveRegisterInstruction) { assert ((FiveRegisterInstruction)instruction).getRegisterCount() > 0; destinationRegister = ((FiveRegisterInstruction)instruction).getRegisterC(); } else { assert instruction instanceof RegisterRangeInstruction; RegisterRangeInstruction rangeInstruction = (RegisterRangeInstruction)instruction; assert rangeInstruction.getRegisterCount() > 0; destinationRegister = rangeInstruction.getStartRegister(); } RegisterType preInstructionDestRegisterType = getPreInstructionRegisterType(destinationRegister); if (preInstructionDestRegisterType.category == RegisterType.UNKNOWN) { // We never let an uninitialized reference propagate past an invoke-init if the object register type is // unknown This is because the uninitialized reference may be an alias to the reference being // initialized, but we can't know that until the object register's type is known RegisterType preInstructionRegisterType = getPreInstructionRegisterType(registerNumber); if (preInstructionRegisterType.category == RegisterType.UNINIT_REF || preInstructionRegisterType.category == RegisterType.UNINIT_THIS) { return true; } } if (preInstructionDestRegisterType.category != RegisterType.UNINIT_REF && preInstructionDestRegisterType.category != RegisterType.UNINIT_THIS) { return false; } if (registerNumber == destinationRegister) { return true; } //check if the uninit ref has been copied to another register return preInstructionDestRegisterType.equals(getPreInstructionRegisterType(registerNumber)); } // On art, the optimizer will often nop out a check-cast instruction after an instance-of instruction. // Normally, check-cast is where the register type actually changes. // In order to correctly handle this case, we have to propagate the narrowed register type to the appropriate // branch of the following if-eqz/if-nez if (instructionIndex > 0 && methodAnalyzer.getClassPath().isArt() && getPredecessorCount() == 1 && (instruction.getOpcode() == Opcode.IF_EQZ || instruction.getOpcode() == Opcode.IF_NEZ)) { AnalyzedInstruction prevInstruction = predecessors.first(); if (prevInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF && MethodAnalyzer.canPropagateTypeAfterInstanceOf( prevInstruction, this, methodAnalyzer.getClassPath())) { Instruction22c instanceOfInstruction = (Instruction22c)prevInstruction.instruction; if (registerNumber == instanceOfInstruction.getRegisterB()) { return true; } // Additionally, there may be a move instruction just before the instance-of, in order to put the value // into a register that is addressable by the instance-of. In this case, we also need to propagate the // new register type for the original register that the value was moved from. // In some cases, the instance-of may have multiple predecessors. In this case, we should only do the // propagation if all predecessors are move-object instructions for the same source register // TODO: do we need to do some sort of additional check that these multiple move-object predecessors actually refer to the same value? if (instructionIndex > 1) { int originalSourceRegister = -1; RegisterType newType = null; for (AnalyzedInstruction prevPrevAnalyzedInstruction : prevInstruction.predecessors) { Opcode opcode = prevPrevAnalyzedInstruction.instruction.getOpcode(); if (opcode == Opcode.MOVE_OBJECT || opcode == Opcode.MOVE_OBJECT_16 || opcode == Opcode.MOVE_OBJECT_FROM16) { TwoRegisterInstruction moveInstruction = ((TwoRegisterInstruction)prevPrevAnalyzedInstruction.instruction); RegisterType originalType = prevPrevAnalyzedInstruction.getPostInstructionRegisterType( moveInstruction.getRegisterB()); if (moveInstruction.getRegisterA() != instanceOfInstruction.getRegisterB()) { originalSourceRegister = -1; break; } if (originalType.type == null) { originalSourceRegister = -1; break; } if (newType == null) { newType = RegisterType.getRegisterType(methodAnalyzer.getClassPath(), (TypeReference)instanceOfInstruction.getReference()); } if (MethodAnalyzer.isNotWideningConversion(originalType, newType)) { if (originalSourceRegister != -1) { if (originalSourceRegister != moveInstruction.getRegisterB()) { originalSourceRegister = -1; break; } } else { originalSourceRegister = moveInstruction.getRegisterB(); } } } else { originalSourceRegister = -1; break; } } if (originalSourceRegister != -1 && registerNumber == originalSourceRegister) { return true; } } } } if (!instruction.getOpcode().setsRegister()) { return false; } int destinationRegister = getDestinationRegister(); if (registerNumber == destinationRegister) { return true; } if (instruction.getOpcode().setsWideRegister() && registerNumber == (destinationRegister + 1)) { return true; } return false; } public List getSetRegisters() { List setRegisters = Lists.newArrayList(); if (instruction.getOpcode().setsRegister()) { setRegisters.add(getDestinationRegister()); } if (instruction.getOpcode().setsWideRegister()) { setRegisters.add(getDestinationRegister() + 1); } if (isInvokeInit()) { //When constructing a new object, the register type will be an uninitialized reference after the new-instance //instruction, but becomes an initialized reference once the method is called. So even though invoke //instructions don't normally change any registers, calling an method will change the type of its //object register. If the uninitialized reference has been copied to other registers, they will be initialized //as well, so we need to check for that too int destinationRegister; if (instruction instanceof FiveRegisterInstruction) { destinationRegister = ((FiveRegisterInstruction)instruction).getRegisterC(); assert ((FiveRegisterInstruction)instruction).getRegisterCount() > 0; } else { assert instruction instanceof RegisterRangeInstruction; RegisterRangeInstruction rangeInstruction = (RegisterRangeInstruction)instruction; assert rangeInstruction.getRegisterCount() > 0; destinationRegister = rangeInstruction.getStartRegister(); } RegisterType preInstructionDestRegisterType = getPreInstructionRegisterType(destinationRegister); if (preInstructionDestRegisterType.category == RegisterType.UNINIT_REF || preInstructionDestRegisterType.category == RegisterType.UNINIT_THIS) { setRegisters.add(destinationRegister); RegisterType objectRegisterType = preRegisterMap[destinationRegister]; for (int i = 0; i < preRegisterMap.length; i++) { if (i == destinationRegister) { continue; } RegisterType preInstructionRegisterType = preRegisterMap[i]; if (preInstructionRegisterType.equals(objectRegisterType)) { setRegisters.add(i); } else if (preInstructionRegisterType.category == RegisterType.UNINIT_REF || preInstructionRegisterType.category == RegisterType.UNINIT_THIS) { RegisterType postInstructionRegisterType = postRegisterMap[i]; if (postInstructionRegisterType.category == RegisterType.UNKNOWN) { setRegisters.add(i); } } } } else if (preInstructionDestRegisterType.category == RegisterType.UNKNOWN) { // We never let an uninitialized reference propagate past an invoke-init if the object register type is // unknown This is because the uninitialized reference may be an alias to the reference being // initialized, but we can't know that until the object register's type is known for (int i = 0; i < preRegisterMap.length; i++) { RegisterType registerType = preRegisterMap[i]; if (registerType.category == RegisterType.UNINIT_REF || registerType.category == RegisterType.UNINIT_THIS) { setRegisters.add(i); } } } } // On art, the optimizer will often nop out a check-cast instruction after an instance-of instruction. // Normally, check-cast is where the register type actually changes. // In order to correctly handle this case, we have to propagate the narrowed register type to the appropriate // branch of the following if-eqz/if-nez if (instructionIndex > 0 && methodAnalyzer.getClassPath().isArt() && getPredecessorCount() == 1 && (instruction.getOpcode() == Opcode.IF_EQZ || instruction.getOpcode() == Opcode.IF_NEZ)) { AnalyzedInstruction prevInstruction = predecessors.first(); if (prevInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF && MethodAnalyzer.canPropagateTypeAfterInstanceOf( prevInstruction, this, methodAnalyzer.getClassPath())) { Instruction22c instanceOfInstruction = (Instruction22c)prevInstruction.instruction; setRegisters.add(instanceOfInstruction.getRegisterB()); // Additionally, there may be a move instruction just before the instance-of, in order to put the value // into a register that is addressable by the instance-of. In this case, we also need to propagate the // new register type for the original register that the value was moved from. // In some cases, the instance-of may have multiple predecessors. In this case, we should only do the // propagation if all predecessors are move-object instructions for the same source register // TODO: do we need to do some sort of additional check that these multiple move-object predecessors actually refer to the same value? if (instructionIndex > 1) { int originalSourceRegister = -1; RegisterType newType = null; for (AnalyzedInstruction prevPrevAnalyzedInstruction : prevInstruction.predecessors) { Opcode opcode = prevPrevAnalyzedInstruction.instruction.getOpcode(); if (opcode == Opcode.MOVE_OBJECT || opcode == Opcode.MOVE_OBJECT_16 || opcode == Opcode.MOVE_OBJECT_FROM16) { TwoRegisterInstruction moveInstruction = ((TwoRegisterInstruction)prevPrevAnalyzedInstruction.instruction); RegisterType originalType = prevPrevAnalyzedInstruction.getPostInstructionRegisterType( moveInstruction.getRegisterB()); if (moveInstruction.getRegisterA() != instanceOfInstruction.getRegisterB()) { originalSourceRegister = -1; break; } if (originalType.type == null) { originalSourceRegister = -1; break; } if (newType == null) { newType = RegisterType.getRegisterType(methodAnalyzer.getClassPath(), (TypeReference)instanceOfInstruction.getReference()); } if (MethodAnalyzer.isNotWideningConversion(originalType, newType)) { if (originalSourceRegister != -1) { if (originalSourceRegister != moveInstruction.getRegisterB()) { originalSourceRegister = -1; break; } } else { originalSourceRegister = moveInstruction.getRegisterB(); } } } else { originalSourceRegister = -1; break; } } if (originalSourceRegister != -1) { setRegisters.add(originalSourceRegister); } } } } return setRegisters; } public int getDestinationRegister() { if (!this.instruction.getOpcode().setsRegister()) { throw new ExceptionWithContext("Cannot call getDestinationRegister() for an instruction that doesn't " + "store a value"); } return ((OneRegisterInstruction)instruction).getRegisterA(); } public int getRegisterCount() { return postRegisterMap.length; } @Nonnull public RegisterType getPostInstructionRegisterType(int registerNumber) { return postRegisterMap[registerNumber]; } @Nonnull public RegisterType getPreInstructionRegisterType(int registerNumber) { return preRegisterMap[registerNumber]; } public int compareTo(@Nonnull AnalyzedInstruction analyzedInstruction) { if (instructionIndex < analyzedInstruction.instructionIndex) { return -1; } else if (instructionIndex == analyzedInstruction.instructionIndex) { return 0; } else { return 1; } } private static class PredecessorOverrideKey { public final AnalyzedInstruction analyzedInstruction; public final int registerNumber; public PredecessorOverrideKey(AnalyzedInstruction analyzedInstruction, int registerNumber) { this.analyzedInstruction = analyzedInstruction; this.registerNumber = registerNumber; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PredecessorOverrideKey that = (PredecessorOverrideKey)o; return com.google.common.base.Objects.equal(registerNumber, that.registerNumber) && Objects.equal(analyzedInstruction, that.analyzedInstruction); } @Override public int hashCode() { return Objects.hashCode(analyzedInstruction, registerNumber); } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java000066400000000000000000000057211342202223400275650ustar00rootroot00000000000000/* * Copyright 2015, 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.analysis; import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.analysis.util.TypeProtoUtils; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.util.MethodUtil; import org.jf.dexlib2.util.TypeUtils; import javax.annotation.Nonnull; public class AnalyzedMethodUtil { public static boolean canAccess(@Nonnull TypeProto type, @Nonnull Method virtualMethod, boolean checkPackagePrivate, boolean checkProtected, boolean checkClass) { if (checkPackagePrivate && MethodUtil.isPackagePrivate(virtualMethod)) { String otherPackage = TypeUtils.getPackage(virtualMethod.getDefiningClass()); String thisPackage = TypeUtils.getPackage(type.getType()); if (!otherPackage.equals(thisPackage)) { return false; } } if (checkProtected && (virtualMethod.getAccessFlags() & AccessFlags.PROTECTED.getValue()) != 0) { if (!TypeProtoUtils.extendsFrom(type, virtualMethod.getDefiningClass())) { return false; } } if (checkClass) { ClassPath classPath = type.getClassPath(); ClassDef methodClassDef = classPath.getClassDef(virtualMethod.getDefiningClass()); if (!TypeUtils.canAccessClass(type.getType(), methodClassDef)) { return false; } } return true; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java000066400000000000000000000147141342202223400261230ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import com.google.common.base.Strings; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.immutable.reference.ImmutableFieldReference; import org.jf.dexlib2.util.TypeUtils; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ArrayProto implements TypeProto { protected final ClassPath classPath; protected final int dimensions; protected final String elementType; public ArrayProto(@Nonnull ClassPath classPath, @Nonnull String type) { this.classPath = classPath; int i=0; while (type.charAt(i) == '[') { i++; if (i == type.length()) { throw new ExceptionWithContext("Invalid array type: %s", type); } } if (i == 0) { throw new ExceptionWithContext("Invalid array type: %s", type); } dimensions = i; elementType = type.substring(i); } @Override public String toString() { return getType(); } @Nonnull @Override public ClassPath getClassPath() { return classPath; } @Nonnull @Override public String getType() { return makeArrayType(elementType, dimensions); } public int getDimensions() { return dimensions; } @Override public boolean isInterface() { return false; } /** * @return The base element type of this array. E.g. This would return Ljava/lang/String; for [[Ljava/lang/String; */ @Nonnull public String getElementType() { return elementType; } /** * @return The immediate element type of this array. E.g. This would return [Ljava/lang/String; for * [[Ljava/lang/String; */ @Nonnull public String getImmediateElementType() { if (dimensions > 1) { return makeArrayType(elementType, dimensions-1); } return elementType; } @Override public boolean implementsInterface(@Nonnull String iface) { return iface.equals("Ljava/lang/Cloneable;") || iface.equals("Ljava/io/Serializable;"); } @Nullable @Override public String getSuperclass() { return "Ljava/lang/Object;"; } @Nonnull @Override public TypeProto getCommonSuperclass(@Nonnull TypeProto other) { if (other instanceof ArrayProto) { if (TypeUtils.isPrimitiveType(getElementType()) || TypeUtils.isPrimitiveType(((ArrayProto)other).getElementType())) { if (dimensions == ((ArrayProto)other).dimensions && getElementType().equals(((ArrayProto)other).getElementType())) { return this; } return classPath.getClass("Ljava/lang/Object;"); } if (dimensions == ((ArrayProto)other).dimensions) { TypeProto thisClass = classPath.getClass(elementType); TypeProto otherClass = classPath.getClass(((ArrayProto)other).elementType); TypeProto mergedClass = thisClass.getCommonSuperclass(otherClass); if (thisClass == mergedClass) { return this; } if (otherClass == mergedClass) { return other; } return classPath.getClass(makeArrayType(mergedClass.getType(), dimensions)); } int dimensions = Math.min(this.dimensions, ((ArrayProto)other).dimensions); return classPath.getClass(makeArrayType("Ljava/lang/Object;", dimensions)); } if (other instanceof ClassProto) { try { if (other.isInterface()) { if (implementsInterface(other.getType())) { return other; } } } catch (UnresolvedClassException ex) { // ignore } return classPath.getClass("Ljava/lang/Object;"); } // otherwise, defer to the other class' getCommonSuperclass return other.getCommonSuperclass(this); } private static final String BRACKETS = Strings.repeat("[", 256); @Nonnull private static String makeArrayType(@Nonnull String elementType, int dimensions) { return BRACKETS.substring(0, dimensions) + elementType; } @Override @Nullable public FieldReference getFieldByOffset(int fieldOffset) { if (fieldOffset==8) { return new ImmutableFieldReference(getType(), "length", "int"); } return null; } @Override @Nullable public Method getMethodByVtableIndex(int vtableIndex) { return classPath.getClass("Ljava/lang/Object;").getMethodByVtableIndex(vtableIndex); } @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) { return classPath.getClass("Ljava/lang/Object;").findMethodIndexInVtable(method); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java000066400000000000000000000156701342202223400257050ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.analysis.reflection.ReflectionClassDef; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.immutable.ImmutableDexFile; import javax.annotation.Nonnull; import java.io.IOException; import java.io.Serializable; import java.util.Arrays; import java.util.List; public class ClassPath { @Nonnull private final TypeProto unknownClass; @Nonnull private List classProviders; private final boolean checkPackagePrivateAccess; public final int oatVersion; public static final int NOT_ART = -1; /** * Creates a new ClassPath instance that can load classes from the given providers * * @param classProviders A varargs array of ClassProviders. When loading a class, these providers will be searched * in order */ public ClassPath(ClassProvider... classProviders) throws IOException { this(Arrays.asList(classProviders), false, NOT_ART); } /** * Creates a new ClassPath instance that can load classes from the given providers * * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in * order */ public ClassPath(Iterable classProviders) throws IOException { this(classProviders, false, NOT_ART); } /** * Creates a new ClassPath instance that can load classes from the given providers * * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in * order * @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by * default * @param oatVersion The applicable oat version, or NOT_ART */ public ClassPath(@Nonnull Iterable classProviders, boolean checkPackagePrivateAccess, int oatVersion) { // add fallbacks for certain special classes that must be present unknownClass = new UnknownClassProto(this); loadedClasses.put(unknownClass.getType(), unknownClass); this.checkPackagePrivateAccess = checkPackagePrivateAccess; this.oatVersion = oatVersion; loadPrimitiveType("Z"); loadPrimitiveType("B"); loadPrimitiveType("S"); loadPrimitiveType("C"); loadPrimitiveType("I"); loadPrimitiveType("J"); loadPrimitiveType("F"); loadPrimitiveType("D"); loadPrimitiveType("L"); this.classProviders = Lists.newArrayList(classProviders); this.classProviders.add(getBasicClasses()); } private void loadPrimitiveType(String type) { loadedClasses.put(type, new PrimitiveProto(this, type)); } private static ClassProvider getBasicClasses() { // fallbacks for some special classes that we assume are present return new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), ImmutableSet.of( new ReflectionClassDef(Class.class), new ReflectionClassDef(Cloneable.class), new ReflectionClassDef(Object.class), new ReflectionClassDef(Serializable.class), new ReflectionClassDef(String.class), new ReflectionClassDef(Throwable.class)))); } public boolean isArt() { return oatVersion != NOT_ART; } @Nonnull public TypeProto getClass(@Nonnull CharSequence type) { return loadedClasses.getUnchecked(type.toString()); } private final CacheLoader classLoader = new CacheLoader() { @Override public TypeProto load(String type) throws Exception { if (type.charAt(0) == '[') { return new ArrayProto(ClassPath.this, type); } else { return new ClassProto(ClassPath.this, type); } } }; @Nonnull private LoadingCache loadedClasses = CacheBuilder.newBuilder().build(classLoader); @Nonnull public ClassDef getClassDef(String type) { for (ClassProvider provider: classProviders) { ClassDef classDef = provider.getClassDef(type); if (classDef != null) { return classDef; } } throw new UnresolvedClassException("Could not resolve class %s", type); } @Nonnull public TypeProto getUnknownClass() { return unknownClass; } public boolean shouldCheckPackagePrivateAccess() { return checkPackagePrivateAccess; } private final Supplier fieldInstructionMapperSupplier = Suppliers.memoize( new Supplier() { @Override public OdexedFieldInstructionMapper get() { return new OdexedFieldInstructionMapper(isArt()); } }); @Nonnull public OdexedFieldInstructionMapper getFieldInstructionMapper() { return fieldInstructionMapperSupplier.get(); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPathResolver.java000066400000000000000000000444651342202223400274330ustar00rootroot00000000000000/* * Copyright 2016, 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.analysis; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import org.jf.dexlib2.DexFileFactory.UnsupportedFileTypeException; import org.jf.dexlib2.dexbacked.DexBackedOdexFile; import org.jf.dexlib2.dexbacked.OatFile; import org.jf.dexlib2.dexbacked.OatFile.OatDexFile; import org.jf.dexlib2.iface.DexFile; import org.jf.dexlib2.iface.MultiDexContainer; import org.jf.dexlib2.iface.MultiDexContainer.MultiDexFile; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.util.List; public class ClassPathResolver { private final Iterable classPathDirs; private final PathEntryLoader pathEntryLoader; /** * Constructs a new ClassPathResolver using a specified list of bootclasspath entries * * @param bootClassPathDirs A list of directories to search for boot classpath entries. Can be empty if all boot * classpath entries are specified as local paths * @param bootClassPathEntries A list of boot classpath entries to load. These can either be local paths, or * device paths (e.g. "/system/framework/framework.jar"). The entry will be interpreted * first as a local path. If not found as a local path, it will be interpreted as a * partial or absolute device path, and will be searched for in bootClassPathDirs * @param extraClassPathEntries A list of additional classpath entries to load. Can be empty. All entries must be * local paths. Device paths are not supported. * @param dexFile The dex file that the classpath will be used to analyze * @throws IOException If any IOException occurs * @throws ResolveException If any classpath entries cannot be loaded for some reason * * If null, a default bootclasspath is used, * depending on the the file type of dexFile and the api level. If empty, no boot * classpath entries will be loaded */ public ClassPathResolver(@Nonnull List bootClassPathDirs, @Nonnull List bootClassPathEntries, @Nonnull List extraClassPathEntries, @Nonnull DexFile dexFile) throws IOException { this(bootClassPathDirs, bootClassPathEntries, extraClassPathEntries, dexFile, true); } /** * Constructs a new ClassPathResolver using a default list of bootclasspath entries * * @param bootClassPathDirs A list of directories to search for boot classpath entries * @param extraClassPathEntries A list of additional classpath entries to load. Can be empty. All entries must be * local paths. Device paths are not supported. * @param dexFile The dex file that the classpath will be used to analyze * @throws IOException If any IOException occurs * @throws ResolveException If any classpath entries cannot be loaded for some reason * * If null, a default bootclasspath is used, * depending on the the file type of dexFile and the api level. If empty, no boot * classpath entries will be loaded */ public ClassPathResolver(@Nonnull List bootClassPathDirs, @Nonnull List extraClassPathEntries, @Nonnull DexFile dexFile) throws IOException { this(bootClassPathDirs, null, extraClassPathEntries, dexFile, true); } private ClassPathResolver(@Nonnull List bootClassPathDirs, @Nullable List bootClassPathEntries, @Nonnull List extraClassPathEntries, @Nonnull DexFile dexFile, boolean unused) throws IOException { this.classPathDirs = bootClassPathDirs; this.pathEntryLoader = new PathEntryLoader(dexFile.getOpcodes()); if (bootClassPathEntries == null) { bootClassPathEntries = getDefaultBootClassPath(dexFile, dexFile.getOpcodes().api); } for (String entry : bootClassPathEntries) { try { loadLocalOrDeviceBootClassPathEntry(entry); } catch (PathEntryLoader.NoDexException ex) { if (entry.endsWith(".jar")) { String odexEntry = entry.substring(0, entry.length() - 4) + ".odex"; try { loadLocalOrDeviceBootClassPathEntry(odexEntry); } catch (PathEntryLoader.NoDexException ex2) { throw new ResolveException("Neither %s nor %s contain a dex file", entry, odexEntry); } catch (NotFoundException ex2) { throw new ResolveException(ex); } } else { throw new ResolveException(ex); } } catch (NotFoundException ex) { if (entry.endsWith(".odex")) { String jarEntry = entry.substring(0, entry.length() - 5) + ".jar"; try { loadLocalOrDeviceBootClassPathEntry(jarEntry); } catch (PathEntryLoader.NoDexException ex2) { throw new ResolveException("Neither %s nor %s contain a dex file", entry, jarEntry); } catch (NotFoundException ex2) { throw new ResolveException(ex); } } else { throw new ResolveException(ex); } } } for (String entry: extraClassPathEntries) { // extra classpath entries must be specified using a local path, so we don't need to do the search through // bootClassPathDirs try { loadLocalClassPathEntry(entry); } catch (PathEntryLoader.NoDexException ex) { throw new ResolveException(ex); } } if (dexFile instanceof MultiDexContainer.MultiDexFile) { MultiDexContainer container = ((MultiDexFile)dexFile).getContainer(); for (String entry: container.getDexEntryNames()) { pathEntryLoader.getClassProviders().add(new DexClassProvider(container.getEntry(entry))); } } else { pathEntryLoader.getClassProviders().add(new DexClassProvider(dexFile)); } } @Nonnull public List getResolvedClassProviders() { return pathEntryLoader.getResolvedClassProviders(); } private boolean loadLocalClassPathEntry(@Nonnull String entry) throws PathEntryLoader.NoDexException, IOException { File entryFile = new File(entry); if (entryFile.exists() && entryFile.isFile()) { try { pathEntryLoader.loadEntry(entryFile, true); return true; } catch (UnsupportedFileTypeException ex) { throw new ResolveException(ex, "Couldn't load classpath entry %s", entry); } } return false; } private void loadLocalOrDeviceBootClassPathEntry(@Nonnull String entry) throws IOException, PathEntryLoader.NoDexException, NotFoundException { // first, see if the entry is a valid local path if (loadLocalClassPathEntry(entry)) { return; } // It's not a local path, so let's try to resolve it as a device path, relative to one of the provided // directories List pathComponents = splitDevicePath(entry); Joiner pathJoiner = Joiner.on(File.pathSeparatorChar); for (String directory: classPathDirs) { File directoryFile = new File(directory); if (!directoryFile.exists()) { continue; } for (int i=0; i splitDevicePath(@Nonnull String path) { return Lists.newArrayList(Splitter.on('/').split(path)); } static class NotFoundException extends Exception { public NotFoundException(String message, Object... formatArgs) { super(String.format(message, formatArgs)); } } /** * An error that occurred while resolving the classpath */ public static class ResolveException extends RuntimeException { public ResolveException (String message, Object... formatArgs) { super(String.format(message, formatArgs)); } public ResolveException (Throwable cause) { super(cause); } public ResolveException (Throwable cause, String message, Object... formatArgs) { super(String.format(message, formatArgs), cause); } } /** * Returns the default boot class path for the given dex file and api level. */ @Nonnull private static List getDefaultBootClassPath(@Nonnull DexFile dexFile, int apiLevel) { if (dexFile instanceof OatFile.OatDexFile) { return bootClassPathForOat((OatDexFile) dexFile); } if (dexFile instanceof DexBackedOdexFile) { return ((DexBackedOdexFile)dexFile).getDependencies(); } if (apiLevel <= 8) { return Lists.newArrayList( "/system/framework/core.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/android.policy.jar", "/system/framework/services.jar"); } else if (apiLevel <= 11) { return Lists.newArrayList( "/system/framework/core.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/android.policy.jar", "/system/framework/services.jar", "/system/framework/core-junit.jar"); } else if (apiLevel <= 13) { return Lists.newArrayList( "/system/framework/core.jar", "/system/framework/apache-xml.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/android.policy.jar", "/system/framework/services.jar", "/system/framework/core-junit.jar"); } else if (apiLevel <= 15) { return Lists.newArrayList( "/system/framework/core.jar", "/system/framework/core-junit.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/android.policy.jar", "/system/framework/services.jar", "/system/framework/apache-xml.jar", "/system/framework/filterfw.jar"); } else if (apiLevel <= 17) { // this is correct as of api 17/4.2.2 return Lists.newArrayList( "/system/framework/core.jar", "/system/framework/core-junit.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/telephony-common.jar", "/system/framework/mms-common.jar", "/system/framework/android.policy.jar", "/system/framework/services.jar", "/system/framework/apache-xml.jar"); } else if (apiLevel <= 18) { return Lists.newArrayList( "/system/framework/core.jar", "/system/framework/core-junit.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/telephony-common.jar", "/system/framework/voip-common.jar", "/system/framework/mms-common.jar", "/system/framework/android.policy.jar", "/system/framework/services.jar", "/system/framework/apache-xml.jar"); } else if (apiLevel <= 19) { return Lists.newArrayList( "/system/framework/core.jar", "/system/framework/conscrypt.jar", "/system/framework/core-junit.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/framework2.jar", "/system/framework/telephony-common.jar", "/system/framework/voip-common.jar", "/system/framework/mms-common.jar", "/system/framework/android.policy.jar", "/system/framework/services.jar", "/system/framework/apache-xml.jar", "/system/framework/webviewchromium.jar"); } else if (apiLevel <= 22) { return Lists.newArrayList( "/system/framework/core-libart.jar", "/system/framework/conscrypt.jar", "/system/framework/okhttp.jar", "/system/framework/core-junit.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/telephony-common.jar", "/system/framework/voip-common.jar", "/system/framework/ims-common.jar", "/system/framework/mms-common.jar", "/system/framework/android.policy.jar", "/system/framework/apache-xml.jar"); } else if (apiLevel <= 23) { return Lists.newArrayList( "/system/framework/core-libart.jar", "/system/framework/conscrypt.jar", "/system/framework/okhttp.jar", "/system/framework/core-junit.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/telephony-common.jar", "/system/framework/voip-common.jar", "/system/framework/ims-common.jar", "/system/framework/apache-xml.jar", "/system/framework/org.apache.http.legacy.boot.jar"); } else /*if (apiLevel <= 24)*/ { return Lists.newArrayList( "/system/framework/core-oj.jar", "/system/framework/core-libart.jar", "/system/framework/conscrypt.jar", "/system/framework/okhttp.jar", "/system/framework/core-junit.jar", "/system/framework/bouncycastle.jar", "/system/framework/ext.jar", "/system/framework/framework.jar", "/system/framework/telephony-common.jar", "/system/framework/voip-common.jar", "/system/framework/ims-common.jar", "/system/framework/apache-xml.jar", "/system/framework/org.apache.http.legacy.boot.jar"); } } private static List bootClassPathForOat(@Nonnull OatDexFile dexFile) { List bcp = dexFile.getContainer().getBootClassPath(); if(bcp.isEmpty()) { return Lists.newArrayList("boot.oat"); } else { return replaceElementsSuffix(bcp, ".art", ".oat"); } } private static List replaceElementsSuffix(List bcp, String originalSuffix, String newSuffix) { for (int i=0; i unresolvedInterfaces = null; public ClassProto(@Nonnull ClassPath classPath, @Nonnull String type) { if (type.charAt(0) != 'L') { throw new ExceptionWithContext("Cannot construct ClassProto for non reference type: %s", type); } this.classPath = classPath; this.type = type; } @Override public String toString() { return type; } @Nonnull @Override public ClassPath getClassPath() { return classPath; } @Nonnull @Override public String getType() { return type; } @Nonnull public ClassDef getClassDef() { return classDefSupplier.get(); } @Nonnull private final Supplier classDefSupplier = Suppliers.memoize(new Supplier() { @Override public ClassDef get() { return classPath.getClassDef(type); } }); /** * Returns true if this class is an interface. * * If this class is not defined, then this will throw an UnresolvedClassException * * @return True if this class is an interface */ public boolean isInterface() { ClassDef classDef = getClassDef(); return (classDef.getAccessFlags() & AccessFlags.INTERFACE.getValue()) != 0; } /** * Returns the set of interfaces that this class implements as a Map. * * The ClassDef value will be present only for the interfaces that this class directly implements (including any * interfaces transitively implemented), but not for any interfaces that are only implemented by a superclass of * this class * * For any interfaces that are only implemented by a superclass (or the class itself, if the class is an interface), * the value will be null. * * If any interface couldn't be resolved, then the interfacesFullyResolved field will be set to false upon return. * * @return the set of interfaces that this class implements as a Map. */ @Nonnull protected LinkedHashMap getInterfaces() { if (!classPath.isArt() || classPath.oatVersion < 72) { return preDefaultMethodInterfaceSupplier.get(); } else { return postDefaultMethodInterfaceSupplier.get(); } } /** * This calculates the interfaces in the order required for vtable generation for dalvik and pre-default method ART */ @Nonnull private final Supplier> preDefaultMethodInterfaceSupplier = Suppliers.memoize(new Supplier>() { @Override public LinkedHashMap get() { Set unresolvedInterfaces = new HashSet(0); LinkedHashMap interfaces = Maps.newLinkedHashMap(); try { for (String interfaceType: getClassDef().getInterfaces()) { if (!interfaces.containsKey(interfaceType)) { ClassDef interfaceDef; try { interfaceDef = classPath.getClassDef(interfaceType); interfaces.put(interfaceType, interfaceDef); } catch (UnresolvedClassException ex) { interfaces.put(interfaceType, null); unresolvedInterfaces.add(interfaceType); interfacesFullyResolved = false; } ClassProto interfaceProto = (ClassProto) classPath.getClass(interfaceType); for (String superInterface: interfaceProto.getInterfaces().keySet()) { if (!interfaces.containsKey(superInterface)) { interfaces.put(superInterface, interfaceProto.getInterfaces().get(superInterface)); } } if (!interfaceProto.interfacesFullyResolved) { unresolvedInterfaces.addAll(interfaceProto.getUnresolvedInterfaces()); interfacesFullyResolved = false; } } } } catch (UnresolvedClassException ex) { interfaces.put(type, null); unresolvedInterfaces.add(type); interfacesFullyResolved = false; } // now add self and super class interfaces, required for common super class lookup // we don't really need ClassDef's for that, so let's just use null if (isInterface() && !interfaces.containsKey(getType())) { interfaces.put(getType(), null); } String superclass = getSuperclass(); try { if (superclass != null) { ClassProto superclassProto = (ClassProto) classPath.getClass(superclass); for (String superclassInterface: superclassProto.getInterfaces().keySet()) { if (!interfaces.containsKey(superclassInterface)) { interfaces.put(superclassInterface, null); } } if (!superclassProto.interfacesFullyResolved) { unresolvedInterfaces.addAll(superclassProto.getUnresolvedInterfaces()); interfacesFullyResolved = false; } } } catch (UnresolvedClassException ex) { unresolvedInterfaces.add(superclass); interfacesFullyResolved = false; } if (unresolvedInterfaces.size() > 0) { ClassProto.this.unresolvedInterfaces = unresolvedInterfaces; } return interfaces; } }); /** * This calculates the interfaces in the order required for vtable generation for post-default method ART */ @Nonnull private final Supplier> postDefaultMethodInterfaceSupplier = Suppliers.memoize(new Supplier>() { @Override public LinkedHashMap get() { Set unresolvedInterfaces = new HashSet(0); LinkedHashMap interfaces = Maps.newLinkedHashMap(); String superclass = getSuperclass(); if (superclass != null) { ClassProto superclassProto = (ClassProto) classPath.getClass(superclass); for (String superclassInterface: superclassProto.getInterfaces().keySet()) { interfaces.put(superclassInterface, null); } if (!superclassProto.interfacesFullyResolved) { unresolvedInterfaces.addAll(superclassProto.getUnresolvedInterfaces()); interfacesFullyResolved = false; } } try { for (String interfaceType: getClassDef().getInterfaces()) { if (!interfaces.containsKey(interfaceType)) { ClassProto interfaceProto = (ClassProto)classPath.getClass(interfaceType); try { for (Entry entry: interfaceProto.getInterfaces().entrySet()) { if (!interfaces.containsKey(entry.getKey())) { interfaces.put(entry.getKey(), entry.getValue()); } } } catch (UnresolvedClassException ex) { interfaces.put(interfaceType, null); unresolvedInterfaces.add(interfaceType); interfacesFullyResolved = false; } if (!interfaceProto.interfacesFullyResolved) { unresolvedInterfaces.addAll(interfaceProto.getUnresolvedInterfaces()); interfacesFullyResolved = false; } try { ClassDef interfaceDef = classPath.getClassDef(interfaceType); interfaces.put(interfaceType, interfaceDef); } catch (UnresolvedClassException ex) { interfaces.put(interfaceType, null); unresolvedInterfaces.add(interfaceType); interfacesFullyResolved = false; } } } } catch (UnresolvedClassException ex) { interfaces.put(type, null); unresolvedInterfaces.add(type); interfacesFullyResolved = false; } if (unresolvedInterfaces.size() > 0) { ClassProto.this.unresolvedInterfaces = unresolvedInterfaces; } return interfaces; } }); @Nonnull protected Set getUnresolvedInterfaces() { if (unresolvedInterfaces == null) { return ImmutableSet.of(); } return unresolvedInterfaces; } /** * Gets the interfaces directly implemented by this class, or the interfaces they transitively implement. * * This does not include any interfaces that are only implemented by a superclass * * @return An iterables of ClassDefs representing the directly or transitively implemented interfaces * @throws UnresolvedClassException if interfaces could not be fully resolved */ @Nonnull protected Iterable getDirectInterfaces() { Iterable directInterfaces = FluentIterable.from(getInterfaces().values()).filter(Predicates.notNull()); if (!interfacesFullyResolved) { throw new UnresolvedClassException("Interfaces for class %s not fully resolved: %s", getType(), Joiner.on(',').join(getUnresolvedInterfaces())); } return directInterfaces; } /** * Checks if this class implements the given interface. * * If the interfaces of this class cannot be fully resolved then this * method will either return true or throw an UnresolvedClassException * * @param iface The interface to check for * @return true if this class implements the given interface, otherwise false * @throws UnresolvedClassException if the interfaces for this class could not be fully resolved, and the interface * is not one of the interfaces that were successfully resolved */ @Override public boolean implementsInterface(@Nonnull String iface) { if (getInterfaces().containsKey(iface)) { return true; } if (!interfacesFullyResolved) { throw new UnresolvedClassException("Interfaces for class %s not fully resolved", getType()); } return false; } @Nullable @Override public String getSuperclass() { return getClassDef().getSuperclass(); } /** * This is a helper method for getCommonSuperclass * * It checks if this class is an interface, and if so, if other implements it. * * If this class is undefined, we go ahead and check if it is listed in other's interfaces. If not, we throw an * UndefinedClassException * * If the interfaces of other cannot be fully resolved, we check the interfaces that can be resolved. If not found, * we throw an UndefinedClassException * * @param other The class to check the interfaces of * @return true if this class is an interface (or is undefined) other implements this class * */ private boolean checkInterface(@Nonnull ClassProto other) { boolean isResolved = true; boolean isInterface = true; try { isInterface = isInterface(); } catch (UnresolvedClassException ex) { isResolved = false; // if we don't know if this class is an interface or not, // we can still try to call other.implementsInterface(this) } if (isInterface) { try { if (other.implementsInterface(getType())) { return true; } } catch (UnresolvedClassException ex) { // There are 2 possibilities here, depending on whether we were able to resolve this class. // 1. If this class is resolved, then we know it is an interface class. The other class either // isn't defined, or its interfaces couldn't be fully resolved. // In this case, we throw an UnresolvedClassException // 2. If this class is not resolved, we had tried to call implementsInterface anyway. We don't // know for sure if this class is an interface or not. We return false, and let processing // continue in getCommonSuperclass if (isResolved) { throw ex; } } } return false; } @Override @Nonnull public TypeProto getCommonSuperclass(@Nonnull TypeProto other) { // use the other type's more specific implementation if (!(other instanceof ClassProto)) { return other.getCommonSuperclass(this); } if (this == other || getType().equals(other.getType())) { return this; } if (this.getType().equals("Ljava/lang/Object;")) { return this; } if (other.getType().equals("Ljava/lang/Object;")) { return other; } boolean gotException = false; try { if (checkInterface((ClassProto)other)) { return this; } } catch (UnresolvedClassException ex) { gotException = true; } try { if (((ClassProto)other).checkInterface(this)) { return other; } } catch (UnresolvedClassException ex) { gotException = true; } if (gotException) { return classPath.getUnknownClass(); } List thisChain = Lists.newArrayList(this); Iterables.addAll(thisChain, TypeProtoUtils.getSuperclassChain(this)); List otherChain = Lists.newArrayList(other); Iterables.addAll(otherChain, TypeProtoUtils.getSuperclassChain(other)); // reverse them, so that the first entry is either Ljava/lang/Object; or Ujava/lang/Object; thisChain = Lists.reverse(thisChain); otherChain = Lists.reverse(otherChain); for (int i=Math.min(thisChain.size(), otherChain.size())-1; i>=0; i--) { TypeProto typeProto = thisChain.get(i); if (typeProto.getType().equals(otherChain.get(i).getType())) { return typeProto; } } return classPath.getUnknownClass(); } @Override @Nullable public FieldReference getFieldByOffset(int fieldOffset) { if (getInstanceFields().size() == 0) { return null; } return getInstanceFields().get(fieldOffset); } @Override @Nullable public Method getMethodByVtableIndex(int vtableIndex) { List vtable = getVtable(); if (vtableIndex < 0 || vtableIndex >= vtable.size()) { return null; } return vtable.get(vtableIndex); } public int findMethodIndexInVtable(@Nonnull MethodReference method) { return findMethodIndexInVtable(getVtable(), method); } private int findMethodIndexInVtable(@Nonnull List vtable, MethodReference method) { for (int i=0; i vtable, MethodReference method) { for (int i=vtable.size() - 1; i>=0; i--) { Method candidate = vtable.get(i); if (MethodUtil.methodSignaturesMatch(candidate, method)) { if (!classPath.shouldCheckPackagePrivateAccess() || AnalyzedMethodUtil.canAccess(this, candidate, true, false, false)) { return i; } } } return -1; } @Nonnull public SparseArray getInstanceFields() { if (classPath.isArt()) { return artInstanceFieldsSupplier.get(); } else { return dalvikInstanceFieldsSupplier.get(); } } @Nonnull private final Supplier> dalvikInstanceFieldsSupplier = Suppliers.memoize(new Supplier>() { @Override public SparseArray get() { //This is a bit of an "involved" operation. We need to follow the same algorithm that dalvik uses to //arrange fields, so that we end up with the same field offsets (which is needed for deodexing). //See mydroid/dalvik/vm/oo/Class.c - computeFieldOffsets() ArrayList fields = getSortedInstanceFields(getClassDef()); final int fieldCount = fields.size(); //the "type" for each field in fields. 0=reference,1=wide,2=other byte[] fieldTypes = new byte[fields.size()]; for (int i=0; i front) { if (fieldTypes[back] == REFERENCE) { swap(fieldTypes, fields, front, back--); break; } back--; } } if (fieldTypes[front] != REFERENCE) { break; } } int startFieldOffset = 8; String superclassType = getSuperclass(); ClassProto superclass = null; if (superclassType != null) { superclass = (ClassProto) classPath.getClass(superclassType); startFieldOffset = superclass.getNextFieldOffset(); } int fieldIndexMod; if ((startFieldOffset % 8) == 0) { fieldIndexMod = 0; } else { fieldIndexMod = 1; } //next, we need to group all the wide fields after the reference fields. But the wide fields have to be //8-byte aligned. If we're on an odd field index, we need to insert a 32-bit field. If the next field //is already a 32-bit field, use that. Otherwise, find the first 32-bit field from the end and swap it in. //If there are no 32-bit fields, do nothing for now. We'll add padding when calculating the field offsets if (front < fieldCount && (front % 2) != fieldIndexMod) { if (fieldTypes[front] == WIDE) { //we need to swap in a 32-bit field, so the wide fields will be correctly aligned back = fieldCount - 1; while (back > front) { if (fieldTypes[back] == OTHER) { swap(fieldTypes, fields, front++, back); break; } back--; } } else { //there's already a 32-bit field here that we can use front++; } } //do the swap thing for wide fields back = fieldCount - 1; for (; front front) { if (fieldTypes[back] == WIDE) { swap(fieldTypes, fields, front, back--); break; } back--; } } if (fieldTypes[front] != WIDE) { break; } } SparseArray superFields; if (superclass != null) { superFields = superclass.getInstanceFields(); } else { superFields = new SparseArray(); } int superFieldCount = superFields.size(); //now the fields are in the correct order. Add them to the SparseArray and lookup, and calculate the offsets int totalFieldCount = superFieldCount + fieldCount; SparseArray instanceFields = new SparseArray(totalFieldCount); int fieldOffset; if (superclass != null && superFieldCount > 0) { for (int i=0; i getSortedInstanceFields(@Nonnull ClassDef classDef) { ArrayList fields = Lists.newArrayList(classDef.getInstanceFields()); Collections.sort(fields); return fields; } private void swap(byte[] fieldTypes, List fields, int position1, int position2) { byte tempType = fieldTypes[position1]; fieldTypes[position1] = fieldTypes[position2]; fieldTypes[position2] = tempType; Field tempField = fields.set(position1, fields.get(position2)); fields.set(position2, tempField); } }); private static abstract class FieldGap implements Comparable { public final int offset; public final int size; public static FieldGap newFieldGap(int offset, int size, int oatVersion) { if (oatVersion >= 67) { return new FieldGap(offset, size) { @Override public int compareTo(@Nonnull FieldGap o) { int result = Ints.compare(o.size, size); if (result != 0) { return result; } return Ints.compare(offset, o.offset); } }; } else { return new FieldGap(offset, size) { @Override public int compareTo(@Nonnull FieldGap o) { int result = Ints.compare(size, o.size); if (result != 0) { return result; } return Ints.compare(o.offset, offset); } }; } } private FieldGap(int offset, int size) { this.offset = offset; this.size = size; } } @Nonnull private final Supplier> artInstanceFieldsSupplier = Suppliers.memoize(new Supplier>() { @Override public SparseArray get() { // We need to follow the same algorithm that art uses to arrange fields, so that we end up with the // same field offsets, which is needed for deodexing. // See LinkFields() in art/runtime/class_linker.cc PriorityQueue gaps = new PriorityQueue(); SparseArray linkedFields = new SparseArray(); ArrayList fields = getSortedInstanceFields(getClassDef()); int fieldOffset = 0; String superclassType = getSuperclass(); if (superclassType != null) { // TODO: what to do if superclass doesn't exist? ClassProto superclass = (ClassProto) classPath.getClass(superclassType); SparseArray superFields = superclass.getInstanceFields(); FieldReference field = null; int lastOffset = 0; for (int i=0; i= fieldSize) { gaps.poll(); linkedFields.put(gap.offset, field); if (gap.size > fieldSize) { addFieldGap(gap.offset + fieldSize, gap.offset + gap.size, gaps); } } else { linkedFields.append(fieldOffset, field); fieldOffset += fieldSize; } } return linkedFields; } private void addFieldGap(int gapStart, int gapEnd, @Nonnull PriorityQueue gaps) { int offset = gapStart; while (offset < gapEnd) { int remaining = gapEnd - offset; if ((remaining >= 4) && (offset % 4 == 0)) { gaps.add(FieldGap.newFieldGap(offset, 4, classPath.oatVersion)); offset += 4; } else if (remaining >= 2 && (offset % 2 == 0)) { gaps.add(FieldGap.newFieldGap(offset, 2, classPath.oatVersion)); offset += 2; } else { gaps.add(FieldGap.newFieldGap(offset, 1, classPath.oatVersion)); offset += 1; } } } @Nonnull private ArrayList getSortedInstanceFields(@Nonnull ClassDef classDef) { ArrayList fields = Lists.newArrayList(classDef.getInstanceFields()); Collections.sort(fields, new Comparator() { @Override public int compare(Field field1, Field field2) { int result = Ints.compare(getFieldSortOrder(field1), getFieldSortOrder(field2)); if (result != 0) { return result; } result = field1.getName().compareTo(field2.getName()); if (result != 0) { return result; } return field1.getType().compareTo(field2.getType()); } }); return fields; } private int getFieldSortOrder(@Nonnull FieldReference field) { // The sort order is based on type size (except references are first), and then based on the // enum value of the primitive type for types of equal size. See: Primitive::Type enum // in art/runtime/primitive.h switch (field.getType().charAt(0)) { /* reference */ case '[': case 'L': return 0; /* 64 bit */ case 'J': return 1; case 'D': return 2; /* 32 bit */ case 'I': return 3; case 'F': return 4; /* 16 bit */ case 'C': return 5; case 'S': return 6; /* 8 bit */ case 'Z': return 7; case 'B': return 8; } throw new ExceptionWithContext("Invalid field type: %s", field.getType()); } private int getFieldSize(@Nonnull FieldReference field) { return getTypeSize(field.getType().charAt(0)); } }); private int getNextFieldOffset() { SparseArray instanceFields = getInstanceFields(); if (instanceFields.size() == 0) { return classPath.isArt() ? 0 : 8; } int lastItemIndex = instanceFields.size()-1; int fieldOffset = instanceFields.keyAt(lastItemIndex); FieldReference lastField = instanceFields.valueAt(lastItemIndex); if (classPath.isArt()) { return fieldOffset + getTypeSize(lastField.getType().charAt(0)); } else { switch (lastField.getType().charAt(0)) { case 'J': case 'D': return fieldOffset + 8; default: return fieldOffset + 4; } } } private static int getTypeSize(char type) { switch (type) { case 'J': case 'D': return 8; case '[': case 'L': case 'I': case 'F': return 4; case 'C': case 'S': return 2; case 'B': case 'Z': return 1; } throw new ExceptionWithContext("Invalid type: %s", type); } @Nonnull public List getVtable() { if (!classPath.isArt() || classPath.oatVersion < 72) { return preDefaultMethodVtableSupplier.get(); } else if (classPath.oatVersion < 87) { return buggyPostDefaultMethodVtableSupplier.get(); } else { return postDefaultMethodVtableSupplier.get(); } } //TODO: check the case when we have a package private method that overrides an interface method @Nonnull private final Supplier> preDefaultMethodVtableSupplier = Suppliers.memoize(new Supplier>() { @Override public List get() { List vtable = Lists.newArrayList(); //copy the virtual methods from the superclass String superclassType; try { superclassType = getSuperclass(); } catch (UnresolvedClassException ex) { vtable.addAll(((ClassProto)classPath.getClass("Ljava/lang/Object;")).getVtable()); vtableFullyResolved = false; return vtable; } if (superclassType != null) { ClassProto superclass = (ClassProto) classPath.getClass(superclassType); vtable.addAll(superclass.getVtable()); // if the superclass's vtable wasn't fully resolved, then we can't know where the new methods added by this // class should start, so we just propagate what we can from the parent and hope for the best. if (!superclass.vtableFullyResolved) { vtableFullyResolved = false; return vtable; } } //iterate over the virtual methods in the current class, and only add them when we don't already have the //method (i.e. if it was implemented by the superclass) if (!isInterface()) { addToVtable(getClassDef().getVirtualMethods(), vtable, true, true); // We use the current class for any vtable method references that we add, rather than the interface, so // we don't end up trying to call invoke-virtual using an interface, which will fail verification Iterable interfaces = getDirectInterfaces(); for (ClassDef interfaceDef: interfaces) { List interfaceMethods = Lists.newArrayList(); for (Method interfaceMethod: interfaceDef.getVirtualMethods()) { interfaceMethods.add(new ReparentedMethod(interfaceMethod, type)); } addToVtable(interfaceMethods, vtable, false, true); } } return vtable; } }); /** * This is the vtable supplier for a version of art that had buggy vtable calculation logic. In some cases it can * produce multiple vtable entries for a given virtual method. This supplier duplicates this buggy logic in order to * generate an identical vtable */ @Nonnull private final Supplier> buggyPostDefaultMethodVtableSupplier = Suppliers.memoize(new Supplier>() { @Override public List get() { List vtable = Lists.newArrayList(); //copy the virtual methods from the superclass String superclassType; try { superclassType = getSuperclass(); } catch (UnresolvedClassException ex) { vtable.addAll(((ClassProto)classPath.getClass("Ljava/lang/Object;")).getVtable()); vtableFullyResolved = false; return vtable; } if (superclassType != null) { ClassProto superclass = (ClassProto) classPath.getClass(superclassType); vtable.addAll(superclass.getVtable()); // if the superclass's vtable wasn't fully resolved, then we can't know where the new methods added by // this class should start, so we just propagate what we can from the parent and hope for the best. if (!superclass.vtableFullyResolved) { vtableFullyResolved = false; return vtable; } } //iterate over the virtual methods in the current class, and only add them when we don't already have the //method (i.e. if it was implemented by the superclass) if (!isInterface()) { addToVtable(getClassDef().getVirtualMethods(), vtable, true, true); List interfaces = Lists.newArrayList(getInterfaces().keySet()); List defaultMethods = Lists.newArrayList(); List defaultConflictMethods = Lists.newArrayList(); List mirandaMethods = Lists.newArrayList(); final HashMap methodOrder = Maps.newHashMap(); for (int i=interfaces.size()-1; i>=0; i--) { String interfaceType = interfaces.get(i); ClassDef interfaceDef = classPath.getClassDef(interfaceType); for (Method interfaceMethod : interfaceDef.getVirtualMethods()) { int vtableIndex = findMethodIndexInVtableReverse(vtable, interfaceMethod); Method oldVtableMethod = null; if (vtableIndex >= 0) { oldVtableMethod = vtable.get(vtableIndex); } for (int j=0; j= 0) { if (!isOverridableByDefaultMethod(vtable.get(vtableIndex))) { continue; } } int defaultMethodIndex = findMethodIndexInVtable(defaultMethods, interfaceMethod); if (defaultMethodIndex >= 0) { if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { ClassProto existingInterface = (ClassProto)classPath.getClass( defaultMethods.get(defaultMethodIndex).getDefiningClass()); if (!existingInterface.implementsInterface(interfaceMethod.getDefiningClass())) { Method removedMethod = defaultMethods.remove(defaultMethodIndex); defaultConflictMethods.add(removedMethod); } } continue; } int defaultConflictMethodIndex = findMethodIndexInVtable( defaultConflictMethods, interfaceMethod); if (defaultConflictMethodIndex >= 0) { // There's already a matching method in the conflict list, we don't need to do // anything else continue; } int mirandaMethodIndex = findMethodIndexInVtable(mirandaMethods, interfaceMethod); if (mirandaMethodIndex >= 0) { if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { ClassProto existingInterface = (ClassProto)classPath.getClass( mirandaMethods.get(mirandaMethodIndex).getDefiningClass()); if (!existingInterface.implementsInterface(interfaceMethod.getDefiningClass())) { Method oldMethod = mirandaMethods.remove(mirandaMethodIndex); int methodOrderValue = methodOrder.get(oldMethod); methodOrder.put(interfaceMethod, methodOrderValue); defaultMethods.add(interfaceMethod); } } continue; } if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { if (oldVtableMethod != null) { if (!interfaceMethodOverrides(interfaceMethod, oldVtableMethod)) { continue; } } defaultMethods.add(interfaceMethod); methodOrder.put(interfaceMethod, methodOrder.size()); } else { // TODO: do we need to check interfaceMethodOverrides here? if (oldVtableMethod == null) { mirandaMethods.add(interfaceMethod); methodOrder.put(interfaceMethod, methodOrder.size()); } } } } Comparator comparator = new Comparator() { @Override public int compare(MethodReference o1, MethodReference o2) { return Ints.compare(methodOrder.get(o1), methodOrder.get(o2)); } }; // The methods should be in the same order within each list as they were iterated over. // They can be misordered if, e.g. a method was originally added to the default list, but then moved // to the conflict list. Collections.sort(mirandaMethods, comparator); Collections.sort(defaultMethods, comparator); Collections.sort(defaultConflictMethods, comparator); vtable.addAll(mirandaMethods); vtable.addAll(defaultMethods); vtable.addAll(defaultConflictMethods); } return vtable; } }); @Nonnull private final Supplier> postDefaultMethodVtableSupplier = Suppliers.memoize(new Supplier>() { @Override public List get() { List vtable = Lists.newArrayList(); //copy the virtual methods from the superclass String superclassType; try { superclassType = getSuperclass(); } catch (UnresolvedClassException ex) { vtable.addAll(((ClassProto)classPath.getClass("Ljava/lang/Object;")).getVtable()); vtableFullyResolved = false; return vtable; } if (superclassType != null) { ClassProto superclass = (ClassProto) classPath.getClass(superclassType); vtable.addAll(superclass.getVtable()); // if the superclass's vtable wasn't fully resolved, then we can't know where the new methods added by // this class should start, so we just propagate what we can from the parent and hope for the best. if (!superclass.vtableFullyResolved) { vtableFullyResolved = false; return vtable; } } //iterate over the virtual methods in the current class, and only add them when we don't already have the //method (i.e. if it was implemented by the superclass) if (!isInterface()) { addToVtable(getClassDef().getVirtualMethods(), vtable, true, true); Iterable interfaces = Lists.reverse(Lists.newArrayList(getDirectInterfaces())); List defaultMethods = Lists.newArrayList(); List defaultConflictMethods = Lists.newArrayList(); List mirandaMethods = Lists.newArrayList(); final HashMap methodOrder = Maps.newHashMap(); for (ClassDef interfaceDef: interfaces) { for (Method interfaceMethod : interfaceDef.getVirtualMethods()) { int vtableIndex = findMethodIndexInVtable(vtable, interfaceMethod); if (vtableIndex >= 0) { if (interfaceMethodOverrides(interfaceMethod, vtable.get(vtableIndex))) { vtable.set(vtableIndex, interfaceMethod); } } else { int defaultMethodIndex = findMethodIndexInVtable(defaultMethods, interfaceMethod); if (defaultMethodIndex >= 0) { if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { ClassProto existingInterface = (ClassProto)classPath.getClass( defaultMethods.get(defaultMethodIndex).getDefiningClass()); if (!existingInterface.implementsInterface(interfaceMethod.getDefiningClass())) { Method removedMethod = defaultMethods.remove(defaultMethodIndex); defaultConflictMethods.add(removedMethod); } } continue; } int defaultConflictMethodIndex = findMethodIndexInVtable( defaultConflictMethods, interfaceMethod); if (defaultConflictMethodIndex >= 0) { // There's already a matching method in the conflict list, we don't need to do // anything else continue; } int mirandaMethodIndex = findMethodIndexInVtable(mirandaMethods, interfaceMethod); if (mirandaMethodIndex >= 0) { if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { ClassProto existingInterface = (ClassProto)classPath.getClass( mirandaMethods.get(mirandaMethodIndex).getDefiningClass()); if (!existingInterface.implementsInterface(interfaceMethod.getDefiningClass())) { Method oldMethod = mirandaMethods.remove(mirandaMethodIndex); int methodOrderValue = methodOrder.get(oldMethod); methodOrder.put(interfaceMethod, methodOrderValue); defaultMethods.add(interfaceMethod); } } continue; } if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { defaultMethods.add(interfaceMethod); methodOrder.put(interfaceMethod, methodOrder.size()); } else { mirandaMethods.add(interfaceMethod); methodOrder.put(interfaceMethod, methodOrder.size()); } } } } Comparator comparator = new Comparator() { @Override public int compare(MethodReference o1, MethodReference o2) { return Ints.compare(methodOrder.get(o1), methodOrder.get(o2)); } }; // The methods should be in the same order within each list as they were iterated over. // They can be misordered if, e.g. a method was originally added to the default list, but then moved // to the conflict list. Collections.sort(defaultMethods, comparator); Collections.sort(defaultConflictMethods, comparator); Collections.sort(mirandaMethods, comparator); addToVtable(defaultMethods, vtable, false, false); addToVtable(defaultConflictMethods, vtable, false, false); addToVtable(mirandaMethods, vtable, false, false); } return vtable; } }); private void addToVtable(@Nonnull Iterable localMethods, @Nonnull List vtable, boolean replaceExisting, boolean sort) { if (sort) { ArrayList methods = Lists.newArrayList(localMethods); Collections.sort(methods); localMethods = methods; } for (Method virtualMethod: localMethods) { int vtableIndex = findMethodIndexInVtable(vtable, virtualMethod); if (vtableIndex >= 0) { if (replaceExisting) { vtable.set(vtableIndex, virtualMethod); } } else { // we didn't find an equivalent method, so add it as a new entry vtable.add(virtualMethod); } } } private static byte getFieldType(@Nonnull FieldReference field) { switch (field.getType().charAt(0)) { case '[': case 'L': return 0; //REFERENCE case 'J': case 'D': return 1; //WIDE default: return 2; //OTHER } } private boolean isOverridableByDefaultMethod(@Nonnull Method method) { ClassProto classProto = (ClassProto)classPath.getClass(method.getDefiningClass()); return classProto.isInterface(); } /** * Checks if the interface method overrides the virtual or interface method2 * @param method A Method from an interface * @param method2 A Method from an interface or a class * @return true if the interface method overrides the virtual or interface method2 */ private boolean interfaceMethodOverrides(@Nonnull Method method, @Nonnull Method method2) { ClassProto classProto = (ClassProto)classPath.getClass(method2.getDefiningClass()); if (classProto.isInterface()) { ClassProto targetClassProto = (ClassProto)classPath.getClass(method.getDefiningClass()); return targetClassProto.implementsInterface(method2.getDefiningClass()); } else { return false; } } static class ReparentedMethod extends BaseMethodReference implements Method { private final Method method; private final String definingClass; public ReparentedMethod(Method method, String definingClass) { this.method = method; this.definingClass = definingClass; } @Nonnull @Override public String getDefiningClass() { return definingClass; } @Nonnull @Override public String getName() { return method.getName(); } @Nonnull @Override public List getParameterTypes() { return method.getParameterTypes(); } @Nonnull @Override public String getReturnType() { return method.getReturnType(); } @Nonnull @Override public List getParameters() { return method.getParameters(); } @Override public int getAccessFlags() { return method.getAccessFlags(); } @Nonnull @Override public Set getAnnotations() { return method.getAnnotations(); } @Nullable @Override public MethodImplementation getImplementation() { return method.getImplementation(); } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java000066400000000000000000000033121342202223400265710ustar00rootroot00000000000000/* * Copyright 2016, 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.analysis; import org.jf.dexlib2.iface.ClassDef; import javax.annotation.Nullable; public interface ClassProvider { @Nullable ClassDef getClassDef(String type); } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/CustomInlineMethodResolver.java000066400000000000000000000125141342202223400313110ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import com.google.common.io.Files; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.instruction.InlineIndexInstruction; import org.jf.dexlib2.immutable.ImmutableMethod; import org.jf.dexlib2.immutable.ImmutableMethodParameter; import org.jf.dexlib2.immutable.reference.ImmutableMethodReference; import org.jf.dexlib2.immutable.util.ParamUtil; import javax.annotation.Nonnull; import java.io.*; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class CustomInlineMethodResolver extends InlineMethodResolver { @Nonnull private final ClassPath classPath; @Nonnull private final Method[] inlineMethods; public CustomInlineMethodResolver(@Nonnull ClassPath classPath, @Nonnull String inlineTable) { this.classPath = classPath; StringReader reader = new StringReader(inlineTable); List lines = new ArrayList(); BufferedReader br = new BufferedReader(reader); try { String line = br.readLine(); while (line != null) { if (line.length() > 0) { lines.add(line); } line = br.readLine(); } } catch (IOException ex) { throw new RuntimeException("Error while parsing inline table", ex); } inlineMethods = new Method[lines.size()]; for (int i=0; i= inlineMethods.length) { throw new RuntimeException("Invalid method index: " + methodIndex); } return inlineMethods[methodIndex]; } private static final Pattern longMethodPattern = Pattern.compile("(L[^;]+;)->([^(]+)\\(([^)]*)\\)(.+)"); @Nonnull private Method parseAndResolveInlineMethod(@Nonnull String inlineMethod) { Matcher m = longMethodPattern.matcher(inlineMethod); if (!m.matches()) { assert false; throw new RuntimeException("Invalid method descriptor: " + inlineMethod); } String className = m.group(1); String methodName = m.group(2); Iterable methodParams = ParamUtil.parseParamString(m.group(3)); String methodRet = m.group(4); ImmutableMethodReference methodRef = new ImmutableMethodReference(className, methodName, methodParams, methodRet); int accessFlags = 0; boolean resolved = false; TypeProto typeProto = classPath.getClass(className); if (typeProto instanceof ClassProto) { ClassDef classDef = ((ClassProto)typeProto).getClassDef(); for (Method method: classDef.getMethods()) { if (method.equals(methodRef)) { resolved = true; accessFlags = method.getAccessFlags(); break; } } } if (!resolved) { throw new RuntimeException("Cannot resolve inline method: " + inlineMethod); } return new ImmutableMethod(className, methodName, methodParams, methodRet, accessFlags, null, null); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java000066400000000000000000000042641342202223400272410ustar00rootroot00000000000000/* * Copyright 2016, 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.analysis; import com.google.common.collect.Maps; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.DexFile; import javax.annotation.Nullable; import java.util.Map; public class DexClassProvider implements ClassProvider { private final DexFile dexFile; private Map classMap = Maps.newHashMap(); public DexClassProvider(DexFile dexFile) { this.dexFile = dexFile; for (ClassDef classDef: dexFile.getClasses()) { classMap.put(classDef.getType(), classDef); } } @Nullable @Override public ClassDef getClassDef(String type) { return classMap.get(type); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/InlineMethodResolver.java000066400000000000000000000247361342202223400301270ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import com.google.common.collect.ImmutableList; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.instruction.InlineIndexInstruction; import org.jf.dexlib2.iface.instruction.VariableRegisterInstruction; import org.jf.dexlib2.immutable.ImmutableMethod; import org.jf.dexlib2.immutable.ImmutableMethodParameter; import org.jf.dexlib2.immutable.util.ParamUtil; import javax.annotation.Nonnull; public abstract class InlineMethodResolver { // These are the possible values for the accessFlag field on a resolved inline method // We can't use, e.g. AccessFlags.STATIC.value, because we need them to be a constant in order to use them as cases // in switch statements public static final int STATIC = 0x8; // AccessFlags.STATIC.value; public static final int VIRTUAL = 0x1; // AccessFlags.PUBLIC.value; public static final int DIRECT = 0x2; // AccessFlags.PRIVATE.value; @Nonnull public static InlineMethodResolver createInlineMethodResolver(int odexVersion) { if (odexVersion == 35) { return new InlineMethodResolver_version35(); } else if (odexVersion == 36) { return new InlineMethodResolver_version36(); } else { throw new RuntimeException(String.format("odex version %d is not supported yet", odexVersion)); } } protected InlineMethodResolver() { } @Nonnull private static Method inlineMethod(int accessFlags, @Nonnull String cls, @Nonnull String name, @Nonnull String params, @Nonnull String returnType) { ImmutableList paramList = ImmutableList.copyOf(ParamUtil.parseParamString(params)); return new ImmutableMethod(cls, name, paramList, returnType, accessFlags, null, null); } @Nonnull public abstract Method resolveExecuteInline(@Nonnull AnalyzedInstruction instruction); private static class InlineMethodResolver_version35 extends InlineMethodResolver { private final Method[] inlineMethods; public InlineMethodResolver_version35() { inlineMethods = new Method[] { inlineMethod(STATIC, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"), inlineMethod(VIRTUAL, "Ljava/lang/String;", "charAt", "I", "C"), inlineMethod(VIRTUAL, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"), inlineMethod(VIRTUAL, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"), inlineMethod(VIRTUAL, "Ljava/lang/String;", "length", "", "I"), inlineMethod(STATIC, "Ljava/lang/Math;", "abs", "I", "I"), inlineMethod(STATIC, "Ljava/lang/Math;", "abs", "J", "J"), inlineMethod(STATIC, "Ljava/lang/Math;", "abs", "F", "F"), inlineMethod(STATIC, "Ljava/lang/Math;", "abs", "D", "D"), inlineMethod(STATIC, "Ljava/lang/Math;", "min", "II", "I"), inlineMethod(STATIC, "Ljava/lang/Math;", "max", "II", "I"), inlineMethod(STATIC, "Ljava/lang/Math;", "sqrt", "D", "D"), inlineMethod(STATIC, "Ljava/lang/Math;", "cos", "D", "D"), inlineMethod(STATIC, "Ljava/lang/Math;", "sin", "D", "D") }; } @Override @Nonnull public Method resolveExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) { InlineIndexInstruction instruction = (InlineIndexInstruction)analyzedInstruction.instruction; int inlineIndex = instruction.getInlineIndex(); if (inlineIndex < 0 || inlineIndex >= inlineMethods.length) { throw new RuntimeException("Invalid inline index: " + inlineIndex); } return inlineMethods[inlineIndex]; } } private static class InlineMethodResolver_version36 extends InlineMethodResolver { private final Method[] inlineMethods; private final Method indexOfIMethod; private final Method indexOfIIMethod; private final Method fastIndexOfMethod; private final Method isEmptyMethod; public InlineMethodResolver_version36() { //The 5th and 6th entries differ between froyo and gingerbread. We have to look at the parameters being //passed to distinguish between them. //froyo indexOfIMethod = inlineMethod(VIRTUAL, "Ljava/lang/String;", "indexOf", "I", "I"); indexOfIIMethod = inlineMethod(VIRTUAL, "Ljava/lang/String;", "indexOf", "II", "I"); //gingerbread fastIndexOfMethod = inlineMethod(DIRECT, "Ljava/lang/String;", "fastIndexOf", "II", "I"); isEmptyMethod = inlineMethod(VIRTUAL, "Ljava/lang/String;", "isEmpty", "", "Z"); inlineMethods = new Method[] { inlineMethod(STATIC, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"), inlineMethod(VIRTUAL, "Ljava/lang/String;", "charAt", "I", "C"), inlineMethod(VIRTUAL, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"), inlineMethod(VIRTUAL, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"), //froyo: deodexUtil.new InlineMethod(VIRTUAL, "Ljava/lang/String;", "indexOf", "I", "I"), //gingerbread: deodexUtil.new InlineMethod(VIRTUAL, "Ljava/lang/String;", "fastIndexOf", "II", "I"), null, //froyo: deodexUtil.new InlineMethod(VIRTUAL, "Ljava/lang/String;", "indexOf", "II", "I"), //gingerbread: deodexUtil.new InlineMethod(VIRTUAL, "Ljava/lang/String;", "isEmpty", "", "Z"), null, inlineMethod(VIRTUAL, "Ljava/lang/String;", "length", "", "I"), inlineMethod(STATIC, "Ljava/lang/Math;", "abs", "I", "I"), inlineMethod(STATIC, "Ljava/lang/Math;", "abs", "J", "J"), inlineMethod(STATIC, "Ljava/lang/Math;", "abs", "F", "F"), inlineMethod(STATIC, "Ljava/lang/Math;", "abs", "D", "D"), inlineMethod(STATIC, "Ljava/lang/Math;", "min", "II", "I"), inlineMethod(STATIC, "Ljava/lang/Math;", "max", "II", "I"), inlineMethod(STATIC, "Ljava/lang/Math;", "sqrt", "D", "D"), inlineMethod(STATIC, "Ljava/lang/Math;", "cos", "D", "D"), inlineMethod(STATIC, "Ljava/lang/Math;", "sin", "D", "D"), inlineMethod(STATIC, "Ljava/lang/Float;", "floatToIntBits", "F", "I"), inlineMethod(STATIC, "Ljava/lang/Float;", "floatToRawIntBits", "F", "I"), inlineMethod(STATIC, "Ljava/lang/Float;", "intBitsToFloat", "I", "F"), inlineMethod(STATIC, "Ljava/lang/Double;", "doubleToLongBits", "D", "J"), inlineMethod(STATIC, "Ljava/lang/Double;", "doubleToRawLongBits", "D", "J"), inlineMethod(STATIC, "Ljava/lang/Double;", "longBitsToDouble", "J", "D"), inlineMethod(STATIC, "Ljava/lang/StrictMath;", "abs", "I", "I"), inlineMethod(STATIC, "Ljava/lang/StrictMath;", "abs", "J", "J"), inlineMethod(STATIC, "Ljava/lang/StrictMath;", "abs", "F", "F"), inlineMethod(STATIC, "Ljava/lang/StrictMath;", "abs", "D", "D"), inlineMethod(STATIC, "Ljava/lang/StrictMath;", "min", "II", "I"), inlineMethod(STATIC, "Ljava/lang/StrictMath;", "max", "II", "I"), inlineMethod(STATIC, "Ljava/lang/StrictMath;", "sqrt", "D", "D"), }; } @Override @Nonnull public Method resolveExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) { InlineIndexInstruction instruction = (InlineIndexInstruction)analyzedInstruction.instruction; int inlineIndex = instruction.getInlineIndex(); if (inlineIndex < 0 || inlineIndex >= inlineMethods.length) { throw new RuntimeException("Invalid method index: " + inlineIndex); } if (inlineIndex == 4) { int parameterCount = ((VariableRegisterInstruction)instruction).getRegisterCount(); if (parameterCount == 2) { return indexOfIMethod; } else if (parameterCount == 3) { return fastIndexOfMethod; } else { throw new RuntimeException("Could not determine the correct inline method to use"); } } else if (inlineIndex == 5) { int parameterCount = ((VariableRegisterInstruction)instruction).getRegisterCount(); if (parameterCount == 3) { return indexOfIIMethod; } else if (parameterCount == 1) { return isEmptyMethod; } else { throw new RuntimeException("Could not determine the correct inline method to use"); } } return inlineMethods[inlineIndex]; } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java000066400000000000000000002700721342202223400267500ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.*; import org.jf.dexlib2.iface.instruction.*; import org.jf.dexlib2.iface.instruction.formats.*; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.reference.Reference; import org.jf.dexlib2.iface.reference.TypeReference; import org.jf.dexlib2.immutable.instruction.*; import org.jf.dexlib2.immutable.reference.ImmutableFieldReference; import org.jf.dexlib2.immutable.reference.ImmutableMethodReference; import org.jf.dexlib2.util.MethodUtil; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.dexlib2.util.TypeUtils; import org.jf.dexlib2.writer.util.TryListBuilder; import org.jf.util.BitSetUtils; import org.jf.util.ExceptionWithContext; import org.jf.util.SparseArray; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.BitSet; import java.util.List; /** * The MethodAnalyzer performs several functions. It "analyzes" the instructions and infers the register types * for each register, it can deodex odexed instructions, and it can verify the bytecode. The analysis and verification * are done in two separate passes, because the analysis has to process instructions multiple times in some cases, and * there's no need to perform the verification multiple times, so we wait until the method is fully analyzed and then * verify it. * * Before calling the analyze() method, you must have initialized the ClassPath by calling * ClassPath.InitializeClassPath */ public class MethodAnalyzer { @Nonnull private final Method method; @Nonnull private final MethodImplementation methodImpl; private final boolean normalizeVirtualMethods; private final int paramRegisterCount; @Nonnull private final ClassPath classPath; @Nullable private final InlineMethodResolver inlineResolver; // This contains all the AnalyzedInstruction instances, keyed by the code unit address of the instruction @Nonnull private final SparseArray analyzedInstructions = new SparseArray(0); // Which instructions have been analyzed, keyed by instruction index @Nonnull private final BitSet analyzedState; @Nullable private AnalysisException analysisException = null; // This is a dummy instruction that occurs immediately before the first real instruction. We can initialize the // register types for this instruction to the parameter types, in order to have them propagate to all of its // successors, e.g. the first real instruction, the first instructions in any exception handlers covering the first // instruction, etc. private final AnalyzedInstruction startOfMethod; public MethodAnalyzer(@Nonnull ClassPath classPath, @Nonnull Method method, @Nullable InlineMethodResolver inlineResolver, boolean normalizeVirtualMethods) { this.classPath = classPath; this.inlineResolver = inlineResolver; this.normalizeVirtualMethods = normalizeVirtualMethods; this.method = method; MethodImplementation methodImpl = method.getImplementation(); if (methodImpl == null) { throw new IllegalArgumentException("The method has no implementation"); } this.methodImpl = methodImpl; // Override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't // have to handle the case this special case of instruction being null, in the main class startOfMethod = new AnalyzedInstruction(this, new ImmutableInstruction10x(Opcode.NOP), -1, methodImpl.getRegisterCount()) { @Override protected boolean addPredecessor(AnalyzedInstruction predecessor) { throw new UnsupportedOperationException(); } @Override @Nonnull public RegisterType getPredecessorRegisterType(@Nonnull AnalyzedInstruction predecessor, int registerNumber) { throw new UnsupportedOperationException(); } }; buildInstructionList(); analyzedState = new BitSet(analyzedInstructions.size()); paramRegisterCount = MethodUtil.getParameterRegisterCount(method); analyze(); } @Nonnull public ClassPath getClassPath() { return classPath; } private void analyze() { Method method = this.method; MethodImplementation methodImpl = this.methodImpl; int totalRegisters = methodImpl.getRegisterCount(); int parameterRegisters = paramRegisterCount; int nonParameterRegisters = totalRegisters - parameterRegisters; //if this isn't a static method, determine which register is the "this" register and set the type to the //current class if (!MethodUtil.isStatic(method)) { int thisRegister = totalRegisters - parameterRegisters; //if this is a constructor, then set the "this" register to an uninitialized reference of the current class if (MethodUtil.isConstructor(method)) { setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister, RegisterType.getRegisterType(RegisterType.UNINIT_THIS, classPath.getClass(method.getDefiningClass()))); } else { setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister, RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(method.getDefiningClass()))); } propagateParameterTypes(totalRegisters-parameterRegisters+1); } else { propagateParameterTypes(totalRegisters-parameterRegisters); } RegisterType uninit = RegisterType.getRegisterType(RegisterType.UNINIT, null); for (int i=0; i=0; i=instructionsToAnalyze.nextSetBit(i+1)) { instructionsToAnalyze.clear(i); if (analyzedState.get(i)) { continue; } AnalyzedInstruction instructionToAnalyze = analyzedInstructions.valueAt(i); try { if (instructionToAnalyze.originalInstruction.getOpcode().odexOnly()) { //if we had deodexed an odex instruction in a previous pass, we might have more specific //register information now, so let's restore the original odexed instruction and //re-deodex it instructionToAnalyze.restoreOdexedInstruction(); } if (!analyzeInstruction(instructionToAnalyze)) { undeodexedInstructions.set(i); continue; } else { didSomething = true; undeodexedInstructions.clear(i); } } catch (AnalysisException ex) { this.analysisException = ex; int codeAddress = getInstructionAddress(instructionToAnalyze); ex.codeAddress = codeAddress; ex.addContext(String.format("opcode: %s", instructionToAnalyze.instruction.getOpcode().name)); ex.addContext(String.format("code address: %d", codeAddress)); ex.addContext(String.format("method: %s", ReferenceUtil.getReferenceString(method))); break; } analyzedState.set(instructionToAnalyze.getInstructionIndex()); for (AnalyzedInstruction successor: instructionToAnalyze.successors) { instructionsToAnalyze.set(successor.getInstructionIndex()); } } if (analysisException != null) { break; } } if (!didSomething) { break; } if (!undeodexedInstructions.isEmpty()) { for (int i=undeodexedInstructions.nextSetBit(0); i>=0; i=undeodexedInstructions.nextSetBit(i+1)) { instructionsToAnalyze.set(i); } } } while (true); //Now, go through and fix up any unresolvable odex instructions. These are usually odex instructions //that operate on a null register, and thus always throw an NPE. They can also be any sort of odex instruction //that occurs after an unresolvable odex instruction. We deodex if possible, or replace with an //UnresolvableOdexInstruction for (int i=0; i< analyzedInstructions.size(); i++) { AnalyzedInstruction analyzedInstruction = analyzedInstructions.valueAt(i); Instruction instruction = analyzedInstruction.getInstruction(); if (instruction.getOpcode().odexOnly()) { int objectRegisterNumber; switch (instruction.getOpcode().format) { case Format10x: analyzeOdexReturnVoid(analyzedInstruction, false); continue; case Format21c: case Format22c: analyzePutGetVolatile(analyzedInstruction, false); continue; case Format35c: analyzeInvokeDirectEmpty(analyzedInstruction, false); continue; case Format3rc: analyzeInvokeObjectInitRange(analyzedInstruction, false); continue; case Format22cs: objectRegisterNumber = ((Instruction22cs)instruction).getRegisterB(); break; case Format35mi: case Format35ms: objectRegisterNumber = ((FiveRegisterInstruction)instruction).getRegisterC(); break; case Format3rmi: case Format3rms: objectRegisterNumber = ((RegisterRangeInstruction)instruction).getStartRegister(); break; default: continue; } analyzedInstruction.setDeodexedInstruction( new UnresolvedOdexInstruction(instruction, objectRegisterNumber)); } } } private void propagateParameterTypes(int parameterStartRegister) { int i=0; for (MethodParameter parameter: method.getParameters()) { if (TypeUtils.isWideType(parameter)) { setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getWideRegisterType(parameter, true)); setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getWideRegisterType(parameter, false)); } else { setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getRegisterType(classPath, parameter)); } } } public List getAnalyzedInstructions() { return analyzedInstructions.getValues(); } public List getInstructions() { return Lists.transform(analyzedInstructions.getValues(), new Function() { @Nullable @Override public Instruction apply(@Nullable AnalyzedInstruction input) { if (input == null) { return null; } return input.instruction; } }); } @Nullable public AnalysisException getAnalysisException() { return analysisException; } public int getParamRegisterCount() { return paramRegisterCount; } public int getInstructionAddress(@Nonnull AnalyzedInstruction instruction) { return analyzedInstructions.keyAt(instruction.instructionIndex); } private void setDestinationRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull RegisterType registerType) { setPostRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(), registerType); } private void propagateChanges(@Nonnull BitSet changedInstructions, int registerNumber, boolean override) { //Using a for loop inside the while loop optimizes for the common case of the successors of an instruction //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on //the next iteration of the while loop. //This could also be done recursively, but in large methods it would likely cause very deep recursion. while (!changedInstructions.isEmpty()) { for (int instructionIndex=changedInstructions.nextSetBit(0); instructionIndex>=0; instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) { changedInstructions.clear(instructionIndex); propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber, changedInstructions, override); } } } private void overridePredecessorRegisterTypeAndPropagateChanges( @Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull AnalyzedInstruction predecessor, int registerNumber, @Nonnull RegisterType registerType) { BitSet changedInstructions = new BitSet(analyzedInstructions.size()); if (!analyzedInstruction.overridePredecessorRegisterType( predecessor, registerNumber, registerType, analyzedState)) { return; } changedInstructions.set(analyzedInstruction.instructionIndex); propagateChanges(changedInstructions, registerNumber, true); if (registerType.category == RegisterType.LONG_LO) { checkWidePair(registerNumber, analyzedInstruction); overridePredecessorRegisterTypeAndPropagateChanges(analyzedInstruction, predecessor, registerNumber + 1, RegisterType.LONG_HI_TYPE); } else if (registerType.category == RegisterType.DOUBLE_LO) { checkWidePair(registerNumber, analyzedInstruction); overridePredecessorRegisterTypeAndPropagateChanges(analyzedInstruction, predecessor, registerNumber + 1, RegisterType.DOUBLE_HI_TYPE); } } private void initializeRefAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction, int registerNumber, @Nonnull RegisterType registerType) { BitSet changedInstructions = new BitSet(analyzedInstructions.size()); if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) { return; } propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions, false); propagateChanges(changedInstructions, registerNumber, false); if (registerType.category == RegisterType.LONG_LO) { checkWidePair(registerNumber, analyzedInstruction); setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.LONG_HI_TYPE); } else if (registerType.category == RegisterType.DOUBLE_LO) { checkWidePair(registerNumber, analyzedInstruction); setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.DOUBLE_HI_TYPE); } } private void setPostRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction, int registerNumber, @Nonnull RegisterType registerType) { BitSet changedInstructions = new BitSet(analyzedInstructions.size()); if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) { return; } propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions, false); propagateChanges(changedInstructions, registerNumber, false); if (registerType.category == RegisterType.LONG_LO) { checkWidePair(registerNumber, analyzedInstruction); setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.LONG_HI_TYPE); } else if (registerType.category == RegisterType.DOUBLE_LO) { checkWidePair(registerNumber, analyzedInstruction); setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.DOUBLE_HI_TYPE); } } private void propagateRegisterToSuccessors(@Nonnull AnalyzedInstruction instruction, int registerNumber, @Nonnull BitSet changedInstructions, boolean override) { RegisterType postRegisterType = instruction.getPostInstructionRegisterType(registerNumber); for (AnalyzedInstruction successor: instruction.successors) { if (successor.mergeRegister(registerNumber, postRegisterType, analyzedState, override)) { changedInstructions.set(successor.instructionIndex); } } } private void buildInstructionList() { int registerCount = methodImpl.getRegisterCount(); ImmutableList instructions = ImmutableList.copyOf(methodImpl.getInstructions()); analyzedInstructions.ensureCapacity(instructions.size()); //first, create all the instructions and populate the instructionAddresses array int currentCodeAddress = 0; for (int i=0; i> tries = methodImpl.getTryBlocks(); tries = TryListBuilder.massageTryBlocks(tries); int triesIndex = 0; TryBlock currentTry = null; AnalyzedInstruction[] currentExceptionHandlers = null; AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[instructions.size()][]; if (tries != null) { for (int i=0; i< analyzedInstructions.size(); i++) { AnalyzedInstruction instruction = analyzedInstructions.valueAt(i); Opcode instructionOpcode = instruction.instruction.getOpcode(); currentCodeAddress = getInstructionAddress(instruction); //check if we have gone past the end of the current try if (currentTry != null) { if (currentTry.getStartCodeAddress() + currentTry.getCodeUnitCount() <= currentCodeAddress) { currentTry = null; triesIndex++; } } //check if the next try is applicable yet if (currentTry == null && triesIndex < tries.size()) { TryBlock tryBlock = tries.get(triesIndex); if (tryBlock.getStartCodeAddress() <= currentCodeAddress) { assert(tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount() > currentCodeAddress); currentTry = tryBlock; currentExceptionHandlers = buildExceptionHandlerArray(tryBlock); } } //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers //for the current instruction if (currentTry != null && instructionOpcode.canThrow()) { exceptionHandlers[i] = currentExceptionHandlers; } } } //finally, populate the successors and predecessors for each instruction. We start at the fake "StartOfMethod" //instruction and follow the execution path. Any unreachable code won't have any predecessors or successors, //and no reachable code will have an unreachable predessor or successor assert analyzedInstructions.size() > 0; BitSet instructionsToProcess = new BitSet(instructions.size()); addPredecessorSuccessor(startOfMethod, analyzedInstructions.valueAt(0), exceptionHandlers, instructionsToProcess); while (!instructionsToProcess.isEmpty()) { int currentInstructionIndex = instructionsToProcess.nextSetBit(0); instructionsToProcess.clear(currentInstructionIndex); AnalyzedInstruction instruction = analyzedInstructions.valueAt(currentInstructionIndex); Opcode instructionOpcode = instruction.instruction.getOpcode(); int instructionCodeAddress = getInstructionAddress(instruction); if (instruction.instruction.getOpcode().canContinue()) { if (currentInstructionIndex == analyzedInstructions.size() - 1) { throw new AnalysisException("Execution can continue past the last instruction"); } AnalyzedInstruction nextInstruction = analyzedInstructions.valueAt(currentInstructionIndex+1); addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess); } if (instruction.instruction instanceof OffsetInstruction) { OffsetInstruction offsetInstruction = (OffsetInstruction)instruction.instruction; if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) { AnalyzedInstruction analyzedSwitchPayload = analyzedInstructions.get( instructionCodeAddress + offsetInstruction.getCodeOffset()); if (analyzedSwitchPayload == null) { throw new AnalysisException("Invalid switch payload offset"); } SwitchPayload switchPayload = (SwitchPayload)analyzedSwitchPayload.instruction; for (SwitchElement switchElement: switchPayload.getSwitchElements()) { AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + switchElement.getOffset()); if (targetInstruction == null) { throw new AnalysisException("Invalid switch target offset"); } addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess); } } else if (instructionOpcode != Opcode.FILL_ARRAY_DATA) { int targetAddressOffset = offsetInstruction.getCodeOffset(); AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + targetAddressOffset); addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess); } } } } private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor, @Nonnull AnalyzedInstruction successor, @Nonnull AnalyzedInstruction[][] exceptionHandlers, @Nonnull BitSet instructionsToProcess) { addPredecessorSuccessor(predecessor, successor, exceptionHandlers, instructionsToProcess, false); } private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor, @Nonnull AnalyzedInstruction successor, @Nonnull AnalyzedInstruction[][] exceptionHandlers, @Nonnull BitSet instructionsToProcess, boolean allowMoveException) { if (!allowMoveException && successor.instruction.getOpcode() == Opcode.MOVE_EXCEPTION) { throw new AnalysisException("Execution can pass from the " + predecessor.instruction.getOpcode().name + " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) + " to the move-exception instruction at address 0x" + Integer.toHexString(getInstructionAddress(successor))); } if (!successor.addPredecessor(predecessor)) { return; } predecessor.addSuccessor(successor); instructionsToProcess.set(successor.getInstructionIndex()); //if the successor can throw an instruction, then we need to add the exception handlers as additional //successors to the predecessor (and then apply this same logic recursively if needed) //Technically, we should handle the monitor-exit instruction as a special case. The exception is actually //thrown *after* the instruction executes, instead of "before" the instruction executes, lke for any other //instruction. But since it doesn't modify any registers, we can treat it like any other instruction. AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex]; if (exceptionHandlersForSuccessor != null) { //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction //can throw an exception assert successor.instruction.getOpcode().canThrow(); for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) { addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, instructionsToProcess, true); } } } @Nonnull private AnalyzedInstruction[] buildExceptionHandlerArray(@Nonnull TryBlock tryBlock) { List exceptionHandlers = tryBlock.getExceptionHandlers(); AnalyzedInstruction[] handlerInstructions = new AnalyzedInstruction[exceptionHandlers.size()]; for (int i=0; i 0) { previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1); } if (previousInstruction == null || !previousInstruction.instruction.getOpcode().setsResult()) { throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " + "invoke-*/fill-new-array instruction"); } RegisterType resultRegisterType; ReferenceInstruction invokeInstruction = (ReferenceInstruction)previousInstruction.instruction; Reference reference = invokeInstruction.getReference(); if (reference instanceof MethodReference) { resultRegisterType = RegisterType.getRegisterType(classPath, ((MethodReference)reference).getReturnType()); } else { resultRegisterType = RegisterType.getRegisterType(classPath, (TypeReference)reference); } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType); } private void analyzeMoveException(@Nonnull AnalyzedInstruction analyzedInstruction) { int instructionAddress = getInstructionAddress(analyzedInstruction); RegisterType exceptionType = RegisterType.UNKNOWN_TYPE; for (TryBlock tryBlock: methodImpl.getTryBlocks()) { for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) { if (handler.getHandlerCodeAddress() == instructionAddress) { String type = handler.getExceptionType(); if (type == null) { exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass("Ljava/lang/Throwable;")); } else { exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(type)) .merge(exceptionType); } } } } if (exceptionType.category == RegisterType.UNKNOWN) { throw new AnalysisException("move-exception must be the first instruction in an exception handler block"); } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType); } private void analyzeOdexReturnVoid(AnalyzedInstruction analyzedInstruction) { analyzeOdexReturnVoid(analyzedInstruction, true); } private void analyzeOdexReturnVoid(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { Instruction10x deodexedInstruction = new ImmutableInstruction10x(Opcode.RETURN_VOID); analyzedInstruction.setDeodexedInstruction(deodexedInstruction); if (analyzeResult) { analyzeInstruction(analyzedInstruction); } } private void analyzeConst(@Nonnull AnalyzedInstruction analyzedInstruction) { NarrowLiteralInstruction instruction = (NarrowLiteralInstruction)analyzedInstruction.instruction; //we assume that the literal value is a valid value for the given instruction type, because it's impossible //to store an invalid literal with the instruction. so we don't need to check the type of the literal setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterTypeForLiteral(instruction.getNarrowLiteral())); } private void analyzeWideConst(@Nonnull AnalyzedInstruction analyzedInstruction) { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); } private void analyzeConstString(@Nonnull AnalyzedInstruction analyzedInstruction) { TypeProto stringClass = classPath.getClass("Ljava/lang/String;"); RegisterType stringType = RegisterType.getRegisterType(RegisterType.REFERENCE, stringClass); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType); } private void analyzeConstClass(@Nonnull AnalyzedInstruction analyzedInstruction) { TypeProto classClass = classPath.getClass("Ljava/lang/Class;"); RegisterType classType = RegisterType.getRegisterType(RegisterType.REFERENCE, classClass); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, classType); } private void analyzeCheckCast(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; TypeReference reference = (TypeReference)instruction.getReference(); RegisterType castRegisterType = RegisterType.getRegisterType(classPath, reference); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType); } public static boolean isNotWideningConversion(RegisterType originalType, RegisterType newType) { if (originalType.type == null || newType.type == null) { return true; } if (originalType.type.isInterface()) { return newType.type.implementsInterface(originalType.type.getType()); } else { TypeProto commonSuperclass = newType.type.getCommonSuperclass(originalType.type); if (commonSuperclass.getType().equals(originalType.type.getType())) { return true; } if (commonSuperclass.getType().equals(newType.type.getType())) { return false; } } return true; } static boolean canPropagateTypeAfterInstanceOf(AnalyzedInstruction analyzedInstanceOfInstruction, AnalyzedInstruction analyzedIfInstruction, ClassPath classPath) { if (!classPath.isArt()) { return false; } Instruction ifInstruction = analyzedIfInstruction.instruction; if (((Instruction21t)ifInstruction).getRegisterA() == analyzedInstanceOfInstruction.getDestinationRegister()) { Reference reference = ((Instruction22c)analyzedInstanceOfInstruction.getInstruction()).getReference(); RegisterType registerType = RegisterType.getRegisterType(classPath, (TypeReference)reference); try { if (registerType.type != null && !registerType.type.isInterface()) { int objectRegister = ((TwoRegisterInstruction)analyzedInstanceOfInstruction.getInstruction()) .getRegisterB(); RegisterType originalType = analyzedIfInstruction.getPreInstructionRegisterType(objectRegister); return isNotWideningConversion(originalType, registerType); } } catch (UnresolvedClassException ex) { return false; } } return false; } /** * Art uses a peephole optimization for an if-eqz or if-nez that occur immediately after an instance-of. It will * narrow the type if possible, and then NOP out any corresponding check-cast instruction later on */ private void analyzeIfEqzNez(@Nonnull AnalyzedInstruction analyzedInstruction) { if (classPath.isArt()) { int instructionIndex = analyzedInstruction.getInstructionIndex(); if (instructionIndex > 0) { if (analyzedInstruction.getPredecessorCount() != 1) { return; } AnalyzedInstruction prevAnalyzedInstruction = analyzedInstruction.getPredecessors().first(); if (prevAnalyzedInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF) { AnalyzedInstruction fallthroughInstruction = analyzedInstructions.valueAt( analyzedInstruction.getInstructionIndex() + 1); int nextAddress = getInstructionAddress(analyzedInstruction) + ((Instruction21t)analyzedInstruction.instruction).getCodeOffset(); AnalyzedInstruction branchInstruction = analyzedInstructions.get(nextAddress); int narrowingRegister = ((Instruction22c)prevAnalyzedInstruction.instruction).getRegisterB(); RegisterType originalType = analyzedInstruction.getPreInstructionRegisterType(narrowingRegister); Instruction22c instanceOfInstruction = (Instruction22c)prevAnalyzedInstruction.instruction; RegisterType newType = RegisterType.getRegisterType(classPath, (TypeReference)instanceOfInstruction.getReference()); for (int register : analyzedInstruction.getSetRegisters()) { if (analyzedInstruction.instruction.getOpcode() == Opcode.IF_EQZ) { overridePredecessorRegisterTypeAndPropagateChanges(fallthroughInstruction, analyzedInstruction, register, newType); overridePredecessorRegisterTypeAndPropagateChanges(branchInstruction, analyzedInstruction, register, originalType); } else { overridePredecessorRegisterTypeAndPropagateChanges(fallthroughInstruction, analyzedInstruction, register, originalType); overridePredecessorRegisterTypeAndPropagateChanges(branchInstruction, analyzedInstruction, register, newType); } } } } } } private void analyzeInstanceOf(@Nonnull AnalyzedInstruction analyzedInstruction) { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BOOLEAN_TYPE); } private void analyzeArrayLength(@Nonnull AnalyzedInstruction analyzedInstruction) { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.INTEGER_TYPE); } private void analyzeNewInstance(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; int register = ((OneRegisterInstruction)analyzedInstruction.instruction).getRegisterA(); RegisterType destRegisterType = analyzedInstruction.getPostInstructionRegisterType(register); if (destRegisterType.category != RegisterType.UNKNOWN) { //the post-instruction destination register will only be set if we have already analyzed this instruction //at least once. If this is the case, then the uninit reference has already been propagated to all //successors and nothing else needs to be done. assert destRegisterType.category == RegisterType.UNINIT_REF; return; } TypeReference typeReference = (TypeReference)instruction.getReference(); RegisterType classType = RegisterType.getRegisterType(classPath, typeReference); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterType(RegisterType.UNINIT_REF, classType.type)); } private void analyzeNewArray(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; TypeReference type = (TypeReference)instruction.getReference(); if (type.getType().charAt(0) != '[') { throw new AnalysisException("new-array used with non-array type"); } RegisterType arrayType = RegisterType.getRegisterType(classPath, type); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType); } private void analyzeFloatWideCmp(@Nonnull AnalyzedInstruction analyzedInstruction) { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BYTE_TYPE); } private void analyze32BitPrimitiveAget(@Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull RegisterType registerType) { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, registerType); } private void analyzeAgetWide(@Nonnull AnalyzedInstruction analyzedInstruction) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (arrayRegisterType.category != RegisterType.NULL) { if (arrayRegisterType.category != RegisterType.REFERENCE || !(arrayRegisterType.type instanceof ArrayProto)) { throw new AnalysisException("aget-wide used with non-array register: %s", arrayRegisterType.toString()); } ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; if (arrayProto.dimensions != 1) { throw new AnalysisException("aget-wide used with multi-dimensional array: %s", arrayRegisterType.toString()); } char arrayBaseType = arrayProto.getElementType().charAt(0); if (arrayBaseType == 'J') { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); } else if (arrayBaseType == 'D') { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); } else { throw new AnalysisException("aget-wide used with narrow array: %s", arrayRegisterType); } } else { // If the array register is null, we can assume that the destination register was meant to be a wide type. // This is the same behavior as dalvik's verifier setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); } } private void analyzeAgetObject(@Nonnull AnalyzedInstruction analyzedInstruction) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (arrayRegisterType.category != RegisterType.NULL) { if (arrayRegisterType.category != RegisterType.REFERENCE || !(arrayRegisterType.type instanceof ArrayProto)) { throw new AnalysisException("aget-object used with non-array register: %s", arrayRegisterType.toString()); } ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; String elementType = arrayProto.getImmediateElementType(); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(elementType))); } else { // If the array register is null, we can assume that the destination register was meant to be a reference // type, so we set the destination to NULL. This is the same behavior as dalvik's verifier setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.NULL_TYPE); } } private void analyze32BitPrimitiveIgetSget(@Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull RegisterType registerType) { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, registerType); } private void analyzeIgetSgetWideObject(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction referenceInstruction = (ReferenceInstruction)analyzedInstruction.instruction; FieldReference fieldReference = (FieldReference)referenceInstruction.getReference(); RegisterType fieldType = RegisterType.getRegisterType(classPath, fieldReference.getType()); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType); } private void analyzeInvokeDirect(@Nonnull AnalyzedInstruction analyzedInstruction) { FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction; analyzeInvokeDirectCommon(analyzedInstruction, instruction.getRegisterC()); } private void analyzeInvokeDirectRange(@Nonnull AnalyzedInstruction analyzedInstruction) { RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction; analyzeInvokeDirectCommon(analyzedInstruction, instruction.getStartRegister()); } private void analyzeInvokeDirectCommon(@Nonnull AnalyzedInstruction analyzedInstruction, int objectRegister) { // This handles the case of invoking a constructor on an uninitialized reference. This propagates the // initialized type for the object register, and also any known aliased registers. // // In some cases, unrelated uninitialized references may not have been propagated past this instruction. This // happens when propagating those types and the type of object register of this instruction isn't known yet. // In this case, we can't determine if the uninitialized reference being propagated in an alias of the object // register, so we don't stop propagation. // // We check for any of these unpropagated uninitialized references here and propagate them. if (analyzedInstruction.isInvokeInit()) { RegisterType uninitRef = analyzedInstruction.getPreInstructionRegisterType(objectRegister); if (uninitRef.category != RegisterType.UNINIT_REF && uninitRef.category != RegisterType.UNINIT_THIS) { assert analyzedInstruction.getSetRegisters().isEmpty(); return; } RegisterType initRef = RegisterType.getRegisterType(RegisterType.REFERENCE, uninitRef.type); for (int register: analyzedInstruction.getSetRegisters()) { RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register); if (registerType == uninitRef) { setPostRegisterTypeAndPropagateChanges(analyzedInstruction, register, initRef); } else { // This is unrelated uninitialized reference. propagate it as-is setPostRegisterTypeAndPropagateChanges(analyzedInstruction, register, registerType); } } } } private void analyzeUnaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull RegisterType destRegisterType) { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); } private void analyzeBinaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { if (checkForBoolean) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; RegisterType source1RegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); RegisterType source2RegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC()); if (BooleanCategories.get(source1RegisterType.category) && BooleanCategories.get(source2RegisterType.category)) { destRegisterType = RegisterType.BOOLEAN_TYPE; } } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); } private void analyzeBinary2AddrOp(@Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { if (checkForBoolean) { TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; RegisterType source1RegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA()); RegisterType source2RegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (BooleanCategories.get(source1RegisterType.category) && BooleanCategories.get(source2RegisterType.category)) { destRegisterType = RegisterType.BOOLEAN_TYPE; } } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); } private void analyzeLiteralBinaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { if (checkForBoolean) { TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (BooleanCategories.get(sourceRegisterType.category)) { int literal = ((NarrowLiteralInstruction)analyzedInstruction.instruction).getNarrowLiteral(); if (literal == 0 || literal == 1) { destRegisterType = RegisterType.BOOLEAN_TYPE; } } } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); } private RegisterType getDestTypeForLiteralShiftRight(@Nonnull AnalyzedInstruction analyzedInstruction, boolean signedShift) { TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), Primitive32BitCategories); long literalShift = ((NarrowLiteralInstruction)analyzedInstruction.instruction).getNarrowLiteral(); if (literalShift == 0) { return sourceRegisterType; } RegisterType destRegisterType; if (!signedShift) { destRegisterType = RegisterType.INTEGER_TYPE; } else { destRegisterType = sourceRegisterType; } literalShift = literalShift & 0x1f; switch (sourceRegisterType.category) { case RegisterType.INTEGER: case RegisterType.FLOAT: if (!signedShift) { if (literalShift > 24) { return RegisterType.POS_BYTE_TYPE; } if (literalShift >= 16) { return RegisterType.CHAR_TYPE; } } else { if (literalShift >= 24) { return RegisterType.BYTE_TYPE; } if (literalShift >= 16) { return RegisterType.SHORT_TYPE; } } break; case RegisterType.SHORT: if (signedShift && literalShift >= 8) { return RegisterType.BYTE_TYPE; } break; case RegisterType.POS_SHORT: if (literalShift >= 8) { return RegisterType.POS_BYTE_TYPE; } break; case RegisterType.CHAR: if (literalShift > 8) { return RegisterType.POS_BYTE_TYPE; } break; case RegisterType.BYTE: break; case RegisterType.POS_BYTE: return RegisterType.POS_BYTE_TYPE; case RegisterType.NULL: case RegisterType.ONE: case RegisterType.BOOLEAN: return RegisterType.NULL_TYPE; default: assert false; } return destRegisterType; } private void analyzeExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) { if (inlineResolver == null) { throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing"); } Instruction35mi instruction = (Instruction35mi)analyzedInstruction.instruction; Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction); Opcode deodexedOpcode; int acccessFlags = resolvedMethod.getAccessFlags(); if (AccessFlags.STATIC.isSet(acccessFlags)) { deodexedOpcode = Opcode.INVOKE_STATIC; } else if (AccessFlags.PRIVATE.isSet(acccessFlags)) { deodexedOpcode = Opcode.INVOKE_DIRECT; } else { deodexedOpcode = Opcode.INVOKE_VIRTUAL; } Instruction35c deodexedInstruction = new ImmutableInstruction35c(deodexedOpcode, instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod); analyzedInstruction.setDeodexedInstruction(deodexedInstruction); analyzeInstruction(analyzedInstruction); } private void analyzeExecuteInlineRange(@Nonnull AnalyzedInstruction analyzedInstruction) { if (inlineResolver == null) { throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing"); } Instruction3rmi instruction = (Instruction3rmi)analyzedInstruction.instruction; Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction); Opcode deodexedOpcode; int acccessFlags = resolvedMethod.getAccessFlags(); if (AccessFlags.STATIC.isSet(acccessFlags)) { deodexedOpcode = Opcode.INVOKE_STATIC_RANGE; } else if (AccessFlags.PRIVATE.isSet(acccessFlags)) { deodexedOpcode = Opcode.INVOKE_DIRECT_RANGE; } else { deodexedOpcode = Opcode.INVOKE_VIRTUAL_RANGE; } Instruction3rc deodexedInstruction = new ImmutableInstruction3rc(deodexedOpcode, instruction.getStartRegister(), instruction.getRegisterCount(), resolvedMethod); analyzedInstruction.setDeodexedInstruction(deodexedInstruction); analyzeInstruction(analyzedInstruction); } private void analyzeInvokeDirectEmpty(@Nonnull AnalyzedInstruction analyzedInstruction) { analyzeInvokeDirectEmpty(analyzedInstruction, true); } private void analyzeInvokeDirectEmpty(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction; Instruction35c deodexedInstruction = new ImmutableInstruction35c(Opcode.INVOKE_DIRECT, instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), instruction.getReference()); analyzedInstruction.setDeodexedInstruction(deodexedInstruction); if (analyzeResult) { analyzeInstruction(analyzedInstruction); } } private void analyzeInvokeObjectInitRange(@Nonnull AnalyzedInstruction analyzedInstruction) { analyzeInvokeObjectInitRange(analyzedInstruction, true); } private void analyzeInvokeObjectInitRange(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction; Instruction deodexedInstruction; int startRegister = instruction.getStartRegister(); // hack: we should be using instruction.getRegisterCount, but some tweaked versions of dalvik appear // to generate invoke-object-init/range instructions with an invalid register count. We know it should // always be 1, so just use that. int registerCount = 1; if (startRegister < 16) { deodexedInstruction = new ImmutableInstruction35c(Opcode.INVOKE_DIRECT, registerCount, startRegister, 0, 0, 0, 0, instruction.getReference()); } else { deodexedInstruction = new ImmutableInstruction3rc(Opcode.INVOKE_DIRECT_RANGE, startRegister, registerCount, instruction.getReference()); } analyzedInstruction.setDeodexedInstruction(deodexedInstruction); if (analyzeResult) { analyzeInstruction(analyzedInstruction); } } private boolean analyzeIputIgetQuick(@Nonnull AnalyzedInstruction analyzedInstruction) { Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction; int fieldOffset = instruction.getFieldOffset(); RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), ReferenceOrUninitCategories); if (objectRegisterType.category == RegisterType.NULL) { return false; } TypeProto objectRegisterTypeProto = objectRegisterType.type; assert objectRegisterTypeProto != null; TypeProto classTypeProto = classPath.getClass(objectRegisterTypeProto.getType()); FieldReference resolvedField = classTypeProto.getFieldByOffset(fieldOffset); if (resolvedField == null) { throw new AnalysisException("Could not resolve the field in class %s at offset %d", objectRegisterType.type.getType(), fieldOffset); } ClassDef thisClass = classPath.getClassDef(method.getDefiningClass()); if (!TypeUtils.canAccessClass(thisClass.getType(), classPath.getClassDef(resolvedField.getDefiningClass()))) { // the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different // than resolvedField.getDefiningClass()), and walk up the class hierarchy. ClassDef fieldClass = classPath.getClassDef(objectRegisterTypeProto.getType()); while (!TypeUtils.canAccessClass(thisClass.getType(), fieldClass)) { String superclass = fieldClass.getSuperclass(); if (superclass == null) { throw new ExceptionWithContext("Couldn't find accessible class while resolving field %s", ReferenceUtil.getShortFieldDescriptor(resolvedField)); } fieldClass = classPath.getClassDef(superclass); } // fieldClass is now the first accessible class found. Now. we need to make sure that the field is // actually valid for this class FieldReference newResolvedField = classPath.getClass(fieldClass.getType()).getFieldByOffset(fieldOffset); if (newResolvedField == null) { throw new ExceptionWithContext("Couldn't find accessible class while resolving field %s", ReferenceUtil.getShortFieldDescriptor(resolvedField)); } resolvedField = new ImmutableFieldReference(fieldClass.getType(), newResolvedField.getName(), newResolvedField.getType()); } String fieldType = resolvedField.getType(); Opcode opcode = classPath.getFieldInstructionMapper().getAndCheckDeodexedOpcode( fieldType, instruction.getOpcode()); Instruction22c deodexedInstruction = new ImmutableInstruction22c(opcode, (byte)instruction.getRegisterA(), (byte)instruction.getRegisterB(), resolvedField); analyzedInstruction.setDeodexedInstruction(deodexedInstruction); analyzeInstruction(analyzedInstruction); return true; } private boolean analyzeInvokeVirtual(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isRange) { MethodReference targetMethod; if (!normalizeVirtualMethods) { return true; } if (isRange) { Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction; targetMethod = (MethodReference)instruction.getReference(); } else { Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction; targetMethod = (MethodReference)instruction.getReference(); } MethodReference replacementMethod = normalizeMethodReference(targetMethod); if (replacementMethod == null || replacementMethod.equals(targetMethod)) { return true; } Instruction deodexedInstruction; if (isRange) { Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction; deodexedInstruction = new ImmutableInstruction3rc(instruction.getOpcode(), instruction.getStartRegister(), instruction.getRegisterCount(), replacementMethod); } else { Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction; deodexedInstruction = new ImmutableInstruction35c(instruction.getOpcode(), instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), replacementMethod); } analyzedInstruction.setDeodexedInstruction(deodexedInstruction); return true; } private boolean analyzeInvokeVirtualQuick(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isSuper, boolean isRange) { int methodIndex; int objectRegister; if (isRange) { Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction; methodIndex = instruction.getVtableIndex(); objectRegister = instruction.getStartRegister(); } else { Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction; methodIndex = instruction.getVtableIndex(); objectRegister = instruction.getRegisterC(); } RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, objectRegister, ReferenceOrUninitCategories); TypeProto objectRegisterTypeProto = objectRegisterType.type; if (objectRegisterType.category == RegisterType.NULL) { return false; } assert objectRegisterTypeProto != null; MethodReference resolvedMethod; if (isSuper) { // invoke-super is only used for the same class that we're currently in TypeProto typeProto = classPath.getClass(method.getDefiningClass()); TypeProto superType; String superclassType = typeProto.getSuperclass(); if (superclassType != null) { superType = classPath.getClass(superclassType); } else { // This is either java.lang.Object, or an UnknownClassProto superType = typeProto; } resolvedMethod = superType.getMethodByVtableIndex(methodIndex); } else { resolvedMethod = objectRegisterTypeProto.getMethodByVtableIndex(methodIndex); } if (resolvedMethod == null) { throw new AnalysisException("Could not resolve the method in class %s at index %d", objectRegisterType.type.getType(), methodIndex); } // no need to check class access for invoke-super. A class can obviously access its superclass. ClassDef thisClass = classPath.getClassDef(method.getDefiningClass()); if (classPath.getClass(resolvedMethod.getDefiningClass()).isInterface()) { resolvedMethod = new ReparentedMethodReference(resolvedMethod, objectRegisterTypeProto.getType()); } else if (!isSuper && !TypeUtils.canAccessClass( thisClass.getType(), classPath.getClassDef(resolvedMethod.getDefiningClass()))) { // the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different // than resolvedMethod.getDefiningClass()), and walk up the class hierarchy. ClassDef methodClass = classPath.getClassDef(objectRegisterTypeProto.getType()); while (!TypeUtils.canAccessClass(thisClass.getType(), methodClass)) { String superclass = methodClass.getSuperclass(); if (superclass == null) { throw new ExceptionWithContext("Couldn't find accessible class while resolving method %s", ReferenceUtil.getMethodDescriptor(resolvedMethod, true)); } methodClass = classPath.getClassDef(superclass); } // methodClass is now the first accessible class found. Now. we need to make sure that the method is // actually valid for this class MethodReference newResolvedMethod = classPath.getClass(methodClass.getType()).getMethodByVtableIndex(methodIndex); if (newResolvedMethod == null) { throw new ExceptionWithContext("Couldn't find accessible class while resolving method %s", ReferenceUtil.getMethodDescriptor(resolvedMethod, true)); } resolvedMethod = newResolvedMethod; resolvedMethod = new ImmutableMethodReference(methodClass.getType(), resolvedMethod.getName(), resolvedMethod.getParameterTypes(), resolvedMethod.getReturnType()); } if (normalizeVirtualMethods) { MethodReference replacementMethod = normalizeMethodReference(resolvedMethod); if (replacementMethod != null) { resolvedMethod = replacementMethod; } } Instruction deodexedInstruction; if (isRange) { Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction; Opcode opcode; if (isSuper) { opcode = Opcode.INVOKE_SUPER_RANGE; } else { opcode = Opcode.INVOKE_VIRTUAL_RANGE; } deodexedInstruction = new ImmutableInstruction3rc(opcode, instruction.getStartRegister(), instruction.getRegisterCount(), resolvedMethod); } else { Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction; Opcode opcode; if (isSuper) { opcode = Opcode.INVOKE_SUPER; } else { opcode = Opcode.INVOKE_VIRTUAL; } deodexedInstruction = new ImmutableInstruction35c(opcode, instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod); } analyzedInstruction.setDeodexedInstruction(deodexedInstruction); analyzeInstruction(analyzedInstruction); return true; } private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction) { return analyzePutGetVolatile(analyzedInstruction, true); } private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { FieldReference field = (FieldReference)((ReferenceInstruction)analyzedInstruction.instruction).getReference(); String fieldType = field.getType(); Opcode originalOpcode = analyzedInstruction.instruction.getOpcode(); Opcode opcode = classPath.getFieldInstructionMapper().getAndCheckDeodexedOpcode( fieldType, originalOpcode); Instruction deodexedInstruction; if (originalOpcode.isStaticFieldAccessor()) { OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.instruction; deodexedInstruction = new ImmutableInstruction21c(opcode, instruction.getRegisterA(), field); } else { TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; deodexedInstruction = new ImmutableInstruction22c(opcode, instruction.getRegisterA(), instruction.getRegisterB(), field); } analyzedInstruction.setDeodexedInstruction(deodexedInstruction); if (analyzeResult) { analyzeInstruction(analyzedInstruction); } return true; } @Nonnull private static RegisterType getAndCheckSourceRegister(@Nonnull AnalyzedInstruction analyzedInstruction, int registerNumber, BitSet validCategories) { assert registerNumber >= 0 && registerNumber < analyzedInstruction.postRegisterMap.length; RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNumber); checkRegister(registerType, registerNumber, validCategories); if (validCategories == WideLowCategories) { checkRegister(registerType, registerNumber, WideLowCategories); checkWidePair(registerNumber, analyzedInstruction); RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNumber + 1); checkRegister(secondRegisterType, registerNumber+1, WideHighCategories); } return registerType; } private static void checkRegister(RegisterType registerType, int registerNumber, BitSet validCategories) { if (!validCategories.get(registerType.category)) { throw new AnalysisException(String.format("Invalid register type %s for register v%d.", registerType.toString(), registerNumber)); } } private static void checkWidePair(int registerNumber, AnalyzedInstruction analyzedInstruction) { if (registerNumber + 1 >= analyzedInstruction.postRegisterMap.length) { throw new AnalysisException(String.format("v%d cannot be used as the first register in a wide register" + "pair because it is the last register.", registerNumber)); } } @Nullable private MethodReference normalizeMethodReference(@Nonnull MethodReference methodRef) { TypeProto typeProto = classPath.getClass(methodRef.getDefiningClass()); int methodIndex; try { methodIndex = typeProto.findMethodIndexInVtable(methodRef); } catch (UnresolvedClassException ex) { return null; } if (methodIndex < 0) { return null; } ClassProto thisClass = (ClassProto)classPath.getClass(method.getDefiningClass()); Method replacementMethod = typeProto.getMethodByVtableIndex(methodIndex); assert replacementMethod != null; while (true) { String superType = typeProto.getSuperclass(); if (superType == null) { break; } typeProto = classPath.getClass(superType); Method resolvedMethod = typeProto.getMethodByVtableIndex(methodIndex); if (resolvedMethod == null) { break; } if (!resolvedMethod.equals(replacementMethod)) { if (!AnalyzedMethodUtil.canAccess(thisClass, resolvedMethod, false, false, true)) { continue; } replacementMethod = resolvedMethod; } } return replacementMethod; } private static class ReparentedMethodReference extends BaseMethodReference { private final MethodReference baseReference; private final String definingClass; public ReparentedMethodReference(MethodReference baseReference, String definingClass) { this.baseReference = baseReference; this.definingClass = definingClass; } @Override @Nonnull public String getName() { return baseReference.getName(); } @Override @Nonnull public List getParameterTypes() { return baseReference.getParameterTypes(); } @Override @Nonnull public String getReturnType() { return baseReference.getReturnType(); } @Nonnull @Override public String getDefiningClass() { return definingClass; } } }smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/OdexedFieldInstructionMapper.java000066400000000000000000000271721342202223400316060ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import org.jf.dexlib2.Opcode; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; public class OdexedFieldInstructionMapper { private static final int GET = 0; private static final int PUT = 1; private static final int INSTANCE = 0; private static final int STATIC = 1; private static final int PRIMITIVE = 0; private static final int WIDE = 1; private static final int REFERENCE = 2; private static class FieldOpcode { public final char type; public final boolean isStatic; @Nonnull public final Opcode normalOpcode; @Nullable public final Opcode quickOpcode; @Nullable public final Opcode volatileOpcode; public FieldOpcode(char type, @Nonnull Opcode normalOpcode, @Nullable Opcode quickOpcode, @Nullable Opcode volatileOpcode) { this.type = type; this.isStatic = false; this.normalOpcode = normalOpcode; this.quickOpcode = quickOpcode; this.volatileOpcode = volatileOpcode; } public FieldOpcode(char type, boolean isStatic, @Nonnull Opcode normalOpcode, @Nullable Opcode volatileOpcode) { this.type = type; this.isStatic = isStatic; this.normalOpcode = normalOpcode; this.quickOpcode = null; this.volatileOpcode = volatileOpcode; } public FieldOpcode(char type, @Nonnull Opcode normalOpcode, @Nullable Opcode quickOpcode) { this.type = type; this.isStatic = false; this.normalOpcode = normalOpcode; this.quickOpcode = quickOpcode; this.volatileOpcode = null; } } private static final FieldOpcode[] dalvikFieldOpcodes = new FieldOpcode[] { new FieldOpcode('Z', Opcode.IGET_BOOLEAN, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE), new FieldOpcode('B', Opcode.IGET_BYTE, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE), new FieldOpcode('S', Opcode.IGET_SHORT, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE), new FieldOpcode('C', Opcode.IGET_CHAR, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE), new FieldOpcode('I', Opcode.IGET, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE), new FieldOpcode('F', Opcode.IGET, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE), new FieldOpcode('J', Opcode.IGET_WIDE, Opcode.IGET_WIDE_QUICK, Opcode.IGET_WIDE_VOLATILE), new FieldOpcode('D', Opcode.IGET_WIDE, Opcode.IGET_WIDE_QUICK, Opcode.IGET_WIDE_VOLATILE), new FieldOpcode('L', Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_QUICK, Opcode.IGET_OBJECT_VOLATILE), new FieldOpcode('[', Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_QUICK, Opcode.IGET_OBJECT_VOLATILE), new FieldOpcode('Z', Opcode.IPUT_BOOLEAN, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE), new FieldOpcode('B', Opcode.IPUT_BYTE, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE), new FieldOpcode('S', Opcode.IPUT_SHORT, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE), new FieldOpcode('C', Opcode.IPUT_CHAR, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE), new FieldOpcode('I', Opcode.IPUT, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE), new FieldOpcode('F', Opcode.IPUT, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE), new FieldOpcode('J', Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_QUICK, Opcode.IPUT_WIDE_VOLATILE), new FieldOpcode('D', Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_QUICK, Opcode.IPUT_WIDE_VOLATILE), new FieldOpcode('L', Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_QUICK, Opcode.IPUT_OBJECT_VOLATILE), new FieldOpcode('[', Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_QUICK, Opcode.IPUT_OBJECT_VOLATILE), new FieldOpcode('Z', true, Opcode.SPUT_BOOLEAN, Opcode.SPUT_VOLATILE), new FieldOpcode('B', true, Opcode.SPUT_BYTE, Opcode.SPUT_VOLATILE), new FieldOpcode('S', true, Opcode.SPUT_SHORT, Opcode.SPUT_VOLATILE), new FieldOpcode('C', true, Opcode.SPUT_CHAR, Opcode.SPUT_VOLATILE), new FieldOpcode('I', true, Opcode.SPUT, Opcode.SPUT_VOLATILE), new FieldOpcode('F', true, Opcode.SPUT, Opcode.SPUT_VOLATILE), new FieldOpcode('J', true, Opcode.SPUT_WIDE, Opcode.SPUT_WIDE_VOLATILE), new FieldOpcode('D', true, Opcode.SPUT_WIDE, Opcode.SPUT_WIDE_VOLATILE), new FieldOpcode('L', true, Opcode.SPUT_OBJECT, Opcode.SPUT_OBJECT_VOLATILE), new FieldOpcode('[', true, Opcode.SPUT_OBJECT, Opcode.SPUT_OBJECT_VOLATILE), new FieldOpcode('Z', true, Opcode.SGET_BOOLEAN, Opcode.SGET_VOLATILE), new FieldOpcode('B', true, Opcode.SGET_BYTE, Opcode.SGET_VOLATILE), new FieldOpcode('S', true, Opcode.SGET_SHORT, Opcode.SGET_VOLATILE), new FieldOpcode('C', true, Opcode.SGET_CHAR, Opcode.SGET_VOLATILE), new FieldOpcode('I', true, Opcode.SGET, Opcode.SGET_VOLATILE), new FieldOpcode('F', true, Opcode.SGET, Opcode.SGET_VOLATILE), new FieldOpcode('J', true, Opcode.SGET_WIDE, Opcode.SGET_WIDE_VOLATILE), new FieldOpcode('D', true, Opcode.SGET_WIDE, Opcode.SGET_WIDE_VOLATILE), new FieldOpcode('L', true, Opcode.SGET_OBJECT, Opcode.SGET_OBJECT_VOLATILE), new FieldOpcode('[', true, Opcode.SGET_OBJECT, Opcode.SGET_OBJECT_VOLATILE), }; private static final FieldOpcode[] artFieldOpcodes = new FieldOpcode[] { new FieldOpcode('Z', Opcode.IGET_BOOLEAN, Opcode.IGET_BOOLEAN_QUICK), new FieldOpcode('B', Opcode.IGET_BYTE, Opcode.IGET_BYTE_QUICK), new FieldOpcode('S', Opcode.IGET_SHORT, Opcode.IGET_SHORT_QUICK), new FieldOpcode('C', Opcode.IGET_CHAR, Opcode.IGET_CHAR_QUICK), new FieldOpcode('I', Opcode.IGET, Opcode.IGET_QUICK), new FieldOpcode('F', Opcode.IGET, Opcode.IGET_QUICK), new FieldOpcode('J', Opcode.IGET_WIDE, Opcode.IGET_WIDE_QUICK), new FieldOpcode('D', Opcode.IGET_WIDE, Opcode.IGET_WIDE_QUICK), new FieldOpcode('L', Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_QUICK), new FieldOpcode('[', Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_QUICK), new FieldOpcode('Z', Opcode.IPUT_BOOLEAN, Opcode.IPUT_BOOLEAN_QUICK), new FieldOpcode('B', Opcode.IPUT_BYTE, Opcode.IPUT_BYTE_QUICK), new FieldOpcode('S', Opcode.IPUT_SHORT, Opcode.IPUT_SHORT_QUICK), new FieldOpcode('C', Opcode.IPUT_CHAR, Opcode.IPUT_CHAR_QUICK), new FieldOpcode('I', Opcode.IPUT, Opcode.IPUT_QUICK), new FieldOpcode('F', Opcode.IPUT, Opcode.IPUT_QUICK), new FieldOpcode('J', Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_QUICK), new FieldOpcode('D', Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_QUICK), new FieldOpcode('L', Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_QUICK), new FieldOpcode('[', Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_QUICK) }; private final FieldOpcode[][][] opcodeMap = new FieldOpcode[2][2][10]; private final Map opcodeValueTypeMap = new HashMap(30); private static int getValueType(char type) { switch (type) { case 'Z': case 'B': case 'S': case 'C': case 'I': case 'F': return PRIMITIVE; case 'J': case 'D': return WIDE; case 'L': case '[': return REFERENCE; } throw new RuntimeException(String.format("Unknown type %s: ", type)); } private static int getTypeIndex(char type) { switch (type) { case 'Z': return 0; case 'B': return 1; case 'S': return 2; case 'C': return 3; case 'I': return 4; case 'F': return 5; case 'J': return 6; case 'D': return 7; case 'L': return 8; case '[': return 9; } throw new RuntimeException(String.format("Unknown type %s: ", type)); } private static boolean isGet(@Nonnull Opcode opcode) { return (opcode.flags & Opcode.SETS_REGISTER) != 0; } private static boolean isStatic(@Nonnull Opcode opcode) { return (opcode.flags & Opcode.STATIC_FIELD_ACCESSOR) != 0; } public OdexedFieldInstructionMapper(boolean isArt) { FieldOpcode[] opcodes; if (isArt) { opcodes = artFieldOpcodes; } else { opcodes = dalvikFieldOpcodes; } for (FieldOpcode fieldOpcode: opcodes) { opcodeMap[isGet(fieldOpcode.normalOpcode)?GET:PUT] [isStatic(fieldOpcode.normalOpcode)?STATIC:INSTANCE] [getTypeIndex(fieldOpcode.type)] = fieldOpcode; if (fieldOpcode.quickOpcode != null) { opcodeValueTypeMap.put(fieldOpcode.quickOpcode, getValueType(fieldOpcode.type)); } if (fieldOpcode.volatileOpcode != null) { opcodeValueTypeMap.put(fieldOpcode.volatileOpcode, getValueType(fieldOpcode.type)); } } } @Nonnull public Opcode getAndCheckDeodexedOpcode(@Nonnull String fieldType, @Nonnull Opcode odexedOpcode) { FieldOpcode fieldOpcode = opcodeMap[isGet(odexedOpcode)?GET:PUT] [isStatic(odexedOpcode)?STATIC:INSTANCE] [getTypeIndex(fieldType.charAt(0))]; if (!isCompatible(odexedOpcode, fieldOpcode.type)) { throw new AnalysisException(String.format("Incorrect field type \"%s\" for %s", fieldType, odexedOpcode.name)); } return fieldOpcode.normalOpcode; } private boolean isCompatible(Opcode opcode, char type) { Integer valueType = opcodeValueTypeMap.get(opcode); if (valueType == null) { throw new RuntimeException("Unexpected opcode: " + opcode.name); } return valueType == getValueType(type); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/PathEntryLoader.java000066400000000000000000000074241342202223400270660ustar00rootroot00000000000000package org.jf.dexlib2.analysis; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.jf.dexlib2.DexFileFactory; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.OatFile; import org.jf.dexlib2.iface.MultiDexContainer; import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Set; public class PathEntryLoader { Opcodes opcodes; public Opcodes getOpcodes() { return opcodes; } final Set loadedFiles = Sets.newHashSet(); final List classProviders = Lists.newArrayList(); public List getClassProviders() { return classProviders; } public PathEntryLoader(Opcodes opcodes) { this.opcodes = opcodes; } @Nonnull public List getResolvedClassProviders() { return classProviders; } public void loadEntry(@Nonnull File entryFile, boolean loadOatDependencies) throws IOException, NoDexException { if (loadedFiles.contains(entryFile)) { return; } MultiDexContainer container; try { container = DexFileFactory.loadDexContainer(entryFile, opcodes); } catch (DexFileFactory.UnsupportedFileTypeException ex) { throw new ClassPathResolver.ResolveException(ex); } List entryNames = container.getDexEntryNames(); if (entryNames.isEmpty()) { throw new NoDexException("%s contains no dex file", entryFile); } loadedFiles.add(entryFile); for (String entryName : entryNames) { classProviders.add(new DexClassProvider(container.getEntry(entryName))); } if (loadOatDependencies && container instanceof OatFile) { List oatDependencies = ((OatFile) container).getBootClassPath(); if (!oatDependencies.isEmpty()) { try { loadOatDependencies(entryFile.getParentFile(), oatDependencies); } catch (ClassPathResolver.NotFoundException ex) { throw new ClassPathResolver.ResolveException(ex, "Error while loading oat file %s", entryFile); } catch (NoDexException ex) { throw new ClassPathResolver.ResolveException(ex, "Error while loading dependencies for oat file %s", entryFile); } } } } private void loadOatDependencies(@Nonnull File directory, @Nonnull List oatDependencies) throws IOException, NoDexException, ClassPathResolver.NotFoundException { // We assume that all oat dependencies are located in the same directory as the oat file for (String oatDependency : oatDependencies) { String oatDependencyName = getFilenameForOatDependency(oatDependency); File file = new File(directory, oatDependencyName); if (!file.exists()) { throw new ClassPathResolver.NotFoundException("Cannot find dependency %s in %s", oatDependencyName, directory); } loadEntry(file, false); } } @Nonnull private String getFilenameForOatDependency(String oatDependency) { int index = oatDependency.lastIndexOf('/'); String dependencyLeaf = oatDependency.substring(index + 1); if (dependencyLeaf.endsWith(".art")) { return dependencyLeaf.substring(0, dependencyLeaf.length() - 4) + ".oat"; } return dependencyLeaf; } static class NoDexException extends Exception { public NoDexException(String message, Object... formatArgs) { super(String.format(message, formatArgs)); } } }smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java000066400000000000000000000060101342202223400270030ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PrimitiveProto implements TypeProto { protected final ClassPath classPath; protected final String type; public PrimitiveProto(@Nonnull ClassPath classPath, @Nonnull String type) { this.classPath = classPath; this.type = type; } @Override public String toString() { return type; } @Nonnull @Override public ClassPath getClassPath() { return classPath; } @Nonnull @Override public String getType() { return type; } @Override public boolean isInterface() { return false; } @Override public boolean implementsInterface(@Nonnull String iface) { return false; } @Nullable @Override public String getSuperclass() { return null; } @Nonnull @Override public TypeProto getCommonSuperclass(@Nonnull TypeProto other) { throw new ExceptionWithContext("Cannot call getCommonSuperclass on PrimitiveProto"); } @Override @Nullable public FieldReference getFieldByOffset(int fieldOffset) { return null; } @Override @Nullable public Method getMethodByVtableIndex(int vtableIndex) { return null; } @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) { return -1; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/RegisterType.java000066400000000000000000000427071342202223400264520ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; import java.io.Writer; public class RegisterType { public final byte category; @Nullable public final TypeProto type; private RegisterType(byte category, @Nullable TypeProto type) { assert ((category == REFERENCE || category == UNINIT_REF || category == UNINIT_THIS) && type != null) || ((category != REFERENCE && category != UNINIT_REF && category != UNINIT_THIS) && type == null); this.category = category; this.type = type; } @Override public String toString() { return "(" + CATEGORY_NAMES[category] + (type==null?"":("," + type)) + ")"; } public void writeTo(Writer writer) throws IOException { writer.write('('); writer.write(CATEGORY_NAMES[category]); if (type != null) { writer.write(','); writer.write(type.getType()); } writer.write(')'); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; RegisterType that = (RegisterType) o; if (category != that.category) { return false; } // These require strict reference equality. Every instance represents a unique // reference that can't be merged with a different one, even if they have the same type. if (category == UNINIT_REF || category == UNINIT_THIS) { return false; } return (type != null ? type.equals(that.type) : that.type == null); } @Override public int hashCode() { int result = category; result = 31 * result + (type != null ? type.hashCode() : 0); return result; } // The Unknown category denotes a register type that hasn't been determined yet public static final byte UNKNOWN = 0; // The Uninit category is for registers that haven't been set yet. e.g. the non-parameter registers in a method // start out as unint public static final byte UNINIT = 1; public static final byte NULL = 2; public static final byte ONE = 3; public static final byte BOOLEAN = 4; public static final byte BYTE = 5; public static final byte POS_BYTE = 6; public static final byte SHORT = 7; public static final byte POS_SHORT = 8; public static final byte CHAR = 9; public static final byte INTEGER = 10; public static final byte FLOAT = 11; public static final byte LONG_LO = 12; public static final byte LONG_HI = 13; public static final byte DOUBLE_LO = 14; public static final byte DOUBLE_HI = 15; // The UninitRef category is used after a new-instance operation, and before the corresponding is called public static final byte UNINIT_REF = 16; // The UninitThis category is used the "this" register inside an method, before the superclass' // method is called public static final byte UNINIT_THIS = 17; public static final byte REFERENCE = 18; // This is used when there are multiple incoming execution paths that have incompatible register types. For // example if the register's type is an Integer on one incoming code path, but is a Reference type on another // incomming code path. There is no register type that can hold either an Integer or a Reference. public static final byte CONFLICTED = 19; public static final String[] CATEGORY_NAMES = new String[] { "Unknown", "Uninit", "Null", "One", "Boolean", "Byte", "PosByte", "Short", "PosShort", "Char", "Integer", "Float", "LongLo", "LongHi", "DoubleLo", "DoubleHi", "UninitRef", "UninitThis", "Reference", "Conflicted" }; //this table is used when merging register types. For example, if a particular register can be either a BYTE //or a Char, then the "merged" type of that register would be Integer, because it is the "smallest" type can //could hold either type of value. protected static byte[][] mergeTable = { /* UNKNOWN UNINIT NULL ONE, BOOLEAN BYTE POS_BYTE SHORT POS_SHORT CHAR INTEGER, FLOAT, LONG_LO LONG_HI DOUBLE_LO DOUBLE_HI UNINIT_REF UNINIT_THIS REFERENCE CONFLICTED*/ /*UNKNOWN*/ {UNKNOWN, UNINIT, NULL, ONE, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, LONG_LO, LONG_HI, DOUBLE_LO, DOUBLE_HI, UNINIT_REF, UNINIT_THIS,REFERENCE, CONFLICTED}, /*UNINIT*/ {UNINIT, UNINIT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*NULL*/ {NULL, CONFLICTED, NULL, BOOLEAN, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, REFERENCE, CONFLICTED}, /*ONE*/ {ONE, CONFLICTED, BOOLEAN, ONE, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*BOOLEAN*/ {BOOLEAN, CONFLICTED, BOOLEAN, BOOLEAN, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*BYTE*/ {BYTE, CONFLICTED, BYTE, BYTE, BYTE, BYTE, BYTE, SHORT, SHORT, INTEGER, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*POS_BYTE*/ {POS_BYTE, CONFLICTED, POS_BYTE, POS_BYTE, POS_BYTE, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*SHORT*/ {SHORT, CONFLICTED, SHORT, SHORT, SHORT, SHORT, SHORT, SHORT, SHORT, INTEGER, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*POS_SHORT*/ {POS_SHORT, CONFLICTED, POS_SHORT, POS_SHORT, POS_SHORT, SHORT, POS_SHORT, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*CHAR*/ {CHAR, CONFLICTED, CHAR, CHAR, CHAR, INTEGER, CHAR, INTEGER, CHAR, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*INTEGER*/ {INTEGER, CONFLICTED, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*FLOAT*/ {FLOAT, CONFLICTED, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*LONG_LO*/ {LONG_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_LO, CONFLICTED, LONG_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*LONG_HI*/ {LONG_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_HI, CONFLICTED, LONG_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*DOUBLE_LO*/ {DOUBLE_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_LO, CONFLICTED, DOUBLE_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*DOUBLE_HI*/ {DOUBLE_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_HI, CONFLICTED, DOUBLE_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*UNINIT_REF*/ {UNINIT_REF, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}, /*UNINIT_THIS*/{UNINIT_THIS, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, UNINIT_THIS,CONFLICTED, CONFLICTED}, /*REFERENCE*/ {REFERENCE, CONFLICTED, REFERENCE, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, REFERENCE, CONFLICTED}, /*CONFLICTED*/ {CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED} }; public static final RegisterType UNKNOWN_TYPE = new RegisterType(UNKNOWN, null); public static final RegisterType UNINIT_TYPE = new RegisterType(UNINIT, null); public static final RegisterType NULL_TYPE = new RegisterType(NULL, null); public static final RegisterType ONE_TYPE = new RegisterType(ONE, null); public static final RegisterType BOOLEAN_TYPE = new RegisterType(BOOLEAN, null); public static final RegisterType BYTE_TYPE = new RegisterType(BYTE, null); public static final RegisterType POS_BYTE_TYPE = new RegisterType(POS_BYTE, null); public static final RegisterType SHORT_TYPE = new RegisterType(SHORT, null); public static final RegisterType POS_SHORT_TYPE = new RegisterType(POS_SHORT, null); public static final RegisterType CHAR_TYPE = new RegisterType(CHAR, null); public static final RegisterType INTEGER_TYPE = new RegisterType(INTEGER, null); public static final RegisterType FLOAT_TYPE = new RegisterType(FLOAT, null); public static final RegisterType LONG_LO_TYPE = new RegisterType(LONG_LO, null); public static final RegisterType LONG_HI_TYPE = new RegisterType(LONG_HI, null); public static final RegisterType DOUBLE_LO_TYPE = new RegisterType(DOUBLE_LO, null); public static final RegisterType DOUBLE_HI_TYPE = new RegisterType(DOUBLE_HI, null); public static final RegisterType CONFLICTED_TYPE = new RegisterType(CONFLICTED, null); @Nonnull public static RegisterType getWideRegisterType(@Nonnull CharSequence type, boolean firstRegister) { switch (type.charAt(0)) { case 'J': if (firstRegister) { return getRegisterType(LONG_LO, null); } else { return getRegisterType(LONG_HI, null); } case 'D': if (firstRegister) { return getRegisterType(DOUBLE_LO, null); } else { return getRegisterType(DOUBLE_HI, null); } default: throw new ExceptionWithContext("Cannot use this method for narrow register type: %s", type); } } @Nonnull public static RegisterType getRegisterType(@Nonnull ClassPath classPath, @Nonnull CharSequence type) { switch (type.charAt(0)) { case 'Z': return BOOLEAN_TYPE; case 'B': return BYTE_TYPE; case 'S': return SHORT_TYPE; case 'C': return CHAR_TYPE; case 'I': return INTEGER_TYPE; case 'F': return FLOAT_TYPE; case 'J': return LONG_LO_TYPE; case 'D': return DOUBLE_LO_TYPE; case 'L': case '[': return getRegisterType(REFERENCE, classPath.getClass(type)); default: throw new AnalysisException("Invalid type: " + type); } } @Nonnull public static RegisterType getRegisterTypeForLiteral(int literalValue) { if (literalValue < -32768) { return INTEGER_TYPE; } if (literalValue < -128) { return SHORT_TYPE; } if (literalValue < 0) { return BYTE_TYPE; } if (literalValue == 0) { return NULL_TYPE; } if (literalValue == 1) { return ONE_TYPE; } if (literalValue < 128) { return POS_BYTE_TYPE; } if (literalValue < 32768) { return POS_SHORT_TYPE; } if (literalValue < 65536) { return CHAR_TYPE; } return INTEGER_TYPE; } @Nonnull public RegisterType merge(@Nonnull RegisterType other) { if (other.equals(this)) { return this; } byte mergedCategory = mergeTable[this.category][other.category]; TypeProto mergedType = null; if (mergedCategory == REFERENCE) { TypeProto type = this.type; if (type != null) { if (other.type != null) { mergedType = type.getCommonSuperclass(other.type); } else { mergedType = type; } } else { mergedType = other.type; } } else if (mergedCategory == UNINIT_REF || mergedCategory == UNINIT_THIS) { if (this.category == UNKNOWN) { return other; } assert other.category == UNKNOWN; return this; } if (mergedType != null) { if (mergedType.equals(this.type)) { return this; } if (mergedType.equals(other.type)) { return other; } } return RegisterType.getRegisterType(mergedCategory, mergedType); } @Nonnull public static RegisterType getRegisterType(byte category, @Nullable TypeProto typeProto) { switch (category) { case UNKNOWN: return UNKNOWN_TYPE; case UNINIT: return UNINIT_TYPE; case NULL: return NULL_TYPE; case ONE: return ONE_TYPE; case BOOLEAN: return BOOLEAN_TYPE; case BYTE: return BYTE_TYPE; case POS_BYTE: return POS_BYTE_TYPE; case SHORT: return SHORT_TYPE; case POS_SHORT: return POS_SHORT_TYPE; case CHAR: return CHAR_TYPE; case INTEGER: return INTEGER_TYPE; case FLOAT: return FLOAT_TYPE; case LONG_LO: return LONG_LO_TYPE; case LONG_HI: return LONG_HI_TYPE; case DOUBLE_LO: return DOUBLE_LO_TYPE; case DOUBLE_HI: return DOUBLE_HI_TYPE; case CONFLICTED: return CONFLICTED_TYPE; } return new RegisterType(category, typeProto); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java000066400000000000000000000043701342202223400257630ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; public interface TypeProto { @Nonnull ClassPath getClassPath(); @Nonnull String getType(); boolean isInterface(); boolean implementsInterface(@Nonnull String iface); @Nullable String getSuperclass(); @Nonnull TypeProto getCommonSuperclass(@Nonnull TypeProto other); @Nullable FieldReference getFieldByOffset(int fieldOffset); @Nullable Method getMethodByVtableIndex(int vtableIndex); int findMethodIndexInVtable(@Nonnull MethodReference method); } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java000066400000000000000000000070261342202223400274700ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class UnknownClassProto implements TypeProto { @Nonnull protected final ClassPath classPath; public UnknownClassProto(@Nonnull ClassPath classPath) { this.classPath = classPath; } @Override public String toString() { return "Ujava/lang/Object;"; } @Nonnull @Override public ClassPath getClassPath() { return classPath; } @Nullable @Override public String getSuperclass() { return null; } @Override public boolean isInterface() { return false; } @Override public boolean implementsInterface(@Nonnull String iface) { return false; } @Nonnull @Override public TypeProto getCommonSuperclass(@Nonnull TypeProto other) { if (other.getType().equals("Ljava/lang/Object;")) { return other; } if (other instanceof ArrayProto) { // if it's an array class, it's safe to assume this unknown class isn't related, and so // java.lang.Object is the only possible superclass return classPath.getClass("Ljava/lang/Object;"); } return this; } @Nonnull @Override public String getType() { // use the otherwise used U prefix for an unknown/unresolvable class return "Ujava/lang/Object;"; } @Override @Nullable public FieldReference getFieldByOffset(int fieldOffset) { return classPath.getClass("Ljava/lang/Object;").getFieldByOffset(fieldOffset); } @Override @Nullable public Method getMethodByVtableIndex(int vtableIndex) { return classPath.getClass("Ljava/lang/Object;").getMethodByVtableIndex(vtableIndex); } @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) { return classPath.getClass("Ljava/lang/Object;").findMethodIndexInVtable(method); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnresolvedClassException.java000066400000000000000000000040101342202223400310000ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import org.jf.util.ExceptionWithContext; public class UnresolvedClassException extends ExceptionWithContext { public UnresolvedClassException(Throwable cause) { super(cause); } public UnresolvedClassException(Throwable cause, String message, Object... formatArgs) { super(cause, message, formatArgs); } public UnresolvedClassException(String message, Object... formatArgs) { super(message, formatArgs); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnresolvedOdexInstruction.java000066400000000000000000000050541342202223400312260ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.iface.instruction.Instruction; /** * This represents a "fixed" odexed instruction, where the object register is always null and so the correct type * can't be determined. Typically, these are replaced by an equivalent instruction that would have the same * effect (namely, an NPE) */ public class UnresolvedOdexInstruction implements Instruction { public final Instruction originalInstruction; //the register number that holds the (null) reference type that the instruction operates on public final int objectRegisterNum; public UnresolvedOdexInstruction(Instruction originalInstruction, int objectRegisterNumber) { this.originalInstruction = originalInstruction; this.objectRegisterNum = objectRegisterNumber; } @Override public Opcode getOpcode() { return originalInstruction.getOpcode(); } @Override public int getCodeUnits() { return originalInstruction.getCodeUnits(); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/000077500000000000000000000000001342202223400253015ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionClassDef.java000066400000000000000000000255111342202223400316470ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis.reflection; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterators; import org.jf.dexlib2.analysis.reflection.util.ReflectionUtils; import org.jf.dexlib2.base.reference.BaseTypeReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.Field; import org.jf.dexlib2.iface.Method; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.util.AbstractSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Wraps a ClassDef around a class loaded in the current VM * * Only supports the basic information exposed by ClassProto */ public class ReflectionClassDef extends BaseTypeReference implements ClassDef { private final Class cls; public ReflectionClassDef(Class cls) { this.cls = cls; } @Override public int getAccessFlags() { // the java modifiers appear to be the same as the dex access flags return cls.getModifiers(); } @Nullable @Override public String getSuperclass() { if (Modifier.isInterface(cls.getModifiers())) { return "Ljava/lang/Object;"; } Class superClass = cls.getSuperclass(); if (superClass == null) { return null; } return ReflectionUtils.javaToDexName(superClass.getName()); } @Nonnull @Override public List getInterfaces() { return ImmutableList.copyOf(Iterators.transform(Iterators.forArray(cls.getInterfaces()), new Function() { @Nullable @Override public String apply(@Nullable Class input) { if (input == null) { return null; } return ReflectionUtils.javaToDexName(input.getName()); } })); } @Nullable @Override public String getSourceFile() { return null; } @Nonnull @Override public Set getAnnotations() { return ImmutableSet.of(); } @Nonnull @Override public Iterable getStaticFields() { return new Iterable() { @Nonnull @Override public Iterator iterator() { Iterator staticFields = Iterators.filter( Iterators.forArray(cls.getDeclaredFields()), new Predicate() { @Override public boolean apply(@Nullable java.lang.reflect.Field input) { return input!=null && Modifier.isStatic(input.getModifiers()); } }); return Iterators.transform(staticFields, new Function() { @Nullable @Override public Field apply(@Nullable java.lang.reflect.Field input) { return new ReflectionField(input); } } ); } }; } @Nonnull @Override public Iterable getInstanceFields() { return new Iterable() { @Nonnull @Override public Iterator iterator() { Iterator staticFields = Iterators.filter( Iterators.forArray(cls.getDeclaredFields()), new Predicate() { @Override public boolean apply(@Nullable java.lang.reflect.Field input) { return input!=null && !Modifier.isStatic(input.getModifiers()); } }); return Iterators.transform(staticFields, new Function() { @Nullable @Override public Field apply(@Nullable java.lang.reflect.Field input) { return new ReflectionField(input); } } ); } }; } @Nonnull @Override public Set getFields() { return new AbstractSet() { @Nonnull @Override public Iterator iterator() { return Iterators.transform(Iterators.forArray(cls.getDeclaredFields()), new Function() { @Nullable @Override public Field apply(@Nullable java.lang.reflect.Field input) { return new ReflectionField(input); } }); } @Override public int size() { return cls.getDeclaredFields().length; } }; } private static final int DIRECT_MODIFIERS = Modifier.PRIVATE | Modifier.STATIC; @Nonnull @Override public Iterable getDirectMethods() { return new Iterable() { @Nonnull @Override public Iterator iterator() { Iterator constructorIterator = Iterators.transform(Iterators.forArray(cls.getDeclaredConstructors()), new Function() { @Nullable @Override public Method apply(@Nullable Constructor input) { return new ReflectionConstructor(input); } }); Iterator directMethods = Iterators.filter( Iterators.forArray(cls.getDeclaredMethods()), new Predicate() { @Override public boolean apply(@Nullable java.lang.reflect.Method input) { return input != null && (input.getModifiers() & DIRECT_MODIFIERS) != 0; } }); Iterator methodIterator = Iterators.transform(directMethods, new Function() { @Nullable @Override public Method apply(@Nullable java.lang.reflect.Method input) { return new ReflectionMethod(input); } }); return Iterators.concat(constructorIterator, methodIterator); } }; } @Nonnull @Override public Iterable getVirtualMethods() { return new Iterable() { @Nonnull @Override public Iterator iterator() { Iterator directMethods = Iterators.filter( Iterators.forArray(cls.getDeclaredMethods()), new Predicate() { @Override public boolean apply(@Nullable java.lang.reflect.Method input) { return input != null && (input.getModifiers() & DIRECT_MODIFIERS) == 0; } }); return Iterators.transform(directMethods, new Function() { @Nullable @Override public Method apply(@Nullable java.lang.reflect.Method input) { return new ReflectionMethod(input); } }); } }; } @Nonnull @Override public Set getMethods() { return new AbstractSet() { @Nonnull @Override public Iterator iterator() { Iterator constructorIterator = Iterators.transform(Iterators.forArray(cls.getDeclaredConstructors()), new Function() { @Nullable @Override public Method apply(@Nullable Constructor input) { return new ReflectionConstructor(input); } }); Iterator methodIterator = Iterators.transform(Iterators.forArray(cls.getDeclaredMethods()), new Function() { @Nullable @Override public Method apply(@Nullable java.lang.reflect.Method input) { return new ReflectionMethod(input); } }); return Iterators.concat(constructorIterator, methodIterator); } @Override public int size() { return cls.getDeclaredMethods().length + cls.getDeclaredConstructors().length; } }; } @Nonnull @Override public String getType() { return ReflectionUtils.javaToDexName(cls.getName()); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionConstructor.java000066400000000000000000000106161342202223400325100ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis.reflection; import com.google.common.collect.ImmutableSet; import org.jf.dexlib2.analysis.reflection.util.ReflectionUtils; import org.jf.dexlib2.base.BaseMethodParameter; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.MethodImplementation; import org.jf.dexlib2.iface.MethodParameter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.lang.reflect.Constructor; import java.util.AbstractList; import java.util.List; import java.util.Set; public class ReflectionConstructor extends BaseMethodReference implements Method { private final Constructor constructor; public ReflectionConstructor(Constructor constructor) { this.constructor = constructor; } @Nonnull @Override public List getParameters() { final Constructor method = this.constructor; return new AbstractList() { private final Class[] parameters = method.getParameterTypes(); @Override public MethodParameter get(final int index) { return new BaseMethodParameter() { @Nonnull @Override public Set getAnnotations() { return ImmutableSet.of(); } @Nullable @Override public String getName() { return null; } @Nonnull @Override public String getType() { return ReflectionUtils.javaToDexName(parameters[index].getName()); } }; } @Override public int size() { return parameters.length; } }; } @Override public int getAccessFlags() { return constructor.getModifiers(); } @Nonnull @Override public Set getAnnotations() { return ImmutableSet.of(); } @Nullable @Override public MethodImplementation getImplementation() { return null; } @Nonnull @Override public String getDefiningClass() { return ReflectionUtils.javaToDexName(constructor.getDeclaringClass().getName()); } @Nonnull @Override public String getName() { return constructor.getName(); } @Nonnull @Override public List getParameterTypes() { return new AbstractList() { private final List parameters = getParameters(); @Override public String get(int index) { return parameters.get(index).getType(); } @Override public int size() { return parameters.size(); } }; } @Nonnull @Override public String getReturnType() { return "V"; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionField.java000066400000000000000000000054711342202223400312110ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis.reflection; import com.google.common.collect.ImmutableSet; import org.jf.dexlib2.analysis.reflection.util.ReflectionUtils; import org.jf.dexlib2.base.reference.BaseFieldReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Field; import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Set; public class ReflectionField extends BaseFieldReference implements Field { private final java.lang.reflect.Field field; public ReflectionField(java.lang.reflect.Field field) { this.field = field; } @Override public int getAccessFlags() { return field.getModifiers(); } @Nullable @Override public EncodedValue getInitialValue() { return null; } @Nonnull @Override public Set getAnnotations() { return ImmutableSet.of(); } @Nonnull @Override public String getDefiningClass() { return ReflectionUtils.javaToDexName(field.getDeclaringClass().getName()); } @Nonnull @Override public String getName() { return field.getName(); } @Nonnull @Override public String getType() { return ReflectionUtils.javaToDexName(field.getType().getName()); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionMethod.java000066400000000000000000000106311342202223400314000ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis.reflection; import com.google.common.collect.ImmutableSet; import org.jf.dexlib2.analysis.reflection.util.ReflectionUtils; import org.jf.dexlib2.base.BaseMethodParameter; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.MethodImplementation; import org.jf.dexlib2.iface.MethodParameter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.AbstractList; import java.util.List; import java.util.Set; public class ReflectionMethod extends BaseMethodReference implements Method { private final java.lang.reflect.Method method; public ReflectionMethod(java.lang.reflect.Method method) { this.method = method; } @Nonnull @Override public List getParameters() { final java.lang.reflect.Method method = this.method; return new AbstractList() { private final Class[] parameters = method.getParameterTypes(); @Override public MethodParameter get(final int index) { return new BaseMethodParameter() { @Nonnull @Override public Set getAnnotations() { return ImmutableSet.of(); } @Nullable @Override public String getName() { return null; } @Nonnull @Override public String getType() { return ReflectionUtils.javaToDexName(parameters[index].getName()); } }; } @Override public int size() { return parameters.length; } }; } @Override public int getAccessFlags() { return method.getModifiers(); } @Nonnull @Override public Set getAnnotations() { return ImmutableSet.of(); } @Nullable @Override public MethodImplementation getImplementation() { return null; } @Nonnull @Override public String getDefiningClass() { return ReflectionUtils.javaToDexName(method.getDeclaringClass().getName()); } @Nonnull @Override public String getName() { return method.getName(); } @Nonnull @Override public List getParameterTypes() { return new AbstractList() { private final List parameters = getParameters(); @Override public String get(int index) { return parameters.get(index).getType(); } @Override public int size() { return parameters.size(); } }; } @Nonnull @Override public String getReturnType() { return ReflectionUtils.javaToDexName(method.getReturnType().getName()); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/util/000077500000000000000000000000001342202223400262565ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/util/ReflectionUtils.java000066400000000000000000000053471342202223400322450ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis.reflection.util; import com.google.common.collect.ImmutableBiMap; public class ReflectionUtils { private static ImmutableBiMap primitiveMap = ImmutableBiMap.builder() .put("boolean", "Z") .put("int", "I") .put("long", "J") .put("double", "D") .put("void", "V") .put("float", "F") .put("char", "C") .put("short", "S") .put("byte", "B") .build(); public static String javaToDexName(String javaName) { if (javaName.charAt(0) == '[') { return javaName.replace('.', '/'); } if (primitiveMap.containsKey(javaName)) { return primitiveMap.get(javaName); } return 'L' + javaName.replace('.', '/') + ';'; } public static String dexToJavaName(String dexName) { if (dexName.charAt(0) == '[') { return dexName.replace('/', '.'); } if (primitiveMap.inverse().containsKey(dexName)) { return primitiveMap.inverse().get(dexName); } return dexName.replace('/', '.').substring(1, dexName.length()-2); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/000077500000000000000000000000001342202223400241245ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java000066400000000000000000000102451342202223400277570ustar00rootroot00000000000000/* * Copyright 2013, 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.analysis.util; import org.jf.dexlib2.analysis.TypeProto; import org.jf.dexlib2.analysis.UnresolvedClassException; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Iterator; import java.util.NoSuchElementException; public class TypeProtoUtils { /** * Get the chain of superclasses of the given class. The first element will be the immediate superclass followed by * it's superclass, etc. up to java.lang.Object. * * Returns an empty iterable if called on java.lang.Object or a primitive. * * If any class in the superclass chain can't be resolved, the iterable will return Ujava/lang/Object; to represent * the unknown class. * * @return An iterable containing the superclasses of this class. */ @Nonnull public static Iterable getSuperclassChain(@Nonnull final TypeProto typeProto) { return new Iterable() { @Override public Iterator iterator() { return new Iterator() { @Nullable private TypeProto type = getSuperclassAsTypeProto(typeProto); @Override public boolean hasNext() { return type != null; } @Override public TypeProto next() { TypeProto type = this.type; if (type == null) { throw new NoSuchElementException(); } this.type = getSuperclassAsTypeProto(type); return type; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } @Nullable public static TypeProto getSuperclassAsTypeProto(@Nonnull TypeProto type) { try { String next = type.getSuperclass(); if (next != null) { return type.getClassPath().getClass(next); } else { return null; } } catch (UnresolvedClassException ex) { return type.getClassPath().getUnknownClass(); } } public static boolean extendsFrom(@Nonnull TypeProto candidate, @Nonnull String possibleSuper) { if (candidate.getType().equals(possibleSuper)) { return true; } for (TypeProto superProto: getSuperclassChain(candidate)) { if (superProto.getType().equals(possibleSuper)) { return true; } } return false; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/000077500000000000000000000000001342202223400222365ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/BaseAnnotation.java000066400000000000000000000056321342202223400260140ustar00rootroot00000000000000/* * 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.base; import com.google.common.primitives.Ints; import org.jf.dexlib2.iface.Annotation; import org.jf.util.CollectionUtils; import java.util.Comparator; public abstract class BaseAnnotation implements Annotation { @Override public int hashCode() { int hashCode = getVisibility(); hashCode = hashCode*31 + getType().hashCode(); return hashCode*31 + getElements().hashCode(); } @Override public boolean equals(Object o) { if (o instanceof Annotation) { Annotation other = (Annotation)o; return (getVisibility() == other.getVisibility()) && getType().equals(other.getType()) && getElements().equals(other.getElements()); } return false; } @Override public int compareTo(Annotation o) { int res = Ints.compare(getVisibility(), o.getVisibility()); if (res != 0) return res; res = getType().compareTo(o.getType()); if (res != 0) return res; return CollectionUtils.compareAsSet(getElements(), o.getElements()); } public static final Comparator BY_TYPE = new Comparator() { @Override public int compare(Annotation annotation1, Annotation annotation2) { return annotation1.getType().compareTo(annotation2.getType()); } }; } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/BaseAnnotationElement.java000066400000000000000000000053151342202223400273240ustar00rootroot00000000000000/* * 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.base; import org.jf.dexlib2.iface.AnnotationElement; import javax.annotation.Nonnull; import java.util.Comparator; public abstract class BaseAnnotationElement implements AnnotationElement { @Override public int hashCode() { int hashCode = getName().hashCode(); return hashCode*31 + getValue().hashCode(); } @Override public boolean equals(Object o) { if (o != null && o instanceof AnnotationElement) { AnnotationElement other = (AnnotationElement)o; return getName().equals(other.getName()) && getValue().equals(other.getValue()); } return false; } @Override public int compareTo(AnnotationElement o) { int res = getName().compareTo(o.getName()); if (res != 0) return res; return getValue().compareTo(o.getValue()); } public static final Comparator BY_NAME = new Comparator() { @Override public int compare(@Nonnull AnnotationElement element1, @Nonnull AnnotationElement element2) { return element1.getName().compareTo(element2.getName()); } }; } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/BaseExceptionHandler.java000066400000000000000000000103061342202223400271300ustar00rootroot00000000000000/* * 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.base; import com.google.common.base.Objects; import com.google.common.primitives.Ints; import org.jf.dexlib2.base.reference.BaseTypeReference; import org.jf.dexlib2.iface.ExceptionHandler; import org.jf.dexlib2.iface.reference.TypeReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Comparator; public abstract class BaseExceptionHandler implements ExceptionHandler { @Nullable @Override public TypeReference getExceptionTypeReference() { final String exceptionType = getExceptionType(); if (exceptionType == null) { return null; } return new BaseTypeReference() { @Nonnull @Override public String getType() { return exceptionType; } }; } @Override public int hashCode() { String exceptionType = getExceptionType(); int hashCode = exceptionType==null?0:exceptionType.hashCode(); return hashCode*31 + getHandlerCodeAddress(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof ExceptionHandler) { ExceptionHandler other = (ExceptionHandler)o; return Objects.equal(getExceptionType(), other.getExceptionType()) && (getHandlerCodeAddress() == other.getHandlerCodeAddress()); } return false; } @Override public int compareTo(@Nonnull ExceptionHandler o) { int res; String exceptionType = getExceptionType(); if (exceptionType == null) { if (o.getExceptionType() != null) { return 1; } } else { String otherExceptionType = o.getExceptionType(); if (otherExceptionType == null) { return -1; } res = exceptionType.compareTo(o.getExceptionType()); if (res != 0) return res; } return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress()); } public static final Comparator BY_EXCEPTION = new Comparator() { @Override public int compare(ExceptionHandler o1, ExceptionHandler o2) { String exceptionType1 = o1.getExceptionType(); if (exceptionType1 == null) { if (o2.getExceptionType() != null) { return 1; } return 0; } else { String exceptionType2 = o2.getExceptionType(); if (exceptionType2 == null) { return -1; } return exceptionType1.compareTo(o2.getExceptionType()); } } }; } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/BaseMethodParameter.java000066400000000000000000000066051342202223400267640ustar00rootroot00000000000000/* * 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.base; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.base.reference.BaseTypeReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.AnnotationElement; import org.jf.dexlib2.iface.MethodParameter; import org.jf.dexlib2.iface.value.ArrayEncodedValue; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.StringEncodedValue; import javax.annotation.Nullable; public abstract class BaseMethodParameter extends BaseTypeReference implements MethodParameter { @Nullable @Override public String getSignature() { Annotation signatureAnnotation = null; for (Annotation annotation: getAnnotations()) { if (annotation.getType().equals("Ldalvik/annotation/Signature;")) { signatureAnnotation = annotation; break; } } if (signatureAnnotation == null) { return null; } ArrayEncodedValue signatureValues = null; for (AnnotationElement annotationElement: signatureAnnotation.getElements()) { if (annotationElement.getName().equals("value")) { EncodedValue encodedValue = annotationElement.getValue(); if (encodedValue.getValueType() != ValueType.ARRAY) { return null; } signatureValues = (ArrayEncodedValue)encodedValue; break; } } if (signatureValues == null) { return null; } StringBuilder sb = new StringBuilder(); for (EncodedValue signatureValue: signatureValues.getValue()) { if (signatureValue.getValueType() != ValueType.STRING) { return null; } sb.append(((StringEncodedValue)signatureValue).getValue()); } return sb.toString(); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/BaseTryBlock.java000066400000000000000000000041621342202223400254300ustar00rootroot00000000000000/* * Copyright 2013, 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.base; import org.jf.dexlib2.iface.ExceptionHandler; import org.jf.dexlib2.iface.TryBlock; public abstract class BaseTryBlock implements TryBlock { @Override public boolean equals(Object o) { if (o instanceof TryBlock) { TryBlock other = (TryBlock)o; return getStartCodeAddress() == other.getStartCodeAddress() && getCodeUnitCount() == other.getCodeUnitCount() && getExceptionHandlers().equals(other.getExceptionHandlers()); } return false; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/reference/000077500000000000000000000000001342202223400241745ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseCallSiteReference.java000066400000000000000000000050561342202223400311570ustar00rootroot00000000000000/* * Copyright 2018, 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.base.reference; import org.jf.dexlib2.iface.reference.CallSiteReference; public abstract class BaseCallSiteReference implements CallSiteReference { @Override public int hashCode() { int hashCode = getName().hashCode(); hashCode = hashCode*31 + getMethodHandle().hashCode(); hashCode = hashCode*31 + getMethodName().hashCode(); hashCode = hashCode*31 + getMethodProto().hashCode(); hashCode = hashCode*31 + getExtraArguments().hashCode(); return hashCode; } @Override public boolean equals(Object o) { if (o != null && o instanceof CallSiteReference) { CallSiteReference other = (CallSiteReference) o; return getMethodHandle().equals(other.getMethodHandle()) && getMethodName().equals(other.getMethodName()) && getMethodProto().equals(other.getMethodProto()) && getExtraArguments().equals(other.getExtraArguments()); } return false; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseFieldReference.java000066400000000000000000000054341342202223400305020ustar00rootroot00000000000000/* * 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.base.reference; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.util.ReferenceUtil; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseFieldReference implements FieldReference { @Override public int hashCode() { int hashCode = getDefiningClass().hashCode(); hashCode = hashCode*31 + getName().hashCode(); return hashCode*31 + getType().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof FieldReference) { FieldReference other = (FieldReference)o; return getDefiningClass().equals(other.getDefiningClass()) && getName().equals(other.getName()) && getType().equals(other.getType()); } return false; } @Override public int compareTo(@Nonnull FieldReference o) { int res = getDefiningClass().compareTo(o.getDefiningClass()); if (res != 0) return res; res = getName().compareTo(o.getName()); if (res != 0) return res; return getType().compareTo(o.getType()); } @Override public String toString() { return ReferenceUtil.getFieldDescriptor(this); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseMethodHandleReference.java000066400000000000000000000065731342202223400320200ustar00rootroot00000000000000/* * Copyright 2018, 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.base.reference; import com.google.common.primitives.Ints; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodHandleReference; import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.reference.Reference; import javax.annotation.Nonnull; public abstract class BaseMethodHandleReference implements MethodHandleReference { @Override public int hashCode() { int hashCode = getMethodHandleType(); hashCode = hashCode*31 + getMemberReference().hashCode(); return hashCode; } @Override public boolean equals(Object o) { if (o != null && o instanceof MethodHandleReference) { MethodHandleReference other = (MethodHandleReference) o; return getMethodHandleType() == other.getMethodHandleType() && getMemberReference().equals(other.getMemberReference()); } return false; } @Override public int compareTo(@Nonnull MethodHandleReference o) { int res = Ints.compare(getMethodHandleType(), o.getMethodHandleType()); if (res != 0) return res; Reference reference = getMemberReference(); if (reference instanceof FieldReference) { // "This should never happen", but if it does, we'll arbitrarily say a field reference compares less than // a method reference if (!(o.getMemberReference() instanceof FieldReference)) { return -1; } return ((FieldReference) reference).compareTo((FieldReference) o.getMemberReference()); } else { if (!(o.getMemberReference() instanceof MethodReference)) { return 1; } return ((MethodReference) reference).compareTo((MethodReference) o.getMemberReference()); } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseMethodProtoReference.java000066400000000000000000000055561342202223400317300ustar00rootroot00000000000000/* * Copyright 2016, 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.base.reference; import com.google.common.collect.Ordering; import org.jf.dexlib2.iface.reference.MethodProtoReference; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.util.CharSequenceUtils; import org.jf.util.CollectionUtils; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseMethodProtoReference implements MethodProtoReference { @Override public int hashCode() { int hashCode = getReturnType().hashCode(); return hashCode*31 + getParameterTypes().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof MethodProtoReference) { MethodProtoReference other = (MethodProtoReference)o; return getReturnType().equals(other.getReturnType()) && CharSequenceUtils.listEquals(getParameterTypes(), other.getParameterTypes()); } return false; } @Override public int compareTo(@Nonnull MethodProtoReference o) { int res = getReturnType().compareTo(o.getReturnType()); if (res != 0) return res; return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameterTypes(), o.getParameterTypes()); } @Override public String toString() { return ReferenceUtil.getMethodProtoDescriptor(this); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseMethodReference.java000066400000000000000000000064001342202223400306710ustar00rootroot00000000000000/* * 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.base.reference; import com.google.common.collect.Ordering; import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.util.CharSequenceUtils; import org.jf.util.CollectionUtils; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseMethodReference implements MethodReference { @Override public int hashCode() { int hashCode = getDefiningClass().hashCode(); hashCode = hashCode*31 + getName().hashCode(); hashCode = hashCode*31 + getReturnType().hashCode(); return hashCode*31 + getParameterTypes().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o != null && o instanceof MethodReference) { MethodReference other = (MethodReference)o; return getDefiningClass().equals(other.getDefiningClass()) && getName().equals(other.getName()) && getReturnType().equals(other.getReturnType()) && CharSequenceUtils.listEquals(getParameterTypes(), other.getParameterTypes()); } return false; } @Override public int compareTo(@Nonnull MethodReference o) { int res = getDefiningClass().compareTo(o.getDefiningClass()); if (res != 0) return res; res = getName().compareTo(o.getName()); if (res != 0) return res; res = getReturnType().compareTo(o.getReturnType()); if (res != 0) return res; return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameterTypes(), o.getParameterTypes()); } @Override public String toString() { return ReferenceUtil.getMethodDescriptor(this); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseStringReference.java000066400000000000000000000050241342202223400307200ustar00rootroot00000000000000/* * 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.base.reference; import org.jf.dexlib2.iface.reference.StringReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseStringReference implements StringReference { @Override public int hashCode() { return getString().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o != null && o instanceof StringReference) { return getString().equals(((StringReference)o).getString()); } return false; } @Override public int compareTo(@Nonnull CharSequence o) { return getString().compareTo(o.toString()); } @Override public int length() { return getString().length(); } @Override public char charAt(int index) { return getString().charAt(index); } @Override public CharSequence subSequence(int start, int end) { return getString().subSequence(start, end); } @Override @Nonnull public String toString() { return getString(); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseTypeReference.java000066400000000000000000000051421342202223400303740ustar00rootroot00000000000000/* * 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.base.reference; import org.jf.dexlib2.iface.reference.TypeReference; import javax.annotation.Nonnull; public abstract class BaseTypeReference implements TypeReference { @Override public int hashCode() { return getType().hashCode(); } @Override public boolean equals(Object o) { if (o != null) { if (o instanceof TypeReference) { return getType().equals(((TypeReference)o).getType()); } if (o instanceof CharSequence) { return getType().equals(o.toString()); } } return false; } @Override public int compareTo(@Nonnull CharSequence o) { return getType().compareTo(o.toString()); } @Override public int length() { return getType().length(); } @Override public char charAt(int index) { return getType().charAt(index); } @Override public CharSequence subSequence(int start, int end) { return getType().subSequence(start, end); } @Override @Nonnull public String toString() { return getType(); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/000077500000000000000000000000001342202223400233525ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseAnnotationEncodedValue.java000066400000000000000000000056021342202223400314040ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.AnnotationEncodedValue; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.util.CollectionUtils; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseAnnotationEncodedValue implements AnnotationEncodedValue { @Override public int hashCode() { int hashCode = getType().hashCode(); return hashCode * 31 + getElements().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof AnnotationEncodedValue) { AnnotationEncodedValue other = (AnnotationEncodedValue)o; return getType().equals(other.getType()) && getElements().equals(other.getElements()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; AnnotationEncodedValue other = (AnnotationEncodedValue)o; res = getType().compareTo(other.getType()); if (res != 0) return res; return CollectionUtils.compareAsSet(getElements(), other.getElements()); } public int getValueType() { return ValueType.ANNOTATION; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseArrayEncodedValue.java000066400000000000000000000050311342202223400303440ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.ArrayEncodedValue; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.util.CollectionUtils; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseArrayEncodedValue implements ArrayEncodedValue { @Override public int hashCode() { return getValue().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof ArrayEncodedValue) { return getValue().equals(((ArrayEncodedValue)o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return CollectionUtils.compareAsList(getValue(), ((ArrayEncodedValue)o).getValue()); } public int getValueType() { return ValueType.ARRAY; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseBooleanEncodedValue.java000066400000000000000000000050341342202223400306500ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Booleans; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.BooleanEncodedValue; import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseBooleanEncodedValue implements BooleanEncodedValue { @Override public int hashCode() { return getValue()?1:0; } @Override public boolean equals(@Nullable Object o) { if (o instanceof BooleanEncodedValue) { return getValue() == ((BooleanEncodedValue)o).getValue(); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return Booleans.compare(getValue(), ((BooleanEncodedValue)o).getValue()); } public int getValueType() { return ValueType.BOOLEAN; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseByteEncodedValue.java000066400000000000000000000047211342202223400301760ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.ByteEncodedValue; import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseByteEncodedValue implements ByteEncodedValue { @Override public int hashCode() { return getValue(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof ByteEncodedValue) { return getValue() == ((ByteEncodedValue)o).getValue(); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return Ints.compare(getValue(), ((ByteEncodedValue)o).getValue()); } public int getValueType() { return ValueType.BYTE; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseCharEncodedValue.java000066400000000000000000000047751342202223400301610ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Chars; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.CharEncodedValue; import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseCharEncodedValue implements CharEncodedValue { @Override public int hashCode() { return getValue(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof CharEncodedValue) { return getValue() == ((CharEncodedValue)o).getValue(); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return Chars.compare(getValue(), ((CharEncodedValue)o).getValue()); } public int getValueType() { return ValueType.CHAR; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseDoubleEncodedValue.java000066400000000000000000000051541342202223400305060ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.DoubleEncodedValue; import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseDoubleEncodedValue implements DoubleEncodedValue { @Override public int hashCode() { long v = Double.doubleToRawLongBits(getValue()); return (int)(v^(v>>>32)); } @Override public boolean equals(@Nullable Object o) { if (o instanceof DoubleEncodedValue) { return Double.doubleToRawLongBits(getValue()) == Double.doubleToRawLongBits(((DoubleEncodedValue)o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return Double.compare(getValue(), ((DoubleEncodedValue)o).getValue()); } public int getValueType() { return ValueType.DOUBLE; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseEnumEncodedValue.java000066400000000000000000000047351342202223400302040ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.EnumEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseEnumEncodedValue implements EnumEncodedValue { @Override public int hashCode() { return getValue().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof EnumEncodedValue) { return getValue().equals(((EnumEncodedValue)o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return getValue().compareTo(((EnumEncodedValue)o).getValue()); } public int getValueType() { return ValueType.ENUM; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseFieldEncodedValue.java000066400000000000000000000047441342202223400303230ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.FieldEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseFieldEncodedValue implements FieldEncodedValue { @Override public int hashCode() { return getValue().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof FieldEncodedValue) { return getValue().equals(((FieldEncodedValue)o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return getValue().compareTo(((FieldEncodedValue)o).getValue()); } public int getValueType() { return ValueType.FIELD; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseFloatEncodedValue.java000066400000000000000000000050611342202223400303360ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.FloatEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseFloatEncodedValue implements FloatEncodedValue { @Override public int hashCode() { return Float.floatToRawIntBits(getValue()); } @Override public boolean equals(@Nullable Object o) { if (o != null && o instanceof FloatEncodedValue) { return Float.floatToRawIntBits(getValue()) == Float.floatToRawIntBits(((FloatEncodedValue)o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return Float.compare(getValue(), ((FloatEncodedValue)o).getValue()); } public int getValueType() { return ValueType.FLOAT; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseIntEncodedValue.java000066400000000000000000000047121342202223400300250ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.IntEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseIntEncodedValue implements IntEncodedValue { @Override public int hashCode() { return getValue(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof IntEncodedValue) { return getValue() == ((IntEncodedValue)o).getValue(); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return Ints.compare(getValue(), ((IntEncodedValue)o).getValue()); } public int getValueType() { return ValueType.INT; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseLongEncodedValue.java000066400000000000000000000051261342202223400301720ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.LongEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseLongEncodedValue implements LongEncodedValue { @Override public int hashCode() { long value = getValue(); int hashCode = (int)value; return hashCode*31 + (int)(value>>>32); } @Override public boolean equals(@Nullable Object o) { if (o instanceof LongEncodedValue) { return getValue() == ((LongEncodedValue)o).getValue(); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return Longs.compare(getValue(), ((LongEncodedValue)o).getValue()); } public int getValueType() { return ValueType.LONG; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseMethodEncodedValue.java000066400000000000000000000047531342202223400305200ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.MethodEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseMethodEncodedValue implements MethodEncodedValue { @Override public int hashCode() { return getValue().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof MethodEncodedValue) { return getValue().equals(((MethodEncodedValue)o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return getValue().compareTo(((MethodEncodedValue)o).getValue()); } public int getValueType() { return ValueType.METHOD; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseMethodHandleEncodedValue.java000066400000000000000000000050061342202223400316240ustar00rootroot00000000000000/* * Copyright 2018, 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.MethodHandleEncodedValue; import javax.annotation.Nonnull; public abstract class BaseMethodHandleEncodedValue implements MethodHandleEncodedValue { @Override public int hashCode() { return getValue().hashCode(); } @Override public boolean equals(Object o) { if (o instanceof MethodHandleEncodedValue) { return getValue().equals(((MethodHandleEncodedValue) o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return getValue().compareTo(((MethodHandleEncodedValue) o).getValue()); } @Override public int getValueType() { return ValueType.METHOD_HANDLE; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseMethodTypeEncodedValue.java000066400000000000000000000047701342202223400313610ustar00rootroot00000000000000/* * Copyright 2018, 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.MethodTypeEncodedValue; import javax.annotation.Nonnull; public abstract class BaseMethodTypeEncodedValue implements MethodTypeEncodedValue { @Override public int hashCode() { return getValue().hashCode(); } @Override public boolean equals(Object o) { if (o instanceof MethodTypeEncodedValue) { return getValue().equals(((MethodTypeEncodedValue) o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return getValue().compareTo(((MethodTypeEncodedValue) o).getValue()); } @Override public int getValueType() { return ValueType.METHOD_TYPE; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseNullEncodedValue.java000066400000000000000000000043661342202223400302120ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.NullEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseNullEncodedValue implements NullEncodedValue { @Override public int hashCode() { return 0; } @Override public boolean equals(@Nullable Object o) { return o instanceof NullEncodedValue; } @Override public int compareTo(@Nonnull EncodedValue o) { return Ints.compare(getValueType(), o.getValueType()); } public int getValueType() { return ValueType.NULL; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseShortEncodedValue.java000066400000000000000000000050061342202223400303670ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import com.google.common.primitives.Shorts; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.ShortEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseShortEncodedValue implements ShortEncodedValue { @Override public int hashCode() { return getValue(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof ShortEncodedValue) { return getValue() == ((ShortEncodedValue)o).getValue(); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return Shorts.compare(getValue(), ((ShortEncodedValue)o).getValue()); } public int getValueType() { return ValueType.SHORT; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseStringEncodedValue.java000066400000000000000000000047531342202223400305460ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.StringEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseStringEncodedValue implements StringEncodedValue { @Override public int hashCode() { return getValue().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof StringEncodedValue) { return getValue().equals(((StringEncodedValue)o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return getValue().compareTo(((StringEncodedValue)o).getValue()); } public int getValueType() { return ValueType.STRING; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/base/value/BaseTypeEncodedValue.java000066400000000000000000000047351342202223400302210ustar00rootroot00000000000000/* * 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.base.value; import com.google.common.primitives.Ints; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.iface.value.TypeEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BaseTypeEncodedValue implements TypeEncodedValue { @Override public int hashCode() { return getValue().hashCode(); } @Override public boolean equals(@Nullable Object o) { if (o instanceof TypeEncodedValue) { return getValue().equals(((TypeEncodedValue)o).getValue()); } return false; } @Override public int compareTo(@Nonnull EncodedValue o) { int res = Ints.compare(getValueType(), o.getValueType()); if (res != 0) return res; return getValue().compareTo(((TypeEncodedValue)o).getValue()); } public int getValueType() { return ValueType.TYPE; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/000077500000000000000000000000001342202223400227525ustar00rootroot00000000000000smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/BuilderDebugItem.java000066400000000000000000000040151342202223400267710ustar00rootroot00000000000000/* * Copyright 2013, 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.builder; import org.jf.dexlib2.iface.debug.DebugItem; public abstract class BuilderDebugItem extends ItemWithLocation implements DebugItem { public BuilderDebugItem() { } @Override public int getCodeAddress() { if (location == null) { throw new IllegalStateException("Cannot get the address of a BuilderDebugItem that isn't associated with " + "a method."); } return location.getCodeAddress(); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/BuilderExceptionHandler.java000066400000000000000000000072611342202223400303660ustar00rootroot00000000000000/* * Copyright 2013, 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.builder; import org.jf.dexlib2.base.BaseExceptionHandler; import org.jf.dexlib2.iface.reference.TypeReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BuilderExceptionHandler extends BaseExceptionHandler { @Nonnull protected final Label handler; private BuilderExceptionHandler(@Nonnull Label handler) { this.handler = handler; } @Nonnull public Label getHandler() { return handler; } static BuilderExceptionHandler newExceptionHandler(@Nullable final TypeReference exceptionType, @Nonnull Label handler) { if (exceptionType == null) { return newExceptionHandler(handler); } return new BuilderExceptionHandler(handler) { @Nullable @Override public String getExceptionType() { return exceptionType.getType(); } @Override public int getHandlerCodeAddress() { return handler.getCodeAddress(); } @Nullable @Override public TypeReference getExceptionTypeReference() { return exceptionType; } }; } static BuilderExceptionHandler newExceptionHandler(@Nonnull Label handler) { return new BuilderExceptionHandler(handler) { @Nullable @Override public String getExceptionType() { return null; } @Override public int getHandlerCodeAddress() { return handler.getCodeAddress(); } }; } static BuilderExceptionHandler newExceptionHandler(@Nullable final String exceptionType, @Nonnull Label handler) { if (exceptionType == null) { return newExceptionHandler(handler); } return new BuilderExceptionHandler(handler) { @Nullable @Override public String getExceptionType() { return exceptionType; } @Override public int getHandlerCodeAddress() { return handler.getCodeAddress(); } }; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/BuilderInstruction.java000066400000000000000000000050411342202223400274450ustar00rootroot00000000000000/* * 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.builder; import org.jf.dexlib2.Format; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.iface.instruction.Instruction; import org.jf.dexlib2.util.Preconditions; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class BuilderInstruction implements Instruction { @Nonnull protected final Opcode opcode; @Nullable MethodLocation location; protected BuilderInstruction(@Nonnull Opcode opcode) { Preconditions.checkFormat(opcode, getFormat()); this.opcode = opcode; } @Nonnull public Opcode getOpcode() { return opcode; } public abstract Format getFormat(); public int getCodeUnits() { return getFormat().size / 2; } @Nonnull public MethodLocation getLocation() { if (location == null) { throw new IllegalStateException("Cannot get the location of an instruction that hasn't been added to a " + "method."); } return location; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/BuilderOffsetInstruction.java000066400000000000000000000057051342202223400306230ustar00rootroot00000000000000/* * Copyright 2013, 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.builder; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.iface.instruction.OffsetInstruction; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; public abstract class BuilderOffsetInstruction extends BuilderInstruction implements OffsetInstruction { @Nonnull protected final Label target; public BuilderOffsetInstruction(@Nonnull Opcode opcode, @Nonnull Label target) { super(opcode); this.target = target; } @Override public int getCodeOffset() { int codeOffset = internalGetCodeOffset(); if (this.getCodeUnits() == 1) { if (codeOffset < Byte.MIN_VALUE || codeOffset > Byte.MAX_VALUE) { throw new ExceptionWithContext("Invalid instruction offset: %d. " + "Offset must be in [-128, 127]", codeOffset); } } else if (this.getCodeUnits() == 2) { if (codeOffset < Short.MIN_VALUE || codeOffset > Short.MAX_VALUE) { throw new ExceptionWithContext("Invalid instruction offset: %d. " + "Offset must be in [-32768, 32767]", codeOffset); } } return codeOffset; } int internalGetCodeOffset() { return target.getCodeAddress() - this.getLocation().getCodeAddress(); } @Nonnull public Label getTarget() { return target; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/BuilderSwitchPayload.java000066400000000000000000000045141342202223400277030ustar00rootroot00000000000000/* * Copyright 2013, 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.builder; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.builder.instruction.BuilderSwitchElement; import org.jf.dexlib2.iface.instruction.SwitchPayload; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; public abstract class BuilderSwitchPayload extends BuilderInstruction implements SwitchPayload { @Nullable MethodLocation referrer; protected BuilderSwitchPayload(@Nonnull Opcode opcode) { super(opcode); } @Nonnull public MethodLocation getReferrer() { if (referrer == null) { throw new IllegalStateException("The referrer has not been set yet"); } return referrer; } @Nonnull @Override public abstract List getSwitchElements(); } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/BuilderTryBlock.java000066400000000000000000000067371342202223400266720ustar00rootroot00000000000000/* * Copyright 2013, 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.builder; import com.google.common.collect.ImmutableList; import org.jf.dexlib2.base.BaseTryBlock; import org.jf.dexlib2.iface.reference.TypeReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; public class BuilderTryBlock extends BaseTryBlock { // We only ever have one exception handler per try block. They are later merged as needed in TryListBuilder @Nonnull public final BuilderExceptionHandler exceptionHandler; @Nonnull public final Label start; // The end location is exclusive, it should point to the codeAddress of the instruction immediately after the last // covered instruction. @Nonnull public final Label end; public BuilderTryBlock(@Nonnull Label start, @Nonnull Label end, @Nullable String exceptionType, @Nonnull Label handler) { this.start = start; this.end = end; this.exceptionHandler = BuilderExceptionHandler.newExceptionHandler(exceptionType, handler); } public BuilderTryBlock(@Nonnull Label start, @Nonnull Label end, @Nullable TypeReference exceptionType, @Nonnull Label handler) { this.start = start; this.end = end; this.exceptionHandler = BuilderExceptionHandler.newExceptionHandler(exceptionType, handler); } public BuilderTryBlock(@Nonnull Label start, @Nonnull Label end, @Nonnull Label handler) { this.start = start; this.end = end; this.exceptionHandler = BuilderExceptionHandler.newExceptionHandler(handler); } @Override public int getStartCodeAddress() { return start.getCodeAddress(); } @Override public int getCodeUnitCount() { return end.getCodeAddress() - start.getCodeAddress(); } @Nonnull @Override public List getExceptionHandlers() { return ImmutableList.of(exceptionHandler); } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/ItemWithLocation.java000066400000000000000000000005111342202223400270350ustar00rootroot00000000000000package org.jf.dexlib2.builder; import javax.annotation.Nullable; public abstract class ItemWithLocation { @Nullable MethodLocation location; public boolean isPlaced() { return location != null; } public void setLocation(MethodLocation methodLocation) { location = methodLocation; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/Label.java000066400000000000000000000040721342202223400246370ustar00rootroot00000000000000/* * Copyright 2013, 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.builder; import javax.annotation.Nonnull; public class Label extends ItemWithLocation { Label() { } Label(MethodLocation location) { this.location = location; } public int getCodeAddress() { return getLocation().getCodeAddress(); } @Nonnull public MethodLocation getLocation() { if (location == null) { throw new IllegalStateException("Cannot get the location of a label that hasn't been placed yet."); } return location; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/LocatedDebugItems.java000066400000000000000000000005131342202223400271400ustar00rootroot00000000000000package org.jf.dexlib2.builder; public class LocatedDebugItems extends LocatedItems { @Override protected String getAddLocatedItemError() { return "Cannot add a debug item that has already been added to a method." + "You must remove it from its current location first."; } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/LocatedItems.java000066400000000000000000000054551342202223400262030ustar00rootroot00000000000000package org.jf.dexlib2.builder; import com.google.common.collect.ImmutableList; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; public abstract class LocatedItems { // We end up creating and keeping around a *lot* of MethodLocation objects // when building a new dex file, so it's worth the trouble of lazily creating // the labels and debugItems lists only when they are needed @Nullable private List items = null; @Nonnull private List getItems() { if (items == null) { return ImmutableList.of(); } return items; } public Set getModifiableItems(MethodLocation newItemsLocation) { return new AbstractSet() { @Nonnull @Override public Iterator iterator() { final Iterator it = getItems().iterator(); return new Iterator() { private @Nullable T currentItem = null; @Override public boolean hasNext() { return it.hasNext(); } @Override public T next() { currentItem = it.next(); return currentItem; } @Override public void remove() { if (currentItem != null) { currentItem.setLocation(null); } it.remove(); } }; } @Override public int size() { return getItems().size(); } @Override public boolean add(@Nonnull T item) { if (item.isPlaced()) { throw new IllegalArgumentException(getAddLocatedItemError()); } item.setLocation(newItemsLocation); addItem(item); return true; } }; } private void addItem(@Nonnull T item) { if (items == null) { items = new ArrayList<>(1); } items.add(item); } protected abstract String getAddLocatedItemError(); public void mergeItemsIntoNext(@Nonnull MethodLocation nextLocation, LocatedItems otherLocatedItems) { if (otherLocatedItems == this) { return; } if (items != null) { for (T item : items) { item.setLocation(nextLocation); } List mergedItems = items; mergedItems.addAll(otherLocatedItems.getItems()); otherLocatedItems.items = mergedItems; items = null; } } } smali-2.2.6/dexlib2/src/main/java/org/jf/dexlib2/builder/LocatedLabels.java000066400000000000000000000004451342202223400263160ustar00rootroot00000000000000package org.jf.dexlib2.builder; public class LocatedLabels extends LocatedItems