Added better support for the case when an optimized instruction can't be resolved due to the object register always being null. It should comment out any dead code following the unresolved instruction (to prevent verification issues, due to the changed method call)

git-svn-id: https://smali.googlecode.com/svn/trunk@455 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-09-10 06:40:58 +00:00
parent ddc8655d10
commit c65a8d8b5f
11 changed files with 325 additions and 161 deletions

View File

@ -42,7 +42,6 @@ public class BlankMethodItem extends MethodItem {
} }
} }
public int getSortOrder() { public int getSortOrder() {
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
} }

View File

@ -26,32 +26,29 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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.antlr.stringtemplate.StringTemplate;
import org.jf.dexlib.Code.Instruction; import org.antlr.stringtemplate.StringTemplateGroup;
/** public class CommentedOutMethodItem extends MethodItem {
* This represents a "fixed" Format35ms, or Format3rms instruction, where the object register is always null and so the private final StringTemplateGroup stg;
* correct type can't be determined. How this is handled is "implementation dependent". baksmali just replaces it with private final MethodItem commentedOutMethodItem;
* 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 CommentedOutMethodItem(StringTemplateGroup stg, MethodItem commentedOutMethodItem) {
* this is the first register, i.e. the object register. The others don't matter, because we don't know what super(commentedOutMethodItem.getOffset());
* the original method call is/was. this.stg = stg;
*/ this.commentedOutMethodItem = commentedOutMethodItem;
public final int RegisterNum;
public Instruction35msn(int registerNum) {
super(Opcode.INVOKE_VIRTUAL);
this.RegisterNum = registerNum;
} }
public int getSortOrder() {
return commentedOutMethodItem.getSortOrder() + 1;
}
public Format getFormat() { @Override
return Format.Format35msn; public String toString() {
StringTemplate template = stg.getInstanceOf("CommentedOutMethodItem");
template.setAttribute("MethodItem", commentedOutMethodItem);
return template.toString();
} }
} }

View File

@ -34,7 +34,7 @@ public class EndTryLabelMethodItem extends LabelMethodItem {
private int labelOffset; private int labelOffset;
public EndTryLabelMethodItem(int offset, StringTemplateGroup stg, int labelOffset) { public EndTryLabelMethodItem(int offset, StringTemplateGroup stg, int labelOffset) {
super(offset, stg, "try_end_"); super(offset, stg, "try_end_", false);
this.labelOffset = labelOffset; this.labelOffset = labelOffset;
} }

View File

@ -28,18 +28,18 @@
package org.jf.baksmali.Adaptors.Format; 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.jf.dexlib.CodeItem;
import org.antlr.stringtemplate.StringTemplateGroup; import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate; import org.antlr.stringtemplate.StringTemplate;
public class Instruction22csnMethodItem extends InstructionFormatMethodItem<Instruction22csn> { public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodItem<UnresolvedNullReference> {
public Instruction22csnMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, public UnresolvedNullReferenceMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg,
Instruction22csn instruction) { UnresolvedNullReference instruction) {
super(codeItem, offset, stg, instruction); super(codeItem, offset, stg, instruction);
} }
protected void setAttributes(StringTemplate template) { protected void setAttributes(StringTemplate template) {
template.setAttribute("Register", formatRegister(instruction.RegisterNum)); template.setAttribute("Register", formatRegister(instruction.ObjectRegisterNum));
} }
} }

View File

@ -34,17 +34,27 @@ import org.antlr.stringtemplate.StringTemplate;
public class LabelMethodItem extends MethodItem { public class LabelMethodItem extends MethodItem {
private final StringTemplateGroup stg; private final StringTemplateGroup stg;
private final String labelPrefix; 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); super(offset);
this.stg = stg; this.stg = stg;
this.labelPrefix = labelPrefix; this.labelPrefix = labelPrefix;
this.isCommentedOut = isCommentedOut;
} }
public int getSortOrder() { public int getSortOrder() {
return 0; return 0;
} }
public boolean isCommentedOut() {
return isCommentedOut;
}
public void setCommentedOut(boolean isCommentedOut) {
this.isCommentedOut = isCommentedOut;
}
public int compareTo(MethodItem methodItem) { public int compareTo(MethodItem methodItem) {
int result = super.compareTo(methodItem); int result = super.compareTo(methodItem);
@ -71,6 +81,7 @@ public class LabelMethodItem extends MethodItem {
@Override @Override
public String toString() { public String toString() {
StringTemplate template = stg.getInstanceOf("Label"); StringTemplate template = stg.getInstanceOf("Label");
template.setAttribute("CommentedOut", this.isCommentedOut);
template.setAttribute("Prefix", labelPrefix); template.setAttribute("Prefix", labelPrefix);
template.setAttribute("HexOffset", getLabelOffset()); template.setAttribute("HexOffset", getLabelOffset());
return template.toString(); return template.toString();

View File

@ -143,7 +143,7 @@ public class MethodDefinition {
MethodItemList methodItemList = new MethodItemList(dexFile, stg, codeItem); MethodItemList methodItemList = new MethodItemList(dexFile, stg, codeItem);
methodItemList.generateMethodItemList(); methodItemList.generateMethodItemList();
methodItems.addAll(methodItemList.labels); methodItems.addAll(methodItemList.labels.values());
methodItems.addAll(methodItemList.instructions); methodItems.addAll(methodItemList.instructions);
methodItems.addAll(methodItemList.blanks); methodItems.addAll(methodItemList.blanks);
methodItems.addAll(methodItemList.catches); methodItems.addAll(methodItemList.catches);
@ -159,7 +159,7 @@ public class MethodDefinition {
private final StringTemplateGroup stg; private final StringTemplateGroup stg;
private final CodeItem codeItem; private final CodeItem codeItem;
public HashSet<LabelMethodItem> labels = new HashSet<LabelMethodItem>(); public HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>();
public List<MethodItem> instructions = new ArrayList<MethodItem>(); public List<MethodItem> instructions = new ArrayList<MethodItem>();
public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>(); public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>();
public List<CatchMethodItem> catches = new ArrayList<CatchMethodItem>(); public List<CatchMethodItem> catches = new ArrayList<CatchMethodItem>();
@ -197,7 +197,7 @@ public class MethodDefinition {
offset = 0; offset = 0;
for (Instruction instruction: instructions) { for (Instruction instruction: instructions) {
addMethodItemsForInstruction(offset, instruction); addMethodItemsForInstruction(offset, instruction, false, null);
blanks.add(new BlankMethodItem(stg, offset)); blanks.add(new BlankMethodItem(stg, offset));
offset += instruction.getSize()/2; offset += instruction.getSize()/2;
@ -237,7 +237,7 @@ public class MethodDefinition {
new InstructionIterator.ProcessInstructionDelegate() { new InstructionIterator.ProcessInstructionDelegate() {
public void ProcessInstruction(int index, Instruction instruction) { public void ProcessInstruction(int index, Instruction instruction) {
int offset = index/2; int offset = index/2;
addMethodItemsForInstruction(offset, instruction); addMethodItemsForInstruction(offset, instruction, false, null);
blanks.add(new BlankMethodItem(stg, offset)); blanks.add(new BlankMethodItem(stg, offset));
} }
}); });
@ -250,136 +250,213 @@ public class MethodDefinition {
addDebugInfo(); 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()) { switch (instruction.getFormat()) {
case Format10t: case Format10t:
instructions.add(new Instruction10tMethodItem(codeItem, offset, stg,(Instruction10t)instruction)); addInstructionMethodItem(
labels.add(new LabelMethodItem(offset + ((Instruction10t)instruction).getOffset(), stg, "goto_")); new Instruction10tMethodItem(codeItem, offset, stg,(Instruction10t)instruction),
commentedOut, comment);
addLabelMethodItem(new LabelMethodItem(offset + ((Instruction10t)instruction).getOffset(), stg,
"goto_", commentedOut));
return; return;
case Format10x: case Format10x:
instructions.add(new Instruction10xMethodItem(codeItem, offset, stg, (Instruction10x)instruction)); addInstructionMethodItem(
new Instruction10xMethodItem(codeItem, offset, stg, (Instruction10x)instruction),
commentedOut, comment);
return; return;
case Format11n: case Format11n:
instructions.add(new Instruction11nMethodItem(codeItem, offset, stg, (Instruction11n)instruction)); addInstructionMethodItem(
new Instruction11nMethodItem(codeItem, offset, stg, (Instruction11n)instruction),
commentedOut, comment);
return; return;
case Format11x: case Format11x:
instructions.add(new Instruction11xMethodItem(codeItem, offset, stg, (Instruction11x)instruction)); addInstructionMethodItem(
new Instruction11xMethodItem(codeItem, offset, stg, (Instruction11x)instruction),
commentedOut, comment);
return; return;
case Format12x: case Format12x:
instructions.add(new Instruction12xMethodItem(codeItem, offset, stg, (Instruction12x)instruction)); addInstructionMethodItem(
new Instruction12xMethodItem(codeItem, offset, stg, (Instruction12x)instruction),
commentedOut, comment);
return; return;
case Format20t: case Format20t:
instructions.add(new Instruction20tMethodItem(codeItem, offset, stg, (Instruction20t)instruction)); addInstructionMethodItem(
labels.add(new LabelMethodItem(offset + ((Instruction20t)instruction).getOffset(), stg, "goto_")); new Instruction20tMethodItem(codeItem, offset, stg, (Instruction20t)instruction),
commentedOut, comment);
addLabelMethodItem(new LabelMethodItem(offset + ((Instruction20t)instruction).getOffset(), stg,
"goto_", commentedOut));
return; return;
case Format21c: case Format21c:
instructions.add(new Instruction21cMethodItem(codeItem, offset, stg, (Instruction21c)instruction)); addInstructionMethodItem(
new Instruction21cMethodItem(codeItem, offset, stg, (Instruction21c)instruction),
commentedOut, comment);
return; return;
case Format21h: case Format21h:
instructions.add(new Instruction21hMethodItem(codeItem, offset, stg, (Instruction21h)instruction)); addInstructionMethodItem(
new Instruction21hMethodItem(codeItem, offset, stg, (Instruction21h)instruction),
commentedOut, comment);
return; return;
case Format21s: case Format21s:
instructions.add(new Instruction21sMethodItem(codeItem, offset, stg, (Instruction21s)instruction)); addInstructionMethodItem(
new Instruction21sMethodItem(codeItem, offset, stg, (Instruction21s)instruction),
commentedOut, comment);
return; return;
case Format21t: case Format21t:
instructions.add(new Instruction21tMethodItem(codeItem, offset, stg, (Instruction21t)instruction)); addInstructionMethodItem(
labels.add(new LabelMethodItem(offset + ((Instruction21t)instruction).getOffset(), stg, "cond_")); new Instruction21tMethodItem(codeItem, offset, stg, (Instruction21t)instruction),
commentedOut, comment);
addLabelMethodItem(new LabelMethodItem(offset + ((Instruction21t)instruction).getOffset(), stg,
"cond_", commentedOut));
return; return;
case Format22b: case Format22b:
instructions.add(new Instruction22bMethodItem(codeItem, offset, stg, (Instruction22b)instruction)); addInstructionMethodItem(
new Instruction22bMethodItem(codeItem, offset, stg, (Instruction22b)instruction),
commentedOut, comment);
return; return;
case Format22c: case Format22c:
instructions.add(new Instruction22cMethodItem(codeItem, offset, stg, (Instruction22c)instruction)); addInstructionMethodItem(
new Instruction22cMethodItem(codeItem, offset, stg, (Instruction22c)instruction),
commentedOut, comment);
return; return;
case Format22cs: case Format22cs:
instructions.add(new Instruction22csMethodItem(codeItem, offset, stg, addInstructionMethodItem(
(Instruction22cs)instruction)); new Instruction22csMethodItem(codeItem, offset, stg, (Instruction22cs)instruction),
commentedOut, comment);
return; return;
case Format22csf: case Format22csf:
instructions.add(new Instruction22csfMethodItem(codeItem, offset, stg, addInstructionMethodItem(
(Instruction22csf)instruction)); new Instruction22csfMethodItem(codeItem, offset, stg, (Instruction22csf)instruction),
return; commentedOut, comment);
case Format22csn:
instructions.add(new Instruction22csnMethodItem(codeItem, offset, stg,
(Instruction22csn)instruction));
return; return;
case Format22s: case Format22s:
instructions.add(new Instruction22sMethodItem(codeItem, offset, stg, (Instruction22s)instruction)); addInstructionMethodItem(
new Instruction22sMethodItem(codeItem, offset, stg, (Instruction22s)instruction),
commentedOut, comment);
return; return;
case Format22t: case Format22t:
instructions.add(new Instruction22tMethodItem(codeItem, offset, stg, (Instruction22t)instruction)); addInstructionMethodItem(
labels.add(new LabelMethodItem(offset + ((Instruction22t)instruction).getOffset(), stg, "cond_")); new Instruction22tMethodItem(codeItem, offset, stg, (Instruction22t)instruction),
commentedOut, comment);
addLabelMethodItem(new LabelMethodItem(offset + ((Instruction22t)instruction).getOffset(), stg,
"cond_", commentedOut));
return; return;
case Format22x: case Format22x:
instructions.add(new Instruction22xMethodItem(codeItem, offset, stg, (Instruction22x)instruction)); addInstructionMethodItem(
new Instruction22xMethodItem(codeItem, offset, stg, (Instruction22x)instruction),
commentedOut, comment);
return; return;
case Format23x: case Format23x:
instructions.add(new Instruction23xMethodItem(codeItem, offset, stg, (Instruction23x)instruction)); addInstructionMethodItem(
new Instruction23xMethodItem(codeItem, offset, stg, (Instruction23x)instruction),
commentedOut, comment);
return; return;
case Format30t: case Format30t:
instructions.add(new Instruction30tMethodItem(codeItem, offset, stg, (Instruction30t)instruction)); addInstructionMethodItem(
labels.add(new LabelMethodItem(offset + ((Instruction30t)instruction).getOffset(), stg, "goto_")); new Instruction30tMethodItem(codeItem, offset, stg, (Instruction30t)instruction),
commentedOut, comment);
addLabelMethodItem(new LabelMethodItem(offset + ((Instruction30t)instruction).getOffset(), stg,
"goto_", commentedOut));
return; return;
case Format31c: case Format31c:
instructions.add(new Instruction31cMethodItem(codeItem, offset, stg, (Instruction31c)instruction)); addInstructionMethodItem(
new Instruction31cMethodItem(codeItem, offset, stg, (Instruction31c)instruction),
commentedOut, comment);
return; return;
case Format31i: case Format31i:
instructions.add(new Instruction31iMethodItem(codeItem, offset, stg, (Instruction31i)instruction)); addInstructionMethodItem(
new Instruction31iMethodItem(codeItem, offset, stg, (Instruction31i)instruction),
commentedOut, comment);
return; return;
case Format31t: 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) { if (instruction.opcode == Opcode.FILL_ARRAY_DATA) {
labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
"array_")); "array_", commentedOut));
} else if (instruction.opcode == Opcode.PACKED_SWITCH) { } else if (instruction.opcode == Opcode.PACKED_SWITCH) {
labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
"pswitch_data_")); "pswitch_data_", commentedOut));
} else if (instruction.opcode == Opcode.SPARSE_SWITCH) { } else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg, addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
"sswitch_data_")); "sswitch_data_", commentedOut));
} }
return; return;
case Format32x: case Format32x:
instructions.add(new Instruction32xMethodItem(codeItem, offset, stg, (Instruction32x)instruction)); addInstructionMethodItem(
new Instruction32xMethodItem(codeItem, offset, stg, (Instruction32x)instruction),
commentedOut, comment);
return; return;
case Format35c: case Format35c:
instructions.add(new Instruction35cMethodItem(codeItem, offset, stg, (Instruction35c)instruction)); addInstructionMethodItem(
new Instruction35cMethodItem(codeItem, offset, stg, (Instruction35c)instruction),
commentedOut, comment);
return; return;
case Format35s: case Format35s:
instructions.add(new Instruction35sMethodItem(codeItem, offset, stg, (Instruction35s)instruction)); addInstructionMethodItem(
new Instruction35sMethodItem(codeItem, offset, stg, (Instruction35s)instruction),
commentedOut, comment);
return; return;
case Format35sf: case Format35sf:
instructions.add(new Instruction35sfMethodItem(codeItem, offset, stg, addInstructionMethodItem(
(Instruction35sf)instruction)); new Instruction35sfMethodItem(codeItem, offset, stg, (Instruction35sf)instruction),
commentedOut, comment);
return; return;
case Format35ms: case Format35ms:
instructions.add(new Instruction35msMethodItem(codeItem, offset, stg, addInstructionMethodItem(
(Instruction35ms)instruction)); new Instruction35msMethodItem(codeItem, offset, stg, (Instruction35ms)instruction),
commentedOut, comment);
return; return;
case Format35msf: case Format35msf:
instructions.add(new Instruction35msfMethodItem(codeItem, offset, stg, addInstructionMethodItem(
(Instruction35msf)instruction)); new Instruction35msfMethodItem(codeItem, offset, stg, (Instruction35msf)instruction),
return; commentedOut, comment);
case Format35msn:
instructions.add(new Instruction35msnMethodItem(codeItem, offset, stg,
(Instruction35msn)instruction));
return; return;
case Format3rc: case Format3rc:
instructions.add(new Instruction3rcMethodItem(codeItem, offset, stg, (Instruction3rc)instruction)); addInstructionMethodItem(
new Instruction3rcMethodItem(codeItem, offset, stg, (Instruction3rc)instruction),
commentedOut, comment);
return; return;
case Format3rms: case Format3rms:
instructions.add(new Instruction3rmsMethodItem(codeItem, offset, stg, addInstructionMethodItem(
(Instruction3rms)instruction)); new Instruction3rmsMethodItem(codeItem, offset, stg, (Instruction3rms)instruction),
commentedOut, comment);
return; return;
case Format3rmsf: case Format3rmsf:
instructions.add(new Instruction3rmsfMethodItem(codeItem, offset, stg, addInstructionMethodItem(
(Instruction3rmsf)instruction)); new Instruction3rmsfMethodItem(codeItem, offset, stg, (Instruction3rmsf)instruction),
commentedOut, comment);
return; return;
case Format51l: case Format51l:
instructions.add(new Instruction51lMethodItem(codeItem, offset, stg, (Instruction51l)instruction)); addInstructionMethodItem(
new Instruction51lMethodItem(codeItem, offset, stg, (Instruction51l)instruction),
commentedOut, comment);
return; return;
case ArrayData: case ArrayData:
instructions.add(new ArrayDataMethodItem(codeItem, offset, stg, (ArrayDataPseudoInstruction)instruction)); addInstructionMethodItem(
new ArrayDataMethodItem(codeItem, offset, stg, (ArrayDataPseudoInstruction)instruction),
commentedOut, comment);
return; return;
case PackedSwitchData: case PackedSwitchData:
{ {
@ -389,14 +466,16 @@ public class MethodDefinition {
PackedSwitchDataPseudoInstruction packedSwitchInstruction = PackedSwitchDataPseudoInstruction packedSwitchInstruction =
(PackedSwitchDataPseudoInstruction)instruction; (PackedSwitchDataPseudoInstruction)instruction;
instructions.add(new PackedSwitchMethodItem(codeItem, offset, stg, addInstructionMethodItem(
packedSwitchInstruction, baseAddress)); new PackedSwitchMethodItem(codeItem, offset, stg, packedSwitchInstruction, baseAddress),
commentedOut, comment);
Iterator<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> iterator = Iterator<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> iterator =
packedSwitchInstruction.getTargets(); packedSwitchInstruction.getTargets();
while (iterator.hasNext()) { while (iterator.hasNext()) {
PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next(); PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
labels.add(new LabelMethodItem(baseAddress + target.target, stg, "pswitch_")); addLabelMethodItem(new LabelMethodItem(baseAddress + target.target, stg, "pswitch_",
commentedOut));
} }
} }
return; return;
@ -409,16 +488,32 @@ public class MethodDefinition {
SparseSwitchDataPseudoInstruction sparseSwitchInstruction = SparseSwitchDataPseudoInstruction sparseSwitchInstruction =
(SparseSwitchDataPseudoInstruction)instruction; (SparseSwitchDataPseudoInstruction)instruction;
instructions.add(new SparseSwitchMethodItem(codeItem, offset, stg, addInstructionMethodItem(
sparseSwitchInstruction, baseAddress)); new SparseSwitchMethodItem(codeItem, offset, stg, sparseSwitchInstruction, baseAddress),
commentedOut, comment);
Iterator<SparseSwitchDataPseudoInstruction.SparseSwitchTarget> iterator = Iterator<SparseSwitchDataPseudoInstruction.SparseSwitchTarget> iterator =
sparseSwitchInstruction.getTargets(); sparseSwitchInstruction.getTargets();
while (iterator.hasNext()) { while (iterator.hasNext()) {
SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next(); 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); 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 //use the offset from the last covered instruction, but make the label
//name refer to the address of the next instruction //name refer to the address of the next instruction
labels.add(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress)); addLabelMethodItem(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress));
labels.add(new LabelMethodItem(catchAllAddress, stg, "handler_")); addLabelMethodItem(new LabelMethodItem(catchAllAddress, stg, "handler_", false));
} }
@ -487,11 +582,11 @@ public class MethodDefinition {
handler.exceptionType, startAddress, endAddress, handler.handlerAddress); handler.exceptionType, startAddress, endAddress, handler.handlerAddress);
catches.add(catchMethodItem); 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 //use the offset from the last covered instruction, but make the label
//name refer to the address of the next instruction //name refer to the address of the next instruction
labels.add(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress)); addLabelMethodItem(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress));
labels.add(new LabelMethodItem(handler.handlerAddress, stg, "handler_")); addLabelMethodItem(new LabelMethodItem(handler.handlerAddress, stg, "handler_", false));
} }
} }
} }

View File

@ -198,12 +198,6 @@ Format22csf(Opcode, RegisterA, RegisterB, Reference) ::=
<Opcode> <RegisterA>, <RegisterB>, <Reference> <Opcode> <RegisterA>, <RegisterB>, <Reference>
>> >>
Format22csn(Opcode, Register) ::=
<<
#Couldn't determine the field while deodexing, replaced with generic method call
invoke-virtual/range {<Register> .. <Register>}, Ljava/lang/Object;->hashCode()I
>>
Format22s(Opcode, RegisterA, RegisterB, Literal) ::= Format22s(Opcode, RegisterA, RegisterB, Literal) ::=
<< <<
<Opcode> <RegisterA>, <RegisterB>, <Literal> <Opcode> <RegisterA>, <RegisterB>, <Literal>
@ -274,12 +268,6 @@ Format35msf(Opcode, Registers, Reference) ::=
<Opcode> {<Registers; separator=", ">}, <Reference> <Opcode> {<Registers; separator=", ">}, <Reference>
>> >>
Format35msn(Opcode, Register) ::=
<<
#Couldn't determine method while deodexing, replaced with generic method call
invoke-virtual/range {<Register> .. <Register>}, Ljava/lang/Object;->hashCode()I
>>
Format3rc(Opcode, StartRegister, LastRegister, Reference) ::= Format3rc(Opcode, StartRegister, LastRegister, Reference) ::=
<< <<
<Opcode> {<StartRegister> .. <LastRegister>}, <Reference> <Opcode> {<StartRegister> .. <LastRegister>}, <Reference>
@ -300,6 +288,21 @@ Format51l(Opcode, Register, Literal) ::=
<Opcode> <Register>, <Literal> <Opcode> <Register>, <Literal>
>> >>
CommentedOutMethodItem(MethodItem) ::=
<<
#<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 {<Register> .. <Register>}, Ljava/lang/Object;->hashCode()I
goto/32 0
>>
ArrayData(Opcode, ElementWidth, Values) ::= ArrayData(Opcode, ElementWidth, Values) ::=
<< <<
.array-data <ElementWidth> .array-data <ElementWidth>
@ -327,9 +330,9 @@ SparseSwitchData(Opcode, Targets) ::=
>> >>
Label(Prefix, HexOffset) ::= Label(Prefix, HexOffset, CommentedOut) ::=
<< <<
<Prefix><HexOffset>: <if(CommentedOut)>#<endif><Prefix><HexOffset>:
>> >>
Line(Line) ::= Line(Line) ::=

View File

@ -26,20 +26,24 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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.Code.Instruction;
import org.jf.dexlib.CodeItem;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
public class Instruction35msnMethodItem extends InstructionFormatMethodItem<Instruction35msn> { public class DeadInstruction extends Instruction {
public Instruction35msnMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg, public final Instruction OriginalInstruction;
Instruction35msn instruction) {
super(codeItem, offset, stg, instruction); public DeadInstruction(Instruction originalInstruction) {
super(originalInstruction.opcode);
this.OriginalInstruction = originalInstruction;
} }
protected void setAttributes(StringTemplate template) { @Override
template.setAttribute("Register", formatRegister(instruction.RegisterNum)); public int getSize() {
return OriginalInstruction.getSize();
}
public Format getFormat() {
return Format.DeadInstruction;
} }
} }

View File

@ -45,7 +45,6 @@ public enum Format {
Format22c(Instruction22c.Factory, 4), Format22c(Instruction22c.Factory, 4),
Format22cs(Instruction22cs.Factory, 4), Format22cs(Instruction22cs.Factory, 4),
Format22csf(null, 4), Format22csf(null, 4),
Format22csn(null, 4),
Format22s(Instruction22s.Factory, 4), Format22s(Instruction22s.Factory, 4),
Format22t(Instruction22t.Factory, 4), Format22t(Instruction22t.Factory, 4),
Format22x(Instruction22x.Factory, 4), Format22x(Instruction22x.Factory, 4),
@ -60,14 +59,16 @@ public enum Format {
Format35sf(null, 6), Format35sf(null, 6),
Format35ms(Instruction35ms.Factory, 6), Format35ms(Instruction35ms.Factory, 6),
Format35msf(null, 6), Format35msf(null, 6),
Format35msn(null, 6),
Format3rc(Instruction3rc.Factory, 6), Format3rc(Instruction3rc.Factory, 6),
Format3rms(Instruction3rms.Factory, 6), Format3rms(Instruction3rms.Factory, 6),
Format3rmsf(null, 6), Format3rmsf(null, 6),
Format51l(Instruction51l.Factory, 10), Format51l(Instruction51l.Factory, 10),
ArrayData(null, -1, true), ArrayData(null, -1, true),
PackedSwitchData(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 Instruction.InstructionFactory Factory;
public final int size; public final int size;

View File

@ -29,30 +29,30 @@
package org.jf.dexlib.Code.Format; package org.jf.dexlib.Code.Format;
import org.jf.dexlib.Code.Instruction; 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 * 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 * 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;
/** public UnresolvedNullReference(Instruction originalInstruction, int objectRegisterNumber) {
* this is the first register, i.e. the object register. The others don't matter, because we don't know what super(originalInstruction.opcode);
* the original field is/was. this.OriginalInstruction = originalInstruction;
*/ this.ObjectRegisterNum = objectRegisterNumber;
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;
} }
@Override
public int getSize() {
return OriginalInstruction.getSize();
}
public Format getFormat() { public Format getFormat() {
return Format.Format35msn; return Format.UnresolvedNullReference;
} }
} }

View File

@ -205,10 +205,12 @@ public class DeodexUtil {
if (deodexInstruction(i)) { if (deodexInstruction(i)) {
didSomething = true; didSomething = true;
} else { } else {
if (!i.dead) {
somethingLeftToDo = true; somethingLeftToDo = true;
} }
} }
} }
}
} while (didSomething); } while (didSomething);
if (somethingLeftToDo) { if (somethingLeftToDo) {
System.err.println("warning: could not fully deodex the method " + System.err.println("warning: could not fully deodex the method " +
@ -219,7 +221,13 @@ public class DeodexUtil {
List<Instruction> instructions = new ArrayList<Instruction>(insns.size()); List<Instruction> instructions = new ArrayList<Instruction>(insns.size());
for (insn i: insns) { 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; assert i.fixedInstruction != null;
instructions.add(i.fixedInstruction); instructions.add(i.fixedInstruction);
} else { } else {
@ -289,7 +297,7 @@ public class DeodexUtil {
//We actually just create an Instruction2csn, which doesn't have any method/field info associated with //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 //it, and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction22csn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
return true; 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 //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 //it, and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction22csn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
return true; 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 //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 //it, and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction22csn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
return true; 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 //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 //it, and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction22csn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
return true; 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 //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 //it, and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction22csn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
return true; 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 //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 //it, and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction22csn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
return true; 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, //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 //and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction35msn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
i.propogateDeadness();
return true; 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, //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 //and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction35msn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
return true; 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, //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 //and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { 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; 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, //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 //and let the caller choose which "default" method to call in this case
if (regType == RegisterType.Null) { if (regType == RegisterType.Null) {
i.fixedInstruction = new Instruction35msn(registerNum); i.fixedInstruction = new UnresolvedNullReference(i.instruction, registerNum);
return true; return true;
} }
@ -804,6 +815,11 @@ public class DeodexUtil {
*/ */
public LinkedList<insn> successors = new LinkedList<insn>(); public LinkedList<insn> successors = new LinkedList<insn>();
/**
* Instructions that can pass on execution to this one
*/
public LinkedList<insn> predecessors = new LinkedList<insn>();
/** /**
* If this instruction is in a try block, these are the first instructions for each * If this instruction is in a try block, these are the first instructions for each
* exception handler * exception handler
@ -860,6 +876,12 @@ public class DeodexUtil {
*/ */
public boolean fixed = false; 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 RegisterType[] registerMap;
public final String[] registerTypes; public final String[] registerTypes;
@ -1246,6 +1268,7 @@ public class DeodexUtil {
private void addSuccessor(insn i) { private void addSuccessor(insn i) {
successors.add(i); successors.add(i);
i.predecessors.add(this);
//if the next instruction can throw an exception, and is covered by exception handlers, //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 //then the execution can in effect go directly from this instruction into the handler
@ -1332,6 +1355,38 @@ public class DeodexUtil {
this.propogateRegisters(); 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() { public void propogateRegisters() {
visited = true; visited = true;
@ -1399,7 +1454,6 @@ public class DeodexUtil {
} }
} else { } else {
String type = destRegisterType(); String type = destRegisterType();
String nextType = nextInsn.registerTypes[registerNum];
if (type != null && !type.equals(nextInsn.registerTypes[registerNum])) { if (type != null && !type.equals(nextInsn.registerTypes[registerNum])) {
//see comment above for loop //see comment above for loop