mirror of
https://github.com/revanced/smali.git
synced 2025-05-29 12:20:11 +02:00
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:
parent
da69b22d6f
commit
1c56c7e750
@ -30,15 +30,14 @@ package org.jf.baksmali.Adaptors;
|
||||
|
||||
import org.jf.baksmali.Adaptors.Format.*;
|
||||
import org.jf.baksmali.baksmali;
|
||||
import org.jf.baksmali.main;
|
||||
import org.jf.dexlib.*;
|
||||
import org.jf.dexlib.Code.*;
|
||||
import org.jf.dexlib.Code.Analysis.AnalyzedInstruction;
|
||||
import org.jf.dexlib.Code.Analysis.MethodAnalyzer;
|
||||
import org.jf.dexlib.Code.Analysis.RegisterType;
|
||||
import org.jf.dexlib.Code.Analysis.ValidationException;
|
||||
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.antlr.stringtemplate.StringTemplateGroup;
|
||||
import org.antlr.stringtemplate.StringTemplate;
|
||||
@ -57,6 +56,8 @@ public class MethodDefinition {
|
||||
private final SparseIntArray sparseSwitchMap;
|
||||
private final SparseIntArray instructionMap;
|
||||
|
||||
private final int registerCount;
|
||||
|
||||
public MethodDefinition(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod) {
|
||||
this.stg = stg;
|
||||
this.encodedMethod = encodedMethod;
|
||||
@ -71,6 +72,8 @@ public class MethodDefinition {
|
||||
sparseSwitchMap = new SparseIntArray(1);
|
||||
instructionMap = new SparseIntArray(instructions.length);
|
||||
|
||||
registerCount = encodedMethod.codeItem.getRegisterCount();
|
||||
|
||||
int currentCodeAddress = 0;
|
||||
for (int i=0; i<instructions.length; i++) {
|
||||
AnalyzedInstruction instruction = instructions[i];
|
||||
@ -91,6 +94,7 @@ public class MethodDefinition {
|
||||
sparseSwitchMap = null;
|
||||
instructionMap = null;
|
||||
methodAnalyzer = null;
|
||||
registerCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,18 +247,22 @@ public class MethodDefinition {
|
||||
}
|
||||
|
||||
AnalyzedInstruction[] instructions;
|
||||
if (baksmali.verboseRegisterInfo) {
|
||||
if (baksmali.registerInfo != 0) {
|
||||
instructions = methodAnalyzer.analyze();
|
||||
|
||||
ValidationException validationException = methodAnalyzer.getValidationException();
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
instructions = methodAnalyzer.makeInstructionArray();
|
||||
}
|
||||
|
||||
BitSet printPreRegister = new BitSet(registerCount);
|
||||
BitSet printPostRegister = new BitSet(registerCount);
|
||||
|
||||
int currentCodeAddress = 0;
|
||||
for (int i=0; i<instructions.length; i++) {
|
||||
AnalyzedInstruction instruction = instructions[i];
|
||||
@ -266,15 +274,51 @@ public class MethodDefinition {
|
||||
methodItems.add(new BlankMethodItem(stg, currentCodeAddress));
|
||||
}
|
||||
|
||||
if (baksmali.verboseRegisterInfo) {
|
||||
if (instruction.getPredecessorCount() > 1 || i == 0) {
|
||||
methodItems.add(new CommentMethodItem(stg, getPreInstructionRegisterString(instruction),
|
||||
currentCodeAddress, Integer.MIN_VALUE));
|
||||
if (baksmali.registerInfo != 0) {
|
||||
printPreRegister.clear();
|
||||
printPostRegister.clear();
|
||||
|
||||
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);
|
||||
}
|
||||
methodItems.add(new CommentMethodItem(stg, getPostInstructionRegisterString(instruction),
|
||||
currentCodeAddress, Integer.MAX_VALUE-1));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -300,13 +344,168 @@ public class MethodDefinition {
|
||||
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();
|
||||
|
||||
for (int i=0; i<instruction.getRegisterCount(); i++) {
|
||||
RegisterType registerType = instruction.getPreInstructionRegisterType(i);
|
||||
sb.append("v");
|
||||
sb.append(i);
|
||||
for (int registerNum = registers.nextSetBit(0); registerNum >= 0;
|
||||
registerNum = registers.nextSetBit(registerNum + 1)) {
|
||||
|
||||
RegisterType registerType = instruction.getPreInstructionRegisterType(registerNum);
|
||||
sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem,registerNum));
|
||||
sb.append("=");
|
||||
if (registerType == null) {
|
||||
sb.append("null");
|
||||
@ -319,22 +518,26 @@ public class MethodDefinition {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getPostInstructionRegisterString(AnalyzedInstruction instruction) {
|
||||
private String getPostInstructionRegisterString(AnalyzedInstruction instruction, BitSet registers) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i=0; i<instruction.getRegisterCount(); i++) {
|
||||
RegisterType registerType = instruction.getPostInstructionRegisterType(i);
|
||||
sb.append("v");
|
||||
sb.append(i);
|
||||
for (int registerNum = registers.nextSetBit(0); registerNum >= 0;
|
||||
registerNum = registers.nextSetBit(registerNum + 1)) {
|
||||
|
||||
RegisterType registerType = instruction.getPostInstructionRegisterType(registerNum);
|
||||
sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem,registerNum));
|
||||
sb.append("=");
|
||||
if (registerType == null) {
|
||||
sb.append("null");
|
||||
} else {
|
||||
sb.append(registerType.toString());
|
||||
}
|
||||
sb.append(";");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private void addTries(List<MethodItem> methodItems) {
|
||||
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) {
|
||||
return;
|
||||
|
@ -45,23 +45,23 @@ public class baksmali {
|
||||
public static boolean useLocalsDirective = false;
|
||||
public static boolean useSequentialLabels = false;
|
||||
public static boolean outputDebugInfo = true;
|
||||
public static boolean verboseRegisterInfo = false;
|
||||
public static int registerInfo = 0;
|
||||
public static String bootClassPath;
|
||||
public static DeodexUtil deodexUtil = null;
|
||||
|
||||
public static void disassembleDexFile(DexFile dexFile, Deodexerant deodexerant, String outputDirectory,
|
||||
String bootClassPath, boolean noParameterRegisters,
|
||||
boolean useLocalsDirective, boolean useSequentialLabels,
|
||||
boolean outputDebugInfo, boolean verboseRegisterInfo)
|
||||
boolean outputDebugInfo, int registerInfo)
|
||||
{
|
||||
baksmali.noParameterRegisters = noParameterRegisters;
|
||||
baksmali.useLocalsDirective = useLocalsDirective;
|
||||
baksmali.useSequentialLabels = useSequentialLabels;
|
||||
baksmali.outputDebugInfo = outputDebugInfo;
|
||||
baksmali.verboseRegisterInfo = verboseRegisterInfo;
|
||||
baksmali.registerInfo = registerInfo;
|
||||
baksmali.bootClassPath = bootClassPath;
|
||||
|
||||
if (verboseRegisterInfo) {
|
||||
if (registerInfo != 0) {
|
||||
ClassPath.InitializeClassPath(bootClassPath==null?null:bootClassPath.split(":"), dexFile);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,14 @@ public class main {
|
||||
|
||||
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 {
|
||||
options = new Options();
|
||||
buildOptions();
|
||||
@ -75,7 +83,8 @@ public class main {
|
||||
boolean useLocalsDirective = false;
|
||||
boolean useSequentialLabels = false;
|
||||
boolean outputDebugInfo = true;
|
||||
boolean verboseRegisterInfo = false;
|
||||
|
||||
int registerInfo = 0;
|
||||
|
||||
String outputDirectory = "out";
|
||||
String dumpFileName = null;
|
||||
@ -147,7 +156,36 @@ public class main {
|
||||
}
|
||||
|
||||
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")) {
|
||||
@ -210,7 +248,7 @@ public class main {
|
||||
|
||||
if (disassemble) {
|
||||
baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, bootClassPath, noParameterRegisters,
|
||||
useLocalsDirective, useSequentialLabels, outputDebugInfo, verboseRegisterInfo);
|
||||
useLocalsDirective, useSequentialLabels, outputDebugInfo, registerInfo);
|
||||
}
|
||||
|
||||
if ((doDump || write) && !dexFile.isOdex()) {
|
||||
@ -238,6 +276,7 @@ public class main {
|
||||
*/
|
||||
private static void usage() {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.setWidth(100);
|
||||
formatter.printHelp("java -jar baksmali.jar [options] <dex-file>",
|
||||
"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.)")
|
||||
.create("b");
|
||||
|
||||
Option verboseRegisterInfoOption = OptionBuilder.withLongOpt("verbose-registers")
|
||||
.withDescription("print verbose register type information for each instruction")
|
||||
Option registerInfoOption = OptionBuilder.withLongOpt("register-info")
|
||||
.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");
|
||||
|
||||
Option classPathOption = OptionBuilder.withLongOpt("bootclasspath")
|
||||
@ -342,7 +391,7 @@ public class main {
|
||||
options.addOption(useLocalsOption);
|
||||
options.addOption(sequentialLabelsOption);
|
||||
options.addOption(noDebugInfoOption);
|
||||
options.addOption(verboseRegisterInfoOption);
|
||||
options.addOption(registerInfoOption);
|
||||
options.addOption(classPathOption);
|
||||
}
|
||||
}
|
@ -6,7 +6,9 @@ import org.jf.dexlib.ItemType;
|
||||
import org.jf.dexlib.MethodIdItem;
|
||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class AnalyzedInstruction {
|
||||
/**
|
||||
@ -63,7 +65,24 @@ public class AnalyzedInstruction {
|
||||
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) {
|
||||
assert checkPredecessorSorted(predecessor);
|
||||
predecessors.add(predecessor);
|
||||
}
|
||||
|
||||
@ -80,6 +99,34 @@ public class AnalyzedInstruction {
|
||||
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
|
||||
* the method parameter types for the "start of method" instruction, or to set the register
|
||||
|
@ -571,12 +571,12 @@ public class ClassPath {
|
||||
if (interfaces != null) {
|
||||
for (TypeIdItem interfaceType: interfaces.getTypes()) {
|
||||
ClassDef interfaceDef = ClassPath.getClassDef(interfaceType.getTypeDescriptor());
|
||||
assert interfaceDef.isInterface;
|
||||
assert interfaceDef.isInterface();
|
||||
implementedInterfaceSet.add(interfaceDef);
|
||||
|
||||
interfaceDef = interfaceDef.getSuperclass();
|
||||
while (!interfaceDef.getClassType().equals("Ljava/lang/Object;")) {
|
||||
assert interfaceDef.isInterface;
|
||||
assert interfaceDef.isInterface();
|
||||
implementedInterfaceSet.add(interfaceDef);
|
||||
interfaceDef = interfaceDef.getSuperclass();
|
||||
}
|
||||
|
@ -183,6 +183,10 @@ public class MethodAnalyzer {
|
||||
(encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0;
|
||||
}
|
||||
|
||||
public AnalyzedInstruction getStartOfMethod() {
|
||||
return startOfMethod;
|
||||
}
|
||||
|
||||
public AnalyzedInstruction[] makeInstructionArray() {
|
||||
AnalyzedInstruction[] instructionArray = new AnalyzedInstruction[instructions.size()];
|
||||
for (int i=0; i<instructions.size(); i++) {
|
||||
@ -214,7 +218,7 @@ public class MethodAnalyzer {
|
||||
return registerTypes;
|
||||
}
|
||||
|
||||
private int getInstructionAddress(AnalyzedInstruction instruction) {
|
||||
public int getInstructionAddress(AnalyzedInstruction instruction) {
|
||||
return instructions.keyAt(instruction.instructionIndex);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user