Add support for generating register information

This commit is contained in:
Ben Gruver 2013-04-07 20:39:07 -07:00
parent 8887625162
commit c91b03ba45
4 changed files with 117 additions and 118 deletions

View File

@ -33,8 +33,12 @@ import org.jf.baksmali.Adaptors.Debug.DebugMethodItem;
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
import org.jf.baksmali.baksmali;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.Format;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.analysis.AnalysisException;
import org.jf.dexlib2.analysis.AnalyzedInstruction;
import org.jf.dexlib2.analysis.MethodAnalyzer;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
@ -73,7 +77,6 @@ public class MethodDefinition {
this.method = method;
this.methodImpl = methodImpl;
try {
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
@ -265,8 +268,11 @@ public class MethodDefinition {
private List<MethodItem> getMethodItems() {
ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
//TODO: addAnalyzedInstructionMethodItems
addInstructionMethodItems(methodItems);
if ((baksmali.registerInfo != 0) || (baksmali.deodex && needsAnalyzed())) {
addAnalyzedInstructionMethodItems(methodItems);
} else {
addInstructionMethodItems(methodItems);
}
addTries(methodItems);
if (baksmali.outputDebugInfo) {
@ -286,6 +292,15 @@ public class MethodDefinition {
return methodItems;
}
private boolean needsAnalyzed() {
for (Instruction instruction: methodImpl.getInstructions()) {
if (instruction.getOpcode().odexOnly()) {
return true;
}
}
return false;
}
private void addInstructionMethodItems(List<MethodItem> methodItems) {
int currentCodeAddress = 0;
for (int i=0; i<instructions.size(); i++) {
@ -338,43 +353,31 @@ public class MethodDefinition {
}
}
//TODO: uncomment
/*private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
MethodAnalyzer methodAnalyzer = new MethodAnalyzer(baksmali.classPath, method, baksmali.inlineResolver);
methodAnalyzer.analyze();
ValidationException validationException = methodAnalyzer.getValidationException();
if (validationException != null) {
AnalysisException analysisException = methodAnalyzer.getAnalysisException();
if (analysisException != 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) {
methodItems.add(new CommentMethodItem(
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE));
}
String.format("AnalysisException: %s" ,analysisException.getMessage()),
analysisException.codeAddress, Integer.MIN_VALUE));
}
List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
List<AnalyzedInstruction> instructions = methodAnalyzer.getAnalyzedInstructions();
int currentCodeAddress = 0;
for (int i=0; i<instructions.size(); i++) {
AnalyzedInstruction instruction = instructions.get(i);
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction.getInstruction());
MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(
this, currentCodeAddress, instruction.getInstruction());
methodItems.add(methodItem);
if (instruction.getInstruction().getFormat() == Format.UnresolvedOdexInstruction) {
if (instruction.getInstruction().getOpcode().format == Format.UnresolvedOdexInstruction) {
methodItems.add(new CommentedOutMethodItem(
InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
encodedMethod.codeItem, currentCodeAddress, instruction.getOriginalInstruction())));
InstructionMethodItemFactory.makeInstructionFormatMethodItem(
this, currentCodeAddress, instruction.getOriginalInstruction())));
}
if (i != instructions.size() - 1) {
@ -392,23 +395,24 @@ public class MethodDefinition {
@Override
public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write("#@");
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
return true;
}
});
}
if (baksmali.registerInfo != 0 && !instruction.getInstruction().getFormat().variableSizeFormat) {
if (baksmali.registerInfo != 0 && !instruction.getInstruction().getOpcode().format.isPayloadFormat) {
methodItems.add(
new PreInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
new PreInstructionRegisterInfoMethodItem(
methodAnalyzer, registerFormatter, instruction, currentCodeAddress));
methodItems.add(
new PostInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
new PostInstructionRegisterInfoMethodItem(registerFormatter, instruction, currentCodeAddress));
}
currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress);
currentCodeAddress += instruction.getInstruction().getCodeUnits();
}
}*/
}
private void addTries(List<MethodItem> methodItems) {
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();

View File

@ -28,16 +28,26 @@
package org.jf.baksmali.Adaptors;
//TODO: uncomment
/*public class PostInstructionRegisterInfoMethodItem extends MethodItem {
private final AnalyzedInstruction analyzedInstruction;
private final MethodAnalyzer methodAnalyzer;
import org.jf.baksmali.baksmali;
import org.jf.baksmali.main;
import org.jf.dexlib2.analysis.AnalyzedInstruction;
import org.jf.dexlib2.analysis.RegisterType;
import org.jf.util.IndentingWriter;
public PostInstructionRegisterInfoMethodItem(AnalyzedInstruction analyzedInstruction, MethodAnalyzer methodAnalyzer,
int codeAddress) {
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.BitSet;
public class PostInstructionRegisterInfoMethodItem extends MethodItem {
@Nonnull private final RegisterFormatter registerFormatter;
@Nonnull private final AnalyzedInstruction analyzedInstruction;
public PostInstructionRegisterInfoMethodItem(@Nonnull RegisterFormatter registerFormatter,
@Nonnull AnalyzedInstruction analyzedInstruction,
int codeAddress) {
super(codeAddress);
this.registerFormatter = registerFormatter;
this.analyzedInstruction = analyzedInstruction;
this.methodAnalyzer = methodAnalyzer;
}
@Override
@ -74,8 +84,6 @@ package org.jf.baksmali.Adaptors;
}
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers) throws IOException {
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
int registerNum = registers.nextSetBit(0);
if (registerNum < 0) {
return false;
@ -83,19 +91,13 @@ package org.jf.baksmali.Adaptors;
writer.write('#');
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum);
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
registerFormatter.writeTo(writer, registerNum);
writer.write('=');
if (registerType == null) {
writer.write("null");
} else {
registerType.writeTo(writer);
}
registerType.writeTo(writer);
writer.write(';');
}
return true;
}
}*/
}

View File

@ -28,16 +28,31 @@
package org.jf.baksmali.Adaptors;
//TODO: uncomment
/*public class PreInstructionRegisterInfoMethodItem extends MethodItem {
private final AnalyzedInstruction analyzedInstruction;
private final MethodAnalyzer methodAnalyzer;
import org.jf.baksmali.baksmali;
import org.jf.baksmali.main;
import org.jf.dexlib2.analysis.AnalyzedInstruction;
import org.jf.dexlib2.analysis.MethodAnalyzer;
import org.jf.dexlib2.analysis.RegisterType;
import org.jf.dexlib2.iface.instruction.*;
import org.jf.util.IndentingWriter;
public PreInstructionRegisterInfoMethodItem(AnalyzedInstruction analyzedInstruction, MethodAnalyzer methodAnalyzer,
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.BitSet;
public class PreInstructionRegisterInfoMethodItem extends MethodItem {
@Nonnull private final MethodAnalyzer methodAnalyzer;
@Nonnull private final RegisterFormatter registerFormatter;
@Nonnull private final AnalyzedInstruction analyzedInstruction;
public PreInstructionRegisterInfoMethodItem(@Nonnull MethodAnalyzer methodAnalyzer,
@Nonnull RegisterFormatter registerFormatter,
@Nonnull AnalyzedInstruction analyzedInstruction,
int codeAddress) {
super(codeAddress);
this.analyzedInstruction = analyzedInstruction;
this.methodAnalyzer = methodAnalyzer;
this.registerFormatter = registerFormatter;
this.analyzedInstruction = analyzedInstruction;
}
@Override
@ -84,25 +99,25 @@ package org.jf.baksmali.Adaptors;
RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getStartRegister(),
instruction.getStartRegister() + instruction.getRegCount());
instruction.getStartRegister() + instruction.getRegisterCount());
} else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) {
FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction();
int regCount = instruction.getRegCount();
int regCount = instruction.getRegisterCount();
switch (regCount) {
case 5:
registers.set(instruction.getRegisterA());
//fall through
case 4:
registers.set(instruction.getRegisterG());
//fall through
case 3:
case 4:
registers.set(instruction.getRegisterF());
//fall through
case 2:
case 3:
registers.set(instruction.getRegisterE());
//fall through
case 1:
case 2:
registers.set(instruction.getRegisterD());
//fall through
case 1:
registers.set(instruction.getRegisterC());
}
} else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction();
@ -113,8 +128,8 @@ package org.jf.baksmali.Adaptors;
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getRegisterA());
registers.set(instruction.getRegisterB());
} else if (analyzedInstruction.getInstruction() instanceof SingleRegisterInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.getInstruction();
} else if (analyzedInstruction.getInstruction() instanceof OneRegisterInstruction) {
OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.getInstruction();
registers.set(instruction.getRegisterA());
}
}
@ -137,19 +152,13 @@ package org.jf.baksmali.Adaptors;
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) {
registers.set(registerNum);
continue;
}
}
}
}
private void addParamRegs(BitSet registers, int registerCount) {
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
int parameterRegisterCount = encodedMethod.method.getPrototype().getParameterRegisterCount();
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
parameterRegisterCount++;
}
int parameterRegisterCount = methodAnalyzer.getParamRegisterCount();
registers.set(registerCount-parameterRegisterCount, registerCount);
}
@ -159,8 +168,6 @@ package org.jf.baksmali.Adaptors;
return false;
}
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
boolean firstRegister = true;
for (int registerNum=0; registerNum<registerCount; registerNum++) {
@ -169,7 +176,7 @@ package org.jf.baksmali.Adaptors;
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
if (predecessorRegisterType.category != RegisterType.Category.Unknown &&
if (predecessorRegisterType.category != RegisterType.UNKNOWN &&
predecessorRegisterType != mergedRegisterType) {
addRegister = true;
@ -188,7 +195,7 @@ package org.jf.baksmali.Adaptors;
}
writer.write('#');
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
registerFormatter.writeTo(writer, registerNum);
writer.write('=');
analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer);
writer.write(":merge{");
@ -221,10 +228,7 @@ package org.jf.baksmali.Adaptors;
return !firstRegister;
}
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers,
boolean addNewline) throws IOException {
ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod();
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers, boolean addNewline) throws IOException {
int registerNum = registers.nextSetBit(0);
if (registerNum < 0) {
return false;
@ -233,21 +237,18 @@ package org.jf.baksmali.Adaptors;
if (addNewline) {
writer.write('\n');
}
writer.write('#');
for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum);
registerFormatter.writeTo(writer, registerNum);
writer.write('=');
if (registerType == null) {
writer.write("null");
} else {
registerType.writeTo(writer);
}
registerType.writeTo(writer);
writer.write(';');
}
return true;
}
}*/
}

View File

@ -28,8 +28,11 @@
package org.jf.baksmali;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.jf.baksmali.Adaptors.ClassDefinition;
import org.jf.dexlib2.analysis.ClassPath;
import org.jf.dexlib2.analysis.InlineMethodResolver;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
@ -38,10 +41,7 @@ import org.jf.util.ClassFileNameHandler;
import org.jf.util.IndentingWriter;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -56,6 +56,7 @@ public class baksmali {
public static InlineMethodResolver inlineResolver = null;
public static int registerInfo = 0;
public static String bootClassPath;
public static ClassPath classPath = null;
public static SyntheticAccessorResolver syntheticAccessorResolver = null;
@ -76,43 +77,34 @@ public class baksmali {
baksmali.registerInfo = registerInfo;
baksmali.bootClassPath = bootClassPath;
//TODO: uncomment
/*if (registerInfo != 0 || deodex || verify) {
if (registerInfo != 0 || deodex) {
try {
String[] extraBootClassPathArray = null;
Iterable<String> extraBootClassPaths = null;
if (extraBootClassPath != null && extraBootClassPath.length() > 0) {
assert extraBootClassPath.charAt(0) == ':';
extraBootClassPathArray = extraBootClassPath.substring(1).split(":");
}
if (dexFile.isOdex() && bootClassPath == null) {
//ext.jar is a special case - it is typically the 2nd jar in the boot class path, but it also
//depends on classes in framework.jar (typically the 3rd jar in the BCP). If the user didn't
//specify a -c option, we should add framework.jar to the boot class path by default, so that it
//"just works"
if (extraBootClassPathArray == null && isExtJar(dexFilePath)) {
extraBootClassPathArray = new String[] {"framework.jar"};
}
ClassPath.InitializeClassPathFromOdex(classPathDirs, extraBootClassPathArray, dexFilePath, dexFile,
checkPackagePrivateAccess);
extraBootClassPaths = Splitter.on(':').split(extraBootClassPath.substring(1));
} else {
String[] bootClassPathArray = null;
if (bootClassPath != null) {
bootClassPathArray = bootClassPath.split(":");
}
ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray,
dexFilePath, dexFile, checkPackagePrivateAccess);
extraBootClassPaths = ImmutableList.of();
}
if (inlineTable != null) {
inlineResolver = new CustomInlineMethodResolver(inlineTable);
Iterable<String> bootClassPaths = null;
if (bootClassPath != null) {
bootClassPaths = Splitter.on(':').split(bootClassPath);
}
classPath = ClassPath.fromClassPath(Arrays.asList(classPathDirs),
Iterables.concat(bootClassPaths, extraBootClassPaths), dexFile);
// TODO: uncomment
/*if (inlineTable != null) {
inlineResolver = new CustomInlineMethodResolver(inlineTable);
}*/
} catch (Exception ex) {
System.err.println("\n\nError occured while loading boot class path files. Aborting.");
ex.printStackTrace(System.err);
System.exit(1);
}
}*/
}
File outputDirectoryFile = new File(outputDirectory);
if (!outputDirectoryFile.exists()) {