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() {
return Integer.MAX_VALUE;
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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<Instruction22csn> {
public Instruction22csnMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg,
Instruction22csn instruction) {
public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodItem<UnresolvedNullReference> {
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));
}
}

View File

@ -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();

View File

@ -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<LabelMethodItem> labels = new HashSet<LabelMethodItem>();
public HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>();
public List<MethodItem> instructions = new ArrayList<MethodItem>();
public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>();
public List<CatchMethodItem> catches = new ArrayList<CatchMethodItem>();
@ -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<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> 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<SparseSwitchDataPseudoInstruction.SparseSwitchTarget> 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));
}
}
}

View File

@ -198,12 +198,6 @@ Format22csf(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) ::=
<<
<Opcode> <RegisterA>, <RegisterB>, <Literal>
@ -274,12 +268,6 @@ Format35msf(Opcode, Registers, 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) ::=
<<
<Opcode> {<StartRegister> .. <LastRegister>}, <Reference>
@ -300,6 +288,21 @@ Format51l(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) ::=
<<
.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) ::=

View File

@ -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<Instruction35msn> {
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;
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -205,10 +205,12 @@ public class DeodexUtil {
if (deodexInstruction(i)) {
didSomething = true;
} else {
if (!i.dead) {
somethingLeftToDo = true;
}
}
}
}
} while (didSomething);
if (somethingLeftToDo) {
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());
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<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
* 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