aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gruver <bgruv@google.com>2015-03-18 20:01:49 -0700
committerBen Gruver <bgruv@google.com>2015-03-18 20:01:49 -0700
commitbd6385f06205cdf98269eb4a2412000b35ac9d62 (patch)
treeacab5f53c84f5cc00b9b25275d730553cc540ff0
parent1aad736c2052ddcd3b354122079759118b513ddf (diff)
downloadsmali-bd6385f06205cdf98269eb4a2412000b35ac9d62.tar.gz
Duplicate a switch payload that is refered to multiple times
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java29
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java75
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/BaksmaliTestUtils.java64
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java104
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/MultiSwitchTest.java42
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/RoundtripTest.java23
-rw-r--r--baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.dexbin0 -> 616 bytes
-rw-r--r--baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.smali72
-rw-r--r--baksmali/src/test/resources/MultiSwitchTest/MultiSwitchOutput.smali119
9 files changed, 473 insertions, 55 deletions
diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java
index 6e0b70ee..b3f9ae17 100644
--- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java
+++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java
@@ -130,26 +130,37 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
}
if (instruction instanceof Instruction31t) {
- Opcode payloadOpcode;
+ boolean validPayload = true;
+
switch (instruction.getOpcode()) {
case PACKED_SWITCH:
- payloadOpcode = Opcode.PACKED_SWITCH_PAYLOAD;
+ int baseAddress = methodDef.getPackedSwitchBaseAddress(
+ this.codeAddress + ((Instruction31t)instruction).getCodeOffset());
+ if (baseAddress == -1) {
+ validPayload = false;
+ }
break;
case SPARSE_SWITCH:
- payloadOpcode = Opcode.SPARSE_SWITCH_PAYLOAD;
+ baseAddress = methodDef.getSparseSwitchBaseAddress(
+ this.codeAddress + ((Instruction31t)instruction).getCodeOffset());
+ if (baseAddress == -1) {
+ validPayload = false;
+ }
break;
case FILL_ARRAY_DATA:
- payloadOpcode = Opcode.ARRAY_PAYLOAD;
+ 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());
}
- try {
- methodDef.findSwitchPayload(this.codeAddress + ((Instruction31t)instruction).getCodeOffset(),
- payloadOpcode);
- } catch (InvalidSwitchPayload ex) {
- writer.write("#invalid payload reference");
+ if (!validPayload) {
+ writer.write("#invalid payload reference\n");
commentOutInstruction = true;
}
}
diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java
index eb5caa67..4081a75c 100644
--- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java
+++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java
@@ -29,6 +29,7 @@
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;
@@ -45,11 +46,14 @@ 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;
@@ -65,6 +69,8 @@ public class MethodDefinition {
@Nonnull public final Method method;
@Nonnull public final MethodImplementation methodImpl;
@Nonnull public final ImmutableList<Instruction> instructions;
+ @Nonnull public final List<Instruction> effectiveInstructions;
+
@Nonnull public final ImmutableList<MethodParameter> methodParameters;
public RegisterFormatter registerFormatter;
@@ -86,10 +92,15 @@ public class MethodDefinition {
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<instructions.size(); i++) {
Instruction instruction = instructions.get(i);
@@ -99,11 +110,20 @@ public class MethodDefinition {
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
try {
- targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
+ targetOffset = findPayloadOffset(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
} catch (InvalidSwitchPayload ex) {
valid = false;
}
if (valid) {
+ if (packedSwitchMap.get(targetOffset, -1) != -1) {
+ Instruction payloadInstruction =
+ findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
+ targetOffset = endOffset;
+ effectiveInstructions.set(i, new ImmutableInstruction31t(opcode,
+ ((Instruction31t)instruction).getRegisterA(), targetOffset-codeOffset));
+ effectiveInstructions.add(payloadInstruction);
+ endOffset += payloadInstruction.getCodeUnits();
+ }
packedSwitchMap.append(targetOffset, codeOffset);
}
} else if (opcode == Opcode.SPARSE_SWITCH) {
@@ -111,18 +131,27 @@ public class MethodDefinition {
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
try {
- targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
+ targetOffset = findPayloadOffset(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
} catch (InvalidSwitchPayload ex) {
valid = false;
// The offset to the payload instruction was invalid. Nothing to do, except that we won't
// add this instruction to the map.
}
if (valid) {
+ if (sparseSwitchMap.get(targetOffset, -1) != -1) {
+ Instruction payloadInstruction =
+ findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
+ targetOffset = endOffset;
+ effectiveInstructions.set(i, new ImmutableInstruction31t(opcode,
+ ((Instruction31t)instruction).getRegisterA(), targetOffset-codeOffset));
+ effectiveInstructions.add(payloadInstruction);
+ endOffset += payloadInstruction.getCodeUnits();
+ }
sparseSwitchMap.append(targetOffset, codeOffset);
}
}
}
- }catch (Exception ex) {
+ } catch (Exception ex) {
String methodString;
try {
methodString = ReferenceUtil.getMethodDescriptor(method);
@@ -216,7 +245,36 @@ public class MethodDefinition {
writer.write(".end method\n");
}
- public int findSwitchPayload(int targetOffset, Opcode type) {
+ 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);
@@ -343,15 +401,16 @@ public class MethodDefinition {
private void addInstructionMethodItems(List<MethodItem> methodItems) {
int currentCodeAddress = 0;
- for (int i=0; i<instructions.size(); i++) {
- Instruction instruction = instructions.get(i);
+
+ for (int i=0; i<effectiveInstructions.size(); i++) {
+ Instruction instruction = effectiveInstructions.get(i);
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
currentCodeAddress, instruction);
methodItems.add(methodItem);
- if (i != instructions.size() - 1) {
+ if (i != effectiveInstructions.size() - 1) {
methodItems.add(new BlankMethodItem(currentCodeAddress));
}
@@ -386,7 +445,7 @@ public class MethodDefinition {
if (methodReference != null &&
SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
- SyntheticAccessorResolver.AccessedMember accessedMember =
+ AccessedMember accessedMember =
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
if (accessedMember != null) {
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
diff --git a/baksmali/src/test/java/org/jf/baksmali/BaksmaliTestUtils.java b/baksmali/src/test/java/org/jf/baksmali/BaksmaliTestUtils.java
index c009e83d..1c570b6c 100644
--- a/baksmali/src/test/java/org/jf/baksmali/BaksmaliTestUtils.java
+++ b/baksmali/src/test/java/org/jf/baksmali/BaksmaliTestUtils.java
@@ -31,6 +31,7 @@
package org.jf.baksmali;
+import com.google.common.io.ByteStreams;
import junit.framework.Assert;
import org.antlr.runtime.RecognitionException;
@@ -40,7 +41,9 @@ import org.jf.smali.SmaliTestUtils;
import org.jf.util.IndentingWriter;
import org.jf.util.TextUtils;
+import javax.annotation.Nonnull;
import java.io.IOException;
+import java.io.InputStream;
import java.io.StringWriter;
public class BaksmaliTestUtils {
@@ -50,24 +53,9 @@ public class BaksmaliTestUtils {
ClassDef classDef = SmaliTestUtils.compileSmali(source, options.apiLevel,
options.experimental);
- StringWriter stringWriter = new StringWriter();
- IndentingWriter writer = new IndentingWriter(stringWriter);
- ClassDefinition classDefinition = new ClassDefinition(options, classDef);
- classDefinition.writeTo(writer);
- writer.close();
-
// Remove unnecessary whitespace and optionally strip all comments from smali file
- String normalizedExpected = expected;
- if (stripComments) {
- normalizedExpected = TextUtils.stripComments(normalizedExpected);
- }
- normalizedExpected = TextUtils.normalizeWhitespace(normalizedExpected);
-
- String normalizedActual = stringWriter.toString();
- if (stripComments) {
- normalizedActual = TextUtils.stripComments(normalizedActual);
- }
- normalizedActual = TextUtils.normalizeWhitespace(normalizedActual);
+ String normalizedActual = getNormalizedSmali(classDef, options, stripComments);
+ String normalizedExpected = normalizeSmali(expected, stripComments);
// Assert that normalized strings are now equal
Assert.assertEquals(normalizedExpected, normalizedActual);
@@ -84,6 +72,48 @@ public class BaksmaliTestUtils {
assertSmaliCompiledEquals(source, expected, options);
}
+ @Nonnull
+ public static String normalizeSmali(@Nonnull String smaliText, boolean stripComments) {
+ if (stripComments) {
+ smaliText = TextUtils.stripComments(smaliText);
+ }
+ return TextUtils.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);
+ }
+
// Static helpers class; do not instantiate.
private BaksmaliTestUtils() { throw new AssertionError(); }
}
diff --git a/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java b/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java
new file mode 100644
index 00000000..35304f7e
--- /dev/null
+++ b/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.Opcodes;
+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 {
+ protected final String testDir;
+
+ protected DisassemblyTest(@Nonnull String testDir) {
+ this.testDir = testDir;
+ }
+
+ protected DisassemblyTest() {
+ 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 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);
+ byte[] inputBytes = BaksmaliTestUtils.readResourceBytesFully(getInputFilename(testName));
+
+ DexBackedDexFile inputDex = new DexBackedDexFile(new Opcodes(options.apiLevel, false), inputBytes);
+ Assert.assertEquals(1, inputDex.getClassCount());
+ ClassDef inputClass = Iterables.getFirst(inputDex.getClasses(), null);
+ Assert.assertNotNull(inputClass);
+ String input = BaksmaliTestUtils.getNormalizedSmali(inputClass, options, true);
+
+ String output;
+ if (getOutputFilename(testName).equals(inputFilename)) {
+ output = input;
+ } else {
+ 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();
+ }
+ }
+}
diff --git a/baksmali/src/test/java/org/jf/baksmali/MultiSwitchTest.java b/baksmali/src/test/java/org/jf/baksmali/MultiSwitchTest.java
new file mode 100644
index 00000000..cb29402f
--- /dev/null
+++ b/baksmali/src/test/java/org/jf/baksmali/MultiSwitchTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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");
+ }
+}
diff --git a/baksmali/src/test/java/org/jf/baksmali/RoundtripTest.java b/baksmali/src/test/java/org/jf/baksmali/RoundtripTest.java
index ba15603c..c9ff2d4d 100644
--- a/baksmali/src/test/java/org/jf/baksmali/RoundtripTest.java
+++ b/baksmali/src/test/java/org/jf/baksmali/RoundtripTest.java
@@ -31,14 +31,12 @@
package org.jf.baksmali;
-import com.google.common.io.ByteStreams;
import org.antlr.runtime.RecognitionException;
import org.junit.Assert;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
/**
* A base test class for performing a roundtrip assembly/disassembly
@@ -78,12 +76,12 @@ public abstract class RoundtripTest {
try {
// Load file from resources as a stream
String inputFilename = getInputFilename(testName);
- String input = readResourceFully(getInputFilename(testName));
+ String input = BaksmaliTestUtils.readResourceFully(getInputFilename(testName));
String output;
if (getOutputFilename(testName).equals(inputFilename)) {
output = input;
} else {
- output = readResourceFully(getOutputFilename(testName));
+ output = BaksmaliTestUtils.readResourceFully(getOutputFilename(testName));
}
// Run smali, baksmali, and then compare strings are equal (minus comments/whitespace)
@@ -94,21 +92,4 @@ public abstract class RoundtripTest {
Assert.fail();
}
}
-
- @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 {
- InputStream smaliStream = RoundtripTest.class.getClassLoader().
- getResourceAsStream(fileName);
- if (smaliStream == null) {
- Assert.fail("Could not load " + fileName);
- }
-
- return new String(ByteStreams.toByteArray(smaliStream), encoding);
- }
}
diff --git a/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.dex b/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.dex
new file mode 100644
index 00000000..6ef3d349
--- /dev/null
+++ b/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.dex
Binary files differ
diff --git a/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.smali b/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.smali
new file mode 100644
index 00000000..b4fd27d8
--- /dev/null
+++ b/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.smali
@@ -0,0 +1,72 @@
+.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 method \ No newline at end of file
diff --git a/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchOutput.smali b/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchOutput.smali
new file mode 100644
index 00000000..f3aeeed5
--- /dev/null
+++ b/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchOutput.smali
@@ -0,0 +1,119 @@
+.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