diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction11nMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction11nMethodItem.java index 8ba5c494..fc66c8cf 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction11nMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction11nMethodItem.java @@ -40,7 +40,7 @@ public class Instruction11nMethodItem extends InstructionFormatMethodItem { + public Instruction22csfMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, + Instruction22csf instruction) { + super(codeItem, offset, stg, instruction); + } + + protected void setAttributes(StringTemplate template) { + template.setAttribute("Reference", Reference.makeReference(template.getGroup(), + instruction.getReferencedItem())); + template.setAttribute("RegisterA", formatRegister(instruction.getRegisterA())); + template.setAttribute("RegisterB", formatRegister(instruction.getRegisterB())); + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22csnMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22csnMethodItem.java new file mode 100644 index 00000000..a58e7b76 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22csnMethodItem.java @@ -0,0 +1,45 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.baksmali.Adaptors.Format; + +import org.jf.dexlib.Code.Format.Instruction22csn; +import org.jf.dexlib.CodeItem; +import org.antlr.stringtemplate.StringTemplateGroup; +import org.antlr.stringtemplate.StringTemplate; + +public class Instruction22csnMethodItem extends InstructionFormatMethodItem { + public Instruction22csnMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, + Instruction22csn instruction) { + super(codeItem, offset, stg, instruction); + } + + protected void setAttributes(StringTemplate template) { + template.setAttribute("Register", instruction.RegisterNum); + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22sMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22sMethodItem.java index 87f8d3ed..6a4d61cf 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22sMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22sMethodItem.java @@ -42,6 +42,6 @@ public class Instruction22sMethodItem extends InstructionFormatMethodItem { + public Instruction35msfMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, + Instruction35msf instruction) { + super(codeItem, offset, stg, instruction); + } + + protected void setAttributes(StringTemplate template) { + template.setAttribute("Reference", Reference.makeReference(template.getGroup(), + instruction.getReferencedItem())); + setRegistersAttribute(template); + } + + private void setRegistersAttribute(StringTemplate template) { + switch (instruction.getRegCount()) { + case 1: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + return; + case 2: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterE())); + return; + case 3: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterE())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterF())); + return; + case 4: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterE())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterF())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterG())); + return; + case 5: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterE())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterF())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterG())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterA())); + } + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35msnMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35msnMethodItem.java new file mode 100644 index 00000000..01c9d17a --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35msnMethodItem.java @@ -0,0 +1,45 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.baksmali.Adaptors.Format; + +import org.jf.dexlib.Code.Format.Instruction35msn; +import org.jf.dexlib.CodeItem; +import org.antlr.stringtemplate.StringTemplateGroup; +import org.antlr.stringtemplate.StringTemplate; + +public class Instruction35msnMethodItem extends InstructionFormatMethodItem { + public Instruction35msnMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, + Instruction35msn instruction) { + super(codeItem, offset, stg, instruction); + } + + protected void setAttributes(StringTemplate template) { + template.setAttribute("Register", instruction.RegisterNum); + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35sfMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35sfMethodItem.java new file mode 100644 index 00000000..f7194d76 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35sfMethodItem.java @@ -0,0 +1,77 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.baksmali.Adaptors.Format; + +import org.jf.dexlib.Code.Format.Instruction35sf; +import org.jf.dexlib.CodeItem; +import org.jf.baksmali.Adaptors.Reference.Reference; +import org.antlr.stringtemplate.StringTemplateGroup; +import org.antlr.stringtemplate.StringTemplate; + +public class Instruction35sfMethodItem extends InstructionFormatMethodItem { + public Instruction35sfMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, + Instruction35sf instruction) { + super(codeItem, offset, stg, instruction); + } + + protected void setAttributes(StringTemplate template) { + template.setAttribute("Reference", Reference.makeReference(template.getGroup(), + instruction.getReferencedItem())); + setRegistersAttribute(template); + } + + private void setRegistersAttribute(StringTemplate template) { + switch (instruction.getRegCount()) { + case 1: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + return; + case 2: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterE())); + return; + case 3: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterE())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterF())); + return; + case 4: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterE())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterF())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterG())); + return; + case 5: + template.setAttribute("Registers", formatRegister(instruction.getRegisterD())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterE())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterF())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterG())); + template.setAttribute("Registers", formatRegister(instruction.getRegisterA())); + } + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction3rmsfMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction3rmsfMethodItem.java new file mode 100644 index 00000000..9114a357 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction3rmsfMethodItem.java @@ -0,0 +1,55 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.baksmali.Adaptors.Format; + +import org.jf.dexlib.Code.Format.Instruction3rc; +import org.jf.dexlib.Code.Format.Instruction3rmsf; +import org.jf.dexlib.CodeItem; +import org.jf.baksmali.Adaptors.Reference.Reference; +import org.jf.baksmali.Adaptors.RegisterFormatter; +import org.antlr.stringtemplate.StringTemplateGroup; +import org.antlr.stringtemplate.StringTemplate; + +public class Instruction3rmsfMethodItem extends InstructionFormatMethodItem { + public Instruction3rmsfMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, + Instruction3rmsf instruction) { + super(codeItem, offset, stg, instruction); + } + + protected void setAttributes(StringTemplate template) { + template.setAttribute("Reference", Reference.makeReference(template.getGroup(), + instruction.getReferencedItem())); + + String[] registers = RegisterFormatter.formatFormat3rcRegisters(codeItem, instruction.getStartRegister(), + instruction.getStartRegister() + instruction.getRegCount() - 1); + + template.setAttribute("StartRegister", registers[0]); + template.setAttribute("LastRegister", registers[1]); + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction51lMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction51lMethodItem.java index 82503383..c3611779 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction51lMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction51lMethodItem.java @@ -40,7 +40,13 @@ public class Instruction51lMethodItem extends InstructionFormatMethodItem= Integer.MIN_VALUE) { + template.setAttribute("Literal", (int)instruction.getLiteral()); + } else { + template.setAttribute("Literal", instruction.getLiteral()); + } } } 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 82c5c339..7b9b3ac5 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 org.jf.baksmali.Adaptors.Format.*; +import org.jf.baksmali.baksmali; import org.jf.dexlib.*; import org.jf.dexlib.Debug.DebugInstructionIterator; import org.jf.dexlib.Code.Format.*; @@ -178,44 +179,69 @@ public class MethodDefinition { return; } - final byte[] encodedInstructions = codeItem.getEncodedInstructions(); + if (baksmali.deodexUtil != null && dexFile.isOdex()) { + List instructions = baksmali.deodexUtil.deodexerizeCode(codeItem); - InstructionIterator.IterateInstructions(encodedInstructions, - new InstructionIterator.ProcessRawInstructionDelegate() { - public void ProcessNormalInstruction(Opcode opcode, int index) { - if (opcode == Opcode.PACKED_SWITCH) { - Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction( - dexFile, opcode, encodedInstructions, index); - packedSwitchMap.put(index/2 + ins.getOffset(), index/2); - } else if (opcode == Opcode.SPARSE_SWITCH) { - Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction( - dexFile, opcode, encodedInstructions, index); - sparseSwitchMap.put(index/2 + ins.getOffset(), index/2); + int offset = 0; + for (Instruction instruction: instructions) { + if (instruction.opcode == Opcode.PACKED_SWITCH) { + Instruction31t ins = (Instruction31t)instruction; + packedSwitchMap.put(offset + ins.getOffset(), offset); + } else if (instruction.opcode == Opcode.SPARSE_SWITCH) { + Instruction31t ins = (Instruction31t)instruction; + sparseSwitchMap.put(offset + ins.getOffset(), offset); + } + + offset += instruction.getSize()/2; + } + + offset = 0; + for (Instruction instruction: instructions) { + addMethodItemsForInstruction(offset, instruction); + blanks.add(new BlankMethodItem(stg, offset)); + + offset += instruction.getSize()/2; + } + } else { + final byte[] encodedInstructions = codeItem.getEncodedInstructions(); + + InstructionIterator.IterateInstructions(encodedInstructions, + new InstructionIterator.ProcessRawInstructionDelegate() { + public void ProcessNormalInstruction(Opcode opcode, int index) { + if (opcode == Opcode.PACKED_SWITCH) { + Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction( + dexFile, opcode, encodedInstructions, index); + packedSwitchMap.put(index/2 + ins.getOffset(), index/2); + } else if (opcode == Opcode.SPARSE_SWITCH) { + Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction( + dexFile, opcode, encodedInstructions, index); + sparseSwitchMap.put(index/2 + ins.getOffset(), index/2); + } } - } - public void ProcessReferenceInstruction(Opcode opcode, int index) { - } + public void ProcessReferenceInstruction(Opcode opcode, int index) { + } - public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) { - } + public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) { + } - public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) { - } + public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) { + } - public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, - int instructionLength) { - } - }); + public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, + int instructionLength) { + } + }); - InstructionIterator.IterateInstructions(dexFile, encodedInstructions, - new InstructionIterator.ProcessInstructionDelegate() { - public void ProcessInstruction(int index, Instruction instruction) { - int offset = index/2; - addMethodItemsForInstruction(offset, instruction); - blanks.add(new BlankMethodItem(stg, offset)); - } - }); + InstructionIterator.IterateInstructions(dexFile, encodedInstructions, + new InstructionIterator.ProcessInstructionDelegate() { + public void ProcessInstruction(int index, Instruction instruction) { + int offset = index/2; + addMethodItemsForInstruction(offset, instruction); + blanks.add(new BlankMethodItem(stg, offset)); + } + }); + } blanks.remove(blanks.size()-1); @@ -269,6 +295,14 @@ public class MethodDefinition { instructions.add(new Instruction22csMethodItem(codeItem, offset, stg, (Instruction22cs)instruction)); return; + case Format22csf: + instructions.add(new Instruction22csfMethodItem(codeItem, offset, stg, + (Instruction22csf)instruction)); + return; + case Format22csn: + instructions.add(new Instruction22csnMethodItem(codeItem, offset, stg, + (Instruction22csn)instruction)); + return; case Format22s: instructions.add(new Instruction22sMethodItem(codeItem, offset, stg, (Instruction22s)instruction)); return; @@ -314,10 +348,22 @@ public class MethodDefinition { case Format35s: instructions.add(new Instruction35sMethodItem(codeItem, offset, stg, (Instruction35s)instruction)); return; + case Format35sf: + instructions.add(new Instruction35sfMethodItem(codeItem, offset, stg, + (Instruction35sf)instruction)); + return; case Format35ms: instructions.add(new Instruction35msMethodItem(codeItem, offset, stg, (Instruction35ms)instruction)); return; + case Format35msf: + instructions.add(new Instruction35msfMethodItem(codeItem, offset, stg, + (Instruction35msf)instruction)); + return; + case Format35msn: + instructions.add(new Instruction35msnMethodItem(codeItem, offset, stg, + (Instruction35msn)instruction)); + return; case Format3rc: instructions.add(new Instruction3rcMethodItem(codeItem, offset, stg, (Instruction3rc)instruction)); return; @@ -325,6 +371,10 @@ public class MethodDefinition { instructions.add(new Instruction3rmsMethodItem(codeItem, offset, stg, (Instruction3rms)instruction)); return; + case Format3rmsf: + instructions.add(new Instruction3rmsfMethodItem(codeItem, offset, stg, + (Instruction3rmsf)instruction)); + return; case Format51l: instructions.add(new Instruction51lMethodItem(codeItem, offset, stg, (Instruction51l)instruction)); return; diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmali.java b/baksmali/src/main/java/org/jf/baksmali/baksmali.java index 5e9f0c58..c1a59c1c 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmali.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmali.java @@ -35,15 +35,22 @@ import org.jf.baksmali.Renderers.*; import org.jf.dexlib.DexFile; import org.jf.dexlib.ClassDefItem; import org.jf.dexlib.StringIdItem; +import org.jf.dexlib.Util.Deodexerant; +import org.jf.dexlib.Util.DeodexUtil; import java.io.*; public class baksmali { public static boolean noParameterRegisters = false; + public static DeodexUtil deodexUtil = null; - public static void disassembleDexFile(DexFile dexFile, String outputDirectory, boolean noParameterRegisters) + public static void disassembleDexFile(DexFile dexFile, Deodexerant deodexerant, String outputDirectory, + boolean noParameterRegisters) { baksmali.noParameterRegisters = noParameterRegisters; + if (deodexerant != null) { + baksmali.deodexUtil = new DeodexUtil(deodexerant); + } File outputDirectoryFile = new File(outputDirectory); if (!outputDirectoryFile.exists()) { @@ -76,6 +83,9 @@ public class baksmali { String classDescriptor = classDefItem.getClassType().getTypeDescriptor(); + //TODO: GROT + System.out.println(classDescriptor); + //validate that the descriptor is formatted like we expect if (classDescriptor.charAt(0) != 'L' || classDescriptor.charAt(classDescriptor.length()-1) != ';') { diff --git a/baksmali/src/main/java/org/jf/baksmali/main.java b/baksmali/src/main/java/org/jf/baksmali/main.java index d863ac66..e71de8d9 100644 --- a/baksmali/src/main/java/org/jf/baksmali/main.java +++ b/baksmali/src/main/java/org/jf/baksmali/main.java @@ -18,12 +18,10 @@ package org.jf.baksmali; import org.apache.commons.cli.*; import org.jf.dexlib.DexFile; -import org.jf.baksmali.Renderers.*; -import org.antlr.stringtemplate.StringTemplateGroup; +import org.jf.dexlib.Util.Deodexerant; import java.io.File; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.IOException; import java.util.Properties; @@ -75,10 +73,13 @@ public class main { boolean fixRegisters = false; boolean noParameterRegisters = false; + String outputDirectory = "out"; String dumpFileName = null; String outputDexFileName = null; String inputDexFileName = null; + String deodexerantHost = null; + int deodexerantPort = 0; String[] remainingArgs = commandLine.getArgs(); @@ -129,6 +130,26 @@ public class main { noParameterRegisters = true; } + if (commandLine.hasOption("x")) { + String deodexerantAddress = commandLine.getOptionValue("x"); + String[] parts = deodexerantAddress.split(":"); + if (parts.length != 2) { + System.err.println("Invalid deodexerant address. Expecting : or :"); + System.exit(1); + } + + deodexerantHost = parts[0]; + if (deodexerantHost.length() == 0) { + deodexerantHost = "localhost"; + } + try { + deodexerantPort = Integer.parseInt(parts[1]); + } catch (NumberFormatException ex) { + System.err.println("Invalid port \"" + deodexerantPort + "\" for deodexerant address"); + System.exit(1); + } + } + try { File dexFileFile = new File(inputDexFileName); if (!dexFileFile.exists()) { @@ -139,11 +160,30 @@ public class main { //Read in and parse the dex file DexFile dexFile = new DexFile(dexFileFile, !fixRegisters); - if (disassemble) { - baksmali.disassembleDexFile(dexFile, outputDirectory, noParameterRegisters); + Deodexerant deodexerant = null; + + + if (deodexerantHost != null) { + if (!dexFile.isOdex()) { + System.err.println("-x cannot be used with a normal dex file. Ignoring -x"); + } + deodexerant = new Deodexerant(dexFile, deodexerantHost, deodexerantPort); } - if (doDump || write) { + if (dexFile.isOdex()) { + if (doDump) { + System.err.println("-d cannot be used with on odex file. Ignoring -d"); + } + if (write) { + System.err.println("-w cannot be used with an odex file. Ignoring -w"); + } + } + + if (disassemble) { + baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, noParameterRegisters); + } + + if ((doDump || write) && !dexFile.isOdex()) { try { dump.dump(dexFile, dumpFileName, outputDexFileName, sort); @@ -228,6 +268,13 @@ public class main { " parameters") .create("p"); + Option deodexerantOption = OptionBuilder.withLongOpt("deodexerant") + .withDescription("connect to deodexerant on the specified HOST:PORT, and deodex the input odex" + + " file. This option is ignored if the input file is a dex file instead of an odex file") + .hasArg() + .withArgName("HOST:PORT") + .create("x"); + OptionGroup dumpCommand = new OptionGroup(); options.addOption(versionOption); @@ -239,5 +286,6 @@ public class main { options.addOption(sortOption); options.addOption(fixSignedRegisterOption); options.addOption(noParameterRegistersOption); + options.addOption(deodexerantOption); } } \ No newline at end of file diff --git a/baksmali/src/main/resources/templates/templates/baksmali.stg b/baksmali/src/main/resources/templates/templates/baksmali.stg index acab30f7..65eb8cae 100644 --- a/baksmali/src/main/resources/templates/templates/baksmali.stg +++ b/baksmali/src/main/resources/templates/templates/baksmali.stg @@ -193,6 +193,17 @@ Format22cs(Opcode, RegisterA, RegisterB, FieldOffset) ::= , , Field@ >> +Format22csf(Opcode, RegisterA, RegisterB, Reference) ::= +<< + , , +>> + +Format22csn(Register) ::= +<< +#Couldn't determine field access while deodexing, replaced with generic method call +invoke-virtual , Ljava/lang/Object;->hashCode()I +>> + Format22s(Opcode, RegisterA, RegisterB, Literal) ::= << , , @@ -248,11 +259,27 @@ Format35s(Opcode, Registers, Reference) ::= {}, >> +Format35sf(Opcode, Registers, Reference) ::= +<< + {}, +>> + Format35ms(Opcode, Registers, MethodIndex) ::= << {}, vtable@ >> +Format35msf(Opcode, Registers, Reference) ::= +<< + {}, +>> + +Format35msn(Register) ::= +<< +#Couldn't determine method while deodexing, replaced with generic method call +invoke-virtual , Ljava/lang/Object;->hashCode()I +>> + Format3rc(Opcode, StartRegister, LastRegister, Reference) ::= << { .. }, @@ -263,6 +290,11 @@ Format3rms(Opcode, StartRegister, LastRegister, MethodIndex) ::= { .. }, vtable@ >> +Format3rmsf(Opcode, StartRegister, LastRegister, Reference) ::= +<< + { .. }, +>> + Format51l(Opcode, Register, Literal) ::= << , diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java index fee982b5..5c36d062 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java @@ -44,6 +44,8 @@ public enum Format { Format22b(Instruction22b.Factory, 4), Format22c(Instruction22c.Factory, 4), Format22cs(Instruction22cs.Factory, 4), + Format22csf(null, 4), + Format22csn(null, 4), Format22s(Instruction22s.Factory, 4), Format22t(Instruction22t.Factory, 4), Format22x(Instruction22x.Factory, 4), @@ -55,9 +57,13 @@ public enum Format { Format32x(Instruction32x.Factory, 6), Format35c(Instruction35c.Factory, 6), Format35s(Instruction35s.Factory, 6), + Format35sf(null, 6), Format35ms(Instruction35ms.Factory, 6), + Format35msf(null, 6), + Format35msn(null, 6), Format3rc(Instruction3rc.Factory, 6), Format3rms(Instruction3rms.Factory, 6), + Format3rmsf(null, 6), Format51l(Instruction51l.Factory, 10), ArrayData(null, -1, true), PackedSwitchData(null, -1, true), diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10t.java index f7fe81ae..603ca1cf 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10t.java @@ -30,10 +30,11 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.Output; -public class Instruction10t extends Instruction { +public class Instruction10t extends Instruction implements OffsetInstruction { public static final InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, byte offA) { @@ -57,7 +58,7 @@ public class Instruction10t extends Instruction { return Format.Format10t; } - public byte getOffset() { + public int getOffset() { return buffer[bufferIndex + 1]; } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11n.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11n.java index d2b80d99..da510f92 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11n.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11n.java @@ -30,11 +30,13 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.Code.LiteralInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction11n extends Instruction { +public class Instruction11n extends Instruction implements SingleRegisterInstruction, LiteralInstruction { public static final InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, byte regA, byte litB) { @@ -59,11 +61,11 @@ public class Instruction11n extends Instruction { return Format.Format11n; } - public byte getRegister() { + public int getRegisterA() { return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); } - public byte getLiteral() { + public long getLiteral() { return NumberUtils.decodeHighSignedNibble(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java index 9d4a8f22..37f62874 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction11x.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction11x extends Instruction { +public class Instruction11x extends Instruction implements SingleRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA) { @@ -54,7 +55,7 @@ public class Instruction11x extends Instruction { return Format.Format11x; } - public short getRegister() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java index a2682a4d..2c6443e1 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction12x.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction12x extends Instruction { +public class Instruction12x extends Instruction implements TwoRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, byte regA, byte regB) { @@ -55,11 +56,11 @@ public class Instruction12x extends Instruction { return Format.Format12x; } - public byte getRegisterA() { + public int getRegisterA() { return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); } - public byte getRegisterB() { + public int getRegisterB() { return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java index df0cd0bb..6ea48a9d 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction20t.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction20t extends Instruction { +public class Instruction20t extends Instruction implements OffsetInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short offA) { @@ -59,7 +60,7 @@ public class Instruction20t extends Instruction { return Format.Format20t; } - public short getOffset() { + public int getOffset() { return NumberUtils.decodeShort(buffer, bufferIndex + 2); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java index bb315a81..6b56e55e 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21c.java @@ -31,13 +31,14 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.InstructionWithReference; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Item; import org.jf.dexlib.TypeIdItem; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction21c extends InstructionWithReference { +public class Instruction21c extends InstructionWithReference implements SingleRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, Item referencedItem) { @@ -69,7 +70,7 @@ public class Instruction21c extends InstructionWithReference { return Format.Format21c; } - public short getRegister() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java index e134c66d..0fd20c90 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21h.java @@ -30,11 +30,13 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.LiteralInstruction; +import org.jf.dexlib.Code.SingleRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction21h extends Instruction { +public class Instruction21h extends Instruction implements SingleRegisterInstruction, LiteralInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, short litB) { @@ -55,11 +57,11 @@ public class Instruction21h extends Instruction { return Format.Format21h; } - public short getRegister() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } - public short getLiteral() { + public long getLiteral() { return NumberUtils.decodeShort(buffer, bufferIndex + 2); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java index a93241de..88462552 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21s.java @@ -30,11 +30,13 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.LiteralInstruction; +import org.jf.dexlib.Code.SingleRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction21s extends Instruction { +public class Instruction21s extends Instruction implements SingleRegisterInstruction, LiteralInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, short litB) { @@ -55,11 +57,11 @@ public class Instruction21s extends Instruction { return Format.Format21s; } - public short getRegister() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } - public short getLiteral() { + public long getLiteral() { return NumberUtils.decodeShort(buffer, bufferIndex + 2); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java index 8851bbbc..02980b4d 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction21t.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction21t extends Instruction { +public class Instruction21t extends Instruction implements OffsetInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, short offB) { @@ -67,7 +68,7 @@ public class Instruction21t extends Instruction { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } - public short getOffset() { + public int getOffset() { return NumberUtils.decodeShort(buffer, bufferIndex + 2); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java index f8d67c92..7a7b6380 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22b.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction22b extends Instruction { +public class Instruction22b extends Instruction implements TwoRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, short regB, byte litC) { @@ -57,11 +58,11 @@ public class Instruction22b extends Instruction { return Format.Format22b; } - public short getRegisterA() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } - public short getRegisterB() { + public int getRegisterB() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 2]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java index d4fc1f58..8040869b 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java @@ -31,12 +31,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.InstructionWithReference; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; import org.jf.dexlib.DexFile; -import org.jf.dexlib.Item; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction22c extends InstructionWithReference { +public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, byte regA, byte regB) { @@ -58,11 +58,11 @@ public class Instruction22c extends InstructionWithReference { return Format.Format22c; } - public byte getRegisterA() { + public int getRegisterA() { return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); } - public byte getRegisterB() { + public int getRegisterB() { return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22cs.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22cs.java index cf911f20..4f512102 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22cs.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22cs.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; import org.jf.dexlib.Util.Output; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.DexFile; -public class Instruction22cs extends Instruction { +public class Instruction22cs extends Instruction implements TwoRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, byte regA, byte regB, int fieldOffset) { @@ -60,11 +61,11 @@ public class Instruction22cs extends Instruction { return Format.Format22cs; } - public byte getRegisterA() { + public int getRegisterA() { return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); } - public byte getRegisterB() { + public int getRegisterB() { return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csf.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csf.java new file mode 100644 index 00000000..ca5eb8e9 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csf.java @@ -0,0 +1,56 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code.Format; + +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; +import org.jf.dexlib.Code.InstructionWithReference; +import org.jf.dexlib.FieldIdItem; + +public class Instruction22csf extends InstructionWithReference implements TwoRegisterInstruction { + private final Instruction22cs unfixedInstruction; + + public Instruction22csf(Opcode opcode, Instruction22cs unfixedInstruction, FieldIdItem field) { + //the opcode should be the "fixed" opcode. i.e. iget-object, etc. (NOT the "quick" version) + super(opcode, field); + this.unfixedInstruction = unfixedInstruction; + } + + public Format getFormat() { + return Format.Format22csf; + } + + public int getRegisterA() { + return unfixedInstruction.getRegisterA(); + } + + public int getRegisterB() { + return unfixedInstruction.getRegisterB(); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csn.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csn.java new file mode 100644 index 00000000..e9a94c25 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csn.java @@ -0,0 +1,58 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code.Format; + +import org.jf.dexlib.Code.Instruction; +import org.jf.dexlib.Code.Opcode; + +/** + * This represents a "fixed" Format22cs instruction, where the object register is always null and so the correct type + * can't be determined. How this is handled is "implementation dependent". baksmali just replaces it with a call to + * object->hashCode(). Since the object register is always null, this will have the same effect as tring to access + * whatever field that was trying to be accessed - namely, a NPE + */ +public class Instruction22csn extends Instruction { + + /** + * this is the first register, i.e. the object register. The others don't matter, because we don't know what + * the original field is/was. + */ + public final int RegisterNum; + + public Instruction22csn(int registerNum) { + //the opcode should be ignored. It just needs to be a 4 byte opcode + super(Opcode.IGET_QUICK); + this.RegisterNum = registerNum; + } + + + public Format getFormat() { + return Format.Format35msn; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java index f8b843ab..2e2e09f0 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22s.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction22s extends Instruction { +public class Instruction22s extends Instruction implements TwoRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, byte regA, byte regB, short litC) { @@ -56,11 +57,11 @@ public class Instruction22s extends Instruction { return Format.Format22s; } - public byte getRegisterA() { + public int getRegisterA() { return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); } - public byte getRegisterB() { + public int getRegisterB() { return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java index 2ce07dc2..caacb1da 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22t.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction22t extends Instruction { +public class Instruction22t extends Instruction implements OffsetInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, byte regA, byte regB, short offC) { @@ -72,7 +73,7 @@ public class Instruction22t extends Instruction { return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); } - public short getOffset() { + public int getOffset() { return NumberUtils.decodeShort(buffer, bufferIndex + 2); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java index 8eaf33b2..c9081f0f 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22x.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction22x extends Instruction { +public class Instruction22x extends Instruction implements TwoRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, int regB) { @@ -59,7 +60,7 @@ public class Instruction22x extends Instruction { return Format.Format22x; } - public short getRegisterA() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java index 632072a9..4a27cf59 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction23x.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.ThreeRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction23x extends Instruction { +public class Instruction23x extends Instruction implements ThreeRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, short regB, short regC) { @@ -58,15 +59,15 @@ public class Instruction23x extends Instruction { return Format.Format23x; } - public short getRegisterA() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } - public short getRegisterB() { + public int getRegisterB() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 2]); } - public short getRegisterC() { + public int getRegisterC() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 3]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java index 19c0b671..5c3f1b0d 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction30t.java @@ -31,11 +31,11 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.DexFile; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction30t extends Instruction -{ +public class Instruction30t extends Instruction implements OffsetInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, int offA) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java index f1fcb212..4213cea8 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31c.java @@ -31,12 +31,13 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.InstructionWithReference; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Item; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction31c extends InstructionWithReference { +public class Instruction31c extends InstructionWithReference implements SingleRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA) { @@ -57,7 +58,7 @@ public class Instruction31c extends InstructionWithReference { return Format.Format31c; } - public short getRegister() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java index 9c3ec82e..43d0ae2b 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31i.java @@ -30,11 +30,13 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.LiteralInstruction; +import org.jf.dexlib.Code.SingleRegisterInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction31i extends Instruction { +public class Instruction31i extends Instruction implements SingleRegisterInstruction, LiteralInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, int litB) { @@ -55,11 +57,11 @@ public class Instruction31i extends Instruction { return Format.Format31i; } - public short getRegister() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } - public int getLiteral() { + public long getLiteral() { return NumberUtils.decodeInt(buffer, bufferIndex + 2); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java index 87e5c40d..0cf455cf 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction31t.java @@ -30,11 +30,12 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.OffsetInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction31t extends Instruction { +public class Instruction31t extends Instruction implements OffsetInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, int offB) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java index be5b6e7e..ad3097c0 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction32x.java @@ -31,11 +31,11 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.DexFile; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.TwoRegisterInstruction; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction32x extends Instruction -{ +public class Instruction32x extends Instruction implements TwoRegisterInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, int regA, int regB) { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msf.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msf.java new file mode 100644 index 00000000..b029c546 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msf.java @@ -0,0 +1,71 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code.Format; + +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.InstructionWithReference; +import org.jf.dexlib.MethodIdItem; + +public class Instruction35msf extends InstructionWithReference { + private final Instruction35ms unfixedInstruction; + + public Instruction35msf(Opcode opcode, Instruction35ms unfixedInstruction, MethodIdItem method) { + //the opcode should be the "fixed" opcode. i.e. iget-object, etc. (NOT the "quick" version) + super(opcode, method); + this.unfixedInstruction = unfixedInstruction; + } + + public Format getFormat() { + return Format.Format35msf; + } + + public int getRegisterA() { + return unfixedInstruction.getRegisterA(); + } + + public byte getRegCount() { + return unfixedInstruction.getRegCount(); + } + + public byte getRegisterD() { + return unfixedInstruction.getRegisterD(); + } + + public byte getRegisterE() { + return unfixedInstruction.getRegisterE(); + } + + public byte getRegisterF() { + return unfixedInstruction.getRegisterF(); + } + + public byte getRegisterG() { + return unfixedInstruction.getRegisterG(); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msn.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msn.java new file mode 100644 index 00000000..71173294 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msn.java @@ -0,0 +1,57 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code.Format; + +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.Instruction; + +/** + * This represents a "fixed" Format35ms, or Format3rms instruction, where the object register is always null and so the + * correct type can't be determined. How this is handled is "implementation dependent". baksmali just replaces it with + * a call to object->hashCode(). Since the object register is always null, this will have the same effect as calling + * whatever the original method was - namely, a NPE + */ +public class Instruction35msn extends Instruction { + + /** + * this is the first register, i.e. the object register. The others don't matter, because we don't know what + * the original method call is/was. + */ + public final int RegisterNum; + + public Instruction35msn(int registerNum) { + super(Opcode.INVOKE_VIRTUAL); + this.RegisterNum = registerNum; + } + + + public Format getFormat() { + return Format.Format35msn; + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35sf.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35sf.java new file mode 100644 index 00000000..785babca --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35sf.java @@ -0,0 +1,69 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code.Format; + +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.InstructionWithReference; + +public class Instruction35sf extends InstructionWithReference { + private final Instruction35s unfixedInstruction; + + public Instruction35sf(Instruction35s unfixedInstruction) { + super(Opcode.INVOKE_DIRECT, unfixedInstruction.getReferencedItem()); + this.unfixedInstruction = unfixedInstruction; + } + + public Format getFormat() { + return Format.Format35sf; + } + + public byte getRegisterA() { + return unfixedInstruction.getRegisterA(); + } + + public byte getRegCount() { + return unfixedInstruction.getRegCount(); + } + + public byte getRegisterD() { + return unfixedInstruction.getRegisterD(); + } + + public byte getRegisterE() { + return unfixedInstruction.getRegisterE(); + } + + public byte getRegisterF() { + return unfixedInstruction.getRegisterF(); + } + + public byte getRegisterG() { + return unfixedInstruction.getRegisterG(); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rmsf.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rmsf.java new file mode 100644 index 00000000..380d25df --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rmsf.java @@ -0,0 +1,55 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code.Format; + +import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.InstructionWithReference; +import org.jf.dexlib.MethodIdItem; + +public class Instruction3rmsf extends InstructionWithReference { + private final Instruction3rms unfixedInstruction; + + public Instruction3rmsf(Opcode opcode, Instruction3rms unfixedInstruction, MethodIdItem method) { + //the opcode should be the "fixed" opcode. i.e. iget-object, etc. (NOT the "quick" version) + super(opcode, method); + this.unfixedInstruction = unfixedInstruction; + } + + public Format getFormat() { + return Format.Format3rmsf; + } + + public int getStartRegister() { + return unfixedInstruction.getStartRegister(); + } + + public short getRegCount() { + return unfixedInstruction.getRegCount(); + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java index 3a725729..f0fe0334 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction51l.java @@ -30,11 +30,13 @@ package org.jf.dexlib.Code.Format; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; +import org.jf.dexlib.Code.SingleRegisterInstruction; +import org.jf.dexlib.Code.LiteralInstruction; import org.jf.dexlib.DexFile; import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.Output; -public class Instruction51l extends Instruction { +public class Instruction51l extends Instruction implements SingleRegisterInstruction, LiteralInstruction { public static final Instruction.InstructionFactory Factory = new Factory(); public static void emit(Output out, Opcode opcode, short regA, long litB) { @@ -55,7 +57,7 @@ public class Instruction51l extends Instruction { return Format.Format51l; } - public short getRegister() { + public int getRegisterA() { return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/LiteralInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/LiteralInstruction.java new file mode 100644 index 00000000..ac6cb494 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/LiteralInstruction.java @@ -0,0 +1,33 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code; + +public interface LiteralInstruction { + long getLiteral(); +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/OffsetInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/OffsetInstruction.java new file mode 100644 index 00000000..0655245b --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/OffsetInstruction.java @@ -0,0 +1,33 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code; + +public interface OffsetInstruction { + public int getOffset(); +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java index 5174b5ae..77722611 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java @@ -255,26 +255,17 @@ public enum Opcode INVOKE_EXECUTE_INLINE((byte)0xee, "execute_inline", ReferenceType.none, Format.Format35ms, true), - INVOKE_DIRECT_EMPTY((byte)0xf0, "invoke-direct-empty", ReferenceType.method, Format.Format35s, true), - IGET_QUICK((byte)0xf2, "iget-quick", ReferenceType.none, Format.Format22cs, true), IGET_WIDE_QUICK((byte)0xf3, "iget-wide-quick", ReferenceType.none, Format.Format22cs, true), IGET_OBJECT_QUICK((byte)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, true), - IPUT_QUICK((byte)0xf5, "iput-quick", ReferenceType.none, Format.Format22cs, true), IPUT_WIDE_QUICK((byte)0xf6, "iput-wide-quick", ReferenceType.none, Format.Format22cs, true), IPUT_OBJECT_QUICK((byte)0xf7, "iput-object-quick", ReferenceType.none, Format.Format22cs, true), - - - INVOKE_VIRTUAL_QUICK((byte)0xf8, "invoke-virtual-quick", ReferenceType.none, Format.Format35ms, true), INVOKE_VIRTUAL_RANGE_QUICK((byte)0xf9, "invoke-virtual-range-quick", ReferenceType.none, Format.Format3rms, true), - - INVOKE_SUPERL_QUICK((byte)0xfa, "invoke-super-quick", ReferenceType.none, Format.Format35ms, true), - INVOKE_SUPER_RANGE_QUICK((byte)0xfb, "invoke-super-range-quick", ReferenceType.none, Format.Format3rms, true), - - ; + INVOKE_SUPER_QUICK((byte)0xfa, "invoke-super-quick", ReferenceType.none, Format.Format35ms, true), + INVOKE_SUPER_RANGE_QUICK((byte)0xfb, "invoke-super-range-quick", ReferenceType.none, Format.Format3rms, true); diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/SingleRegisterInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/SingleRegisterInstruction.java new file mode 100644 index 00000000..40b322d8 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/SingleRegisterInstruction.java @@ -0,0 +1,33 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code; + +public interface SingleRegisterInstruction { + int getRegisterA(); +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/ThreeRegisterInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/ThreeRegisterInstruction.java new file mode 100644 index 00000000..3eab7bfd --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/ThreeRegisterInstruction.java @@ -0,0 +1,33 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code; + +public interface ThreeRegisterInstruction extends TwoRegisterInstruction { + int getRegisterC(); +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/TwoRegisterInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/TwoRegisterInstruction.java new file mode 100644 index 00000000..e9523bce --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/TwoRegisterInstruction.java @@ -0,0 +1,35 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code; + +public interface TwoRegisterInstruction extends SingleRegisterInstruction { + int getRegisterA(); + int getRegisterB(); + +} diff --git a/dexlib/src/main/java/org/jf/dexlib/CodeItem.java b/dexlib/src/main/java/org/jf/dexlib/CodeItem.java index 06ad5353..8d2f7ba2 100644 --- a/dexlib/src/main/java/org/jf/dexlib/CodeItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/CodeItem.java @@ -28,16 +28,14 @@ package org.jf.dexlib; -import org.jf.dexlib.Code.InstructionReader; -import org.jf.dexlib.Code.InstructionIterator; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.InstructionWriter; +import org.jf.dexlib.Code.*; import org.jf.dexlib.Util.AnnotatedOutput; import org.jf.dexlib.Util.Input; import org.jf.dexlib.Util.SparseArray; import org.jf.dexlib.Util.Leb128Utils; import java.util.List; +import java.util.LinkedList; public class CodeItem extends Item { private int registerCount; @@ -358,6 +356,13 @@ public class CodeItem extends Item { return tries; } + /** + * @return an array of the EncodedCatchHandler objects in this CodeItem + */ + public EncodedCatchHandler[] getHandlers() { + return encodedCatchHandlers; + } + /** * @return the DebugInfoItem associated with this CodeItem */ @@ -381,6 +386,28 @@ public class CodeItem extends Item { return parent; } + /** + * Used by OdexUtil to update this CodeItem with a deodexed version of the instructions + * @param newEncodedInstructions + */ + public void updateCode(byte[] newEncodedInstructions) { + final LinkedList referencedItemsList = new LinkedList(); + + + InstructionIterator.IterateInstructions(dexFile, newEncodedInstructions, + new InstructionIterator.ProcessInstructionDelegate() { + public void ProcessInstruction(int index, Instruction instruction) { + if (instruction.opcode.referenceType != ReferenceType.none) { + referencedItemsList.add(((InstructionWithReference)instruction).getReferencedItem()); + } + } + }); + + referencedItems = new Item[referencedItemsList.size()]; + referencedItemsList.toArray(referencedItems); + encodedInstructions = newEncodedInstructions; + } + public static class TryItem { /** * The address (in 2-byte words) within the code where the try block starts diff --git a/dexlib/src/main/java/org/jf/dexlib/DexFile.java b/dexlib/src/main/java/org/jf/dexlib/DexFile.java index 16b1e0d5..777daaeb 100644 --- a/dexlib/src/main/java/org/jf/dexlib/DexFile.java +++ b/dexlib/src/main/java/org/jf/dexlib/DexFile.java @@ -166,11 +166,18 @@ public class DexFile */ private final DexFile dexFile = this; + /** + * Is this file an odex file? This is only set when reading in an odex file + */ + private boolean isOdex = false; + private int dataOffset; private int dataSize; private int fileSize; + private boolean disableInterning = false; + /** * A private constructor containing common code to initialize the section maps and lists @@ -278,7 +285,7 @@ public class DexFile } boolean isDex = true; - boolean isOdex = true; + this.isOdex = true; for (int i=0; i<8; i++) { if (magic[i] != dexMagic[i]) { isDex = false; @@ -401,6 +408,30 @@ public class DexFile this.sortAllItems = value; } + /** + * Disables adding new items to this dex file. The various getInterned*() type + * methods on individual items will return null if there isn't an existing item + * that matches + */ + public void disableInterning() { + this.disableInterning = true; + } + + /** + * @return a boolean value indicating whether interning new items has been disabled + * for this dex file + */ + public boolean getInterningDisabled() { + return disableInterning; + } + + /** + * @return a boolean value indicating whether this dex file was created by reading in an odex file + */ + public boolean isOdex() { + return this.isOdex; + } + /** * Get a boolean value indicating whether items in this dex file should be * written back out "in-place", or whether the normal layout logic should be diff --git a/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java b/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java index 6289dae6..eb19d8a5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java @@ -155,6 +155,20 @@ public class ProtoIdItem extends Item { return cachedPrototypeString; } + /** + * @return the return type of the method + */ + public TypeIdItem getReturnType() { + return returnType; + } + + /** + * @return a TypeListItem containing the method parameter types + */ + public TypeListItem getParameters() { + return parameters; + } + /** * @return the number of registers required for the parameters of this ProtoIdItem */ diff --git a/dexlib/src/main/java/org/jf/dexlib/Section.java b/dexlib/src/main/java/org/jf/dexlib/Section.java index d7cf78f7..28299e86 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Section.java +++ b/dexlib/src/main/java/org/jf/dexlib/Section.java @@ -174,8 +174,11 @@ public abstract class Section { * as the item passed to this method. */ protected T intern(T item) { + if (item == null) { + return null; + } T internedItem = getInternedItem(item); - if (internedItem == null) { + if (internedItem == null && !item.dexFile.getInterningDisabled()) { uniqueItems.put(item, item); items.add(item); return item; diff --git a/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java b/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java index 8847dc24..79195e95 100644 --- a/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java @@ -53,16 +53,6 @@ public class StringIdItem extends Item { this.stringDataItem = stringDataItem; } - /** - * Creates a new StringIdItem and associated StringDataItem - * for the given String value - * @param dexFile The DexFile that this item will belong to - * @param stringValue The string value that this item represents - */ - private StringIdItem(DexFile dexFile, String stringValue) { - this(dexFile, StringDataItem.getInternedStringDataItem(dexFile, stringValue)); - } - /** * Returns a StringIdItem for the given values, and that has been interned into * the given DexFile @@ -72,7 +62,11 @@ public class StringIdItem extends Item { * the given DexFile */ public static StringIdItem getInternedStringIdItem(DexFile dexFile, String stringValue) { - StringIdItem stringIdItem = new StringIdItem(dexFile, stringValue); + StringDataItem stringDataItem = StringDataItem.getInternedStringDataItem(dexFile, stringValue); + if (stringDataItem == null) { + return null; + } + StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem); return dexFile.StringIdsSection.intern(stringIdItem); } diff --git a/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java b/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java index 08a9d654..7e137986 100644 --- a/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java @@ -77,7 +77,11 @@ public class TypeIdItem extends Item { * the given DexFile */ public static TypeIdItem getInternedTypeIdItem(DexFile dexFile, String typeDescriptor) { - TypeIdItem typeIdItem = new TypeIdItem(dexFile, StringIdItem.getInternedStringIdItem(dexFile, typeDescriptor)); + StringIdItem stringIdItem = StringIdItem.getInternedStringIdItem(dexFile, typeDescriptor); + if (stringIdItem == null) { + return null; + } + TypeIdItem typeIdItem = new TypeIdItem(dexFile, stringIdItem); return dexFile.TypeIdsSection.intern(typeIdItem); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java b/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java new file mode 100644 index 00000000..08c2ad7e --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java @@ -0,0 +1,1479 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Util; + +import org.jf.dexlib.*; +import org.jf.dexlib.Code.*; +import org.jf.dexlib.Code.Format.*; + +import java.util.*; + +public class DeodexUtil { + private final Deodexerant deodexerant; + + //a table that reflects which instructions can throw an exception + public static final BitSet instructionThrowTable = new BitSet(256); + + { + //mark the instructions that can throw an exception + instructionThrowTable.set(Opcode.CONST_STRING.value & 0xFF); + instructionThrowTable.set(Opcode.CONST_STRING_JUMBO.value & 0xFF); + instructionThrowTable.set(Opcode.CONST_CLASS.value & 0xFF); + instructionThrowTable.set(Opcode.MONITOR_ENTER.value & 0xFF); + instructionThrowTable.set(Opcode.MONITOR_EXIT.value & 0xFF); + instructionThrowTable.set(Opcode.CHECK_CAST.value & 0xFF); + instructionThrowTable.set(Opcode.INSTANCE_OF.value & 0xFF); + instructionThrowTable.set(Opcode.ARRAY_LENGTH.value & 0xFF); + instructionThrowTable.set(Opcode.NEW_INSTANCE.value & 0xFF); + instructionThrowTable.set(Opcode.NEW_ARRAY.value & 0xFF); + instructionThrowTable.set(Opcode.FILLED_NEW_ARRAY.value & 0xFF); + instructionThrowTable.set(Opcode.FILLED_NEW_ARRAY_RANGE.value & 0xFF); + instructionThrowTable.set(Opcode.AGET.value & 0xFF); + instructionThrowTable.set(Opcode.AGET_BOOLEAN.value & 0xFF); + instructionThrowTable.set(Opcode.AGET_BYTE.value & 0xFF); + instructionThrowTable.set(Opcode.AGET_CHAR.value & 0xFF); + instructionThrowTable.set(Opcode.AGET_SHORT.value & 0xFF); + instructionThrowTable.set(Opcode.AGET_WIDE.value & 0xFF); + instructionThrowTable.set(Opcode.AGET_OBJECT.value & 0xFF); + instructionThrowTable.set(Opcode.APUT.value & 0xFF); + instructionThrowTable.set(Opcode.APUT_BOOLEAN.value & 0xFF); + instructionThrowTable.set(Opcode.APUT_BYTE.value & 0xFF); + instructionThrowTable.set(Opcode.APUT_CHAR.value & 0xFF); + instructionThrowTable.set(Opcode.APUT_SHORT.value & 0xFF); + instructionThrowTable.set(Opcode.APUT_WIDE.value & 0xFF); + instructionThrowTable.set(Opcode.APUT_OBJECT.value & 0xFF); + instructionThrowTable.set(Opcode.IGET.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_BOOLEAN.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_BYTE.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_CHAR.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_SHORT.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_WIDE.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_OBJECT.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_BOOLEAN.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_BYTE.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_CHAR.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_SHORT.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_WIDE.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_OBJECT.value & 0xFF); + instructionThrowTable.set(Opcode.SGET.value & 0xFF); + instructionThrowTable.set(Opcode.SGET_BOOLEAN.value & 0xFF); + instructionThrowTable.set(Opcode.SGET_BYTE.value & 0xFF); + instructionThrowTable.set(Opcode.SGET_CHAR.value & 0xFF); + instructionThrowTable.set(Opcode.SGET_SHORT.value & 0xFF); + instructionThrowTable.set(Opcode.SGET_WIDE.value & 0xFF); + instructionThrowTable.set(Opcode.SGET_OBJECT.value & 0xFF); + instructionThrowTable.set(Opcode.SPUT.value & 0xFF); + instructionThrowTable.set(Opcode.SPUT_BOOLEAN.value & 0xFF); + instructionThrowTable.set(Opcode.SPUT_BYTE.value & 0xFF); + instructionThrowTable.set(Opcode.SPUT_CHAR.value & 0xFF); + instructionThrowTable.set(Opcode.SPUT_SHORT.value & 0xFF); + instructionThrowTable.set(Opcode.SPUT_WIDE.value & 0xFF); + instructionThrowTable.set(Opcode.SPUT_OBJECT.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_VIRTUAL.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_VIRTUAL_RANGE.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_SUPER.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_SUPER_RANGE.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_DIRECT.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_DIRECT_RANGE.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_STATIC.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_STATIC_RANGE.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_INTERFACE.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_INTERFACE_RANGE.value & 0xFF); + instructionThrowTable.set(Opcode.DIV_INT.value & 0xFF); + instructionThrowTable.set(Opcode.REM_INT.value & 0xFF); + instructionThrowTable.set(Opcode.DIV_LONG.value & 0xFF); + instructionThrowTable.set(Opcode.REM_LONG.value & 0xFF); + instructionThrowTable.set(Opcode.DIV_INT_2ADDR.value & 0xFF); + instructionThrowTable.set(Opcode.REM_INT_2ADDR.value & 0xFF); + instructionThrowTable.set(Opcode.DIV_LONG_2ADDR.value & 0xFF); + instructionThrowTable.set(Opcode.REM_LONG_2ADDR.value & 0xFF); + instructionThrowTable.set(Opcode.DIV_INT_LIT16.value & 0xFF); + instructionThrowTable.set(Opcode.REM_INT_LIT16.value & 0xFF); + instructionThrowTable.set(Opcode.DIV_INT_LIT8.value & 0xFF); + instructionThrowTable.set(Opcode.REM_INT_LIT8.value & 0xFF); + instructionThrowTable.set(Opcode.THROW.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_WIDE_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.IGET_OBJECT_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_WIDE_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.IPUT_OBJECT_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_VIRTUAL_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_VIRTUAL_RANGE_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_SUPER_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_SUPER_RANGE_QUICK.value & 0xFF); + instructionThrowTable.set(Opcode.INVOKE_DIRECT_EMPTY.value & 0xFF); + } + + public DeodexUtil(Deodexerant deodexerant) { + this.deodexerant = deodexerant; + deodexerant.dexFile.disableInterning(); + } + + private List makeInsnList(final CodeItem codeItem) { + + final ArrayList insns = new ArrayList(); + final HashMap insnsMap = new HashMap(); + + byte[] encodedInstructions = codeItem.getEncodedInstructions().clone(); + + InstructionIterator.IterateInstructions(codeItem.getDexFile(), encodedInstructions, + new InstructionIterator.ProcessInstructionDelegate() { + public void ProcessInstruction(int index, Instruction instruction) { + insn i = new insn(codeItem, instruction, insnsMap, index/2); + insns.add(i); + insnsMap.put(index/2, i); + } + }); + + if (codeItem.getTries() != null) { + for (CodeItem.TryItem tryItem: codeItem.getTries()) { + insn[] handlers; + + if (tryItem.encodedCatchHandler.catchAllHandlerAddress != -1) { + handlers = new insn[tryItem.encodedCatchHandler.handlers.length + 1]; + handlers[handlers.length - 1] = insnsMap.get(tryItem.encodedCatchHandler.catchAllHandlerAddress); + } else { + handlers = new insn[tryItem.encodedCatchHandler.handlers.length]; + } + + for (int i=0; i deodexerizeCode(CodeItem codeItem) { + List insns = makeInsnList(codeItem); + + byte[] encodedInstructions = codeItem.getEncodedInstructions().clone(); + + boolean didSomething; + boolean somethingLeftToDo; + do { + int offset = 0; + didSomething = false; + somethingLeftToDo = false; + for (insn i: insns) { + if (i.instruction.opcode.odexOnly && !i.fixed) { + if (deodexInstruction(i, offset, encodedInstructions)) { + didSomething = true; + i.fixed = true; + } else { + somethingLeftToDo = true; + } + } + + offset += i.instruction.getSize()/2; + } + } while (didSomething && somethingLeftToDo); + if (somethingLeftToDo) { + System.err.println("warning: could not fully deodex the method " + + codeItem.getParent().method.getContainingClass().getTypeDescriptor() + "->" + + codeItem.getParent().method.getMethodName() + + codeItem.getParent().method.getPrototype().getPrototypeString()); + } + + List instructions = new ArrayList(insns.size()); + for (insn i: insns) { + if (i.instruction.opcode.odexOnly) { + //TODO: could probably get rid of insn.fixed + assert i.fixed; + assert i.fixedInstruction != null; + instructions.add(i.fixedInstruction); + } else { + instructions.add(i.instruction); + } + } + return instructions; + } + + private boolean deodexInstruction(insn i, int offset, byte[] encodedInstructions) { + switch (i.instruction.opcode) { + case INVOKE_EXECUTE_INLINE: + { + int inlineMethodIndex = ((Instruction35ms)i.instruction).getMethodIndex(); + Deodexerant.InlineMethod inlineMethod = + deodexerant.lookupInlineMethod(inlineMethodIndex); + if (inlineMethod == null) { + throw new RuntimeException("Could not find the inline method with index " + inlineMethodIndex); + } + assert inlineMethod != null; + assert inlineMethod.methodIdItem != null; + + Opcode opcode = null; + switch (inlineMethod.methodType) { + case Direct: + opcode = Opcode.INVOKE_DIRECT; + break; + case Static: + opcode = Opcode.INVOKE_STATIC; + break; + case Virtual: + opcode = Opcode.INVOKE_VIRTUAL; + break; + } + + i.fixedInstruction = new Instruction35msf(opcode, (Instruction35ms)i.instruction, + inlineMethod.methodIdItem); + + + insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); + assert nextInstruction != null; + if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { + nextInstruction.registerReferenceType = inlineMethod.methodIdItem.getPrototype().getReturnType(); + } + + return true; + } + case INVOKE_DIRECT_EMPTY: + { + i.fixedInstruction = new Instruction35sf((Instruction35s)i.instruction); + return true; + } + case IGET_QUICK: + { + Instruction22cs ins = (Instruction22cs)i.instruction; + int registerNum = ins.getRegisterB(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what field is being accessed. What will really happen is that when it tries to access the field, it + //will obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction2csn, which doesn't have any method/field info associated with + //it, and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction22csn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); + if (field == null) { + throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + + " for class: " + type.getTypeDescriptor()); + } + String fieldType = field.getFieldType().getTypeDescriptor(); + + Opcode opcode; + switch (fieldType.charAt(0)) { + case 'Z': + opcode = Opcode.IGET_BOOLEAN; + break; + case 'B': + opcode = Opcode.IGET_BYTE; + break; + case 'S': + opcode = Opcode.IGET_SHORT; + break; + case 'C': + opcode = Opcode.IGET_CHAR; + break; + case 'I': + case 'F': + opcode = Opcode.IGET; + break; + default: + throw new RuntimeException("Unexpected field type for iget-quick opcode: " + fieldType); + } + + i.fixedInstruction = new Instruction22csf(opcode, (Instruction22cs)i.instruction, field); + + return true; + } + case IGET_WIDE_QUICK: + { + Instruction22cs ins = (Instruction22cs)i.instruction; + int registerNum = ins.getRegisterB(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what field is being accessed. What will really happen is that when it tries to access the field, it + //will obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction2csn, which doesn't have any method/field info associated with + //it, and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction22csn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); + if (field == null) { + throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + + " for class: " + type.getTypeDescriptor()); + } + + assert field.getFieldType().getTypeDescriptor().charAt(0) == 'J' || + field.getFieldType().getTypeDescriptor().charAt(0) == 'D'; + + i.fixedInstruction = new Instruction22csf(Opcode.IGET_WIDE, (Instruction22cs)i.instruction, field); + return true; + } + case IGET_OBJECT_QUICK: + { + Instruction22cs ins = (Instruction22cs)i.instruction; + int registerNum = ins.getRegisterB(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what field is being accessed. What will really happen is that when it tries to access the field, it + //will obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction2csn, which doesn't have any method/field info associated with + //it, and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction22csn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); + if (field == null) { + throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + + " for class: " + type.getTypeDescriptor()); + } + + assert field.getFieldType().getTypeDescriptor().charAt(0) == 'L' || + field.getFieldType().getTypeDescriptor().charAt(0) == '['; + + i.fixedInstruction = new Instruction22csf(Opcode.IGET_OBJECT, (Instruction22cs)i.instruction, field); + + i.updateRegisterReferenceType(field.getFieldType()); + return true; + } + case IPUT_QUICK: + { + Instruction22cs ins = (Instruction22cs)i.instruction; + int registerNum = ins.getRegisterB(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what field is being accessed. What will really happen is that when it tries to access the field, it + //will obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction2csn, which doesn't have any method/field info associated with + //it, and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction22csn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); + if (field == null) { + throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + + " for class: " + type.getTypeDescriptor()); + } + String fieldType = field.getFieldType().getTypeDescriptor(); + + Opcode opcode; + switch (fieldType.charAt(0)) { + case 'Z': + opcode = Opcode.IPUT_BOOLEAN; + break; + case 'B': + opcode = Opcode.IPUT_BYTE; + break; + case 'S': + opcode = Opcode.IPUT_SHORT; + break; + case 'C': + opcode = Opcode.IPUT_CHAR; + break; + case 'I': + case 'F': + opcode = Opcode.IPUT; + break; + default: + throw new RuntimeException("Unexpected field type for iget-quick opcode: " + fieldType); + } + + i.fixedInstruction = new Instruction22csf(opcode, (Instruction22cs)i.instruction, field); + + return true; + } + case IPUT_WIDE_QUICK: + { + Instruction22cs ins = (Instruction22cs)i.instruction; + int registerNum = ins.getRegisterB(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what field is being accessed. What will really happen is that when it tries to access the field, it + //will obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction2csn, which doesn't have any method/field info associated with + //it, and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction22csn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); + if (field == null) { + throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + + " for class: " + type.getTypeDescriptor()); + } + + assert field.getFieldType().getTypeDescriptor().charAt(0) == 'J' || + field.getFieldType().getTypeDescriptor().charAt(0) == 'D'; + + i.fixedInstruction = new Instruction22csf(Opcode.IPUT_WIDE, (Instruction22cs)i.instruction, field); + + return true; + } + case IPUT_OBJECT_QUICK: + { + Instruction22cs ins = (Instruction22cs)i.instruction; + int registerNum = ins.getRegisterB(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what field is being accessed. What will really happen is that when it tries to access the field, it + //will obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction2csn, which doesn't have any method/field info associated with + //it, and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction22csn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); + if (field == null) { + throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + + " for class: " + type.getTypeDescriptor()); + } + + assert field.getFieldType().getTypeDescriptor().charAt(0) == 'L' || + field.getFieldType().getTypeDescriptor().charAt(0) == '['; + + i.fixedInstruction = new Instruction22csf(Opcode.IPUT_OBJECT, (Instruction22cs)i.instruction, field); + + return true; + } + case INVOKE_VIRTUAL_QUICK: + { + Instruction35ms ins = ((Instruction35ms)i.instruction); + int registerNum = ins.getRegisterD(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what method to call. What will really happen is that when it tries to call the method, it will + //obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction3msn, which doesn't have any method info associated with it, + //and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction35msn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), false); + if (method == null) { + throw new RuntimeException("Could not find the virtual method with vtable index " + + ins.getMethodIndex() + " for class: " + type.getTypeDescriptor()); + } + + i.fixedInstruction = new Instruction35msf(Opcode.INVOKE_VIRTUAL, (Instruction35ms)i.instruction, + method); + + insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); + assert nextInstruction != null; + if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { + nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); + } + return true; + } + case INVOKE_VIRTUAL_RANGE_QUICK: + { + Instruction3rms ins = ((Instruction3rms)i.instruction); + int registerNum = ins.getStartRegister(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what method to call. What will really happen is that when it tries to call the method, it will + //obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction3msn, which doesn't have any method info associated with it, + //and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction35msn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), false); + if (method == null) { + throw new RuntimeException("Could not find the virtual method with vtable index " + + ins.getMethodIndex() + " for class: " + type.getTypeDescriptor()); + } + + i.fixedInstruction = new Instruction3rmsf(Opcode.INVOKE_VIRTUAL_RANGE, (Instruction3rms)i.instruction, + method); + + insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); + assert nextInstruction != null; + if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { + nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); + } + return true; + } + case INVOKE_SUPER_QUICK: + { + Instruction35ms ins = ((Instruction35ms)i.instruction); + int registerNum = ins.getRegisterD(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what method to call. What will really happen is that when it tries to call the method, it will + //obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction3msn, which doesn't have any method info associated with it, + //and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction35msn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), true); + if (method == null) { + throw new RuntimeException("Could not find the super method with vtable index " + + ins.getMethodIndex() + " for class: " + type.getTypeDescriptor()); + } + + i.fixedInstruction = new Instruction35msf(Opcode.INVOKE_SUPER, (Instruction35ms)i.instruction, + method); + + insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); + assert nextInstruction != null; + if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { + nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); + } + return true; + } + case INVOKE_SUPER_RANGE_QUICK: + { + Instruction3rms ins = ((Instruction3rms)i.instruction); + int registerNum = ins.getStartRegister(); + + RegisterType regType = i.registerMap[registerNum]; + + assert regType != RegisterType.NonReference && regType != RegisterType.Conflicted; + + //if the register type is Null, we can't determine the type of the register, and so we can't determine + //what method to call. What will really happen is that when it tries to call the method, it will + //obviously throw a NPE. We can get this same effect by replacing this opcode with a call to + //a method on java.lang.Object. + //We actually just create an Instruction3msn, which doesn't have any method info associated with it, + //and let the caller choose which "default" method to call in this case + if (regType == RegisterType.Null) { + i.fixedInstruction = new Instruction35msn(registerNum); + return true; + } + + if (regType != RegisterType.Reference) { + return false; + } + + TypeIdItem type = i.registerTypes[registerNum]; + if (type == null) { + return false; + } + + MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), true); + if (method == null) { + throw new RuntimeException("Could not find the super method with vtable index " + + ins.getMethodIndex() + " for class: " + type.getTypeDescriptor()); + } + + i.fixedInstruction = new Instruction3rmsf(Opcode.INVOKE_SUPER_RANGE, (Instruction3rms)i.instruction, + method); + + insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); + assert nextInstruction != null; + if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { + nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); + } + return true; + } + default: + throw new RuntimeException("Unexpected opcode " + i.instruction.opcode); + } + } + + public enum RegisterType { + Unknown, + Null, + NonReference, + Reference, + Conflicted; + + //TODO: make a table lookup for this + public static RegisterType mergeRegisterTypes(RegisterType type1, RegisterType type2) { + if (type1 == type2) { + return type1; + } + if (type1 == Conflicted || type2 == Conflicted) { + return Conflicted; + } + + if (type1 == Unknown) { + return type2; + } + + if (type2 == Unknown) { + return type1; + } + + if (type1 == Null) { + if (type2 == Reference || type2 == NonReference) { + return type2; + } + } + if (type2 == Null) { + if (type1 == Reference || type1 == NonReference) { + return type1; + } + } + + if ((type1 == Reference && type2 == NonReference) || (type1 == NonReference && type2 == Reference)) { + return Conflicted; + } + + assert false; + return null; + } + } + + public class insn { + /** + * The CodeItem that this instruction is a part of + */ + public final CodeItem codeItem; + /** + * The actual instruction + */ + public final Instruction instruction; + /** + * The offset in the instruction stream, in 2-byte instruction blocks + */ + public final int offset; + /** + * True if this instruction can throw an exception + */ + public final boolean canThrow; + //TODO: ugh, boxed Integers. need to find/write a primitive integer hash map + /** + * maps an instruction stream offset to an insn + */ + public final HashMap insnsMap; + + /** + * Instructions that can execution could pass on to next + */ + public LinkedList successors = new LinkedList(); + + /** + * If this instruction is in a try block, these are the first instructions for each + * exception handler + */ + public insn[] exceptionHandlers = null; + + /** + * true if this instruction stores a value in a register + */ + public boolean setsRegister = false; + /** + * true if this instruction sets a wide register. In this case, registerNum is the first of the + * 2 registers + */ + public boolean setsWideRegister = false; + /** + * If setsRegister is true, this is the instruction that is modified + */ + public int registerNum; + /** + * If setsRegister is true, this is the register type of register that is modified + */ + public RegisterType registerType; + /** + * if setsRegister is true, and the register type is a reference, this is the + * reference type of the register, or null if not known yet. + */ + public TypeIdItem registerReferenceType; + + /** + * Stores a "fake" fixed instruction, which is included in the instruction list that deodexerizeCode produces + */ + public Instruction fixedInstruction; + + + /** + * Whether this instruction can be the first instruction to successfully execute. This could be the first + * instruction in the method, or if that instruction is covered by a try block, then the first instruction + * in any of the exception handlers. Or if they are covered by try blocks... you get the idea + */ + public boolean firstInstruction = false; + /** + * If this instruction has been visited in the course of determining the type of a register + */ + public boolean visited = false; + /** + * If this is an odex instruction, and has been fixed. + */ + public boolean fixed = false; + + public final RegisterType[] registerMap; + public final TypeIdItem[] registerTypes; + + public insn(CodeItem codeItem, Instruction instruction, HashMap insnsMap, int offset) { + this.codeItem = codeItem; + this.instruction = instruction; + this.offset = offset; + this.canThrow = DeodexUtil.instructionThrowTable.get(instruction.opcode.value & 0xFF); + this.insnsMap = insnsMap; + + registerMap = new RegisterType[codeItem.getRegisterCount()]; + registerTypes = new TypeIdItem[codeItem.getRegisterCount()]; + + for (int i=0; i iterator = + packedSwitchData.getTargets(); + while (iterator.hasNext()) { + PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next(); + addSuccessor(getInstructionAtOffset(offset + target.target)); + } + break; + } + case SPARSE_SWITCH: + { + insn sparseSwitchDataInsn = + getInstructionAtOffset(offset + ((OffsetInstruction)instruction).getOffset()); + assert sparseSwitchDataInsn.instruction instanceof SparseSwitchDataPseudoInstruction; + SparseSwitchDataPseudoInstruction sparseSwitchData = + (SparseSwitchDataPseudoInstruction)sparseSwitchDataInsn.instruction; + Iterator iterator = + sparseSwitchData.getTargets(); + while (iterator.hasNext()) { + SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next(); + addSuccessor(getInstructionAtOffset(offset + target.target)); + } + break; + } + case MOVE_WIDE: + case MOVE_WIDE_FROM16: + case MOVE_WIDE_16: + case NEG_LONG: + case NOT_LONG: + case NEG_DOUBLE: + case INT_TO_LONG: + case INT_TO_DOUBLE: + case LONG_TO_DOUBLE: + case FLOAT_TO_LONG: + case FLOAT_TO_DOUBLE: + case DOUBLE_TO_LONG: + case ADD_LONG: + case SUB_LONG: + case MUL_LONG: + case DIV_LONG: + case REM_LONG: + case AND_LONG: + case OR_LONG: + case XOR_LONG: + case SHL_LONG: + case SHR_LONG: + case USHR_LONG: + case ADD_DOUBLE: + case SUB_DOUBLE: + case MUL_DOUBLE: + case DIV_DOUBLE: + case REM_DOUBLE: + case MOVE_RESULT_WIDE: + case AGET_WIDE: + case IGET_WIDE: + case SGET_WIDE: + case IGET_WIDE_QUICK: + { + setsWideRegister = true; + //fall through + } + case MOVE: + case MOVE_FROM16: + case MOVE_16: + case ARRAY_LENGTH: + case NEG_INT: + case NOT_INT: + case NEG_FLOAT: + case INT_TO_FLOAT: + case LONG_TO_INT: + case LONG_TO_FLOAT: + case FLOAT_TO_INT: + case DOUBLE_TO_INT: + case DOUBLE_TO_FLOAT: + case INT_TO_BYTE: + case INT_TO_CHAR: + case INT_TO_SHORT: + case ADD_INT: + case SUB_INT: + case MUL_INT: + case DIV_INT: + case REM_INT: + case AND_INT: + case OR_INT: + case XOR_INT: + case SHL_INT: + case SHR_INT: + case USHR_INT: + case ADD_FLOAT: + case SUB_FLOAT: + case MUL_FLOAT: + case DIV_FLOAT: + case REM_FLOAT: + case ADD_INT_LIT16: + case RSUB_INT: + case MUL_INT_LIT16: + case DIV_INT_LIT16: + case REM_INT_LIT16: + case AND_INT_LIT16: + case OR_INT_LIT16: + case XOR_INT_LIT16: + case ADD_INT_LIT8: + case RSUB_INT_LIT8: + case MUL_INT_LIT8: + case DIV_INT_LIT8: + case REM_INT_LIT8: + case AND_INT_LIT8: + case OR_INT_LIT8: + case XOR_INT_LIT8: + case SHL_INT_LIT8: + case SHR_INT_LIT8: + case USHR_INT_LIT8: + case MOVE_RESULT: + case CMPL_FLOAT: + case CMPG_FLOAT: + case CMPL_DOUBLE: + case CMPG_DOUBLE: + case CMP_LONG: + case AGET: + case AGET_BOOLEAN: + case AGET_BYTE: + case AGET_CHAR: + case AGET_SHORT: + case IGET: + case IGET_BOOLEAN: + case IGET_BYTE: + case IGET_CHAR: + case IGET_SHORT: + case SGET: + case SGET_BOOLEAN: + case SGET_BYTE: + case SGET_CHAR: + case SGET_SHORT: + case IGET_QUICK: + { + setsRegister = true; + registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); + registerType = RegisterType.NonReference; + break; + } + case MOVE_OBJECT: + case MOVE_OBJECT_FROM16: + case MOVE_OBJECT_16: + case AGET_OBJECT: + case IGET_OBJECT_QUICK: + { + setsRegister = true; + registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); + registerType = RegisterType.Reference; + break; + } + case MOVE_RESULT_OBJECT: + { + setsRegister = true; + if (previousInsn == null) { + throw new RuntimeException("This move-result-object instruction does not have an invoke" + + " instruction immediately prior to it"); + } + registerNum = ((Instruction11x)instruction).getRegisterA(); + registerType = RegisterType.Reference; + registerReferenceType = getReturnType(previousInsn.instruction); + break; + } + case MOVE_EXCEPTION: + { + setsRegister = true; + registerNum = ((Instruction11x)instruction).getRegisterA(); + registerType = RegisterType.Reference; + //typically, there will only be a single exception type for a particular handler block, so optimize + //the array size for that case, but support the case of multiple exception types as well + List exceptionTypes = new ArrayList(1); + for (CodeItem.TryItem tryItem: codeItem.getTries()) { + if (tryItem.encodedCatchHandler.catchAllHandlerAddress == this.offset) { + //if this is a catch all handler, the only possible type is Ljava/lang/Throwable; + registerReferenceType = TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(), + "Ljava/lang/Throwable;"); + + //it's possible that Ljava/lang/Throwable; hasn't be interned into the dex file. since + //we've turned off interning for the current dex file, we will just get a null back. + //This "shouldn't" be a problem, because if the type hasn't been interned, it's safe to + //say that there were no method/field accesses for that type, so we won't need to know + //the specific type of this register. + + break; + } + + for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) { + if (handler.handlerAddress == this.offset) { + exceptionTypes.add(handler.exceptionType); + } + } + } + if (registerReferenceType == null) { + //optimize for the case when there is only a single exception type + if (exceptionTypes.size() == 1) { + registerReferenceType = exceptionTypes.get(0); + } else { + registerReferenceType = findCommonSuperclass(exceptionTypes); + } + } + break; + } + case CONST_WIDE_16: + case CONST_WIDE_32: + case CONST_WIDE: + case CONST_WIDE_HIGH16: + { + setsRegister = true; + registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); + registerType = RegisterType.NonReference; + setsWideRegister = true; + break; + } + case CONST_4: + case CONST_16: + case CONST: + case CONST_HIGH16: + { + setsRegister = true; + registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); + if (((LiteralInstruction)instruction).getLiteral() == 0) { + registerType = RegisterType.Null; + } else { + registerType = RegisterType.NonReference; + } + break; + } + case CONST_STRING: + { + setsRegister = true; + registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); + registerType = RegisterType.Reference; + registerReferenceType = TypeIdItem.getInternedTypeIdItem(this.codeItem.getDexFile(), + "Ljava/lang/String;"); + break; + } + case CONST_CLASS: + { + setsRegister = true; + registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); + registerType = RegisterType.Reference; + registerReferenceType = TypeIdItem.getInternedTypeIdItem(this.codeItem.getDexFile(), + "Ljava/lang/Class;"); + break; + } + case CHECK_CAST: + case NEW_INSTANCE: + case NEW_ARRAY: + { + setsRegister = true; + registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); + registerType = RegisterType.Reference; + registerReferenceType = (TypeIdItem)((InstructionWithReference)instruction).getReferencedItem(); + break; + } + case IGET_OBJECT: + case SGET_OBJECT: + { + setsRegister = true; + registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); + registerType = RegisterType.Reference; + registerReferenceType = ((FieldIdItem)((InstructionWithReference)instruction).getReferencedItem()) + .getFieldType(); + break; + } + } + + //if we got here, then we can assume that it's possible for execution to continue on to the next + //instruction. Otherwise, we would have returned from within the switch statement + addSuccessor(getInstructionAtOffset(offset + instruction.getSize()/2)); + } + + private TypeIdItem findCommonSuperclass(TypeIdItem item1, TypeIdItem item2) { + if (item1 == item2) { + return item1; + } + if (item1 == null) { + return item2; + } + if (item2 == null) { + return item1; + } + + String superclass = + deodexerant.lookupCommonSuperclass(item1.getTypeDescriptor(), item2.getTypeDescriptor()); + + TypeIdItem superType = TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(), superclass); + //if the class isn't interned, let's see if we can find a superclass that is interned. This should be safe + //because there should be no fields or methods specific to this type being referenced.. otherwise it would + //already be interned + //TODO: array types need to be handled correctly + while (superType == null && superclass != null) { + superclass = deodexerant.lookupSuperclass(superclass); + if (superclass != null) { + superType = TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(), superclass); + } + } + //we might not find anything. if so, just return null. This should be ok, due to the same reasoning as + //above + return superType; + } + + private TypeIdItem findCommonSuperclass(List exceptionTypes) { + assert exceptionTypes.size() > 1; + + String superclass = exceptionTypes.get(0).getTypeDescriptor(); + + for (int i=1; i cachedVirtualMethods = new HashMap(); + public MethodIdItem lookupVirtualMethod(TypeIdItem type, int methodIndex, boolean superLookup) { + int hash = type.hashCode() + methodIndex * 31; + + connectIfNeeded(); + + String commandChar = superLookup?"S":"V"; + String response = sendCommand(commandChar + " " + type.getTypeDescriptor() + " " + methodIndex); + + int colon = response.indexOf(':'); + if (colon == -1) { + throw new RuntimeException("Invalid response from deodexerant"); + } + + String methodDescriptor = response.substring(colon+2); + + return parseAndLookupMethod(methodDescriptor); + } + + public String lookupSuperclass(String typeDescriptor) { + connectIfNeeded(); + + String response = sendCommand("P " + typeDescriptor); + int colon = response.indexOf(':'); + if (colon == -1) { + throw new RuntimeException("Invalid response from deodexerant"); + } + + String type = response.substring(colon+2); + if (type.length() == 0) { + return null; + } + return type; + } + + public String lookupCommonSuperclass(String typeDescriptor1, String typeDescriptor2) { + connectIfNeeded(); + + String response = sendCommand("C " + typeDescriptor1 + " " + typeDescriptor2); + int colon = response.indexOf(':'); + if (colon == -1) { + return null; + } + + return response.substring(colon+2); + } + + private String sendCommand(String cmd) { + try { + out.println(cmd); + out.flush(); + String response = in.readLine(); + if (response.startsWith("err")) { + String error = response.substring(5); + throw new RuntimeException(error); + } + return response; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private void connectIfNeeded() { + try { + if (socket != null) { + return; + } + + socket = new Socket(host, port); + + out = new PrintWriter(socket.getOutputStream(), true); + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private static final Pattern methodPattern = Pattern.compile("(\\[*(?:L[^;]+;)|[ZBSCIJFD])->([^(]+)\\(([^)]*)\\)(.+)"); + private MethodIdItem parseAndLookupMethod(String method) { + //expecting a string like Lsome/class;->someMethod(IIII)Lreturn/type; + + Matcher m = methodPattern.matcher(method); + if (!m.matches()) { + throw new RuntimeException("invalid method string: " + method); + } + + String clazz = m.group(1); + String methodName = m.group(2); + String params = m.group(3); + String ret = m.group(4); + + LinkedList paramList = new LinkedList(); + + for (int i=0; i 0) { + paramListItem = TypeListItem.getInternedTypeListItem(dexFile, paramList); + if (paramListItem == null) { + throw new RuntimeException("Could not find type list item in dex file"); + } + } + + ProtoIdItem protoItem = ProtoIdItem.getInternedProtoIdItem(dexFile, retType, paramListItem); + if (protoItem == null) { + throw new RuntimeException("Could not find prototype item in dex file"); + } + + StringIdItem methodNameItem = StringIdItem.getInternedStringIdItem(dexFile, methodName); + if (methodNameItem == null) { + throw new RuntimeException("Could not find method name item in dex file"); + } + + MethodIdItem methodIdItem; + + do { + methodIdItem = MethodIdItem.getInternedMethodIdItem(dexFile, classType, protoItem, methodNameItem); + if (methodIdItem != null) { + return methodIdItem; + } + + String superclassDescriptor = lookupSuperclass(classType.getTypeDescriptor()); + classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); + + while (classType == null && superclassDescriptor != null) { + superclassDescriptor = lookupSuperclass(superclassDescriptor); + classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); + } + + } while (classType != null); + throw new RuntimeException("Could not find method in dex file"); + } + + private static final Pattern fieldPattern = Pattern.compile("(\\[*L[^;]+;)->([^:]+):(.+)"); + private FieldIdItem parseAndLookupField(String field) { + //expecting a string like Lsome/class;->someField:Lfield/type; + + Matcher m = fieldPattern.matcher(field); + if (!m.matches()) { + throw new RuntimeException("invalid field string: " + field); + } + + String clazz = m.group(1); + String fieldName = m.group(2); + String fieldType = m.group(3); + + TypeIdItem classType = TypeIdItem.getInternedTypeIdItem(dexFile, clazz); + StringIdItem fieldNameItem = StringIdItem.getInternedStringIdItem(dexFile, fieldName); + TypeIdItem fieldTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, fieldType); + + FieldIdItem fieldIdItem; + + do { + fieldIdItem = FieldIdItem.getInternedFieldIdItem(dexFile, classType, fieldTypeItem, fieldNameItem); + if (fieldIdItem != null) { + return fieldIdItem; + } + + String superclassDescriptor = lookupSuperclass(classType.getTypeDescriptor()); + classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); + + while (classType == null && superclassDescriptor != null) { + superclassDescriptor = lookupSuperclass(superclassDescriptor); + classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); + } + + } while (classType != null); + throw new RuntimeException("Could not find field in dex file"); + } + + public enum InlineMethodType { + Virtual, + Direct, + Static + } + + public static class InlineMethod { + public final MethodIdItem methodIdItem; + public final InlineMethodType methodType; + public InlineMethod(MethodIdItem methodIdItem, InlineMethodType methodType) { + this.methodIdItem = methodIdItem; + this.methodType = methodType; + } + } + + private static TypeIdItem getType(DexFile dexFile, String typeDescriptor) { + TypeIdItem type = TypeIdItem.getInternedTypeIdItem(dexFile, typeDescriptor); + if (type == null) { + throw new RuntimeException("Could not find type \"" + typeDescriptor + "\" in dex file"); + } + return type; + } +}