Add finer grained control of what register information is printed out

git-svn-id: https://smali.googlecode.com/svn/trunk@625 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2010-02-14 20:04:59 +00:00
parent da69b22d6f
commit 1c56c7e750
6 changed files with 342 additions and 39 deletions

View File

@ -30,15 +30,14 @@ package org.jf.baksmali.Adaptors;
import org.jf.baksmali.Adaptors.Format.*; import org.jf.baksmali.Adaptors.Format.*;
import org.jf.baksmali.baksmali; import org.jf.baksmali.baksmali;
import org.jf.baksmali.main;
import org.jf.dexlib.*; import org.jf.dexlib.*;
import org.jf.dexlib.Code.*;
import org.jf.dexlib.Code.Analysis.AnalyzedInstruction; import org.jf.dexlib.Code.Analysis.AnalyzedInstruction;
import org.jf.dexlib.Code.Analysis.MethodAnalyzer; import org.jf.dexlib.Code.Analysis.MethodAnalyzer;
import org.jf.dexlib.Code.Analysis.RegisterType; import org.jf.dexlib.Code.Analysis.RegisterType;
import org.jf.dexlib.Code.Analysis.ValidationException; import org.jf.dexlib.Code.Analysis.ValidationException;
import org.jf.dexlib.Debug.DebugInstructionIterator; import org.jf.dexlib.Debug.DebugInstructionIterator;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Code.OffsetInstruction;
import org.jf.dexlib.Util.AccessFlags; import org.jf.dexlib.Util.AccessFlags;
import org.antlr.stringtemplate.StringTemplateGroup; import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate; import org.antlr.stringtemplate.StringTemplate;
@ -57,6 +56,8 @@ public class MethodDefinition {
private final SparseIntArray sparseSwitchMap; private final SparseIntArray sparseSwitchMap;
private final SparseIntArray instructionMap; private final SparseIntArray instructionMap;
private final int registerCount;
public MethodDefinition(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod) { public MethodDefinition(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod) {
this.stg = stg; this.stg = stg;
this.encodedMethod = encodedMethod; this.encodedMethod = encodedMethod;
@ -71,6 +72,8 @@ public class MethodDefinition {
sparseSwitchMap = new SparseIntArray(1); sparseSwitchMap = new SparseIntArray(1);
instructionMap = new SparseIntArray(instructions.length); instructionMap = new SparseIntArray(instructions.length);
registerCount = encodedMethod.codeItem.getRegisterCount();
int currentCodeAddress = 0; int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) { for (int i=0; i<instructions.length; i++) {
AnalyzedInstruction instruction = instructions[i]; AnalyzedInstruction instruction = instructions[i];
@ -91,6 +94,7 @@ public class MethodDefinition {
sparseSwitchMap = null; sparseSwitchMap = null;
instructionMap = null; instructionMap = null;
methodAnalyzer = null; methodAnalyzer = null;
registerCount = 0;
} }
} }
@ -243,18 +247,22 @@ public class MethodDefinition {
} }
AnalyzedInstruction[] instructions; AnalyzedInstruction[] instructions;
if (baksmali.verboseRegisterInfo) { if (baksmali.registerInfo != 0) {
instructions = methodAnalyzer.analyze(); instructions = methodAnalyzer.analyze();
ValidationException validationException = methodAnalyzer.getValidationException(); ValidationException validationException = methodAnalyzer.getValidationException();
if (validationException != null) { if (validationException != null) {
methodItems.add(new CommentMethodItem(stg, validationException.getMessage(), methodItems.add(new CommentMethodItem(stg,
String.format("ValidationException: %s" ,validationException.getMessage()),
validationException.getCodeAddress(), Integer.MIN_VALUE)); validationException.getCodeAddress(), Integer.MIN_VALUE));
} }
} else { } else {
instructions = methodAnalyzer.makeInstructionArray(); instructions = methodAnalyzer.makeInstructionArray();
} }
BitSet printPreRegister = new BitSet(registerCount);
BitSet printPostRegister = new BitSet(registerCount);
int currentCodeAddress = 0; int currentCodeAddress = 0;
for (int i=0; i<instructions.length; i++) { for (int i=0; i<instructions.length; i++) {
AnalyzedInstruction instruction = instructions[i]; AnalyzedInstruction instruction = instructions[i];
@ -266,15 +274,51 @@ public class MethodDefinition {
methodItems.add(new BlankMethodItem(stg, currentCodeAddress)); methodItems.add(new BlankMethodItem(stg, currentCodeAddress));
} }
if (baksmali.verboseRegisterInfo) { if (baksmali.registerInfo != 0) {
if (instruction.getPredecessorCount() > 1 || i == 0) { printPreRegister.clear();
methodItems.add(new CommentMethodItem(stg, getPreInstructionRegisterString(instruction), printPostRegister.clear();
currentCodeAddress, Integer.MIN_VALUE));
}
methodItems.add(new CommentMethodItem(stg, getPostInstructionRegisterString(instruction),
currentCodeAddress, Integer.MAX_VALUE-1));
}
if ((baksmali.registerInfo & main.ALL) != 0) {
printPreRegister.set(0, registerCount);
printPostRegister.set(0, registerCount);
} else {
if ((baksmali.registerInfo & main.ALLPRE) != 0) {
printPreRegister.set(0, registerCount);
} else {
if ((baksmali.registerInfo & main.ARGS) != 0) {
addArgsRegs(printPreRegister, instruction);
}
if ((baksmali.registerInfo & main.MERGE) != 0) {
addMergeRegs(printPreRegister, instructions, i);
} else if ((baksmali.registerInfo & main.FULLMERGE) != 0 &&
(i == 0 || instruction.isBeginningInstruction())) {
addParamRegs(printPreRegister);
}
}
if ((baksmali.registerInfo & main.ALLPOST) != 0) {
printPostRegister.set(0, registerCount);
} else if ((baksmali.registerInfo & main.DEST) != 0) {
addDestRegs(printPostRegister, instruction);
}
}
if ((baksmali.registerInfo & main.FULLMERGE) != 0) {
addFullMergeRegs(printPreRegister, methodItems, methodAnalyzer, i, currentCodeAddress);
}
if (!printPreRegister.isEmpty()) {
methodItems.add(new CommentMethodItem(stg,
getPreInstructionRegisterString(instruction, printPreRegister),
currentCodeAddress, 99.9));
}
if (!printPostRegister.isEmpty()) {
methodItems.add(new CommentMethodItem(stg,
getPostInstructionRegisterString(instruction, printPostRegister),
currentCodeAddress, 100.1));
}
}
currentCodeAddress += instruction.instruction.getSize(currentCodeAddress); currentCodeAddress += instruction.instruction.getSize(currentCodeAddress);
} }
@ -300,13 +344,168 @@ public class MethodDefinition {
return methodItems; return methodItems;
} }
private String getPreInstructionRegisterString(AnalyzedInstruction instruction) { private void addArgsRegs(BitSet printPreRegister, AnalyzedInstruction analyzedInstruction) {
if (analyzedInstruction.instruction instanceof RegisterRangeInstruction) {
RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction;
printPreRegister.set(instruction.getStartRegister(),
instruction.getStartRegister() + instruction.getRegCount());
} else if (analyzedInstruction.instruction instanceof FiveRegisterInstruction) {
FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction;
int regCount = instruction.getRegCount();
switch (regCount) {
case 5:
printPreRegister.set(instruction.getRegisterA());
//fall through
case 4:
printPreRegister.set(instruction.getRegisterG());
//fall through
case 3:
printPreRegister.set(instruction.getRegisterF());
//fall through
case 2:
printPreRegister.set(instruction.getRegisterE());
//fall through
case 1:
printPreRegister.set(instruction.getRegisterD());
}
} else if (analyzedInstruction.instruction instanceof ThreeRegisterInstruction) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
printPreRegister.set(instruction.getRegisterA());
printPreRegister.set(instruction.getRegisterB());
printPreRegister.set(instruction.getRegisterC());
} else if (analyzedInstruction.instruction instanceof TwoRegisterInstruction) {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
printPreRegister.set(instruction.getRegisterA());
printPreRegister.set(instruction.getRegisterB());
} else if (analyzedInstruction.instruction instanceof SingleRegisterInstruction) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
printPreRegister.set(instruction.getRegisterA());
}
}
private void addFullMergeRegs(BitSet printPreRegister, List<MethodItem> methodItems, MethodAnalyzer methodAnalyzer,
int instructionNum, int currentCodeAddress) {
if (instructionNum == 0) {
return;
}
//MethodAnalyzer cached the analyzedInstructions, so we're not actually re-analyzing, just getting the
//instructions that have already been analyzed
AnalyzedInstruction[] instructions = methodAnalyzer.analyze();
AnalyzedInstruction instruction = instructions[instructionNum];
if (instruction.getPredecessorCount() <= 1) {
return;
}
StringBuffer sb = new StringBuffer();
for (int registerNum=0; registerNum<registerCount; registerNum++) {
sb.setLength(0);
sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem, registerNum));
sb.append('=');
sb.append(instruction.getPreInstructionRegisterType(registerNum));
sb.append(":merge{");
RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum);
boolean addRegister = false;
boolean first = true;
for (AnalyzedInstruction predecessor: instruction.getPredecessors()) {
RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
if (!first) {
sb.append(',');
if (!addRegister && mergedRegisterType != predecessorRegisterType) {
addRegister = true;
}
}
if (predecessor.getInstructionIndex() == -1) {
//the fake "StartOfMethod" instruction
sb.append("Start:");
} else {
sb.append("0x");
sb.append(Integer.toHexString(methodAnalyzer.getInstructionAddress(predecessor)));
sb.append(':');
}
sb.append(predecessor.getPostInstructionRegisterType(registerNum).toString());
first = false;
}
if (!addRegister) {
continue;
}
sb.append("}");
methodItems.add(new CommentMethodItem(stg, sb.toString(), currentCodeAddress, 99.8));
printPreRegister.clear(registerNum);
}
}
private void addMergeRegs(BitSet printPreRegister, AnalyzedInstruction instructions[], int instructionNum) {
//MethodAnalyzer cached the analyzedInstructions, so we're not actually re-analyzing, just getting the
//instructions that have already been analyzed
AnalyzedInstruction instruction = instructions[instructionNum];
if (instructionNum == 0) {
addParamRegs(printPreRegister);
} else {
if (instruction.isBeginningInstruction()) {
addParamRegs(printPreRegister);
}
if (instruction.getPredecessorCount() <= 1) {
//in the common case of an instruction that only has a single predecessor which is the previous
//instruction, the pre-instruction registers will always match the previous instruction's
//post-instruction registers
return;
}
for (int registerNum=0; registerNum<registerCount; registerNum++) {
RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum);
for (AnalyzedInstruction predecessor: instruction.getPredecessors()) {
if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) {
printPreRegister.set(registerNum);
continue;
}
}
}
}
}
private void addParamRegs(BitSet printPreRegister) {
int registerCount = encodedMethod.codeItem.getRegisterCount();
int parameterRegisterCount = encodedMethod.method.getPrototype().getParameterRegisterCount();
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
parameterRegisterCount++;
}
printPreRegister.set(registerCount-parameterRegisterCount, registerCount);
}
private void addDestRegs(BitSet printPostRegister, AnalyzedInstruction analyzedInstruction) {
for (int registerNum=0; registerNum<registerCount; registerNum++) {
if (analyzedInstruction.getPreInstructionRegisterType(registerNum) !=
analyzedInstruction.getPostInstructionRegisterType(registerNum)) {
printPostRegister.set(registerNum);
}
}
}
private String getPreInstructionRegisterString(AnalyzedInstruction instruction, BitSet registers) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i=0; i<instruction.getRegisterCount(); i++) { for (int registerNum = registers.nextSetBit(0); registerNum >= 0;
RegisterType registerType = instruction.getPreInstructionRegisterType(i); registerNum = registers.nextSetBit(registerNum + 1)) {
sb.append("v");
sb.append(i); RegisterType registerType = instruction.getPreInstructionRegisterType(registerNum);
sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem,registerNum));
sb.append("="); sb.append("=");
if (registerType == null) { if (registerType == null) {
sb.append("null"); sb.append("null");
@ -319,22 +518,26 @@ public class MethodDefinition {
return sb.toString(); return sb.toString();
} }
private String getPostInstructionRegisterString(AnalyzedInstruction instruction) { private String getPostInstructionRegisterString(AnalyzedInstruction instruction, BitSet registers) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i=0; i<instruction.getRegisterCount(); i++) { for (int registerNum = registers.nextSetBit(0); registerNum >= 0;
RegisterType registerType = instruction.getPostInstructionRegisterType(i); registerNum = registers.nextSetBit(registerNum + 1)) {
sb.append("v");
sb.append(i); RegisterType registerType = instruction.getPostInstructionRegisterType(registerNum);
sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem,registerNum));
sb.append("="); sb.append("=");
sb.append(registerType.toString()); if (registerType == null) {
sb.append("null");
} else {
sb.append(registerType.toString());
}
sb.append(";"); sb.append(";");
} }
return sb.toString(); return sb.toString();
} }
private void addTries(List<MethodItem> methodItems) { private void addTries(List<MethodItem> methodItems) {
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) { if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) {
return; return;

View File

@ -45,23 +45,23 @@ public class baksmali {
public static boolean useLocalsDirective = false; public static boolean useLocalsDirective = false;
public static boolean useSequentialLabels = false; public static boolean useSequentialLabels = false;
public static boolean outputDebugInfo = true; public static boolean outputDebugInfo = true;
public static boolean verboseRegisterInfo = false; public static int registerInfo = 0;
public static String bootClassPath; public static String bootClassPath;
public static DeodexUtil deodexUtil = null; public static DeodexUtil deodexUtil = null;
public static void disassembleDexFile(DexFile dexFile, Deodexerant deodexerant, String outputDirectory, public static void disassembleDexFile(DexFile dexFile, Deodexerant deodexerant, String outputDirectory,
String bootClassPath, boolean noParameterRegisters, String bootClassPath, boolean noParameterRegisters,
boolean useLocalsDirective, boolean useSequentialLabels, boolean useLocalsDirective, boolean useSequentialLabels,
boolean outputDebugInfo, boolean verboseRegisterInfo) boolean outputDebugInfo, int registerInfo)
{ {
baksmali.noParameterRegisters = noParameterRegisters; baksmali.noParameterRegisters = noParameterRegisters;
baksmali.useLocalsDirective = useLocalsDirective; baksmali.useLocalsDirective = useLocalsDirective;
baksmali.useSequentialLabels = useSequentialLabels; baksmali.useSequentialLabels = useSequentialLabels;
baksmali.outputDebugInfo = outputDebugInfo; baksmali.outputDebugInfo = outputDebugInfo;
baksmali.verboseRegisterInfo = verboseRegisterInfo; baksmali.registerInfo = registerInfo;
baksmali.bootClassPath = bootClassPath; baksmali.bootClassPath = bootClassPath;
if (verboseRegisterInfo) { if (registerInfo != 0) {
ClassPath.InitializeClassPath(bootClassPath==null?null:bootClassPath.split(":"), dexFile); ClassPath.InitializeClassPath(bootClassPath==null?null:bootClassPath.split(":"), dexFile);
} }

View File

@ -31,6 +31,14 @@ public class main {
private static final Options options; private static final Options options;
public static final int ALL = 1;
public static final int ALLPRE = 2;
public static final int ALLPOST = 4;
public static final int ARGS = 8;
public static final int DEST = 16;
public static final int MERGE = 32;
public static final int FULLMERGE = 64;
static { static {
options = new Options(); options = new Options();
buildOptions(); buildOptions();
@ -75,7 +83,8 @@ public class main {
boolean useLocalsDirective = false; boolean useLocalsDirective = false;
boolean useSequentialLabels = false; boolean useSequentialLabels = false;
boolean outputDebugInfo = true; boolean outputDebugInfo = true;
boolean verboseRegisterInfo = false;
int registerInfo = 0;
String outputDirectory = "out"; String outputDirectory = "out";
String dumpFileName = null; String dumpFileName = null;
@ -147,7 +156,36 @@ public class main {
} }
if (commandLine.hasOption("r")) { if (commandLine.hasOption("r")) {
verboseRegisterInfo = true; String[] values = commandLine.getOptionValues('r');
if (values == null || values.length == 0) {
registerInfo = ARGS | DEST | MERGE;
} else {
for (String value: values) {
if (value.equalsIgnoreCase("ALL")) {
registerInfo |= ALL;
} else if (value.equalsIgnoreCase("ALLPRE")) {
registerInfo |= ALLPRE;
} else if (value.equalsIgnoreCase("ALLPOST")) {
registerInfo |= ALLPOST;
} else if (value.equalsIgnoreCase("ARGS")) {
registerInfo |= ARGS;
} else if (value.equalsIgnoreCase("DEST")) {
registerInfo |= DEST;
} else if (value.equalsIgnoreCase("MERGE")) {
registerInfo |= MERGE;
} else if (value.equalsIgnoreCase("FULLMERGE")) {
registerInfo |= FULLMERGE;
} else {
usage();
return;
}
}
if ((registerInfo & FULLMERGE) != 0) {
registerInfo &= ~MERGE;
}
}
} }
if (commandLine.hasOption("c")) { if (commandLine.hasOption("c")) {
@ -210,7 +248,7 @@ public class main {
if (disassemble) { if (disassemble) {
baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, bootClassPath, noParameterRegisters, baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, bootClassPath, noParameterRegisters,
useLocalsDirective, useSequentialLabels, outputDebugInfo, verboseRegisterInfo); useLocalsDirective, useSequentialLabels, outputDebugInfo, registerInfo);
} }
if ((doDump || write) && !dexFile.isOdex()) { if ((doDump || write) && !dexFile.isOdex()) {
@ -238,6 +276,7 @@ public class main {
*/ */
private static void usage() { private static void usage() {
HelpFormatter formatter = new HelpFormatter(); HelpFormatter formatter = new HelpFormatter();
formatter.setWidth(100);
formatter.printHelp("java -jar baksmali.jar [options] <dex-file>", formatter.printHelp("java -jar baksmali.jar [options] <dex-file>",
"disassembles and/or dumps a dex file", options, ""); "disassembles and/or dumps a dex file", options, "");
} }
@ -319,8 +358,18 @@ public class main {
.withDescription("don't write out debug info (.local, .param, .line, etc.)") .withDescription("don't write out debug info (.local, .param, .line, etc.)")
.create("b"); .create("b");
Option verboseRegisterInfoOption = OptionBuilder.withLongOpt("verbose-registers") Option registerInfoOption = OptionBuilder.withLongOpt("register-info")
.withDescription("print verbose register type information for each instruction") .hasOptionalArgs()
.withArgName("REGISTER_INFO_TYPES")
.withValueSeparator(',')
.withDescription("print the specificed type(s) of register information for each instruction. " +
"\"ARGS,DEST,MERGE\" is the default if no types are specified.\nValid values are:\nALL: all " +
"pre- and post-instruction registers.\nALLPRE: all pre-instruction registers\nALLPOST: all " +
"post-instruction registers\nARGS: any pre-instruction registers used as arguments to the " +
"instruction\nDEST: the post-instruction destination register, if any\nMERGE: Any " +
"pre-instruction register has been merged from more than 1 different post-instruction " +
"register from its predecessors\nFULLMERGE: For each register that would be printed by " +
"MERGE, also show the incoming register types that were merged")
.create("r"); .create("r");
Option classPathOption = OptionBuilder.withLongOpt("bootclasspath") Option classPathOption = OptionBuilder.withLongOpt("bootclasspath")
@ -342,7 +391,7 @@ public class main {
options.addOption(useLocalsOption); options.addOption(useLocalsOption);
options.addOption(sequentialLabelsOption); options.addOption(sequentialLabelsOption);
options.addOption(noDebugInfoOption); options.addOption(noDebugInfoOption);
options.addOption(verboseRegisterInfoOption); options.addOption(registerInfoOption);
options.addOption(classPathOption); options.addOption(classPathOption);
} }
} }

View File

@ -6,7 +6,9 @@ import org.jf.dexlib.ItemType;
import org.jf.dexlib.MethodIdItem; import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.Util.ExceptionWithContext; import org.jf.dexlib.Util.ExceptionWithContext;
import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
public class AnalyzedInstruction { public class AnalyzedInstruction {
/** /**
@ -63,7 +65,24 @@ public class AnalyzedInstruction {
return predecessors.size(); return predecessors.size();
} }
public List<AnalyzedInstruction> getPredecessors() {
return Collections.unmodifiableList(predecessors);
}
private boolean checkPredecessorSorted(AnalyzedInstruction predecessor) {
if (predecessors.size() == 0) {
return true;
}
if (predecessor.getInstructionIndex() <= predecessors.getLast().getInstructionIndex()) {
return false;
}
return true;
}
protected void addPredecessor(AnalyzedInstruction predecessor) { protected void addPredecessor(AnalyzedInstruction predecessor) {
assert checkPredecessorSorted(predecessor);
predecessors.add(predecessor); predecessors.add(predecessor);
} }
@ -80,6 +99,34 @@ public class AnalyzedInstruction {
return true; return true;
} }
public int getSuccessorCount() {
return successors.size();
}
public List<AnalyzedInstruction> getSuccesors() {
return Collections.unmodifiableList(successors);
}
/**
* Is this instruction a "beginning instruction". A beginning instruction is defined to be an instruction
* that can be the first successfully executed instruction in the method. The first instruction is always a
* beginning instruction. If the first instruction can throw an exception, and is covered by a try block, then
* the first instruction of any exception handler for that try block is also a beginning instruction. And likewise,
* if any of those instructions can throw an exception and are covered by try blocks, the first instruction of the
* corresponding exception handler is a beginning instruction, etc.
* @return a boolean value indicating whether this instruction is a beginning instruction
*/
public boolean isBeginningInstruction() {
if (predecessors.size() == 0) {
return false;
}
if (predecessors.getFirst().instructionIndex == -1) {
return true;
}
return false;
}
/* /*
* Sets the "post-instruction" register type as indicated. This should only be used to set * Sets the "post-instruction" register type as indicated. This should only be used to set
* the method parameter types for the "start of method" instruction, or to set the register * the method parameter types for the "start of method" instruction, or to set the register

View File

@ -94,7 +94,7 @@ public class ClassPath {
if (classType.charAt(0) == '[') { if (classType.charAt(0) == '[') {
return theClassPath.createArrayClassDef(classType); return theClassPath.createArrayClassDef(classType);
} else { } else {
//TODO: we should output a warning //TODO: we should output a warning
return theClassPath.createUnresolvedClassDef(classType); return theClassPath.createUnresolvedClassDef(classType);
} }
} }
@ -571,12 +571,12 @@ public class ClassPath {
if (interfaces != null) { if (interfaces != null) {
for (TypeIdItem interfaceType: interfaces.getTypes()) { for (TypeIdItem interfaceType: interfaces.getTypes()) {
ClassDef interfaceDef = ClassPath.getClassDef(interfaceType.getTypeDescriptor()); ClassDef interfaceDef = ClassPath.getClassDef(interfaceType.getTypeDescriptor());
assert interfaceDef.isInterface; assert interfaceDef.isInterface();
implementedInterfaceSet.add(interfaceDef); implementedInterfaceSet.add(interfaceDef);
interfaceDef = interfaceDef.getSuperclass(); interfaceDef = interfaceDef.getSuperclass();
while (!interfaceDef.getClassType().equals("Ljava/lang/Object;")) { while (!interfaceDef.getClassType().equals("Ljava/lang/Object;")) {
assert interfaceDef.isInterface; assert interfaceDef.isInterface();
implementedInterfaceSet.add(interfaceDef); implementedInterfaceSet.add(interfaceDef);
interfaceDef = interfaceDef.getSuperclass(); interfaceDef = interfaceDef.getSuperclass();
} }

View File

@ -183,6 +183,10 @@ public class MethodAnalyzer {
(encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0; (encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0;
} }
public AnalyzedInstruction getStartOfMethod() {
return startOfMethod;
}
public AnalyzedInstruction[] makeInstructionArray() { public AnalyzedInstruction[] makeInstructionArray() {
AnalyzedInstruction[] instructionArray = new AnalyzedInstruction[instructions.size()]; AnalyzedInstruction[] instructionArray = new AnalyzedInstruction[instructions.size()];
for (int i=0; i<instructions.size(); i++) { for (int i=0; i<instructions.size(); i++) {
@ -214,7 +218,7 @@ public class MethodAnalyzer {
return registerTypes; return registerTypes;
} }
private int getInstructionAddress(AnalyzedInstruction instruction) { public int getInstructionAddress(AnalyzedInstruction instruction) {
return instructions.keyAt(instruction.instructionIndex); return instructions.keyAt(instruction.instructionIndex);
} }