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

View File

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

View File

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

View File

@ -28,8 +28,11 @@
package org.jf.baksmali; package org.jf.baksmali;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.jf.baksmali.Adaptors.ClassDefinition; import org.jf.baksmali.Adaptors.ClassDefinition;
import org.jf.dexlib2.analysis.ClassPath;
import org.jf.dexlib2.analysis.InlineMethodResolver; import org.jf.dexlib2.analysis.InlineMethodResolver;
import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile; import org.jf.dexlib2.iface.DexFile;
@ -38,10 +41,7 @@ import org.jf.util.ClassFileNameHandler;
import org.jf.util.IndentingWriter; import org.jf.util.IndentingWriter;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -56,6 +56,7 @@ public class baksmali {
public static InlineMethodResolver inlineResolver = null; public static InlineMethodResolver inlineResolver = null;
public static int registerInfo = 0; public static int registerInfo = 0;
public static String bootClassPath; public static String bootClassPath;
public static ClassPath classPath = null;
public static SyntheticAccessorResolver syntheticAccessorResolver = null; public static SyntheticAccessorResolver syntheticAccessorResolver = null;
@ -76,43 +77,34 @@ public class baksmali {
baksmali.registerInfo = registerInfo; baksmali.registerInfo = registerInfo;
baksmali.bootClassPath = bootClassPath; baksmali.bootClassPath = bootClassPath;
//TODO: uncomment if (registerInfo != 0 || deodex) {
/*if (registerInfo != 0 || deodex || verify) {
try { try {
String[] extraBootClassPathArray = null; Iterable<String> extraBootClassPaths = null;
if (extraBootClassPath != null && extraBootClassPath.length() > 0) { if (extraBootClassPath != null && extraBootClassPath.length() > 0) {
assert extraBootClassPath.charAt(0) == ':'; assert extraBootClassPath.charAt(0) == ':';
extraBootClassPathArray = extraBootClassPath.substring(1).split(":"); extraBootClassPaths = Splitter.on(':').split(extraBootClassPath.substring(1));
}
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);
} else { } else {
String[] bootClassPathArray = null; extraBootClassPaths = ImmutableList.of();
if (bootClassPath != null) {
bootClassPathArray = bootClassPath.split(":");
}
ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray,
dexFilePath, dexFile, checkPackagePrivateAccess);
} }
if (inlineTable != null) { Iterable<String> bootClassPaths = null;
inlineResolver = new CustomInlineMethodResolver(inlineTable); 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) { } catch (Exception ex) {
System.err.println("\n\nError occured while loading boot class path files. Aborting."); System.err.println("\n\nError occured while loading boot class path files. Aborting.");
ex.printStackTrace(System.err); ex.printStackTrace(System.err);
System.exit(1); System.exit(1);
} }
}*/ }
File outputDirectoryFile = new File(outputDirectory); File outputDirectoryFile = new File(outputDirectory);
if (!outputDirectoryFile.exists()) { if (!outputDirectoryFile.exists()) {