Split the logic for generating the instruction method items depending on whether we need to use the MethodAnalyzer or not

git-svn-id: https://smali.googlecode.com/svn/trunk@736 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2010-06-12 15:55:36 +00:00
parent 41265daa5a
commit f7344d33d0
2 changed files with 124 additions and 52 deletions

View File

@ -43,7 +43,35 @@ public class InstructionMethodItemFactory {
public static InstructionMethodItem makeInstructionFormatMethodItem(MethodDefinition methodDefinition, public static InstructionMethodItem makeInstructionFormatMethodItem(MethodDefinition methodDefinition,
CodeItem codeItem, CodeItem codeItem,
int codeAddress, boolean dead, int codeAddress,
Instruction instruction) {
if (instruction instanceof OffsetInstruction) {
return new OffsetInstructionFormatMethodItem(methodDefinition.getLabelCache(), codeItem, codeAddress,
instruction);
}
switch (instruction.getFormat()) {
case ArrayData:
return new ArrayDataMethodItem(codeItem, codeAddress, false,
(ArrayDataPseudoInstruction)instruction);
case PackedSwitchData:
return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress, false,
(PackedSwitchDataPseudoInstruction)instruction);
case SparseSwitchData:
return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress, false,
(SparseSwitchDataPseudoInstruction)instruction);
case UnresolvedNullReference:
assert false;
throw new RuntimeException("UnresolvedNullReference not supported, use " +
"makeAnalyzedInstructionFormatMethodItem instead");
default:
return new InstructionMethodItem(codeItem, codeAddress, instruction);
}
}
public static InstructionMethodItem makeAnalyzedInstructionFormatMethodItem(MethodDefinition methodDefinition,
CodeItem codeItem, int codeAddress,
boolean isDead,
Instruction instruction, Instruction instruction,
boolean isLastInstruction) { boolean isLastInstruction) {
if (instruction instanceof OffsetInstruction) { if (instruction instanceof OffsetInstruction) {
@ -53,13 +81,13 @@ public class InstructionMethodItemFactory {
switch (instruction.getFormat()) { switch (instruction.getFormat()) {
case ArrayData: case ArrayData:
return new ArrayDataMethodItem(codeItem, codeAddress, dead, return new ArrayDataMethodItem(codeItem, codeAddress, isDead,
(ArrayDataPseudoInstruction)instruction); (ArrayDataPseudoInstruction)instruction);
case PackedSwitchData: case PackedSwitchData:
return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress, dead, return new PackedSwitchMethodItem(methodDefinition, codeItem, codeAddress, isDead,
(PackedSwitchDataPseudoInstruction)instruction); (PackedSwitchDataPseudoInstruction)instruction);
case SparseSwitchData: case SparseSwitchData:
return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress, dead, return new SparseSwitchMethodItem(methodDefinition, codeItem, codeAddress, isDead,
(SparseSwitchDataPseudoInstruction)instruction); (SparseSwitchDataPseudoInstruction)instruction);
case UnresolvedNullReference: case UnresolvedNullReference:
return new UnresolvedNullReferenceMethodItem(codeItem, codeAddress, return new UnresolvedNullReferenceMethodItem(codeItem, codeAddress,

View File

@ -49,7 +49,7 @@ import java.util.*;
public class MethodDefinition { public class MethodDefinition {
private final ClassDataItem.EncodedMethod encodedMethod; private final ClassDataItem.EncodedMethod encodedMethod;
private final MethodAnalyzer methodAnalyzer; private MethodAnalyzer methodAnalyzer;
private final LabelCache labelCache = new LabelCache(); private final LabelCache labelCache = new LabelCache();
@ -66,29 +66,28 @@ public class MethodDefinition {
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh. //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
if (encodedMethod.codeItem != null) { if (encodedMethod.codeItem != null) {
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex); Instruction[] instructions = encodedMethod.codeItem.getInstructions();
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
packedSwitchMap = new SparseIntArray(1); packedSwitchMap = new SparseIntArray(1);
sparseSwitchMap = new SparseIntArray(1); sparseSwitchMap = new SparseIntArray(1);
instructionMap = new SparseIntArray(instructions.size()); instructionMap = new SparseIntArray(instructions.length);
int currentCodeAddress = 0; int currentCodeAddress = 0;
for (int i=0; i<instructions.size(); i++) { for (int i=0; i<instructions.length; i++) {
AnalyzedInstruction instruction = instructions.get(i); Instruction instruction = instructions[i];
if (instruction.getInstruction().opcode == Opcode.PACKED_SWITCH) { if (instruction.opcode == Opcode.PACKED_SWITCH) {
packedSwitchMap.append( packedSwitchMap.append(
currentCodeAddress + currentCodeAddress +
((OffsetInstruction)instruction.getInstruction()).getTargetAddressOffset(), ((OffsetInstruction)instruction).getTargetAddressOffset(),
currentCodeAddress); currentCodeAddress);
} else if (instruction.getInstruction().opcode == Opcode.SPARSE_SWITCH) { } else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
sparseSwitchMap.append( sparseSwitchMap.append(
currentCodeAddress + currentCodeAddress +
((OffsetInstruction)instruction.getInstruction()).getTargetAddressOffset(), ((OffsetInstruction)instruction).getTargetAddressOffset(),
currentCodeAddress); currentCodeAddress);
} }
instructionMap.append(currentCodeAddress, i); instructionMap.append(currentCodeAddress, i);
currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress); currentCodeAddress += instruction.getSize(currentCodeAddress);
} }
} else { } else {
packedSwitchMap = null; packedSwitchMap = null;
@ -281,31 +280,96 @@ public class MethodDefinition {
} }
private List<MethodItem> getMethodItems() { private List<MethodItem> getMethodItems() {
List<MethodItem> methodItems = new ArrayList<MethodItem>(); ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
if (encodedMethod.codeItem == null) { if (encodedMethod.codeItem == null) {
return methodItems; return methodItems;
} }
if (baksmali.registerInfo != 0 || baksmali.deodex || baksmali.verify) { if (baksmali.registerInfo != 0 || baksmali.deodex || baksmali.verify) {
methodAnalyzer.analyze(); addAnalyzedInstructionMethodItems(methodItems);
} else {
addInstructionMethodItems(methodItems);
}
ValidationException validationException = methodAnalyzer.getValidationException(); addTries(methodItems);
addDebugInfo(methodItems);
if (baksmali.useSequentialLabels) {
setLabelSequentialNumbers();
}
for (LabelMethodItem labelMethodItem: labelCache.getLabels()) {
if (labelMethodItem.isCommentedOut()) {
methodItems.add(new CommentedOutMethodItem(labelMethodItem));
} else {
methodItems.add(labelMethodItem);
}
}
Collections.sort(methodItems);
return methodItems;
}
private void addInstructionMethodItems(List<MethodItem> methodItems) {
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) {
Instruction instruction = instructions[i];
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction);
methodItems.add(methodItem);
if (i != instructions.length - 1) {
methodItems.add(new BlankMethodItem(currentCodeAddress));
}
if (baksmali.addCodeOffsets) {
methodItems.add(new MethodItem(currentCodeAddress) {
@Override
public double getSortOrder() {
return -1000;
}
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write("#@");
writer.printLongAsHex(codeAddress & 0xFFFFFFFF);
return true;
}
});
}
currentCodeAddress += instruction.getSize(currentCodeAddress);
}
}
private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex);
methodAnalyzer.analyze();
ValidationException validationException = methodAnalyzer.getValidationException();
if (validationException != null) {
methodItems.add(new CommentMethodItem(
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE));
} else if (baksmali.verify) {
methodAnalyzer.verify();
validationException = methodAnalyzer.getValidationException();
if (validationException != null) { if (validationException != null) {
methodItems.add(new CommentMethodItem( methodItems.add(new CommentMethodItem(
String.format("ValidationException: %s" ,validationException.getMessage()), String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE)); validationException.getCodeAddress(), Integer.MIN_VALUE));
} else if (baksmali.verify) {
methodAnalyzer.verify();
validationException = methodAnalyzer.getValidationException();
if (validationException != null) {
methodItems.add(new CommentMethodItem(
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE));
}
} }
} }
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions(); List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
AnalyzedInstruction lastInstruction = null; AnalyzedInstruction lastInstruction = null;
@ -325,8 +389,8 @@ public class MethodDefinition {
for (int i=0; i<instructions.size(); i++) { for (int i=0; i<instructions.size(); i++) {
AnalyzedInstruction instruction = instructions.get(i); AnalyzedInstruction instruction = instructions.get(i);
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this, MethodItem methodItem = InstructionMethodItemFactory.makeAnalyzedInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction.isDead(), instruction.getInstruction(), encodedMethod.codeItem, currentCodeAddress, instruction.isDead(), instruction.getInstruction(),
instruction == lastInstruction); instruction == lastInstruction);
if (instruction.isDead() && !instruction.getInstruction().getFormat().variableSizeFormat) { if (instruction.isDead() && !instruction.getInstruction().getFormat().variableSizeFormat) {
@ -350,9 +414,9 @@ public class MethodDefinition {
if (instruction.getInstruction().getFormat() == Format.UnresolvedNullReference) { if (instruction.getInstruction().getFormat() == Format.UnresolvedNullReference) {
methodItems.add(new CommentedOutMethodItem( methodItems.add(new CommentedOutMethodItem(
InstructionMethodItemFactory.makeInstructionFormatMethodItem(this, encodedMethod.codeItem, InstructionMethodItemFactory.makeAnalyzedInstructionFormatMethodItem(this,
currentCodeAddress, instruction.isDead(), instruction.getOriginalInstruction(), encodedMethod.codeItem, currentCodeAddress, instruction.isDead(),
false))); instruction.getOriginalInstruction(), false)));
} }
if (i != instructions.size() - 1) { if (i != instructions.size() - 1) {
@ -386,26 +450,6 @@ public class MethodDefinition {
currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress); currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress);
} }
addTries(methodItems);
addDebugInfo(methodItems);
if (baksmali.useSequentialLabels) {
setLabelSequentialNumbers();
}
for (LabelMethodItem labelMethodItem: labelCache.getLabels()) {
if (labelMethodItem.isCommentedOut()) {
methodItems.add(new CommentedOutMethodItem(labelMethodItem));
} else {
methodItems.add(labelMethodItem);
}
}
Collections.sort(methodItems);
return methodItems;
} }
private void addTries(List<MethodItem> methodItems) { private void addTries(List<MethodItem> methodItems) {