aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Light <allight@google.com>2015-09-28 16:43:03 -0700
committerAlex Light <allight@google.com>2015-09-28 16:43:03 -0700
commitbdccf9c3ef6f14aa499e1e1f31ed0742cbdaa2a5 (patch)
tree4384941ba7ed66a92cbb80c18960d19a93182ae5
parentdb3791542b8e836b60544b8941a17628c9aad1f9 (diff)
parent613c493e9698812c0531acf073bc7ca9e4538eac (diff)
downloadsmali-bdccf9c3ef6f14aa499e1e1f31ed0742cbdaa2a5.tar.gz
Merge remote-tracking branch 'aosp/upstream-master' into aosp/master
* Brings up c456c55c40d0731edb9913fae73f16b9d94ac45b which fixes a smali bug relating to interface ordering.
-rw-r--r--README.md10
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java3
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/InterfaceOrderTest.java41
-rw-r--r--baksmali/src/test/resources/InterfaceOrderTest/InterfaceOrder.smali37
-rw-r--r--build.gradle22
-rw-r--r--dexlib2/build.gradle47
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java11
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java4
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionClassDef.java28
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java13
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java4
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java11
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java4
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java12
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/iface/ClassDef.java7
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableClassDef.java13
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/rewriter/ClassDefRewriter.java5
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java2
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java32
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java13
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java2
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java10
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java2
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java6
-rw-r--r--dexlib2/src/test/resources/accessorTest.dexbin0 -> 28940 bytes
-rw-r--r--smali/src/main/java/org/jf/smali/main.java85
26 files changed, 323 insertions, 101 deletions
diff --git a/README.md b/README.md
index 52c24db9..57848991 100644
--- a/README.md
+++ b/README.md
@@ -2,16 +2,16 @@
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.)
-The primary webpage is http://smali.googlecode.com, and the source is also mirrored at https://github.com/jesusfreke/smali. If you are interested in submitting a patch, feel free to send me a pull request on either site.
+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.
#### Support
-- [googlecode Issue tracker](https://code.google.com/p/smali/issues/list) - 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. Think of it more in terms of.. multi-player notepad.
+- [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://code.google.com/p/smali/wiki/Registers)
-- [Types, Methods and Fields wiki page](https://code.google.com/p/smali/wiki/TypesMethodsAndFields)
+- [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)
diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java
index 9c171f49..2529af8a 100644
--- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java
+++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java
@@ -146,8 +146,7 @@ public class ClassDefinition {
}
private void writeInterfaces(IndentingWriter writer) throws IOException {
- List<String> interfaces = Lists.newArrayList(classDef.getInterfaces());
- Collections.sort(interfaces);
+ List<String> interfaces = classDef.getInterfaces();
if (interfaces.size() != 0) {
writer.write('\n');
diff --git a/baksmali/src/test/java/org/jf/baksmali/InterfaceOrderTest.java b/baksmali/src/test/java/org/jf/baksmali/InterfaceOrderTest.java
new file mode 100644
index 00000000..d85d7913
--- /dev/null
+++ b/baksmali/src/test/java/org/jf/baksmali/InterfaceOrderTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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());
+ }
+}
diff --git a/baksmali/src/test/resources/InterfaceOrderTest/InterfaceOrder.smali b/baksmali/src/test/resources/InterfaceOrderTest/InterfaceOrder.smali
new file mode 100644
index 00000000..b4745cb3
--- /dev/null
+++ b/baksmali/src/test/resources/InterfaceOrderTest/InterfaceOrder.smali
@@ -0,0 +1,37 @@
+.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 <init>()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
diff --git a/build.gradle b/build.gradle
index f0d1e00a..edf156fe 100644
--- a/build.gradle
+++ b/build.gradle
@@ -31,7 +31,7 @@
apply plugin: 'idea'
-version = '2.0.5'
+version = '2.0.8'
def jarVersion = version
@@ -57,6 +57,11 @@ if (!('release' in gradle.startParameter.taskNames)) {
// use something like module-1.2.3-dev.jar for the jar name, rather than the full
// module-1.2.3-001afe02-dirty.jar
jarVersion = baseVersion + '-dev'
+} else {
+ if (System.env.JDK6_HOME == null && !JavaVersion.current().isJava6()) {
+ throw new InvalidUserDataException("bzzzzzzzt. Release builds must be performed with java 6. " +
+ "Either run gradle with java 6, or define the JDK6_HOME environment variable.")
+ }
}
// Note: please don't use this. This is strictly for the official releases
@@ -79,6 +84,19 @@ subprojects {
}
}
+ if (System.env.JDK6_HOME != null) {
+ sourceCompatibility = 1.6
+ targetCompatibility = 1.6
+
+ tasks.withType(JavaCompile) {
+ doFirst {
+ options.fork = true
+ options.bootClasspath = "$System.env.JDK6_HOME/jre/lib/rt.jar"
+ options.bootClasspath += "$File.pathSeparator$System.env.JDK6_HOME/jre/lib/jsse.jar"
+ }
+ }
+ }
+
version = parent.version
ext {
@@ -90,7 +108,7 @@ subprojects {
stringtemplate: 'org.antlr:stringtemplate:3.2.1',
commons_cli: 'commons-cli:commons-cli:1.2',
jflex: 'de.jflex:jflex:1.4.3',
- jflex_plugin: 'co.tomlee.gradle.plugins:gradle-jflex-plugin:0.0.1',
+ jflex_plugin: 'co.tomlee.gradle.plugins:gradle-jflex-plugin:0.0.2',
proguard_gradle: 'net.sf.proguard:proguard-gradle:5.2.1',
dx: 'com.google.android.tools:dx:1.7'
]
diff --git a/dexlib2/build.gradle b/dexlib2/build.gradle
index dc3e853a..8fbe5ffe 100644
--- a/dexlib2/build.gradle
+++ b/dexlib2/build.gradle
@@ -29,6 +29,17 @@
* 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
@@ -46,9 +57,6 @@ dependencies {
dx depends.dx
}
-ext.testAccessorOutputDir = file("${buildDir}/generated-accessor-test-sources")
-ext.testAccessorOutputFile = file("${buildDir}/generated-accessor-test-sources/org/jf/dexlib2/AccessorTypes.java")
-
// You must manually execute this task to regenerate SyntheticAccessorFSM.java, after modifying the ragel file
// e.g. ./gradlew ragel
task ragel(type:Exec) {
@@ -59,48 +67,31 @@ task ragel(type:Exec) {
}
task generateAccessorTestSource(type: JavaExec) {
- doFirst {
- file(testAccessorOutputFile.parent).mkdirs()
- }
-
+ file(testAccessorOutputFile.parent).mkdirs()
outputs.dir file(testAccessorOutputDir)
- sourceSets['test'].java.srcDir file(testAccessorOutputDir)
classpath = configurations.accessorTestGenerator
main = 'org.jf.dexlib2.AccessorTestGenerator'
args testAccessorOutputFile
}
-compileTestJava.dependsOn generateAccessorTestSource
-
-task generateAccessorTestDex(type: JavaExec, dependsOn: compileTestJava) {
- def outputDex = file(new File(sourceSets.test.output.resourcesDir, 'accessorTest.dex'))
+compileAccessorTestJava.dependsOn(generateAccessorTestSource)
- doFirst {
- file(outputDex.parent).mkdirs()
-
- // this has to be done in doFirst, so that the generated classes will be available.
- // otherwise, it the tree will be populated while the build is being configured,
- // which is before the compileTestJava has run
- fileTree(project.sourceSets.test.output.classesDir) {
- include 'org/jf/dexlib2/AccessorTypes*.class'
- }.each { File file ->
- args file
- }
- }
+// 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.test.output.classesDir)
+ inputs.dir(project.sourceSets.accessorTest.output.classesDir)
outputs.file outputDex
main 'com.android.dx.command.Main'
classpath = configurations.dx
- workingDir project.sourceSets.test.output.classesDir
- //executable 'dx'
args '--dex'
args '--no-strict'
args "--output=${outputDex}"
+ args sourceSets.accessorTest.output.classesDir
}
-test.dependsOn generateAccessorTestDex
uploadArchives {
repositories.mavenDeployer {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
index a1ddee2e..113b60a3 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
@@ -45,12 +45,23 @@ import java.util.zip.ZipFile;
public final class DexFileFactory {
@Nonnull
+ public static DexBackedDexFile loadDexFile(String path, int api)
+ throws IOException {
+ return loadDexFile(path, api, false);
+ }
+
+ @Nonnull
public static DexBackedDexFile loadDexFile(String path, int api, boolean experimental)
throws IOException {
return loadDexFile(new File(path), "classes.dex", new Opcodes(api, experimental));
}
@Nonnull
+ public static DexBackedDexFile loadDexFile(File dexFile, int api) throws IOException {
+ return loadDexFile(dexFile, api, false);
+ }
+
+ @Nonnull
public static DexBackedDexFile loadDexFile(File dexFile, int api, boolean experimental)
throws IOException {
return loadDexFile(dexFile, "classes.dex", new Opcodes(api, experimental));
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java b/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java
index dd876813..e718e275 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java
@@ -40,6 +40,10 @@ public class Opcodes {
private final Opcode[] opcodesByValue;
private final HashMap<String, Opcode> opcodesByName;
+ public Opcodes(int api) {
+ this(api, false);
+ }
+
public Opcodes(int api, boolean experimental) {
opcodesByValue = new Opcode[256];
opcodesByName = Maps.newHashMap();
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionClassDef.java
index fc1dc62f..7e8a2829 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionClassDef.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionClassDef.java
@@ -33,6 +33,7 @@ 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;
@@ -48,6 +49,7 @@ 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;
/**
@@ -78,23 +80,17 @@ public class ReflectionClassDef extends BaseTypeReference implements ClassDef {
return ReflectionUtils.javaToDexName(superClass.getName());
}
- @Nonnull @Override public Set<String> getInterfaces() {
- return new AbstractSet<String>() {
- @Nonnull @Override public Iterator<String> iterator() {
- return Iterators.transform(Iterators.forArray(cls.getInterfaces()), new Function<Class, String>() {
- @Nullable @Override public String apply(@Nullable Class input) {
- if (input == null) {
- return null;
- }
- return ReflectionUtils.javaToDexName(input.getName());
- }
- });
+ @Nonnull @Override public List<String> getInterfaces() {
+ return ImmutableList.copyOf(Iterators.transform(Iterators.forArray(cls.getInterfaces()), new Function<Class, String>() {
+ @Nullable
+ @Override
+ public String apply(@Nullable Class input) {
+ if (input == null) {
+ return null;
+ }
+ return ReflectionUtils.javaToDexName(input.getName());
}
-
- @Override public int size() {
- return cls.getInterfaces().length;
- }
- };
+ }));
}
@Nullable @Override public String getSourceFile() {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java
index 9596a278..88f1dce9 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.dexbacked;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.jf.dexlib2.base.reference.BaseTypeReference;
@@ -47,7 +48,9 @@ import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import java.util.AbstractList;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
@@ -114,21 +117,21 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
@Nonnull
@Override
- public Set<String> getInterfaces() {
+ public List<String> getInterfaces() {
final int interfacesOffset = dexFile.readSmallUint(classDefOffset + ClassDefItem.INTERFACES_OFFSET);
if (interfacesOffset > 0) {
final int size = dexFile.readSmallUint(interfacesOffset);
- return new FixedSizeSet<String>() {
- @Nonnull
+ return new AbstractList<String>() {
@Override
- public String readItem(int index) {
+ @Nonnull
+ public String get(int index) {
return dexFile.getType(dexFile.readUshort(interfacesOffset + 4 + (2*index)));
}
@Override public int size() { return size; }
};
}
- return ImmutableSet.of();
+ return ImmutableList.of();
}
@Nonnull
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java
index f26b7e12..eccb9218 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java
@@ -32,7 +32,7 @@
package org.jf.dexlib2.dexbacked;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterators;
+import com.google.common.collect.ImmutableSet;
import org.jf.dexlib2.base.reference.BaseMethodReference;
import org.jf.dexlib2.dexbacked.raw.MethodIdItem;
import org.jf.dexlib2.dexbacked.raw.ProtoIdItem;
@@ -152,7 +152,7 @@ public class DexBackedMethod extends BaseMethodReference implements Method {
if (methodImpl != null) {
return methodImpl.getParameterNames(null);
}
- return Iterators.emptyIterator();
+ return ImmutableSet.<String>of().iterator();
}
@Nonnull
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java
index 0c06b1d7..676d86cd 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethodImplementation.java
@@ -123,7 +123,16 @@ public class DexBackedMethodImplementation implements MethodImplementation {
@Nonnull
private DebugInfo getDebugInfo() {
- return DebugInfo.newOrEmpty(dexFile, dexFile.readSmallUint(codeOffset + CodeItem.DEBUG_INFO_OFFSET), this);
+ int debugOffset = dexFile.readInt(codeOffset + CodeItem.DEBUG_INFO_OFFSET);
+
+ if (debugOffset == -1 || debugOffset == 0) {
+ return DebugInfo.newOrEmpty(dexFile, 0, this);
+ }
+ if (debugOffset < 0) {
+ System.err.println("%s: Invalid debug offset");
+ return DebugInfo.newOrEmpty(dexFile, 0, this);
+ }
+ return DebugInfo.newOrEmpty(dexFile, debugOffset, this);
}
@Nonnull @Override
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java
index 9c79e270..27d72ad1 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java
@@ -100,10 +100,10 @@ public class CodeItem {
int triesCount = reader.readUshort();
out.annotate(2, "tries_size = %d", triesCount);
- int debugInfoOffset = reader.readSmallUint();
+ int debugInfoOffset = reader.readInt();
out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset);
- if (debugInfoOffset != 0) {
+ if (debugInfoOffset > 0) {
addDebugInfoIdentity(debugInfoOffset, itemIdentity);
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java
index 6759820e..8a32b5f6 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java
@@ -31,12 +31,12 @@
package org.jf.dexlib2.dexbacked.util;
-import com.google.common.collect.Iterators;
+import com.google.common.collect.ImmutableSet;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.DebugItemType;
+import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.dexbacked.DexBackedMethod;
import org.jf.dexlib2.dexbacked.DexBackedMethodImplementation;
-import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.dexbacked.DexReader;
import org.jf.dexlib2.iface.MethodParameter;
import org.jf.dexlib2.iface.debug.DebugItem;
@@ -70,9 +70,13 @@ public abstract class DebugInfo implements Iterable<DebugItem> {
private static class EmptyDebugInfo extends DebugInfo {
public static final EmptyDebugInfo INSTANCE = new EmptyDebugInfo();
private EmptyDebugInfo() {}
- @Nonnull @Override public Iterator<DebugItem> iterator() { return Iterators.emptyIterator(); }
+
+ @Nonnull @Override public Iterator<DebugItem> iterator() {
+ return ImmutableSet.<DebugItem>of().iterator();
+ }
+
@Nonnull @Override public Iterator<String> getParameterNames(@Nullable DexReader reader) {
- return Iterators.emptyIterator();
+ return ImmutableSet.<String>of().iterator();
}
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/ClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/ClassDef.java
index 31d7fb99..78e17b15 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/iface/ClassDef.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/ClassDef.java
@@ -35,6 +35,7 @@ import org.jf.dexlib2.iface.reference.TypeReference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import java.util.List;
import java.util.Set;
/**
@@ -72,11 +73,11 @@ public interface ClassDef extends TypeReference, Annotatable {
@Nullable String getSuperclass();
/**
- * Gets a set of the interfaces that this class implements.
+ * Gets a list of the interfaces that this class implements.
*
- * @return A set of the interfaces that this class implements
+ * @return A list of the interfaces that this class implements
*/
- @Nonnull Set<String> getInterfaces();
+ @Nonnull List<String> getInterfaces();
/**
* Gets the name of the primary source file that this class is defined in, if available.
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableClassDef.java
index 42e14549..8bdfff26 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableClassDef.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableClassDef.java
@@ -47,12 +47,13 @@ import javax.annotation.Nullable;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
@Nonnull protected final String type;
protected final int accessFlags;
@Nullable protected final String superclass;
- @Nonnull protected final ImmutableSet<String> interfaces;
+ @Nonnull protected final ImmutableList<String> interfaces;
@Nullable protected final String sourceFile;
@Nonnull protected final ImmutableSet<? extends ImmutableAnnotation> annotations;
@Nonnull protected final ImmutableSortedSet<? extends ImmutableField> staticFields;
@@ -78,7 +79,7 @@ public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
this.type = type;
this.accessFlags = accessFlags;
this.superclass = superclass;
- this.interfaces = interfaces==null ? ImmutableSet.<String>of() : ImmutableSet.copyOf(interfaces);
+ this.interfaces = interfaces==null ? ImmutableList.<String>of() : ImmutableList.copyOf(interfaces);
this.sourceFile = sourceFile;
this.annotations = ImmutableAnnotation.immutableSetOf(annotations);
this.staticFields = ImmutableField.immutableSetOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC));
@@ -100,7 +101,7 @@ public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
this.type = type;
this.accessFlags = accessFlags;
this.superclass = superclass;
- this.interfaces = interfaces==null ? ImmutableSet.<String>of() : ImmutableSet.copyOf(interfaces);
+ this.interfaces = interfaces==null ? ImmutableList.<String>of() : ImmutableList.copyOf(interfaces);
this.sourceFile = sourceFile;
this.annotations = ImmutableAnnotation.immutableSetOf(annotations);
this.staticFields = ImmutableField.immutableSetOf(staticFields);
@@ -112,7 +113,7 @@ public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
public ImmutableClassDef(@Nonnull String type,
int accessFlags,
@Nullable String superclass,
- @Nullable ImmutableSet<String> interfaces,
+ @Nullable ImmutableList<String> interfaces,
@Nullable String sourceFile,
@Nullable ImmutableSet<? extends ImmutableAnnotation> annotations,
@Nullable ImmutableSortedSet<? extends ImmutableField> staticFields,
@@ -122,7 +123,7 @@ public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
this.type = type;
this.accessFlags = accessFlags;
this.superclass = superclass;
- this.interfaces = ImmutableUtils.nullToEmptySet(interfaces);
+ this.interfaces = ImmutableUtils.nullToEmptyList(interfaces);
this.sourceFile = sourceFile;
this.annotations = ImmutableUtils.nullToEmptySet(annotations);
this.staticFields = ImmutableUtils.nullToEmptySortedSet(staticFields);
@@ -151,7 +152,7 @@ public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
@Nonnull @Override public String getType() { return type; }
@Override public int getAccessFlags() { return accessFlags; }
@Nullable @Override public String getSuperclass() { return superclass; }
- @Nonnull @Override public ImmutableSet<String> getInterfaces() { return interfaces; }
+ @Nonnull @Override public ImmutableList<String> getInterfaces() { return interfaces; }
@Nullable @Override public String getSourceFile() { return sourceFile; }
@Nonnull @Override public ImmutableSet<? extends ImmutableAnnotation> getAnnotations() { return annotations; }
@Nonnull @Override public ImmutableSet<? extends ImmutableField> getStaticFields() { return staticFields; }
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ClassDefRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ClassDefRewriter.java
index ad246e5b..7e34ee33 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ClassDefRewriter.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ClassDefRewriter.java
@@ -41,6 +41,7 @@ import org.jf.dexlib2.iface.Method;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
public class ClassDefRewriter implements Rewriter<ClassDef> {
@@ -73,8 +74,8 @@ public class ClassDefRewriter implements Rewriter<ClassDef> {
return RewriterUtils.rewriteNullable(rewriters.getTypeRewriter(), classDef.getSuperclass());
}
- @Override @Nonnull public Set<String> getInterfaces() {
- return RewriterUtils.rewriteSet(rewriters.getTypeRewriter(), classDef.getInterfaces());
+ @Override @Nonnull public List<String> getInterfaces() {
+ return RewriterUtils.rewriteList(rewriters.getTypeRewriter(), classDef.getInterfaces());
}
@Override @Nullable public String getSourceFile() {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java
index bb2e4a72..d28dd444 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java
@@ -53,7 +53,7 @@ public interface ClassSection<StringKey extends CharSequence, TypeKey extends Ch
@Nonnull TypeKey getType(@Nonnull ClassKey key);
int getAccessFlags(@Nonnull ClassKey key);
@Nullable TypeKey getSuperclass(@Nonnull ClassKey key);
- @Nullable TypeListKey getSortedInterfaces(@Nonnull ClassKey key);
+ @Nullable TypeListKey getInterfaces(@Nonnull ClassKey key);
@Nullable StringKey getSourceFile(@Nonnull ClassKey key);
@Nullable Collection<? extends EncodedValue> getStaticInitializers(@Nonnull ClassKey key);
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java
index 0650ab3c..be23978e 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java
@@ -58,6 +58,7 @@ import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.iface.reference.TypeReference;
import org.jf.dexlib2.util.InstructionUtil;
import org.jf.dexlib2.util.MethodUtil;
+import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.dexlib2.writer.io.DeferredOutputStream;
import org.jf.dexlib2.writer.io.DeferredOutputStreamFactory;
import org.jf.dexlib2.writer.io.DexDataStore;
@@ -196,6 +197,33 @@ public abstract class DexWriter<
classSection.getItems().size() * ClassDefItem.ITEM_SIZE;
}
+ @Nonnull
+ public List<String> getMethodReferences() {
+ List<String> methodReferences = Lists.newArrayList();
+ for (Entry<? extends MethodRefKey, Integer> methodReference: methodSection.getItems()) {
+ methodReferences.add(ReferenceUtil.getMethodDescriptor(methodReference.getKey()));
+ }
+ return methodReferences;
+ }
+
+ @Nonnull
+ public List<String> getFieldReferences() {
+ List<String> fieldReferences = Lists.newArrayList();
+ for (Entry<? extends FieldRefKey, Integer> fieldReference: fieldSection.getItems()) {
+ fieldReferences.add(ReferenceUtil.getFieldDescriptor(fieldReference.getKey()));
+ }
+ return fieldReferences;
+ }
+
+ @Nonnull
+ public List<String> getTypeReferences() {
+ List<String> classReferences = Lists.newArrayList();
+ for (Entry<? extends TypeKey, Integer> typeReference: typeSection.getItems()) {
+ classReferences.add(typeReference.getKey().toString());
+ }
+ return classReferences;
+ }
+
public void writeTo(@Nonnull DexDataStore dest) throws IOException {
this.writeTo(dest, MemoryDeferredOutputStream.getFactory());
}
@@ -405,7 +433,7 @@ public abstract class DexWriter<
nextIndex = writeClass(indexWriter, offsetWriter, nextIndex, superEntry);
// then, try to write interfaces
- for (TypeKey interfaceTypeKey: typeListSection.getTypes(classSection.getSortedInterfaces(key))) {
+ for (TypeKey interfaceTypeKey: typeListSection.getTypes(classSection.getInterfaces(key))) {
Map.Entry<? extends ClassKey, Integer> interfaceEntry = classSection.getClassEntryByType(interfaceTypeKey);
nextIndex = writeClass(indexWriter, offsetWriter, nextIndex, interfaceEntry);
}
@@ -418,7 +446,7 @@ public abstract class DexWriter<
indexWriter.writeInt(typeSection.getItemIndex(classSection.getType(key)));
indexWriter.writeInt(classSection.getAccessFlags(key));
indexWriter.writeInt(typeSection.getNullableItemIndex(classSection.getSuperclass(key)));
- indexWriter.writeInt(typeListSection.getNullableItemOffset(classSection.getSortedInterfaces(key)));
+ indexWriter.writeInt(typeListSection.getNullableItemOffset(classSection.getInterfaces(key)));
indexWriter.writeInt(stringSection.getNullableItemIndex(classSection.getSourceFile(key)));
indexWriter.writeInt(classSection.getAnnotationDirectoryOffset(key));
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java
index f19a2e7f..10215925 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.writer.builder;
+import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.*;
import org.jf.dexlib2.base.reference.BaseTypeReference;
@@ -101,16 +102,8 @@ public class BuilderClassDef extends BaseTypeReference implements ClassDef {
@Nonnull @Override public SortedSet<BuilderMethod> getVirtualMethods() { return virtualMethods; }
@Nonnull @Override
- public Set<String> getInterfaces() {
- return new AbstractSet<String>() {
- @Nonnull @Override public Iterator<String> iterator() {
- return Iterators.transform(interfaces.iterator(), Functions.toStringFunction());
- }
-
- @Override public int size() {
- return interfaces.size();
- }
- };
+ public List<String> getInterfaces() {
+ return Lists.transform(this.interfaces, Functions.toStringFunction());
}
@Nonnull @Override public Collection<BuilderField> getFields() {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java
index 8ab53db8..29980f32 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java
@@ -122,7 +122,7 @@ public class BuilderClassPool implements ClassSection<BuilderStringReference, Bu
return builderClassDef.superclass;
}
- @Nullable @Override public BuilderTypeList getSortedInterfaces(@Nonnull BuilderClassDef builderClassDef) {
+ @Nullable @Override public BuilderTypeList getInterfaces(@Nonnull BuilderClassDef builderClassDef) {
return builderClassDef.interfaces;
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java
index 469a3324..9a727b27 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java
@@ -35,6 +35,7 @@ import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.MethodImplementation;
@@ -117,16 +118,15 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
if (interfaces == null) {
interfaces = ImmutableList.of();
} else {
- interfaces = Lists.newArrayList(interfaces);
- Collections.sort(interfaces);
- String prev = null;
+ Set<String> interfaces_copy = Sets.newHashSet(interfaces);
Iterator<String> interfaceIterator = interfaces.iterator();
while (interfaceIterator.hasNext()) {
String iface = interfaceIterator.next();
- if (prev != null && iface.equals(prev)) {
+ if (!interfaces_copy.contains(iface)) {
interfaceIterator.remove();
+ } else {
+ interfaces_copy.remove(iface);
}
- prev = iface;
}
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java
index 96eca2ae..0389973a 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java
@@ -250,7 +250,7 @@ public class ClassPool implements ClassSection<CharSequence, CharSequence,
return classDef.getSuperclass();
}
- @Nullable @Override public TypeListPool.Key<SortedSet<String>> getSortedInterfaces(@Nonnull PoolClassDef classDef) {
+ @Nullable @Override public TypeListPool.Key<List<String>> getInterfaces(@Nonnull PoolClassDef classDef) {
return classDef.interfaces;
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java
index fe897d26..00958fb8 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java
@@ -43,7 +43,7 @@ import java.util.*;
class PoolClassDef extends BaseTypeReference implements ClassDef {
@Nonnull final ClassDef classDef;
- @Nonnull final TypeListPool.Key<SortedSet<String>> interfaces;
+ @Nonnull final TypeListPool.Key<List<String>> interfaces;
@Nonnull final ImmutableSortedSet<Field> staticFields;
@Nonnull final ImmutableSortedSet<Field> instanceFields;
@Nonnull final ImmutableSortedSet<PoolMethod> directMethods;
@@ -56,7 +56,7 @@ class PoolClassDef extends BaseTypeReference implements ClassDef {
PoolClassDef(@Nonnull ClassDef classDef) {
this.classDef = classDef;
- interfaces = new TypeListPool.Key<SortedSet<String>>(ImmutableSortedSet.copyOf(classDef.getInterfaces()));
+ interfaces = new TypeListPool.Key<List<String>>(ImmutableList.copyOf(classDef.getInterfaces()));
staticFields = ImmutableSortedSet.copyOf(classDef.getStaticFields());
instanceFields = ImmutableSortedSet.copyOf(classDef.getInstanceFields());
directMethods = ImmutableSortedSet.copyOf(
@@ -77,7 +77,7 @@ class PoolClassDef extends BaseTypeReference implements ClassDef {
return classDef.getSuperclass();
}
- @Nonnull @Override public SortedSet<String> getInterfaces() {
+ @Nonnull @Override public List<String> getInterfaces() {
return interfaces.types;
}
diff --git a/dexlib2/src/test/resources/accessorTest.dex b/dexlib2/src/test/resources/accessorTest.dex
new file mode 100644
index 00000000..456f85f4
--- /dev/null
+++ b/dexlib2/src/test/resources/accessorTest.dex
Binary files differ
diff --git a/smali/src/main/java/org/jf/smali/main.java b/smali/src/main/java/org/jf/smali/main.java
index 31f65a88..98fb7a1f 100644
--- a/smali/src/main/java/org/jf/smali/main.java
+++ b/smali/src/main/java/org/jf/smali/main.java
@@ -28,7 +28,9 @@
package org.jf.smali;
+import com.google.common.base.Strings;
import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.Token;
import org.antlr.runtime.TokenSource;
@@ -113,6 +115,15 @@ public class main {
boolean printTokens = false;
boolean experimental = false;
+ boolean listMethods = false;
+ String methodListFilename = null;
+
+ boolean listFields = false;
+ String fieldListFilename = null;
+
+ boolean listTypes = false;
+ String typeListFilename = null;
+
int apiLevel = 15;
String outputDexFile = "out.dex";
@@ -153,6 +164,18 @@ public class main {
case 'j':
jobs = Integer.parseInt(commandLine.getOptionValue("j"));
break;
+ case 'm':
+ listMethods = true;
+ methodListFilename = commandLine.getOptionValue("m");
+ break;
+ case 'f':
+ listFields = true;
+ fieldListFilename = commandLine.getOptionValue("f");
+ break;
+ case 't':
+ listTypes = true;
+ typeListFilename = commandLine.getOptionValue("t");
+ break;
case 'V':
verboseErrors = true;
break;
@@ -232,6 +255,27 @@ public class main {
System.exit(1);
}
+ if (listMethods) {
+ if (Strings.isNullOrEmpty(methodListFilename)) {
+ methodListFilename = outputDexFile + ".methods";
+ }
+ writeReferences(dexBuilder.getMethodReferences(), methodListFilename);
+ }
+
+ if (listFields) {
+ if (Strings.isNullOrEmpty(fieldListFilename)) {
+ fieldListFilename = outputDexFile + ".fields";
+ }
+ writeReferences(dexBuilder.getFieldReferences(), fieldListFilename);
+ }
+
+ if (listTypes) {
+ if (Strings.isNullOrEmpty(typeListFilename)) {
+ typeListFilename = outputDexFile + ".types";
+ }
+ writeReferences(dexBuilder.getTypeReferences(), typeListFilename);
+ }
+
dexBuilder.writeTo(new FileDataStore(new File(outputDexFile)));
} catch (RuntimeException ex) {
System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
@@ -244,6 +288,23 @@ public class main {
}
}
+ private static void writeReferences(List<String> references, String filename) {
+ PrintWriter writer = null;
+ try {
+ writer = new PrintWriter(new BufferedWriter(new FileWriter(filename)));
+
+ for (String reference: Ordering.natural().sortedCopy(references)) {
+ writer.println(reference);
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
private static void getSmaliFilesInDir(@Nonnull File dir, @Nonnull Set<File> smaliFiles) {
File[] files = dir.listFiles();
if (files != null) {
@@ -378,6 +439,27 @@ public class main {
.withArgName("API_LEVEL")
.create("a");
+ Option listMethodsOption = OptionBuilder.withLongOpt("list-methods")
+ .withDescription("Lists all the method references to FILE" +
+ " (<output_dex_filename>.methods by default)")
+ .hasOptionalArg()
+ .withArgName("FILE")
+ .create("m");
+
+ Option listFieldsOption = OptionBuilder.withLongOpt("list-fields")
+ .withDescription("Lists all the field references to FILE" +
+ " (<output_dex_filename>.fields by default)")
+ .hasOptionalArg()
+ .withArgName("FILE")
+ .create("f");
+
+ Option listClassesOption = OptionBuilder.withLongOpt("list-types")
+ .withDescription("Lists all the type references to FILE" +
+ " (<output_dex_filename>.types by default)")
+ .hasOptionalArg()
+ .withArgName("FILE")
+ .create("t");
+
Option experimentalOption = OptionBuilder.withLongOpt("experimental")
.withDescription("enable experimental opcodes to be assembled, even if they " +
" aren't necessarily supported by the Android runtime yet")
@@ -405,6 +487,9 @@ public class main {
basicOptions.addOption(apiLevelOption);
basicOptions.addOption(experimentalOption);
basicOptions.addOption(jobsOption);
+ basicOptions.addOption(listMethodsOption);
+ basicOptions.addOption(listFieldsOption);
+ basicOptions.addOption(listClassesOption);
debugOptions.addOption(verboseErrorsOption);
debugOptions.addOption(printTokensOption);