diff options
author | Ben Gruver <bgruv@google.com> | 2015-03-18 20:01:49 -0700 |
---|---|---|
committer | Ben Gruver <bgruv@google.com> | 2015-03-18 20:01:49 -0700 |
commit | bd6385f06205cdf98269eb4a2412000b35ac9d62 (patch) | |
tree | acab5f53c84f5cc00b9b25275d730553cc540ff0 | |
parent | 1aad736c2052ddcd3b354122079759118b513ddf (diff) | |
download | smali-bd6385f06205cdf98269eb4a2412000b35ac9d62.tar.gz |
Duplicate a switch payload that is refered to multiple times
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 Binary files differnew file mode 100644 index 00000000..6ef3d349 --- /dev/null +++ b/baksmali/src/test/resources/MultiSwitchTest/MultiSwitchInput.dex 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 |