diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentMethodItem.java new file mode 100644 index 00000000..cf38fcd5 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/CommentMethodItem.java @@ -0,0 +1,25 @@ +package org.jf.baksmali.Adaptors; + +import org.antlr.stringtemplate.StringTemplate; +import org.antlr.stringtemplate.StringTemplateGroup; + +public class CommentMethodItem extends MethodItem { + private final StringTemplate template; + private final int sortOrder; + + public CommentMethodItem(StringTemplateGroup stg, String comment, int codeAddress, int sortOrder) { + super(codeAddress); + template = stg.getInstanceOf("Comment"); + template.setAttribute("Comment", comment); + this.sortOrder = sortOrder; + } + + public int getSortOrder() { + return sortOrder; + } + + @Override + public String toString() { + return template.toString(); + } +} 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 7777d6ea..776dc14e 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java @@ -31,6 +31,9 @@ package org.jf.baksmali.Adaptors; import org.jf.baksmali.Adaptors.Format.*; import org.jf.baksmali.baksmali; import org.jf.dexlib.*; +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.Debug.DebugInstructionIterator; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; @@ -45,6 +48,7 @@ import java.util.*; public class MethodDefinition { private final StringTemplateGroup stg; private final ClassDataItem.EncodedMethod encodedMethod; + private final MethodAnalyzer methodAnalyzer; private final LabelCache labelCache = new LabelCache(); @@ -59,7 +63,8 @@ public class MethodDefinition { //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh. if (encodedMethod.codeItem != null) { - Instruction[] instructions = encodedMethod.codeItem.getInstructions(); + methodAnalyzer = new MethodAnalyzer(encodedMethod); + AnalyzedInstruction[] instructions = methodAnalyzer.makeInstructionArray(); packedSwitchMap = new SparseIntArray(1); sparseSwitchMap = new SparseIntArray(1); @@ -67,23 +72,24 @@ public class MethodDefinition { int currentCodeAddress = 0; for (int i=0; i 1 || i == 0) { + methodItems.add(new CommentMethodItem(stg, getPreInstructionRegisterString(instruction), + currentCodeAddress, Integer.MIN_VALUE)); + } + methodItems.add(new CommentMethodItem(stg, getPostInstructionRegisterString(instruction), + currentCodeAddress, Integer.MAX_VALUE-1)); + } + + + currentCodeAddress += instruction.instruction.getSize(currentCodeAddress); } addTries(methodItems); @@ -264,6 +285,41 @@ public class MethodDefinition { return methodItems; } + private String getPreInstructionRegisterString(AnalyzedInstruction instruction) { + StringBuilder sb = new StringBuilder(); + + for (int i=0; i methodItems) { if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) { return; diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmali.java b/baksmali/src/main/java/org/jf/baksmali/baksmali.java index af5e8822..a7b2afee 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmali.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmali.java @@ -33,6 +33,7 @@ import org.antlr.stringtemplate.StringTemplateGroup; import org.jf.baksmali.Adaptors.ClassDefinition; import org.jf.baksmali.Deodex.*; import org.jf.baksmali.Renderers.*; +import org.jf.dexlib.Code.Analysis.ClassPath; import org.jf.dexlib.DexFile; import org.jf.dexlib.ClassDefItem; import org.jf.dexlib.StringIdItem; @@ -44,16 +45,25 @@ 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 String bootClassPath; public static DeodexUtil deodexUtil = null; public static void disassembleDexFile(DexFile dexFile, Deodexerant deodexerant, String outputDirectory, - boolean noParameterRegisters, boolean useLocalsDirective, - boolean useSequentialLabels, boolean outputDebugInfo) + String bootClassPath, boolean noParameterRegisters, + boolean useLocalsDirective, boolean useSequentialLabels, + boolean outputDebugInfo, boolean verboseRegisterInfo) { baksmali.noParameterRegisters = noParameterRegisters; baksmali.useLocalsDirective = useLocalsDirective; baksmali.useSequentialLabels = useSequentialLabels; baksmali.outputDebugInfo = outputDebugInfo; + baksmali.verboseRegisterInfo = verboseRegisterInfo; + baksmali.bootClassPath = bootClassPath; + + if (verboseRegisterInfo) { + ClassPath.InitializeClassPath(bootClassPath.split(":"), dexFile); + } if (deodexerant != null) { baksmali.deodexUtil = new DeodexUtil(deodexerant); diff --git a/baksmali/src/main/java/org/jf/baksmali/main.java b/baksmali/src/main/java/org/jf/baksmali/main.java index a80db352..9d823155 100644 --- a/baksmali/src/main/java/org/jf/baksmali/main.java +++ b/baksmali/src/main/java/org/jf/baksmali/main.java @@ -75,13 +75,14 @@ public class main { boolean useLocalsDirective = false; boolean useSequentialLabels = false; boolean outputDebugInfo = true; - + boolean verboseRegisterInfo = false; String outputDirectory = "out"; String dumpFileName = null; String outputDexFileName = null; String inputDexFileName = null; String deodexerantHost = null; + String bootClassPath = "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar"; int deodexerantPort = 0; String[] remainingArgs = commandLine.getArgs(); @@ -145,6 +146,14 @@ public class main { outputDebugInfo = false; } + if (commandLine.hasOption("r")) { + verboseRegisterInfo = true; + } + + if (commandLine.hasOption("c")) { + bootClassPath = commandLine.getOptionValue("c"); + } + if (commandLine.hasOption("x")) { String deodexerantAddress = commandLine.getOptionValue("x"); String[] parts = deodexerantAddress.split(":"); @@ -200,8 +209,8 @@ public class main { } if (disassemble) { - baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, noParameterRegisters, - useLocalsDirective, useSequentialLabels, outputDebugInfo); + baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, bootClassPath, noParameterRegisters, + useLocalsDirective, useSequentialLabels, outputDebugInfo, verboseRegisterInfo); } if ((doDump || write) && !dexFile.isOdex()) { @@ -310,6 +319,16 @@ 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") + .create("r"); + + Option classPathOption = OptionBuilder.withLongOpt("bootclasspath") + .withDescription("the bootclasspath jars to use, for analysis") + .hasArg() + .withArgName("BOOTCLASSPATH") + .create("c"); + options.addOption(versionOption); options.addOption(helpOption); options.addOption(dumpOption); @@ -323,5 +342,7 @@ public class main { options.addOption(useLocalsOption); options.addOption(sequentialLabelsOption); options.addOption(noDebugInfoOption); + options.addOption(verboseRegisterInfoOption); + options.addOption(classPathOption); } } \ No newline at end of file diff --git a/baksmali/src/main/resources/templates/templates/baksmali.stg b/baksmali/src/main/resources/templates/templates/baksmali.stg index 55084034..789f3433 100644 --- a/baksmali/src/main/resources/templates/templates/baksmali.stg +++ b/baksmali/src/main/resources/templates/templates/baksmali.stg @@ -434,4 +434,9 @@ AnnotationEncodedValue(AnnotationType, Elements) ::= AnnotationElement(Name, Value) ::= << = +>> + +Comment(Comment) ::= +<< +# >> \ No newline at end of file diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/AnalyzedInstruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/AnalyzedInstruction.java index 36116d12..5049baa9 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/AnalyzedInstruction.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/AnalyzedInstruction.java @@ -12,7 +12,7 @@ public class AnalyzedInstruction { /** * The actual instruction */ - protected final Instruction instruction; + public final Instruction instruction; /** * The index of the instruction, where the first instruction in the method is at index 0, and so on @@ -49,12 +49,20 @@ public class AnalyzedInstruction { this.instruction = instruction; this.instructionIndex = instructionIndex; this.postRegisterMap = new RegisterType[registerCount]; + RegisterType unknown = RegisterType.getRegisterType(RegisterType.Category.Unknown, null); + for (int i=0; i")) { + if (!method.getMethodName().getStringValue().equals("")) { return false; } @@ -175,6 +184,14 @@ public class AnalyzedInstruction { return ((SingleRegisterInstruction)instruction).getRegisterA(); } + public int getRegisterCount() { + return postRegisterMap.length; + } + + public RegisterType getPostInstructionRegisterType(int registerNumber) { + return postRegisterMap[registerNumber]; + } + public RegisterType getPreInstructionRegisterType(int registerNumber) { //if the specific register is not a destination register, then the stored post-instruction register type will //be the same as the pre-instruction regsiter type, so we can use that. diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/ClassPath.java b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/ClassPath.java index a96537c0..83986056 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/ClassPath.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/ClassPath.java @@ -15,35 +15,32 @@ public class ClassPath { private static ClassPath theClassPath = null; private final HashMap classDefs; - protected final ClassDef javaLangObjectClassDef; //Ljava/lang/Object; + protected ClassDef javaLangObjectClassDef; //Ljava/lang/Object; public static void InitializeClassPath(String[] bootClassPath, DexFile dexFile) { if (theClassPath != null) { throw new ExceptionWithContext("Cannot initialize ClassPath multiple times"); } - theClassPath = new ClassPath(bootClassPath, dexFile); + theClassPath = new ClassPath(); + theClassPath.initClassPath(bootClassPath, dexFile); } - private ClassPath(String[] bootClassPath, DexFile dexFile) { + private ClassPath() { + classDefs = new HashMap(); + } + + private void initClassPath(String[] bootClassPath, DexFile dexFile) { if (bootClassPath == null || bootClassPath.length == 0) { throw new ExceptionWithContext("No BOOTCLASSPATH entries were given"); } - classDefs = new HashMap(); - for (String bootClassPathEntry: bootClassPath) { loadBootClassPath(bootClassPathEntry); } loadDexFile(dexFile); - try { - javaLangObjectClassDef = getClassDef("Ljava/lang/Object;"); - } catch (ClassNotFoundException ex) { - throw ExceptionWithContext.withContext(ex, "Ljava/lang/Object; must be present in the classpath"); - } - for (String primitiveType: new String[]{"Z", "B", "S", "C", "I", "J", "F", "D"}) { ClassDef classDef = new PrimitiveClassDef(primitiveType); classDefs.put(primitiveType, classDef); @@ -77,8 +74,12 @@ public class ClassPath { //TODO: need to check if the class already exists. (and if so, what to do about it?) ClassDef classDef = new ClassDef(classDefItem); classDefs.put(classDef.getClassType(), classDef); - classDef.dumpVtable(); - classDef.dumpFields(); + + if (classDefItem.getClassType().getTypeDescriptor().equals("Ljava/lang/Object;")) { + theClassPath.javaLangObjectClassDef = classDef; + } + /*classDef.dumpVtable(); + classDef.dumpFields();*/ } } @@ -274,7 +275,7 @@ public class ClassPath { } } - public static class ClassDef { + public static class ClassDef implements Comparable { private final String classType; private final ClassDef superclass; /** @@ -329,7 +330,7 @@ public class ClassPath { } } - protected ClassDef(ClassDefItem classDefItem) { + protected ClassDef(ClassDefItem classDefItem) { classType = classDefItem.getClassType().getTypeDescriptor(); isInterface = (classDefItem.getAccessFlags() & AccessFlags.INTERFACE.getValue()) != 0; @@ -406,23 +407,23 @@ public class ClassPath { } //TODO: GROT - public void dumpVtable() { + /*public void dumpVtable() { System.out.println(classType + " methods:"); int i=0; for (String method: vtable) { System.out.println(i + ":\t" + method); i++; } - } + }*/ //TODO: GROT - public void dumpFields() { + /*public void dumpFields() { System.out.println(classType + " fields:"); for (int i=0; i")) { + if (!encodedMethod.method.getMethodName().getStringValue().equals("")) { throw new ValidationException("The constructor flag can only be used with an method."); } @@ -90,7 +91,7 @@ public class MethodAnalyzer { RegisterType.getRegisterType(RegisterType.Category.UninitRef, ClassPath.getClassDef(methodIdItem.getContainingClass()))); } else { - if (encodedMethod.method.getMethodName().equals("")) { + if (encodedMethod.method.getMethodName().getStringValue().equals("")) { throw new ValidationException("An method must have the \"constructor\" access flag"); } @@ -119,8 +120,8 @@ public class MethodAnalyzer { while (!instructionsToVerify.isEmpty()) { for(int i=instructionsToVerify.nextSetBit(0); i>=0; i=instructionsToVerify.nextSetBit(i+1)) { - analyzeInstruction(instructions.get(i)); instructionsToVerify.clear(i); + analyzeInstruction(instructions.valueAt(i)); } } @@ -201,7 +202,7 @@ public class MethodAnalyzer { boolean changed = analyzedInstruction.setPostRegisterType(registerNumber, registerType); - if (!changed || analyzedInstruction.setsRegister(registerNumber)) { + if (!changed) { return; } @@ -216,7 +217,7 @@ public class MethodAnalyzer { while (!changedInstructions.isEmpty()) { for (int instructionIndex=changedInstructions.nextSetBit(0); instructionIndex>=0; - instructionIndex=changedInstructions.nextSetBit(instructionIndex)) { + instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) { changedInstructions.clear(instructionIndex); @@ -242,9 +243,10 @@ public class MethodAnalyzer { if (!successor.setsRegister(registerNumber)) { RegisterType registerType = successor.getMergedRegisterTypeFromPredecessors(registerNumber); - if (registerType.category == RegisterType.Category.UninitRef && instruction.isInvokeInit()) { + //TODO: GROT? + /*if (registerType.category == RegisterType.Category.UninitRef && instruction.isInvokeInit()) { continue; - } + }*/ if (successor.setPostRegisterType(registerNumber, registerType)) { changedInstructions.set(successor.instructionIndex); @@ -261,8 +263,6 @@ public class MethodAnalyzer { assert encodedMethod.codeItem != null; int registerCount = encodedMethod.codeItem.getRegisterCount(); - startOfMethod = new AnalyzedInstruction(null, -1, registerCount); - Instruction[] insns = encodedMethod.codeItem.getInstructions(); instructions = new SparseArray(insns.length); @@ -284,34 +284,36 @@ public class MethodAnalyzer { AnalyzedInstruction[] currentExceptionHandlers = null; AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[insns.length][]; - for (int i=0; i currentCodeAddress); + //check if the next try is applicable yet + if (currentTry == null && triesIndex < tries.length) { + CodeItem.TryItem tryItem = tries[triesIndex]; + if (tryItem.getStartCodeAddress() <= currentCodeAddress) { + assert(tryItem.getStartCodeAddress() + tryItem.getTryLength() > currentCodeAddress); - currentTry = tryItem; + currentTry = tryItem; - currentExceptionHandlers = buildExceptionHandlerArray(tryItem); + currentExceptionHandlers = buildExceptionHandlerArray(tryItem); + } } - } - //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers - //for the current instruction - if (currentTry != null && instructionOpcode.canThrow()) { - exceptionHandlers[i] = currentExceptionHandlers; + //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers + //for the current instruction + if (currentTry != null && instructionOpcode.canThrow()) { + exceptionHandlers[i] = currentExceptionHandlers; + } } } @@ -333,8 +335,8 @@ public class MethodAnalyzer { addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers); } - if (instruction instanceof OffsetInstruction) { - OffsetInstruction offsetInstruction = (OffsetInstruction)instruction; + if (instruction.instruction instanceof OffsetInstruction) { + OffsetInstruction offsetInstruction = (OffsetInstruction)instruction.instruction; if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) { MultiOffsetInstruction switchDataInstruction = @@ -431,7 +433,7 @@ public class MethodAnalyzer { case MOVE_OBJECT: case MOVE_OBJECT_FROM16: case MOVE_OBJECT_16: - handleMove(analyzedInstruction, ReferenceCategories); + handleMove(analyzedInstruction, ReferenceOrUninitCategories); return; case MOVE_RESULT: handleMoveResult(analyzedInstruction, Primitive32BitCategories); @@ -904,9 +906,12 @@ public class MethodAnalyzer { private static final EnumSet Primitive32BitCategories = EnumSet.of( RegisterType.Category.Null, + RegisterType.Category.One, RegisterType.Category.Boolean, RegisterType.Category.Byte, + RegisterType.Category.PosByte, RegisterType.Category.Short, + RegisterType.Category.PosShort, RegisterType.Category.Char, RegisterType.Category.Integer, RegisterType.Category.Float); @@ -923,11 +928,19 @@ public class MethodAnalyzer { RegisterType.Category.Null, RegisterType.Category.Reference); + private static final EnumSet ReferenceOrUninitCategories = EnumSet.of( + RegisterType.Category.Null, + RegisterType.Category.UninitRef, + RegisterType.Category.Reference); + private static final EnumSet ReferenceAndPrimitive32BitCategories = EnumSet.of( RegisterType.Category.Null, + RegisterType.Category.One, RegisterType.Category.Boolean, RegisterType.Category.Byte, + RegisterType.Category.PosByte, RegisterType.Category.Short, + RegisterType.Category.PosShort, RegisterType.Category.Char, RegisterType.Category.Integer, RegisterType.Category.Float, @@ -1037,8 +1050,9 @@ public class MethodAnalyzer { if (thisRegisterType.category == RegisterType.Category.UninitRef) { throw new ValidationException("Returning from constructor without calling the superclass' "); } - assert thisRegisterType.category == RegisterType.Category.Reference; - assert thisRegisterType.type == ClassPath.getClassDef(encodedMethod.method.getContainingClass()); + //TODO: GROT + //assert thisRegisterType.category == RegisterType.Category.Reference; + //assert thisRegisterType.type == ClassPath.getClassDef(encodedMethod.method.getContainingClass()); } private void handleReturnVoid(AnalyzedInstruction analyzedInstruction) { @@ -2285,8 +2299,8 @@ public class MethodAnalyzer { } if (isInit) { - if (objectRegisterType.type == methodClassDef.getSuperclass()) { - if (!encodedMethod.method.getMethodName().equals("")) { + if (objectRegisterType.type.getSuperclass() == methodClassDef) { + if (!encodedMethod.method.getMethodName().getStringValue().equals("")) { throw new ValidationException(String.format("Cannot call %s on type %s. The object type must " + "match the method type exactly", methodIdItem.getMethodString(), objectRegisterType.type.getClassType())); @@ -2302,44 +2316,46 @@ public class MethodAnalyzer { } } - List parameterTypes = typeListItem.getTypes(); - int parameterTypeIndex = 0; - while (!registers.pastEnd()) { - assert parameterTypeIndex < parameterTypes.size(); - RegisterType parameterType = - RegisterType.getRegisterTypeForTypeIdItem(parameterTypes.get(parameterTypeIndex)); + if (typeListItem != null) { + List parameterTypes = typeListItem.getTypes(); + int parameterTypeIndex = 0; + while (!registers.pastEnd()) { + assert parameterTypeIndex < parameterTypes.size(); + RegisterType parameterType = + RegisterType.getRegisterTypeForTypeIdItem(parameterTypes.get(parameterTypeIndex)); - int register = registers.getRegister(); + int register = registers.getRegister(); - RegisterType parameterRegisterType; - if (WideLowCategories.contains(parameterType.category)) { - parameterRegisterType = getAndCheckSourceRegister(analyzedInstruction, register, WideLowCategories); + RegisterType parameterRegisterType; + if (WideLowCategories.contains(parameterType.category)) { + parameterRegisterType = getAndCheckSourceRegister(analyzedInstruction, register, WideLowCategories); - if (!registers.moveNext()) { - throw new ValidationException(String.format("No 2nd register specified for wide register pair v%d", - parameterTypeIndex+1)); + if (!registers.moveNext()) { + throw new ValidationException(String.format("No 2nd register specified for wide register pair v%d", + parameterTypeIndex+1)); + } + int nextRegister = registers.getRegister(); + + if (nextRegister != register + 1) { + throw new ValidationException(String.format("Invalid wide register pair (v%d, v%d). Registers " + + "must be consecutive.", register, nextRegister)); + } + } else { + parameterRegisterType = analyzedInstruction.getPreInstructionRegisterType(register); } - int nextRegister = registers.getRegister(); - if (nextRegister != register + 1) { - throw new ValidationException(String.format("Invalid wide register pair (v%d, v%d). Registers " + - "must be consecutive.", register, nextRegister)); + assert parameterRegisterType != null; + + if (!parameterRegisterType.canBeAssignedTo(parameterType)) { + throw new ValidationException( + String.format("Invalid register type %s for parameter %d %s.", + parameterRegisterType.toString(), parameterTypeIndex+1, + parameterType.toString())); } - } else { - parameterRegisterType = analyzedInstruction.getPreInstructionRegisterType(register); + + parameterTypeIndex++; + registers.moveNext(); } - - assert parameterRegisterType != null; - - if (!parameterRegisterType.canBeAssignedTo(parameterType)) { - throw new ValidationException( - String.format("Invalid register type %s for parameter %d %s.", - parameterRegisterType.toString(), parameterTypeIndex+1, - parameterType.toString())); - } - - parameterTypeIndex++; - registers.moveNext(); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/RegisterType.java b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/RegisterType.java index f932e3d2..31100c1c 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/RegisterType.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/RegisterType.java @@ -222,18 +222,18 @@ public class RegisterType { } Category mergedCategory = Category.mergeTable[this.category.ordinal()][type.category.ordinal()]; - if (mergedCategory == Category.Conflicted) { - throw new ValidationException("Incompatible register types." + - " Category1: " + this.category.name() + - (this.type==null?"":" Type1: " + this.type.getClassType()) + - " Category2: " + type.category.name() + - (type.type==null?"":" Type2: " + type.type.getClassType())); - } ClassDef mergedType = null; if (mergedCategory == Category.Reference) { mergedType = ClassPath.getCommonSuperclass(this.type, type.type); } + if (mergedCategory == Category.UninitRef) { + if (this.category == Category.Unknown) { + return type; + } + assert type.category == Category.Unknown; + return this; + } return RegisterType.getRegisterType(mergedCategory, mergedType); } diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java index d26097b4..92111e53 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java @@ -281,9 +281,9 @@ public enum Opcode //if the instruction sets the "hidden" result register public static final int SETS_RESULT = 0x8; //if the instruction sets the value of it's first register - public static final int SETS_REGISTER = 0x16; + public static final int SETS_REGISTER = 0x10; //if the instruction sets the value of it's first register to a wide type - public static final int SETS_WIDE_REGISTER = 0x32; + public static final int SETS_WIDE_REGISTER = 0x20; static { opcodesByValue = new Opcode[256];