diff options
author | Igor Murashkin <iam@google.com> | 2015-02-18 17:38:30 -0800 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2015-03-16 11:40:58 -0700 |
commit | 144951a9e9e6c87866245f2bdeebf0ebedaa0e38 (patch) | |
tree | bdbc5c4f2ad3ea320798ade74888490123c30ad5 /dexlib2/src | |
parent | f70084bdfeba10dfb68c2c63eb1bedd4e42b4b0f (diff) | |
download | smali-144951a9e9e6c87866245f2bdeebf0ebedaa0e38.tar.gz |
Add lambda experimental dalvik opcodes
* Add new -X/--experimental flag to [dis]assemble opcodes not in art yet
* Add new opcodes liberate-variable, box-lambda, unbox-lambda,
capture-variable, create-lambda, invoke-lambda
* Add support for encoding 25x instructions
* Adds LambdaTest to check new opcodes assemble/disassemble properly
TODO: invoke-lambda-range
Change-Id: I5c8bcbfa8b6cb9a13ef2017fce2d1b7fda6e11c3
Diffstat (limited to 'dexlib2/src')
23 files changed, 528 insertions, 63 deletions
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java index d08da036..85f8a426 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java @@ -45,22 +45,26 @@ import java.util.zip.ZipFile; public final class DexFileFactory { @Nonnull - public static DexBackedDexFile loadDexFile(String path, int api) throws IOException { - return loadDexFile(new File(path), "classes.dex", new Opcodes(api)); + 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, "classes.dex", new Opcodes(api)); + public static DexBackedDexFile loadDexFile(File dexFile, int api, boolean experimental) + throws IOException { + return loadDexFile(dexFile, "classes.dex", new Opcodes(api, experimental)); } @Nonnull - public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry, int api) throws IOException { - return loadDexFile(dexFile, dexEntry, new Opcodes(api)); + public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry, int api, + boolean experimental) throws IOException { + return loadDexFile(dexFile, dexEntry, new Opcodes(api, experimental)); } @Nonnull - public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry, @Nonnull Opcodes opcodes) throws IOException { + public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry, + @Nonnull Opcodes opcodes) throws IOException { ZipFile zipFile = null; boolean isZipFile = false; try { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Format.java b/dexlib2/src/main/java/org/jf/dexlib2/Format.java index d91b7432..ee34aa50 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/Format.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/Format.java @@ -51,6 +51,7 @@ public enum Format { Format22t(4), Format22x(4), Format23x(4), + Format25x(4), Format30t(6), Format31c(6), Format31i(6), diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java b/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java index d0adee8c..3b082ee8 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java @@ -269,13 +269,13 @@ public enum Opcode INVOKE_OBJECT_INIT_RANGE((short)0xf0, "invoke-object-init/range", minApi(14), ReferenceType.METHOD, Format.Format3rc, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE), RETURN_VOID_BARRIER((short)0xf1, "return-void-barrier", minApi(11), ReferenceType.NONE, Format.Format10x, Opcode.ODEX_ONLY), IGET_QUICK((short)0xf2, "iget-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), - IGET_WIDE_QUICK((short)0xf3, "iget-wide-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), - IGET_OBJECT_QUICK((short)0xf4, "iget-object-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), - IPUT_QUICK((short)0xf5, "iput-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), - IPUT_WIDE_QUICK((short)0xf6, "iput-wide-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), - IPUT_OBJECT_QUICK((short)0xf7, "iput-object-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), - INVOKE_VIRTUAL_QUICK((short)0xf8, "invoke-virtual-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), - INVOKE_VIRTUAL_QUICK_RANGE((short)0xf9, "invoke-virtual-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), + IGET_WIDE_QUICK((short)0xf3, "iget-wide-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), + IGET_OBJECT_QUICK((short)0xf4, "iget-object-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + IPUT_QUICK((short)0xf5, "iput-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + IPUT_WIDE_QUICK((short)0xf6, "iput-wide-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + IPUT_OBJECT_QUICK((short)0xf7, "iput-object-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + INVOKE_VIRTUAL_QUICK((short)0xf8, "invoke-virtual-quick", maxApi(22), ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), + INVOKE_VIRTUAL_QUICK_RANGE((short)0xf9, "invoke-virtual-quick/range", maxApi(22), ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER_QUICK((short)0xfa, "invoke-super-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER_QUICK_RANGE((short)0xfb, "invoke-super-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), @@ -285,7 +285,17 @@ public enum Opcode PACKED_SWITCH_PAYLOAD((short)0x100, "packed-switch-payload", ReferenceType.NONE, Format.PackedSwitchPayload, 0), SPARSE_SWITCH_PAYLOAD((short)0x200, "sparse-switch-payload", ReferenceType.NONE, Format.SparseSwitchPayload, 0), - ARRAY_PAYLOAD((short)0x300, "array-payload", ReferenceType.NONE, Format.ArrayPayload, 0); + ARRAY_PAYLOAD((short)0x300, "array-payload", ReferenceType.NONE, Format.ArrayPayload, 0), + + // Reuse the deprecated f3-ff opcodes in Art: + INVOKE_LAMBDA((short)0xf3, "invoke-lambda", minApi(23), ReferenceType.NONE, Format.Format25x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.EXPERIMENTAL), + // TODO: What about JUMBO support if the string ID is too large? + CAPTURE_VARIABLE((short)0xf5, "capture-variable", minApi(23), ReferenceType.STRING, Format.Format21c, Opcode.EXPERIMENTAL), + CREATE_LAMBDA((short)0xf6, "create-lambda", minApi(23), ReferenceType.METHOD, Format.Format21c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL), + // TODO: do we need a capture/liberate wide? + LIBERATE_VARIABLE((short)0xf7, "liberate-variable", minApi(23), ReferenceType.STRING, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL), + BOX_LAMBDA((short)0xf8, "box-lambda", minApi(23), ReferenceType.NONE, Format.Format22x, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL), + UNBOX_LAMBDA((short)0xf9, "unbox-lambda", minApi(23), ReferenceType.TYPE, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL); //if the instruction can throw an exception public static final int CAN_THROW = 0x1; @@ -309,6 +319,8 @@ public enum Opcode public static final int JUMBO_OPCODE = 0x200; //if the instruction can initialize an uninitialized object reference public static final int CAN_INITIALIZE_REFERENCE = 0x400; + //if the instruction is experimental (not potentially supported by Android runtime yet) + public static final int EXPERIMENTAL = 0x800; private static final int ALL_APIS = 0xFFFF0000; @@ -417,4 +429,8 @@ public enum Opcode public final boolean canInitializeReference() { return (flags & CAN_INITIALIZE_REFERENCE) != 0; } + + public final boolean isExperimental() { + return (flags & EXPERIMENTAL) != 0; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java b/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java index d6e5532e..dd876813 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java @@ -40,13 +40,14 @@ public class Opcodes { private final Opcode[] opcodesByValue; private final HashMap<String, Opcode> opcodesByName; - public Opcodes(int api) { + public Opcodes(int api, boolean experimental) { opcodesByValue = new Opcode[256]; opcodesByName = Maps.newHashMap(); for (Opcode opcode: Opcode.values()) { if (!opcode.format.isPayloadFormat) { - if (api <= opcode.getMaxApi() && api >= opcode.getMinApi()) { + if (api <= opcode.getMaxApi() && api >= opcode.getMinApi() && + (experimental || !opcode.isExperimental())) { opcodesByValue[opcode.value] = opcode; opcodesByName.put(opcode.name.toLowerCase(), opcode); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java index 7efeb408..bd9cfb1b 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java @@ -164,18 +164,18 @@ public class ClassPath { @Nonnull public static ClassPath fromClassPath(Iterable<String> classPathDirs, Iterable<String> classPath, DexFile dexFile, - int api) { - return fromClassPath(classPathDirs, classPath, dexFile, api, api == 17); + int api, boolean experimental) { + return fromClassPath(classPathDirs, classPath, dexFile, api, api == 17, experimental); } @Nonnull public static ClassPath fromClassPath(Iterable<String> classPathDirs, Iterable<String> classPath, DexFile dexFile, - int api, boolean checkPackagePrivateAccess) { + int api, boolean checkPackagePrivateAccess, boolean experimental) { ArrayList<DexFile> dexFiles = Lists.newArrayList(); for (String classPathEntry: classPath) { try { - dexFiles.add(loadClassPathEntry(classPathDirs, classPathEntry, api)); + dexFiles.add(loadClassPathEntry(classPathDirs, classPathEntry, api, experimental)); } catch (ExceptionWithContext e){} } dexFiles.add(dexFile); @@ -186,7 +186,8 @@ public class ClassPath { @Nonnull private static DexFile loadClassPathEntry(@Nonnull Iterable<String> classPathDirs, - @Nonnull String bootClassPathEntry, int api) { + @Nonnull String bootClassPathEntry, int api, + boolean experimental) { File rawEntry = new File(bootClassPathEntry); // strip off the path - we only care about the filename String entryName = rawEntry.getName(); @@ -221,7 +222,7 @@ public class ClassPath { "warning: cannot open %s for reading. Will continue looking.", file.getPath())); } else { try { - return DexFileFactory.loadDexFile(file, api); + return DexFileFactory.loadDexFile(file, api, experimental); } catch (DexFileFactory.NoClassesDexException ex) { // ignore and continue } catch (Exception ex) { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/DumpFields.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/DumpFields.java index d57ce961..2bb3e492 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/DumpFields.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/DumpFields.java @@ -73,6 +73,7 @@ public class DumpFields { ArrayList<String> bootClassPathDirs = Lists.newArrayList(); String outFile = "fields.txt"; int apiLevel = 15; + boolean experimental = false; for (int i=0; i<parsedOptions.length; i++) { Option option = parsedOptions[i]; @@ -88,6 +89,9 @@ public class DumpFields { case 'a': apiLevel = Integer.parseInt(commandLine.getOptionValue("a")); break; + case 'X': + experimental = true; + break; default: assert false; } @@ -107,9 +111,9 @@ public class DumpFields { } try { - DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, apiLevel); + DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, apiLevel, experimental); Iterable<String> bootClassPaths = Splitter.on(":").split("core.jar:ext.jar:framework.jar:android.policy.jar:services.jar"); - ClassPath classPath = ClassPath.fromClassPath(bootClassPathDirs, bootClassPaths, dexFile, apiLevel); + ClassPath classPath = ClassPath.fromClassPath(bootClassPathDirs, bootClassPaths, dexFile, apiLevel, experimental); FileOutputStream outStream = new FileOutputStream(outFile); for (ClassDef classDef: dexFile.getClasses()) { @@ -163,8 +167,14 @@ public class DumpFields { .withArgName("API_LEVEL") .create("a"); + Option experimentalOption = OptionBuilder.withLongOpt("experimental") + .withDescription("Enable dumping experimental opcodes, that aren't necessarily " + + "supported by the android runtime yet.") + .create("X"); + options.addOption(classPathDirOption); options.addOption(outputFileOption); options.addOption(apiLevelOption); + options.addOption(experimentalOption); } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/DumpVtables.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/DumpVtables.java index 0d7656c3..193c0d39 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/DumpVtables.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/DumpVtables.java @@ -71,6 +71,7 @@ public class DumpVtables { ArrayList<String> bootClassPathDirs = Lists.newArrayList(); String outFile = "vtables.txt"; int apiLevel = 15; + boolean experimental = false; for (int i=0; i<parsedOptions.length; i++) { Option option = parsedOptions[i]; @@ -86,6 +87,9 @@ public class DumpVtables { case 'a': apiLevel = Integer.parseInt(commandLine.getOptionValue("a")); break; + case 'X': + experimental = true; + break; default: assert false; } @@ -105,9 +109,9 @@ public class DumpVtables { } try { - DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, apiLevel); + DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, apiLevel, experimental); Iterable<String> bootClassPaths = Splitter.on(":").split("core.jar:ext.jar:framework.jar:android.policy.jar:services.jar"); - ClassPath classPath = ClassPath.fromClassPath(bootClassPathDirs, bootClassPaths, dexFile, apiLevel); + ClassPath classPath = ClassPath.fromClassPath(bootClassPathDirs, bootClassPaths, dexFile, apiLevel, experimental); FileOutputStream outStream = new FileOutputStream(outFile); for (ClassDef classDef: dexFile.getClasses()) { @@ -167,8 +171,14 @@ public class DumpVtables { .withArgName("API_LEVEL") .create("a"); + Option experimentalOption = OptionBuilder.withLongOpt("experimental") + .withDescription("Enable dumping experimental opcodes, that aren't necessarily " + + "supported by the android runtime yet.") + .create("X"); + options.addOption(classPathDirOption); options.addOption(outputFileOption); options.addOption(apiLevelOption); + options.addOption(experimentalOption); } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java index f734e018..84981221 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java @@ -511,82 +511,90 @@ public class MutableMethodImplementation implements MethodImplementation { @Nonnull Instruction instruction) { switch (instruction.getOpcode().format) { case Format10t: - setInstruction(location, newBuilderInstruction10t(location.codeAddress, codeAddressToIndex, - (Instruction10t)instruction)); + setInstruction(location, newBuilderInstruction10t(location.codeAddress, + codeAddressToIndex, + (Instruction10t) instruction)); return; case Format10x: - setInstruction(location, newBuilderInstruction10x((Instruction10x)instruction)); + setInstruction(location, newBuilderInstruction10x((Instruction10x) instruction)); return; case Format11n: - setInstruction(location, newBuilderInstruction11n((Instruction11n)instruction)); + setInstruction(location, newBuilderInstruction11n((Instruction11n) instruction)); return; case Format11x: - setInstruction(location, newBuilderInstruction11x((Instruction11x)instruction)); + setInstruction(location, newBuilderInstruction11x((Instruction11x) instruction)); return; case Format12x: - setInstruction(location, newBuilderInstruction12x((Instruction12x)instruction)); + setInstruction(location, newBuilderInstruction12x((Instruction12x) instruction)); return; case Format20bc: - setInstruction(location, newBuilderInstruction20bc((Instruction20bc)instruction)); + setInstruction(location, newBuilderInstruction20bc((Instruction20bc) instruction)); return; case Format20t: - setInstruction(location, newBuilderInstruction20t(location.codeAddress, codeAddressToIndex, - (Instruction20t)instruction)); + setInstruction(location, newBuilderInstruction20t(location.codeAddress, + codeAddressToIndex, + (Instruction20t) instruction)); return; case Format21c: - setInstruction(location, newBuilderInstruction21c((Instruction21c)instruction)); + setInstruction(location, newBuilderInstruction21c((Instruction21c) instruction)); return; case Format21ih: - setInstruction(location, newBuilderInstruction21ih((Instruction21ih)instruction)); + setInstruction(location, newBuilderInstruction21ih((Instruction21ih) instruction)); return; case Format21lh: - setInstruction(location, newBuilderInstruction21lh((Instruction21lh)instruction)); + setInstruction(location, newBuilderInstruction21lh((Instruction21lh) instruction)); return; case Format21s: - setInstruction(location, newBuilderInstruction21s((Instruction21s)instruction)); + setInstruction(location, newBuilderInstruction21s((Instruction21s) instruction)); return; case Format21t: - setInstruction(location, newBuilderInstruction21t(location.codeAddress, codeAddressToIndex, - (Instruction21t)instruction)); + setInstruction(location, newBuilderInstruction21t(location.codeAddress, + codeAddressToIndex, + (Instruction21t) instruction)); return; case Format22b: - setInstruction(location, newBuilderInstruction22b((Instruction22b)instruction)); + setInstruction(location, newBuilderInstruction22b((Instruction22b) instruction)); return; case Format22c: - setInstruction(location, newBuilderInstruction22c((Instruction22c)instruction)); + setInstruction(location, newBuilderInstruction22c((Instruction22c) instruction)); return; case Format22s: - setInstruction(location, newBuilderInstruction22s((Instruction22s)instruction)); + setInstruction(location, newBuilderInstruction22s((Instruction22s) instruction)); return; case Format22t: - setInstruction(location, newBuilderInstruction22t(location.codeAddress, codeAddressToIndex, - (Instruction22t)instruction)); + setInstruction(location, newBuilderInstruction22t(location.codeAddress, + codeAddressToIndex, + (Instruction22t) instruction)); return; case Format22x: - setInstruction(location, newBuilderInstruction22x((Instruction22x)instruction)); + setInstruction(location, newBuilderInstruction22x((Instruction22x) instruction)); return; case Format23x: - setInstruction(location, newBuilderInstruction23x((Instruction23x)instruction)); + setInstruction(location, newBuilderInstruction23x((Instruction23x) instruction)); + return; + case Format25x: + setInstruction(location, newBuilderInstruction25x((Instruction25x) instruction)); return; case Format30t: - setInstruction(location, newBuilderInstruction30t(location.codeAddress, codeAddressToIndex, - (Instruction30t)instruction)); + setInstruction(location, newBuilderInstruction30t(location.codeAddress, + codeAddressToIndex, + (Instruction30t) instruction)); return; case Format31c: - setInstruction(location, newBuilderInstruction31c((Instruction31c)instruction)); + setInstruction(location, newBuilderInstruction31c((Instruction31c) instruction)); return; case Format31i: - setInstruction(location, newBuilderInstruction31i((Instruction31i)instruction)); + setInstruction(location, newBuilderInstruction31i((Instruction31i) instruction)); return; case Format31t: setInstruction(location, newBuilderInstruction31t(location, codeAddressToIndex, - (Instruction31t)instruction)); + (Instruction31t) instruction)); return; case Format32x: - setInstruction(location, newBuilderInstruction32x((Instruction32x)instruction)); + setInstruction(location, newBuilderInstruction32x((Instruction32x) instruction)); return; case Format35c: - setInstruction(location, newBuilderInstruction35c((Instruction35c)instruction)); + setInstruction(location, newBuilderInstruction35c((Instruction35c) instruction)); return; case Format3rc: setInstruction(location, newBuilderInstruction3rc((Instruction3rc)instruction)); @@ -821,6 +829,18 @@ public class MutableMethodImplementation implements MethodImplementation { } @Nonnull + private BuilderInstruction25x newBuilderInstruction25x(@Nonnull Instruction25x instruction) { + return new BuilderInstruction25x( + instruction.getOpcode(), + instruction.getParameterRegisterCount(), + instruction.getRegisterFixedC(), + instruction.getRegisterParameterD(), + instruction.getRegisterParameterE(), + instruction.getRegisterParameterF(), + instruction.getRegisterParameterG()); + } + + @Nonnull private BuilderInstruction3rc newBuilderInstruction3rc(@Nonnull Instruction3rc instruction) { return new BuilderInstruction3rc( instruction.getOpcode(), diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction25x.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction25x.java new file mode 100644 index 00000000..3783d2b6 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction25x.java @@ -0,0 +1,82 @@ +/* + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.builder.instruction; + +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.builder.BuilderInstruction; +import org.jf.dexlib2.iface.instruction.formats.Instruction25x; +import org.jf.dexlib2.util.Preconditions; + +import javax.annotation.Nonnull; + +public class BuilderInstruction25x extends BuilderInstruction implements Instruction25x { + public static final Format FORMAT = Format.Format25x; + + protected final int parameterRegisterCount; + protected final int registerClosure; + protected final int registerD; + protected final int registerE; + protected final int registerF; + protected final int registerG; + + public BuilderInstruction25x(@Nonnull Opcode opcode, + int parameterRegisterCount, + int registerClosure, + int registerD, + int registerE, + int registerF, + int registerG) { + super(opcode); + this.parameterRegisterCount = + Preconditions.check25xParameterRegisterCount(parameterRegisterCount); + this.registerClosure = Preconditions.checkNibbleRegister(registerClosure); //at least 1 reg + this.registerD = (parameterRegisterCount>0) ? + Preconditions.checkNibbleRegister(registerD) : 0; + this.registerE = (parameterRegisterCount>1) ? + Preconditions.checkNibbleRegister(registerE) : 0; + this.registerF = (parameterRegisterCount>2) ? + Preconditions.checkNibbleRegister(registerF) : 0; + this.registerG = (parameterRegisterCount>3) ? + Preconditions.checkNibbleRegister(registerG) : 0; + } + + @Override public int getRegisterCount() { return parameterRegisterCount + 1; } + @Override public int getParameterRegisterCount() { return parameterRegisterCount; } + @Override public int getRegisterFixedC() { return registerClosure; } + @Override public int getRegisterParameterD() { return registerD; } + @Override public int getRegisterParameterE() { return registerE; } + @Override public int getRegisterParameterF() { return registerF; } + @Override public int getRegisterParameterG() { return registerG; } + + @Override public Format getFormat() { return FORMAT; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java index a4c29990..ac82f4b4 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java @@ -115,6 +115,8 @@ public abstract class DexBackedInstruction implements Instruction { return new DexBackedInstruction22x(dexFile, opcode, instructionStartOffset); case Format23x: return new DexBackedInstruction23x(dexFile, opcode, instructionStartOffset); + case Format25x: + return new DexBackedInstruction25x(dexFile, opcode, instructionStartOffset); case Format30t: return new DexBackedInstruction30t(dexFile, opcode, instructionStartOffset); case Format31c: diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction25x.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction25x.java new file mode 100644 index 00000000..80fb8767 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction25x.java @@ -0,0 +1,83 @@ +/* + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.dexbacked.instruction; + +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.dexbacked.DexBackedDexFile; +import org.jf.dexlib2.iface.instruction.formats.Instruction25x; +import org.jf.util.NibbleUtils; + +import javax.annotation.Nonnull; + +public class DexBackedInstruction25x extends DexBackedInstruction implements Instruction25x { + public DexBackedInstruction25x(@Nonnull DexBackedDexFile dexFile, + @Nonnull Opcode opcode, + int instructionStart) { + super(dexFile, opcode, instructionStart); + } + + @Override + public int getRegisterCount() { + return getParameterRegisterCount() + 1; + } + + @Override + public int getParameterRegisterCount() { + return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 1)); + } + + @Override + public int getRegisterFixedC() { + return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 2)); + } + + @Override + public int getRegisterParameterD() { + return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 2)); + } + + @Override + public int getRegisterParameterE() { + return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 3)); + } + + @Override + public int getRegisterParameterF() { + return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 3)); + } + + @Override + public int getRegisterParameterG() { + return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 1)); + } + +} 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 c3946976..9c79e270 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 @@ -129,6 +129,9 @@ public class CodeItem { case Format10x: annotateInstruction10x(out, instruction); break; + case Format25x: + annotateInstruction25x(out, (Instruction25x) instruction); + break; case Format35c: annotateInstruction35c(out, (Instruction35c)instruction); break; @@ -282,6 +285,30 @@ public class CodeItem { instruction.getOpcode().name, Joiner.on(", ").join(args), reference)); } + private void annotateInstruction25x(@Nonnull AnnotatedBytes out, + @Nonnull Instruction25x instruction) { + List<String> args = Lists.newArrayList(); + + int registerCount = instruction.getRegisterCount(); //at least 1. + if (registerCount == 2) { + args.add(formatRegister(instruction.getRegisterParameterD())); + } else if (registerCount == 3) { + args.add(formatRegister(instruction.getRegisterParameterD())); + args.add(formatRegister(instruction.getRegisterParameterE())); + } else if (registerCount == 4) { + args.add(formatRegister(instruction.getRegisterParameterD())); + args.add(formatRegister(instruction.getRegisterParameterE())); + args.add(formatRegister(instruction.getRegisterParameterF())); + } else if (registerCount == 5) { + args.add(formatRegister(instruction.getRegisterParameterD())); + args.add(formatRegister(instruction.getRegisterParameterE())); + args.add(formatRegister(instruction.getRegisterParameterF())); + args.add(formatRegister(instruction.getRegisterParameterG())); + } + out.annotate(6, String.format("%s %s, {%s}", + instruction.getOpcode().name, instruction.getRegisterFixedC(), Joiner.on(", ").join(args))); + } + private void annotateInstruction3rc(@Nonnull AnnotatedBytes out, @Nonnull Instruction3rc instruction) { int startRegister = instruction.getStartRegister(); int endRegister = startRegister + instruction.getRegisterCount() - 1; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/OneFixedFourParameterRegisterInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/OneFixedFourParameterRegisterInstruction.java new file mode 100644 index 00000000..c03bff77 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/OneFixedFourParameterRegisterInstruction.java @@ -0,0 +1,47 @@ +/* + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.iface.instruction; + +public interface OneFixedFourParameterRegisterInstruction extends VariableRegisterInstruction { + int getRegisterFixedC(); + int getRegisterParameterD(); + int getRegisterParameterE(); + int getRegisterParameterF(); + int getRegisterParameterG(); + + /** Returns the count of just the parameter register counts; in range of [0, 4] */ + int getParameterRegisterCount(); + + /** Includes the total sum of both fixed and parameter register counts; at least 1 */ + @Override + int getRegisterCount(); +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction25x.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction25x.java new file mode 100644 index 00000000..51df2dee --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction25x.java @@ -0,0 +1,37 @@ +/* + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.iface.instruction.formats; + +import org.jf.dexlib2.iface.instruction.OneFixedFourParameterRegisterInstruction; + +public interface Instruction25x extends OneFixedFourParameterRegisterInstruction { +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java index 432f1930..ed50ef5b 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java @@ -97,6 +97,8 @@ public abstract class ImmutableInstruction implements Instruction { return ImmutableInstruction22x.of((Instruction22x)instruction); case Format23x: return ImmutableInstruction23x.of((Instruction23x)instruction); + case Format25x: + return ImmutableInstruction25x.of((Instruction25x) instruction); case Format30t: return ImmutableInstruction30t.of((Instruction30t)instruction); case Format31c: diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction25x.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction25x.java new file mode 100644 index 00000000..2f31eaea --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction25x.java @@ -0,0 +1,97 @@ +/* + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.immutable.instruction; + +import org.jf.dexlib2.Format; +import org.jf.dexlib2.Opcode; +import org.jf.dexlib2.iface.instruction.formats.Instruction25x; +import org.jf.dexlib2.util.Preconditions; + +import javax.annotation.Nonnull; + +public class ImmutableInstruction25x extends ImmutableInstruction implements Instruction25x { + public static final Format FORMAT = Format.Format25x; + + protected final int parameterRegisterCount; + protected final int registerClosure; + protected final int registerD; + protected final int registerE; + protected final int registerF; + protected final int registerG; + + public ImmutableInstruction25x(@Nonnull Opcode opcode, + int parameterRegisterCount, + int registerClosure, + int registerD, + int registerE, + int registerF, + int registerG) { + super(opcode); + this.parameterRegisterCount = + Preconditions.check25xParameterRegisterCount(parameterRegisterCount); + this.registerClosure = Preconditions.checkNibbleRegister(registerClosure); + this.registerD = (parameterRegisterCount>0) ? + Preconditions.checkNibbleRegister(registerD) : 0; + this.registerE = (parameterRegisterCount>1) ? + Preconditions.checkNibbleRegister(registerE) : 0; + this.registerF = (parameterRegisterCount>2) ? + Preconditions.checkNibbleRegister(registerF) : 0; + this.registerG = (parameterRegisterCount>3) ? + Preconditions.checkNibbleRegister(registerG) : 0; + } + + public static ImmutableInstruction25x of(Instruction25x instruction) { + if (instruction instanceof ImmutableInstruction25x) { + return (ImmutableInstruction25x)instruction; + } + return new ImmutableInstruction25x( + instruction.getOpcode(), + instruction.getRegisterCount(), + instruction.getRegisterFixedC(), + instruction.getRegisterParameterD(), + instruction.getRegisterParameterE(), + instruction.getRegisterParameterF(), + instruction.getRegisterParameterG()); + } + + + @Override public int getParameterRegisterCount() { return parameterRegisterCount; } + @Override public int getRegisterCount() { return parameterRegisterCount + 1; } + + @Override public int getRegisterFixedC() { return registerClosure; } + @Override public int getRegisterParameterD() { return registerD; } + @Override public int getRegisterParameterE() { return registerE; } + @Override public int getRegisterParameterF() { return registerF; } + @Override public int getRegisterParameterG() { return registerG; } + + @Override public Format getFormat() { return FORMAT; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java b/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java index ab86b652..51c083ca 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java @@ -133,6 +133,15 @@ public class Preconditions { return registerCount; } + public static int check25xParameterRegisterCount(int registerCount) { + if (registerCount < 0 || registerCount > 4) { + throw new IllegalArgumentException( + String.format("Invalid parameter register count: %d. " + + "Must be between 0 and 4, inclusive.", registerCount)); + } + return registerCount; + } + public static int checkRegisterRangeCount(int registerCount) { if ((registerCount & 0xFFFFFF00) != 0) { throw new IllegalArgumentException( 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 268df9b1..dd6ec9f1 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java @@ -976,6 +976,9 @@ public abstract class DexWriter< case Format23x: instructionWriter.write((Instruction23x)instruction); break; + case Format25x: + instructionWriter.write((Instruction25x)instruction); + break; case Format30t: instructionWriter.write((Instruction30t)instruction); break; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java index 17d31337..23a77759 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java @@ -317,6 +317,19 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend } } + public void write(@Nonnull Instruction25x instruction) { + try { + writer.write(instruction.getOpcode().value); + writer.write(packNibbles( + instruction.getRegisterParameterG(), instruction.getParameterRegisterCount())); + writer.write(packNibbles( + instruction.getRegisterFixedC(), instruction.getRegisterParameterD())); + writer.write(packNibbles( + instruction.getRegisterParameterE(), instruction.getRegisterParameterF())); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } public void write(@Nonnull Instruction3rc instruction) { try { writer.write(instruction.getOpcode().value); diff --git a/dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java b/dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java index 13e7b30f..924d3fd3 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java @@ -79,7 +79,7 @@ public class AccessorTest { public void testAccessors() throws IOException { URL url = AccessorTest.class.getClassLoader().getResource("accessorTest.dex"); Assert.assertNotNull(url); - DexFile f = DexFileFactory.loadDexFile(url.getFile(), 15); + DexFile f = DexFileFactory.loadDexFile(url.getFile(), 15, false); SyntheticAccessorResolver sar = new SyntheticAccessorResolver(f.getClasses()); diff --git a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java index 686b2101..65a82f05 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java @@ -69,7 +69,7 @@ public class CustomMethodInlineTableTest { DexFile dexFile = new ImmutableDexFile(ImmutableList.of(classDef)); ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile, - 15); + 15, false); InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V"); MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver); @@ -96,7 +96,7 @@ public class CustomMethodInlineTableTest { DexFile dexFile = new ImmutableDexFile(ImmutableList.of(classDef)); ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile, - 15); + 15, false); InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V"); MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver); @@ -123,7 +123,7 @@ public class CustomMethodInlineTableTest { DexFile dexFile = new ImmutableDexFile(ImmutableList.of(classDef)); ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile, - 15); + 15, false); InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V"); MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver); diff --git a/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java b/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java index b2cc52db..66abe06a 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java @@ -75,7 +75,7 @@ public class DexWriterTest { throw new RuntimeException(ex); } - DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15), dataStore.getData()); + DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dataStore.getData()); ClassDef dbClassDef = Iterables.getFirst(dexFile.getClasses(), null); Assert.assertNotNull(dbClassDef); Annotation dbAnnotation = Iterables.getFirst(dbClassDef.getAnnotations(), null); diff --git a/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java b/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java index 38015e74..7e504a17 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java @@ -92,7 +92,7 @@ public class JumboStringConversionTest { MemoryDataStore dexStore = new MemoryDataStore(); dexBuilder.writeTo(dexStore); - DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15), dexStore.getData()); + DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dexStore.getData()); ClassDef classDef = Iterables.getFirst(dexFile.getClasses(), null); Assert.assertNotNull(classDef); @@ -189,7 +189,7 @@ public class JumboStringConversionTest { MemoryDataStore dexStore = new MemoryDataStore(); dexBuilder.writeTo(dexStore); - DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15), dexStore.getData()); + DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dexStore.getData()); ClassDef classDef = Iterables.getFirst(dexFile.getClasses(), null); Assert.assertNotNull(classDef); |