diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/BlankMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/BlankMethodItem.java index 18d7b0da..f173a515 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/BlankMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/BlankMethodItem.java @@ -42,7 +42,6 @@ public class BlankMethodItem extends MethodItem { } } - public int getSortOrder() { return Integer.MAX_VALUE; } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msn.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentedOutMethodItem.java similarity index 60% rename from dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msn.java rename to baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentedOutMethodItem.java index 71173294..1e362108 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35msn.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentedOutMethodItem.java @@ -26,32 +26,29 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.jf.dexlib.Code.Format; +package org.jf.baksmali.Adaptors; -import org.jf.dexlib.Code.Opcode; -import org.jf.dexlib.Code.Instruction; +import org.antlr.stringtemplate.StringTemplate; +import org.antlr.stringtemplate.StringTemplateGroup; -/** - * 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 { +public class CommentedOutMethodItem extends MethodItem { + private final StringTemplateGroup stg; + private final MethodItem commentedOutMethodItem; - /** - * 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 CommentedOutMethodItem(StringTemplateGroup stg, MethodItem commentedOutMethodItem) { + super(commentedOutMethodItem.getOffset()); + this.stg = stg; + this.commentedOutMethodItem = commentedOutMethodItem; } + public int getSortOrder() { + return commentedOutMethodItem.getSortOrder() + 1; + } - public Format getFormat() { - return Format.Format35msn; + @Override + public String toString() { + StringTemplate template = stg.getInstanceOf("CommentedOutMethodItem"); + template.setAttribute("MethodItem", commentedOutMethodItem); + return template.toString(); } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/EndTryLabelMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/EndTryLabelMethodItem.java index 2298fdde..403c4832 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/EndTryLabelMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/EndTryLabelMethodItem.java @@ -34,7 +34,7 @@ public class EndTryLabelMethodItem extends LabelMethodItem { private int labelOffset; public EndTryLabelMethodItem(int offset, StringTemplateGroup stg, int labelOffset) { - super(offset, stg, "try_end_"); + super(offset, stg, "try_end_", false); this.labelOffset = labelOffset; } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22csnMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedNullReferenceMethodItem.java similarity index 83% rename from baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22csnMethodItem.java rename to baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedNullReferenceMethodItem.java index e5bacc74..aea5f7be 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction22csnMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/UnresolvedNullReferenceMethodItem.java @@ -28,18 +28,18 @@ package org.jf.baksmali.Adaptors.Format; -import org.jf.dexlib.Code.Format.Instruction22csn; +import org.jf.dexlib.Code.Format.UnresolvedNullReference; 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) { +public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodItem { + public UnresolvedNullReferenceMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, + UnresolvedNullReference instruction) { super(codeItem, offset, stg, instruction); } protected void setAttributes(StringTemplate template) { - template.setAttribute("Register", formatRegister(instruction.RegisterNum)); + template.setAttribute("Register", formatRegister(instruction.ObjectRegisterNum)); } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/LabelMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/LabelMethodItem.java index d9866e6c..be2f7ab5 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/LabelMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/LabelMethodItem.java @@ -34,17 +34,27 @@ import org.antlr.stringtemplate.StringTemplate; public class LabelMethodItem extends MethodItem { private final StringTemplateGroup stg; private final String labelPrefix; + private boolean isCommentedOut = false; - public LabelMethodItem(int offset, StringTemplateGroup stg, String labelPrefix) { + public LabelMethodItem(int offset, StringTemplateGroup stg, String labelPrefix, boolean isCommentedOut) { super(offset); this.stg = stg; this.labelPrefix = labelPrefix; + this.isCommentedOut = isCommentedOut; } public int getSortOrder() { return 0; } + public boolean isCommentedOut() { + return isCommentedOut; + } + + public void setCommentedOut(boolean isCommentedOut) { + this.isCommentedOut = isCommentedOut; + } + public int compareTo(MethodItem methodItem) { int result = super.compareTo(methodItem); @@ -71,6 +81,7 @@ public class LabelMethodItem extends MethodItem { @Override public String toString() { StringTemplate template = stg.getInstanceOf("Label"); + template.setAttribute("CommentedOut", this.isCommentedOut); template.setAttribute("Prefix", labelPrefix); template.setAttribute("HexOffset", getLabelOffset()); return template.toString(); 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 7b9b3ac5..7564825e 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java @@ -143,7 +143,7 @@ public class MethodDefinition { MethodItemList methodItemList = new MethodItemList(dexFile, stg, codeItem); methodItemList.generateMethodItemList(); - methodItems.addAll(methodItemList.labels); + methodItems.addAll(methodItemList.labels.values()); methodItems.addAll(methodItemList.instructions); methodItems.addAll(methodItemList.blanks); methodItems.addAll(methodItemList.catches); @@ -159,7 +159,7 @@ public class MethodDefinition { private final StringTemplateGroup stg; private final CodeItem codeItem; - public HashSet labels = new HashSet(); + public HashMap labels = new HashMap(); public List instructions = new ArrayList(); public List blanks = new ArrayList(); public List catches = new ArrayList(); @@ -197,7 +197,7 @@ public class MethodDefinition { offset = 0; for (Instruction instruction: instructions) { - addMethodItemsForInstruction(offset, instruction); + addMethodItemsForInstruction(offset, instruction, false, null); blanks.add(new BlankMethodItem(stg, offset)); offset += instruction.getSize()/2; @@ -237,7 +237,7 @@ public class MethodDefinition { new InstructionIterator.ProcessInstructionDelegate() { public void ProcessInstruction(int index, Instruction instruction) { int offset = index/2; - addMethodItemsForInstruction(offset, instruction); + addMethodItemsForInstruction(offset, instruction, false, null); blanks.add(new BlankMethodItem(stg, offset)); } }); @@ -250,136 +250,213 @@ public class MethodDefinition { addDebugInfo(); } - private void addMethodItemsForInstruction(int offset, Instruction instruction) { + private void addInstructionMethodItem(InstructionFormatMethodItem methodItem, boolean commentedOut, + String comment) { + if (commentedOut) { + instructions.add(new CommentedOutMethodItem(stg, methodItem)); + } else { + instructions.add(methodItem); + } + } + + private void addLabelMethodItem(LabelMethodItem labelMethodItem) { + LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem); + if (internedLabelMethodItem != null) { + if (!labelMethodItem.isCommentedOut() && internedLabelMethodItem.isCommentedOut()) { + internedLabelMethodItem.setCommentedOut(false); + } + } else { + labels.put(labelMethodItem, labelMethodItem); + } + } + + private void addMethodItemsForInstruction(int offset, Instruction instruction, boolean commentedOut, + String comment) { switch (instruction.getFormat()) { case Format10t: - instructions.add(new Instruction10tMethodItem(codeItem, offset, stg,(Instruction10t)instruction)); - labels.add(new LabelMethodItem(offset + ((Instruction10t)instruction).getOffset(), stg, "goto_")); + addInstructionMethodItem( + new Instruction10tMethodItem(codeItem, offset, stg,(Instruction10t)instruction), + commentedOut, comment); + addLabelMethodItem(new LabelMethodItem(offset + ((Instruction10t)instruction).getOffset(), stg, + "goto_", commentedOut)); return; case Format10x: - instructions.add(new Instruction10xMethodItem(codeItem, offset, stg, (Instruction10x)instruction)); + addInstructionMethodItem( + new Instruction10xMethodItem(codeItem, offset, stg, (Instruction10x)instruction), + commentedOut, comment); return; case Format11n: - instructions.add(new Instruction11nMethodItem(codeItem, offset, stg, (Instruction11n)instruction)); + addInstructionMethodItem( + new Instruction11nMethodItem(codeItem, offset, stg, (Instruction11n)instruction), + commentedOut, comment); return; case Format11x: - instructions.add(new Instruction11xMethodItem(codeItem, offset, stg, (Instruction11x)instruction)); + addInstructionMethodItem( + new Instruction11xMethodItem(codeItem, offset, stg, (Instruction11x)instruction), + commentedOut, comment); return; case Format12x: - instructions.add(new Instruction12xMethodItem(codeItem, offset, stg, (Instruction12x)instruction)); + addInstructionMethodItem( + new Instruction12xMethodItem(codeItem, offset, stg, (Instruction12x)instruction), + commentedOut, comment); return; case Format20t: - instructions.add(new Instruction20tMethodItem(codeItem, offset, stg, (Instruction20t)instruction)); - labels.add(new LabelMethodItem(offset + ((Instruction20t)instruction).getOffset(), stg, "goto_")); + addInstructionMethodItem( + new Instruction20tMethodItem(codeItem, offset, stg, (Instruction20t)instruction), + commentedOut, comment); + addLabelMethodItem(new LabelMethodItem(offset + ((Instruction20t)instruction).getOffset(), stg, + "goto_", commentedOut)); return; case Format21c: - instructions.add(new Instruction21cMethodItem(codeItem, offset, stg, (Instruction21c)instruction)); + addInstructionMethodItem( + new Instruction21cMethodItem(codeItem, offset, stg, (Instruction21c)instruction), + commentedOut, comment); return; case Format21h: - instructions.add(new Instruction21hMethodItem(codeItem, offset, stg, (Instruction21h)instruction)); + addInstructionMethodItem( + new Instruction21hMethodItem(codeItem, offset, stg, (Instruction21h)instruction), + commentedOut, comment); return; case Format21s: - instructions.add(new Instruction21sMethodItem(codeItem, offset, stg, (Instruction21s)instruction)); + addInstructionMethodItem( + new Instruction21sMethodItem(codeItem, offset, stg, (Instruction21s)instruction), + commentedOut, comment); return; case Format21t: - instructions.add(new Instruction21tMethodItem(codeItem, offset, stg, (Instruction21t)instruction)); - labels.add(new LabelMethodItem(offset + ((Instruction21t)instruction).getOffset(), stg, "cond_")); + addInstructionMethodItem( + new Instruction21tMethodItem(codeItem, offset, stg, (Instruction21t)instruction), + commentedOut, comment); + addLabelMethodItem(new LabelMethodItem(offset + ((Instruction21t)instruction).getOffset(), stg, + "cond_", commentedOut)); return; case Format22b: - instructions.add(new Instruction22bMethodItem(codeItem, offset, stg, (Instruction22b)instruction)); + addInstructionMethodItem( + new Instruction22bMethodItem(codeItem, offset, stg, (Instruction22b)instruction), + commentedOut, comment); return; case Format22c: - instructions.add(new Instruction22cMethodItem(codeItem, offset, stg, (Instruction22c)instruction)); + addInstructionMethodItem( + new Instruction22cMethodItem(codeItem, offset, stg, (Instruction22c)instruction), + commentedOut, comment); return; case Format22cs: - instructions.add(new Instruction22csMethodItem(codeItem, offset, stg, - (Instruction22cs)instruction)); + addInstructionMethodItem( + new Instruction22csMethodItem(codeItem, offset, stg, (Instruction22cs)instruction), + commentedOut, comment); return; case Format22csf: - instructions.add(new Instruction22csfMethodItem(codeItem, offset, stg, - (Instruction22csf)instruction)); - return; - case Format22csn: - instructions.add(new Instruction22csnMethodItem(codeItem, offset, stg, - (Instruction22csn)instruction)); + addInstructionMethodItem( + new Instruction22csfMethodItem(codeItem, offset, stg, (Instruction22csf)instruction), + commentedOut, comment); return; case Format22s: - instructions.add(new Instruction22sMethodItem(codeItem, offset, stg, (Instruction22s)instruction)); + addInstructionMethodItem( + new Instruction22sMethodItem(codeItem, offset, stg, (Instruction22s)instruction), + commentedOut, comment); return; case Format22t: - instructions.add(new Instruction22tMethodItem(codeItem, offset, stg, (Instruction22t)instruction)); - labels.add(new LabelMethodItem(offset + ((Instruction22t)instruction).getOffset(), stg, "cond_")); + addInstructionMethodItem( + new Instruction22tMethodItem(codeItem, offset, stg, (Instruction22t)instruction), + commentedOut, comment); + addLabelMethodItem(new LabelMethodItem(offset + ((Instruction22t)instruction).getOffset(), stg, + "cond_", commentedOut)); return; case Format22x: - instructions.add(new Instruction22xMethodItem(codeItem, offset, stg, (Instruction22x)instruction)); + addInstructionMethodItem( + new Instruction22xMethodItem(codeItem, offset, stg, (Instruction22x)instruction), + commentedOut, comment); return; case Format23x: - instructions.add(new Instruction23xMethodItem(codeItem, offset, stg, (Instruction23x)instruction)); + addInstructionMethodItem( + new Instruction23xMethodItem(codeItem, offset, stg, (Instruction23x)instruction), + commentedOut, comment); return; case Format30t: - instructions.add(new Instruction30tMethodItem(codeItem, offset, stg, (Instruction30t)instruction)); - labels.add(new LabelMethodItem(offset + ((Instruction30t)instruction).getOffset(), stg, "goto_")); + addInstructionMethodItem( + new Instruction30tMethodItem(codeItem, offset, stg, (Instruction30t)instruction), + commentedOut, comment); + addLabelMethodItem(new LabelMethodItem(offset + ((Instruction30t)instruction).getOffset(), stg, + "goto_", commentedOut)); return; case Format31c: - instructions.add(new Instruction31cMethodItem(codeItem, offset, stg, (Instruction31c)instruction)); + addInstructionMethodItem( + new Instruction31cMethodItem(codeItem, offset, stg, (Instruction31c)instruction), + commentedOut, comment); return; case Format31i: - instructions.add(new Instruction31iMethodItem(codeItem, offset, stg, (Instruction31i)instruction)); + addInstructionMethodItem( + new Instruction31iMethodItem(codeItem, offset, stg, (Instruction31i)instruction), + commentedOut, comment); return; case Format31t: - instructions.add(new Instruction31tMethodItem(codeItem, offset, stg, (Instruction31t)instruction)); + addInstructionMethodItem( + new Instruction31tMethodItem(codeItem, offset, stg, (Instruction31t)instruction), + commentedOut, comment); if (instruction.opcode == Opcode.FILL_ARRAY_DATA) { - labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, - "array_")); + addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, + "array_", commentedOut)); } else if (instruction.opcode == Opcode.PACKED_SWITCH) { - labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, - "pswitch_data_")); + addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, + "pswitch_data_", commentedOut)); } else if (instruction.opcode == Opcode.SPARSE_SWITCH) { - labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, - "sswitch_data_")); + addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, + "sswitch_data_", commentedOut)); } return; case Format32x: - instructions.add(new Instruction32xMethodItem(codeItem, offset, stg, (Instruction32x)instruction)); + addInstructionMethodItem( + new Instruction32xMethodItem(codeItem, offset, stg, (Instruction32x)instruction), + commentedOut, comment); return; case Format35c: - instructions.add(new Instruction35cMethodItem(codeItem, offset, stg, (Instruction35c)instruction)); + addInstructionMethodItem( + new Instruction35cMethodItem(codeItem, offset, stg, (Instruction35c)instruction), + commentedOut, comment); return; case Format35s: - instructions.add(new Instruction35sMethodItem(codeItem, offset, stg, (Instruction35s)instruction)); + addInstructionMethodItem( + new Instruction35sMethodItem(codeItem, offset, stg, (Instruction35s)instruction), + commentedOut, comment); return; case Format35sf: - instructions.add(new Instruction35sfMethodItem(codeItem, offset, stg, - (Instruction35sf)instruction)); + addInstructionMethodItem( + new Instruction35sfMethodItem(codeItem, offset, stg, (Instruction35sf)instruction), + commentedOut, comment); return; case Format35ms: - instructions.add(new Instruction35msMethodItem(codeItem, offset, stg, - (Instruction35ms)instruction)); + addInstructionMethodItem( + new Instruction35msMethodItem(codeItem, offset, stg, (Instruction35ms)instruction), + commentedOut, comment); return; case Format35msf: - instructions.add(new Instruction35msfMethodItem(codeItem, offset, stg, - (Instruction35msf)instruction)); - return; - case Format35msn: - instructions.add(new Instruction35msnMethodItem(codeItem, offset, stg, - (Instruction35msn)instruction)); + addInstructionMethodItem( + new Instruction35msfMethodItem(codeItem, offset, stg, (Instruction35msf)instruction), + commentedOut, comment); return; case Format3rc: - instructions.add(new Instruction3rcMethodItem(codeItem, offset, stg, (Instruction3rc)instruction)); + addInstructionMethodItem( + new Instruction3rcMethodItem(codeItem, offset, stg, (Instruction3rc)instruction), + commentedOut, comment); return; case Format3rms: - instructions.add(new Instruction3rmsMethodItem(codeItem, offset, stg, - (Instruction3rms)instruction)); + addInstructionMethodItem( + new Instruction3rmsMethodItem(codeItem, offset, stg, (Instruction3rms)instruction), + commentedOut, comment); return; case Format3rmsf: - instructions.add(new Instruction3rmsfMethodItem(codeItem, offset, stg, - (Instruction3rmsf)instruction)); + addInstructionMethodItem( + new Instruction3rmsfMethodItem(codeItem, offset, stg, (Instruction3rmsf)instruction), + commentedOut, comment); return; case Format51l: - instructions.add(new Instruction51lMethodItem(codeItem, offset, stg, (Instruction51l)instruction)); + addInstructionMethodItem( + new Instruction51lMethodItem(codeItem, offset, stg, (Instruction51l)instruction), + commentedOut, comment); return; case ArrayData: - instructions.add(new ArrayDataMethodItem(codeItem, offset, stg, (ArrayDataPseudoInstruction)instruction)); + addInstructionMethodItem( + new ArrayDataMethodItem(codeItem, offset, stg, (ArrayDataPseudoInstruction)instruction), + commentedOut, comment); return; case PackedSwitchData: { @@ -389,14 +466,16 @@ public class MethodDefinition { PackedSwitchDataPseudoInstruction packedSwitchInstruction = (PackedSwitchDataPseudoInstruction)instruction; - instructions.add(new PackedSwitchMethodItem(codeItem, offset, stg, - packedSwitchInstruction, baseAddress)); + addInstructionMethodItem( + new PackedSwitchMethodItem(codeItem, offset, stg, packedSwitchInstruction, baseAddress), + commentedOut, comment); Iterator iterator = packedSwitchInstruction.getTargets(); while (iterator.hasNext()) { PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next(); - labels.add(new LabelMethodItem(baseAddress + target.target, stg, "pswitch_")); + addLabelMethodItem(new LabelMethodItem(baseAddress + target.target, stg, "pswitch_", + commentedOut)); } } return; @@ -409,16 +488,32 @@ public class MethodDefinition { SparseSwitchDataPseudoInstruction sparseSwitchInstruction = (SparseSwitchDataPseudoInstruction)instruction; - instructions.add(new SparseSwitchMethodItem(codeItem, offset, stg, - sparseSwitchInstruction, baseAddress)); + addInstructionMethodItem( + new SparseSwitchMethodItem(codeItem, offset, stg, sparseSwitchInstruction, baseAddress), + commentedOut, comment); Iterator iterator = sparseSwitchInstruction.getTargets(); while (iterator.hasNext()) { SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next(); - labels.add(new LabelMethodItem(baseAddress + target.target, stg, "sswitch_")); + addLabelMethodItem(new LabelMethodItem(baseAddress + target.target, stg, "sswitch_", + commentedOut)); } } + return; + } + case UnresolvedNullReference: + { + addInstructionMethodItem(new UnresolvedNullReferenceMethodItem(codeItem, offset, stg, + (UnresolvedNullReference)instruction), commentedOut, comment); + addMethodItemsForInstruction(offset, ((UnresolvedNullReference)instruction).OriginalInstruction, + true, null); + return; + } + case DeadInstruction: + { + addMethodItemsForInstruction(offset, ((DeadInstruction)instruction).OriginalInstruction, true, null); + return; } } } @@ -471,11 +566,11 @@ public class MethodDefinition { }; catches.add(catchMethodItem); - labels.add(new LabelMethodItem(startAddress, stg, "try_start_")); + addLabelMethodItem(new LabelMethodItem(startAddress, stg, "try_start_", false)); //use the offset from the last covered instruction, but make the label //name refer to the address of the next instruction - labels.add(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress)); - labels.add(new LabelMethodItem(catchAllAddress, stg, "handler_")); + addLabelMethodItem(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress)); + addLabelMethodItem(new LabelMethodItem(catchAllAddress, stg, "handler_", false)); } @@ -487,11 +582,11 @@ public class MethodDefinition { handler.exceptionType, startAddress, endAddress, handler.handlerAddress); catches.add(catchMethodItem); - labels.add(new LabelMethodItem(startAddress, stg, "try_start_")); + addLabelMethodItem(new LabelMethodItem(startAddress, stg, "try_start_", false)); //use the offset from the last covered instruction, but make the label //name refer to the address of the next instruction - labels.add(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress)); - labels.add(new LabelMethodItem(handler.handlerAddress, stg, "handler_")); + addLabelMethodItem(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress)); + addLabelMethodItem(new LabelMethodItem(handler.handlerAddress, stg, "handler_", false)); } } } diff --git a/baksmali/src/main/resources/templates/templates/baksmali.stg b/baksmali/src/main/resources/templates/templates/baksmali.stg index 6dd519ee..62b7346e 100644 --- a/baksmali/src/main/resources/templates/templates/baksmali.stg +++ b/baksmali/src/main/resources/templates/templates/baksmali.stg @@ -198,12 +198,6 @@ Format22csf(Opcode, RegisterA, RegisterB, Reference) ::= , , >> -Format22csn(Opcode, Register) ::= -<< -#Couldn't determine the field while deodexing, replaced with generic method call -invoke-virtual/range { .. }, Ljava/lang/Object;->hashCode()I ->> - Format22s(Opcode, RegisterA, RegisterB, Literal) ::= << , , @@ -274,12 +268,6 @@ Format35msf(Opcode, Registers, Reference) ::= {}, >> -Format35msn(Opcode, Register) ::= -<< -#Couldn't determine method while deodexing, replaced with generic method call -invoke-virtual/range { .. }, Ljava/lang/Object;->hashCode()I ->> - Format3rc(Opcode, StartRegister, LastRegister, Reference) ::= << { .. }, @@ -300,6 +288,21 @@ Format51l(Opcode, Register, Literal) ::= , >> +CommentedOutMethodItem(MethodItem) ::= +<< +# +>> + +UnresolvedNullReference(Opcode, Register) ::= +<< +#Couldn't resolve optimized instruction while deodexing, due to the object register +#always being null. Replaced with generic method call +invoke-virtual/range { .. }, Ljava/lang/Object;->hashCode()I +goto/32 0 +>> + + + ArrayData(Opcode, ElementWidth, Values) ::= << .array-data @@ -327,9 +330,9 @@ SparseSwitchData(Opcode, Targets) ::= >> -Label(Prefix, HexOffset) ::= +Label(Prefix, HexOffset, CommentedOut) ::= << -: +#: >> Line(Line) ::= diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35msnMethodItem.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/DeadInstruction.java similarity index 68% rename from baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35msnMethodItem.java rename to dexlib/src/main/java/org/jf/dexlib/Code/Format/DeadInstruction.java index 747ddf83..d66b1f93 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/Instruction35msnMethodItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/DeadInstruction.java @@ -26,20 +26,24 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.jf.baksmali.Adaptors.Format; +package org.jf.dexlib.Code.Format; -import org.jf.dexlib.Code.Format.Instruction35msn; -import org.jf.dexlib.CodeItem; -import org.antlr.stringtemplate.StringTemplateGroup; -import org.antlr.stringtemplate.StringTemplate; +import org.jf.dexlib.Code.Instruction; -public class Instruction35msnMethodItem extends InstructionFormatMethodItem { - public Instruction35msnMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, - Instruction35msn instruction) { - super(codeItem, offset, stg, instruction); +public class DeadInstruction extends Instruction { + public final Instruction OriginalInstruction; + + public DeadInstruction(Instruction originalInstruction) { + super(originalInstruction.opcode); + this.OriginalInstruction = originalInstruction; } - protected void setAttributes(StringTemplate template) { - template.setAttribute("Register", formatRegister(instruction.RegisterNum)); + @Override + public int getSize() { + return OriginalInstruction.getSize(); + } + + public Format getFormat() { + return Format.DeadInstruction; } } 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 5c36d062..61976876 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 @@ -45,7 +45,6 @@ public enum Format { 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), @@ -60,14 +59,16 @@ public enum Format { 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), - SparseSwitchData(null, -1, true); + SparseSwitchData(null, -1, true), + UnresolvedNullReference(null, -1, false), + DeadInstruction(null, -1, false) + ; public final Instruction.InstructionFactory Factory; public final int size; diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csn.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/UnresolvedNullReference.java similarity index 69% rename from dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csn.java rename to dexlib/src/main/java/org/jf/dexlib/Code/Format/UnresolvedNullReference.java index e9a94c25..8d71b253 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22csn.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/UnresolvedNullReference.java @@ -29,30 +29,30 @@ 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 + * This represents a "fixed" odexed 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 + * whatever method/field that was trying to be accessed - namely, a NPE */ -public class Instruction22csn extends Instruction { +public class UnresolvedNullReference extends Instruction { + public final Instruction OriginalInstruction; + //the register number that holds the (null) reference type that the instruction operates on + public final int ObjectRegisterNum; - /** - * 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 UnresolvedNullReference(Instruction originalInstruction, int objectRegisterNumber) { + super(originalInstruction.opcode); + this.OriginalInstruction = originalInstruction; + this.ObjectRegisterNum = objectRegisterNumber; } + @Override + public int getSize() { + return OriginalInstruction.getSize(); + } public Format getFormat() { - return Format.Format35msn; + return Format.UnresolvedNullReference; } } diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java b/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java index fea02e1b..2aa960f5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java @@ -205,7 +205,9 @@ public class DeodexUtil { if (deodexInstruction(i)) { didSomething = true; } else { - somethingLeftToDo = true; + if (!i.dead) { + somethingLeftToDo = true; + } } } } @@ -219,7 +221,13 @@ public class DeodexUtil { List instructions = new ArrayList(insns.size()); for (insn i: insns) { - if (i.instruction.opcode.odexOnly) { + if (i.dead) { + if (i.fixedInstruction != null) { + instructions.add(new DeadInstruction(i.fixedInstruction)); + } else { + instructions.add(new DeadInstruction(i.instruction)); + } + } else if (i.instruction.opcode.odexOnly) { assert i.fixedInstruction != null; instructions.add(i.fixedInstruction); } else { @@ -289,7 +297,7 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); return true; } @@ -351,7 +359,7 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); return true; } @@ -392,7 +400,7 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); return true; } @@ -435,7 +443,7 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); return true; } @@ -497,7 +505,7 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); return true; } @@ -539,7 +547,7 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); return true; } @@ -581,7 +589,8 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); + i.propogateDeadness(); return true; } @@ -627,7 +636,7 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); return true; } @@ -673,7 +682,9 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); + //we need to mark any following instructions as dead + i.propogateDeadness(); return true; } @@ -719,7 +730,7 @@ public class DeodexUtil { //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); + i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum); return true; } @@ -804,6 +815,11 @@ public class DeodexUtil { */ public LinkedList successors = new LinkedList(); + /** + * Instructions that can pass on execution to this one + */ + public LinkedList predecessors = new LinkedList(); + /** * If this instruction is in a try block, these are the first instructions for each * exception handler @@ -860,6 +876,12 @@ public class DeodexUtil { */ public boolean fixed = false; + /** + * If this code is dead. Note that not all dead code is marked. Only the dead code that comes after an odexed + * instruction can't be resolved because its object register is always null. + */ + public boolean dead = false; + public final RegisterType[] registerMap; public final String[] registerTypes; @@ -1246,6 +1268,7 @@ public class DeodexUtil { private void addSuccessor(insn i) { successors.add(i); + i.predecessors.add(this); //if the next instruction can throw an exception, and is covered by exception handlers, //then the execution can in effect go directly from this instruction into the handler @@ -1332,6 +1355,38 @@ public class DeodexUtil { this.propogateRegisters(); } + /** + * This is initially called when this instruction is an odexed instruction that can't be resolved because + * the object register is always null. For each of its successor instructions, it checks if all of the other + * predecessors of that successor are also "dead". If so, it marks it as dead and recursively calls + * propogateDeadness on it. The effect is that all the code that follows after the initial unresolved + * instruction is marked dead, until a non-dead code path merges with the dead code path (and it becomes... + * undead. mmMMmmMMmm brains) + */ + public void propogateDeadness() { + for (insn successor: successors) { + //the first instruction of the method (or the first instruction of any exception handlers covering + //the first instruction) can never be dead + if (successor.firstInstruction) { + continue; + } + + boolean allSucessorsPredecessorsDead = true; + for (insn successorPredecessor: successor.predecessors) { + if (successorPredecessor != this) { + if (!successorPredecessor.dead) { + allSucessorsPredecessorsDead = false; + break; + } + } + } + if (allSucessorsPredecessorsDead) { + successor.dead = true; + successor.propogateDeadness(); + } + } + } + public void propogateRegisters() { visited = true; @@ -1399,7 +1454,6 @@ public class DeodexUtil { } } else { String type = destRegisterType(); - String nextType = nextInsn.registerTypes[registerNum]; if (type != null && !type.equals(nextInsn.registerTypes[registerNum])) { //see comment above for loop