diff --git a/baksmali/src/main/java/org/jf/baksmali/deodexCheck.java b/baksmali/src/main/java/org/jf/baksmali/deodexCheck.java deleted file mode 100644 index 8d38d017..00000000 --- a/baksmali/src/main/java/org/jf/baksmali/deodexCheck.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2010 Ben Gruver (JesusFreke) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.jf.baksmali; - -import org.apache.commons.cli.*; -import org.jf.dexlib.Code.Analysis.ClassPath; - -import java.util.ArrayList; -import java.util.List; - -public class deodexCheck { - public static void main(String[] args) { - CommandLineParser parser = new PosixParser(); - CommandLine commandLine; - - Options options = buildOptions(); - - try { - commandLine = parser.parse(options, args); - } catch (ParseException ex) { - usage(options); - return; - } - - String bootClassPath = "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar"; - List bootClassPathDirs = new ArrayList(); - bootClassPathDirs.add("."); - String deodexerantHost = null; - int deodexerantPort = 0; - int classStartIndex = 0; - - - String[] remainingArgs = commandLine.getArgs(); - - - if (commandLine.hasOption("v")) { - main.version(); - return; - } - - if (commandLine.hasOption("?")) { - usage(options); - return; - } - - if (remainingArgs.length > 0) { - usage(options); - return; - } - - - if (commandLine.hasOption("c")) { - String bcp = commandLine.getOptionValue("c"); - if (bcp.charAt(0) == ':') { - bootClassPath = bootClassPath + bcp; - } else { - bootClassPath = bcp; - } - } - - if (commandLine.hasOption("i")) { - try { - classStartIndex = Integer.parseInt(commandLine.getOptionValue("i")); - } catch (Exception ex) { - } - } - - if (commandLine.hasOption("d")) { - bootClassPathDirs.add(commandLine.getOptionValue("d")); - } - - if (commandLine.hasOption("x")) { - String deodexerantAddress = commandLine.getOptionValue("x"); - String[] parts = deodexerantAddress.split(":"); - if (parts.length != 2) { - System.err.println("Invalid deodexerant address. Expecting : or :"); - System.exit(1); - } - - deodexerantHost = parts[0]; - if (deodexerantHost.length() == 0) { - deodexerantHost = "localhost"; - } - try { - deodexerantPort = Integer.parseInt(parts[1]); - } catch (NumberFormatException ex) { - System.err.println("Invalid port \"" + deodexerantPort + "\" for deodexerant address"); - System.exit(1); - } - } - - String[] bootClassPathDirsArray = new String[bootClassPathDirs.size()]; - for (int i=0; i -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils/Log.h" - -#define VERSION "1.0" - -#define VER1_(x) #x -#define VER_(x) VER1_(x) -#define ANDROID_VERSION VER_(ANDROID_VER) - -typedef struct InlineSub { - Method* method; - int inlineIdx; -} InlineSub; - -static DexStringCache stringCache; - -static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2); - -//The following methods yanked from vm/analysis/CodeVerify.c -/* - * Compute the "class depth" of a class. This is the distance from the - * class to the top of the tree, chasing superclass links. java.lang.Object - * has a class depth of 0. - */ -static int getClassDepth(ClassObject* clazz) -{ - int depth = 0; - - while (clazz->super != NULL) { - clazz = clazz->super; - depth++; - } - return depth; -} - -/* - * Given two classes, walk up the superclass tree to find a common - * ancestor. (Called from findCommonSuperclass().) - * - * TODO: consider caching the class depth in the class object so we don't - * have to search for it here. - */ -static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2) -{ - int depth1, depth2; - - depth1 = getClassDepth(c1); - depth2 = getClassDepth(c2); - - /* pull the deepest one up */ - if (depth1 > depth2) { - while (depth1 > depth2) { - c1 = c1->super; - depth1--; - } - } else { - while (depth2 > depth1) { - c2 = c2->super; - depth2--; - } - } - - /* walk up in lock-step */ - while (c1 != c2) { - c1 = c1->super; - c2 = c2->super; - - assert(c1 != NULL && c2 != NULL); - } - - return c1; -} - -/* - * Merge two array classes. We can't use the general "walk up to the - * superclass" merge because the superclass of an array is always Object. - * We want String[] + Integer[] = Object[]. This works for higher dimensions - * as well, e.g. String[][] + Integer[][] = Object[][]. - * - * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[]. - * - * If Class implements Type, Class[] + Type[] = Type[]. - * - * If the dimensions don't match, we want to convert to an array of Object - * with the least dimension, e.g. String[][] + String[][][][] = Object[][]. - * - * This gets a little awkward because we may have to ask the VM to create - * a new array type with the appropriate element and dimensions. However, we - * shouldn't be doing this often. - */ -static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2) -{ - ClassObject* arrayClass = NULL; - ClassObject* commonElem; - int i, numDims; - - assert(c1->arrayDim > 0); - assert(c2->arrayDim > 0); - - if (c1->arrayDim == c2->arrayDim) { - //commonElem = digForSuperclass(c1->elementClass, c2->elementClass); - commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass); - numDims = c1->arrayDim; - } else { - if (c1->arrayDim < c2->arrayDim) - numDims = c1->arrayDim; - else - numDims = c2->arrayDim; - commonElem = c1->super; // == java.lang.Object - } - - /* walk from the element to the (multi-)dimensioned array type */ - for (i = 0; i < numDims; i++) { - arrayClass = dvmFindArrayClassForElement(commonElem); - commonElem = arrayClass; - } - - return arrayClass; -} - -/* - * Find the first common superclass of the two classes. We're not - * interested in common interfaces. - * - * The easiest way to do this for concrete classes is to compute the "class - * depth" of each, move up toward the root of the deepest one until they're - * at the same depth, then walk both up to the root until they match. - * - * If both classes are arrays of non-primitive types, we need to merge - * based on array depth and element type. - * - * If one class is an interface, we check to see if the other class/interface - * (or one of its predecessors) implements the interface. If so, we return - * the interface; otherwise, we return Object. - * - * NOTE: we continue the tradition of "lazy interface handling". To wit, - * suppose we have three classes: - * One implements Fancy, Free - * Two implements Fancy, Free - * Three implements Free - * where Fancy and Free are unrelated interfaces. The code requires us - * to merge One into Two. Ideally we'd use a common interface, which - * gives us a choice between Fancy and Free, and no guidance on which to - * use. If we use Free, we'll be okay when Three gets merged in, but if - * we choose Fancy, we're hosed. The "ideal" solution is to create a - * set of common interfaces and carry that around, merging further references - * into it. This is a pain. The easy solution is to simply boil them - * down to Objects and let the runtime invokeinterface call fail, which - * is what we do. - */ -static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2) -{ - assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2)); - - if (c1 == c2) - return c1; - - if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) { - return c1; - } - if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) { - return c2; - } - - if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2) && - !dvmIsPrimitiveClass(c1->elementClass) && - !dvmIsPrimitiveClass(c2->elementClass)) - { - return findCommonArraySuperclass(c1, c2); - } - - return digForSuperclass(c1, c2); -} - - - - - - - - - - - - - - -//method yanked from vm/analysis/DexOptimize.c -/* - * Try to load all classes in the specified DEX. If they have some sort - * of broken dependency, e.g. their superclass lives in a different DEX - * that wasn't previously loaded into the bootstrap class path, loading - * will fail. This is the desired behavior. - * - * We have no notion of class loader at this point, so we load all of - * the classes with the bootstrap class loader. It turns out this has - * exactly the behavior we want, and has no ill side effects because we're - * running in a separate process and anything we load here will be forgotten. - * - * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions. - * This works because we only call here as part of optimization / pre-verify, - * not during verification as part of loading a class into a running VM. - * - * This returns "false" if the world is too screwed up to do anything - * useful at all. - */ -int loadAllClasses(DvmDex* pDvmDex) -{ - u4 count = pDvmDex->pDexFile->pHeader->classDefsSize; - u4 idx; - int loaded = 0; - - dvmSetBootPathExtraDex(pDvmDex); - - /* - * We have some circularity issues with Class and Object that are most - * easily avoided by ensuring that Object is never the first thing we - * try to find. Take care of that here. (We only need to do this when - * loading classes from the DEX file that contains Object, and only - * when Object comes first in the list, but it costs very little to - * do it in all cases.) - */ - if (dvmFindSystemClass("Ljava/lang/Class;") == NULL) { - return false; - } - - for (idx = 0; idx < count; idx++) { - const DexClassDef* pClassDef; - const char* classDescriptor; - ClassObject* newClass; - - pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx); - classDescriptor = - dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx); - - //newClass = dvmDefineClass(pDexFile, classDescriptor, - // NULL); - newClass = dvmFindSystemClassNoInit(classDescriptor); - if (newClass == NULL) { - dvmClearOptException(dvmThreadSelf()); - } else if (newClass->pDvmDex != pDvmDex) { - /* - * We don't load the new one, and we tag the first one found - * with the "multiple def" flag so the resolver doesn't try - * to make it available. - */ - SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS); - } else { - loaded++; - } - } - - dvmSetBootPathExtraDex(NULL); - return true; -} - -int dumpFields(char *classType, FILE *clientOut) -{ - ClassObject *clazz; - if (classType[0] == '[') - clazz = dvmFindArrayClass(classType, NULL); - else - clazz = dvmFindSystemClassNoInit(classType); - - if (clazz == NULL) - return 0; - - int i; - do - { - InstField *pField = clazz->ifields; - for (i=0; iifieldCount; i++, pField++) - fprintf(clientOut, "field: %d %s:%s\n", pField->byteOffset, pField->field.name, pField->field.signature); - - clazz = clazz->super; - } while (clazz != NULL); - - return 1; -} - -int dumpInlineMethods(FILE *clientOut) -{ - const InlineOperation *inlineTable = dvmGetInlineOpsTable(); - int count = dvmGetInlineOpsTableLength(); - - int i; - for (i=0; iclassDescriptor); - if (clazz == NULL) - return 0; - - char *methodType; - Method *method = dvmFindDirectMethodByDescriptor(clazz, inlineOp->methodName, inlineOp->methodSignature); - if (method == NULL) - { - method = dvmFindVirtualMethodByDescriptor(clazz, inlineOp->methodName, inlineOp->methodSignature); - methodType = "virtual"; - } else { - if (dvmIsStaticMethod(method)) - methodType = "static"; - else - methodType = "direct"; - } - - if (method == NULL) - return 0; - - fprintf(clientOut, "inline: %s %s->%s%s\n", methodType, method->clazz->descriptor, method->name, dexProtoGetMethodDescriptor(&method->prototype, &stringCache)); - } - - return 1; -} - -int dumpVirtualMethods(char *classType, FILE *clientOut) -{ - ClassObject *clazz; - if (classType[0] == '[') - clazz = dvmFindArrayClass(classType, NULL); - else - clazz = dvmFindSystemClassNoInit(classType); - - - if (clazz == NULL) - { - fprintf(clientOut, "err: could not find class %s\n", classType); - return 0; - } - - //interface classes don't have virtual methods, by definition. But it's possible - //to call virtual methods defined on the Object class via an interface type - if (dvmIsInterfaceClass(clazz)) - { - clazz = dvmFindSystemClassNoInit("Ljava/lang/Object;"); - if (clazz == NULL) - { - fprintf(clientOut, "err: could not find class %s\n", classType); - return 0; - } - } - - int i; - for (i=0; ivtableCount; i++) - { - Method *method = clazz->vtable[i]; - fprintf(clientOut, "vtable: %s%s\n", method->name, - dexProtoGetMethodDescriptor(&method->prototype, &stringCache)); - } - return 1; -} - -ClassObject *lookupSuperclass(char *classType) -{ - ClassObject *clazz = dvmFindSystemClassNoInit(classType); - - if (clazz == NULL) - return NULL; - - return clazz->super; -} - -/* - * Parse arguments. Most of it just gets passed through to the VM. The - * JNI spec defines a handful of standard arguments. - */ -int main(int argc, char* const argv[]) -{ - const char* inputFileName; - JavaVM* vm = NULL; - JNIEnv* env = NULL; - DvmDex* pDvmDex = NULL; - DexClassLookup* pClassLookup; - - if (argc != 3) { - fprintf(stderr, "deodexerant %s (Android %s)\n", VERSION, ANDROID_VERSION); - fprintf(stderr, "usage: deodexerant \n"); - return 1; - } - - inputFileName = argv[1]; - - struct stat inputInfo; - - if (stat(inputFileName, &inputInfo) != 0) { - fprintf(stderr, "could not stat '%s' : %s\n", inputFileName, strerror(errno)); - return 1; - } - - int odexFd = open(inputFileName, O_RDONLY); - if (odexFd < 0) { - fprintf(stderr, "Unable to open '%s': %s\n", inputFileName, strerror(errno)); - return 1; - } - - int port = atoi(argv[2]); - int socketFd = socket(AF_INET, SOCK_STREAM, 0); - if (socketFd < 0) - { - fprintf(stderr, "Unable to open socket\n"); - return 1; - } - - struct sockaddr_in serverAddress, clientAddress; - bzero((char *)&serverAddress, sizeof(serverAddress)); - serverAddress.sin_family = AF_INET; - serverAddress.sin_addr.s_addr = INADDR_ANY; - serverAddress.sin_port = htons(port); - if (bind(socketFd, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) - { - fprintf(stderr, "Unable to bind socket\n"); - return 1; - } - - const char* bcp = getenv("BOOTCLASSPATH"); - if (bcp == NULL) { - fprintf(stderr, "BOOTCLASSPATH not set\n"); - return 1; - } - - - DexClassVerifyMode verifyMode = VERIFY_MODE_ALL; - DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED; - - if (dvmPrepForDexOpt(bcp, dexOptMode, verifyMode, - 0) != 0) - { - fprintf(stderr, "VM init failed\n"); - return 1; - } - - /* - * Map the entire file (so we don't have to worry about page - * alignment). The expectation is that the output file contains - * our DEX data plus room for a small header. - */ - bool success; - void* mapAddr; - mapAddr = mmap(NULL, inputInfo.st_size, PROT_READ, - MAP_PRIVATE, odexFd, 0); - if (mapAddr == MAP_FAILED) { - fprintf(stderr, "unable to mmap DEX cache: %s\n", strerror(errno)); - return 1; - } - - if (dvmDexFileOpenPartial(mapAddr + *((int *)(mapAddr+8)), *((int *)(mapAddr+12)), &pDvmDex) != 0) { - fprintf(stderr, "Unable to create DexFile\n"); - return 1; - } - - pClassLookup = dexCreateClassLookup(pDvmDex->pDexFile); - if (pClassLookup == NULL) - { - fprintf(stderr, "unable to create class lookup\n"); - return 1; - } - - pDvmDex->pDexFile->pClassLookup = pClassLookup; - - if (!loadAllClasses(pDvmDex)) - { - fprintf(stderr, "error while loading classes\n"); - return 1; - } - - - - - listen(socketFd, 1); - - int clientSocketLength = sizeof(clientAddress); - int clientFd = accept(socketFd, (struct sockaddr *) &clientAddress, &clientSocketLength); - if (clientFd < 0) - { - fprintf(stderr, "Unable to accept incomming connection\n"); - return 1; - } - - FILE *clientIn = fdopen(clientFd, "r"); - if (clientIn == 0) - { - fprintf(stderr, "Unable to fdopen socket to get input stream\n"); - return 1; - } - - FILE *clientOut = fdopen(dup(clientFd), "w"); - if (clientOut == 0) - { - fprintf(stderr, "Unable to fdopen socket to get output stream\n"); - return 1; - } - - char *command = NULL; - unsigned int len = 0; - dexStringCacheInit(&stringCache); - - while ((command = fgetln(clientIn, &len)) != NULL) { - while (len > 0 && (command[len-1] == '\r' || command[len-1] == '\n')) - len--; - char *buf = malloc(len+1); - memcpy(buf, command, len); - buf[len] = 0; - - //printf("%s\n", buf); - - char *cmd = strtok(buf, " "); - if (cmd == NULL) { - fprintf(clientOut, "err: error interpreting command\n"); - fflush(clientOut); - continue; - } - - switch (cmd[0]) - { - case 'F' : - { - char *classType = strtok(NULL, " "); - if (classType == NULL) - { - fprintf(clientOut, "err: no classType for field lookup\n"); - fflush(clientOut); - break; - } - - if (!dumpFields(classType, clientOut)) - { - fprintf(clientOut, "err: error while dumping fields\n"); - fflush(clientOut); - break; - } - - fprintf(clientOut, "done\n"); - fflush(clientOut); - break; - } - case 'I': - { - if (!dumpInlineMethods(clientOut)) - { - fprintf(clientOut, "err: inline method not found\n"); - fflush(clientOut); - break; - } - - fprintf(clientOut, "done\n"); - fflush(clientOut); - break; - } - case 'V': - { - char *classType = strtok(NULL, " "); - if (classType == NULL) - { - fprintf(clientOut, "err: no classType for vtable dump\n"); - fflush(clientOut); - break; - } - - if (!dumpVirtualMethods(classType, clientOut)) { - fprintf(clientOut, "err: error encountered while dumping virtual methods\n"); - fflush(clientOut); - break; - } - - fprintf(clientOut, "done\n"); - fflush(clientOut); - break; - } - case 'P': - { - char *classType = strtok(NULL, " "); - if (classType == NULL) - { - fprintf(clientOut, "err: no classType for superclass lookup\n"); - fflush(clientOut); - break; - } - - ClassObject *clazz = lookupSuperclass(classType); - if (clazz == NULL) - { - fprintf(clientOut, "class: \n"); - fflush(clientOut); - break; - } - - fprintf(clientOut, "class: %s\n", clazz->descriptor); - fflush(clientOut); - break; - } - case 'C': - { - char *classType1 = strtok(NULL, " "); - if (classType1 == NULL) - { - fprintf(clientOut, "err: no classType for common superclass lookup\n"); - fflush(clientOut); - break; - } - - ClassObject *clazz1; - if (classType1[0] == '[') - clazz1 = dvmFindArrayClass(classType1, NULL); - else - clazz1 = dvmFindSystemClassNoInit(classType1); - - if (clazz1 == NULL) - { - fprintf(clientOut, "err: class %s could not be found for common superclass lookup. This can be caused if a library the odex depends on is not in the BOOTCLASSPATH environment variable\n", classType1); - fflush(clientOut); - break; - } - - char *classType2 = strtok(NULL, " "); - if (classType2 == NULL) - { - fprintf(clientOut, "err: no classType for common superclass lookup\n"); - fflush(clientOut); - break; - } - - ClassObject *clazz2; - if (classType2[0] == '[') - clazz2 = dvmFindArrayClass(classType2, NULL); - else - clazz2 = dvmFindSystemClassNoInit(classType2); - - if (clazz2 == NULL) - { - fprintf(clientOut, "err: class %s could not be found for common superclass lookup. This can be caused if a library the odex depends on is not in the BOOTCLASSPATH environment variable\n", classType2); - fflush(clientOut); - break; - } - - ClassObject *clazz = findCommonSuperclass(clazz1, clazz2); - fprintf(clientOut, "class: %s\n", clazz->descriptor); - fflush(clientOut); - break; - } - default: - fprintf(clientOut, "err: not a valid command\n"); - fflush(clientOut); - } - - /*gettimeofday(&tv, NULL); - - printf("end %07d\n", tv.tv_usec);*/ - - - } - - return 0; -} - diff --git a/deodexerant/README b/deodexerant/README deleted file mode 100644 index 967abc7d..00000000 --- a/deodexerant/README +++ /dev/null @@ -1,26 +0,0 @@ -usage: -deodexerant - -deodexerant is a binary that is intended to run on an android phone, in order -to provide assistance to baksmali in deodexing .odex files. It communicates -over TCP and implements a simplistic protocol for looking up various -information needed during the deodex process, which can only be provided by -the dalvik vm. I.E. vtable lookups, field lookups by byte offset, superclass -lookups for classes not defined in the .odex file being processed, etc. - -deodexerant is intended to be build within the AOSP build system. Assuming -you have $MYDROID set to the root of the AOSP source tree, and $SMALI -set to the root of the smali source tree, - -1. cp -r $SMALI/deodexerant $MYDROID/dalvik/deodexerant -2. cd $MYDROID/dalvik/deodexerant -3. source ../../build/envsetup.sh -4. mm - -It should should spit out a deodexerant binary at - -$MYDROID/out/target/product/common/system/bin/deodexerant - -Or wherever your current build setup is configured to stick those types of -things - 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 6d2f3bd6..42cb8f68 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 @@ -1212,79 +1212,4 @@ public class ClassPath { return null; } } - - - public static void validateAgainstDeodexerant(String host, int port, int skipClasses) { - Deodexerant deodexerant = new Deodexerant(host, port); - - int count = 0; - - try { - String[] inlineMethods = deodexerant.getInlineMethods(); - (new DeodexUtil(null)).checkInlineMethods(inlineMethods); - } catch (Exception ex) { - throw ExceptionWithContext.withContext(ex, "Error while checking inline methods"); - } - - try { - for (ClassDef classDef: theClassPath.classDefs.values()) { - if (count < skipClasses) { - count++; - continue; - } - - if ((count%1000)==0) { - System.out.println(count); - } - if (classDef instanceof UnresolvedClassDef || classDef instanceof ArrayClassDef || - classDef instanceof PrimitiveClassDef) { - continue; - } - - String[] vtable = deodexerant.getVirtualMethods(classDef.classType); - - if (vtable.length != classDef.vtable.length) { - throw new ValidationException(String.format("virtual table size mismatch for class %s", - classDef.classType)); - } - - for (int i=0; i this.inlineMethods.length) { - throw new ValidationException("Inline method count mismatch"); - } - - for (int i=0; i responseLines = new ArrayList(); - String response = in.readLine(); - if (response == null) { - throw new RuntimeException("Error talking to deodexerant"); - } - while (!response.startsWith("done")) - { - if (response.startsWith("err")) { - throw new RuntimeException(response.substring(5)); - } - - int pos = response.indexOf(':') + 1; - - responseLines.add(response.substring(pos+1)); - response = in.readLine(); - } - - String[] lines = new String[responseLines.size()]; - - for (int i=0; i