From c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1 Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Sun, 7 Apr 2013 20:39:07 -0700 Subject: [PATCH] Add support for generating register information --- .../baksmali/Adaptors/MethodDefinition.java | 70 +++++++++-------- ...PostInstructionRegisterInfoMethodItem.java | 38 ++++----- .../PreInstructionRegisterInfoMethodItem.java | 77 ++++++++++--------- .../main/java/org/jf/baksmali/baksmali.java | 50 +++++------- 4 files changed, 117 insertions(+), 118 deletions(-) diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java index 458baa22..82d6042b 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java @@ -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 getMethodItems() { ArrayList methodItems = new ArrayList(); - //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 methodItems) { int currentCodeAddress = 0; for (int i=0; i methodItems) { - methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver); + private void addAnalyzedInstructionMethodItems(List 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 instructions = methodAnalyzer.getInstructions(); + List instructions = methodAnalyzer.getAnalyzedInstructions(); int currentCodeAddress = 0; for (int i=0; i methodItems) { List tryBlocks = methodImpl.getTryBlocks(); diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PostInstructionRegisterInfoMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PostInstructionRegisterInfoMethodItem.java index 70eb775c..87bf1c1f 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PostInstructionRegisterInfoMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PostInstructionRegisterInfoMethodItem.java @@ -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; } -}*/ +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java index cd6917a6..3a49b1d0 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java @@ -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= 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; } -}*/ +} diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmali.java b/baksmali/src/main/java/org/jf/baksmali/baksmali.java index 28a11f00..1a347a39 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmali.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmali.java @@ -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 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 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()) {