Revert "Remove libdex (including dexdump/list)."

This reverts commit 48a66c5d261c333fc3d672e910b26cd6b1a05083.


REASON:
win_sdk is not happy with my migration :-(

Change-Id: Ib5d25b65ffef8bebc42fc586d2c65add04aa2b54
diff --git a/Android.mk b/Android.mk
index 39feee1..5401832 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,7 +15,10 @@
 LOCAL_PATH := $(call my-dir)
 
 subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+		libdex \
 		dexgen \
+		dexlist \
+		dexdump \
 		dx \
 		tools \
 	))
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 8eff181..2894484 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -51,3 +51,7 @@
 $(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
 $(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
 $(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(OUT)/obj/STATIC_LIBRARIES/libdex_intermediates/import_includes)
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
new file mode 100644
index 0000000..d0116bc
--- /dev/null
+++ b/dexdump/Android.mk
@@ -0,0 +1,70 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# dexdump, similar in purpose to objdump.
+#
+LOCAL_PATH:= $(call my-dir)
+
+dexdump_src_files := DexDump.cpp
+dexdump_c_includes := dalvik
+
+dexdump_static_libraries_sdk := \
+    libdex \
+    libbase
+
+dexdump_static_libraries := \
+    $(dexdump_static_libraries_sdk) \
+    libutils \
+    liblog
+
+##
+##
+## Build the device command line tool dexdump
+##
+##
+ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexdump
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_SHARED_LIBRARIES := libz liblog libutils
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries_sdk)
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_LDLIBS +=
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_EXECUTABLE)
+
+endif # !SDK_ONLY
+
+
+##
+##
+## Build the host command line tool dexdump
+##
+##
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexdump
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries)
+ifneq ($(strip $(USE_MINGW)),)
+LOCAL_STATIC_LIBRARIES += libz
+else
+LOCAL_LDLIBS += -lpthread -lz
+endif
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
new file mode 100644
index 0000000..d3735d6
--- /dev/null
+++ b/dexdump/DexDump.cpp
@@ -0,0 +1,1925 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * The "dexdump" tool is intended to mimic "objdump".  When possible, use
+ * similar command-line arguments.
+ *
+ * TODO: rework the "plain" output format to be more regexp-friendly
+ *
+ * Differences between XML output and the "current.xml" file:
+ * - classes in same package are not all grouped together; generally speaking
+ *   nothing is sorted
+ * - no "deprecated" on fields and methods
+ * - no "value" on fields
+ * - no parameter names
+ * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
+ * - class shows declared fields and methods; does not show inherited fields
+ */
+
+#include "libdex/DexFile.h"
+
+#include "libdex/CmdUtils.h"
+#include "libdex/DexCatch.h"
+#include "libdex/DexClass.h"
+#include "libdex/DexDebugInfo.h"
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexProto.h"
+#include "libdex/InstrUtils.h"
+#include "libdex/SysUtil.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <assert.h>
+#include <inttypes.h>
+
+static const char* gProgName = "dexdump";
+
+enum OutputFormat {
+    OUTPUT_PLAIN = 0,               /* default */
+    OUTPUT_XML,                     /* fancy */
+};
+
+/* command-line options */
+struct Options {
+    bool checksumOnly;
+    bool disassemble;
+    bool showFileHeaders;
+    bool showSectionHeaders;
+    bool ignoreBadChecksum;
+    bool dumpRegisterMaps;
+    OutputFormat outputFormat;
+    const char* tempFileName;
+    bool exportsOnly;
+    bool verbose;
+};
+
+struct Options gOptions;
+
+/* basic info about a field or method */
+struct FieldMethodInfo {
+    const char* classDescriptor;
+    const char* name;
+    const char* signature;
+};
+
+/*
+ * Get 2 little-endian bytes.
+ */
+static inline u2 get2LE(unsigned char const* pSrc)
+{
+    return pSrc[0] | (pSrc[1] << 8);
+}
+
+/*
+ * Get 4 little-endian bytes.
+ */
+static inline u4 get4LE(unsigned char const* pSrc)
+{
+    return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
+}
+
+/*
+ * Converts a single-character primitive type into its human-readable
+ * equivalent.
+ */
+static const char* primitiveTypeLabel(char typeChar)
+{
+    switch (typeChar) {
+    case 'B':   return "byte";
+    case 'C':   return "char";
+    case 'D':   return "double";
+    case 'F':   return "float";
+    case 'I':   return "int";
+    case 'J':   return "long";
+    case 'S':   return "short";
+    case 'V':   return "void";
+    case 'Z':   return "boolean";
+    default:
+                return "UNKNOWN";
+    }
+}
+
+/*
+ * Converts a type descriptor to human-readable "dotted" form.  For
+ * example, "Ljava/lang/String;" becomes "java.lang.String", and
+ * "[I" becomes "int[]".  Also converts '$' to '.', which means this
+ * form can't be converted back to a descriptor.
+ */
+static char* descriptorToDot(const char* str)
+{
+    int targetLen = strlen(str);
+    int offset = 0;
+    int arrayDepth = 0;
+    char* newStr;
+
+    /* strip leading [s; will be added to end */
+    while (targetLen > 1 && str[offset] == '[') {
+        offset++;
+        targetLen--;
+    }
+    arrayDepth = offset;
+
+    if (targetLen == 1) {
+        /* primitive type */
+        str = primitiveTypeLabel(str[offset]);
+        offset = 0;
+        targetLen = strlen(str);
+    } else {
+        /* account for leading 'L' and trailing ';' */
+        if (targetLen >= 2 && str[offset] == 'L' &&
+            str[offset+targetLen-1] == ';')
+        {
+            targetLen -= 2;
+            offset++;
+        }
+    }
+
+    newStr = (char*)malloc(targetLen + arrayDepth * 2 +1);
+
+    /* copy class name over */
+    int i;
+    for (i = 0; i < targetLen; i++) {
+        char ch = str[offset + i];
+        newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
+    }
+
+    /* add the appropriate number of brackets for arrays */
+    while (arrayDepth-- > 0) {
+        newStr[i++] = '[';
+        newStr[i++] = ']';
+    }
+    newStr[i] = '\0';
+    assert(i == targetLen + arrayDepth * 2);
+
+    return newStr;
+}
+
+/*
+ * Converts the class name portion of a type descriptor to human-readable
+ * "dotted" form.
+ *
+ * Returns a newly-allocated string.
+ */
+static char* descriptorClassToDot(const char* str)
+{
+    const char* lastSlash;
+    char* newStr;
+    char* cp;
+
+    /* reduce to just the class name, trimming trailing ';' */
+    lastSlash = strrchr(str, '/');
+    if (lastSlash == NULL)
+        lastSlash = str + 1;        /* start past 'L' */
+    else
+        lastSlash++;                /* start past '/' */
+
+    newStr = strdup(lastSlash);
+    newStr[strlen(lastSlash)-1] = '\0';
+    for (cp = newStr; *cp != '\0'; cp++) {
+        if (*cp == '$')
+            *cp = '.';
+    }
+
+    return newStr;
+}
+
+/*
+ * Returns a quoted string representing the boolean value.
+ */
+static const char* quotedBool(bool val)
+{
+    if (val)
+        return "\"true\"";
+    else
+        return "\"false\"";
+}
+
+static const char* quotedVisibility(u4 accessFlags)
+{
+    if ((accessFlags & ACC_PUBLIC) != 0)
+        return "\"public\"";
+    else if ((accessFlags & ACC_PROTECTED) != 0)
+        return "\"protected\"";
+    else if ((accessFlags & ACC_PRIVATE) != 0)
+        return "\"private\"";
+    else
+        return "\"package\"";
+}
+
+/*
+ * Count the number of '1' bits in a word.
+ */
+static int countOnes(u4 val)
+{
+    int count = 0;
+
+    val = val - ((val >> 1) & 0x55555555);
+    val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
+    count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+
+    return count;
+}
+
+/*
+ * Flag for use with createAccessFlagStr().
+ */
+enum AccessFor {
+    kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
+    kAccessForMAX
+};
+
+/*
+ * Create a new string with human-readable access flags.
+ *
+ * In the base language the access_flags fields are type u2; in Dalvik
+ * they're u4.
+ */
+static char* createAccessFlagStr(u4 flags, AccessFor forWhat)
+{
+#define NUM_FLAGS   18
+    static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
+        {
+            /* class, inner class */
+            "PUBLIC",           /* 0x0001 */
+            "PRIVATE",          /* 0x0002 */
+            "PROTECTED",        /* 0x0004 */
+            "STATIC",           /* 0x0008 */
+            "FINAL",            /* 0x0010 */
+            "?",                /* 0x0020 */
+            "?",                /* 0x0040 */
+            "?",                /* 0x0080 */
+            "?",                /* 0x0100 */
+            "INTERFACE",        /* 0x0200 */
+            "ABSTRACT",         /* 0x0400 */
+            "?",                /* 0x0800 */
+            "SYNTHETIC",        /* 0x1000 */
+            "ANNOTATION",       /* 0x2000 */
+            "ENUM",             /* 0x4000 */
+            "?",                /* 0x8000 */
+            "VERIFIED",         /* 0x10000 */
+            "OPTIMIZED",        /* 0x20000 */
+        },
+        {
+            /* method */
+            "PUBLIC",           /* 0x0001 */
+            "PRIVATE",          /* 0x0002 */
+            "PROTECTED",        /* 0x0004 */
+            "STATIC",           /* 0x0008 */
+            "FINAL",            /* 0x0010 */
+            "SYNCHRONIZED",     /* 0x0020 */
+            "BRIDGE",           /* 0x0040 */
+            "VARARGS",          /* 0x0080 */
+            "NATIVE",           /* 0x0100 */
+            "?",                /* 0x0200 */
+            "ABSTRACT",         /* 0x0400 */
+            "STRICT",           /* 0x0800 */
+            "SYNTHETIC",        /* 0x1000 */
+            "?",                /* 0x2000 */
+            "?",                /* 0x4000 */
+            "MIRANDA",          /* 0x8000 */
+            "CONSTRUCTOR",      /* 0x10000 */
+            "DECLARED_SYNCHRONIZED", /* 0x20000 */
+        },
+        {
+            /* field */
+            "PUBLIC",           /* 0x0001 */
+            "PRIVATE",          /* 0x0002 */
+            "PROTECTED",        /* 0x0004 */
+            "STATIC",           /* 0x0008 */
+            "FINAL",            /* 0x0010 */
+            "?",                /* 0x0020 */
+            "VOLATILE",         /* 0x0040 */
+            "TRANSIENT",        /* 0x0080 */
+            "?",                /* 0x0100 */
+            "?",                /* 0x0200 */
+            "?",                /* 0x0400 */
+            "?",                /* 0x0800 */
+            "SYNTHETIC",        /* 0x1000 */
+            "?",                /* 0x2000 */
+            "ENUM",             /* 0x4000 */
+            "?",                /* 0x8000 */
+            "?",                /* 0x10000 */
+            "?",                /* 0x20000 */
+        },
+    };
+    const int kLongest = 21;        /* strlen of longest string above */
+    int i, count;
+    char* str;
+    char* cp;
+
+    /*
+     * Allocate enough storage to hold the expected number of strings,
+     * plus a space between each.  We over-allocate, using the longest
+     * string above as the base metric.
+     */
+    count = countOnes(flags);
+    cp = str = (char*) malloc(count * (kLongest+1) +1);
+
+    for (i = 0; i < NUM_FLAGS; i++) {
+        if (flags & 0x01) {
+            const char* accessStr = kAccessStrings[forWhat][i];
+            int len = strlen(accessStr);
+            if (cp != str)
+                *cp++ = ' ';
+
+            memcpy(cp, accessStr, len);
+            cp += len;
+        }
+        flags >>= 1;
+    }
+    *cp = '\0';
+
+    return str;
+}
+
+
+/*
+ * Copy character data from "data" to "out", converting non-ASCII values
+ * to printf format chars or an ASCII filler ('.' or '?').
+ *
+ * The output buffer must be able to hold (2*len)+1 bytes.  The result is
+ * NUL-terminated.
+ */
+static void asciify(char* out, const unsigned char* data, size_t len)
+{
+    while (len--) {
+        if (*data < 0x20) {
+            /* could do more here, but we don't need them yet */
+            switch (*data) {
+            case '\0':
+                *out++ = '\\';
+                *out++ = '0';
+                break;
+            case '\n':
+                *out++ = '\\';
+                *out++ = 'n';
+                break;
+            default:
+                *out++ = '.';
+                break;
+            }
+        } else if (*data >= 0x80) {
+            *out++ = '?';
+        } else {
+            *out++ = *data;
+        }
+        data++;
+    }
+    *out = '\0';
+}
+
+/*
+ * Dump the file header.
+ */
+void dumpFileHeader(const DexFile* pDexFile)
+{
+    const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
+    const DexHeader* pHeader = pDexFile->pHeader;
+    char sanitized[sizeof(pHeader->magic)*2 +1];
+
+    assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic));
+
+    if (pOptHeader != NULL) {
+        printf("Optimized DEX file header:\n");
+
+        asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic));
+        printf("magic               : '%s'\n", sanitized);
+        printf("dex_offset          : %d (0x%06x)\n",
+            pOptHeader->dexOffset, pOptHeader->dexOffset);
+        printf("dex_length          : %d\n", pOptHeader->dexLength);
+        printf("deps_offset         : %d (0x%06x)\n",
+            pOptHeader->depsOffset, pOptHeader->depsOffset);
+        printf("deps_length         : %d\n", pOptHeader->depsLength);
+        printf("opt_offset          : %d (0x%06x)\n",
+            pOptHeader->optOffset, pOptHeader->optOffset);
+        printf("opt_length          : %d\n", pOptHeader->optLength);
+        printf("flags               : %08x\n", pOptHeader->flags);
+        printf("checksum            : %08x\n", pOptHeader->checksum);
+        printf("\n");
+    }
+
+    printf("DEX file header:\n");
+    asciify(sanitized, pHeader->magic, sizeof(pHeader->magic));
+    printf("magic               : '%s'\n", sanitized);
+    printf("checksum            : %08x\n", pHeader->checksum);
+    printf("signature           : %02x%02x...%02x%02x\n",
+        pHeader->signature[0], pHeader->signature[1],
+        pHeader->signature[kSHA1DigestLen-2],
+        pHeader->signature[kSHA1DigestLen-1]);
+    printf("file_size           : %d\n", pHeader->fileSize);
+    printf("header_size         : %d\n", pHeader->headerSize);
+    printf("link_size           : %d\n", pHeader->linkSize);
+    printf("link_off            : %d (0x%06x)\n",
+        pHeader->linkOff, pHeader->linkOff);
+    printf("string_ids_size     : %d\n", pHeader->stringIdsSize);
+    printf("string_ids_off      : %d (0x%06x)\n",
+        pHeader->stringIdsOff, pHeader->stringIdsOff);
+    printf("type_ids_size       : %d\n", pHeader->typeIdsSize);
+    printf("type_ids_off        : %d (0x%06x)\n",
+        pHeader->typeIdsOff, pHeader->typeIdsOff);
+    printf("proto_ids_size       : %d\n", pHeader->protoIdsSize);
+    printf("proto_ids_off        : %d (0x%06x)\n",
+        pHeader->protoIdsOff, pHeader->protoIdsOff);
+    printf("field_ids_size      : %d\n", pHeader->fieldIdsSize);
+    printf("field_ids_off       : %d (0x%06x)\n",
+        pHeader->fieldIdsOff, pHeader->fieldIdsOff);
+    printf("method_ids_size     : %d\n", pHeader->methodIdsSize);
+    printf("method_ids_off      : %d (0x%06x)\n",
+        pHeader->methodIdsOff, pHeader->methodIdsOff);
+    printf("class_defs_size     : %d\n", pHeader->classDefsSize);
+    printf("class_defs_off      : %d (0x%06x)\n",
+        pHeader->classDefsOff, pHeader->classDefsOff);
+    printf("data_size           : %d\n", pHeader->dataSize);
+    printf("data_off            : %d (0x%06x)\n",
+        pHeader->dataOff, pHeader->dataOff);
+    printf("\n");
+}
+
+/*
+ * Dump the "table of contents" for the opt area.
+ */
+void dumpOptDirectory(const DexFile* pDexFile)
+{
+    const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
+    if (pOptHeader == NULL)
+        return;
+
+    printf("OPT section contents:\n");
+
+    const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset);
+
+    if (*pOpt == 0) {
+        printf("(1.0 format, only class lookup table is present)\n\n");
+        return;
+    }
+
+    /*
+     * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit
+     * length, then the data.  Chunks start on 64-bit boundaries.
+     */
+    while (*pOpt != kDexChunkEnd) {
+        const char* verboseStr;
+
+        u4 size = *(pOpt+1);
+
+        switch (*pOpt) {
+        case kDexChunkClassLookup:
+            verboseStr = "class lookup hash table";
+            break;
+        case kDexChunkRegisterMaps:
+            verboseStr = "register maps";
+            break;
+        default:
+            verboseStr = "(unknown chunk type)";
+            break;
+        }
+
+        printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt,
+            *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt,
+            verboseStr, size);
+
+        size = (size + 8 + 7) & ~7;
+        pOpt += size / sizeof(u4);
+    }
+    printf("\n");
+}
+
+/*
+ * Dump a class_def_item.
+ */
+void dumpClassDef(DexFile* pDexFile, int idx)
+{
+    const DexClassDef* pClassDef;
+    const u1* pEncodedData;
+    DexClassData* pClassData;
+
+    pClassDef = dexGetClassDef(pDexFile, idx);
+    pEncodedData = dexGetClassData(pDexFile, pClassDef);
+    pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+
+    if (pClassData == NULL) {
+        fprintf(stderr, "Trouble reading class data\n");
+        return;
+    }
+
+    printf("Class #%d header:\n", idx);
+    printf("class_idx           : %d\n", pClassDef->classIdx);
+    printf("access_flags        : %d (0x%04x)\n",
+        pClassDef->accessFlags, pClassDef->accessFlags);
+    printf("superclass_idx      : %d\n", pClassDef->superclassIdx);
+    printf("interfaces_off      : %d (0x%06x)\n",
+        pClassDef->interfacesOff, pClassDef->interfacesOff);
+    printf("source_file_idx     : %d\n", pClassDef->sourceFileIdx);
+    printf("annotations_off     : %d (0x%06x)\n",
+        pClassDef->annotationsOff, pClassDef->annotationsOff);
+    printf("class_data_off      : %d (0x%06x)\n",
+        pClassDef->classDataOff, pClassDef->classDataOff);
+    printf("static_fields_size  : %d\n", pClassData->header.staticFieldsSize);
+    printf("instance_fields_size: %d\n",
+            pClassData->header.instanceFieldsSize);
+    printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
+    printf("virtual_methods_size: %d\n",
+            pClassData->header.virtualMethodsSize);
+    printf("\n");
+
+    free(pClassData);
+}
+
+/*
+ * Dump an interface that a class declares to implement.
+ */
+void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
+    int i)
+{
+    const char* interfaceName =
+        dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : '%s'\n", i, interfaceName);
+    } else {
+        char* dotted = descriptorToDot(interfaceName);
+        printf("<implements name=\"%s\">\n</implements>\n", dotted);
+        free(dotted);
+    }
+}
+
+/*
+ * Dump the catches table associated with the code.
+ */
+void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
+{
+    u4 triesSize = pCode->triesSize;
+
+    if (triesSize == 0) {
+        printf("      catches       : (none)\n");
+        return;
+    }
+
+    printf("      catches       : %d\n", triesSize);
+
+    const DexTry* pTries = dexGetTries(pCode);
+    u4 i;
+
+    for (i = 0; i < triesSize; i++) {
+        const DexTry* pTry = &pTries[i];
+        u4 start = pTry->startAddr;
+        u4 end = start + pTry->insnCount;
+        DexCatchIterator iterator;
+
+        printf("        0x%04x - 0x%04x\n", start, end);
+
+        dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
+
+        for (;;) {
+            DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+            const char* descriptor;
+
+            if (handler == NULL) {
+                break;
+            }
+
+            descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
+                dexStringByTypeIdx(pDexFile, handler->typeIdx);
+
+            printf("          %s -> 0x%04x\n", descriptor,
+                    handler->address);
+        }
+    }
+}
+
+static int dumpPositionsCb(void * /* cnxt */, u4 address, u4 lineNum)
+{
+    printf("        0x%04x line=%d\n", address, lineNum);
+    return 0;
+}
+
+/*
+ * Dump the positions list.
+ */
+void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
+        const DexMethod *pDexMethod)
+{
+    printf("      positions     : \n");
+    const DexMethodId *pMethodId
+            = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    const char *classDescriptor
+            = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
+            pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
+}
+
+static void dumpLocalsCb(void * /* cnxt */, u2 reg, u4 startAddress,
+        u4 endAddress, const char *name, const char *descriptor,
+        const char *signature)
+{
+    printf("        0x%04x - 0x%04x reg=%d %s %s %s\n",
+            startAddress, endAddress, reg, name, descriptor,
+            signature);
+}
+
+/*
+ * Dump the locals list.
+ */
+void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
+        const DexMethod *pDexMethod)
+{
+    printf("      locals        : \n");
+
+    const DexMethodId *pMethodId
+            = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    const char *classDescriptor
+            = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
+            pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
+}
+
+/*
+ * Get information about a method.
+ */
+bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
+{
+    const DexMethodId* pMethodId;
+
+    if (methodIdx >= pDexFile->pHeader->methodIdsSize)
+        return false;
+
+    pMethodId = dexGetMethodId(pDexFile, methodIdx);
+    pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
+    pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+
+    pMethInfo->classDescriptor =
+            dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+    return true;
+}
+
+/*
+ * Get information about a field.
+ */
+bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
+{
+    const DexFieldId* pFieldId;
+
+    if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
+        return false;
+
+    pFieldId = dexGetFieldId(pDexFile, fieldIdx);
+    pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
+    pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+    pFieldInfo->classDescriptor =
+        dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
+    return true;
+}
+
+
+/*
+ * Look up a class' descriptor.
+ */
+const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
+{
+    return dexStringByTypeIdx(pDexFile, classIdx);
+}
+
+/*
+ * Helper for dumpInstruction(), which builds the string
+ * representation for the index in the given instruction. This will
+ * first try to use the given buffer, but if the result won't fit,
+ * then this will allocate a new buffer to hold the result. A pointer
+ * to the buffer which holds the full result is always returned, and
+ * this can be compared with the one passed in, to see if the result
+ * needs to be free()d.
+ */
+static char* indexString(DexFile* pDexFile,
+    const DecodedInstruction* pDecInsn, char* buf, size_t bufSize)
+{
+    int outSize;
+    u4 index;
+    u4 width;
+
+    /* TODO: Make the index *always* be in field B, to simplify this code. */
+    switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
+    case kFmt20bc:
+    case kFmt21c:
+    case kFmt35c:
+    case kFmt35ms:
+    case kFmt3rc:
+    case kFmt3rms:
+    case kFmt35mi:
+    case kFmt3rmi:
+        index = pDecInsn->vB;
+        width = 4;
+        break;
+    case kFmt31c:
+        index = pDecInsn->vB;
+        width = 8;
+        break;
+    case kFmt22c:
+    case kFmt22cs:
+        index = pDecInsn->vC;
+        width = 4;
+        break;
+    default:
+        index = 0;
+        width = 4;
+        break;
+    }
+
+    switch (pDecInsn->indexType) {
+    case kIndexUnknown:
+        /*
+         * This function shouldn't ever get called for this type, but do
+         * something sensible here, just to help with debugging.
+         */
+        outSize = snprintf(buf, bufSize, "<unknown-index>");
+        break;
+    case kIndexNone:
+        /*
+         * This function shouldn't ever get called for this type, but do
+         * something sensible here, just to help with debugging.
+         */
+        outSize = snprintf(buf, bufSize, "<no-index>");
+        break;
+    case kIndexVaries:
+        /*
+         * This one should never show up in a dexdump, so no need to try
+         * to get fancy here.
+         */
+        outSize = snprintf(buf, bufSize, "<index-varies> // thing@%0*x",
+                width, index);
+        break;
+    case kIndexTypeRef:
+        if (index < pDexFile->pHeader->typeIdsSize) {
+            outSize = snprintf(buf, bufSize, "%s // type@%0*x",
+                               getClassDescriptor(pDexFile, index), width, index);
+        } else {
+            outSize = snprintf(buf, bufSize, "<type?> // type@%0*x", width, index);
+        }
+        break;
+    case kIndexStringRef:
+        if (index < pDexFile->pHeader->stringIdsSize) {
+            outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
+                               dexStringById(pDexFile, index), width, index);
+        } else {
+            outSize = snprintf(buf, bufSize, "<string?> // string@%0*x",
+                               width, index);
+        }
+        break;
+    case kIndexMethodRef:
+        {
+            FieldMethodInfo methInfo;
+            if (getMethodInfo(pDexFile, index, &methInfo)) {
+                outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
+                        methInfo.classDescriptor, methInfo.name,
+                        methInfo.signature, width, index);
+                free((void *) methInfo.signature);
+            } else {
+                outSize = snprintf(buf, bufSize, "<method?> // method@%0*x",
+                        width, index);
+            }
+        }
+        break;
+    case kIndexFieldRef:
+        {
+            FieldMethodInfo fieldInfo;
+            if (getFieldInfo(pDexFile, index, &fieldInfo)) {
+                outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
+                        fieldInfo.classDescriptor, fieldInfo.name,
+                        fieldInfo.signature, width, index);
+            } else {
+                outSize = snprintf(buf, bufSize, "<field?> // field@%0*x",
+                        width, index);
+            }
+        }
+        break;
+    case kIndexInlineMethod:
+        outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x",
+                width, index, width, index);
+        break;
+    case kIndexVtableOffset:
+        outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
+                width, index, width, index);
+        break;
+    case kIndexFieldOffset:
+        outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
+        break;
+    default:
+        outSize = snprintf(buf, bufSize, "<?>");
+        break;
+    }
+
+    if (outSize >= (int) bufSize) {
+        /*
+         * The buffer wasn't big enough; allocate and retry. Note:
+         * snprintf() doesn't count the '\0' as part of its returned
+         * size, so we add explicit space for it here.
+         */
+        outSize++;
+        buf = (char*)malloc(outSize);
+        if (buf == NULL) {
+            return NULL;
+        }
+        return indexString(pDexFile, pDecInsn, buf, outSize);
+    } else {
+        return buf;
+    }
+}
+
+/*
+ * Dump a single instruction.
+ */
+void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
+    int insnWidth, const DecodedInstruction* pDecInsn)
+{
+    char indexBufChars[200];
+    char *indexBuf = indexBufChars;
+    const u2* insns = pCode->insns;
+    int i;
+
+    // Address of instruction (expressed as byte offset).
+    printf("%06zx:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
+
+    for (i = 0; i < 8; i++) {
+        if (i < insnWidth) {
+            if (i == 7) {
+                printf(" ... ");
+            } else {
+                /* print 16-bit value in little-endian order */
+                const u1* bytePtr = (const u1*) &insns[insnIdx+i];
+                printf(" %02x%02x", bytePtr[0], bytePtr[1]);
+            }
+        } else {
+            fputs("     ", stdout);
+        }
+    }
+
+    if (pDecInsn->opcode == OP_NOP) {
+        u2 instr = get2LE((const u1*) &insns[insnIdx]);
+        if (instr == kPackedSwitchSignature) {
+            printf("|%04x: packed-switch-data (%d units)",
+                insnIdx, insnWidth);
+        } else if (instr == kSparseSwitchSignature) {
+            printf("|%04x: sparse-switch-data (%d units)",
+                insnIdx, insnWidth);
+        } else if (instr == kArrayDataSignature) {
+            printf("|%04x: array-data (%d units)",
+                insnIdx, insnWidth);
+        } else {
+            printf("|%04x: nop // spacer", insnIdx);
+        }
+    } else {
+        printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opcode));
+    }
+
+    if (pDecInsn->indexType != kIndexNone) {
+        indexBuf = indexString(pDexFile, pDecInsn,
+                indexBufChars, sizeof(indexBufChars));
+    }
+
+    switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
+    case kFmt10x:        // op
+        break;
+    case kFmt12x:        // op vA, vB
+        printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
+        break;
+    case kFmt11n:        // op vA, #+B
+        printf(" v%d, #int %d // #%x",
+            pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
+        break;
+    case kFmt11x:        // op vAA
+        printf(" v%d", pDecInsn->vA);
+        break;
+    case kFmt10t:        // op +AA
+    case kFmt20t:        // op +AAAA
+        {
+            s4 targ = (s4) pDecInsn->vA;
+            printf(" %04x // %c%04x",
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+        }
+        break;
+    case kFmt22x:        // op vAA, vBBBB
+        printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
+        break;
+    case kFmt21t:        // op vAA, +BBBB
+        {
+            s4 targ = (s4) pDecInsn->vB;
+            printf(" v%d, %04x // %c%04x", pDecInsn->vA,
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+        }
+        break;
+    case kFmt21s:        // op vAA, #+BBBB
+        printf(" v%d, #int %d // #%x",
+            pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
+        break;
+    case kFmt21h:        // op vAA, #+BBBB0000[00000000]
+        // The printed format varies a bit based on the actual opcode.
+        if (pDecInsn->opcode == OP_CONST_HIGH16) {
+            s4 value = pDecInsn->vB << 16;
+            printf(" v%d, #int %d // #%x",
+                pDecInsn->vA, value, (u2)pDecInsn->vB);
+        } else {
+            s8 value = ((s8) pDecInsn->vB) << 48;
+            printf(" v%d, #long %" PRId64 " // #%x",
+                pDecInsn->vA, value, (u2)pDecInsn->vB);
+        }
+        break;
+    case kFmt21c:        // op vAA, thing@BBBB
+    case kFmt31c:        // op vAA, thing@BBBBBBBB
+        printf(" v%d, %s", pDecInsn->vA, indexBuf);
+        break;
+    case kFmt23x:        // op vAA, vBB, vCC
+        printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
+        break;
+    case kFmt22b:        // op vAA, vBB, #+CC
+        printf(" v%d, v%d, #int %d // #%02x",
+            pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
+        break;
+    case kFmt22t:        // op vA, vB, +CCCC
+        {
+            s4 targ = (s4) pDecInsn->vC;
+            printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+        }
+        break;
+    case kFmt22s:        // op vA, vB, #+CCCC
+        printf(" v%d, v%d, #int %d // #%04x",
+            pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
+        break;
+    case kFmt22c:        // op vA, vB, thing@CCCC
+    case kFmt22cs:       // [opt] op vA, vB, field offset CCCC
+        printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf);
+        break;
+    case kFmt30t:
+        printf(" #%08x", pDecInsn->vA);
+        break;
+    case kFmt31i:        // op vAA, #+BBBBBBBB
+        {
+            /* this is often, but not always, a float */
+            union {
+                float f;
+                u4 i;
+            } conv;
+            conv.i = pDecInsn->vB;
+            printf(" v%d, #float %f // #%08x",
+                pDecInsn->vA, conv.f, pDecInsn->vB);
+        }
+        break;
+    case kFmt31t:       // op vAA, offset +BBBBBBBB
+        printf(" v%d, %08x // +%08x",
+            pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
+        break;
+    case kFmt32x:        // op vAAAA, vBBBB
+        printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
+        break;
+    case kFmt35c:        // op {vC, vD, vE, vF, vG}, thing@BBBB
+    case kFmt35ms:       // [opt] invoke-virtual+super
+    case kFmt35mi:       // [opt] inline invoke
+        {
+            fputs(" {", stdout);
+            for (i = 0; i < (int) pDecInsn->vA; i++) {
+                if (i == 0)
+                    printf("v%d", pDecInsn->arg[i]);
+                else
+                    printf(", v%d", pDecInsn->arg[i]);
+            }
+            printf("}, %s", indexBuf);
+        }
+        break;
+    case kFmt3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
+    case kFmt3rms:       // [opt] invoke-virtual+super/range
+    case kFmt3rmi:       // [opt] execute-inline/range
+        {
+            /*
+             * This doesn't match the "dx" output when some of the args are
+             * 64-bit values -- dx only shows the first register.
+             */
+            fputs(" {", stdout);
+            for (i = 0; i < (int) pDecInsn->vA; i++) {
+                if (i == 0)
+                    printf("v%d", pDecInsn->vC + i);
+                else
+                    printf(", v%d", pDecInsn->vC + i);
+            }
+            printf("}, %s", indexBuf);
+        }
+        break;
+    case kFmt51l:        // op vAA, #+BBBBBBBBBBBBBBBB
+        {
+            /* this is often, but not always, a double */
+            union {
+                double d;
+                u8 j;
+            } conv;
+            conv.j = pDecInsn->vB_wide;
+            printf(" v%d, #double %f // #%016" PRIx64,
+                pDecInsn->vA, conv.d, pDecInsn->vB_wide);
+        }
+        break;
+    case kFmt00x:        // unknown op or breakpoint
+        break;
+    default:
+        printf(" ???");
+        break;
+    }
+
+    putchar('\n');
+
+    if (indexBuf != indexBufChars) {
+        free(indexBuf);
+    }
+}
+
+/*
+ * Dump a bytecode disassembly.
+ */
+void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
+{
+    const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
+    const u2* insns;
+    int insnIdx;
+    FieldMethodInfo methInfo;
+    int startAddr;
+    char* className = NULL;
+
+    assert(pCode->insnsSize > 0);
+    insns = pCode->insns;
+
+    methInfo.classDescriptor =
+    methInfo.name =
+    methInfo.signature = NULL;
+
+    getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
+    startAddr = ((u1*)pCode - pDexFile->baseAddr);
+    className = descriptorToDot(methInfo.classDescriptor);
+
+    printf("%06x:                                        |[%06x] %s.%s:%s\n",
+        startAddr, startAddr,
+        className, methInfo.name, methInfo.signature);
+    free((void *) methInfo.signature);
+
+    insnIdx = 0;
+    while (insnIdx < (int) pCode->insnsSize) {
+        int insnWidth;
+        DecodedInstruction decInsn;
+        u2 instr;
+
+        /*
+         * Note: This code parallels the function
+         * dexGetWidthFromInstruction() in InstrUtils.c, but this version
+         * can deal with data in either endianness.
+         *
+         * TODO: Figure out if this really matters, and possibly change
+         * this to just use dexGetWidthFromInstruction().
+         */
+        instr = get2LE((const u1*)insns);
+        if (instr == kPackedSwitchSignature) {
+            insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
+        } else if (instr == kSparseSwitchSignature) {
+            insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
+        } else if (instr == kArrayDataSignature) {
+            int width = get2LE((const u1*)(insns+1));
+            int size = get2LE((const u1*)(insns+2)) |
+                       (get2LE((const u1*)(insns+3))<<16);
+            // The plus 1 is to round up for odd size and width.
+            insnWidth = 4 + ((size * width) + 1) / 2;
+        } else {
+            Opcode opcode = dexOpcodeFromCodeUnit(instr);
+            insnWidth = dexGetWidthFromOpcode(opcode);
+            if (insnWidth == 0) {
+                fprintf(stderr,
+                    "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
+                break;
+            }
+        }
+
+        dexDecodeInstruction(insns, &decInsn);
+        dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
+
+        insns += insnWidth;
+        insnIdx += insnWidth;
+    }
+
+    free(className);
+}
+
+/*
+ * Dump a "code" struct.
+ */
+void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
+{
+    const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
+
+    printf("      registers     : %d\n", pCode->registersSize);
+    printf("      ins           : %d\n", pCode->insSize);
+    printf("      outs          : %d\n", pCode->outsSize);
+    printf("      insns size    : %d 16-bit code units\n", pCode->insnsSize);
+
+    if (gOptions.disassemble)
+        dumpBytecodes(pDexFile, pDexMethod);
+
+    dumpCatches(pDexFile, pCode);
+    /* both of these are encoded in debug info */
+    dumpPositions(pDexFile, pCode, pDexMethod);
+    dumpLocals(pDexFile, pCode, pDexMethod);
+}
+
+/*
+ * Dump a method.
+ */
+void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
+{
+    const DexMethodId* pMethodId;
+    const char* backDescriptor;
+    const char* name;
+    char* typeDescriptor = NULL;
+    char* accessStr = NULL;
+
+    if (gOptions.exportsOnly &&
+        (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
+    {
+        return;
+    }
+
+    pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    name = dexStringById(pDexFile, pMethodId->nameIdx);
+    typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+
+    backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    accessStr = createAccessFlagStr(pDexMethod->accessFlags,
+                    kAccessForMethod);
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : (in %s)\n", i, backDescriptor);
+        printf("      name          : '%s'\n", name);
+        printf("      type          : '%s'\n", typeDescriptor);
+        printf("      access        : 0x%04x (%s)\n",
+            pDexMethod->accessFlags, accessStr);
+
+        if (pDexMethod->codeOff == 0) {
+            printf("      code          : (none)\n");
+        } else {
+            printf("      code          -\n");
+            dumpCode(pDexFile, pDexMethod);
+        }
+
+        if (gOptions.disassemble)
+            putchar('\n');
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        bool constructor = (name[0] == '<');
+
+        if (constructor) {
+            char* tmp;
+
+            tmp = descriptorClassToDot(backDescriptor);
+            printf("<constructor name=\"%s\"\n", tmp);
+            free(tmp);
+
+            tmp = descriptorToDot(backDescriptor);
+            printf(" type=\"%s\"\n", tmp);
+            free(tmp);
+        } else {
+            printf("<method name=\"%s\"\n", name);
+
+            const char* returnType = strrchr(typeDescriptor, ')');
+            if (returnType == NULL) {
+                fprintf(stderr, "bad method type descriptor '%s'\n",
+                    typeDescriptor);
+                goto bail;
+            }
+
+            char* tmp = descriptorToDot(returnType+1);
+            printf(" return=\"%s\"\n", tmp);
+            free(tmp);
+
+            printf(" abstract=%s\n",
+                quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
+            printf(" native=%s\n",
+                quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
+
+            bool isSync =
+                (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
+                (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
+            printf(" synchronized=%s\n", quotedBool(isSync));
+        }
+
+        printf(" static=%s\n",
+            quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pDexMethod->accessFlags));
+
+        printf(">\n");
+
+        /*
+         * Parameters.
+         */
+        if (typeDescriptor[0] != '(') {
+            fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
+            goto bail;
+        }
+
+        char tmpBuf[strlen(typeDescriptor)+1];      /* more than big enough */
+        int argNum = 0;
+
+        const char* base = typeDescriptor+1;
+
+        while (*base != ')') {
+            char* cp = tmpBuf;
+
+            while (*base == '[')
+                *cp++ = *base++;
+
+            if (*base == 'L') {
+                /* copy through ';' */
+                do {
+                    *cp = *base++;
+                } while (*cp++ != ';');
+            } else {
+                /* primitive char, copy it */
+                if (strchr("ZBCSIFJD", *base) == NULL) {
+                    fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
+                    goto bail;
+                }
+                *cp++ = *base++;
+            }
+
+            /* null terminate and display */
+            *cp++ = '\0';
+
+            char* tmp = descriptorToDot(tmpBuf);
+            printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
+                argNum++, tmp);
+            free(tmp);
+        }
+
+        if (constructor)
+            printf("</constructor>\n");
+        else
+            printf("</method>\n");
+    }
+
+bail:
+    free(typeDescriptor);
+    free(accessStr);
+}
+
+/*
+ * Dump a static (class) field.
+ */
+void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
+{
+    const DexFieldId* pFieldId;
+    const char* backDescriptor;
+    const char* name;
+    const char* typeDescriptor;
+    char* accessStr;
+
+    if (gOptions.exportsOnly &&
+        (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
+    {
+        return;
+    }
+
+    pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
+    name = dexStringById(pDexFile, pFieldId->nameIdx);
+    typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+    backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
+
+    accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : (in %s)\n", i, backDescriptor);
+        printf("      name          : '%s'\n", name);
+        printf("      type          : '%s'\n", typeDescriptor);
+        printf("      access        : 0x%04x (%s)\n",
+            pSField->accessFlags, accessStr);
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        char* tmp;
+
+        printf("<field name=\"%s\"\n", name);
+
+        tmp = descriptorToDot(typeDescriptor);
+        printf(" type=\"%s\"\n", tmp);
+        free(tmp);
+
+        printf(" transient=%s\n",
+            quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
+        printf(" volatile=%s\n",
+            quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
+        // "value=" not knowable w/o parsing annotations
+        printf(" static=%s\n",
+            quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pSField->accessFlags));
+        printf(">\n</field>\n");
+    }
+
+    free(accessStr);
+}
+
+/*
+ * Dump an instance field.
+ */
+void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
+{
+    dumpSField(pDexFile, pIField, i);
+}
+
+/*
+ * Dump the class.
+ *
+ * Note "idx" is a DexClassDef index, not a DexTypeId index.
+ *
+ * If "*pLastPackage" is NULL or does not match the current class' package,
+ * the value will be replaced with a newly-allocated string.
+ */
+void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
+{
+    const DexTypeList* pInterfaces;
+    const DexClassDef* pClassDef;
+    DexClassData* pClassData = NULL;
+    const u1* pEncodedData;
+    const char* fileName;
+    const char* classDescriptor;
+    const char* superclassDescriptor;
+    char* accessStr = NULL;
+    int i;
+
+    pClassDef = dexGetClassDef(pDexFile, idx);
+
+    if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
+        //printf("<!-- omitting non-public class %s -->\n",
+        //    classDescriptor);
+        goto bail;
+    }
+
+    pEncodedData = dexGetClassData(pDexFile, pClassDef);
+    pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+
+    if (pClassData == NULL) {
+        printf("Trouble reading class data (#%d)\n", idx);
+        goto bail;
+    }
+
+    classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+    /*
+     * For the XML output, show the package name.  Ideally we'd gather
+     * up the classes, sort them, and dump them alphabetically so the
+     * package name wouldn't jump around, but that's not a great plan
+     * for something that needs to run on the device.
+     */
+    if (!(classDescriptor[0] == 'L' &&
+          classDescriptor[strlen(classDescriptor)-1] == ';'))
+    {
+        /* arrays and primitives should not be defined explicitly */
+        fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
+        /* keep going? */
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        char* mangle;
+        char* lastSlash;
+        char* cp;
+
+        mangle = strdup(classDescriptor + 1);
+        mangle[strlen(mangle)-1] = '\0';
+
+        /* reduce to just the package name */
+        lastSlash = strrchr(mangle, '/');
+        if (lastSlash != NULL) {
+            *lastSlash = '\0';
+        } else {
+            *mangle = '\0';
+        }
+
+        for (cp = mangle; *cp != '\0'; cp++) {
+            if (*cp == '/')
+                *cp = '.';
+        }
+
+        if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
+            /* start of a new package */
+            if (*pLastPackage != NULL)
+                printf("</package>\n");
+            printf("<package name=\"%s\"\n>\n", mangle);
+            free(*pLastPackage);
+            *pLastPackage = mangle;
+        } else {
+            free(mangle);
+        }
+    }
+
+    accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
+
+    if (pClassDef->superclassIdx == kDexNoIndex) {
+        superclassDescriptor = NULL;
+    } else {
+        superclassDescriptor =
+            dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("Class #%d            -\n", idx);
+        printf("  Class descriptor  : '%s'\n", classDescriptor);
+        printf("  Access flags      : 0x%04x (%s)\n",
+            pClassDef->accessFlags, accessStr);
+
+        if (superclassDescriptor != NULL)
+            printf("  Superclass        : '%s'\n", superclassDescriptor);
+
+        printf("  Interfaces        -\n");
+    } else {
+        char* tmp;
+
+        tmp = descriptorClassToDot(classDescriptor);
+        printf("<class name=\"%s\"\n", tmp);
+        free(tmp);
+
+        if (superclassDescriptor != NULL) {
+            tmp = descriptorToDot(superclassDescriptor);
+            printf(" extends=\"%s\"\n", tmp);
+            free(tmp);
+        }
+        printf(" abstract=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
+        printf(" static=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pClassDef->accessFlags));
+        printf(">\n");
+    }
+    pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
+    if (pInterfaces != NULL) {
+        for (i = 0; i < (int) pInterfaces->size; i++)
+            dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Static fields     -\n");
+    for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
+        dumpSField(pDexFile, &pClassData->staticFields[i], i);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Instance fields   -\n");
+    for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
+        dumpIField(pDexFile, &pClassData->instanceFields[i], i);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Direct methods    -\n");
+    for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
+        dumpMethod(pDexFile, &pClassData->directMethods[i], i);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Virtual methods   -\n");
+    for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
+        dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
+    }
+
+    // TODO: Annotations.
+
+    if (pClassDef->sourceFileIdx != kDexNoIndex)
+        fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
+    else
+        fileName = "unknown";
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("  source_file_idx   : %d (%s)\n",
+            pClassDef->sourceFileIdx, fileName);
+        printf("\n");
+    }
+
+    if (gOptions.outputFormat == OUTPUT_XML) {
+        printf("</class>\n");
+    }
+
+bail:
+    free(pClassData);
+    free(accessStr);
+}
+
+
+/*
+ * Advance "ptr" to ensure 32-bit alignment.
+ */
+static inline const u1* align32(const u1* ptr)
+{
+    return (u1*) (((uintptr_t) ptr + 3) & ~0x03);
+}
+
+
+/*
+ * Dump a map in the "differential" format.
+ *
+ * TODO: show a hex dump of the compressed data.  (We can show the
+ * uncompressed data if we move the compression code to libdex; otherwise
+ * it's too complex to merit a fast & fragile implementation here.)
+ */
+void dumpDifferentialCompressedMap(const u1** pData)
+{
+    const u1* data = *pData;
+    const u1* dataStart = data -1;      // format byte already removed
+    u1 regWidth;
+    u2 numEntries;
+
+    /* standard header */
+    regWidth = *data++;
+    numEntries = *data++;
+    numEntries |= (*data++) << 8;
+
+    /* compressed data begins with the compressed data length */
+    int compressedLen = readUnsignedLeb128(&data);
+    int addrWidth = 1;
+    if ((*data & 0x80) != 0)
+        addrWidth++;
+
+    int origLen = 4 + (addrWidth + regWidth) * numEntries;
+    int compLen = (data - dataStart) + compressedLen;
+
+    printf("        (differential compression %d -> %d [%d -> %d])\n",
+        origLen, compLen,
+        (addrWidth + regWidth) * numEntries, compressedLen);
+
+    /* skip past end of entry */
+    data += compressedLen;
+
+    *pData = data;
+}
+
+/*
+ * Dump register map contents of the current method.
+ *
+ * "*pData" should point to the start of the register map data.  Advances
+ * "*pData" to the start of the next map.
+ */
+void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
+    const u1** pData)
+{
+    const u1* data = *pData;
+    const DexMethodId* pMethodId;
+    const char* name;
+    int offset = data - (u1*) pDexFile->pOptHeader;
+
+    pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    name = dexStringById(pDexFile, pMethodId->nameIdx);
+    printf("      #%d: 0x%08x %s\n", idx, offset, name);
+
+    u1 format;
+    int addrWidth;
+
+    format = *data++;
+    if (format == 1) {              /* kRegMapFormatNone */
+        /* no map */
+        printf("        (no map)\n");
+        addrWidth = 0;
+    } else if (format == 2) {       /* kRegMapFormatCompact8 */
+        addrWidth = 1;
+    } else if (format == 3) {       /* kRegMapFormatCompact16 */
+        addrWidth = 2;
+    } else if (format == 4) {       /* kRegMapFormatDifferential */
+        dumpDifferentialCompressedMap(&data);
+        goto bail;
+    } else {
+        printf("        (unknown format %d!)\n", format);
+        /* don't know how to skip data; failure will cascade to end of class */
+        goto bail;
+    }
+
+    if (addrWidth > 0) {
+        u1 regWidth;
+        u2 numEntries;
+        int idx, addr, byte;
+
+        regWidth = *data++;
+        numEntries = *data++;
+        numEntries |= (*data++) << 8;
+
+        for (idx = 0; idx < numEntries; idx++) {
+            addr = *data++;
+            if (addrWidth > 1)
+                addr |= (*data++) << 8;
+
+            printf("        %4x:", addr);
+            for (byte = 0; byte < regWidth; byte++) {
+                printf(" %02x", *data++);
+            }
+            printf("\n");
+        }
+    }
+
+bail:
+    //if (addrWidth >= 0)
+    //    *pData = align32(data);
+    *pData = data;
+}
+
+/*
+ * Dump the contents of the register map area.
+ *
+ * These are only present in optimized DEX files, and the structure is
+ * not really exposed to other parts of the VM itself.  We're going to
+ * dig through them here, but this is pretty fragile.  DO NOT rely on
+ * this or derive other code from it.
+ */
+void dumpRegisterMaps(DexFile* pDexFile)
+{
+    const u1* pClassPool = (const u1*)pDexFile->pRegisterMapPool;
+    const u4* classOffsets;
+    const u1* ptr;
+    u4 numClasses;
+    int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
+    int idx;
+
+    if (pClassPool == NULL) {
+        printf("No register maps found\n");
+        return;
+    }
+
+    ptr = pClassPool;
+    numClasses = get4LE(ptr);
+    ptr += sizeof(u4);
+    classOffsets = (const u4*) ptr;
+
+    printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
+    printf("Maps for %d classes\n", numClasses);
+    for (idx = 0; idx < (int) numClasses; idx++) {
+        const DexClassDef* pClassDef;
+        const char* classDescriptor;
+
+        pClassDef = dexGetClassDef(pDexFile, idx);
+        classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+        printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
+            baseFileOffset + classOffsets[idx], classDescriptor);
+
+        if (classOffsets[idx] == 0)
+            continue;
+
+        /*
+         * What follows is a series of RegisterMap entries, one for every
+         * direct method, then one for every virtual method.
+         */
+        DexClassData* pClassData;
+        const u1* pEncodedData;
+        const u1* data = (u1*) pClassPool + classOffsets[idx];
+        u2 methodCount;
+        int i;
+
+        pEncodedData = dexGetClassData(pDexFile, pClassDef);
+        pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+        if (pClassData == NULL) {
+            fprintf(stderr, "Trouble reading class data\n");
+            continue;
+        }
+
+        methodCount = *data++;
+        methodCount |= (*data++) << 8;
+        data += 2;      /* two pad bytes follow methodCount */
+        if (methodCount != pClassData->header.directMethodsSize
+                            + pClassData->header.virtualMethodsSize)
+        {
+            printf("NOTE: method count discrepancy (%d != %d + %d)\n",
+                methodCount, pClassData->header.directMethodsSize,
+                pClassData->header.virtualMethodsSize);
+            /* this is bad, but keep going anyway */
+        }
+
+        printf("    direct methods: %d\n",
+            pClassData->header.directMethodsSize);
+        for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
+            dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
+        }
+
+        printf("    virtual methods: %d\n",
+            pClassData->header.virtualMethodsSize);
+        for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
+            dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
+        }
+
+        free(pClassData);
+    }
+}
+
+/*
+ * Dump the requested sections of the file.
+ */
+void processDexFile(const char* fileName, DexFile* pDexFile)
+{
+    char* package = NULL;
+    int i;
+
+    if (gOptions.verbose) {
+        printf("Opened '%s', DEX version '%.3s'\n", fileName,
+            pDexFile->pHeader->magic +4);
+    }
+
+    if (gOptions.dumpRegisterMaps) {
+        dumpRegisterMaps(pDexFile);
+        return;
+    }
+
+    if (gOptions.showFileHeaders) {
+        dumpFileHeader(pDexFile);
+        dumpOptDirectory(pDexFile);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_XML)
+        printf("<api>\n");
+
+    for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
+        if (gOptions.showSectionHeaders)
+            dumpClassDef(pDexFile, i);
+
+        dumpClass(pDexFile, i, &package);
+    }
+
+    /* free the last one allocated */
+    if (package != NULL) {
+        printf("</package>\n");
+        free(package);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_XML)
+        printf("</api>\n");
+}
+
+
+/*
+ * Process one file.
+ */
+int process(const char* fileName)
+{
+    DexFile* pDexFile = NULL;
+    MemMapping map;
+    bool mapped = false;
+    int result = -1;
+
+    if (gOptions.verbose)
+        printf("Processing '%s'...\n", fileName);
+
+    if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0) {
+        return result;
+    }
+    mapped = true;
+
+    int flags = kDexParseVerifyChecksum;
+    if (gOptions.ignoreBadChecksum)
+        flags |= kDexParseContinueOnError;
+
+    pDexFile = dexFileParse((u1*)map.addr, map.length, flags);
+    if (pDexFile == NULL) {
+        fprintf(stderr, "ERROR: DEX parse failed\n");
+        goto bail;
+    }
+
+    if (gOptions.checksumOnly) {
+        printf("Checksum verified\n");
+    } else {
+        processDexFile(fileName, pDexFile);
+    }
+
+    result = 0;
+
+bail:
+    if (mapped)
+        sysReleaseShmem(&map);
+    if (pDexFile != NULL)
+        dexFileFree(pDexFile);
+    return result;
+}
+
+
+/*
+ * Show usage.
+ */
+void usage(void)
+{
+    fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
+    fprintf(stderr,
+        "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
+        gProgName);
+    fprintf(stderr, "\n");
+    fprintf(stderr, " -c : verify checksum and exit\n");
+    fprintf(stderr, " -d : disassemble code sections\n");
+    fprintf(stderr, " -f : display summary information from file header\n");
+    fprintf(stderr, " -h : display file header details\n");
+    fprintf(stderr, " -i : ignore checksum failures\n");
+    fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
+    fprintf(stderr, " -m : dump register maps (and nothing else)\n");
+    fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
+}
+
+/*
+ * Parse args.
+ *
+ * I'm not using getopt_long() because we may not have it in libc.
+ */
+int main(int argc, char* const argv[])
+{
+    bool wantUsage = false;
+    int ic;
+
+    memset(&gOptions, 0, sizeof(gOptions));
+    gOptions.verbose = true;
+
+    while (1) {
+        ic = getopt(argc, argv, "cdfhil:mt:");
+        if (ic < 0)
+            break;
+
+        switch (ic) {
+        case 'c':       // verify the checksum then exit
+            gOptions.checksumOnly = true;
+            break;
+        case 'd':       // disassemble Dalvik instructions
+            gOptions.disassemble = true;
+            break;
+        case 'f':       // dump outer file header
+            gOptions.showFileHeaders = true;
+            break;
+        case 'h':       // dump section headers, i.e. all meta-data
+            gOptions.showSectionHeaders = true;
+            break;
+        case 'i':       // continue even if checksum is bad
+            gOptions.ignoreBadChecksum = true;
+            break;
+        case 'l':       // layout
+            if (strcmp(optarg, "plain") == 0) {
+                gOptions.outputFormat = OUTPUT_PLAIN;
+            } else if (strcmp(optarg, "xml") == 0) {
+                gOptions.outputFormat = OUTPUT_XML;
+                gOptions.verbose = false;
+                gOptions.exportsOnly = true;
+            } else {
+                wantUsage = true;
+            }
+            break;
+        case 'm':       // dump register maps only
+            gOptions.dumpRegisterMaps = true;
+            break;
+        case 't':       // temp file, used when opening compressed Jar
+            gOptions.tempFileName = optarg;
+            break;
+        default:
+            wantUsage = true;
+            break;
+        }
+    }
+
+    if (optind == argc) {
+        fprintf(stderr, "%s: no file specified\n", gProgName);
+        wantUsage = true;
+    }
+
+    if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
+        fprintf(stderr, "Can't specify both -c and -i\n");
+        wantUsage = true;
+    }
+
+    if (wantUsage) {
+        usage();
+        return 2;
+    }
+
+    int result = 0;
+    while (optind < argc) {
+        result |= process(argv[optind++]);
+    }
+
+    return (result != 0);
+}
diff --git a/dexdump/NOTICE b/dexdump/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/dexdump/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
new file mode 100644
index 0000000..4e7668d
--- /dev/null
+++ b/dexlist/Android.mk
@@ -0,0 +1,47 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# dexlist -- list all concrete methods found in a DEX file
+#
+LOCAL_PATH:= $(call my-dir)
+
+dexdump_src_files := \
+		DexList.cpp
+
+dexdump_c_includes := \
+		dalvik
+
+dexdump_static_libraries := \
+		libdex
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexlist
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_SHARED_LIBRARIES := libcutils libz libutils
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries) libbase
+LOCAL_LDLIBS +=
+LOCAL_32_BIT_ONLY := true
+#include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexlist
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries) libcutils liblog libutils libbase
+LOCAL_LDLIBS += -lpthread -lz
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlist/DexList.cpp b/dexlist/DexList.cpp
new file mode 100644
index 0000000..94eba4b
--- /dev/null
+++ b/dexlist/DexList.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * List all methods in all concrete classes in one or more DEX files.
+ */
+
+#include "libdex/DexFile.h"
+
+#include "libdex/CmdUtils.h"
+#include "libdex/DexClass.h"
+#include "libdex/DexDebugInfo.h"
+#include "libdex/DexProto.h"
+#include "libdex/SysUtil.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <assert.h>
+
+static const char* gProgName = "dexlist";
+
+/* command-line args */
+static struct {
+    char*       argCopy;
+    const char* classToFind;
+    const char* methodToFind;
+} gParms;
+
+
+/*
+ * Return a newly-allocated string for the "dot version" of the class
+ * name for the given type descriptor. That is, The initial "L" and
+ * final ";" (if any) have been removed and all occurrences of '/'
+ * have been changed to '.'.
+ */
+static char* descriptorToDot(const char* str)
+{
+    size_t at = strlen(str);
+    char* newStr;
+
+    if (str[0] == 'L') {
+        assert(str[at - 1] == ';');
+        at -= 2; /* Two fewer chars to copy. */
+        str++; /* Skip the 'L'. */
+    }
+
+    newStr = (char*)malloc(at + 1); /* Add one for the '\0'. */
+    newStr[at] = '\0';
+
+    while (at > 0) {
+        at--;
+        newStr[at] = (str[at] == '/') ? '.' : str[at];
+    }
+
+    return newStr;
+}
+
+/*
+ * Position table callback; we just want to catch the number of the
+ * first line in the method, which *should* correspond to the first
+ * entry from the table.  (Could also use "min" here.)
+ */
+static int positionsCallback(void* cnxt, u4 /*address */, u4 lineNum)
+{
+    int* pFirstLine = (int*) cnxt;
+    if (*pFirstLine == -1)
+        *pFirstLine = lineNum;
+    return 0;
+}
+
+
+/*
+ * Dump a method.
+ */
+void dumpMethod(DexFile* pDexFile, const char* fileName,
+    const DexMethod* pDexMethod, int /* i */)
+{
+    const DexMethodId* pMethodId;
+    const DexCode* pCode;
+    const char* classDescriptor;
+    const char* methodName;
+    int firstLine;
+
+    /* abstract and native methods don't get listed */
+    if (pDexMethod->codeOff == 0)
+        return;
+
+    pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    methodName = dexStringById(pDexFile, pMethodId->nameIdx);
+
+    classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    pCode = dexGetCode(pDexFile, pDexMethod);
+    assert(pCode != NULL);
+
+    /*
+     * If the filename is empty, then set it to something printable
+     * so that it is easier to parse.
+     *
+     * TODO: A method may override its class's default source file by
+     * specifying a different one in its debug info. This possibility
+     * should be handled here.
+     */
+    if (fileName == NULL || fileName[0] == 0) {
+        fileName = "(none)";
+    }
+
+    firstLine = -1;
+    dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
+        pDexMethod->accessFlags, positionsCallback, NULL, &firstLine);
+
+    char* className = descriptorToDot(classDescriptor);
+    char* desc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+    u4 insnsOff = pDexMethod->codeOff + offsetof(DexCode, insns);
+
+    if (gParms.methodToFind != NULL &&
+        (strcmp(gParms.classToFind, className) != 0 ||
+         strcmp(gParms.methodToFind, methodName) != 0))
+    {
+        goto skip;
+    }
+
+    printf("0x%08x %d %s %s %s %s %d\n",
+        insnsOff, pCode->insnsSize * 2,
+        className, methodName, desc,
+        fileName, firstLine);
+
+skip:
+    free(desc);
+    free(className);
+}
+
+/*
+ * Run through all direct and virtual methods in the class.
+ */
+void dumpClass(DexFile* pDexFile, int idx)
+{
+    const DexClassDef* pClassDef;
+    DexClassData* pClassData;
+    const u1* pEncodedData;
+    const char* fileName;
+    int i;
+
+    pClassDef = dexGetClassDef(pDexFile, idx);
+    pEncodedData = dexGetClassData(pDexFile, pClassDef);
+    pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+
+    if (pClassData == NULL) {
+        fprintf(stderr, "Trouble reading class data\n");
+        return;
+    }
+
+    if (pClassDef->sourceFileIdx == 0xffffffff) {
+        fileName = NULL;
+    } else {
+        fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
+    }
+
+    /*
+     * TODO: Each class def points at a sourceFile, so maybe that
+     * should be printed out. However, this needs to be coordinated
+     * with the tools that parse this output.
+     */
+
+    for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
+        dumpMethod(pDexFile, fileName, &pClassData->directMethods[i], i);
+    }
+
+    for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
+        dumpMethod(pDexFile, fileName, &pClassData->virtualMethods[i], i);
+    }
+
+    free(pClassData);
+}
+
+/*
+ * Process a file.
+ *
+ * Returns 0 on success.
+ */
+int process(const char* fileName)
+{
+    DexFile* pDexFile = NULL;
+    MemMapping map;
+    bool mapped = false;
+    int result = -1;
+    UnzipToFileResult utfr;
+
+    utfr = dexOpenAndMap(fileName, NULL, &map, true);
+    if (utfr != kUTFRSuccess) {
+        if (utfr == kUTFRNoClassesDex) {
+            /* no classes.dex in the APK; pretend we succeeded */
+            result = 0;
+            goto bail;
+        }
+        fprintf(stderr, "Unable to process '%s'\n", fileName);
+        goto bail;
+    }
+    mapped = true;
+
+    pDexFile = dexFileParse((u1*)map.addr, map.length, kDexParseDefault);
+    if (pDexFile == NULL) {
+        fprintf(stderr, "Warning: DEX parse failed for '%s'\n", fileName);
+        goto bail;
+    }
+
+    printf("#%s\n", fileName);
+
+    int i;
+    for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
+        dumpClass(pDexFile, i);
+    }
+
+    result = 0;
+
+bail:
+    if (mapped)
+        sysReleaseShmem(&map);
+    if (pDexFile != NULL)
+        dexFileFree(pDexFile);
+    return result;
+}
+
+
+/*
+ * Show usage.
+ */
+void usage(void)
+{
+    fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
+    fprintf(stderr, "%s: dexfile [dexfile2 ...]\n", gProgName);
+    fprintf(stderr, "\n");
+}
+
+/*
+ * Parse args.
+ */
+int main(int argc, char* const argv[])
+{
+    int result = 0;
+    int i;
+
+    /*
+     * Find all instances of the fully-qualified method name.  This isn't
+     * really what dexlist is for, but it's easy to do it here.
+     */
+    if (argc > 3 && strcmp(argv[1], "--method") == 0) {
+        gParms.argCopy = strdup(argv[2]);
+        char* meth = strrchr(gParms.argCopy, '.');
+        if (meth == NULL) {
+            fprintf(stderr, "Expected package.Class.method\n");
+            free(gParms.argCopy);
+            return 2;
+        }
+        *meth = '\0';
+        gParms.classToFind = gParms.argCopy;
+        gParms.methodToFind = meth+1;
+        argv += 2;
+        argc -= 2;
+    }
+
+    if (argc < 2) {
+        fprintf(stderr, "%s: no file specified\n", gProgName);
+        usage();
+        return 2;
+    }
+
+    /*
+     * Run through the list of files.  If one of them fails we contine on,
+     * only returning a failure at the end.
+     */
+    for (i = 1; i < argc; i++)
+        result |= process(argv[i]);
+
+    free(gParms.argCopy);
+    return result;
+}
diff --git a/docs/embedded-vm-control.html b/docs/embedded-vm-control.html
index 65446a4..5c444de 100644
--- a/docs/embedded-vm-control.html
+++ b/docs/embedded-vm-control.html
@@ -245,6 +245,10 @@
 problems it may be useful to add the property to
 <code>/data/local.prop</code>.
 
+<p>Note also that the
+<code>dexdump</code> tool always verifies DEX checksums, and can be used
+to check for corruption in a large set of files.
+
 
 <h2><a name="general">General Flags</a></h2>
 
diff --git a/libdex/Android.mk b/libdex/Android.mk
new file mode 100644
index 0000000..cabc8dc
--- /dev/null
+++ b/libdex/Android.mk
@@ -0,0 +1,77 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+dex_src_files := \
+	CmdUtils.cpp \
+	DexCatch.cpp \
+	DexClass.cpp \
+	DexDataMap.cpp \
+	DexDebugInfo.cpp \
+	DexFile.cpp \
+	DexInlines.cpp \
+	DexOptData.cpp \
+	DexOpcodes.cpp \
+	DexProto.cpp \
+	DexSwapVerify.cpp \
+	DexUtf.cpp \
+	InstrUtils.cpp \
+	Leb128.cpp \
+	OptInvocation.cpp \
+	sha1.cpp \
+	SysUtil.cpp \
+
+dex_include_files := \
+	dalvik \
+	external/zlib \
+	external/safe-iop/include
+
+##
+##
+## Build the device version of libdex
+##
+##
+ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
+
+include $(CLEAR_VARS)
+#LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1
+LOCAL_SRC_FILES := $(dex_src_files)
+LOCAL_C_INCLUDES += $(dex_include_files)
+LOCAL_CPPFLAGS := -std=gnu++11
+LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_WHOLE_STATIC_LIBRARIES := libziparchive
+LOCAL_SHARED_LIBRARIES := libutils
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libdex
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_STATIC_LIBRARY)
+
+endif # !SDK_ONLY
+
+
+##
+##
+## Build the host version of libdex
+##
+##
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(dex_src_files)
+LOCAL_C_INCLUDES += $(dex_include_files)
+LOCAL_CPPFLAGS := -std=gnu++11
+LOCAL_STATIC_LIBRARIES := liblog libutils
+LOCAL_WHOLE_STATIC_LIBRARIES := libziparchive-host
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libdex
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libdex/CmdUtils.cpp b/libdex/CmdUtils.cpp
new file mode 100644
index 0000000..cdb7bb9
--- /dev/null
+++ b/libdex/CmdUtils.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Some utility functions for use with command-line utilities.
+ */
+#include "DexFile.h"
+#include "ZipArchive.h"
+#include "CmdUtils.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/*
+ * Extract "classes.dex" from archive file.
+ *
+ * If "quiet" is set, don't report common errors.
+ */
+UnzipToFileResult dexUnzipToFile(const char* zipFileName,
+    const char* outFileName, bool quiet)
+{
+    UnzipToFileResult result = kUTFRSuccess;
+    static const char* kFileToExtract = "classes.dex";
+    ZipArchiveHandle archive;
+    ZipEntry entry;
+    bool unlinkOnFailure = false;
+    int fd = -1;
+
+    if (dexZipOpenArchive(zipFileName, &archive) != 0) {
+        if (!quiet) {
+            fprintf(stderr, "Unable to open '%s' as zip archive\n",
+                zipFileName);
+        }
+        result = kUTFRNotZip;
+        goto bail;
+    }
+
+    fd = open(outFileName, O_RDWR | O_CREAT | O_EXCL, 0600);
+    if (fd < 0) {
+        fprintf(stderr, "Unable to create output file '%s': %s\n",
+            outFileName, strerror(errno));
+        result = kUTFROutputFileProblem;
+        goto bail;
+    }
+
+    unlinkOnFailure = true;
+
+    if (dexZipFindEntry(archive, kFileToExtract, &entry) != 0) {
+        if (!quiet) {
+            fprintf(stderr, "Unable to find '%s' in '%s'\n",
+                kFileToExtract, zipFileName);
+        }
+        result = kUTFRNoClassesDex;
+        goto bail;
+    }
+
+    if (dexZipExtractEntryToFile(archive, &entry, fd) != 0) {
+        fprintf(stderr, "Extract of '%s' from '%s' failed\n",
+            kFileToExtract, zipFileName);
+        result = kUTFRBadZip;
+        goto bail;
+    }
+
+bail:
+    if (fd >= 0)
+        close(fd);
+    if (unlinkOnFailure && result != kUTFRSuccess)
+        unlink(outFileName);
+    dexZipCloseArchive(archive);
+    return result;
+}
+
+/*
+ * Map the specified DEX file read-only (possibly after expanding it into a
+ * temp file from a Jar).  Pass in a MemMapping struct to hold the info.
+ * If the file is an unoptimized DEX file, then byte-swapping and structural
+ * verification are performed on it before the memory is made read-only.
+ *
+ * The temp file is deleted after the map succeeds.
+ *
+ * This is intended for use by tools (e.g. dexdump) that need to get a
+ * read-only copy of a DEX file that could be in a number of different states.
+ *
+ * If "tempFileName" is NULL, a default value is used.  The temp file is
+ * deleted after the map succeeds.
+ *
+ * If "quiet" is set, don't report common errors.
+ *
+ * Returns 0 (kUTFRSuccess) on success.
+ */
+UnzipToFileResult dexOpenAndMap(const char* fileName, const char* tempFileName,
+    MemMapping* pMap, bool quiet)
+{
+    UnzipToFileResult result = kUTFRGenericFailure;
+    int len = strlen(fileName);
+    char tempNameBuf[32];
+    bool removeTemp = false;
+    int fd = -1;
+
+    if (len < 5) {
+        if (!quiet) {
+            fprintf(stderr,
+                "ERROR: filename must end in .dex, .zip, .jar, or .apk\n");
+        }
+        result = kUTFRBadArgs;
+        goto bail;
+    }
+
+    if (strcasecmp(fileName + len -3, "dex") != 0) {
+        if (tempFileName == NULL) {
+            /*
+             * Try .zip/.jar/.apk, all of which are Zip archives with
+             * "classes.dex" inside.  We need to extract the compressed
+             * data to a temp file, the location of which varies.
+             *
+             * On the device we must use /sdcard because most other
+             * directories aren't writable (either because of permissions
+             * or because the volume is mounted read-only).  On desktop
+             * it's nice to use the designated temp directory.
+             */
+            if (access("/tmp", W_OK) == 0) {
+                sprintf(tempNameBuf, "/tmp/dex-temp-%d", getpid());
+            } else if (access("/sdcard", W_OK) == 0) {
+                sprintf(tempNameBuf, "/sdcard/dex-temp-%d", getpid());
+            } else {
+                fprintf(stderr,
+                    "NOTE: /tmp and /sdcard unavailable for temp files\n");
+                sprintf(tempNameBuf, "dex-temp-%d", getpid());
+            }
+
+            tempFileName = tempNameBuf;
+        }
+
+        result = dexUnzipToFile(fileName, tempFileName, quiet);
+
+        if (result == kUTFRSuccess) {
+            //printf("+++ Good unzip to '%s'\n", tempFileName);
+            fileName = tempFileName;
+            removeTemp = true;
+        } else if (result == kUTFRNotZip) {
+            if (!quiet) {
+                fprintf(stderr, "Not Zip, retrying as DEX\n");
+            }
+        } else {
+            if (!quiet && result == kUTFRNoClassesDex) {
+                fprintf(stderr, "Zip has no classes.dex\n");
+            }
+            goto bail;
+        }
+    }
+
+    result = kUTFRGenericFailure;
+
+    /*
+     * Pop open the (presumed) DEX file.
+     */
+    fd = open(fileName, O_RDONLY | O_BINARY);
+    if (fd < 0) {
+        if (!quiet) {
+            fprintf(stderr, "ERROR: unable to open '%s': %s\n",
+                fileName, strerror(errno));
+        }
+        goto bail;
+    }
+
+    if (sysMapFileInShmemWritableReadOnly(fd, pMap) != 0) {
+        fprintf(stderr, "ERROR: Unable to map '%s'\n", fileName);
+        goto bail;
+    }
+
+    /*
+     * This call will fail if the file exists on a filesystem that
+     * doesn't support mprotect(). If that's the case, then the file
+     * will have already been mapped private-writable by the previous
+     * call, so we don't need to do anything special if this call
+     * returns non-zero.
+     */
+    sysChangeMapAccess(pMap->addr, pMap->length, true, pMap);
+
+    if (dexSwapAndVerifyIfNecessary((u1*) pMap->addr, pMap->length)) {
+        fprintf(stderr, "ERROR: Failed structural verification of '%s'\n",
+            fileName);
+        goto bail;
+    }
+
+    /*
+     * Similar to above, this call will fail if the file wasn't ever
+     * read-only to begin with. This is innocuous, though it is
+     * undesirable from a memory hygiene perspective.
+     */
+    sysChangeMapAccess(pMap->addr, pMap->length, false, pMap);
+
+    /*
+     * Success!  Close the file and return with the start/length in pMap.
+     */
+    result = kUTFRSuccess;
+
+bail:
+    if (fd >= 0)
+        close(fd);
+    if (removeTemp) {
+        /* this will fail if the OS doesn't allow removal of a mapped file */
+        if (unlink(tempFileName) != 0) {
+            fprintf(stderr, "WARNING: unable to remove temp '%s'\n",
+                tempFileName);
+        }
+    }
+    return result;
+}
diff --git a/libdex/CmdUtils.h b/libdex/CmdUtils.h
new file mode 100644
index 0000000..887eed9
--- /dev/null
+++ b/libdex/CmdUtils.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Access .dex (Dalvik Executable Format) files.  The code here assumes that
+ * the DEX file has been rewritten (byte-swapped, word-aligned) and that
+ * the contents can be directly accessed as a collection of C arrays.  Please
+ * see docs/dalvik/dex-format.html for a detailed description.
+ *
+ * The structure and field names were chosen to match those in the DEX spec.
+ *
+ * It's generally assumed that the DEX file will be stored in shared memory,
+ * obviating the need to copy code and constant pool entries into newly
+ * allocated storage.  Maintaining local pointers to items in the shared area
+ * is valid and encouraged.
+ *
+ * All memory-mapped structures are 32-bit aligned unless otherwise noted.
+ */
+#ifndef LIBDEX_CMDUTILS_H_
+#define LIBDEX_CMDUTILS_H_
+
+/* encode the result of unzipping to a file */
+enum UnzipToFileResult {
+    kUTFRSuccess = 0,
+    kUTFRGenericFailure,
+    kUTFRBadArgs,
+    kUTFRNotZip,
+    kUTFRNoClassesDex,
+    kUTFROutputFileProblem,
+    kUTFRBadZip,
+};
+
+/*
+ * Map the specified DEX file read-only (possibly after expanding it into a
+ * temp file from a Jar).  Pass in a MemMapping struct to hold the info.
+ * If the file is an unoptimized DEX file, then byte-swapping and structural
+ * verification are performed on it before the memory is made read-only.
+ *
+ * The temp file is deleted after the map succeeds.
+ *
+ * This is intended for use by tools (e.g. dexdump) that need to get a
+ * read-only copy of a DEX file that could be in a number of different states.
+ *
+ * If "tempFileName" is NULL, a default value is used.  The temp file is
+ * deleted after the map succeeds.
+ *
+ * If "quiet" is set, don't report common errors.
+ *
+ * Returns 0 (kUTFRSuccess) on success.
+ */
+UnzipToFileResult dexOpenAndMap(const char* fileName, const char* tempFileName,
+    MemMapping* pMap, bool quiet);
+
+/*
+ * Utility function to open a Zip archive, find "classes.dex", and extract
+ * it to a file.
+ */
+UnzipToFileResult dexUnzipToFile(const char* zipFileName,
+    const char* outFileName, bool quiet);
+
+#endif  // LIBDEX_CMDUTILS_H_
diff --git a/libdex/DexCatch.cpp b/libdex/DexCatch.cpp
new file mode 100644
index 0000000..ed97e87
--- /dev/null
+++ b/libdex/DexCatch.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions for dealing with try-catch info.
+ */
+
+#include "DexCatch.h"
+
+/* Get the first handler offset for the given DexCode.
+ * It's not 0 because the handlers list is prefixed with its size
+ * (in entries) as a uleb128. */
+u4 dexGetFirstHandlerOffset(const DexCode* pCode) {
+    if (pCode->triesSize == 0) {
+        return 0;
+    }
+
+    const u1* baseData = dexGetCatchHandlerData(pCode);
+    const u1* data = baseData;
+
+    readUnsignedLeb128(&data);
+
+    return data - baseData;
+}
+
+/* Get count of handler lists for the given DexCode. */
+u4 dexGetHandlersSize(const DexCode* pCode) {
+    if (pCode->triesSize == 0) {
+        return 0;
+    }
+
+    const u1* data = dexGetCatchHandlerData(pCode);
+
+    return readUnsignedLeb128(&data);
+}
+
+/* Helper for dexFindCatchHandlerOffset(), which does an actual search
+ * in the tries table. Returns -1 if there is no applicable handler. */
+int dexFindCatchHandlerOffset0(u2 triesSize, const DexTry* pTries,
+        u4 address) {
+    // Note: Signed type is important for max and min.
+    int min = 0;
+    int max = triesSize - 1;
+
+    while (max >= min) {
+        int guess = (min + max) >> 1;
+        const DexTry* pTry = &pTries[guess];
+        u4 start = pTry->startAddr;
+
+        if (address < start) {
+            max = guess - 1;
+            continue;
+        }
+
+        u4 end = start + pTry->insnCount;
+
+        if (address >= end) {
+            min = guess + 1;
+            continue;
+        }
+
+        // We have a winner!
+        return (int) pTry->handlerOff;
+    }
+
+    // No match.
+    return -1;
+}
+
+/* Get the handler offset just past the end of the one just iterated over.
+ * This ends the iteration if it wasn't already. */
+u4 dexCatchIteratorGetEndOffset(DexCatchIterator* pIterator,
+        const DexCode* pCode) {
+    while (dexCatchIteratorNext(pIterator) != NULL) /* empty */ ;
+
+    return (u4) (pIterator->pEncodedData - dexGetCatchHandlerData(pCode));
+}
diff --git a/libdex/DexCatch.h b/libdex/DexCatch.h
new file mode 100644
index 0000000..cfea2d9
--- /dev/null
+++ b/libdex/DexCatch.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions for dealing with try-catch info.
+ */
+
+#ifndef LIBDEX_DEXCATCH_H_
+#define LIBDEX_DEXCATCH_H_
+
+#include "DexFile.h"
+#include "Leb128.h"
+
+/*
+ * Catch handler entry, used while iterating over catch_handler_items.
+ */
+struct DexCatchHandler {
+    u4          typeIdx;    /* type index of the caught exception type */
+    u4          address;    /* handler address */
+};
+
+/* Get the first handler offset for the given DexCode.
+ * It's not 0 because the handlers list is prefixed with its size
+ * (in entries) as a uleb128. */
+u4 dexGetFirstHandlerOffset(const DexCode* pCode);
+
+/* Get count of handler lists for the given DexCode. */
+u4 dexGetHandlersSize(const DexCode* pCode);
+
+/*
+ * Iterator over catch handler data. This structure should be treated as
+ * opaque.
+ */
+struct DexCatchIterator {
+    const u1* pEncodedData;
+    bool catchesAll;
+    u4 countRemaining;
+    DexCatchHandler handler;
+};
+
+/* Initialize a DexCatchIterator to emptiness. This mostly exists to
+ * squelch innocuous warnings. */
+DEX_INLINE void dexCatchIteratorClear(DexCatchIterator* pIterator) {
+    pIterator->pEncodedData = NULL;
+    pIterator->catchesAll = false;
+    pIterator->countRemaining = 0;
+    pIterator->handler.typeIdx = 0;
+    pIterator->handler.address = 0;
+}
+
+/* Initialize a DexCatchIterator with a direct pointer to encoded handlers. */
+DEX_INLINE void dexCatchIteratorInitToPointer(DexCatchIterator* pIterator,
+    const u1* pEncodedData)
+{
+    s4 count = readSignedLeb128(&pEncodedData);
+
+    if (count <= 0) {
+        pIterator->catchesAll = true;
+        count = -count;
+    } else {
+        pIterator->catchesAll = false;
+    }
+
+    pIterator->pEncodedData = pEncodedData;
+    pIterator->countRemaining = count;
+}
+
+/* Initialize a DexCatchIterator to a particular handler offset. */
+DEX_INLINE void dexCatchIteratorInit(DexCatchIterator* pIterator,
+    const DexCode* pCode, u4 offset)
+{
+    dexCatchIteratorInitToPointer(pIterator,
+            dexGetCatchHandlerData(pCode) + offset);
+}
+
+/* Get the next item from a DexCatchIterator. Returns NULL if at end. */
+DEX_INLINE DexCatchHandler* dexCatchIteratorNext(DexCatchIterator* pIterator) {
+    if (pIterator->countRemaining == 0) {
+        if (! pIterator->catchesAll) {
+            return NULL;
+        }
+
+        pIterator->catchesAll = false;
+        pIterator->handler.typeIdx = kDexNoIndex;
+    } else {
+        u4 typeIdx = readUnsignedLeb128(&pIterator->pEncodedData);
+        pIterator->handler.typeIdx = typeIdx;
+        pIterator->countRemaining--;
+    }
+
+    pIterator->handler.address = readUnsignedLeb128(&pIterator->pEncodedData);
+    return &pIterator->handler;
+}
+
+/* Get the handler offset just past the end of the one just iterated over.
+ * This ends the iteration if it wasn't already. */
+u4 dexCatchIteratorGetEndOffset(DexCatchIterator* pIterator,
+    const DexCode* pCode);
+
+/* Helper for dexFindCatchHandler(). Do not call directly. */
+int dexFindCatchHandlerOffset0(u2 triesSize, const DexTry* pTries,
+        u4 address);
+
+/* Find the handler associated with a given address, if any.
+ * Initializes the given iterator and returns true if a match is
+ * found. Returns false if there is no applicable handler. */
+DEX_INLINE bool dexFindCatchHandler(DexCatchIterator *pIterator,
+        const DexCode* pCode, u4 address) {
+    u2 triesSize = pCode->triesSize;
+    int offset = -1;
+
+    // Short-circuit the overwhelmingly common cases.
+    switch (triesSize) {
+        case 0: {
+            break;
+        }
+        case 1: {
+            const DexTry* tries = dexGetTries(pCode);
+            u4 start = tries[0].startAddr;
+
+            if (address < start) {
+                break;
+            }
+
+            u4 end = start + tries[0].insnCount;
+
+            if (address >= end) {
+                break;
+            }
+
+            offset = tries[0].handlerOff;
+            break;
+        }
+        default: {
+            offset = dexFindCatchHandlerOffset0(triesSize, dexGetTries(pCode),
+                    address);
+        }
+    }
+
+    if (offset < 0) {
+        dexCatchIteratorClear(pIterator); // This squelches warnings.
+        return false;
+    } else {
+        dexCatchIteratorInit(pIterator, pCode, offset);
+        return true;
+    }
+}
+
+#endif  // LIBDEX_DEXCATCH_H_
diff --git a/libdex/DexClass.cpp b/libdex/DexClass.cpp
new file mode 100644
index 0000000..552229c
--- /dev/null
+++ b/libdex/DexClass.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions to deal with class definition structures in DEX files
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "DexClass.h"
+#include "Leb128.h"
+
+/* Helper for verification which reads and verifies a given number
+ * of uleb128 values. */
+static bool verifyUlebs(const u1* pData, const u1* pLimit, u4 count) {
+    bool okay = true;
+    u4 i;
+
+    while (okay && (count-- != 0)) {
+        readAndVerifyUnsignedLeb128(&pData, pLimit, &okay);
+    }
+
+    return okay;
+}
+
+/* Read and verify the header of a class_data_item. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure). */
+bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit,
+        DexClassDataHeader *pHeader) {
+    if (! verifyUlebs(*pData, pLimit, 4)) {
+        return false;
+    }
+
+    dexReadClassDataHeader(pData, pHeader);
+    return true;
+}
+
+/* Read and verify an encoded_field. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure).
+ *
+ * The lastIndex value should be set to 0 before the first field in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags or indices
+ * are valid. */
+bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit,
+        DexField* pField, u4* lastIndex) {
+    if (! verifyUlebs(*pData, pLimit, 2)) {
+        return false;
+    }
+
+    dexReadClassDataField(pData, pField, lastIndex);
+    return true;
+}
+
+/* Read and verify an encoded_method. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure).
+ *
+ * The lastIndex value should be set to 0 before the first method in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags, indices, or offsets
+ * are valid. */
+bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit,
+        DexMethod* pMethod, u4* lastIndex) {
+    if (! verifyUlebs(*pData, pLimit, 3)) {
+        return false;
+    }
+
+    dexReadClassDataMethod(pData, pMethod, lastIndex);
+    return true;
+}
+
+/* Read, verify, and return an entire class_data_item. This updates
+ * the given data pointer to point past the end of the read data. This
+ * function allocates a single chunk of memory for the result, which
+ * must subsequently be free()d. This function returns NULL if there
+ * was trouble parsing the data. If this function is passed NULL, it
+ * returns an initialized empty DexClassData structure.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags, indices, or offsets
+ * are valid. */
+DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit) {
+    DexClassDataHeader header;
+    u4 lastIndex;
+
+    if (*pData == NULL) {
+        DexClassData* result = (DexClassData*) malloc(sizeof(DexClassData));
+        memset(result, 0, sizeof(*result));
+        return result;
+    }
+
+    if (! dexReadAndVerifyClassDataHeader(pData, pLimit, &header)) {
+        return NULL;
+    }
+
+    size_t resultSize = sizeof(DexClassData) +
+        (header.staticFieldsSize * sizeof(DexField)) +
+        (header.instanceFieldsSize * sizeof(DexField)) +
+        (header.directMethodsSize * sizeof(DexMethod)) +
+        (header.virtualMethodsSize * sizeof(DexMethod));
+
+    DexClassData* result = (DexClassData*) malloc(resultSize);
+    u1* ptr = ((u1*) result) + sizeof(DexClassData);
+    bool okay = true;
+    u4 i;
+
+    if (result == NULL) {
+        return NULL;
+    }
+
+    result->header = header;
+
+    if (header.staticFieldsSize != 0) {
+        result->staticFields = (DexField*) ptr;
+        ptr += header.staticFieldsSize * sizeof(DexField);
+    } else {
+        result->staticFields = NULL;
+    }
+
+    if (header.instanceFieldsSize != 0) {
+        result->instanceFields = (DexField*) ptr;
+        ptr += header.instanceFieldsSize * sizeof(DexField);
+    } else {
+        result->instanceFields = NULL;
+    }
+
+    if (header.directMethodsSize != 0) {
+        result->directMethods = (DexMethod*) ptr;
+        ptr += header.directMethodsSize * sizeof(DexMethod);
+    } else {
+        result->directMethods = NULL;
+    }
+
+    if (header.virtualMethodsSize != 0) {
+        result->virtualMethods = (DexMethod*) ptr;
+    } else {
+        result->virtualMethods = NULL;
+    }
+
+    lastIndex = 0;
+    for (i = 0; okay && (i < header.staticFieldsSize); i++) {
+        okay = dexReadAndVerifyClassDataField(pData, pLimit,
+                &result->staticFields[i], &lastIndex);
+    }
+
+    lastIndex = 0;
+    for (i = 0; okay && (i < header.instanceFieldsSize); i++) {
+        okay = dexReadAndVerifyClassDataField(pData, pLimit,
+                &result->instanceFields[i], &lastIndex);
+    }
+
+    lastIndex = 0;
+    for (i = 0; okay && (i < header.directMethodsSize); i++) {
+        okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
+                &result->directMethods[i], &lastIndex);
+    }
+
+    lastIndex = 0;
+    for (i = 0; okay && (i < header.virtualMethodsSize); i++) {
+        okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
+                &result->virtualMethods[i], &lastIndex);
+    }
+
+    if (! okay) {
+        free(result);
+        return NULL;
+    }
+
+    return result;
+}
diff --git a/libdex/DexClass.h b/libdex/DexClass.h
new file mode 100644
index 0000000..11b3b0e
--- /dev/null
+++ b/libdex/DexClass.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions to deal with class definition structures in DEX files
+ */
+
+#ifndef LIBDEX_DEXCLASS_H_
+#define LIBDEX_DEXCLASS_H_
+
+#include "DexFile.h"
+#include "Leb128.h"
+
+/* expanded form of a class_data_item header */
+struct DexClassDataHeader {
+    u4 staticFieldsSize;
+    u4 instanceFieldsSize;
+    u4 directMethodsSize;
+    u4 virtualMethodsSize;
+};
+
+/* expanded form of encoded_field */
+struct DexField {
+    u4 fieldIdx;    /* index to a field_id_item */
+    u4 accessFlags;
+};
+
+/* expanded form of encoded_method */
+struct DexMethod {
+    u4 methodIdx;    /* index to a method_id_item */
+    u4 accessFlags;
+    u4 codeOff;      /* file offset to a code_item */
+};
+
+/* expanded form of class_data_item. Note: If a particular item is
+ * absent (e.g., no static fields), then the corresponding pointer
+ * is set to NULL. */
+struct DexClassData {
+    DexClassDataHeader header;
+    DexField*          staticFields;
+    DexField*          instanceFields;
+    DexMethod*         directMethods;
+    DexMethod*         virtualMethods;
+};
+
+/* Read and verify the header of a class_data_item. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure). */
+bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit,
+        DexClassDataHeader *pHeader);
+
+/* Read and verify an encoded_field. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure).
+ *
+ * The lastIndex value should be set to 0 before the first field in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags or indices
+ * are valid. */
+bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit,
+        DexField* pField, u4* lastIndex);
+
+/* Read and verify an encoded_method. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure).
+ *
+ * The lastIndex value should be set to 0 before the first method in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags, indices, or offsets
+ * are valid. */
+bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit,
+        DexMethod* pMethod, u4* lastIndex);
+
+/* Read, verify, and return an entire class_data_item. This updates
+ * the given data pointer to point past the end of the read data. This
+ * function allocates a single chunk of memory for the result, which
+ * must subsequently be free()d. This function returns NULL if there
+ * was trouble parsing the data. If this function is passed NULL, it
+ * returns an initialized empty DexClassData structure.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags, indices, or offsets
+ * are valid. */
+DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit);
+
+/*
+ * Get the DexCode for a DexMethod.  Returns NULL if the class is native
+ * or abstract.
+ */
+DEX_INLINE const DexCode* dexGetCode(const DexFile* pDexFile,
+    const DexMethod* pDexMethod)
+{
+    if (pDexMethod->codeOff == 0)
+        return NULL;
+    return (const DexCode*) (pDexFile->baseAddr + pDexMethod->codeOff);
+}
+
+
+/* Read the header of a class_data_item without verification. This
+ * updates the given data pointer to point past the end of the read
+ * data. */
+DEX_INLINE void dexReadClassDataHeader(const u1** pData,
+        DexClassDataHeader *pHeader) {
+    pHeader->staticFieldsSize = readUnsignedLeb128(pData);
+    pHeader->instanceFieldsSize = readUnsignedLeb128(pData);
+    pHeader->directMethodsSize = readUnsignedLeb128(pData);
+    pHeader->virtualMethodsSize = readUnsignedLeb128(pData);
+}
+
+/* Read an encoded_field without verification. This updates the
+ * given data pointer to point past the end of the read data.
+ *
+ * The lastIndex value should be set to 0 before the first field in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ */
+DEX_INLINE void dexReadClassDataField(const u1** pData, DexField* pField,
+        u4* lastIndex) {
+    u4 index = *lastIndex + readUnsignedLeb128(pData);
+
+    pField->accessFlags = readUnsignedLeb128(pData);
+    pField->fieldIdx = index;
+    *lastIndex = index;
+}
+
+/* Read an encoded_method without verification. This updates the
+ * given data pointer to point past the end of the read data.
+ *
+ * The lastIndex value should be set to 0 before the first method in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ */
+DEX_INLINE void dexReadClassDataMethod(const u1** pData, DexMethod* pMethod,
+        u4* lastIndex) {
+    u4 index = *lastIndex + readUnsignedLeb128(pData);
+
+    pMethod->accessFlags = readUnsignedLeb128(pData);
+    pMethod->codeOff = readUnsignedLeb128(pData);
+    pMethod->methodIdx = index;
+    *lastIndex = index;
+}
+
+#endif  // LIBDEX_DEXCLASS_H_
diff --git a/libdex/DexDataMap.cpp b/libdex/DexDataMap.cpp
new file mode 100644
index 0000000..65da14c
--- /dev/null
+++ b/libdex/DexDataMap.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Verification-time map of data section items
+ */
+
+#include "DexDataMap.h"
+#include <safe_iop.h>
+#include <stdlib.h>
+
+/*
+ * Allocate and initialize a DexDataMap. Returns NULL on failure.
+ */
+DexDataMap* dexDataMapAlloc(u4 maxCount) {
+    /*
+     * Allocate a single chunk for the DexDataMap per se as well as the
+     * two arrays.
+     */
+    size_t size = 0;
+    DexDataMap* map = NULL;
+
+    /*
+     * Avoiding pulling in safe_iop for safe_iopf.
+     */
+    const u4 sizeOfItems = (u4) (sizeof(u4) + sizeof(u2));
+    if (!safe_mul(&size, maxCount, sizeOfItems) ||
+        !safe_add(&size, size, sizeof(DexDataMap))) {
+      return NULL;
+    }
+
+    map = (DexDataMap*) malloc(size);
+
+    if (map == NULL) {
+        return NULL;
+    }
+
+    map->count = 0;
+    map->max = maxCount;
+    map->offsets = (u4*) (map + 1);
+    map->types = (u2*) (map->offsets + maxCount);
+
+    return map;
+}
+
+/*
+ * Free a DexDataMap.
+ */
+void dexDataMapFree(DexDataMap* map) {
+    /*
+     * Since everything got allocated together, everything can be freed
+     * in one fell swoop. Also, free(NULL) is a nop (per spec), so we
+     * don't have to worry about an explicit test for that.
+     */
+    free(map);
+}
+
+/*
+ * Add a new element to the map. The offset must be greater than the
+ * all previously added offsets.
+ */
+void dexDataMapAdd(DexDataMap* map, u4 offset, u2 type) {
+    assert(map != NULL);
+    assert(map->count < map->max);
+
+    if ((map->count != 0) &&
+            (map->offsets[map->count - 1] >= offset)) {
+        ALOGE("Out-of-order data map offset: %#x then %#x",
+                map->offsets[map->count - 1], offset);
+        return;
+    }
+
+    map->offsets[map->count] = offset;
+    map->types[map->count] = type;
+    map->count++;
+}
+
+/*
+ * Get the type associated with the given offset. This returns -1 if
+ * there is no entry for the given offset.
+ */
+int dexDataMapGet(DexDataMap* map, u4 offset) {
+    assert(map != NULL);
+
+    // Note: Signed type is important for max and min.
+    int min = 0;
+    int max = map->count - 1;
+    u4* offsets = map->offsets;
+
+    while (max >= min) {
+        int guessIdx = (min + max) >> 1;
+        u4 guess = offsets[guessIdx];
+
+        if (offset < guess) {
+            max = guessIdx - 1;
+        } else if (offset > guess) {
+            min = guessIdx + 1;
+        } else {
+            // We have a winner!
+            return map->types[guessIdx];
+        }
+    }
+
+    // No match.
+    return -1;
+}
+
+/*
+ * Verify that there is an entry in the map, mapping the given offset to
+ * the given type. This will return true if such an entry exists and
+ * return false as well as log an error if not.
+ */
+bool dexDataMapVerify(DexDataMap* map, u4 offset, u2 type) {
+    int found = dexDataMapGet(map, offset);
+
+    if (found == type) {
+        return true;
+    }
+
+    if (found < 0) {
+        ALOGE("No data map entry found @ %#x; expected %x",
+                offset, type);
+    } else {
+        ALOGE("Unexpected data map entry @ %#x: expected %x, found %x",
+                offset, type, found);
+    }
+
+    return false;
+}
diff --git a/libdex/DexDataMap.h b/libdex/DexDataMap.h
new file mode 100644
index 0000000..7e43dc9
--- /dev/null
+++ b/libdex/DexDataMap.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Verification-time map of data section items
+ */
+
+#ifndef LIBDEX_DEXDATAMAP_H_
+#define LIBDEX_DEXDATAMAP_H_
+
+#include "DexFile.h"
+
+struct DexDataMap {
+    u4 count;    /* number of items currently in the map */
+    u4 max;      /* maximum number of items that may be held */
+    u4* offsets; /* array of item offsets */
+    u2* types;   /* corresponding array of item types */
+};
+
+/*
+ * Allocate and initialize a DexDataMap. Returns NULL on failure.
+ */
+DexDataMap* dexDataMapAlloc(u4 maxCount);
+
+/*
+ * Free a DexDataMap.
+ */
+void dexDataMapFree(DexDataMap* map);
+
+/*
+ * Add a new element to the map. The offset must be greater than the
+ * all previously added offsets.
+ */
+void dexDataMapAdd(DexDataMap* map, u4 offset, u2 type);
+
+/*
+ * Get the type associated with the given offset. This returns -1 if
+ * there is no entry for the given offset.
+ */
+int dexDataMapGet(DexDataMap* map, u4 offset);
+
+/*
+ * Verify that there is an entry in the map, mapping the given offset to
+ * the given type. This will return true if such an entry exists and
+ * return false as well as log an error if not.
+ */
+bool dexDataMapVerify(DexDataMap* map, u4 offset, u2 type);
+
+/*
+ * Like dexDataMapVerify(), but also accept a 0 offset as valid.
+ */
+DEX_INLINE bool dexDataMapVerify0Ok(DexDataMap* map, u4 offset, u2 type) {
+    if (offset == 0) {
+        return true;
+    }
+
+    return dexDataMapVerify(map, offset, type);
+}
+
+#endif  // LIBDEX_DEXDATAMAP_H_
diff --git a/libdex/DexDebugInfo.cpp b/libdex/DexDebugInfo.cpp
new file mode 100644
index 0000000..6a7b6bb
--- /dev/null
+++ b/libdex/DexDebugInfo.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Handling of method debug info in a .dex file.
+ */
+
+#include "DexDebugInfo.h"
+#include "DexProto.h"
+#include "Leb128.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Decode the arguments in a method signature, which looks something
+ * like "(ID[Ljava/lang/String;)V".
+ *
+ * Returns the type signature letter for the next argument, or ')' if
+ * there are no more args.  Advances "pSig" to point to the character
+ * after the one returned.
+ */
+static char decodeSignature(const char** pSig)
+{
+    const char* sig = *pSig;
+
+    if (*sig == '(')
+        sig++;
+
+    if (*sig == 'L') {
+        /* object ref */
+        while (*++sig != ';')
+            ;
+        *pSig = sig+1;
+        return 'L';
+    }
+    if (*sig == '[') {
+        /* array; advance past array type */
+        while (*++sig == '[')
+            ;
+        if (*sig == 'L') {
+            while (*++sig != ';')
+                ;
+        }
+        *pSig = sig+1;
+        return '[';
+    }
+    if (*sig == '\0')
+        return *sig;        /* don't advance further */
+
+    *pSig = sig+1;
+    return *sig;
+}
+
+/*
+ * returns the length of a type string, given the start of the
+ * type string. Used for the case where the debug info format
+ * references types that are inside a method type signature.
+ */
+static int typeLength(const char *type) {
+    // Assumes any leading '(' has already been gobbled
+    const char *end = type;
+    decodeSignature(&end);
+    return end - type;
+}
+
+/*
+ * Reads a string index as encoded for the debug info format,
+ * returning a string pointer or NULL as appropriate.
+ */
+static const char* readStringIdx(const DexFile* pDexFile,
+        const u1** pStream) {
+    u4 stringIdx = readUnsignedLeb128(pStream);
+
+    // Remember, encoded string indicies have 1 added to them.
+    if (stringIdx == 0) {
+        return NULL;
+    } else {
+        return dexStringById(pDexFile, stringIdx - 1);
+    }
+}
+
+/*
+ * Reads a type index as encoded for the debug info format, returning
+ * a string pointer for its descriptor or NULL as appropriate.
+ */
+static const char* readTypeIdx(const DexFile* pDexFile,
+        const u1** pStream) {
+    u4 typeIdx = readUnsignedLeb128(pStream);
+
+    // Remember, encoded type indicies have 1 added to them.
+    if (typeIdx == 0) {
+        return NULL;
+    } else {
+        return dexStringByTypeIdx(pDexFile, typeIdx - 1);
+    }
+}
+
+struct LocalInfo {
+    const char *name;
+    const char *descriptor;
+    const char *signature;
+    u2 startAddress;
+    bool live;
+};
+
+static void emitLocalCbIfLive(void *cnxt, int reg, u4 endAddress,
+        LocalInfo *localInReg, DexDebugNewLocalCb localCb)
+{
+    if (localCb != NULL && localInReg[reg].live) {
+        localCb(cnxt, reg, localInReg[reg].startAddress, endAddress,
+                localInReg[reg].name,
+                localInReg[reg].descriptor,
+                localInReg[reg].signature == NULL
+                ? "" : localInReg[reg].signature );
+    }
+}
+
+static void invalidStream(const char* classDescriptor, const DexProto* proto) {
+    IF_ALOGE() {
+        char* methodDescriptor = dexProtoCopyMethodDescriptor(proto);
+        ALOGE("Invalid debug info stream. class %s; proto %s",
+                classDescriptor, methodDescriptor);
+        free(methodDescriptor);
+    }
+}
+
+static void dexDecodeDebugInfo0(
+            const DexFile* pDexFile,
+            const DexCode* pCode,
+            const char* classDescriptor,
+            u4 protoIdx,
+            u4 accessFlags,
+            DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb,
+            void* cnxt,
+            const u1* stream,
+            LocalInfo* localInReg)
+{
+    DexProto proto = { pDexFile, protoIdx };
+    u4 insnsSize = pCode->insnsSize;
+    u4 line = readUnsignedLeb128(&stream);
+    u4 parametersSize = readUnsignedLeb128(&stream);
+    u2 argReg = pCode->registersSize - pCode->insSize;
+    u4 address = 0;
+
+    if ((accessFlags & ACC_STATIC) == 0) {
+        /*
+         * The code is an instance method, which means that there is
+         * an initial this parameter. Also, the proto list should
+         * contain exactly one fewer argument word than the insSize
+         * indicates.
+         */
+        assert(pCode->insSize == (dexProtoComputeArgsSize(&proto) + 1));
+        localInReg[argReg].name = "this";
+        localInReg[argReg].descriptor = classDescriptor;
+        localInReg[argReg].startAddress = 0;
+        localInReg[argReg].live = true;
+        argReg++;
+    } else {
+        assert(pCode->insSize == dexProtoComputeArgsSize(&proto));
+    }
+
+    DexParameterIterator iterator;
+    dexParameterIteratorInit(&iterator, &proto);
+
+    while (parametersSize-- != 0) {
+        const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
+        const char *name;
+        int reg;
+
+        if ((argReg >= pCode->registersSize) || (descriptor == NULL)) {
+            invalidStream(classDescriptor, &proto);
+            return;
+        }
+
+        name = readStringIdx(pDexFile, &stream);
+        reg = argReg;
+
+        switch (descriptor[0]) {
+            case 'D':
+            case 'J':
+                argReg += 2;
+                break;
+            default:
+                argReg += 1;
+                break;
+        }
+
+        if (name != NULL) {
+            localInReg[reg].name = name;
+            localInReg[reg].descriptor = descriptor;
+            localInReg[reg].signature = NULL;
+            localInReg[reg].startAddress = address;
+            localInReg[reg].live = true;
+        }
+    }
+
+    for (;;)  {
+        u1 opcode = *stream++;
+        u2 reg;
+
+        switch (opcode) {
+            case DBG_END_SEQUENCE:
+                return;
+
+            case DBG_ADVANCE_PC:
+                address += readUnsignedLeb128(&stream);
+                break;
+
+            case DBG_ADVANCE_LINE:
+                line += readSignedLeb128(&stream);
+                break;
+
+            case DBG_START_LOCAL:
+            case DBG_START_LOCAL_EXTENDED:
+                reg = readUnsignedLeb128(&stream);
+                if (reg > pCode->registersSize) {
+                    invalidStream(classDescriptor, &proto);
+                    return;
+                }
+
+                // Emit what was previously there, if anything
+                emitLocalCbIfLive(cnxt, reg, address,
+                    localInReg, localCb);
+
+                localInReg[reg].name = readStringIdx(pDexFile, &stream);
+                localInReg[reg].descriptor = readTypeIdx(pDexFile, &stream);
+                if (opcode == DBG_START_LOCAL_EXTENDED) {
+                    localInReg[reg].signature
+                        = readStringIdx(pDexFile, &stream);
+                } else {
+                    localInReg[reg].signature = NULL;
+                }
+                localInReg[reg].startAddress = address;
+                localInReg[reg].live = true;
+                break;
+
+            case DBG_END_LOCAL:
+                reg = readUnsignedLeb128(&stream);
+                if (reg > pCode->registersSize) {
+                    invalidStream(classDescriptor, &proto);
+                    return;
+                }
+
+                emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb);
+                localInReg[reg].live = false;
+                break;
+
+            case DBG_RESTART_LOCAL:
+                reg = readUnsignedLeb128(&stream);
+                if (reg > pCode->registersSize) {
+                    invalidStream(classDescriptor, &proto);
+                    return;
+                }
+
+                if (localInReg[reg].name == NULL
+                        || localInReg[reg].descriptor == NULL) {
+                    invalidStream(classDescriptor, &proto);
+                    return;
+                }
+
+                /*
+                 * If the register is live, the "restart" is superfluous,
+                 * and we don't want to mess with the existing start address.
+                 */
+                if (!localInReg[reg].live) {
+                    localInReg[reg].startAddress = address;
+                    localInReg[reg].live = true;
+                }
+                break;
+
+            case DBG_SET_PROLOGUE_END:
+            case DBG_SET_EPILOGUE_BEGIN:
+            case DBG_SET_FILE:
+                break;
+
+            default: {
+                int adjopcode = opcode - DBG_FIRST_SPECIAL;
+
+                address += adjopcode / DBG_LINE_RANGE;
+                line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
+
+                if (posCb != NULL) {
+                    int done;
+                    done = posCb(cnxt, address, line);
+
+                    if (done) {
+                        // early exit
+                        return;
+                    }
+                }
+                break;
+            }
+        }
+    }
+}
+
+// TODO optimize localCb == NULL case
+void dexDecodeDebugInfo(
+            const DexFile* pDexFile,
+            const DexCode* pCode,
+            const char* classDescriptor,
+            u4 protoIdx,
+            u4 accessFlags,
+            DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb,
+            void* cnxt)
+{
+    const u1* stream = dexGetDebugInfoStream(pDexFile, pCode);
+    LocalInfo localInReg[pCode->registersSize];
+
+    memset(localInReg, 0, sizeof(LocalInfo) * pCode->registersSize);
+
+    if (stream != NULL) {
+        dexDecodeDebugInfo0(pDexFile, pCode, classDescriptor, protoIdx, accessFlags,
+            posCb, localCb, cnxt, stream, localInReg);
+    }
+
+    for (int reg = 0; reg < pCode->registersSize; reg++) {
+        emitLocalCbIfLive(cnxt, reg, pCode->insnsSize, localInReg, localCb);
+    }
+}
diff --git a/libdex/DexDebugInfo.h b/libdex/DexDebugInfo.h
new file mode 100644
index 0000000..bd0954c
--- /dev/null
+++ b/libdex/DexDebugInfo.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Handling of method debug info in a .dex file.
+ */
+
+#ifndef LIBDEX_DEXDEBUGINFO_H_
+#define LIBDEX_DEXDEBUGINFO_H_
+
+#include "DexFile.h"
+
+/*
+ * Callback for "new position table entry".
+ * Returning non-0 causes the decoder to stop early.
+ */
+typedef int (*DexDebugNewPositionCb)(void *cnxt, u4 address, u4 lineNum);
+
+/*
+ * Callback for "new locals table entry". "signature" is an empty string
+ * if no signature is available for an entry.
+ */
+typedef void (*DexDebugNewLocalCb)(void *cnxt, u2 reg, u4 startAddress,
+        u4 endAddress, const char *name, const char *descriptor,
+        const char *signature);
+
+/*
+ * Decode debug info for method.
+ *
+ * posCb is called in ascending address order.
+ * localCb is called in order of ascending end address.
+ */
+void dexDecodeDebugInfo(
+            const DexFile* pDexFile,
+            const DexCode* pDexCode,
+            const char* classDescriptor,
+            u4 protoIdx,
+            u4 accessFlags,
+            DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb,
+            void* cnxt);
+
+#endif  // LIBDEX_DEXDEBUGINFO_H_
diff --git a/libdex/DexFile.cpp b/libdex/DexFile.cpp
new file mode 100644
index 0000000..54070a2
--- /dev/null
+++ b/libdex/DexFile.cpp
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Access the contents of a .dex file.
+ */
+
+#include "DexFile.h"
+#include "DexOptData.h"
+#include "DexProto.h"
+#include "DexCatch.h"
+#include "Leb128.h"
+#include "sha1.h"
+#include "ZipArchive.h"
+
+#include <zlib.h>
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+/*
+ * Verifying checksums is good, but it slows things down and causes us to
+ * touch every page.  In the "optimized" world, it doesn't work at all,
+ * because we rewrite the contents.
+ */
+static const bool kVerifyChecksum = false;
+static const bool kVerifySignature = false;
+
+/* (documented in header) */
+char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type) {
+    const char* string = dexGetPrimitiveTypeDescriptor(type);
+
+    return (string == NULL) ? '\0' : string[0];
+}
+
+/* (documented in header) */
+const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) {
+    switch (type) {
+        case PRIM_VOID:    return "V";
+        case PRIM_BOOLEAN: return "Z";
+        case PRIM_BYTE:    return "B";
+        case PRIM_SHORT:   return "S";
+        case PRIM_CHAR:    return "C";
+        case PRIM_INT:     return "I";
+        case PRIM_LONG:    return "J";
+        case PRIM_FLOAT:   return "F";
+        case PRIM_DOUBLE:  return "D";
+        default:           return NULL;
+    }
+
+    return NULL;
+}
+
+/* (documented in header) */
+const char* dexGetBoxedTypeDescriptor(PrimitiveType type) {
+    switch (type) {
+        case PRIM_VOID:    return NULL;
+        case PRIM_BOOLEAN: return "Ljava/lang/Boolean;";
+        case PRIM_BYTE:    return "Ljava/lang/Byte;";
+        case PRIM_SHORT:   return "Ljava/lang/Short;";
+        case PRIM_CHAR:    return "Ljava/lang/Character;";
+        case PRIM_INT:     return "Ljava/lang/Integer;";
+        case PRIM_LONG:    return "Ljava/lang/Long;";
+        case PRIM_FLOAT:   return "Ljava/lang/Float;";
+        case PRIM_DOUBLE:  return "Ljava/lang/Double;";
+        default:           return NULL;
+    }
+}
+
+/* (documented in header) */
+PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar) {
+    switch (descriptorChar) {
+        case 'V': return PRIM_VOID;
+        case 'Z': return PRIM_BOOLEAN;
+        case 'B': return PRIM_BYTE;
+        case 'S': return PRIM_SHORT;
+        case 'C': return PRIM_CHAR;
+        case 'I': return PRIM_INT;
+        case 'J': return PRIM_LONG;
+        case 'F': return PRIM_FLOAT;
+        case 'D': return PRIM_DOUBLE;
+        default:  return PRIM_NOT;
+    }
+}
+
+/* Return the UTF-8 encoded string with the specified string_id index,
+ * also filling in the UTF-16 size (number of 16-bit code points).*/
+const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx,
+        u4* utf16Size) {
+    const DexStringId* pStringId = dexGetStringId(pDexFile, idx);
+    const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff;
+
+    *utf16Size = readUnsignedLeb128(&ptr);
+    return (const char*) ptr;
+}
+
+/*
+ * Format an SHA-1 digest for printing.  tmpBuf must be able to hold at
+ * least kSHA1DigestOutputLen bytes.
+ */
+const char* dvmSHA1DigestToStr(const unsigned char digest[], char* tmpBuf);
+
+/*
+ * Compute a SHA-1 digest on a range of bytes.
+ */
+static void dexComputeSHA1Digest(const unsigned char* data, size_t length,
+    unsigned char digest[])
+{
+    SHA1_CTX context;
+    SHA1Init(&context);
+    SHA1Update(&context, data, length);
+    SHA1Final(digest, &context);
+}
+
+/*
+ * Format the SHA-1 digest into the buffer, which must be able to hold at
+ * least kSHA1DigestOutputLen bytes.  Returns a pointer to the buffer,
+ */
+static const char* dexSHA1DigestToStr(const unsigned char digest[],char* tmpBuf)
+{
+    static const char hexDigit[] = "0123456789abcdef";
+    char* cp;
+    int i;
+
+    cp = tmpBuf;
+    for (i = 0; i < kSHA1DigestLen; i++) {
+        *cp++ = hexDigit[digest[i] >> 4];
+        *cp++ = hexDigit[digest[i] & 0x0f];
+    }
+    *cp++ = '\0';
+
+    assert(cp == tmpBuf + kSHA1DigestOutputLen);
+
+    return tmpBuf;
+}
+
+/*
+ * Compute a hash code on a UTF-8 string, for use with internal hash tables.
+ *
+ * This may or may not be compatible with UTF-8 hash functions used inside
+ * the Dalvik VM.
+ *
+ * The basic "multiply by 31 and add" approach does better on class names
+ * than most other things tried (e.g. adler32).
+ */
+static u4 classDescriptorHash(const char* str)
+{
+    u4 hash = 1;
+
+    while (*str != '\0')
+        hash = hash * 31 + *str++;
+
+    return hash;
+}
+
+/*
+ * Add an entry to the class lookup table.  We hash the string and probe
+ * until we find an open slot.
+ */
+static void classLookupAdd(DexFile* pDexFile, DexClassLookup* pLookup,
+    int stringOff, int classDefOff, int* pNumProbes)
+{
+    const char* classDescriptor =
+        (const char*) (pDexFile->baseAddr + stringOff);
+    const DexClassDef* pClassDef =
+        (const DexClassDef*) (pDexFile->baseAddr + classDefOff);
+    u4 hash = classDescriptorHash(classDescriptor);
+    int mask = pLookup->numEntries-1;
+    int idx = hash & mask;
+
+    /*
+     * Find the first empty slot.  We oversized the table, so this is
+     * guaranteed to finish.
+     */
+    int probes = 0;
+    while (pLookup->table[idx].classDescriptorOffset != 0) {
+        idx = (idx + 1) & mask;
+        probes++;
+    }
+    //if (probes > 1)
+    //    ALOGW("classLookupAdd: probes=%d", probes);
+
+    pLookup->table[idx].classDescriptorHash = hash;
+    pLookup->table[idx].classDescriptorOffset = stringOff;
+    pLookup->table[idx].classDefOffset = classDefOff;
+    *pNumProbes = probes;
+}
+
+/*
+ * Create the class lookup hash table.
+ *
+ * Returns newly-allocated storage.
+ */
+DexClassLookup* dexCreateClassLookup(DexFile* pDexFile)
+{
+    DexClassLookup* pLookup;
+    int allocSize;
+    int i, numEntries;
+    int numProbes, totalProbes, maxProbes;
+
+    numProbes = totalProbes = maxProbes = 0;
+
+    assert(pDexFile != NULL);
+
+    /*
+     * Using a factor of 3 results in far less probing than a factor of 2,
+     * but almost doubles the flash storage requirements for the bootstrap
+     * DEX files.  The overall impact on class loading performance seems
+     * to be minor.  We could probably get some performance improvement by
+     * using a secondary hash.
+     */
+    numEntries = dexRoundUpPower2(pDexFile->pHeader->classDefsSize * 2);
+    allocSize = offsetof(DexClassLookup, table)
+                    + numEntries * sizeof(pLookup->table[0]);
+
+    pLookup = (DexClassLookup*) calloc(1, allocSize);
+    if (pLookup == NULL)
+        return NULL;
+    pLookup->size = allocSize;
+    pLookup->numEntries = numEntries;
+
+    for (i = 0; i < (int)pDexFile->pHeader->classDefsSize; i++) {
+        const DexClassDef* pClassDef;
+        const char* pString;
+
+        pClassDef = dexGetClassDef(pDexFile, i);
+        pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+        classLookupAdd(pDexFile, pLookup,
+            (u1*)pString - pDexFile->baseAddr,
+            (u1*)pClassDef - pDexFile->baseAddr, &numProbes);
+
+        if (numProbes > maxProbes)
+            maxProbes = numProbes;
+        totalProbes += numProbes;
+    }
+
+    ALOGV("Class lookup: classes=%d slots=%d (%d%% occ) alloc=%d"
+         " total=%d max=%d",
+        pDexFile->pHeader->classDefsSize, numEntries,
+        (100 * pDexFile->pHeader->classDefsSize) / numEntries,
+        allocSize, totalProbes, maxProbes);
+
+    return pLookup;
+}
+
+
+/*
+ * Set up the basic raw data pointers of a DexFile. This function isn't
+ * meant for general use.
+ */
+void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data) {
+    DexHeader *pHeader = (DexHeader*) data;
+
+    pDexFile->baseAddr = data;
+    pDexFile->pHeader = pHeader;
+    pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff);
+    pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff);
+    pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff);
+    pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff);
+    pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff);
+    pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff);
+    pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff);
+}
+
+/*
+ * Parse an optimized or unoptimized .dex file sitting in memory.  This is
+ * called after the byte-ordering and structure alignment has been fixed up.
+ *
+ * On success, return a newly-allocated DexFile.
+ */
+DexFile* dexFileParse(const u1* data, size_t length, int flags)
+{
+    DexFile* pDexFile = NULL;
+    const DexHeader* pHeader;
+    const u1* magic;
+    int result = -1;
+
+    if (length < sizeof(DexHeader)) {
+        ALOGE("too short to be a valid .dex");
+        goto bail;      /* bad file format */
+    }
+
+    pDexFile = (DexFile*) malloc(sizeof(DexFile));
+    if (pDexFile == NULL)
+        goto bail;      /* alloc failure */
+    memset(pDexFile, 0, sizeof(DexFile));
+
+    /*
+     * Peel off the optimized header.
+     */
+    if (memcmp(data, DEX_OPT_MAGIC, 4) == 0) {
+        magic = data;
+        if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
+            ALOGE("bad opt version (0x%02x %02x %02x %02x)",
+                 magic[4], magic[5], magic[6], magic[7]);
+            goto bail;
+        }
+
+        pDexFile->pOptHeader = (const DexOptHeader*) data;
+        ALOGV("Good opt header, DEX offset is %d, flags=0x%02x",
+            pDexFile->pOptHeader->dexOffset, pDexFile->pOptHeader->flags);
+
+        /* parse the optimized dex file tables */
+        if (!dexParseOptData(data, length, pDexFile))
+            goto bail;
+
+        /* ignore the opt header and appended data from here on out */
+        data += pDexFile->pOptHeader->dexOffset;
+        length -= pDexFile->pOptHeader->dexOffset;
+        if (pDexFile->pOptHeader->dexLength > length) {
+            ALOGE("File truncated? stored len=%d, rem len=%d",
+                pDexFile->pOptHeader->dexLength, (int) length);
+            goto bail;
+        }
+        length = pDexFile->pOptHeader->dexLength;
+    }
+
+    dexFileSetupBasicPointers(pDexFile, data);
+    pHeader = pDexFile->pHeader;
+
+    if (!dexHasValidMagic(pHeader)) {
+        goto bail;
+    }
+
+    /*
+     * Verify the checksum(s).  This is reasonably quick, but does require
+     * touching every byte in the DEX file.  The base checksum changes after
+     * byte-swapping and DEX optimization.
+     */
+    if (flags & kDexParseVerifyChecksum) {
+        u4 adler = dexComputeChecksum(pHeader);
+        if (adler != pHeader->checksum) {
+            ALOGE("ERROR: bad checksum (%08x vs %08x)",
+                adler, pHeader->checksum);
+            if (!(flags & kDexParseContinueOnError))
+                goto bail;
+        } else {
+            ALOGV("+++ adler32 checksum (%08x) verified", adler);
+        }
+
+        const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
+        if (pOptHeader != NULL) {
+            adler = dexComputeOptChecksum(pOptHeader);
+            if (adler != pOptHeader->checksum) {
+                ALOGE("ERROR: bad opt checksum (%08x vs %08x)",
+                    adler, pOptHeader->checksum);
+                if (!(flags & kDexParseContinueOnError))
+                    goto bail;
+            } else {
+                ALOGV("+++ adler32 opt checksum (%08x) verified", adler);
+            }
+        }
+    }
+
+    /*
+     * Verify the SHA-1 digest.  (Normally we don't want to do this --
+     * the digest is used to uniquely identify the original DEX file, and
+     * can't be computed for verification after the DEX is byte-swapped
+     * and optimized.)
+     */
+    if (kVerifySignature) {
+        unsigned char sha1Digest[kSHA1DigestLen];
+        const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum) +
+                            kSHA1DigestLen;
+
+        dexComputeSHA1Digest(data + nonSum, length - nonSum, sha1Digest);
+        if (memcmp(sha1Digest, pHeader->signature, kSHA1DigestLen) != 0) {
+            char tmpBuf1[kSHA1DigestOutputLen];
+            char tmpBuf2[kSHA1DigestOutputLen];
+            ALOGE("ERROR: bad SHA1 digest (%s vs %s)",
+                dexSHA1DigestToStr(sha1Digest, tmpBuf1),
+                dexSHA1DigestToStr(pHeader->signature, tmpBuf2));
+            if (!(flags & kDexParseContinueOnError))
+                goto bail;
+        } else {
+            ALOGV("+++ sha1 digest verified");
+        }
+    }
+
+    if (pHeader->fileSize != length) {
+        ALOGE("ERROR: stored file size (%d) != expected (%d)",
+            (int) pHeader->fileSize, (int) length);
+        if (!(flags & kDexParseContinueOnError))
+            goto bail;
+    }
+
+    if (pHeader->classDefsSize == 0) {
+        ALOGE("ERROR: DEX file has no classes in it, failing");
+        goto bail;
+    }
+
+    /*
+     * Success!
+     */
+    result = 0;
+
+bail:
+    if (result != 0 && pDexFile != NULL) {
+        dexFileFree(pDexFile);
+        pDexFile = NULL;
+    }
+    return pDexFile;
+}
+
+/*
+ * Free up the DexFile and any associated data structures.
+ *
+ * Note we may be called with a partially-initialized DexFile.
+ */
+void dexFileFree(DexFile* pDexFile)
+{
+    if (pDexFile == NULL)
+        return;
+
+    free(pDexFile);
+}
+
+/*
+ * Look up a class definition entry by descriptor.
+ *
+ * "descriptor" should look like "Landroid/debug/Stuff;".
+ */
+const DexClassDef* dexFindClass(const DexFile* pDexFile,
+    const char* descriptor)
+{
+    const DexClassLookup* pLookup = pDexFile->pClassLookup;
+    u4 hash;
+    int idx, mask;
+
+    hash = classDescriptorHash(descriptor);
+    mask = pLookup->numEntries - 1;
+    idx = hash & mask;
+
+    /*
+     * Search until we find a matching entry or an empty slot.
+     */
+    while (true) {
+        int offset;
+
+        offset = pLookup->table[idx].classDescriptorOffset;
+        if (offset == 0)
+            return NULL;
+
+        if (pLookup->table[idx].classDescriptorHash == hash) {
+            const char* str;
+
+            str = (const char*) (pDexFile->baseAddr + offset);
+            if (strcmp(str, descriptor) == 0) {
+                return (const DexClassDef*)
+                    (pDexFile->baseAddr + pLookup->table[idx].classDefOffset);
+            }
+        }
+
+        idx = (idx + 1) & mask;
+    }
+}
+
+
+/*
+ * Compute the DEX file checksum for a memory-mapped DEX file.
+ */
+u4 dexComputeChecksum(const DexHeader* pHeader)
+{
+    const u1* start = (const u1*) pHeader;
+
+    uLong adler = adler32(0L, Z_NULL, 0);
+    const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
+
+    return (u4) adler32(adler, start + nonSum, pHeader->fileSize - nonSum);
+}
+
+/*
+ * Compute the size, in bytes, of a DexCode.
+ */
+size_t dexGetDexCodeSize(const DexCode* pCode)
+{
+    /*
+     * The catch handler data is the last entry.  It has a variable number
+     * of variable-size pieces, so we need to create an iterator.
+     */
+    u4 handlersSize;
+    u4 offset;
+    u4 ui;
+
+    if (pCode->triesSize != 0) {
+        handlersSize = dexGetHandlersSize(pCode);
+        offset = dexGetFirstHandlerOffset(pCode);
+    } else {
+        handlersSize = 0;
+        offset = 0;
+    }
+
+    for (ui = 0; ui < handlersSize; ui++) {
+        DexCatchIterator iterator;
+        dexCatchIteratorInit(&iterator, pCode, offset);
+        offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
+    }
+
+    const u1* handlerData = dexGetCatchHandlerData(pCode);
+
+    //ALOGD("+++ pCode=%p handlerData=%p last offset=%d",
+    //    pCode, handlerData, offset);
+
+    /* return the size of the catch handler + everything before it */
+    return (handlerData - (u1*) pCode) + offset;
+}
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+u4 dexRoundUpPower2(u4 val)
+{
+    val--;
+    val |= val >> 1;
+    val |= val >> 2;
+    val |= val >> 4;
+    val |= val >> 8;
+    val |= val >> 16;
+    val++;
+
+    return val;
+}
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
new file mode 100644
index 0000000..e8ab319
--- /dev/null
+++ b/libdex/DexFile.h
@@ -0,0 +1,1027 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Access .dex (Dalvik Executable Format) files.  The code here assumes that
+ * the DEX file has been rewritten (byte-swapped, word-aligned) and that
+ * the contents can be directly accessed as a collection of C arrays.  Please
+ * see docs/dalvik/dex-format.html for a detailed description.
+ *
+ * The structure and field names were chosen to match those in the DEX spec.
+ *
+ * It's generally assumed that the DEX file will be stored in shared memory,
+ * obviating the need to copy code and constant pool entries into newly
+ * allocated storage.  Maintaining local pointers to items in the shared area
+ * is valid and encouraged.
+ *
+ * All memory-mapped structures are 32-bit aligned unless otherwise noted.
+ */
+
+#ifndef LIBDEX_DEXFILE_H_
+#define LIBDEX_DEXFILE_H_
+
+#ifndef LOG_TAG
+# define LOG_TAG "libdex"
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include "cutils/log.h"
+
+/*
+ * If "very verbose" logging is enabled, make it equivalent to ALOGV.
+ * Otherwise, make it disappear.
+ *
+ * Define this above the #include "Dalvik.h" to enable for only a
+ * single file.
+ */
+/* #define VERY_VERBOSE_LOG */
+#if defined(VERY_VERBOSE_LOG)
+# define LOGVV      ALOGV
+# define IF_LOGVV() IF_ALOGV()
+#else
+# define LOGVV(...) ((void)0)
+# define IF_LOGVV() if (false)
+#endif
+
+/*
+ * These match the definitions in the VM specification.
+ */
+typedef uint8_t             u1;
+typedef uint16_t            u2;
+typedef uint32_t            u4;
+typedef uint64_t            u8;
+typedef int8_t              s1;
+typedef int16_t             s2;
+typedef int32_t             s4;
+typedef int64_t             s8;
+
+#include "libdex/SysUtil.h"
+
+/*
+ * gcc-style inline management -- ensures we have a copy of all functions
+ * in the library, so code that links against us will work whether or not
+ * it was built with optimizations enabled.
+ */
+#ifndef _DEX_GEN_INLINES             /* only defined by DexInlines.c */
+# define DEX_INLINE extern __inline__
+#else
+# define DEX_INLINE
+#endif
+
+/* DEX file magic number */
+#define DEX_MAGIC       "dex\n"
+
+/* current version, encoded in 4 bytes of ASCII */
+#define DEX_MAGIC_VERS  "036\0"
+
+/*
+ * older but still-recognized version (corresponding to Android API
+ * levels 13 and earlier
+ */
+#define DEX_MAGIC_VERS_API_13  "035\0"
+
+/* same, but for optimized DEX header */
+#define DEX_OPT_MAGIC   "dey\n"
+#define DEX_OPT_MAGIC_VERS  "036\0"
+
+#define DEX_DEP_MAGIC   "deps"
+
+/*
+ * 160-bit SHA-1 digest.
+ */
+enum { kSHA1DigestLen = 20,
+       kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 };
+
+/* general constants */
+enum {
+    kDexEndianConstant = 0x12345678,    /* the endianness indicator */
+    kDexNoIndex = 0xffffffff,           /* not a valid index value */
+};
+
+/*
+ * Enumeration of all the primitive types.
+ */
+enum PrimitiveType {
+    PRIM_NOT        = 0,       /* value is a reference type, not a primitive type */
+    PRIM_VOID       = 1,
+    PRIM_BOOLEAN    = 2,
+    PRIM_BYTE       = 3,
+    PRIM_SHORT      = 4,
+    PRIM_CHAR       = 5,
+    PRIM_INT        = 6,
+    PRIM_LONG       = 7,
+    PRIM_FLOAT      = 8,
+    PRIM_DOUBLE     = 9,
+};
+
+/*
+ * access flags and masks; the "standard" ones are all <= 0x4000
+ *
+ * Note: There are related declarations in vm/oo/Object.h in the ClassFlags
+ * enum.
+ */
+enum {
+    ACC_PUBLIC       = 0x00000001,       // class, field, method, ic
+    ACC_PRIVATE      = 0x00000002,       // field, method, ic
+    ACC_PROTECTED    = 0x00000004,       // field, method, ic
+    ACC_STATIC       = 0x00000008,       // field, method, ic
+    ACC_FINAL        = 0x00000010,       // class, field, method, ic
+    ACC_SYNCHRONIZED = 0x00000020,       // method (only allowed on natives)
+    ACC_SUPER        = 0x00000020,       // class (not used in Dalvik)
+    ACC_VOLATILE     = 0x00000040,       // field
+    ACC_BRIDGE       = 0x00000040,       // method (1.5)
+    ACC_TRANSIENT    = 0x00000080,       // field
+    ACC_VARARGS      = 0x00000080,       // method (1.5)
+    ACC_NATIVE       = 0x00000100,       // method
+    ACC_INTERFACE    = 0x00000200,       // class, ic
+    ACC_ABSTRACT     = 0x00000400,       // class, method, ic
+    ACC_STRICT       = 0x00000800,       // method
+    ACC_SYNTHETIC    = 0x00001000,       // field, method, ic
+    ACC_ANNOTATION   = 0x00002000,       // class, ic (1.5)
+    ACC_ENUM         = 0x00004000,       // class, field, ic (1.5)
+    ACC_CONSTRUCTOR  = 0x00010000,       // method (Dalvik only)
+    ACC_DECLARED_SYNCHRONIZED =
+                       0x00020000,       // method (Dalvik only)
+    ACC_CLASS_MASK =
+        (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
+                | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
+    ACC_INNER_CLASS_MASK =
+        (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC),
+    ACC_FIELD_MASK =
+        (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
+                | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM),
+    ACC_METHOD_MASK =
+        (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
+                | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE
+                | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR
+                | ACC_DECLARED_SYNCHRONIZED),
+};
+
+/* annotation constants */
+enum {
+    kDexVisibilityBuild         = 0x00,     /* annotation visibility */
+    kDexVisibilityRuntime       = 0x01,
+    kDexVisibilitySystem        = 0x02,
+
+    kDexAnnotationByte          = 0x00,
+    kDexAnnotationShort         = 0x02,
+    kDexAnnotationChar          = 0x03,
+    kDexAnnotationInt           = 0x04,
+    kDexAnnotationLong          = 0x06,
+    kDexAnnotationFloat         = 0x10,
+    kDexAnnotationDouble        = 0x11,
+    kDexAnnotationString        = 0x17,
+    kDexAnnotationType          = 0x18,
+    kDexAnnotationField         = 0x19,
+    kDexAnnotationMethod        = 0x1a,
+    kDexAnnotationEnum          = 0x1b,
+    kDexAnnotationArray         = 0x1c,
+    kDexAnnotationAnnotation    = 0x1d,
+    kDexAnnotationNull          = 0x1e,
+    kDexAnnotationBoolean       = 0x1f,
+
+    kDexAnnotationValueTypeMask = 0x1f,     /* low 5 bits */
+    kDexAnnotationValueArgShift = 5,
+};
+
+/* map item type codes */
+enum {
+    kDexTypeHeaderItem               = 0x0000,
+    kDexTypeStringIdItem             = 0x0001,
+    kDexTypeTypeIdItem               = 0x0002,
+    kDexTypeProtoIdItem              = 0x0003,
+    kDexTypeFieldIdItem              = 0x0004,
+    kDexTypeMethodIdItem             = 0x0005,
+    kDexTypeClassDefItem             = 0x0006,
+    kDexTypeMapList                  = 0x1000,
+    kDexTypeTypeList                 = 0x1001,
+    kDexTypeAnnotationSetRefList     = 0x1002,
+    kDexTypeAnnotationSetItem        = 0x1003,
+    kDexTypeClassDataItem            = 0x2000,
+    kDexTypeCodeItem                 = 0x2001,
+    kDexTypeStringDataItem           = 0x2002,
+    kDexTypeDebugInfoItem            = 0x2003,
+    kDexTypeAnnotationItem           = 0x2004,
+    kDexTypeEncodedArrayItem         = 0x2005,
+    kDexTypeAnnotationsDirectoryItem = 0x2006,
+};
+
+/* auxillary data section chunk codes */
+enum {
+    kDexChunkClassLookup            = 0x434c4b50,   /* CLKP */
+    kDexChunkRegisterMaps           = 0x524d4150,   /* RMAP */
+
+    kDexChunkEnd                    = 0x41454e44,   /* AEND */
+};
+
+/* debug info opcodes and constants */
+enum {
+    DBG_END_SEQUENCE         = 0x00,
+    DBG_ADVANCE_PC           = 0x01,
+    DBG_ADVANCE_LINE         = 0x02,
+    DBG_START_LOCAL          = 0x03,
+    DBG_START_LOCAL_EXTENDED = 0x04,
+    DBG_END_LOCAL            = 0x05,
+    DBG_RESTART_LOCAL        = 0x06,
+    DBG_SET_PROLOGUE_END     = 0x07,
+    DBG_SET_EPILOGUE_BEGIN   = 0x08,
+    DBG_SET_FILE             = 0x09,
+    DBG_FIRST_SPECIAL        = 0x0a,
+    DBG_LINE_BASE            = -4,
+    DBG_LINE_RANGE           = 15,
+};
+
+/*
+ * Direct-mapped "header_item" struct.
+ */
+struct DexHeader {
+    u1  magic[8];           /* includes version number */
+    u4  checksum;           /* adler32 checksum */
+    u1  signature[kSHA1DigestLen]; /* SHA-1 hash */
+    u4  fileSize;           /* length of entire file */
+    u4  headerSize;         /* offset to start of next section */
+    u4  endianTag;
+    u4  linkSize;
+    u4  linkOff;
+    u4  mapOff;
+    u4  stringIdsSize;
+    u4  stringIdsOff;
+    u4  typeIdsSize;
+    u4  typeIdsOff;
+    u4  protoIdsSize;
+    u4  protoIdsOff;
+    u4  fieldIdsSize;
+    u4  fieldIdsOff;
+    u4  methodIdsSize;
+    u4  methodIdsOff;
+    u4  classDefsSize;
+    u4  classDefsOff;
+    u4  dataSize;
+    u4  dataOff;
+};
+
+/*
+ * Direct-mapped "map_item".
+ */
+struct DexMapItem {
+    u2 type;              /* type code (see kDexType* above) */
+    u2 unused;
+    u4 size;              /* count of items of the indicated type */
+    u4 offset;            /* file offset to the start of data */
+};
+
+/*
+ * Direct-mapped "map_list".
+ */
+struct DexMapList {
+    u4  size;               /* #of entries in list */
+    DexMapItem list[1];     /* entries */
+};
+
+/*
+ * Direct-mapped "string_id_item".
+ */
+struct DexStringId {
+    u4 stringDataOff;      /* file offset to string_data_item */
+};
+
+/*
+ * Direct-mapped "type_id_item".
+ */
+struct DexTypeId {
+    u4  descriptorIdx;      /* index into stringIds list for type descriptor */
+};
+
+/*
+ * Direct-mapped "field_id_item".
+ */
+struct DexFieldId {
+    u2  classIdx;           /* index into typeIds list for defining class */
+    u2  typeIdx;            /* index into typeIds for field type */
+    u4  nameIdx;            /* index into stringIds for field name */
+};
+
+/*
+ * Direct-mapped "method_id_item".
+ */
+struct DexMethodId {
+    u2  classIdx;           /* index into typeIds list for defining class */
+    u2  protoIdx;           /* index into protoIds for method prototype */
+    u4  nameIdx;            /* index into stringIds for method name */
+};
+
+/*
+ * Direct-mapped "proto_id_item".
+ */
+struct DexProtoId {
+    u4  shortyIdx;          /* index into stringIds for shorty descriptor */
+    u4  returnTypeIdx;      /* index into typeIds list for return type */
+    u4  parametersOff;      /* file offset to type_list for parameter types */
+};
+
+/*
+ * Direct-mapped "class_def_item".
+ */
+struct DexClassDef {
+    u4  classIdx;           /* index into typeIds for this class */
+    u4  accessFlags;
+    u4  superclassIdx;      /* index into typeIds for superclass */
+    u4  interfacesOff;      /* file offset to DexTypeList */
+    u4  sourceFileIdx;      /* index into stringIds for source file name */
+    u4  annotationsOff;     /* file offset to annotations_directory_item */
+    u4  classDataOff;       /* file offset to class_data_item */
+    u4  staticValuesOff;    /* file offset to DexEncodedArray */
+};
+
+/*
+ * Direct-mapped "type_item".
+ */
+struct DexTypeItem {
+    u2  typeIdx;            /* index into typeIds */
+};
+
+/*
+ * Direct-mapped "type_list".
+ */
+struct DexTypeList {
+    u4  size;               /* #of entries in list */
+    DexTypeItem list[1];    /* entries */
+};
+
+/*
+ * Direct-mapped "code_item".
+ *
+ * The "catches" table is used when throwing an exception,
+ * "debugInfo" is used when displaying an exception stack trace or
+ * debugging. An offset of zero indicates that there are no entries.
+ */
+struct DexCode {
+    u2  registersSize;
+    u2  insSize;
+    u2  outsSize;
+    u2  triesSize;
+    u4  debugInfoOff;       /* file offset to debug info stream */
+    u4  insnsSize;          /* size of the insns array, in u2 units */
+    u2  insns[1];
+    /* followed by optional u2 padding */
+    /* followed by try_item[triesSize] */
+    /* followed by uleb128 handlersSize */
+    /* followed by catch_handler_item[handlersSize] */
+};
+
+/*
+ * Direct-mapped "try_item".
+ */
+struct DexTry {
+    u4  startAddr;          /* start address, in 16-bit code units */
+    u2  insnCount;          /* instruction count, in 16-bit code units */
+    u2  handlerOff;         /* offset in encoded handler data to handlers */
+};
+
+/*
+ * Link table.  Currently undefined.
+ */
+struct DexLink {
+    u1  bleargh;
+};
+
+
+/*
+ * Direct-mapped "annotations_directory_item".
+ */
+struct DexAnnotationsDirectoryItem {
+    u4  classAnnotationsOff;  /* offset to DexAnnotationSetItem */
+    u4  fieldsSize;           /* count of DexFieldAnnotationsItem */
+    u4  methodsSize;          /* count of DexMethodAnnotationsItem */
+    u4  parametersSize;       /* count of DexParameterAnnotationsItem */
+    /* followed by DexFieldAnnotationsItem[fieldsSize] */
+    /* followed by DexMethodAnnotationsItem[methodsSize] */
+    /* followed by DexParameterAnnotationsItem[parametersSize] */
+};
+
+/*
+ * Direct-mapped "field_annotations_item".
+ */
+struct DexFieldAnnotationsItem {
+    u4  fieldIdx;
+    u4  annotationsOff;             /* offset to DexAnnotationSetItem */
+};
+
+/*
+ * Direct-mapped "method_annotations_item".
+ */
+struct DexMethodAnnotationsItem {
+    u4  methodIdx;
+    u4  annotationsOff;             /* offset to DexAnnotationSetItem */
+};
+
+/*
+ * Direct-mapped "parameter_annotations_item".
+ */
+struct DexParameterAnnotationsItem {
+    u4  methodIdx;
+    u4  annotationsOff;             /* offset to DexAnotationSetRefList */
+};
+
+/*
+ * Direct-mapped "annotation_set_ref_item".
+ */
+struct DexAnnotationSetRefItem {
+    u4  annotationsOff;             /* offset to DexAnnotationSetItem */
+};
+
+/*
+ * Direct-mapped "annotation_set_ref_list".
+ */
+struct DexAnnotationSetRefList {
+    u4  size;
+    DexAnnotationSetRefItem list[1];
+};
+
+/*
+ * Direct-mapped "annotation_set_item".
+ */
+struct DexAnnotationSetItem {
+    u4  size;
+    u4  entries[1];                 /* offset to DexAnnotationItem */
+};
+
+/*
+ * Direct-mapped "annotation_item".
+ *
+ * NOTE: this structure is byte-aligned.
+ */
+struct DexAnnotationItem {
+    u1  visibility;
+    u1  annotation[1];              /* data in encoded_annotation format */
+};
+
+/*
+ * Direct-mapped "encoded_array".
+ *
+ * NOTE: this structure is byte-aligned.
+ */
+struct DexEncodedArray {
+    u1  array[1];                   /* data in encoded_array format */
+};
+
+/*
+ * Lookup table for classes.  It provides a mapping from class name to
+ * class definition.  Used by dexFindClass().
+ *
+ * We calculate this at DEX optimization time and embed it in the file so we
+ * don't need the same hash table in every VM.  This is slightly slower than
+ * a hash table with direct pointers to the items, but because it's shared
+ * there's less of a penalty for using a fairly sparse table.
+ */
+struct DexClassLookup {
+    int     size;                       // total size, including "size"
+    int     numEntries;                 // size of table[]; always power of 2
+    struct {
+        u4      classDescriptorHash;    // class descriptor hash code
+        int     classDescriptorOffset;  // in bytes, from start of DEX
+        int     classDefOffset;         // in bytes, from start of DEX
+    } table[1];
+};
+
+/*
+ * Header added by DEX optimization pass.  Values are always written in
+ * local byte and structure padding.  The first field (magic + version)
+ * is guaranteed to be present and directly readable for all expected
+ * compiler configurations; the rest is version-dependent.
+ *
+ * Try to keep this simple and fixed-size.
+ */
+struct DexOptHeader {
+    u1  magic[8];           /* includes version number */
+
+    u4  dexOffset;          /* file offset of DEX header */
+    u4  dexLength;
+    u4  depsOffset;         /* offset of optimized DEX dependency table */
+    u4  depsLength;
+    u4  optOffset;          /* file offset of optimized data tables */
+    u4  optLength;
+
+    u4  flags;              /* some info flags */
+    u4  checksum;           /* adler32 checksum covering deps/opt */
+
+    /* pad for 64-bit alignment if necessary */
+};
+
+#define DEX_OPT_FLAG_BIG            (1<<1)  /* swapped to big-endian */
+
+#define DEX_INTERFACE_CACHE_SIZE    128     /* must be power of 2 */
+
+/*
+ * Structure representing a DEX file.
+ *
+ * Code should regard DexFile as opaque, using the API calls provided here
+ * to access specific structures.
+ */
+struct DexFile {
+    /* directly-mapped "opt" header */
+    const DexOptHeader* pOptHeader;
+
+    /* pointers to directly-mapped structs and arrays in base DEX */
+    const DexHeader*    pHeader;
+    const DexStringId*  pStringIds;
+    const DexTypeId*    pTypeIds;
+    const DexFieldId*   pFieldIds;
+    const DexMethodId*  pMethodIds;
+    const DexProtoId*   pProtoIds;
+    const DexClassDef*  pClassDefs;
+    const DexLink*      pLinkData;
+
+    /*
+     * These are mapped out of the "auxillary" section, and may not be
+     * included in the file.
+     */
+    const DexClassLookup* pClassLookup;
+    const void*         pRegisterMapPool;       // RegisterMapClassPool
+
+    /* points to start of DEX file data */
+    const u1*           baseAddr;
+
+    /* track memory overhead for auxillary structures */
+    int                 overhead;
+
+    /* additional app-specific data structures associated with the DEX */
+    //void*               auxData;
+};
+
+/*
+ * Utility function -- rounds up to the nearest power of 2.
+ */
+u4 dexRoundUpPower2(u4 val);
+
+/*
+ * Parse an optimized or unoptimized .dex file sitting in memory.
+ *
+ * On success, return a newly-allocated DexFile.
+ */
+DexFile* dexFileParse(const u1* data, size_t length, int flags);
+
+/* bit values for "flags" argument to dexFileParse */
+enum {
+    kDexParseDefault            = 0,
+    kDexParseVerifyChecksum     = 1,
+    kDexParseContinueOnError    = (1 << 1),
+};
+
+/*
+ * Fix the byte ordering of all fields in the DEX file, and do
+ * structural verification. This is only required for code that opens
+ * "raw" DEX files, such as the DEX optimizer.
+ *
+ * Return 0 on success.
+ */
+int dexSwapAndVerify(u1* addr, int len);
+
+/*
+ * Detect the file type of the given memory buffer via magic number.
+ * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
+ * but return successfully on an optimized DEX file, and report an
+ * error for all other cases.
+ *
+ * Return 0 on success.
+ */
+int dexSwapAndVerifyIfNecessary(u1* addr, int len);
+
+/*
+ * Check to see if the file magic and format version in the given
+ * header are recognized as valid. Returns true if they are
+ * acceptable.
+ */
+bool dexHasValidMagic(const DexHeader* pHeader);
+
+/*
+ * Compute DEX checksum.
+ */
+u4 dexComputeChecksum(const DexHeader* pHeader);
+
+/*
+ * Free a DexFile structure, along with any associated structures.
+ */
+void dexFileFree(DexFile* pDexFile);
+
+/*
+ * Create class lookup table.
+ */
+DexClassLookup* dexCreateClassLookup(DexFile* pDexFile);
+
+/*
+ * Find a class definition by descriptor.
+ */
+const DexClassDef* dexFindClass(const DexFile* pFile, const char* descriptor);
+
+/*
+ * Set up the basic raw data pointers of a DexFile. This function isn't
+ * meant for general use.
+ */
+void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data);
+
+/* return the DexMapList of the file, if any */
+DEX_INLINE const DexMapList* dexGetMap(const DexFile* pDexFile) {
+    u4 mapOff = pDexFile->pHeader->mapOff;
+
+    if (mapOff == 0) {
+        return NULL;
+    } else {
+        return (const DexMapList*) (pDexFile->baseAddr + mapOff);
+    }
+}
+
+/* return the const char* string data referred to by the given string_id */
+DEX_INLINE const char* dexGetStringData(const DexFile* pDexFile,
+        const DexStringId* pStringId) {
+    const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff;
+
+    // Skip the uleb128 length.
+    while (*(ptr++) > 0x7f) /* empty */ ;
+
+    return (const char*) ptr;
+}
+/* return the StringId with the specified index */
+DEX_INLINE const DexStringId* dexGetStringId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->stringIdsSize);
+    return &pDexFile->pStringIds[idx];
+}
+/* return the UTF-8 encoded string with the specified string_id index */
+DEX_INLINE const char* dexStringById(const DexFile* pDexFile, u4 idx) {
+    const DexStringId* pStringId = dexGetStringId(pDexFile, idx);
+    return dexGetStringData(pDexFile, pStringId);
+}
+
+/* Return the UTF-8 encoded string with the specified string_id index,
+ * also filling in the UTF-16 size (number of 16-bit code points).*/
+const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx,
+        u4* utf16Size);
+
+/* return the TypeId with the specified index */
+DEX_INLINE const DexTypeId* dexGetTypeId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->typeIdsSize);
+    return &pDexFile->pTypeIds[idx];
+}
+
+/*
+ * Get the descriptor string associated with a given type index.
+ * The caller should not free() the returned string.
+ */
+DEX_INLINE const char* dexStringByTypeIdx(const DexFile* pDexFile, u4 idx) {
+    const DexTypeId* typeId = dexGetTypeId(pDexFile, idx);
+    return dexStringById(pDexFile, typeId->descriptorIdx);
+}
+
+/* return the MethodId with the specified index */
+DEX_INLINE const DexMethodId* dexGetMethodId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->methodIdsSize);
+    return &pDexFile->pMethodIds[idx];
+}
+
+/* return the FieldId with the specified index */
+DEX_INLINE const DexFieldId* dexGetFieldId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->fieldIdsSize);
+    return &pDexFile->pFieldIds[idx];
+}
+
+/* return the ProtoId with the specified index */
+DEX_INLINE const DexProtoId* dexGetProtoId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->protoIdsSize);
+    return &pDexFile->pProtoIds[idx];
+}
+
+/*
+ * Get the parameter list from a ProtoId. The returns NULL if the ProtoId
+ * does not have a parameter list.
+ */
+DEX_INLINE const DexTypeList* dexGetProtoParameters(
+    const DexFile *pDexFile, const DexProtoId* pProtoId) {
+    if (pProtoId->parametersOff == 0) {
+        return NULL;
+    }
+    return (const DexTypeList*)
+        (pDexFile->baseAddr + pProtoId->parametersOff);
+}
+
+/* return the ClassDef with the specified index */
+DEX_INLINE const DexClassDef* dexGetClassDef(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->classDefsSize);
+    return &pDexFile->pClassDefs[idx];
+}
+
+/* given a ClassDef pointer, recover its index */
+DEX_INLINE u4 dexGetIndexForClassDef(const DexFile* pDexFile,
+    const DexClassDef* pClassDef)
+{
+    assert(pClassDef >= pDexFile->pClassDefs &&
+           pClassDef < pDexFile->pClassDefs + pDexFile->pHeader->classDefsSize);
+    return pClassDef - pDexFile->pClassDefs;
+}
+
+/* get the interface list for a DexClass */
+DEX_INLINE const DexTypeList* dexGetInterfacesList(const DexFile* pDexFile,
+    const DexClassDef* pClassDef)
+{
+    if (pClassDef->interfacesOff == 0)
+        return NULL;
+    return (const DexTypeList*)
+        (pDexFile->baseAddr + pClassDef->interfacesOff);
+}
+/* return the Nth entry in a DexTypeList. */
+DEX_INLINE const DexTypeItem* dexGetTypeItem(const DexTypeList* pList,
+    u4 idx)
+{
+    assert(idx < pList->size);
+    return &pList->list[idx];
+}
+/* return the type_idx for the Nth entry in a TypeList */
+DEX_INLINE u4 dexTypeListGetIdx(const DexTypeList* pList, u4 idx) {
+    const DexTypeItem* pItem = dexGetTypeItem(pList, idx);
+    return pItem->typeIdx;
+}
+
+/* get the static values list for a DexClass */
+DEX_INLINE const DexEncodedArray* dexGetStaticValuesList(
+    const DexFile* pDexFile, const DexClassDef* pClassDef)
+{
+    if (pClassDef->staticValuesOff == 0)
+        return NULL;
+    return (const DexEncodedArray*)
+        (pDexFile->baseAddr + pClassDef->staticValuesOff);
+}
+
+/* get the annotations directory item for a DexClass */
+DEX_INLINE const DexAnnotationsDirectoryItem* dexGetAnnotationsDirectoryItem(
+    const DexFile* pDexFile, const DexClassDef* pClassDef)
+{
+    if (pClassDef->annotationsOff == 0)
+        return NULL;
+    return (const DexAnnotationsDirectoryItem*)
+        (pDexFile->baseAddr + pClassDef->annotationsOff);
+}
+
+/* get the source file string */
+DEX_INLINE const char* dexGetSourceFile(
+    const DexFile* pDexFile, const DexClassDef* pClassDef)
+{
+    if (pClassDef->sourceFileIdx == 0xffffffff)
+        return NULL;
+    return dexStringById(pDexFile, pClassDef->sourceFileIdx);
+}
+
+/* get the size, in bytes, of a DexCode */
+size_t dexGetDexCodeSize(const DexCode* pCode);
+
+/* Get the list of "tries" for the given DexCode. */
+DEX_INLINE const DexTry* dexGetTries(const DexCode* pCode) {
+    const u2* insnsEnd = &pCode->insns[pCode->insnsSize];
+
+    // Round to four bytes.
+    if ((((uintptr_t) insnsEnd) & 3) != 0) {
+        insnsEnd++;
+    }
+
+    return (const DexTry*) insnsEnd;
+}
+
+/* Get the base of the encoded data for the given DexCode. */
+DEX_INLINE const u1* dexGetCatchHandlerData(const DexCode* pCode) {
+    const DexTry* pTries = dexGetTries(pCode);
+    return (const u1*) &pTries[pCode->triesSize];
+}
+
+/* get a pointer to the start of the debugging data */
+DEX_INLINE const u1* dexGetDebugInfoStream(const DexFile* pDexFile,
+    const DexCode* pCode)
+{
+    if (pCode->debugInfoOff == 0) {
+        return NULL;
+    } else {
+        return pDexFile->baseAddr + pCode->debugInfoOff;
+    }
+}
+
+/* DexClassDef convenience - get class descriptor */
+DEX_INLINE const char* dexGetClassDescriptor(const DexFile* pDexFile,
+    const DexClassDef* pClassDef)
+{
+    return dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+}
+
+/* DexClassDef convenience - get superclass descriptor */
+DEX_INLINE const char* dexGetSuperClassDescriptor(const DexFile* pDexFile,
+    const DexClassDef* pClassDef)
+{
+    if (pClassDef->superclassIdx == 0)
+        return NULL;
+    return dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
+}
+
+/* DexClassDef convenience - get class_data_item pointer */
+DEX_INLINE const u1* dexGetClassData(const DexFile* pDexFile,
+    const DexClassDef* pClassDef)
+{
+    if (pClassDef->classDataOff == 0)
+        return NULL;
+    return (const u1*) (pDexFile->baseAddr + pClassDef->classDataOff);
+}
+
+/* Get an annotation set at a particular offset. */
+DEX_INLINE const DexAnnotationSetItem* dexGetAnnotationSetItem(
+    const DexFile* pDexFile, u4 offset)
+{
+    if (offset == 0) {
+        return NULL;
+    }
+    return (const DexAnnotationSetItem*) (pDexFile->baseAddr + offset);
+}
+/* get the class' annotation set */
+DEX_INLINE const DexAnnotationSetItem* dexGetClassAnnotationSet(
+    const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    return dexGetAnnotationSetItem(pDexFile, pAnnoDir->classAnnotationsOff);
+}
+
+/* get the class' field annotation list */
+DEX_INLINE const DexFieldAnnotationsItem* dexGetFieldAnnotations(
+    const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    (void) pDexFile;
+    if (pAnnoDir->fieldsSize == 0)
+        return NULL;
+
+    // Skip past the header to the start of the field annotations.
+    return (const DexFieldAnnotationsItem*) &pAnnoDir[1];
+}
+
+/* get field annotation list size */
+DEX_INLINE int dexGetFieldAnnotationsSize(const DexFile* pDexFile,
+    const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    (void) pDexFile;
+    return pAnnoDir->fieldsSize;
+}
+
+/* return a pointer to the field's annotation set */
+DEX_INLINE const DexAnnotationSetItem* dexGetFieldAnnotationSetItem(
+    const DexFile* pDexFile, const DexFieldAnnotationsItem* pItem)
+{
+    return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff);
+}
+
+/* get the class' method annotation list */
+DEX_INLINE const DexMethodAnnotationsItem* dexGetMethodAnnotations(
+    const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    (void) pDexFile;
+    if (pAnnoDir->methodsSize == 0)
+        return NULL;
+
+    /*
+     * Skip past the header and field annotations to the start of the
+     * method annotations.
+     */
+    const u1* addr = (const u1*) &pAnnoDir[1];
+    addr += pAnnoDir->fieldsSize * sizeof (DexFieldAnnotationsItem);
+    return (const DexMethodAnnotationsItem*) addr;
+}
+
+/* get method annotation list size */
+DEX_INLINE int dexGetMethodAnnotationsSize(const DexFile* pDexFile,
+    const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    (void) pDexFile;
+    return pAnnoDir->methodsSize;
+}
+
+/* return a pointer to the method's annotation set */
+DEX_INLINE const DexAnnotationSetItem* dexGetMethodAnnotationSetItem(
+    const DexFile* pDexFile, const DexMethodAnnotationsItem* pItem)
+{
+    return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff);
+}
+
+/* get the class' parameter annotation list */
+DEX_INLINE const DexParameterAnnotationsItem* dexGetParameterAnnotations(
+    const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    (void) pDexFile;
+    if (pAnnoDir->parametersSize == 0)
+        return NULL;
+
+    /*
+     * Skip past the header, field annotations, and method annotations
+     * to the start of the parameter annotations.
+     */
+    const u1* addr = (const u1*) &pAnnoDir[1];
+    addr += pAnnoDir->fieldsSize * sizeof (DexFieldAnnotationsItem);
+    addr += pAnnoDir->methodsSize * sizeof (DexMethodAnnotationsItem);
+    return (const DexParameterAnnotationsItem*) addr;
+}
+
+/* get method annotation list size */
+DEX_INLINE int dexGetParameterAnnotationsSize(const DexFile* pDexFile,
+    const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    (void) pDexFile;
+    return pAnnoDir->parametersSize;
+}
+
+/* return the parameter annotation ref list */
+DEX_INLINE const DexAnnotationSetRefList* dexGetParameterAnnotationSetRefList(
+    const DexFile* pDexFile, const DexParameterAnnotationsItem* pItem)
+{
+    if (pItem->annotationsOff == 0) {
+        return NULL;
+    }
+    return (const DexAnnotationSetRefList*) (pDexFile->baseAddr + pItem->annotationsOff);
+}
+
+/* get method annotation list size */
+DEX_INLINE int dexGetParameterAnnotationSetRefSize(const DexFile* pDexFile,
+    const DexParameterAnnotationsItem* pItem)
+{
+    if (pItem->annotationsOff == 0) {
+        return 0;
+    }
+    return dexGetParameterAnnotationSetRefList(pDexFile, pItem)->size;
+}
+
+/* return the Nth entry from an annotation set ref list */
+DEX_INLINE const DexAnnotationSetRefItem* dexGetParameterAnnotationSetRef(
+    const DexAnnotationSetRefList* pList, u4 idx)
+{
+    assert(idx < pList->size);
+    return &pList->list[idx];
+}
+
+/* given a DexAnnotationSetRefItem, return the DexAnnotationSetItem */
+DEX_INLINE const DexAnnotationSetItem* dexGetSetRefItemItem(
+    const DexFile* pDexFile, const DexAnnotationSetRefItem* pItem)
+{
+    return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff);
+}
+
+/* return the Nth annotation offset from a DexAnnotationSetItem */
+DEX_INLINE u4 dexGetAnnotationOff(
+    const DexAnnotationSetItem* pAnnoSet, u4 idx)
+{
+    assert(idx < pAnnoSet->size);
+    return pAnnoSet->entries[idx];
+}
+
+/* return the Nth annotation item from a DexAnnotationSetItem */
+DEX_INLINE const DexAnnotationItem* dexGetAnnotationItem(
+    const DexFile* pDexFile, const DexAnnotationSetItem* pAnnoSet, u4 idx)
+{
+    u4 offset = dexGetAnnotationOff(pAnnoSet, idx);
+    if (offset == 0) {
+        return NULL;
+    }
+    return (const DexAnnotationItem*) (pDexFile->baseAddr + offset);
+}
+
+/*
+ * Get the type descriptor character associated with a given primitive
+ * type. This returns '\0' if the type is invalid.
+ */
+char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type);
+
+/*
+ * Get the type descriptor string associated with a given primitive
+ * type.
+ */
+const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type);
+
+/*
+ * Get the boxed type descriptor string associated with a given
+ * primitive type. This returns NULL for an invalid type, including
+ * particularly for type "void". In the latter case, even though there
+ * is a class Void, there's no such thing as a boxed instance of it.
+ */
+const char* dexGetBoxedTypeDescriptor(PrimitiveType type);
+
+/*
+ * Get the primitive type constant from the given descriptor character.
+ * This returns PRIM_NOT (note: this is a 0) if the character is invalid
+ * as a primitive type descriptor.
+ */
+PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar);
+
+#endif  // LIBDEX_DEXFILE_H_
diff --git a/libdex/DexInlines.cpp b/libdex/DexInlines.cpp
new file mode 100644
index 0000000..cbedb62
--- /dev/null
+++ b/libdex/DexInlines.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Generate non-inline copies of inline functions in header files.
+ */
+
+#define _DEX_GEN_INLINES
+
+#include "DexFile.h"
+
+#include "DexCatch.h"
+#include "DexClass.h"
+#include "DexDataMap.h"
+#include "DexUtf.h"
+#include "DexOpcodes.h"
+#include "DexProto.h"
+#include "InstrUtils.h"
+#include "Leb128.h"
+#include "ZipArchive.h"
diff --git a/libdex/DexOpcodes.cpp b/libdex/DexOpcodes.cpp
new file mode 100644
index 0000000..bdcc558
--- /dev/null
+++ b/libdex/DexOpcodes.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Table of Dalvik opcode names.
+ *
+ * IMPORTANT NOTE: The contents of this file are mostly generated
+ * automatically by the opcode-gen tool. Any edits to the generated
+ * sections will get wiped out the next time the tool is run.
+ */
+
+#include "DexOpcodes.h"
+#include <assert.h>
+
+/*
+ * Dalvik opcode names.
+ */
+static const char* gOpNames[kNumPackedOpcodes] = {
+    // BEGIN(libdex-opcode-names); GENERATED AUTOMATICALLY BY opcode-gen
+    "nop",
+    "move",
+    "move/from16",
+    "move/16",
+    "move-wide",
+    "move-wide/from16",
+    "move-wide/16",
+    "move-object",
+    "move-object/from16",
+    "move-object/16",
+    "move-result",
+    "move-result-wide",
+    "move-result-object",
+    "move-exception",
+    "return-void",
+    "return",
+    "return-wide",
+    "return-object",
+    "const/4",
+    "const/16",
+    "const",
+    "const/high16",
+    "const-wide/16",
+    "const-wide/32",
+    "const-wide",
+    "const-wide/high16",
+    "const-string",
+    "const-string/jumbo",
+    "const-class",
+    "monitor-enter",
+    "monitor-exit",
+    "check-cast",
+    "instance-of",
+    "array-length",
+    "new-instance",
+    "new-array",
+    "filled-new-array",
+    "filled-new-array/range",
+    "fill-array-data",
+    "throw",
+    "goto",
+    "goto/16",
+    "goto/32",
+    "packed-switch",
+    "sparse-switch",
+    "cmpl-float",
+    "cmpg-float",
+    "cmpl-double",
+    "cmpg-double",
+    "cmp-long",
+    "if-eq",
+    "if-ne",
+    "if-lt",
+    "if-ge",
+    "if-gt",
+    "if-le",
+    "if-eqz",
+    "if-nez",
+    "if-ltz",
+    "if-gez",
+    "if-gtz",
+    "if-lez",
+    "unused-3e",
+    "unused-3f",
+    "unused-40",
+    "unused-41",
+    "unused-42",
+    "unused-43",
+    "aget",
+    "aget-wide",
+    "aget-object",
+    "aget-boolean",
+    "aget-byte",
+    "aget-char",
+    "aget-short",
+    "aput",
+    "aput-wide",
+    "aput-object",
+    "aput-boolean",
+    "aput-byte",
+    "aput-char",
+    "aput-short",
+    "iget",
+    "iget-wide",
+    "iget-object",
+    "iget-boolean",
+    "iget-byte",
+    "iget-char",
+    "iget-short",
+    "iput",
+    "iput-wide",
+    "iput-object",
+    "iput-boolean",
+    "iput-byte",
+    "iput-char",
+    "iput-short",
+    "sget",
+    "sget-wide",
+    "sget-object",
+    "sget-boolean",
+    "sget-byte",
+    "sget-char",
+    "sget-short",
+    "sput",
+    "sput-wide",
+    "sput-object",
+    "sput-boolean",
+    "sput-byte",
+    "sput-char",
+    "sput-short",
+    "invoke-virtual",
+    "invoke-super",
+    "invoke-direct",
+    "invoke-static",
+    "invoke-interface",
+    "unused-73",
+    "invoke-virtual/range",
+    "invoke-super/range",
+    "invoke-direct/range",
+    "invoke-static/range",
+    "invoke-interface/range",
+    "unused-79",
+    "unused-7a",
+    "neg-int",
+    "not-int",
+    "neg-long",
+    "not-long",
+    "neg-float",
+    "neg-double",
+    "int-to-long",
+    "int-to-float",
+    "int-to-double",
+    "long-to-int",
+    "long-to-float",
+    "long-to-double",
+    "float-to-int",
+    "float-to-long",
+    "float-to-double",
+    "double-to-int",
+    "double-to-long",
+    "double-to-float",
+    "int-to-byte",
+    "int-to-char",
+    "int-to-short",
+    "add-int",
+    "sub-int",
+    "mul-int",
+    "div-int",
+    "rem-int",
+    "and-int",
+    "or-int",
+    "xor-int",
+    "shl-int",
+    "shr-int",
+    "ushr-int",
+    "add-long",
+    "sub-long",
+    "mul-long",
+    "div-long",
+    "rem-long",
+    "and-long",
+    "or-long",
+    "xor-long",
+    "shl-long",
+    "shr-long",
+    "ushr-long",
+    "add-float",
+    "sub-float",
+    "mul-float",
+    "div-float",
+    "rem-float",
+    "add-double",
+    "sub-double",
+    "mul-double",
+    "div-double",
+    "rem-double",
+    "add-int/2addr",
+    "sub-int/2addr",
+    "mul-int/2addr",
+    "div-int/2addr",
+    "rem-int/2addr",
+    "and-int/2addr",
+    "or-int/2addr",
+    "xor-int/2addr",
+    "shl-int/2addr",
+    "shr-int/2addr",
+    "ushr-int/2addr",
+    "add-long/2addr",
+    "sub-long/2addr",
+    "mul-long/2addr",
+    "div-long/2addr",
+    "rem-long/2addr",
+    "and-long/2addr",
+    "or-long/2addr",
+    "xor-long/2addr",
+    "shl-long/2addr",
+    "shr-long/2addr",
+    "ushr-long/2addr",
+    "add-float/2addr",
+    "sub-float/2addr",
+    "mul-float/2addr",
+    "div-float/2addr",
+    "rem-float/2addr",
+    "add-double/2addr",
+    "sub-double/2addr",
+    "mul-double/2addr",
+    "div-double/2addr",
+    "rem-double/2addr",
+    "add-int/lit16",
+    "rsub-int",
+    "mul-int/lit16",
+    "div-int/lit16",
+    "rem-int/lit16",
+    "and-int/lit16",
+    "or-int/lit16",
+    "xor-int/lit16",
+    "add-int/lit8",
+    "rsub-int/lit8",
+    "mul-int/lit8",
+    "div-int/lit8",
+    "rem-int/lit8",
+    "and-int/lit8",
+    "or-int/lit8",
+    "xor-int/lit8",
+    "shl-int/lit8",
+    "shr-int/lit8",
+    "ushr-int/lit8",
+    "+iget-volatile",
+    "+iput-volatile",
+    "+sget-volatile",
+    "+sput-volatile",
+    "+iget-object-volatile",
+    "+iget-wide-volatile",
+    "+iput-wide-volatile",
+    "+sget-wide-volatile",
+    "+sput-wide-volatile",
+    "^breakpoint",
+    "^throw-verification-error",
+    "+execute-inline",
+    "+execute-inline/range",
+    "+invoke-object-init/range",
+    "+return-void-barrier",
+    "+iget-quick",
+    "+iget-wide-quick",
+    "+iget-object-quick",
+    "+iput-quick",
+    "+iput-wide-quick",
+    "+iput-object-quick",
+    "+invoke-virtual-quick",
+    "+invoke-virtual-quick/range",
+    "+invoke-super-quick",
+    "+invoke-super-quick/range",
+    "+iput-object-volatile",
+    "+sget-object-volatile",
+    "+sput-object-volatile",
+    "unused-ff",
+    // END(libdex-opcode-names)
+};
+
+/*
+ * Return the name of an opcode.
+ */
+const char* dexGetOpcodeName(Opcode op)
+{
+    assert(op >= 0 && op < kNumPackedOpcodes);
+    return gOpNames[op];
+}
diff --git a/libdex/DexOpcodes.h b/libdex/DexOpcodes.h
new file mode 100644
index 0000000..8a17841
--- /dev/null
+++ b/libdex/DexOpcodes.h
@@ -0,0 +1,624 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Dalvik opcode information.
+ *
+ * IMPORTANT NOTE: The contents of this file are mostly generated
+ * automatically by the opcode-gen tool. Any edits to the generated
+ * sections will get wiped out the next time the tool is run.
+ *
+ * See the file opcode-gen/README.txt for information about updating
+ * opcodes and instruction formats.
+ */
+
+#ifndef LIBDEX_DEXOPCODES_H_
+#define LIBDEX_DEXOPCODES_H_
+
+#include "DexFile.h"
+
+/*
+ * kMaxOpcodeValue: the highest possible raw (unpacked) opcode value
+ *
+ * kNumPackedOpcodes: the highest possible packed opcode value of a
+ * valid Dalvik opcode, plus one
+ *
+ * TODO: Change this once the rest of the code is prepared to deal with
+ * extended opcodes.
+ */
+// BEGIN(libdex-maximum-values); GENERATED AUTOMATICALLY BY opcode-gen
+#define kMaxOpcodeValue 0xffff
+#define kNumPackedOpcodes 0x100
+// END(libdex-maximum-values); GENERATED AUTOMATICALLY BY opcode-gen
+
+/*
+ * Switch table and array data signatures are a code unit consisting
+ * of "NOP" (0x00) in the low-order byte and a non-zero identifying
+ * code in the high-order byte. (A true NOP is 0x0000.)
+ */
+#define kPackedSwitchSignature  0x0100
+#define kSparseSwitchSignature  0x0200
+#define kArrayDataSignature     0x0300
+
+/*
+ * Enumeration of all Dalvik opcodes, where the enumeration value
+ * associated with each is the corresponding packed opcode number.
+ * This is different than the opcode value from the Dalvik bytecode
+ * spec for opcode values >= 0xff; see dexOpcodeFromCodeUnit() below.
+ *
+ * A note about the "breakpoint" opcode. This instruction is special,
+ * in that it should never be seen by anything but the debug
+ * interpreter. During debugging it takes the place of an arbitrary
+ * opcode, which means operations like "tell me the opcode width so I
+ * can find the next instruction" aren't possible. (This is
+ * correctable, but probably not useful.)
+ */
+enum Opcode {
+    // BEGIN(libdex-opcode-enum); GENERATED AUTOMATICALLY BY opcode-gen
+    OP_NOP                          = 0x00,
+    OP_MOVE                         = 0x01,
+    OP_MOVE_FROM16                  = 0x02,
+    OP_MOVE_16                      = 0x03,
+    OP_MOVE_WIDE                    = 0x04,
+    OP_MOVE_WIDE_FROM16             = 0x05,
+    OP_MOVE_WIDE_16                 = 0x06,
+    OP_MOVE_OBJECT                  = 0x07,
+    OP_MOVE_OBJECT_FROM16           = 0x08,
+    OP_MOVE_OBJECT_16               = 0x09,
+    OP_MOVE_RESULT                  = 0x0a,
+    OP_MOVE_RESULT_WIDE             = 0x0b,
+    OP_MOVE_RESULT_OBJECT           = 0x0c,
+    OP_MOVE_EXCEPTION               = 0x0d,
+    OP_RETURN_VOID                  = 0x0e,
+    OP_RETURN                       = 0x0f,
+    OP_RETURN_WIDE                  = 0x10,
+    OP_RETURN_OBJECT                = 0x11,
+    OP_CONST_4                      = 0x12,
+    OP_CONST_16                     = 0x13,
+    OP_CONST                        = 0x14,
+    OP_CONST_HIGH16                 = 0x15,
+    OP_CONST_WIDE_16                = 0x16,
+    OP_CONST_WIDE_32                = 0x17,
+    OP_CONST_WIDE                   = 0x18,
+    OP_CONST_WIDE_HIGH16            = 0x19,
+    OP_CONST_STRING                 = 0x1a,
+    OP_CONST_STRING_JUMBO           = 0x1b,
+    OP_CONST_CLASS                  = 0x1c,
+    OP_MONITOR_ENTER                = 0x1d,
+    OP_MONITOR_EXIT                 = 0x1e,
+    OP_CHECK_CAST                   = 0x1f,
+    OP_INSTANCE_OF                  = 0x20,
+    OP_ARRAY_LENGTH                 = 0x21,
+    OP_NEW_INSTANCE                 = 0x22,
+    OP_NEW_ARRAY                    = 0x23,
+    OP_FILLED_NEW_ARRAY             = 0x24,
+    OP_FILLED_NEW_ARRAY_RANGE       = 0x25,
+    OP_FILL_ARRAY_DATA              = 0x26,
+    OP_THROW                        = 0x27,
+    OP_GOTO                         = 0x28,
+    OP_GOTO_16                      = 0x29,
+    OP_GOTO_32                      = 0x2a,
+    OP_PACKED_SWITCH                = 0x2b,
+    OP_SPARSE_SWITCH                = 0x2c,
+    OP_CMPL_FLOAT                   = 0x2d,
+    OP_CMPG_FLOAT                   = 0x2e,
+    OP_CMPL_DOUBLE                  = 0x2f,
+    OP_CMPG_DOUBLE                  = 0x30,
+    OP_CMP_LONG                     = 0x31,
+    OP_IF_EQ                        = 0x32,
+    OP_IF_NE                        = 0x33,
+    OP_IF_LT                        = 0x34,
+    OP_IF_GE                        = 0x35,
+    OP_IF_GT                        = 0x36,
+    OP_IF_LE                        = 0x37,
+    OP_IF_EQZ                       = 0x38,
+    OP_IF_NEZ                       = 0x39,
+    OP_IF_LTZ                       = 0x3a,
+    OP_IF_GEZ                       = 0x3b,
+    OP_IF_GTZ                       = 0x3c,
+    OP_IF_LEZ                       = 0x3d,
+    OP_UNUSED_3E                    = 0x3e,
+    OP_UNUSED_3F                    = 0x3f,
+    OP_UNUSED_40                    = 0x40,
+    OP_UNUSED_41                    = 0x41,
+    OP_UNUSED_42                    = 0x42,
+    OP_UNUSED_43                    = 0x43,
+    OP_AGET                         = 0x44,
+    OP_AGET_WIDE                    = 0x45,
+    OP_AGET_OBJECT                  = 0x46,
+    OP_AGET_BOOLEAN                 = 0x47,
+    OP_AGET_BYTE                    = 0x48,
+    OP_AGET_CHAR                    = 0x49,
+    OP_AGET_SHORT                   = 0x4a,
+    OP_APUT                         = 0x4b,
+    OP_APUT_WIDE                    = 0x4c,
+    OP_APUT_OBJECT                  = 0x4d,
+    OP_APUT_BOOLEAN                 = 0x4e,
+    OP_APUT_BYTE                    = 0x4f,
+    OP_APUT_CHAR                    = 0x50,
+    OP_APUT_SHORT                   = 0x51,
+    OP_IGET                         = 0x52,
+    OP_IGET_WIDE                    = 0x53,
+    OP_IGET_OBJECT                  = 0x54,
+    OP_IGET_BOOLEAN                 = 0x55,
+    OP_IGET_BYTE                    = 0x56,
+    OP_IGET_CHAR                    = 0x57,
+    OP_IGET_SHORT                   = 0x58,
+    OP_IPUT                         = 0x59,
+    OP_IPUT_WIDE                    = 0x5a,
+    OP_IPUT_OBJECT                  = 0x5b,
+    OP_IPUT_BOOLEAN                 = 0x5c,
+    OP_IPUT_BYTE                    = 0x5d,
+    OP_IPUT_CHAR                    = 0x5e,
+    OP_IPUT_SHORT                   = 0x5f,
+    OP_SGET                         = 0x60,
+    OP_SGET_WIDE                    = 0x61,
+    OP_SGET_OBJECT                  = 0x62,
+    OP_SGET_BOOLEAN                 = 0x63,
+    OP_SGET_BYTE                    = 0x64,
+    OP_SGET_CHAR                    = 0x65,
+    OP_SGET_SHORT                   = 0x66,
+    OP_SPUT                         = 0x67,
+    OP_SPUT_WIDE                    = 0x68,
+    OP_SPUT_OBJECT                  = 0x69,
+    OP_SPUT_BOOLEAN                 = 0x6a,
+    OP_SPUT_BYTE                    = 0x6b,
+    OP_SPUT_CHAR                    = 0x6c,
+    OP_SPUT_SHORT                   = 0x6d,
+    OP_INVOKE_VIRTUAL               = 0x6e,
+    OP_INVOKE_SUPER                 = 0x6f,
+    OP_INVOKE_DIRECT                = 0x70,
+    OP_INVOKE_STATIC                = 0x71,
+    OP_INVOKE_INTERFACE             = 0x72,
+    OP_UNUSED_73                    = 0x73,
+    OP_INVOKE_VIRTUAL_RANGE         = 0x74,
+    OP_INVOKE_SUPER_RANGE           = 0x75,
+    OP_INVOKE_DIRECT_RANGE          = 0x76,
+    OP_INVOKE_STATIC_RANGE          = 0x77,
+    OP_INVOKE_INTERFACE_RANGE       = 0x78,
+    OP_UNUSED_79                    = 0x79,
+    OP_UNUSED_7A                    = 0x7a,
+    OP_NEG_INT                      = 0x7b,
+    OP_NOT_INT                      = 0x7c,
+    OP_NEG_LONG                     = 0x7d,
+    OP_NOT_LONG                     = 0x7e,
+    OP_NEG_FLOAT                    = 0x7f,
+    OP_NEG_DOUBLE                   = 0x80,
+    OP_INT_TO_LONG                  = 0x81,
+    OP_INT_TO_FLOAT                 = 0x82,
+    OP_INT_TO_DOUBLE                = 0x83,
+    OP_LONG_TO_INT                  = 0x84,
+    OP_LONG_TO_FLOAT                = 0x85,
+    OP_LONG_TO_DOUBLE               = 0x86,
+    OP_FLOAT_TO_INT                 = 0x87,
+    OP_FLOAT_TO_LONG                = 0x88,
+    OP_FLOAT_TO_DOUBLE              = 0x89,
+    OP_DOUBLE_TO_INT                = 0x8a,
+    OP_DOUBLE_TO_LONG               = 0x8b,
+    OP_DOUBLE_TO_FLOAT              = 0x8c,
+    OP_INT_TO_BYTE                  = 0x8d,
+    OP_INT_TO_CHAR                  = 0x8e,
+    OP_INT_TO_SHORT                 = 0x8f,
+    OP_ADD_INT                      = 0x90,
+    OP_SUB_INT                      = 0x91,
+    OP_MUL_INT                      = 0x92,
+    OP_DIV_INT                      = 0x93,
+    OP_REM_INT                      = 0x94,
+    OP_AND_INT                      = 0x95,
+    OP_OR_INT                       = 0x96,
+    OP_XOR_INT                      = 0x97,
+    OP_SHL_INT                      = 0x98,
+    OP_SHR_INT                      = 0x99,
+    OP_USHR_INT                     = 0x9a,
+    OP_ADD_LONG                     = 0x9b,
+    OP_SUB_LONG                     = 0x9c,
+    OP_MUL_LONG                     = 0x9d,
+    OP_DIV_LONG                     = 0x9e,
+    OP_REM_LONG                     = 0x9f,
+    OP_AND_LONG                     = 0xa0,
+    OP_OR_LONG                      = 0xa1,
+    OP_XOR_LONG                     = 0xa2,
+    OP_SHL_LONG                     = 0xa3,
+    OP_SHR_LONG                     = 0xa4,
+    OP_USHR_LONG                    = 0xa5,
+    OP_ADD_FLOAT                    = 0xa6,
+    OP_SUB_FLOAT                    = 0xa7,
+    OP_MUL_FLOAT                    = 0xa8,
+    OP_DIV_FLOAT                    = 0xa9,
+    OP_REM_FLOAT                    = 0xaa,
+    OP_ADD_DOUBLE                   = 0xab,
+    OP_SUB_DOUBLE                   = 0xac,
+    OP_MUL_DOUBLE                   = 0xad,
+    OP_DIV_DOUBLE                   = 0xae,
+    OP_REM_DOUBLE                   = 0xaf,
+    OP_ADD_INT_2ADDR                = 0xb0,
+    OP_SUB_INT_2ADDR                = 0xb1,
+    OP_MUL_INT_2ADDR                = 0xb2,
+    OP_DIV_INT_2ADDR                = 0xb3,
+    OP_REM_INT_2ADDR                = 0xb4,
+    OP_AND_INT_2ADDR                = 0xb5,
+    OP_OR_INT_2ADDR                 = 0xb6,
+    OP_XOR_INT_2ADDR                = 0xb7,
+    OP_SHL_INT_2ADDR                = 0xb8,
+    OP_SHR_INT_2ADDR                = 0xb9,
+    OP_USHR_INT_2ADDR               = 0xba,
+    OP_ADD_LONG_2ADDR               = 0xbb,
+    OP_SUB_LONG_2ADDR               = 0xbc,
+    OP_MUL_LONG_2ADDR               = 0xbd,
+    OP_DIV_LONG_2ADDR               = 0xbe,
+    OP_REM_LONG_2ADDR               = 0xbf,
+    OP_AND_LONG_2ADDR               = 0xc0,
+    OP_OR_LONG_2ADDR                = 0xc1,
+    OP_XOR_LONG_2ADDR               = 0xc2,
+    OP_SHL_LONG_2ADDR               = 0xc3,
+    OP_SHR_LONG_2ADDR               = 0xc4,
+    OP_USHR_LONG_2ADDR              = 0xc5,
+    OP_ADD_FLOAT_2ADDR              = 0xc6,
+    OP_SUB_FLOAT_2ADDR              = 0xc7,
+    OP_MUL_FLOAT_2ADDR              = 0xc8,
+    OP_DIV_FLOAT_2ADDR              = 0xc9,
+    OP_REM_FLOAT_2ADDR              = 0xca,
+    OP_ADD_DOUBLE_2ADDR             = 0xcb,
+    OP_SUB_DOUBLE_2ADDR             = 0xcc,
+    OP_MUL_DOUBLE_2ADDR             = 0xcd,
+    OP_DIV_DOUBLE_2ADDR             = 0xce,
+    OP_REM_DOUBLE_2ADDR             = 0xcf,
+    OP_ADD_INT_LIT16                = 0xd0,
+    OP_RSUB_INT                     = 0xd1,
+    OP_MUL_INT_LIT16                = 0xd2,
+    OP_DIV_INT_LIT16                = 0xd3,
+    OP_REM_INT_LIT16                = 0xd4,
+    OP_AND_INT_LIT16                = 0xd5,
+    OP_OR_INT_LIT16                 = 0xd6,
+    OP_XOR_INT_LIT16                = 0xd7,
+    OP_ADD_INT_LIT8                 = 0xd8,
+    OP_RSUB_INT_LIT8                = 0xd9,
+    OP_MUL_INT_LIT8                 = 0xda,
+    OP_DIV_INT_LIT8                 = 0xdb,
+    OP_REM_INT_LIT8                 = 0xdc,
+    OP_AND_INT_LIT8                 = 0xdd,
+    OP_OR_INT_LIT8                  = 0xde,
+    OP_XOR_INT_LIT8                 = 0xdf,
+    OP_SHL_INT_LIT8                 = 0xe0,
+    OP_SHR_INT_LIT8                 = 0xe1,
+    OP_USHR_INT_LIT8                = 0xe2,
+    OP_IGET_VOLATILE                = 0xe3,
+    OP_IPUT_VOLATILE                = 0xe4,
+    OP_SGET_VOLATILE                = 0xe5,
+    OP_SPUT_VOLATILE                = 0xe6,
+    OP_IGET_OBJECT_VOLATILE         = 0xe7,
+    OP_IGET_WIDE_VOLATILE           = 0xe8,
+    OP_IPUT_WIDE_VOLATILE           = 0xe9,
+    OP_SGET_WIDE_VOLATILE           = 0xea,
+    OP_SPUT_WIDE_VOLATILE           = 0xeb,
+    OP_BREAKPOINT                   = 0xec,
+    OP_THROW_VERIFICATION_ERROR     = 0xed,
+    OP_EXECUTE_INLINE               = 0xee,
+    OP_EXECUTE_INLINE_RANGE         = 0xef,
+    OP_INVOKE_OBJECT_INIT_RANGE     = 0xf0,
+    OP_RETURN_VOID_BARRIER          = 0xf1,
+    OP_IGET_QUICK                   = 0xf2,
+    OP_IGET_WIDE_QUICK              = 0xf3,
+    OP_IGET_OBJECT_QUICK            = 0xf4,
+    OP_IPUT_QUICK                   = 0xf5,
+    OP_IPUT_WIDE_QUICK              = 0xf6,
+    OP_IPUT_OBJECT_QUICK            = 0xf7,
+    OP_INVOKE_VIRTUAL_QUICK         = 0xf8,
+    OP_INVOKE_VIRTUAL_QUICK_RANGE   = 0xf9,
+    OP_INVOKE_SUPER_QUICK           = 0xfa,
+    OP_INVOKE_SUPER_QUICK_RANGE     = 0xfb,
+    OP_IPUT_OBJECT_VOLATILE         = 0xfc,
+    OP_SGET_OBJECT_VOLATILE         = 0xfd,
+    OP_SPUT_OBJECT_VOLATILE         = 0xfe,
+    OP_UNUSED_FF                    = 0xff,
+    // END(libdex-opcode-enum)
+};
+
+/*
+ * Macro used to generate a computed goto table for use in implementing
+ * an interpreter in C.
+ */
+#define DEFINE_GOTO_TABLE(_name) \
+    static const void* _name[kNumPackedOpcodes] = {                      \
+        /* BEGIN(libdex-goto-table); GENERATED AUTOMATICALLY BY opcode-gen */ \
+        H(OP_NOP),                                                            \
+        H(OP_MOVE),                                                           \
+        H(OP_MOVE_FROM16),                                                    \
+        H(OP_MOVE_16),                                                        \
+        H(OP_MOVE_WIDE),                                                      \
+        H(OP_MOVE_WIDE_FROM16),                                               \
+        H(OP_MOVE_WIDE_16),                                                   \
+        H(OP_MOVE_OBJECT),                                                    \
+        H(OP_MOVE_OBJECT_FROM16),                                             \
+        H(OP_MOVE_OBJECT_16),                                                 \
+        H(OP_MOVE_RESULT),                                                    \
+        H(OP_MOVE_RESULT_WIDE),                                               \
+        H(OP_MOVE_RESULT_OBJECT),                                             \
+        H(OP_MOVE_EXCEPTION),                                                 \
+        H(OP_RETURN_VOID),                                                    \
+        H(OP_RETURN),                                                         \
+        H(OP_RETURN_WIDE),                                                    \
+        H(OP_RETURN_OBJECT),                                                  \
+        H(OP_CONST_4),                                                        \
+        H(OP_CONST_16),                                                       \
+        H(OP_CONST),                                                          \
+        H(OP_CONST_HIGH16),                                                   \
+        H(OP_CONST_WIDE_16),                                                  \
+        H(OP_CONST_WIDE_32),                                                  \
+        H(OP_CONST_WIDE),                                                     \
+        H(OP_CONST_WIDE_HIGH16),                                              \
+        H(OP_CONST_STRING),                                                   \
+        H(OP_CONST_STRING_JUMBO),                                             \
+        H(OP_CONST_CLASS),                                                    \
+        H(OP_MONITOR_ENTER),                                                  \
+        H(OP_MONITOR_EXIT),                                                   \
+        H(OP_CHECK_CAST),                                                     \
+        H(OP_INSTANCE_OF),                                                    \
+        H(OP_ARRAY_LENGTH),                                                   \
+        H(OP_NEW_INSTANCE),                                                   \
+        H(OP_NEW_ARRAY),                                                      \
+        H(OP_FILLED_NEW_ARRAY),                                               \
+        H(OP_FILLED_NEW_ARRAY_RANGE),                                         \
+        H(OP_FILL_ARRAY_DATA),                                                \
+        H(OP_THROW),                                                          \
+        H(OP_GOTO),                                                           \
+        H(OP_GOTO_16),                                                        \
+        H(OP_GOTO_32),                                                        \
+        H(OP_PACKED_SWITCH),                                                  \
+        H(OP_SPARSE_SWITCH),                                                  \
+        H(OP_CMPL_FLOAT),                                                     \
+        H(OP_CMPG_FLOAT),                                                     \
+        H(OP_CMPL_DOUBLE),                                                    \
+        H(OP_CMPG_DOUBLE),                                                    \
+        H(OP_CMP_LONG),                                                       \
+        H(OP_IF_EQ),                                                          \
+        H(OP_IF_NE),                                                          \
+        H(OP_IF_LT),                                                          \
+        H(OP_IF_GE),                                                          \
+        H(OP_IF_GT),                                                          \
+        H(OP_IF_LE),                                                          \
+        H(OP_IF_EQZ),                                                         \
+        H(OP_IF_NEZ),                                                         \
+        H(OP_IF_LTZ),                                                         \
+        H(OP_IF_GEZ),                                                         \
+        H(OP_IF_GTZ),                                                         \
+        H(OP_IF_LEZ),                                                         \
+        H(OP_UNUSED_3E),                                                      \
+        H(OP_UNUSED_3F),                                                      \
+        H(OP_UNUSED_40),                                                      \
+        H(OP_UNUSED_41),                                                      \
+        H(OP_UNUSED_42),                                                      \
+        H(OP_UNUSED_43),                                                      \
+        H(OP_AGET),                                                           \
+        H(OP_AGET_WIDE),                                                      \
+        H(OP_AGET_OBJECT),                                                    \
+        H(OP_AGET_BOOLEAN),                                                   \
+        H(OP_AGET_BYTE),                                                      \
+        H(OP_AGET_CHAR),                                                      \
+        H(OP_AGET_SHORT),                                                     \
+        H(OP_APUT),                                                           \
+        H(OP_APUT_WIDE),                                                      \
+        H(OP_APUT_OBJECT),                                                    \
+        H(OP_APUT_BOOLEAN),                                                   \
+        H(OP_APUT_BYTE),                                                      \
+        H(OP_APUT_CHAR),                                                      \
+        H(OP_APUT_SHORT),                                                     \
+        H(OP_IGET),                                                           \
+        H(OP_IGET_WIDE),                                                      \
+        H(OP_IGET_OBJECT),                                                    \
+        H(OP_IGET_BOOLEAN),                                                   \
+        H(OP_IGET_BYTE),                                                      \
+        H(OP_IGET_CHAR),                                                      \
+        H(OP_IGET_SHORT),                                                     \
+        H(OP_IPUT),                                                           \
+        H(OP_IPUT_WIDE),                                                      \
+        H(OP_IPUT_OBJECT),                                                    \
+        H(OP_IPUT_BOOLEAN),                                                   \
+        H(OP_IPUT_BYTE),                                                      \
+        H(OP_IPUT_CHAR),                                                      \
+        H(OP_IPUT_SHORT),                                                     \
+        H(OP_SGET),                                                           \
+        H(OP_SGET_WIDE),                                                      \
+        H(OP_SGET_OBJECT),                                                    \
+        H(OP_SGET_BOOLEAN),                                                   \
+        H(OP_SGET_BYTE),                                                      \
+        H(OP_SGET_CHAR),                                                      \
+        H(OP_SGET_SHORT),                                                     \
+        H(OP_SPUT),                                                           \
+        H(OP_SPUT_WIDE),                                                      \
+        H(OP_SPUT_OBJECT),                                                    \
+        H(OP_SPUT_BOOLEAN),                                                   \
+        H(OP_SPUT_BYTE),                                                      \
+        H(OP_SPUT_CHAR),                                                      \
+        H(OP_SPUT_SHORT),                                                     \
+        H(OP_INVOKE_VIRTUAL),                                                 \
+        H(OP_INVOKE_SUPER),                                                   \
+        H(OP_INVOKE_DIRECT),                                                  \
+        H(OP_INVOKE_STATIC),                                                  \
+        H(OP_INVOKE_INTERFACE),                                               \
+        H(OP_UNUSED_73),                                                      \
+        H(OP_INVOKE_VIRTUAL_RANGE),                                           \
+        H(OP_INVOKE_SUPER_RANGE),                                             \
+        H(OP_INVOKE_DIRECT_RANGE),                                            \
+        H(OP_INVOKE_STATIC_RANGE),                                            \
+        H(OP_INVOKE_INTERFACE_RANGE),                                         \
+        H(OP_UNUSED_79),                                                      \
+        H(OP_UNUSED_7A),                                                      \
+        H(OP_NEG_INT),                                                        \
+        H(OP_NOT_INT),                                                        \
+        H(OP_NEG_LONG),                                                       \
+        H(OP_NOT_LONG),                                                       \
+        H(OP_NEG_FLOAT),                                                      \
+        H(OP_NEG_DOUBLE),                                                     \
+        H(OP_INT_TO_LONG),                                                    \
+        H(OP_INT_TO_FLOAT),                                                   \
+        H(OP_INT_TO_DOUBLE),                                                  \
+        H(OP_LONG_TO_INT),                                                    \
+        H(OP_LONG_TO_FLOAT),                                                  \
+        H(OP_LONG_TO_DOUBLE),                                                 \
+        H(OP_FLOAT_TO_INT),                                                   \
+        H(OP_FLOAT_TO_LONG),                                                  \
+        H(OP_FLOAT_TO_DOUBLE),                                                \
+        H(OP_DOUBLE_TO_INT),                                                  \
+        H(OP_DOUBLE_TO_LONG),                                                 \
+        H(OP_DOUBLE_TO_FLOAT),                                                \
+        H(OP_INT_TO_BYTE),                                                    \
+        H(OP_INT_TO_CHAR),                                                    \
+        H(OP_INT_TO_SHORT),                                                   \
+        H(OP_ADD_INT),                                                        \
+        H(OP_SUB_INT),                                                        \
+        H(OP_MUL_INT),                                                        \
+        H(OP_DIV_INT),                                                        \
+        H(OP_REM_INT),                                                        \
+        H(OP_AND_INT),                                                        \
+        H(OP_OR_INT),                                                         \
+        H(OP_XOR_INT),                                                        \
+        H(OP_SHL_INT),                                                        \
+        H(OP_SHR_INT),                                                        \
+        H(OP_USHR_INT),                                                       \
+        H(OP_ADD_LONG),                                                       \
+        H(OP_SUB_LONG),                                                       \
+        H(OP_MUL_LONG),                                                       \
+        H(OP_DIV_LONG),                                                       \
+        H(OP_REM_LONG),                                                       \
+        H(OP_AND_LONG),                                                       \
+        H(OP_OR_LONG),                                                        \
+        H(OP_XOR_LONG),                                                       \
+        H(OP_SHL_LONG),                                                       \
+        H(OP_SHR_LONG),                                                       \
+        H(OP_USHR_LONG),                                                      \
+        H(OP_ADD_FLOAT),                                                      \
+        H(OP_SUB_FLOAT),                                                      \
+        H(OP_MUL_FLOAT),                                                      \
+        H(OP_DIV_FLOAT),                                                      \
+        H(OP_REM_FLOAT),                                                      \
+        H(OP_ADD_DOUBLE),                                                     \
+        H(OP_SUB_DOUBLE),                                                     \
+        H(OP_MUL_DOUBLE),                                                     \
+        H(OP_DIV_DOUBLE),                                                     \
+        H(OP_REM_DOUBLE),                                                     \
+        H(OP_ADD_INT_2ADDR),                                                  \
+        H(OP_SUB_INT_2ADDR),                                                  \
+        H(OP_MUL_INT_2ADDR),                                                  \
+        H(OP_DIV_INT_2ADDR),                                                  \
+        H(OP_REM_INT_2ADDR),                                                  \
+        H(OP_AND_INT_2ADDR),                                                  \
+        H(OP_OR_INT_2ADDR),                                                   \
+        H(OP_XOR_INT_2ADDR),                                                  \
+        H(OP_SHL_INT_2ADDR),                                                  \
+        H(OP_SHR_INT_2ADDR),                                                  \
+        H(OP_USHR_INT_2ADDR),                                                 \
+        H(OP_ADD_LONG_2ADDR),                                                 \
+        H(OP_SUB_LONG_2ADDR),                                                 \
+        H(OP_MUL_LONG_2ADDR),                                                 \
+        H(OP_DIV_LONG_2ADDR),                                                 \
+        H(OP_REM_LONG_2ADDR),                                                 \
+        H(OP_AND_LONG_2ADDR),                                                 \
+        H(OP_OR_LONG_2ADDR),                                                  \
+        H(OP_XOR_LONG_2ADDR),                                                 \
+        H(OP_SHL_LONG_2ADDR),                                                 \
+        H(OP_SHR_LONG_2ADDR),                                                 \
+        H(OP_USHR_LONG_2ADDR),                                                \
+        H(OP_ADD_FLOAT_2ADDR),                                                \
+        H(OP_SUB_FLOAT_2ADDR),                                                \
+        H(OP_MUL_FLOAT_2ADDR),                                                \
+        H(OP_DIV_FLOAT_2ADDR),                                                \
+        H(OP_REM_FLOAT_2ADDR),                                                \
+        H(OP_ADD_DOUBLE_2ADDR),                                               \
+        H(OP_SUB_DOUBLE_2ADDR),                                               \
+        H(OP_MUL_DOUBLE_2ADDR),                                               \
+        H(OP_DIV_DOUBLE_2ADDR),                                               \
+        H(OP_REM_DOUBLE_2ADDR),                                               \
+        H(OP_ADD_INT_LIT16),                                                  \
+        H(OP_RSUB_INT),                                                       \
+        H(OP_MUL_INT_LIT16),                                                  \
+        H(OP_DIV_INT_LIT16),                                                  \
+        H(OP_REM_INT_LIT16),                                                  \
+        H(OP_AND_INT_LIT16),                                                  \
+        H(OP_OR_INT_LIT16),                                                   \
+        H(OP_XOR_INT_LIT16),                                                  \
+        H(OP_ADD_INT_LIT8),                                                   \
+        H(OP_RSUB_INT_LIT8),                                                  \
+        H(OP_MUL_INT_LIT8),                                                   \
+        H(OP_DIV_INT_LIT8),                                                   \
+        H(OP_REM_INT_LIT8),                                                   \
+        H(OP_AND_INT_LIT8),                                                   \
+        H(OP_OR_INT_LIT8),                                                    \
+        H(OP_XOR_INT_LIT8),                                                   \
+        H(OP_SHL_INT_LIT8),                                                   \
+        H(OP_SHR_INT_LIT8),                                                   \
+        H(OP_USHR_INT_LIT8),                                                  \
+        H(OP_IGET_VOLATILE),                                                  \
+        H(OP_IPUT_VOLATILE),                                                  \
+        H(OP_SGET_VOLATILE),                                                  \
+        H(OP_SPUT_VOLATILE),                                                  \
+        H(OP_IGET_OBJECT_VOLATILE),                                           \
+        H(OP_IGET_WIDE_VOLATILE),                                             \
+        H(OP_IPUT_WIDE_VOLATILE),                                             \
+        H(OP_SGET_WIDE_VOLATILE),                                             \
+        H(OP_SPUT_WIDE_VOLATILE),                                             \
+        H(OP_BREAKPOINT),                                                     \
+        H(OP_THROW_VERIFICATION_ERROR),                                       \
+        H(OP_EXECUTE_INLINE),                                                 \
+        H(OP_EXECUTE_INLINE_RANGE),                                           \
+        H(OP_INVOKE_OBJECT_INIT_RANGE),                                       \
+        H(OP_RETURN_VOID_BARRIER),                                            \
+        H(OP_IGET_QUICK),                                                     \
+        H(OP_IGET_WIDE_QUICK),                                                \
+        H(OP_IGET_OBJECT_QUICK),                                              \
+        H(OP_IPUT_QUICK),                                                     \
+        H(OP_IPUT_WIDE_QUICK),                                                \
+        H(OP_IPUT_OBJECT_QUICK),                                              \
+        H(OP_INVOKE_VIRTUAL_QUICK),                                           \
+        H(OP_INVOKE_VIRTUAL_QUICK_RANGE),                                     \
+        H(OP_INVOKE_SUPER_QUICK),                                             \
+        H(OP_INVOKE_SUPER_QUICK_RANGE),                                       \
+        H(OP_IPUT_OBJECT_VOLATILE),                                           \
+        H(OP_SGET_OBJECT_VOLATILE),                                           \
+        H(OP_SPUT_OBJECT_VOLATILE),                                           \
+        H(OP_UNUSED_FF),                                                      \
+        /* END(libdex-goto-table) */                                          \
+    };
+
+/*
+ * Return the Opcode for a given raw opcode code unit (which may
+ * include data payload). The packed index is a zero-based index which
+ * can be used to point into various opcode-related tables. The Dalvik
+ * opcode space is inherently sparse, in that the opcode unit is 16
+ * bits wide, but for most opcodes, eight of those bits are for data.
+ */
+DEX_INLINE Opcode dexOpcodeFromCodeUnit(u2 codeUnit) {
+    /*
+     * This will want to become table-driven should the opcode layout
+     * get more complicated.
+     *
+     * Note: This has to match the corresponding code in opcode-gen, so
+     * that data tables get generated in a consistent way.
+     */
+    int lowByte = codeUnit & 0xff;
+    if (lowByte != 0xff) {
+        return (Opcode) lowByte;
+    } else {
+        return (Opcode) ((codeUnit >> 8) | 0x100);
+    }
+}
+
+/*
+ * Return the name of an opcode.
+ */
+const char* dexGetOpcodeName(Opcode op);
+
+#endif  // LIBDEX_DEXOPCODES_H_
diff --git a/libdex/DexOptData.cpp b/libdex/DexOptData.cpp
new file mode 100644
index 0000000..dd41751
--- /dev/null
+++ b/libdex/DexOptData.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions to parse and manipulate the additional data tables added
+ * to optimized .dex files.
+ */
+
+#include <zlib.h>
+
+#include "DexOptData.h"
+
+/*
+ * Check to see if a given data pointer is a valid double-word-aligned
+ * pointer into the given memory range (from start inclusive to end
+ * exclusive). Returns true if valid.
+ */
+static bool isValidPointer(const void* ptr, const void* start, const void* end)
+{
+    return (ptr >= start) && (ptr < end) && (((uintptr_t) ptr & 7) == 0);
+}
+
+/* (documented in header file) */
+u4 dexComputeOptChecksum(const DexOptHeader* pOptHeader)
+{
+    const u1* start = (const u1*) pOptHeader + pOptHeader->depsOffset;
+    const u1* end = (const u1*) pOptHeader +
+        pOptHeader->optOffset + pOptHeader->optLength;
+
+    uLong adler = adler32(0L, Z_NULL, 0);
+
+    return (u4) adler32(adler, start, end - start);
+}
+
+/* (documented in header file) */
+bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile)
+{
+    const void* pOptStart = data + pDexFile->pOptHeader->optOffset;
+    const void* pOptEnd = data + length;
+    const u4* pOpt = (const u4*) pOptStart;
+    u4 optLength = (const u1*) pOptEnd - (const u1*) pOptStart;
+
+    /*
+     * Make sure the opt data start is in range and aligned. This may
+     * seem like a superfluous check, but (a) if the file got
+     * truncated, it might turn out that pOpt >= pOptEnd; and (b)
+     * if the opt data header got corrupted, pOpt might not be
+     * properly aligned. This test will catch both of these cases.
+     */
+    if (!isValidPointer(pOpt, pOptStart, pOptEnd)) {
+        ALOGE("Bogus opt data start pointer");
+        return false;
+    }
+
+    /* Make sure that the opt data length is a whole number of words. */
+    if ((optLength & 3) != 0) {
+        ALOGE("Unaligned opt data area end");
+        return false;
+    }
+
+    /*
+     * Make sure that the opt data area is large enough to have at least
+     * one chunk header.
+     */
+    if (optLength < 8) {
+        ALOGE("Undersized opt data area (%u)", optLength);
+        return false;
+    }
+
+    /* Process chunks until we see the end marker. */
+    while (*pOpt != kDexChunkEnd) {
+        if (!isValidPointer(pOpt + 2, pOptStart, pOptEnd)) {
+            ALOGE("Bogus opt data content pointer at offset %u",
+                    ((const u1*) pOpt) - data);
+            return false;
+        }
+
+        u4 size = *(pOpt + 1);
+        const u1* pOptData = (const u1*) (pOpt + 2);
+
+        /*
+         * The rounded size is 64-bit aligned and includes +8 for the
+         * type/size header (which was extracted immediately above).
+         */
+        u4 roundedSize = (size + 8 + 7) & ~7;
+        const u4* pNextOpt = pOpt + (roundedSize / sizeof(u4));
+
+        if (!isValidPointer(pNextOpt, pOptStart, pOptEnd)) {
+            ALOGE("Opt data area problem for chunk of size %u at offset %u",
+                    size, ((const u1*) pOpt) - data);
+            return false;
+        }
+
+        switch (*pOpt) {
+        case kDexChunkClassLookup:
+            pDexFile->pClassLookup = (const DexClassLookup*) pOptData;
+            break;
+        case kDexChunkRegisterMaps:
+            ALOGV("+++ found register maps, size=%u", size);
+            pDexFile->pRegisterMapPool = pOptData;
+            break;
+        default:
+            ALOGI("Unknown chunk 0x%08x (%c%c%c%c), size=%d in opt data area",
+                *pOpt,
+                (char) ((*pOpt) >> 24), (char) ((*pOpt) >> 16),
+                (char) ((*pOpt) >> 8),  (char)  (*pOpt),
+                size);
+            break;
+        }
+
+        pOpt = pNextOpt;
+    }
+
+    return true;
+}
diff --git a/libdex/DexOptData.h b/libdex/DexOptData.h
new file mode 100644
index 0000000..69eda01
--- /dev/null
+++ b/libdex/DexOptData.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions to parse and manipulate the additional data tables added
+ * to optimized .dex files.
+ */
+
+#ifndef _LIBDEX_DEXOPTDATA
+#define _LIBDEX_DEXOPTDATA
+
+#include "libdex/DexFile.h"
+
+/*
+ * Parse the optimized data tables in the given dex file.
+ *
+ * @param data pointer to the start of the entire dex file
+ * @param length length of the entire dex file, in bytes
+ * @param pDexFile pointer to the associated dex file structure
+ */
+bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile);
+
+/*
+ * Compute the checksum of the optimized data tables pointed at by the given
+ * header.
+ */
+u4 dexComputeOptChecksum(const DexOptHeader* pOptHeader);
+
+#endif /* def _LIBDEX_DEXOPTDATA */
diff --git a/libdex/DexProto.cpp b/libdex/DexProto.cpp
new file mode 100644
index 0000000..06c59b3
--- /dev/null
+++ b/libdex/DexProto.cpp
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions for dealing with method prototypes
+ */
+
+#include "DexProto.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * ===========================================================================
+ *      String Cache
+ * ===========================================================================
+ */
+
+/*
+ * Make sure that the given cache can hold a string of the given length,
+ * including the final '\0' byte.
+ */
+void dexStringCacheAlloc(DexStringCache* pCache, size_t length) {
+    if (pCache->allocatedSize != 0) {
+        if (pCache->allocatedSize >= length) {
+            return;
+        }
+        free((void*) pCache->value);
+    }
+
+    if (length <= sizeof(pCache->buffer)) {
+        pCache->value = pCache->buffer;
+        pCache->allocatedSize = 0;
+    } else {
+        pCache->value = (char*) malloc(length);
+        pCache->allocatedSize = length;
+    }
+}
+
+/*
+ * Initialize the given DexStringCache. Use this function before passing
+ * one into any other function.
+ */
+void dexStringCacheInit(DexStringCache* pCache) {
+    pCache->value = pCache->buffer;
+    pCache->allocatedSize = 0;
+    pCache->buffer[0] = '\0';
+}
+
+/*
+ * Release the allocated contents of the given DexStringCache, if any.
+ * Use this function after your last use of a DexStringCache.
+ */
+void dexStringCacheRelease(DexStringCache* pCache) {
+    if (pCache->allocatedSize != 0) {
+        free((void*) pCache->value);
+        pCache->value = pCache->buffer;
+        pCache->allocatedSize = 0;
+    }
+}
+
+/*
+ * If the given DexStringCache doesn't already point at the given value,
+ * make a copy of it into the cache. This always returns a writable
+ * pointer to the contents (whether or not a copy had to be made). This
+ * function is intended to be used after making a call that at least
+ * sometimes doesn't populate a DexStringCache.
+ */
+char* dexStringCacheEnsureCopy(DexStringCache* pCache, const char* value) {
+    if (value != pCache->value) {
+        size_t length = strlen(value) + 1;
+        dexStringCacheAlloc(pCache, length);
+        memcpy(pCache->value, value, length);
+    }
+
+    return pCache->value;
+}
+
+/*
+ * Abandon the given DexStringCache, and return a writable copy of the
+ * given value (reusing the string cache's allocation if possible).
+ * The return value must be free()d by the caller. Use this instead of
+ * dexStringCacheRelease() if you want the buffer to survive past the
+ * scope of the DexStringCache.
+ */
+char* dexStringCacheAbandon(DexStringCache* pCache, const char* value) {
+    if ((value == pCache->value) && (pCache->allocatedSize != 0)) {
+        char* result = pCache->value;
+        pCache->allocatedSize = 0;
+        pCache->value = pCache->buffer;
+        return result;
+    } else {
+        return strdup(value);
+    }
+}
+
+
+/*
+ * ===========================================================================
+ *      Method Prototypes
+ * ===========================================================================
+ */
+
+/*
+ * Return the DexProtoId from the given DexProto. The DexProto must
+ * actually refer to a DexProtoId.
+ */
+static inline const DexProtoId* getProtoId(const DexProto* pProto) {
+    return dexGetProtoId(pProto->dexFile, pProto->protoIdx);
+}
+
+/* (documented in header file) */
+const char* dexProtoGetShorty(const DexProto* pProto) {
+    const DexProtoId* protoId = getProtoId(pProto);
+
+    return dexStringById(pProto->dexFile, protoId->shortyIdx);
+}
+
+/* (documented in header file) */
+const char* dexProtoGetMethodDescriptor(const DexProto* pProto,
+        DexStringCache* pCache) {
+    const DexFile* dexFile = pProto->dexFile;
+    const DexProtoId* protoId = getProtoId(pProto);
+    const DexTypeList* typeList = dexGetProtoParameters(dexFile, protoId);
+    size_t length = 3; // parens and terminating '\0'
+    u4 paramCount = (typeList == NULL) ? 0 : typeList->size;
+    u4 i;
+
+    for (i = 0; i < paramCount; i++) {
+        u4 idx = dexTypeListGetIdx(typeList, i);
+        length += strlen(dexStringByTypeIdx(dexFile, idx));
+    }
+
+    length += strlen(dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
+
+    dexStringCacheAlloc(pCache, length);
+
+    char *at = (char*) pCache->value;
+    *(at++) = '(';
+
+    for (i = 0; i < paramCount; i++) {
+        u4 idx = dexTypeListGetIdx(typeList, i);
+        const char* desc = dexStringByTypeIdx(dexFile, idx);
+        strcpy(at, desc);
+        at += strlen(desc);
+    }
+
+    *(at++) = ')';
+
+    strcpy(at, dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
+    return pCache->value;
+}
+
+/* (documented in header file) */
+char* dexProtoCopyMethodDescriptor(const DexProto* pProto) {
+    DexStringCache cache;
+
+    dexStringCacheInit(&cache);
+    return dexStringCacheAbandon(&cache,
+            dexProtoGetMethodDescriptor(pProto, &cache));
+}
+
+/* (documented in header file) */
+const char* dexProtoGetParameterDescriptors(const DexProto* pProto,
+        DexStringCache* pCache) {
+    DexParameterIterator iterator;
+    size_t length = 1; /* +1 for the terminating '\0' */
+
+    dexParameterIteratorInit(&iterator, pProto);
+
+    for (;;) {
+        const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
+        if (descriptor == NULL) {
+            break;
+        }
+
+        length += strlen(descriptor);
+    }
+
+    dexParameterIteratorInit(&iterator, pProto);
+
+    dexStringCacheAlloc(pCache, length);
+    char *at = (char*) pCache->value;
+
+    for (;;) {
+        const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
+        if (descriptor == NULL) {
+            break;
+        }
+
+        strcpy(at, descriptor);
+        at += strlen(descriptor);
+    }
+
+    return pCache->value;
+}
+
+/* (documented in header file) */
+const char* dexProtoGetReturnType(const DexProto* pProto) {
+    const DexProtoId* protoId = getProtoId(pProto);
+    return dexStringByTypeIdx(pProto->dexFile, protoId->returnTypeIdx);
+}
+
+/* (documented in header file) */
+size_t dexProtoGetParameterCount(const DexProto* pProto) {
+    const DexProtoId* protoId = getProtoId(pProto);
+    const DexTypeList* typeList =
+        dexGetProtoParameters(pProto->dexFile, protoId);
+    return (typeList == NULL) ? 0 : typeList->size;
+}
+
+/* (documented in header file) */
+int dexProtoComputeArgsSize(const DexProto* pProto) {
+    const char* shorty = dexProtoGetShorty(pProto);
+    int count = 0;
+
+    /* Skip the return type. */
+    shorty++;
+
+    for (;;) {
+        switch (*(shorty++)) {
+            case '\0': {
+                return count;
+            }
+            case 'D':
+            case 'J': {
+                count += 2;
+                break;
+            }
+            default: {
+                count++;
+                break;
+            }
+        }
+    }
+}
+
+/*
+ * Common implementation for dexProtoCompare() and dexProtoCompareParameters().
+ */
+static int protoCompare(const DexProto* pProto1, const DexProto* pProto2,
+        bool compareReturnType) {
+
+    if (pProto1 == pProto2) {
+        // Easy out.
+        return 0;
+    } else {
+        const DexFile* dexFile1 = pProto1->dexFile;
+        const DexProtoId* protoId1 = getProtoId(pProto1);
+        const DexTypeList* typeList1 =
+            dexGetProtoParameters(dexFile1, protoId1);
+        int paramCount1 = (typeList1 == NULL) ? 0 : typeList1->size;
+
+        const DexFile* dexFile2 = pProto2->dexFile;
+        const DexProtoId* protoId2 = getProtoId(pProto2);
+        const DexTypeList* typeList2 =
+            dexGetProtoParameters(dexFile2, protoId2);
+        int paramCount2 = (typeList2 == NULL) ? 0 : typeList2->size;
+
+        if (protoId1 == protoId2) {
+            // Another easy out.
+            return 0;
+        }
+
+        // Compare return types.
+
+        if (compareReturnType) {
+            int result =
+                strcmp(dexStringByTypeIdx(dexFile1, protoId1->returnTypeIdx),
+                        dexStringByTypeIdx(dexFile2, protoId2->returnTypeIdx));
+
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        // Compare parameters.
+
+        int minParam = (paramCount1 > paramCount2) ? paramCount2 : paramCount1;
+        int i;
+
+        for (i = 0; i < minParam; i++) {
+            u4 idx1 = dexTypeListGetIdx(typeList1, i);
+            u4 idx2 = dexTypeListGetIdx(typeList2, i);
+            int result =
+                strcmp(dexStringByTypeIdx(dexFile1, idx1),
+                        dexStringByTypeIdx(dexFile2, idx2));
+
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        if (paramCount1 < paramCount2) {
+            return -1;
+        } else if (paramCount1 > paramCount2) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+}
+
+/* (documented in header file) */
+int dexProtoCompare(const DexProto* pProto1, const DexProto* pProto2) {
+    return protoCompare(pProto1, pProto2, true);
+}
+
+/* (documented in header file) */
+int dexProtoCompareParameters(const DexProto* pProto1, const DexProto* pProto2){
+    return protoCompare(pProto1, pProto2, false);
+}
+
+
+/*
+ * Helper for dexProtoCompareToDescriptor(), which gets the return type
+ * descriptor from a method descriptor string.
+ */
+static const char* methodDescriptorReturnType(const char* descriptor) {
+    const char* result = strchr(descriptor, ')');
+
+    if (result == NULL) {
+        return NULL;
+    }
+
+    // The return type is the character just past the ')'.
+    return result + 1;
+}
+
+/*
+ * Helper for dexProtoCompareToDescriptor(), which indicates the end
+ * of an embedded argument type descriptor, which is also the
+ * beginning of the next argument type descriptor. Since this is for
+ * argument types, it doesn't accept 'V' as a valid type descriptor.
+ */
+static const char* methodDescriptorNextType(const char* descriptor) {
+    // Skip any array references.
+
+    while (*descriptor == '[') {
+        descriptor++;
+    }
+
+    switch (*descriptor) {
+        case 'B': case 'C': case 'D': case 'F':
+        case 'I': case 'J': case 'S': case 'Z': {
+            return descriptor + 1;
+        }
+        case 'L': {
+            const char* result = strchr(descriptor + 1, ';');
+            if (result != NULL) {
+                // The type ends just past the ';'.
+                return result + 1;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Common implementation for dexProtoCompareToDescriptor() and
+ * dexProtoCompareToParameterDescriptors(). The descriptor argument
+ * can be either a full method descriptor (with parens and a return
+ * type) or an unadorned concatenation of types (e.g. a list of
+ * argument types).
+ */
+static int protoCompareToParameterDescriptors(const DexProto* proto,
+        const char* descriptor, bool expectParens) {
+    char expectedEndChar = expectParens ? ')' : '\0';
+    DexParameterIterator iterator;
+    dexParameterIteratorInit(&iterator, proto);
+
+    if (expectParens) {
+        // Skip the '('.
+        assert (*descriptor == '(');
+        descriptor++;
+    }
+
+    for (;;) {
+        const char* protoDesc = dexParameterIteratorNextDescriptor(&iterator);
+
+        if (*descriptor == expectedEndChar) {
+            // It's the end of the descriptor string.
+            if (protoDesc == NULL) {
+                // It's also the end of the prototype's arguments.
+                return 0;
+            } else {
+                // The prototype still has more arguments.
+                return 1;
+            }
+        }
+
+        if (protoDesc == NULL) {
+            /*
+             * The prototype doesn't have arguments left, but the
+             * descriptor string does.
+             */
+            return -1;
+        }
+
+        // Both prototype and descriptor have arguments. Compare them.
+
+        const char* nextDesc = methodDescriptorNextType(descriptor);
+        assert(nextDesc != NULL);
+
+        for (;;) {
+            char c1 = *(protoDesc++);
+            char c2 = (descriptor < nextDesc) ? *(descriptor++) : '\0';
+
+            if (c1 < c2) {
+                // This includes the case where the proto is shorter.
+                return -1;
+            } else if (c1 > c2) {
+                // This includes the case where the desc is shorter.
+                return 1;
+            } else if (c1 == '\0') {
+                // The two types are equal in length. (c2 necessarily == '\0'.)
+                break;
+            }
+        }
+
+        /*
+         * If we made it here, the two arguments matched, and
+         * descriptor == nextDesc.
+         */
+    }
+}
+
+/* (documented in header file) */
+int dexProtoCompareToDescriptor(const DexProto* proto,
+        const char* descriptor) {
+    // First compare the return types.
+
+    const char *returnType = methodDescriptorReturnType(descriptor);
+    assert(returnType != NULL);
+
+    int result = strcmp(dexProtoGetReturnType(proto), returnType);
+
+    if (result != 0) {
+        return result;
+    }
+
+    // The return types match, so we have to check arguments.
+    return protoCompareToParameterDescriptors(proto, descriptor, true);
+}
+
+/* (documented in header file) */
+int dexProtoCompareToParameterDescriptors(const DexProto* proto,
+        const char* descriptors) {
+    return protoCompareToParameterDescriptors(proto, descriptors, false);
+}
+
+
+
+
+
+
+/*
+ * ===========================================================================
+ *      Parameter Iterators
+ * ===========================================================================
+ */
+
+/*
+ * Initialize the given DexParameterIterator to be at the start of the
+ * parameters of the given prototype.
+ */
+void dexParameterIteratorInit(DexParameterIterator* pIterator,
+        const DexProto* pProto) {
+    pIterator->proto = pProto;
+    pIterator->cursor = 0;
+
+    pIterator->parameters =
+        dexGetProtoParameters(pProto->dexFile, getProtoId(pProto));
+    pIterator->parameterCount = (pIterator->parameters == NULL) ? 0
+        : pIterator->parameters->size;
+}
+
+/*
+ * Get the type_id index for the next parameter, if any. This returns
+ * kDexNoIndex if the last parameter has already been consumed.
+ */
+u4 dexParameterIteratorNextIndex(DexParameterIterator* pIterator) {
+    int cursor = pIterator->cursor;
+    int parameterCount = pIterator->parameterCount;
+
+    if (cursor >= parameterCount) {
+        // The iteration is complete.
+        return kDexNoIndex;
+    } else {
+        u4 idx = dexTypeListGetIdx(pIterator->parameters, cursor);
+        pIterator->cursor++;
+        return idx;
+    }
+}
+
+/*
+ * Get the type descriptor for the next parameter, if any. This returns
+ * NULL if the last parameter has already been consumed.
+ */
+const char* dexParameterIteratorNextDescriptor(
+        DexParameterIterator* pIterator) {
+    u4 idx = dexParameterIteratorNextIndex(pIterator);
+
+    if (idx == kDexNoIndex) {
+        return NULL;
+    }
+
+    return dexStringByTypeIdx(pIterator->proto->dexFile, idx);
+}
diff --git a/libdex/DexProto.h b/libdex/DexProto.h
new file mode 100644
index 0000000..dccae6c
--- /dev/null
+++ b/libdex/DexProto.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions for dealing with method prototypes
+ */
+
+#ifndef LIBDEX_DEXPROTO_H_
+#define LIBDEX_DEXPROTO_H_
+
+#include "DexFile.h"
+
+/*
+ * Single-thread single-string cache. This structure holds a pointer to
+ * a string which is semi-automatically manipulated by some of the
+ * method prototype functions. Functions which use in this struct
+ * generally return a string that is valid until the next
+ * time the same DexStringCache is used.
+ */
+struct DexStringCache {
+    char* value;          /* the latest value */
+    size_t allocatedSize; /* size of the allocated buffer, if allocated */
+    char buffer[120];     /* buffer used to hold small-enough results */
+};
+
+/*
+ * Make sure that the given cache can hold a string of the given length,
+ * including the final '\0' byte.
+ */
+void dexStringCacheAlloc(DexStringCache* pCache, size_t length);
+
+/*
+ * Initialize the given DexStringCache. Use this function before passing
+ * one into any other function.
+ */
+void dexStringCacheInit(DexStringCache* pCache);
+
+/*
+ * Release the allocated contents of the given DexStringCache, if any.
+ * Use this function after your last use of a DexStringCache.
+ */
+void dexStringCacheRelease(DexStringCache* pCache);
+
+/*
+ * If the given DexStringCache doesn't already point at the given value,
+ * make a copy of it into the cache. This always returns a writable
+ * pointer to the contents (whether or not a copy had to be made). This
+ * function is intended to be used after making a call that at least
+ * sometimes doesn't populate a DexStringCache.
+ */
+char* dexStringCacheEnsureCopy(DexStringCache* pCache, const char* value);
+
+/*
+ * Abandon the given DexStringCache, and return a writable copy of the
+ * given value (reusing the string cache's allocation if possible).
+ * The return value must be free()d by the caller. Use this instead of
+ * dexStringCacheRelease() if you want the buffer to survive past the
+ * scope of the DexStringCache.
+ */
+char* dexStringCacheAbandon(DexStringCache* pCache, const char* value);
+
+/*
+ * Method prototype structure, which refers to a protoIdx in a
+ * particular DexFile.
+ */
+struct DexProto {
+    const DexFile* dexFile;     /* file the idx refers to */
+    u4 protoIdx;                /* index into proto_ids table of dexFile */
+};
+
+/*
+ * Set the given DexProto to refer to the prototype of the given MethodId.
+ */
+DEX_INLINE void dexProtoSetFromMethodId(DexProto* pProto,
+    const DexFile* pDexFile, const DexMethodId* pMethodId)
+{
+    pProto->dexFile = pDexFile;
+    pProto->protoIdx = pMethodId->protoIdx;
+}
+
+/*
+ * Get the short-form method descriptor for the given prototype. The
+ * prototype must be protoIdx-based.
+ */
+const char* dexProtoGetShorty(const DexProto* pProto);
+
+/*
+ * Get the full method descriptor for the given prototype.
+ */
+const char* dexProtoGetMethodDescriptor(const DexProto* pProto,
+    DexStringCache* pCache);
+
+/*
+ * Get a copy of the descriptor string associated with the given prototype.
+ * The returned pointer must be free()ed by the caller.
+ */
+char* dexProtoCopyMethodDescriptor(const DexProto* pProto);
+
+/*
+ * Get the parameter descriptors for the given prototype. This is the
+ * concatenation of all the descriptors for all the parameters, in
+ * order, with no other adornment.
+ */
+const char* dexProtoGetParameterDescriptors(const DexProto* pProto,
+    DexStringCache* pCache);
+
+/*
+ * Return the utf-8 encoded descriptor string from the proto of a MethodId.
+ */
+DEX_INLINE const char* dexGetDescriptorFromMethodId(const DexFile* pDexFile,
+        const DexMethodId* pMethodId, DexStringCache* pCache)
+{
+    DexProto proto;
+
+    dexProtoSetFromMethodId(&proto, pDexFile, pMethodId);
+    return dexProtoGetMethodDescriptor(&proto, pCache);
+}
+
+/*
+ * Get a copy of the utf-8 encoded method descriptor string from the
+ * proto of a MethodId. The returned pointer must be free()ed by the
+ * caller.
+ */
+DEX_INLINE char* dexCopyDescriptorFromMethodId(const DexFile* pDexFile,
+    const DexMethodId* pMethodId)
+{
+    DexProto proto;
+
+    dexProtoSetFromMethodId(&proto, pDexFile, pMethodId);
+    return dexProtoCopyMethodDescriptor(&proto);
+}
+
+/*
+ * Get the type descriptor for the return type of the given prototype.
+ */
+const char* dexProtoGetReturnType(const DexProto* pProto);
+
+/*
+ * Get the parameter count of the given prototype.
+ */
+size_t dexProtoGetParameterCount(const DexProto* pProto);
+
+/*
+ * Compute the number of parameter words (u4 units) required by the
+ * given prototype. For example, if the method takes (int, long) and
+ * returns double, this would return 3 (one for the int, two for the
+ * long, and the return type isn't relevant).
+ */
+int dexProtoComputeArgsSize(const DexProto* pProto);
+
+/*
+ * Compare the two prototypes. The two prototypes are compared
+ * with the return type as the major order, then the first arguments,
+ * then second, etc. If two prototypes are identical except that one
+ * has extra arguments, then the shorter argument is considered the
+ * earlier one in sort order (similar to strcmp()).
+ */
+int dexProtoCompare(const DexProto* pProto1, const DexProto* pProto2);
+
+/*
+ * Compare the two prototypes, ignoring return type. The two
+ * prototypes are compared with the first argument as the major order,
+ * then second, etc. If two prototypes are identical except that one
+ * has extra arguments, then the shorter argument is considered the
+ * earlier one in sort order (similar to strcmp()).
+ */
+int dexProtoCompareParameters(const DexProto* pProto1,
+        const DexProto* pProto2);
+
+/*
+ * Compare a prototype and a string method descriptor. The comparison
+ * is done as if the descriptor were converted to a prototype and compared
+ * with dexProtoCompare().
+ */
+int dexProtoCompareToDescriptor(const DexProto* proto, const char* descriptor);
+
+/*
+ * Compare a prototype and a concatenation of type descriptors. The
+ * comparison is done as if the descriptors were converted to a
+ * prototype and compared with dexProtoCompareParameters().
+ */
+int dexProtoCompareToParameterDescriptors(const DexProto* proto,
+        const char* descriptors);
+
+/*
+ * Single-thread prototype parameter iterator. This structure holds a
+ * pointer to a prototype and its parts, along with a cursor.
+ */
+struct DexParameterIterator {
+    const DexProto* proto;
+    const DexTypeList* parameters;
+    int parameterCount;
+    int cursor;
+};
+
+/*
+ * Initialize the given DexParameterIterator to be at the start of the
+ * parameters of the given prototype.
+ */
+void dexParameterIteratorInit(DexParameterIterator* pIterator,
+        const DexProto* pProto);
+
+/*
+ * Get the type_id index for the next parameter, if any. This returns
+ * kDexNoIndex if the last parameter has already been consumed.
+ */
+u4 dexParameterIteratorNextIndex(DexParameterIterator* pIterator);
+
+/*
+ * Get the type descriptor for the next parameter, if any. This returns
+ * NULL if the last parameter has already been consumed.
+ */
+const char* dexParameterIteratorNextDescriptor(
+        DexParameterIterator* pIterator);
+
+#endif  // LIBDEX_DEXPROTO_H_
diff --git a/libdex/DexSwapVerify.cpp b/libdex/DexSwapVerify.cpp
new file mode 100644
index 0000000..46ce141
--- /dev/null
+++ b/libdex/DexSwapVerify.cpp
@@ -0,0 +1,2957 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Byte-swapping and verification of dex files.
+ */
+
+#include "DexFile.h"
+#include "DexClass.h"
+#include "DexDataMap.h"
+#include "DexProto.h"
+#include "DexUtf.h"
+#include "Leb128.h"
+
+#include <safe_iop.h>
+#include <zlib.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#define SWAP2(_value)      (_value)
+#define SWAP4(_value)      (_value)
+#define SWAP8(_value)      (_value)
+
+#define SWAP_FIELD2(_field) (_field) = SWAP2(_field)
+#define SWAP_FIELD4(_field) (_field) = SWAP4(_field)
+#define SWAP_FIELD8(_field) (_field) = SWAP8(_field)
+
+/*
+ * Some information we pass around to help verify values.
+ */
+struct CheckState {
+    const DexHeader*  pHeader;
+    const u1*         fileStart;
+    const u1*         fileEnd;      // points to fileStart + fileLen
+    u4                fileLen;
+    DexDataMap*       pDataMap;     // set after map verification
+    const DexFile*    pDexFile;     // set after intraitem verification
+
+    /*
+     * bitmap of type_id indices that have been used to define classes;
+     * initialized immediately before class_def cross-verification, and
+     * freed immediately after it
+     */
+    u4*               pDefinedClassBits;
+
+    const void*       previousItem; // set during section iteration
+};
+
+/*
+ * Return the file offset of the given pointer.
+ */
+static inline u4 fileOffset(const CheckState* state, const void* ptr) {
+    return ((const u1*) ptr) - state->fileStart;
+}
+
+/*
+ * Return a pointer for the given file offset.
+ */
+static inline void* filePointer(const CheckState* state, u4 offset) {
+    return (void*) (state->fileStart + offset);
+}
+
+/*
+ * Verify that a pointer range, start inclusive to end exclusive, only
+ * covers bytes in the file and doesn't point beyond the end of the
+ * file. That is, the start must indicate a valid byte or may point at
+ * the byte just past the end of the file (but no further), and the
+ * end must be no less than the start and must also not point beyond
+ * the byte just past the end of the file.
+ */
+static inline bool checkPtrRange(const CheckState* state,
+        const void* start, const void* end, const char* label) {
+    const void* fileStart = state->fileStart;
+    const void* fileEnd = state->fileEnd;
+    if ((start < fileStart) || (start > fileEnd)
+            || (end < start) || (end > fileEnd)) {
+        ALOGW("Bad offset range for %s: %#x..%#x", label,
+                fileOffset(state, start), fileOffset(state, end));
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Verify that a range of offsets, start inclusive to end exclusive,
+ * are all valid. That is, the start must indicate a valid byte or may
+ * point at the byte just past the end of the file (but no further),
+ * and the end must be no less than the start and must also not point
+ * beyond the byte just past the end of the file.
+ *
+ * Assumes "const CheckState* state".
+ */
+#define CHECK_OFFSET_RANGE(_start, _end) {                                  \
+        const u1* _startPtr = (const u1*) filePointer(state, (_start));     \
+        const u1* _endPtr = (const u1*) filePointer(state, (_end));         \
+        if (!checkPtrRange(state, _startPtr, _endPtr,                       \
+                        #_start ".." #_end)) {                              \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Verify that a pointer range, start inclusive to end exclusive, only
+ * covers bytes in the file and doesn't point beyond the end of the
+ * file. That is, the start must indicate a valid byte or may point at
+ * the byte just past the end of the file (but no further), and the
+ * end must be no less than the start and must also not point beyond
+ * the byte just past the end of the file.
+ *
+ * Assumes "const CheckState* state".
+ */
+#define CHECK_PTR_RANGE(_start, _end) {                                     \
+        if (!checkPtrRange(state, (_start), (_end), #_start ".." #_end)) {  \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Make sure a list of items fits entirely within the file.
+ *
+ * Assumes "const CheckState* state" and "typeof(_count) == typeof(_elemSize)"
+ * If the type sizes or signs are mismatched, this will return 0.
+ */
+#define CHECK_LIST_SIZE(_ptr, _count, _elemSize) {                          \
+        const u1* _start = (const u1*) (_ptr);                              \
+        const u1* _end = _start + ((_count) * (_elemSize));                 \
+        if (!safe_mul(NULL, (_count), (_elemSize)) ||                       \
+            !checkPtrRange(state, _start, _end, #_ptr)) {                   \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Swap a field that is known to hold an absolute DEX file offset. Note:
+ * This does not check to see that the swapped offset points within the
+ * mapped file, since that should be handled (with even more rigor) by
+ * the cross-verification phase.
+ *
+ * Assumes "const CheckState* state".
+ */
+#define SWAP_OFFSET4(_field) {                                              \
+        SWAP_FIELD4((_field));                                              \
+    }
+
+/*
+ * Verify that an index falls in a valid range.
+ */
+#define CHECK_INDEX(_field, _limit) {                                       \
+        if ((_field) >= (_limit)) {                                         \
+            ALOGW("Bad index: %s(%u) > %s(%u)",                             \
+                #_field, (u4)(_field), #_limit, (u4)(_limit));              \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Swap an index, and verify that it falls in a valid range.
+ */
+#define SWAP_INDEX2(_field, _limit) {                                       \
+        SWAP_FIELD2((_field));                                              \
+        CHECK_INDEX((_field), (_limit));                                    \
+    }
+
+/*
+ * Verify that an index falls in a valid range or is kDexNoIndex.
+ */
+#define CHECK_INDEX_OR_NOINDEX(_field, _limit) {                            \
+        if ((_field) != kDexNoIndex && (_field) >= (_limit)) {              \
+            ALOGW("Bad index: %s(%u) > %s(%u)",                             \
+                #_field, (u4)(_field), #_limit, (u4)(_limit));              \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Swap an index, and verify that it falls in a valid range.
+ */
+#define SWAP_INDEX4(_field, _limit) {                                       \
+        SWAP_FIELD4((_field));                                              \
+        CHECK_INDEX((_field), (_limit));                                    \
+    }
+
+/*
+ * Swap an index, and verify that it falls in a valid range or is
+ * kDexNoIndex.
+ */
+#define SWAP_INDEX4_OR_NOINDEX(_field, _limit) {                            \
+        SWAP_FIELD4((_field));                                              \
+        CHECK_INDEX_OR_NOINDEX((_field), (_limit));                         \
+    }
+
+/* Verify the definer of a given field_idx. */
+static bool verifyFieldDefiner(const CheckState* state, u4 definingClass,
+        u4 fieldIdx) {
+    const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
+    return field->classIdx == definingClass;
+}
+
+/* Verify the definer of a given method_idx. */
+static bool verifyMethodDefiner(const CheckState* state, u4 definingClass,
+        u4 methodIdx) {
+    const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
+    return meth->classIdx == definingClass;
+}
+
+/*
+ * Calculate the required size (in elements) of the array pointed at by
+ * pDefinedClassBits.
+ */
+static size_t calcDefinedClassBitsSize(const CheckState* state)
+{
+    // Divide typeIdsSize by 32 (0x20), rounding up.
+    return (state->pHeader->typeIdsSize + 0x1f) >> 5;
+}
+
+/*
+ * Set the given bit in pDefinedClassBits, returning its former value.
+ */
+static bool setDefinedClassBit(const CheckState* state, u4 typeIdx) {
+    u4 arrayIdx = typeIdx >> 5;
+    u4 bit = 1 << (typeIdx & 0x1f);
+    u4* element = &state->pDefinedClassBits[arrayIdx];
+    bool result = (*element & bit) != 0;
+
+    *element |= bit;
+
+    return result;
+}
+
+/*
+ * Swap the header_item.
+ */
+static bool swapDexHeader(const CheckState* state, DexHeader* pHeader)
+{
+    CHECK_PTR_RANGE(pHeader, pHeader + 1);
+
+    // magic is ok
+    SWAP_FIELD4(pHeader->checksum);
+    // signature is ok
+    SWAP_FIELD4(pHeader->fileSize);
+    SWAP_FIELD4(pHeader->headerSize);
+    SWAP_FIELD4(pHeader->endianTag);
+    SWAP_FIELD4(pHeader->linkSize);
+    SWAP_OFFSET4(pHeader->linkOff);
+    SWAP_OFFSET4(pHeader->mapOff);
+    SWAP_FIELD4(pHeader->stringIdsSize);
+    SWAP_OFFSET4(pHeader->stringIdsOff);
+    SWAP_FIELD4(pHeader->typeIdsSize);
+    SWAP_OFFSET4(pHeader->typeIdsOff);
+    SWAP_FIELD4(pHeader->fieldIdsSize);
+    SWAP_OFFSET4(pHeader->fieldIdsOff);
+    SWAP_FIELD4(pHeader->methodIdsSize);
+    SWAP_OFFSET4(pHeader->methodIdsOff);
+    SWAP_FIELD4(pHeader->protoIdsSize);
+    SWAP_OFFSET4(pHeader->protoIdsOff);
+    SWAP_FIELD4(pHeader->classDefsSize);
+    SWAP_OFFSET4(pHeader->classDefsOff);
+    SWAP_FIELD4(pHeader->dataSize);
+    SWAP_OFFSET4(pHeader->dataOff);
+
+    if (pHeader->endianTag != kDexEndianConstant) {
+        ALOGE("Unexpected endian_tag: %#x", pHeader->endianTag);
+        return false;
+    }
+
+    // Assign variables so the diagnostic is prettier. (Hooray for macros.)
+    u4 linkOff = pHeader->linkOff;
+    u4 linkEnd = linkOff + pHeader->linkSize;
+    u4 dataOff = pHeader->dataOff;
+    u4 dataEnd = dataOff + pHeader->dataSize;
+    CHECK_OFFSET_RANGE(linkOff, linkEnd);
+    CHECK_OFFSET_RANGE(dataOff, dataEnd);
+
+    /*
+     * Note: The offsets and ranges of the other header items end up getting
+     * checked during the first iteration over the map.
+     */
+
+    return true;
+}
+
+/* Check the header section for sanity. */
+static bool checkHeaderSection(const CheckState* state, u4 sectionOffset,
+        u4 sectionCount, u4* endOffset) {
+    if (sectionCount != 1) {
+        ALOGE("Multiple header items");
+        return false;
+    }
+
+    if (sectionOffset != 0) {
+        ALOGE("Header at %#x; not at start of file", sectionOffset);
+        return false;
+    }
+
+    const DexHeader* pHeader = (const DexHeader*) filePointer(state, 0);
+    *endOffset = pHeader->headerSize;
+    return true;
+}
+
+/*
+ * Helper for swapMap(), which turns a map type constant into a small
+ * one-bit-on integer, suitable for use in an int-sized bit set.
+ */
+static u4 mapTypeToBitMask(int mapType) {
+    switch (mapType) {
+        case kDexTypeHeaderItem:               return 1 << 0;
+        case kDexTypeStringIdItem:             return 1 << 1;
+        case kDexTypeTypeIdItem:               return 1 << 2;
+        case kDexTypeProtoIdItem:              return 1 << 3;
+        case kDexTypeFieldIdItem:              return 1 << 4;
+        case kDexTypeMethodIdItem:             return 1 << 5;
+        case kDexTypeClassDefItem:             return 1 << 6;
+        case kDexTypeMapList:                  return 1 << 7;
+        case kDexTypeTypeList:                 return 1 << 8;
+        case kDexTypeAnnotationSetRefList:     return 1 << 9;
+        case kDexTypeAnnotationSetItem:        return 1 << 10;
+        case kDexTypeClassDataItem:            return 1 << 11;
+        case kDexTypeCodeItem:                 return 1 << 12;
+        case kDexTypeStringDataItem:           return 1 << 13;
+        case kDexTypeDebugInfoItem:            return 1 << 14;
+        case kDexTypeAnnotationItem:           return 1 << 15;
+        case kDexTypeEncodedArrayItem:         return 1 << 16;
+        case kDexTypeAnnotationsDirectoryItem: return 1 << 17;
+        default: {
+            ALOGE("Unknown map item type %04x", mapType);
+            return 0;
+        }
+    }
+}
+
+/*
+ * Helper for swapMap(), which indicates if an item type should appear
+ * in the data section.
+ */
+static bool isDataSectionType(int mapType) {
+    switch (mapType) {
+        case kDexTypeHeaderItem:
+        case kDexTypeStringIdItem:
+        case kDexTypeTypeIdItem:
+        case kDexTypeProtoIdItem:
+        case kDexTypeFieldIdItem:
+        case kDexTypeMethodIdItem:
+        case kDexTypeClassDefItem: {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Swap the map_list and verify what we can about it. Also, if verification
+ * passes, allocate the state's DexDataMap.
+ */
+static bool swapMap(CheckState* state, DexMapList* pMap)
+{
+    DexMapItem* item = pMap->list;
+    u4 count;
+    u4 dataItemCount = 0; // Total count of items in the data section.
+    u4 dataItemsLeft = state->pHeader->dataSize; // See use below.
+    u4 usedBits = 0;      // Bit set: one bit per section
+    bool first = true;
+    u4 lastOffset = 0;
+
+    SWAP_FIELD4(pMap->size);
+    count = pMap->size;
+    const u4 sizeOfItem = (u4) sizeof(DexMapItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
+
+    while (count--) {
+        SWAP_FIELD2(item->type);
+        SWAP_FIELD2(item->unused);
+        SWAP_FIELD4(item->size);
+        SWAP_OFFSET4(item->offset);
+
+        if (first) {
+            first = false;
+        } else if (lastOffset >= item->offset) {
+            ALOGE("Out-of-order map item: %#x then %#x",
+                    lastOffset, item->offset);
+            return false;
+        }
+
+        if (item->offset >= state->pHeader->fileSize) {
+            ALOGE("Map item after end of file: %x, size %#x",
+                    item->offset, state->pHeader->fileSize);
+            return false;
+        }
+
+        if (isDataSectionType(item->type)) {
+            u4 icount = item->size;
+
+            /*
+             * This sanity check on the data section items ensures that
+             * there are no more items than the number of bytes in
+             * the data section.
+             */
+            if (icount > dataItemsLeft) {
+                ALOGE("Unrealistically many items in the data section: "
+                        "at least %d", dataItemCount + icount);
+                return false;
+            }
+
+            dataItemsLeft -= icount;
+            dataItemCount += icount;
+        }
+
+        u4 bit = mapTypeToBitMask(item->type);
+
+        if (bit == 0) {
+            return false;
+        }
+
+        if ((usedBits & bit) != 0) {
+            ALOGE("Duplicate map section of type %#x", item->type);
+            return false;
+        }
+
+        usedBits |= bit;
+        lastOffset = item->offset;
+        item++;
+    }
+
+    if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
+        ALOGE("Map is missing header entry");
+        return false;
+    }
+
+    if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
+        ALOGE("Map is missing map_list entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
+            && ((state->pHeader->stringIdsOff != 0)
+                    || (state->pHeader->stringIdsSize != 0))) {
+        ALOGE("Map is missing string_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
+            && ((state->pHeader->typeIdsOff != 0)
+                    || (state->pHeader->typeIdsSize != 0))) {
+        ALOGE("Map is missing type_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
+            && ((state->pHeader->protoIdsOff != 0)
+                    || (state->pHeader->protoIdsSize != 0))) {
+        ALOGE("Map is missing proto_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
+            && ((state->pHeader->fieldIdsOff != 0)
+                    || (state->pHeader->fieldIdsSize != 0))) {
+        ALOGE("Map is missing field_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
+            && ((state->pHeader->methodIdsOff != 0)
+                    || (state->pHeader->methodIdsSize != 0))) {
+        ALOGE("Map is missing method_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
+            && ((state->pHeader->classDefsOff != 0)
+                    || (state->pHeader->classDefsSize != 0))) {
+        ALOGE("Map is missing class_defs entry");
+        return false;
+    }
+
+    state->pDataMap = dexDataMapAlloc(dataItemCount);
+    if (state->pDataMap == NULL) {
+        ALOGE("Unable to allocate data map (size %#x)", dataItemCount);
+        return false;
+    }
+
+    return true;
+}
+
+/* Check the map section for sanity. */
+static bool checkMapSection(const CheckState* state, u4 sectionOffset,
+        u4 sectionCount, u4* endOffset) {
+    if (sectionCount != 1) {
+        ALOGE("Multiple map list items");
+        return false;
+    }
+
+    if (sectionOffset != state->pHeader->mapOff) {
+        ALOGE("Map not at header-defined offset: %#x, expected %#x",
+                sectionOffset, state->pHeader->mapOff);
+        return false;
+    }
+
+    const DexMapList* pMap = (const DexMapList*) filePointer(state, sectionOffset);
+
+    *endOffset =
+        sectionOffset + sizeof(u4) + (pMap->size * sizeof(DexMapItem));
+    return true;
+}
+
+/* Perform byte-swapping and intra-item verification on string_id_item. */
+static void* swapStringIdItem(const CheckState* state, void* ptr) {
+    DexStringId* item = (DexStringId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_OFFSET4(item->stringDataOff);
+
+    return item + 1;
+}
+
+/* Perform cross-item verification of string_id_item. */
+static void* crossVerifyStringIdItem(const CheckState* state, void* ptr) {
+    const DexStringId* item = (const DexStringId*) ptr;
+
+    if (!dexDataMapVerify(state->pDataMap,
+                    item->stringDataOff, kDexTypeStringDataItem)) {
+        return NULL;
+    }
+
+    const DexStringId* item0 = (const DexStringId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering.
+        const char* s0 = dexGetStringData(state->pDexFile, item0);
+        const char* s1 = dexGetStringData(state->pDexFile, item);
+        if (dexUtf8Cmp(s0, s1) >= 0) {
+            ALOGE("Out-of-order string_ids: '%s' then '%s'", s0, s1);
+            return NULL;
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on type_id_item. */
+static void* swapTypeIdItem(const CheckState* state, void* ptr) {
+    DexTypeId* item = (DexTypeId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX4(item->descriptorIdx, state->pHeader->stringIdsSize);
+
+    return item + 1;
+}
+
+/* Perform cross-item verification of type_id_item. */
+static void* crossVerifyTypeIdItem(const CheckState* state, void* ptr) {
+    const DexTypeId* item = (const DexTypeId*) ptr;
+    const char* descriptor =
+        dexStringById(state->pDexFile, item->descriptorIdx);
+
+    if (!dexIsValidTypeDescriptor(descriptor)) {
+        ALOGE("Invalid type descriptor: '%s'", descriptor);
+        return NULL;
+    }
+
+    const DexTypeId* item0 = (const DexTypeId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering. This relies on string_ids being in order.
+        if (item0->descriptorIdx >= item->descriptorIdx) {
+            ALOGE("Out-of-order type_ids: %#x then %#x",
+                    item0->descriptorIdx, item->descriptorIdx);
+            return NULL;
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on proto_id_item. */
+static void* swapProtoIdItem(const CheckState* state, void* ptr) {
+    DexProtoId* item = (DexProtoId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX4(item->shortyIdx, state->pHeader->stringIdsSize);
+    SWAP_INDEX4(item->returnTypeIdx, state->pHeader->typeIdsSize);
+    SWAP_OFFSET4(item->parametersOff);
+
+    return item + 1;
+}
+
+/* Helper for crossVerifyProtoIdItem(), which checks a shorty character
+ * to see if it is compatible with a type descriptor. Returns true if
+ * so, false if not. */
+static bool shortyDescMatch(char shorty, const char* descriptor, bool
+        isReturnType) {
+    switch (shorty) {
+        case 'V': {
+            if (!isReturnType) {
+                ALOGE("Invalid use of void");
+                return false;
+            }
+            // Fall through.
+        }
+        case 'B':
+        case 'C':
+        case 'D':
+        case 'F':
+        case 'I':
+        case 'J':
+        case 'S':
+        case 'Z': {
+            if ((descriptor[0] != shorty) || (descriptor[1] != '\0')) {
+                ALOGE("Shorty vs. primitive type mismatch: '%c', '%s'",
+                        shorty, descriptor);
+                return false;
+            }
+            break;
+        }
+        case 'L': {
+            if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
+                ALOGE("Shorty vs. type mismatch: '%c', '%s'",
+                        shorty, descriptor);
+                return false;
+            }
+            break;
+        }
+        default: {
+            ALOGE("Bogus shorty: '%c'", shorty);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/* Perform cross-item verification of proto_id_item. */
+static void* crossVerifyProtoIdItem(const CheckState* state, void* ptr) {
+    const DexProtoId* item = (const DexProtoId*) ptr;
+    const char* shorty =
+        dexStringById(state->pDexFile, item->shortyIdx);
+
+    if (!dexDataMapVerify0Ok(state->pDataMap,
+                    item->parametersOff, kDexTypeTypeList)) {
+        return NULL;
+    }
+
+    if (!shortyDescMatch(*shorty,
+                    dexStringByTypeIdx(state->pDexFile, item->returnTypeIdx),
+                    true)) {
+        return NULL;
+    }
+
+    u4 protoIdx = item - state->pDexFile->pProtoIds;
+    DexProto proto = { state->pDexFile, protoIdx };
+    DexParameterIterator iterator;
+
+    dexParameterIteratorInit(&iterator, &proto);
+    shorty++; // Skip the return type.
+
+    for (;;) {
+        const char *desc = dexParameterIteratorNextDescriptor(&iterator);
+
+        if (desc == NULL) {
+            break;
+        }
+
+        if (*shorty == '\0') {
+            ALOGE("Shorty is too short");
+            return NULL;
+        }
+
+        if (!shortyDescMatch(*shorty, desc, false)) {
+            return NULL;
+        }
+
+        shorty++;
+    }
+
+    if (*shorty != '\0') {
+        ALOGE("Shorty is too long");
+        return NULL;
+    }
+
+    const DexProtoId* item0 = (const DexProtoId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering. This relies on type_ids being in order.
+        if (item0->returnTypeIdx > item->returnTypeIdx) {
+            ALOGE("Out-of-order proto_id return types");
+            return NULL;
+        } else if (item0->returnTypeIdx == item->returnTypeIdx) {
+            bool badOrder = false;
+            DexProto proto0 = { state->pDexFile, protoIdx - 1 };
+            DexParameterIterator iterator0;
+
+            dexParameterIteratorInit(&iterator, &proto);
+            dexParameterIteratorInit(&iterator0, &proto0);
+
+            for (;;) {
+                u4 idx0 = dexParameterIteratorNextIndex(&iterator0);
+                u4 idx1 = dexParameterIteratorNextIndex(&iterator);
+
+                if (idx1 == kDexNoIndex) {
+                    badOrder = true;
+                    break;
+                }
+
+                if (idx0 == kDexNoIndex) {
+                    break;
+                }
+
+                if (idx0 < idx1) {
+                    break;
+                } else if (idx0 > idx1) {
+                    badOrder = true;
+                    break;
+                }
+            }
+
+            if (badOrder) {
+                ALOGE("Out-of-order proto_id arguments");
+                return NULL;
+            }
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on field_id_item. */
+static void* swapFieldIdItem(const CheckState* state, void* ptr) {
+    DexFieldId* item = (DexFieldId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
+    SWAP_INDEX2(item->typeIdx, state->pHeader->typeIdsSize);
+    SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
+
+    return item + 1;
+}
+
+/* Perform cross-item verification of field_id_item. */
+static void* crossVerifyFieldIdItem(const CheckState* state, void* ptr) {
+    const DexFieldId* item = (const DexFieldId*) ptr;
+    const char* s;
+
+    s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
+    if (!dexIsClassDescriptor(s)) {
+        ALOGE("Invalid descriptor for class_idx: '%s'", s);
+        return NULL;
+    }
+
+    s = dexStringByTypeIdx(state->pDexFile, item->typeIdx);
+    if (!dexIsFieldDescriptor(s)) {
+        ALOGE("Invalid descriptor for type_idx: '%s'", s);
+        return NULL;
+    }
+
+    s = dexStringById(state->pDexFile, item->nameIdx);
+    if (!dexIsValidMemberName(s)) {
+        ALOGE("Invalid name: '%s'", s);
+        return NULL;
+    }
+
+    const DexFieldId* item0 = (const DexFieldId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering. This relies on the other sections being in order.
+        bool done = false;
+        bool bogus = false;
+
+        if (item0->classIdx > item->classIdx) {
+            bogus = true;
+            done = true;
+        } else if (item0->classIdx < item->classIdx) {
+            done = true;
+        }
+
+        if (!done) {
+            if (item0->nameIdx > item->nameIdx) {
+                bogus = true;
+                done = true;
+            } else if (item0->nameIdx < item->nameIdx) {
+                done = true;
+            }
+        }
+
+        if (!done) {
+            if (item0->typeIdx >= item->typeIdx) {
+                bogus = true;
+            }
+        }
+
+        if (bogus) {
+            ALOGE("Out-of-order field_ids");
+            return NULL;
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on method_id_item. */
+static void* swapMethodIdItem(const CheckState* state, void* ptr) {
+    DexMethodId* item = (DexMethodId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
+    SWAP_INDEX2(item->protoIdx, state->pHeader->protoIdsSize);
+    SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
+
+    return item + 1;
+}
+
+/* Perform cross-item verification of method_id_item. */
+static void* crossVerifyMethodIdItem(const CheckState* state, void* ptr) {
+    const DexMethodId* item = (const DexMethodId*) ptr;
+    const char* s;
+
+    s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
+    if (!dexIsReferenceDescriptor(s)) {
+        ALOGE("Invalid descriptor for class_idx: '%s'", s);
+        return NULL;
+    }
+
+    s = dexStringById(state->pDexFile, item->nameIdx);
+    if (!dexIsValidMemberName(s)) {
+        ALOGE("Invalid name: '%s'", s);
+        return NULL;
+    }
+
+    const DexMethodId* item0 = (const DexMethodId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering. This relies on the other sections being in order.
+        bool done = false;
+        bool bogus = false;
+
+        if (item0->classIdx > item->classIdx) {
+            bogus = true;
+            done = true;
+        } else if (item0->classIdx < item->classIdx) {
+            done = true;
+        }
+
+        if (!done) {
+            if (item0->nameIdx > item->nameIdx) {
+                bogus = true;
+                done = true;
+            } else if (item0->nameIdx < item->nameIdx) {
+                done = true;
+            }
+        }
+
+        if (!done) {
+            if (item0->protoIdx >= item->protoIdx) {
+                bogus = true;
+            }
+        }
+
+        if (bogus) {
+            ALOGE("Out-of-order method_ids");
+            return NULL;
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on class_def_item. */
+static void* swapClassDefItem(const CheckState* state, void* ptr) {
+    DexClassDef* item = (DexClassDef*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX4(item->classIdx, state->pHeader->typeIdsSize);
+    SWAP_FIELD4(item->accessFlags);
+    SWAP_INDEX4_OR_NOINDEX(item->superclassIdx, state->pHeader->typeIdsSize);
+    SWAP_OFFSET4(item->interfacesOff);
+    SWAP_INDEX4_OR_NOINDEX(item->sourceFileIdx, state->pHeader->stringIdsSize);
+    SWAP_OFFSET4(item->annotationsOff);
+    SWAP_OFFSET4(item->classDataOff);
+
+    if ((item->accessFlags & ~ACC_CLASS_MASK) != 0) {
+        // The VM specification says that unknown flags should be ignored.
+        ALOGV("Bogus class access flags %x", item->accessFlags);
+        item->accessFlags &= ACC_CLASS_MASK;
+    }
+
+    return item + 1;
+}
+
+/* defined below */
+static u4 findFirstClassDataDefiner(const CheckState* state,
+        DexClassData* classData);
+static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
+        const DexAnnotationsDirectoryItem* dir);
+
+/* Helper for crossVerifyClassDefItem(), which checks a class_data_item to
+ * make sure all its references are to a given class. */
+static bool verifyClassDataIsForDef(const CheckState* state, u4 offset,
+        u4 definerIdx) {
+    if (offset == 0) {
+        return true;
+    }
+
+    const u1* data = (const u1*) filePointer(state, offset);
+    DexClassData* classData = dexReadAndVerifyClassData(&data, NULL);
+
+    if (classData == NULL) {
+        // Shouldn't happen, but bail here just in case.
+        return false;
+    }
+
+    /*
+     * The class_data_item verification ensures that
+     * it consistently refers to the same definer, so all we need to
+     * do is check the first one.
+     */
+    u4 dataDefiner = findFirstClassDataDefiner(state, classData);
+    bool result = (dataDefiner == definerIdx) || (dataDefiner == kDexNoIndex);
+
+    free(classData);
+    return result;
+}
+
+/* Helper for crossVerifyClassDefItem(), which checks an
+ * annotations_directory_item to make sure all its references are to a
+ * given class. */
+static bool verifyAnnotationsDirectoryIsForDef(const CheckState* state,
+        u4 offset, u4 definerIdx) {
+    if (offset == 0) {
+        return true;
+    }
+
+    const DexAnnotationsDirectoryItem* dir =
+        (const DexAnnotationsDirectoryItem*) filePointer(state, offset);
+    u4 annoDefiner = findFirstAnnotationsDirectoryDefiner(state, dir);
+
+    return (annoDefiner == definerIdx) || (annoDefiner == kDexNoIndex);
+}
+
+/* Perform cross-item verification of class_def_item. */
+static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) {
+    const DexClassDef* item = (const DexClassDef*) ptr;
+    u4 classIdx = item->classIdx;
+    const char* descriptor = dexStringByTypeIdx(state->pDexFile, classIdx);
+
+    if (!dexIsClassDescriptor(descriptor)) {
+        ALOGE("Invalid class: '%s'", descriptor);
+        return NULL;
+    }
+
+    if (setDefinedClassBit(state, classIdx)) {
+        ALOGE("Duplicate class definition: '%s'", descriptor);
+        return NULL;
+    }
+
+    bool okay =
+        dexDataMapVerify0Ok(state->pDataMap,
+                item->interfacesOff, kDexTypeTypeList)
+        && dexDataMapVerify0Ok(state->pDataMap,
+                item->annotationsOff, kDexTypeAnnotationsDirectoryItem)
+        && dexDataMapVerify0Ok(state->pDataMap,
+                item->classDataOff, kDexTypeClassDataItem)
+        && dexDataMapVerify0Ok(state->pDataMap,
+                item->staticValuesOff, kDexTypeEncodedArrayItem);
+
+    if (!okay) {
+        return NULL;
+    }
+
+    if (item->superclassIdx != kDexNoIndex) {
+        descriptor = dexStringByTypeIdx(state->pDexFile, item->superclassIdx);
+        if (!dexIsClassDescriptor(descriptor)) {
+            ALOGE("Invalid superclass: '%s'", descriptor);
+            return NULL;
+        }
+    }
+
+    const DexTypeList* interfaces =
+        dexGetInterfacesList(state->pDexFile, item);
+    if (interfaces != NULL) {
+        u4 size = interfaces->size;
+        u4 i;
+
+        /*
+         * Ensure that all interfaces refer to classes (not arrays or
+         * primitives).
+         */
+        for (i = 0; i < size; i++) {
+            descriptor = dexStringByTypeIdx(state->pDexFile,
+                    dexTypeListGetIdx(interfaces, i));
+            if (!dexIsClassDescriptor(descriptor)) {
+                ALOGE("Invalid interface: '%s'", descriptor);
+                return NULL;
+            }
+        }
+
+        /*
+         * Ensure that there are no duplicates. This is an O(N^2) test,
+         * but in practice the number of interfaces implemented by any
+         * given class is low. I will buy a milkshake for the
+         * first person to show me a realistic case for which this test
+         * would be unacceptably slow.
+         */
+        for (i = 1; i < size; i++) {
+            u4 idx1 = dexTypeListGetIdx(interfaces, i);
+            u4 j;
+            for (j = 0; j < i; j++) {
+                u4 idx2 = dexTypeListGetIdx(interfaces, j);
+                if (idx1 == idx2) {
+                    ALOGE("Duplicate interface: '%s'",
+                            dexStringByTypeIdx(state->pDexFile, idx1));
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    if (!verifyClassDataIsForDef(state, item->classDataOff, item->classIdx)) {
+        ALOGE("Invalid class_data_item");
+        return NULL;
+    }
+
+    if (!verifyAnnotationsDirectoryIsForDef(state, item->annotationsOff,
+                    item->classIdx)) {
+        ALOGE("Invalid annotations_directory_item");
+        return NULL;
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Helper for swapAnnotationsDirectoryItem(), which performs
+ * byte-swapping and intra-item verification on an
+ * annotation_directory_item's field elements. */
+static u1* swapFieldAnnotations(const CheckState* state, u4 count, u1* addr) {
+    DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
+    bool first = true;
+    u4 lastIdx = 0;
+
+    const u4 sizeOfItem = (u4) sizeof(DexFieldAnnotationsItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
+
+    while (count--) {
+        SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize);
+        SWAP_OFFSET4(item->annotationsOff);
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= item->fieldIdx) {
+            ALOGE("Out-of-order field_idx: %#x then %#x", lastIdx,
+                 item->fieldIdx);
+            return NULL;
+        }
+
+        lastIdx = item->fieldIdx;
+        item++;
+    }
+
+    return (u1*) item;
+}
+
+/* Helper for swapAnnotationsDirectoryItem(), which performs
+ * byte-swapping and intra-item verification on an
+ * annotation_directory_item's method elements. */
+static u1* swapMethodAnnotations(const CheckState* state, u4 count, u1* addr) {
+    DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
+    bool first = true;
+    u4 lastIdx = 0;
+
+    const u4 sizeOfItem = (u4) sizeof(DexMethodAnnotationsItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
+
+    while (count--) {
+        SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
+        SWAP_OFFSET4(item->annotationsOff);
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= item->methodIdx) {
+            ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
+                 item->methodIdx);
+            return NULL;
+        }
+
+        lastIdx = item->methodIdx;
+        item++;
+    }
+
+    return (u1*) item;
+}
+
+/* Helper for swapAnnotationsDirectoryItem(), which performs
+ * byte-swapping and intra-item verification on an
+ * annotation_directory_item's parameter elements. */
+static u1* swapParameterAnnotations(const CheckState* state, u4 count,
+        u1* addr) {
+    DexParameterAnnotationsItem* item = (DexParameterAnnotationsItem*) addr;
+    bool first = true;
+    u4 lastIdx = 0;
+
+    const u4 sizeOfItem = (u4) sizeof(DexParameterAnnotationsItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
+
+    while (count--) {
+        SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
+        SWAP_OFFSET4(item->annotationsOff);
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= item->methodIdx) {
+            ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
+                 item->methodIdx);
+            return NULL;
+        }
+
+        lastIdx = item->methodIdx;
+        item++;
+    }
+
+    return (u1*) item;
+}
+
+/* Perform byte-swapping and intra-item verification on
+ * annotations_directory_item. */
+static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) {
+    DexAnnotationsDirectoryItem* item = (DexAnnotationsDirectoryItem*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_OFFSET4(item->classAnnotationsOff);
+    SWAP_FIELD4(item->fieldsSize);
+    SWAP_FIELD4(item->methodsSize);
+    SWAP_FIELD4(item->parametersSize);
+
+    u1* addr = (u1*) (item + 1);
+
+    if (item->fieldsSize != 0) {
+        addr = swapFieldAnnotations(state, item->fieldsSize, addr);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    if (item->methodsSize != 0) {
+        addr = swapMethodAnnotations(state, item->methodsSize, addr);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    if (item->parametersSize != 0) {
+        addr = swapParameterAnnotations(state, item->parametersSize, addr);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    return addr;
+}
+
+/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
+ * field elements. */
+static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count,
+        const u1* addr, u4 definingClass) {
+    const DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
+
+    while (count--) {
+        if (!verifyFieldDefiner(state, definingClass, item->fieldIdx)) {
+            return NULL;
+        }
+        if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
+                        kDexTypeAnnotationSetItem)) {
+            return NULL;
+        }
+        item++;
+    }
+
+    return (const u1*) item;
+}
+
+/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
+ * method elements. */
+static const u1* crossVerifyMethodAnnotations(const CheckState* state,
+        u4 count, const u1* addr, u4 definingClass) {
+    const DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
+
+    while (count--) {
+        if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
+            return NULL;
+        }
+        if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
+                        kDexTypeAnnotationSetItem)) {
+            return NULL;
+        }
+        item++;
+    }
+
+    return (const u1*) item;
+}
+
+/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
+ * parameter elements. */
+static const u1* crossVerifyParameterAnnotations(const CheckState* state,
+        u4 count, const u1* addr, u4 definingClass) {
+    const DexParameterAnnotationsItem* item =
+        (DexParameterAnnotationsItem*) addr;
+
+    while (count--) {
+        if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
+            return NULL;
+        }
+        if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
+                        kDexTypeAnnotationSetRefList)) {
+            return NULL;
+        }
+        item++;
+    }
+
+    return (const u1*) item;
+}
+
+/* Helper for crossVerifyClassDefItem() and
+ * crossVerifyAnnotationsDirectoryItem(), which finds the type_idx of
+ * the definer of the first item in the data. */
+static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
+        const DexAnnotationsDirectoryItem* dir) {
+    if (dir->fieldsSize != 0) {
+        const DexFieldAnnotationsItem* fields =
+            dexGetFieldAnnotations(state->pDexFile, dir);
+        const DexFieldId* field =
+            dexGetFieldId(state->pDexFile, fields[0].fieldIdx);
+        return field->classIdx;
+    }
+
+    if (dir->methodsSize != 0) {
+        const DexMethodAnnotationsItem* methods =
+            dexGetMethodAnnotations(state->pDexFile, dir);
+        const DexMethodId* method =
+            dexGetMethodId(state->pDexFile, methods[0].methodIdx);
+        return method->classIdx;
+    }
+
+    if (dir->parametersSize != 0) {
+        const DexParameterAnnotationsItem* parameters =
+            dexGetParameterAnnotations(state->pDexFile, dir);
+        const DexMethodId* method =
+            dexGetMethodId(state->pDexFile, parameters[0].methodIdx);
+        return method->classIdx;
+    }
+
+    return kDexNoIndex;
+}
+
+/* Perform cross-item verification of annotations_directory_item. */
+static void* crossVerifyAnnotationsDirectoryItem(const CheckState* state,
+        void* ptr) {
+    const DexAnnotationsDirectoryItem* item = (const DexAnnotationsDirectoryItem*) ptr;
+    u4 definingClass = findFirstAnnotationsDirectoryDefiner(state, item);
+
+    if (!dexDataMapVerify0Ok(state->pDataMap,
+                    item->classAnnotationsOff, kDexTypeAnnotationSetItem)) {
+        return NULL;
+    }
+
+    const u1* addr = (const u1*) (item + 1);
+
+    if (item->fieldsSize != 0) {
+        addr = crossVerifyFieldAnnotations(state, item->fieldsSize, addr,
+                definingClass);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    if (item->methodsSize != 0) {
+        addr = crossVerifyMethodAnnotations(state, item->methodsSize, addr,
+                definingClass);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    if (item->parametersSize != 0) {
+        addr = crossVerifyParameterAnnotations(state, item->parametersSize,
+                addr, definingClass);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    return (void*) addr;
+}
+
+/* Perform byte-swapping and intra-item verification on type_list. */
+static void* swapTypeList(const CheckState* state, void* ptr)
+{
+    DexTypeList* pTypeList = (DexTypeList*) ptr;
+    DexTypeItem* pType;
+    u4 count;
+
+    CHECK_PTR_RANGE(pTypeList, pTypeList + 1);
+    SWAP_FIELD4(pTypeList->size);
+    count = pTypeList->size;
+    pType = pTypeList->list;
+
+    const u4 sizeOfItem = (u4) sizeof(DexTypeItem);
+    CHECK_LIST_SIZE(pType, count, sizeOfItem);
+
+    while (count--) {
+        SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize);
+        pType++;
+    }
+
+    return pType;
+}
+
+/* Perform byte-swapping and intra-item verification on
+ * annotation_set_ref_list. */
+static void* swapAnnotationSetRefList(const CheckState* state, void* ptr) {
+    DexAnnotationSetRefList* list = (DexAnnotationSetRefList*) ptr;
+    DexAnnotationSetRefItem* item;
+    u4 count;
+
+    CHECK_PTR_RANGE(list, list + 1);
+    SWAP_FIELD4(list->size);
+    count = list->size;
+    item = list->list;
+
+    const u4 sizeOfItem = (u4) sizeof(DexAnnotationSetRefItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
+
+    while (count--) {
+        SWAP_OFFSET4(item->annotationsOff);
+        item++;
+    }
+
+    return item;
+}
+
+/* Perform cross-item verification of annotation_set_ref_list. */
+static void* crossVerifyAnnotationSetRefList(const CheckState* state,
+        void* ptr) {
+    const DexAnnotationSetRefList* list = (const DexAnnotationSetRefList*) ptr;
+    const DexAnnotationSetRefItem* item = list->list;
+    int count = list->size;
+
+    while (count--) {
+        if (!dexDataMapVerify0Ok(state->pDataMap,
+                        item->annotationsOff, kDexTypeAnnotationSetItem)) {
+            return NULL;
+        }
+        item++;
+    }
+
+    return (void*) item;
+}
+
+/* Perform byte-swapping and intra-item verification on
+ * annotation_set_item. */
+static void* swapAnnotationSetItem(const CheckState* state, void* ptr) {
+    DexAnnotationSetItem* set = (DexAnnotationSetItem*) ptr;
+    u4* item;
+    u4 count;
+
+    CHECK_PTR_RANGE(set, set + 1);
+    SWAP_FIELD4(set->size);
+    count = set->size;
+    item = set->entries;
+
+    const u4 sizeOfItem = (u4) sizeof(u4);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
+
+    while (count--) {
+        SWAP_OFFSET4(*item);
+        item++;
+    }
+
+    return item;
+}
+
+/* Helper for crossVerifyAnnotationSetItem(), which extracts the type_idx
+ * out of an annotation_item. */
+static u4 annotationItemTypeIdx(const DexAnnotationItem* item) {
+    const u1* data = item->annotation;
+    return readUnsignedLeb128(&data);
+}
+
+/* Perform cross-item verification of annotation_set_item. */
+static void* crossVerifyAnnotationSetItem(const CheckState* state, void* ptr) {
+    const DexAnnotationSetItem* set = (const DexAnnotationSetItem*) ptr;
+    int count = set->size;
+    u4 lastIdx = 0;
+    bool first = true;
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if (!dexDataMapVerify0Ok(state->pDataMap,
+                        dexGetAnnotationOff(set, i), kDexTypeAnnotationItem)) {
+            return NULL;
+        }
+
+        const DexAnnotationItem* annotation =
+            dexGetAnnotationItem(state->pDexFile, set, i);
+        u4 idx = annotationItemTypeIdx(annotation);
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= idx) {
+            ALOGE("Out-of-order entry types: %#x then %#x",
+                    lastIdx, idx);
+            return NULL;
+        }
+
+        lastIdx = idx;
+    }
+
+    return (void*) (set->entries + count);
+}
+
+/* Helper for verifyClassDataItem(), which checks a list of fields. */
+static bool verifyFields(const CheckState* state, u4 size,
+        DexField* fields, bool expectStatic) {
+    u4 i;
+
+    for (i = 0; i < size; i++) {
+        DexField* field = &fields[i];
+        u4 accessFlags = field->accessFlags;
+        bool isStatic = (accessFlags & ACC_STATIC) != 0;
+
+        CHECK_INDEX(field->fieldIdx, state->pHeader->fieldIdsSize);
+
+        if (isStatic != expectStatic) {
+            ALOGE("Field in wrong list @ %d", i);
+            return false;
+        }
+
+        if ((accessFlags & ~ACC_FIELD_MASK) != 0) {
+            // The VM specification says that unknown flags should be ignored.
+            ALOGV("Bogus field access flags %x @ %d", accessFlags, i);
+            field->accessFlags &= ACC_FIELD_MASK;
+        }
+    }
+
+    return true;
+}
+
+/* Helper for verifyClassDataItem(), which checks a list of methods. */
+static bool verifyMethods(const CheckState* state, u4 size,
+        DexMethod* methods, bool expectDirect) {
+    u4 i;
+
+    for (i = 0; i < size; i++) {
+        DexMethod* method = &methods[i];
+
+        CHECK_INDEX(method->methodIdx, state->pHeader->methodIdsSize);
+
+        u4 accessFlags = method->accessFlags;
+        bool isDirect =
+            (accessFlags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
+        bool expectCode = (accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
+        bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
+        bool allowSynchronized = (accessFlags & ACC_NATIVE) != 0;
+
+        if (isDirect != expectDirect) {
+            ALOGE("Method in wrong list @ %d", i);
+            return false;
+        }
+
+        if (isSynchronized && !allowSynchronized) {
+            ALOGE("Bogus method access flags (synchronization) %x @ %d", accessFlags, i);
+            return false;
+        }
+
+        if ((accessFlags & ~ACC_METHOD_MASK) != 0) {
+            // The VM specification says that unknown flags should be ignored.
+            ALOGV("Bogus method access flags %x @ %d", accessFlags, i);
+            method->accessFlags &= ACC_METHOD_MASK;
+        }
+
+        if (expectCode) {
+            if (method->codeOff == 0) {
+                ALOGE("Unexpected zero code_off for access_flags %x",
+                        accessFlags);
+                return false;
+            }
+        } else if (method->codeOff != 0) {
+            ALOGE("Unexpected non-zero code_off %#x for access_flags %x",
+                    method->codeOff, accessFlags);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/* Helper for verifyClassDataItem(), which does most of the work. */
+static bool verifyClassDataItem0(const CheckState* state,
+        DexClassData* classData) {
+    bool okay;
+
+    okay = verifyFields(state, classData->header.staticFieldsSize,
+            classData->staticFields, true);
+
+    if (!okay) {
+        ALOGE("Trouble with static fields");
+        return false;
+    }
+
+    verifyFields(state, classData->header.instanceFieldsSize,
+            classData->instanceFields, false);
+
+    if (!okay) {
+        ALOGE("Trouble with instance fields");
+        return false;
+    }
+
+    okay = verifyMethods(state, classData->header.directMethodsSize,
+            classData->directMethods, true);
+
+    if (!okay) {
+        ALOGE("Trouble with direct methods");
+        return false;
+    }
+
+    okay = verifyMethods(state, classData->header.virtualMethodsSize,
+            classData->virtualMethods, false);
+
+    if (!okay) {
+        ALOGE("Trouble with virtual methods");
+        return false;
+    }
+
+    return true;
+}
+
+/* Perform intra-item verification on class_data_item. */
+static void* intraVerifyClassDataItem(const CheckState* state, void* ptr) {
+    const u1* data = (const u1*) ptr;
+    DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
+
+    if (classData == NULL) {
+        ALOGE("Unable to parse class_data_item");
+        return NULL;
+    }
+
+    bool okay = verifyClassDataItem0(state, classData);
+
+    free(classData);
+
+    if (!okay) {
+        return NULL;
+    }
+
+    return (void*) data;
+}
+
+/* Helper for crossVerifyClassDefItem() and
+ * crossVerifyClassDataItem(), which finds the type_idx of the definer
+ * of the first item in the data. */
+static u4 findFirstClassDataDefiner(const CheckState* state,
+        DexClassData* classData) {
+    if (classData->header.staticFieldsSize != 0) {
+        u4 fieldIdx = classData->staticFields[0].fieldIdx;
+        const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
+        return field->classIdx;
+    }
+
+    if (classData->header.instanceFieldsSize != 0) {
+        u4 fieldIdx = classData->instanceFields[0].fieldIdx;
+        const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
+        return field->classIdx;
+    }
+
+    if (classData->header.directMethodsSize != 0) {
+        u4 methodIdx = classData->directMethods[0].methodIdx;
+        const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
+        return meth->classIdx;
+    }
+
+    if (classData->header.virtualMethodsSize != 0) {
+        u4 methodIdx = classData->virtualMethods[0].methodIdx;
+        const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
+        return meth->classIdx;
+    }
+
+    return kDexNoIndex;
+}
+
+/* Perform cross-item verification of class_data_item. */
+static void* crossVerifyClassDataItem(const CheckState* state, void* ptr) {
+    const u1* data = (const u1*) ptr;
+    DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
+    u4 definingClass = findFirstClassDataDefiner(state, classData);
+    bool okay = true;
+    u4 i;
+
+    for (i = classData->header.staticFieldsSize; okay && (i > 0); /*i*/) {
+        i--;
+        const DexField* field = &classData->staticFields[i];
+        okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
+    }
+
+    for (i = classData->header.instanceFieldsSize; okay && (i > 0); /*i*/) {
+        i--;
+        const DexField* field = &classData->instanceFields[i];
+        okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
+    }
+
+    for (i = classData->header.directMethodsSize; okay && (i > 0); /*i*/) {
+        i--;
+        const DexMethod* meth = &classData->directMethods[i];
+        okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
+                kDexTypeCodeItem)
+            && verifyMethodDefiner(state, definingClass, meth->methodIdx);
+    }
+
+    for (i = classData->header.virtualMethodsSize; okay && (i > 0); /*i*/) {
+        i--;
+        const DexMethod* meth = &classData->virtualMethods[i];
+        okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
+                kDexTypeCodeItem)
+            && verifyMethodDefiner(state, definingClass, meth->methodIdx);
+    }
+
+    free(classData);
+
+    if (!okay) {
+        return NULL;
+    }
+
+    return (void*) data;
+}
+
+/* Helper for swapCodeItem(), which fills an array with all the valid
+ * handlerOff values for catch handlers and also verifies the handler
+ * contents. */
+static u4 setHandlerOffsAndVerify(const CheckState* state,
+        DexCode* code, u4 firstOffset, u4 handlersSize, u4* handlerOffs) {
+    const u1* fileEnd = state->fileEnd;
+    const u1* handlersBase = dexGetCatchHandlerData(code);
+    u4 offset = firstOffset;
+    bool okay = true;
+    u4 i;
+
+    for (i = 0; i < handlersSize; i++) {
+        const u1* ptr = handlersBase + offset;
+        int size = readAndVerifySignedLeb128(&ptr, fileEnd, &okay);
+        bool catchAll;
+
+        if (!okay) {
+            ALOGE("Bogus size");
+            return 0;
+        }
+
+        if ((size < -65536) || (size > 65536)) {
+            ALOGE("Invalid size: %d", size);
+            return 0;
+        }
+
+        if (size <= 0) {
+            catchAll = true;
+            size = -size;
+        } else {
+            catchAll = false;
+        }
+
+        handlerOffs[i] = offset;
+
+        while (size-- > 0) {
+            u4 typeIdx =
+                readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
+
+            if (!okay) {
+                ALOGE("Bogus type_idx");
+                return 0;
+            }
+
+            CHECK_INDEX(typeIdx, state->pHeader->typeIdsSize);
+
+            u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
+
+            if (!okay) {
+                ALOGE("Bogus addr");
+                return 0;
+            }
+
+            if (addr >= code->insnsSize) {
+                ALOGE("Invalid addr: %#x", addr);
+                return 0;
+            }
+        }
+
+        if (catchAll) {
+            u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
+
+            if (!okay) {
+                ALOGE("Bogus catch_all_addr");
+                return 0;
+            }
+
+            if (addr >= code->insnsSize) {
+                ALOGE("Invalid catch_all_addr: %#x", addr);
+                return 0;
+            }
+        }
+
+        offset = ptr - handlersBase;
+    }
+
+    return offset;
+}
+
+/* Helper for swapCodeItem(), which does all the try-catch related
+ * swapping and verification. */
+static void* swapTriesAndCatches(const CheckState* state, DexCode* code) {
+    const u1* encodedHandlers = dexGetCatchHandlerData(code);
+    const u1* encodedPtr = encodedHandlers;
+    bool okay = true;
+    u4 handlersSize =
+        readAndVerifyUnsignedLeb128(&encodedPtr, state->fileEnd, &okay);
+
+    if (!okay) {
+        ALOGE("Bogus handlers_size");
+        return NULL;
+    }
+
+    if ((handlersSize == 0) || (handlersSize >= 65536)) {
+        ALOGE("Invalid handlers_size: %d", handlersSize);
+        return NULL;
+    }
+
+    u4 handlerOffs[handlersSize]; // list of valid handlerOff values
+    u4 endOffset = setHandlerOffsAndVerify(state, code,
+            encodedPtr - encodedHandlers,
+            handlersSize, handlerOffs);
+
+    if (endOffset == 0) {
+        return NULL;
+    }
+
+    DexTry* tries = (DexTry*) dexGetTries(code);
+    u4 count = code->triesSize;
+    u4 lastEnd = 0;
+
+    const u4 sizeOfItem = (u4) sizeof(DexTry);
+    CHECK_LIST_SIZE(tries, count, sizeOfItem);
+
+    while (count--) {
+        u4 i;
+
+        SWAP_FIELD4(tries->startAddr);
+        SWAP_FIELD2(tries->insnCount);
+        SWAP_FIELD2(tries->handlerOff);
+
+        if (tries->startAddr < lastEnd) {
+            ALOGE("Out-of-order try");
+            return NULL;
+        }
+
+        if (tries->startAddr >= code->insnsSize) {
+            ALOGE("Invalid start_addr: %#x", tries->startAddr);
+            return NULL;
+        }
+
+        for (i = 0; i < handlersSize; i++) {
+            if (tries->handlerOff == handlerOffs[i]) {
+                break;
+            }
+        }
+
+        if (i == handlersSize) {
+            ALOGE("Bogus handler offset: %#x", tries->handlerOff);
+            return NULL;
+        }
+
+        lastEnd = tries->startAddr + tries->insnCount;
+
+        if (lastEnd > code->insnsSize) {
+            ALOGE("Invalid insn_count: %#x (end addr %#x)",
+                    tries->insnCount, lastEnd);
+            return NULL;
+        }
+
+        tries++;
+    }
+
+    return (u1*) encodedHandlers + endOffset;
+}
+
+/* Perform byte-swapping and intra-item verification on code_item. */
+static void* swapCodeItem(const CheckState* state, void* ptr) {
+    DexCode* item = (DexCode*) ptr;
+    u2* insns;
+    u4 count;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_FIELD2(item->registersSize);
+    SWAP_FIELD2(item->insSize);
+    SWAP_FIELD2(item->outsSize);
+    SWAP_FIELD2(item->triesSize);
+    SWAP_OFFSET4(item->debugInfoOff);
+    SWAP_FIELD4(item->insnsSize);
+
+    if (item->insSize > item->registersSize) {
+        ALOGE("insSize (%u) > registersSize (%u)", item->insSize,
+                item->registersSize);
+        return NULL;
+    }
+
+    if ((item->outsSize > 5) && (item->outsSize > item->registersSize)) {
+        /*
+         * It's okay for outsSize to be up to five, even if registersSize
+         * is smaller, since the short forms of method invocation allow
+         * repetition of a register multiple times within a single parameter
+         * list. Longer parameter lists, though, need to be represented
+         * in-order in the register file.
+         */
+        ALOGE("outsSize (%u) > registersSize (%u)", item->outsSize,
+                item->registersSize);
+        return NULL;
+    }
+
+    count = item->insnsSize;
+    insns = item->insns;
+
+    const u4 sizeOfItem = (u4) sizeof(u2);
+    CHECK_LIST_SIZE(insns, count, sizeOfItem);
+
+    while (count--) {
+        *insns = SWAP2(*insns);
+        insns++;
+    }
+
+    if (item->triesSize == 0) {
+        ptr = insns;
+    } else {
+        if ((((uintptr_t) insns) & 3) != 0) {
+            // Four-byte alignment for the tries. Verify the spacer is a 0.
+            if (*insns != 0) {
+                ALOGE("Non-zero padding: %#x", (u4) *insns);
+                return NULL;
+            }
+        }
+
+        ptr = swapTriesAndCatches(state, item);
+    }
+
+    return ptr;
+}
+
+/* Perform intra-item verification on string_data_item. */
+static void* intraVerifyStringDataItem(const CheckState* state, void* ptr) {
+    const u1* fileEnd = state->fileEnd;
+    const u1* data = (const u1*) ptr;
+    bool okay = true;
+    u4 utf16Size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+    u4 i;
+
+    if (!okay) {
+        ALOGE("Bogus utf16_size");
+        return NULL;
+    }
+
+    for (i = 0; i < utf16Size; i++) {
+        if (data >= fileEnd) {
+            ALOGE("String data would go beyond end-of-file");
+            return NULL;
+        }
+
+        u1 byte1 = *(data++);
+
+        // Switch on the high four bits.
+        switch (byte1 >> 4) {
+            case 0x00: {
+                // Special case of bit pattern 0xxx.
+                if (byte1 == 0) {
+                    ALOGE("String shorter than indicated utf16_size %#x",
+                            utf16Size);
+                    return NULL;
+                }
+                break;
+            }
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07: {
+                // Bit pattern 0xxx. No need for any extra bytes or checks.
+                break;
+            }
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0f: {
+                /*
+                 * Bit pattern 10xx or 1111, which are illegal start bytes.
+                 * Note: 1111 is valid for normal UTF-8, but not the
+                 * modified UTF-8 used here.
+                 */
+                ALOGE("Illegal start byte %#x", byte1);
+                return NULL;
+            }
+            case 0x0e: {
+                // Bit pattern 1110, so there are two additional bytes.
+                u1 byte2 = *(data++);
+                if ((byte2 & 0xc0) != 0x80) {
+                    ALOGE("Illegal continuation byte %#x", byte2);
+                    return NULL;
+                }
+                u1 byte3 = *(data++);
+                if ((byte3 & 0xc0) != 0x80) {
+                    ALOGE("Illegal continuation byte %#x", byte3);
+                    return NULL;
+                }
+                u2 value = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6)
+                    | (byte3 & 0x3f);
+                if (value < 0x800) {
+                    ALOGE("Illegal representation for value %x", value);
+                    return NULL;
+                }
+                break;
+            }
+            case 0x0c:
+            case 0x0d: {
+                // Bit pattern 110x, so there is one additional byte.
+                u1 byte2 = *(data++);
+                if ((byte2 & 0xc0) != 0x80) {
+                    ALOGE("Illegal continuation byte %#x", byte2);
+                    return NULL;
+                }
+                u2 value = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);
+                if ((value != 0) && (value < 0x80)) {
+                    ALOGE("Illegal representation for value %x", value);
+                    return NULL;
+                }
+                break;
+            }
+        }
+    }
+
+    if (*(data++) != '\0') {
+        ALOGE("String longer than indicated utf16_size %#x", utf16Size);
+        return NULL;
+    }
+
+    return (void*) data;
+}
+
+/* Perform intra-item verification on debug_info_item. */
+static void* intraVerifyDebugInfoItem(const CheckState* state, void* ptr) {
+    const u1* fileEnd = state->fileEnd;
+    const u1* data = (const u1*) ptr;
+    bool okay = true;
+    u4 i;
+
+    readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+    if (!okay) {
+        ALOGE("Bogus line_start");
+        return NULL;
+    }
+
+    u4 parametersSize =
+        readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+    if (!okay) {
+        ALOGE("Bogus parameters_size");
+        return NULL;
+    }
+
+    if (parametersSize > 65536) {
+        ALOGE("Invalid parameters_size: %#x", parametersSize);
+        return NULL;
+    }
+
+    for (i = 0; i < parametersSize; i++) {
+        u4 parameterName =
+            readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+        if (!okay) {
+            ALOGE("Bogus parameter_name");
+            return NULL;
+        }
+
+        if (parameterName != 0) {
+            parameterName--;
+            CHECK_INDEX(parameterName, state->pHeader->stringIdsSize);
+        }
+    }
+
+    bool done = false;
+    while (!done) {
+        u1 opcode = *(data++);
+
+        switch (opcode) {
+            case DBG_END_SEQUENCE: {
+                done = true;
+                break;
+            }
+            case DBG_ADVANCE_PC: {
+                readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                break;
+            }
+            case DBG_ADVANCE_LINE: {
+                readAndVerifySignedLeb128(&data, fileEnd, &okay);
+                break;
+            }
+            case DBG_START_LOCAL: {
+                u4 idx;
+                u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (regNum >= 65536) {
+                    okay = false;
+                    break;
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                break;
+            }
+            case DBG_END_LOCAL:
+            case DBG_RESTART_LOCAL: {
+                u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (regNum >= 65536) {
+                    okay = false;
+                    break;
+                }
+                break;
+            }
+            case DBG_START_LOCAL_EXTENDED: {
+                u4 idx;
+                u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (regNum >= 65536) {
+                    okay = false;
+                    break;
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                break;
+            }
+            case DBG_SET_FILE: {
+                u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                break;
+            }
+            default: {
+                // No arguments to parse for anything else.
+            }
+        }
+
+        if (!okay) {
+            ALOGE("Bogus syntax for opcode %02x", opcode);
+            return NULL;
+        }
+    }
+
+    return (void*) data;
+}
+
+/* defined below */
+static const u1* verifyEncodedValue(const CheckState* state, const u1* data,
+        bool crossVerify);
+static const u1* verifyEncodedAnnotation(const CheckState* state,
+        const u1* data, bool crossVerify);
+
+/* Helper for verifyEncodedValue(), which reads a 1- to 4- byte unsigned
+ * little endian value. */
+static u4 readUnsignedLittleEndian(const CheckState* state, const u1** pData,
+        u4 size) {
+    const u1* data = *pData;
+    u4 result = 0;
+    u4 i;
+
+    CHECK_PTR_RANGE(data, data + size);
+
+    for (i = 0; i < size; i++) {
+        result |= ((u4) *(data++)) << (i * 8);
+    }
+
+    *pData = data;
+    return result;
+}
+
+/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
+ * verifies an encoded_array. */
+static const u1* verifyEncodedArray(const CheckState* state,
+        const u1* data, bool crossVerify) {
+    bool okay = true;
+    u4 size = readAndVerifyUnsignedLeb128(&data, state->fileEnd, &okay);
+
+    if (!okay) {
+        ALOGE("Bogus encoded_array size");
+        return NULL;
+    }
+
+    while (size--) {
+        data = verifyEncodedValue(state, data, crossVerify);
+        if (data == NULL) {
+            ALOGE("Bogus encoded_array value");
+            return NULL;
+        }
+    }
+
+    return data;
+}
+
+/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
+ * verifies an encoded_value. */
+static const u1* verifyEncodedValue(const CheckState* state,
+        const u1* data, bool crossVerify) {
+    CHECK_PTR_RANGE(data, data + 1);
+
+    u1 headerByte = *(data++);
+    u4 valueType = headerByte & kDexAnnotationValueTypeMask;
+    u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
+
+    switch (valueType) {
+        case kDexAnnotationByte: {
+            if (valueArg != 0) {
+                ALOGE("Bogus byte size %#x", valueArg);
+                return NULL;
+            }
+            data++;
+            break;
+        }
+        case kDexAnnotationShort:
+        case kDexAnnotationChar: {
+            if (valueArg > 1) {
+                ALOGE("Bogus char/short size %#x", valueArg);
+                return NULL;
+            }
+            data += valueArg + 1;
+            break;
+        }
+        case kDexAnnotationInt:
+        case kDexAnnotationFloat: {
+            if (valueArg > 3) {
+                ALOGE("Bogus int/float size %#x", valueArg);
+                return NULL;
+            }
+            data += valueArg + 1;
+            break;
+        }
+        case kDexAnnotationLong:
+        case kDexAnnotationDouble: {
+            data += valueArg + 1;
+            break;
+        }
+        case kDexAnnotationString: {
+            if (valueArg > 3) {
+                ALOGE("Bogus string size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+            break;
+        }
+        case kDexAnnotationType: {
+            if (valueArg > 3) {
+                ALOGE("Bogus type size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->typeIdsSize);
+            break;
+        }
+        case kDexAnnotationField:
+        case kDexAnnotationEnum: {
+            if (valueArg > 3) {
+                ALOGE("Bogus field/enum size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->fieldIdsSize);
+            break;
+        }
+        case kDexAnnotationMethod: {
+            if (valueArg > 3) {
+                ALOGE("Bogus method size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->methodIdsSize);
+            break;
+        }
+        case kDexAnnotationArray: {
+            if (valueArg != 0) {
+                ALOGE("Bogus array value_arg %#x", valueArg);
+                return NULL;
+            }
+            data = verifyEncodedArray(state, data, crossVerify);
+            break;
+        }
+        case kDexAnnotationAnnotation: {
+            if (valueArg != 0) {
+                ALOGE("Bogus annotation value_arg %#x", valueArg);
+                return NULL;
+            }
+            data = verifyEncodedAnnotation(state, data, crossVerify);
+            break;
+        }
+        case kDexAnnotationNull: {
+            if (valueArg != 0) {
+                ALOGE("Bogus null value_arg %#x", valueArg);
+                return NULL;
+            }
+            // Nothing else to do for this type.
+            break;
+        }
+        case kDexAnnotationBoolean: {
+            if (valueArg > 1) {
+                ALOGE("Bogus boolean value_arg %#x", valueArg);
+                return NULL;
+            }
+            // Nothing else to do for this type.
+            break;
+        }
+        default: {
+            ALOGE("Bogus value_type %#x", valueType);
+            return NULL;
+        }
+    }
+
+    return data;
+}
+
+/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
+ * verifies an encoded_annotation. */
+static const u1* verifyEncodedAnnotation(const CheckState* state,
+        const u1* data, bool crossVerify) {
+    const u1* fileEnd = state->fileEnd;
+    bool okay = true;
+    u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+    if (!okay) {
+        ALOGE("Bogus encoded_annotation type_idx");
+        return NULL;
+    }
+
+    CHECK_INDEX(idx, state->pHeader->typeIdsSize);
+
+    if (crossVerify) {
+        const char* descriptor = dexStringByTypeIdx(state->pDexFile, idx);
+        if (!dexIsClassDescriptor(descriptor)) {
+            ALOGE("Bogus annotation type: '%s'", descriptor);
+            return NULL;
+        }
+    }
+
+    u4 size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+    u4 lastIdx = 0;
+    bool first = true;
+
+    if (!okay) {
+        ALOGE("Bogus encoded_annotation size");
+        return NULL;
+    }
+
+    while (size--) {
+        idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+        if (!okay) {
+            ALOGE("Bogus encoded_annotation name_idx");
+            return NULL;
+        }
+
+        CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+
+        if (crossVerify) {
+            const char* name = dexStringById(state->pDexFile, idx);
+            if (!dexIsValidMemberName(name)) {
+                ALOGE("Bogus annotation member name: '%s'", name);
+                return NULL;
+            }
+        }
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= idx) {
+            ALOGE("Out-of-order encoded_annotation name_idx: %#x then %#x",
+                    lastIdx, idx);
+            return NULL;
+        }
+
+        data = verifyEncodedValue(state, data, crossVerify);
+        lastIdx = idx;
+
+        if (data == NULL) {
+            return NULL;
+        }
+    }
+
+    return data;
+}
+
+/* Perform intra-item verification on encoded_array_item. */
+static void* intraVerifyEncodedArrayItem(const CheckState* state, void* ptr) {
+    return (void*) verifyEncodedArray(state, (const u1*) ptr, false);
+}
+
+/* Perform intra-item verification on annotation_item. */
+static void* intraVerifyAnnotationItem(const CheckState* state, void* ptr) {
+    const u1* data = (const u1*) ptr;
+
+    CHECK_PTR_RANGE(data, data + 1);
+
+    switch (*(data++)) {
+        case kDexVisibilityBuild:
+        case kDexVisibilityRuntime:
+        case kDexVisibilitySystem: {
+            break;
+        }
+        default: {
+            ALOGE("Bogus annotation visibility: %#x", *data);
+            return NULL;
+        }
+    }
+
+    return (void*) verifyEncodedAnnotation(state, data, false);
+}
+
+/* Perform cross-item verification on annotation_item. */
+static void* crossVerifyAnnotationItem(const CheckState* state, void* ptr) {
+    const u1* data = (const u1*) ptr;
+
+    // Skip the visibility byte.
+    data++;
+
+    return (void*) verifyEncodedAnnotation(state, data, true);
+}
+
+
+
+
+/*
+ * Function to visit an individual top-level item type.
+ */
+typedef void* ItemVisitorFunction(const CheckState* state, void* ptr);
+
+/*
+ * Iterate over all the items in a section, optionally updating the
+ * data map (done if mapType is passed as non-negative). The section
+ * must consist of concatenated items of the same type.
+ */
+static bool iterateSectionWithOptionalUpdate(CheckState* state,
+        u4 offset, u4 count, ItemVisitorFunction* func, u4 alignment,
+        u4* nextOffset, int mapType) {
+    u4 alignmentMask = alignment - 1;
+    u4 i;
+
+    state->previousItem = NULL;
+
+    for (i = 0; i < count; i++) {
+        u4 newOffset = (offset + alignmentMask) & ~alignmentMask;
+        u1* ptr = (u1*) filePointer(state, newOffset);
+
+        if (offset < newOffset) {
+            ptr = (u1*) filePointer(state, offset);
+            if (offset < newOffset) {
+                CHECK_OFFSET_RANGE(offset, newOffset);
+                while (offset < newOffset) {
+                    if (*ptr != '\0') {
+                        ALOGE("Non-zero padding 0x%02x @ %x", *ptr, offset);
+                        return false;
+                    }
+                    ptr++;
+                    offset++;
+                }
+            }
+        }
+
+        u1* newPtr = (u1*) func(state, ptr);
+        newOffset = fileOffset(state, newPtr);
+
+        if (newPtr == NULL) {
+            ALOGE("Trouble with item %d @ offset %#x", i, offset);
+            return false;
+        }
+
+        if (newOffset > state->fileLen) {
+            ALOGE("Item %d @ offset %#x ends out of bounds", i, offset);
+            return false;
+        }
+
+        if (mapType >= 0) {
+            dexDataMapAdd(state->pDataMap, offset, mapType);
+        }
+
+        state->previousItem = ptr;
+        offset = newOffset;
+    }
+
+    if (nextOffset != NULL) {
+        *nextOffset = offset;
+    }
+
+    return true;
+}
+
+/*
+ * Iterate over all the items in a section. The section must consist of
+ * concatenated items of the same type. This variant will not update the data
+ * map.
+ */
+static bool iterateSection(CheckState* state, u4 offset, u4 count,
+        ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
+    return iterateSectionWithOptionalUpdate(state, offset, count, func,
+            alignment, nextOffset, -1);
+}
+
+/*
+ * Like iterateSection(), but also check that the offset and count match
+ * a given pair of expected values.
+ */
+static bool checkBoundsAndIterateSection(CheckState* state,
+        u4 offset, u4 count, u4 expectedOffset, u4 expectedCount,
+        ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
+    if (offset != expectedOffset) {
+        ALOGE("Bogus offset for section: got %#x; expected %#x",
+                offset, expectedOffset);
+        return false;
+    }
+
+    if (count != expectedCount) {
+        ALOGE("Bogus size for section: got %#x; expected %#x",
+                count, expectedCount);
+        return false;
+    }
+
+    return iterateSection(state, offset, count, func, alignment, nextOffset);
+}
+
+/*
+ * Like iterateSection(), but also update the data section map and
+ * check that all the items fall within the data section.
+ */
+static bool iterateDataSection(CheckState* state, u4 offset, u4 count,
+        ItemVisitorFunction* func, u4 alignment, u4* nextOffset, int mapType) {
+    u4 dataStart = state->pHeader->dataOff;
+    u4 dataEnd = dataStart + state->pHeader->dataSize;
+
+    assert(nextOffset != NULL);
+
+    if ((offset < dataStart) || (offset >= dataEnd)) {
+        ALOGE("Bogus offset for data subsection: %#x", offset);
+        return false;
+    }
+
+    if (!iterateSectionWithOptionalUpdate(state, offset, count, func,
+                    alignment, nextOffset, mapType)) {
+        return false;
+    }
+
+    if (*nextOffset > dataEnd) {
+        ALOGE("Out-of-bounds end of data subsection: %#x", *nextOffset);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Byte-swap all items in the given map except the header and the map
+ * itself, both of which should have already gotten swapped. This also
+ * does all possible intra-item verification, that is, verification
+ * that doesn't need to assume the sanctity of the contents of *other*
+ * items. The intra-item limitation is because at the time an item is
+ * asked to verify itself, it can't assume that the items it refers to
+ * have been byte-swapped and verified.
+ */
+static bool swapEverythingButHeaderAndMap(CheckState* state,
+        DexMapList* pMap) {
+    const DexMapItem* item = pMap->list;
+    u4 lastOffset = 0;
+    u4 count = pMap->size;
+    bool okay = true;
+
+    while (okay && count--) {
+        u4 sectionOffset = item->offset;
+        u4 sectionCount = item->size;
+        u2 type = item->type;
+
+        if (lastOffset < sectionOffset) {
+            CHECK_OFFSET_RANGE(lastOffset, sectionOffset);
+            const u1* ptr = (const u1*) filePointer(state, lastOffset);
+            while (lastOffset < sectionOffset) {
+                if (*ptr != '\0') {
+                    ALOGE("Non-zero padding 0x%02x before section start @ %x",
+                            *ptr, lastOffset);
+                    okay = false;
+                    break;
+                }
+                ptr++;
+                lastOffset++;
+            }
+        } else if (lastOffset > sectionOffset) {
+            ALOGE("Section overlap or out-of-order map: %x, %x",
+                    lastOffset, sectionOffset);
+            okay = false;
+        }
+
+        if (!okay) {
+            break;
+        }
+
+        switch (type) {
+            case kDexTypeHeaderItem: {
+                /*
+                 * The header got swapped very early on, but do some
+                 * additional sanity checking here.
+                 */
+                okay = checkHeaderSection(state, sectionOffset, sectionCount,
+                        &lastOffset);
+                break;
+            }
+            case kDexTypeStringIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->stringIdsOff,
+                        state->pHeader->stringIdsSize, swapStringIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeTypeIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->typeIdsOff,
+                        state->pHeader->typeIdsSize, swapTypeIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeProtoIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->protoIdsOff,
+                        state->pHeader->protoIdsSize, swapProtoIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeFieldIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->fieldIdsOff,
+                        state->pHeader->fieldIdsSize, swapFieldIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeMethodIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->methodIdsOff,
+                        state->pHeader->methodIdsSize, swapMethodIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeClassDefItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->classDefsOff,
+                        state->pHeader->classDefsSize, swapClassDefItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeMapList: {
+                /*
+                 * The map section was swapped early on, but do some
+                 * additional sanity checking here.
+                 */
+                okay = checkMapSection(state, sectionOffset, sectionCount,
+                        &lastOffset);
+                break;
+            }
+            case kDexTypeTypeList: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapTypeList, sizeof(u4), &lastOffset, type);
+                break;
+            }
+            case kDexTypeAnnotationSetRefList: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapAnnotationSetRefList, sizeof(u4), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeAnnotationSetItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapAnnotationSetItem, sizeof(u4), &lastOffset, type);
+                break;
+            }
+            case kDexTypeClassDataItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyClassDataItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeCodeItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapCodeItem, sizeof(u4), &lastOffset, type);
+                break;
+            }
+            case kDexTypeStringDataItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyStringDataItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeDebugInfoItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyDebugInfoItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeAnnotationItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyAnnotationItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeEncodedArrayItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyEncodedArrayItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeAnnotationsDirectoryItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapAnnotationsDirectoryItem, sizeof(u4), &lastOffset,
+                        type);
+                break;
+            }
+            default: {
+                ALOGE("Unknown map item type %04x", type);
+                return false;
+            }
+        }
+
+        if (!okay) {
+            ALOGE("Swap of section type %04x failed", type);
+        }
+
+        item++;
+    }
+
+    return okay;
+}
+
+/*
+ * Perform cross-item verification on everything that needs it. This
+ * pass is only called after all items are byte-swapped and
+ * intra-verified (checked for internal consistency).
+ */
+static bool crossVerifyEverything(CheckState* state, DexMapList* pMap)
+{
+    const DexMapItem* item = pMap->list;
+    u4 count = pMap->size;
+    bool okay = true;
+
+    while (okay && count--) {
+        u4 sectionOffset = item->offset;
+        u4 sectionCount = item->size;
+
+        switch (item->type) {
+            case kDexTypeHeaderItem:
+            case kDexTypeMapList:
+            case kDexTypeTypeList:
+            case kDexTypeCodeItem:
+            case kDexTypeStringDataItem:
+            case kDexTypeDebugInfoItem:
+            case kDexTypeAnnotationItem:
+            case kDexTypeEncodedArrayItem: {
+                // There is no need for cross-item verification for these.
+                break;
+            }
+            case kDexTypeStringIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyStringIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeTypeIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyTypeIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeProtoIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyProtoIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeFieldIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyFieldIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeMethodIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyMethodIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeClassDefItem: {
+                // Allocate (on the stack) the "observed class_def" bits.
+                size_t arraySize = calcDefinedClassBitsSize(state);
+                u4 definedClassBits[arraySize];
+                memset(definedClassBits, 0, arraySize * sizeof(u4));
+                state->pDefinedClassBits = definedClassBits;
+
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyClassDefItem, sizeof(u4), NULL);
+
+                state->pDefinedClassBits = NULL;
+                break;
+            }
+            case kDexTypeAnnotationSetRefList: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyAnnotationSetRefList, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeAnnotationSetItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyAnnotationSetItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeClassDataItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyClassDataItem, sizeof(u1), NULL);
+                break;
+            }
+            case kDexTypeAnnotationsDirectoryItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyAnnotationsDirectoryItem, sizeof(u4), NULL);
+                break;
+            }
+            default: {
+                ALOGE("Unknown map item type %04x", item->type);
+                return false;
+            }
+        }
+
+        if (!okay) {
+            ALOGE("Cross-item verify of section type %04x failed",
+                    item->type);
+        }
+
+        item++;
+    }
+
+    return okay;
+}
+
+/* (documented in header file) */
+bool dexHasValidMagic(const DexHeader* pHeader)
+{
+    const u1* magic = pHeader->magic;
+    const u1* version = &magic[4];
+
+    if (memcmp(magic, DEX_MAGIC, 4) != 0) {
+        ALOGE("ERROR: unrecognized magic number (%02x %02x %02x %02x)",
+            magic[0], magic[1], magic[2], magic[3]);
+        return false;
+    }
+
+    if ((memcmp(version, DEX_MAGIC_VERS, 4) != 0) &&
+            (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0)) {
+        /*
+         * Magic was correct, but this is an unsupported older or
+         * newer format variant.
+         */
+        ALOGE("ERROR: unsupported dex version (%02x %02x %02x %02x)",
+            version[0], version[1], version[2], version[3]);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Fix the byte ordering of all fields in the DEX file, and do
+ * structural verification. This is only required for code that opens
+ * "raw" DEX files, such as the DEX optimizer.
+ *
+ * Returns 0 on success, nonzero on failure.
+ */
+int dexSwapAndVerify(u1* addr, int len)
+{
+    DexHeader* pHeader;
+    CheckState state;
+    bool okay = true;
+
+    memset(&state, 0, sizeof(state));
+    ALOGV("+++ swapping and verifying");
+
+    /*
+     * Note: The caller must have verified that "len" is at least as
+     * large as a dex file header.
+     */
+    pHeader = (DexHeader*) addr;
+
+    if (!dexHasValidMagic(pHeader)) {
+        okay = false;
+    }
+
+    if (okay) {
+        int expectedLen = (int) SWAP4(pHeader->fileSize);
+        if (len < expectedLen) {
+            ALOGE("ERROR: Bad length: expected %d, got %d", expectedLen, len);
+            okay = false;
+        } else if (len != expectedLen) {
+            ALOGW("WARNING: Odd length: expected %d, got %d", expectedLen,
+                    len);
+            // keep going
+        }
+    }
+
+    if (okay) {
+        /*
+         * Compute the adler32 checksum and compare it to what's stored in
+         * the file.  This isn't free, but chances are good that we just
+         * unpacked this from a jar file and have all of the pages sitting
+         * in memory, so it's pretty quick.
+         *
+         * This might be a big-endian system, so we need to do this before
+         * we byte-swap the header.
+         */
+        uLong adler = adler32(0L, Z_NULL, 0);
+        const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
+        u4 storedFileSize = SWAP4(pHeader->fileSize);
+        u4 expectedChecksum = SWAP4(pHeader->checksum);
+
+        adler = adler32(adler, ((const u1*) pHeader) + nonSum,
+                    storedFileSize - nonSum);
+
+        if (adler != expectedChecksum) {
+            ALOGE("ERROR: bad checksum (%08lx, expected %08x)",
+                adler, expectedChecksum);
+            okay = false;
+        }
+    }
+
+    if (okay) {
+        state.fileStart = addr;
+        state.fileEnd = addr + len;
+        state.fileLen = len;
+        state.pDexFile = NULL;
+        state.pDataMap = NULL;
+        state.pDefinedClassBits = NULL;
+        state.previousItem = NULL;
+
+        /*
+         * Swap the header and check the contents.
+         */
+        okay = swapDexHeader(&state, pHeader);
+    }
+
+    if (okay) {
+        state.pHeader = pHeader;
+
+        if (pHeader->headerSize < sizeof(DexHeader)) {
+            ALOGE("ERROR: Small header size %d, struct %d",
+                    pHeader->headerSize, (int) sizeof(DexHeader));
+            okay = false;
+        } else if (pHeader->headerSize > sizeof(DexHeader)) {
+            ALOGW("WARNING: Large header size %d, struct %d",
+                    pHeader->headerSize, (int) sizeof(DexHeader));
+            // keep going?
+        }
+    }
+
+    if (okay) {
+        /*
+         * Look for the map. Swap it and then use it to find and swap
+         * everything else.
+         */
+        if (pHeader->mapOff != 0) {
+            DexFile dexFile;
+            DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
+
+            okay = okay && swapMap(&state, pDexMap);
+            okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
+
+            dexFileSetupBasicPointers(&dexFile, addr);
+            state.pDexFile = &dexFile;
+
+            okay = okay && crossVerifyEverything(&state, pDexMap);
+        } else {
+            ALOGE("ERROR: No map found; impossible to byte-swap and verify");
+            okay = false;
+        }
+    }
+
+    if (!okay) {
+        ALOGE("ERROR: Byte swap + verify failed");
+    }
+
+    if (state.pDataMap != NULL) {
+        dexDataMapFree(state.pDataMap);
+    }
+
+    return !okay;       // 0 == success
+}
+
+/*
+ * Detect the file type of the given memory buffer via magic number.
+ * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
+ * but return successfully on an optimized DEX file, and report an
+ * error for all other cases.
+ *
+ * Returns 0 on success, nonzero on failure.
+ */
+int dexSwapAndVerifyIfNecessary(u1* addr, int len)
+{
+    if (memcmp(addr, DEX_OPT_MAGIC, 4) == 0) {
+        // It is an optimized dex file.
+        return 0;
+    }
+
+    if (memcmp(addr, DEX_MAGIC, 4) == 0) {
+        // It is an unoptimized dex file.
+        return dexSwapAndVerify(addr, len);
+    }
+
+    ALOGE("ERROR: Bad magic number (0x%02x %02x %02x %02x)",
+             addr[0], addr[1], addr[2], addr[3]);
+
+    return 1;
+}
diff --git a/libdex/DexUtf.cpp b/libdex/DexUtf.cpp
new file mode 100644
index 0000000..df49d18
--- /dev/null
+++ b/libdex/DexUtf.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Validate and manipulate MUTF-8 encoded string data.
+ */
+
+#include "DexUtf.h"
+
+/* Compare two '\0'-terminated modified UTF-8 strings, using Unicode
+ * code point values for comparison. This treats different encodings
+ * for the same code point as equivalent, except that only a real '\0'
+ * byte is considered the string terminator. The return value is as
+ * for strcmp(). */
+int dexUtf8Cmp(const char* s1, const char* s2) {
+    for (;;) {
+        if (*s1 == '\0') {
+            if (*s2 == '\0') {
+                return 0;
+            }
+            return -1;
+        } else if (*s2 == '\0') {
+            return 1;
+        }
+
+        int utf1 = dexGetUtf16FromUtf8(&s1);
+        int utf2 = dexGetUtf16FromUtf8(&s2);
+        int diff = utf1 - utf2;
+
+        if (diff != 0) {
+            return diff;
+        }
+    }
+}
+
+/* for dexIsValidMemberNameUtf8(), a bit vector indicating valid low ascii */
+u4 DEX_MEMBER_VALID_LOW_ASCII[4] = {
+    0x00000000, // 00..1f low control characters; nothing valid
+    0x03ff2010, // 20..3f digits and symbols; valid: '0'..'9', '$', '-'
+    0x87fffffe, // 40..5f uppercase etc.; valid: 'A'..'Z', '_'
+    0x07fffffe  // 60..7f lowercase etc.; valid: 'a'..'z'
+};
+
+/* Helper for dexIsValidMemberNameUtf8(); do not call directly. */
+bool dexIsValidMemberNameUtf8_0(const char** pUtf8Ptr) {
+    /*
+     * It's a multibyte encoded character. Decode it and analyze. We
+     * accept anything that isn't (a) an improperly encoded low value,
+     * (b) an improper surrogate pair, (c) an encoded '\0', (d) a high
+     * control character, or (e) a high space, layout, or special
+     * character (U+00a0, U+2000..U+200f, U+2028..U+202f,
+     * U+fff0..U+ffff). This is all specified in the dex format
+     * document.
+     */
+
+    u2 utf16 = dexGetUtf16FromUtf8(pUtf8Ptr);
+
+    // Perform follow-up tests based on the high 8 bits.
+    switch (utf16 >> 8) {
+        case 0x00: {
+            // It's only valid if it's above the ISO-8859-1 high space (0xa0).
+            return (utf16 > 0x00a0);
+        }
+        case 0xd8:
+        case 0xd9:
+        case 0xda:
+        case 0xdb: {
+            /*
+             * It's a leading surrogate. Check to see that a trailing
+             * surrogate follows.
+             */
+            utf16 = dexGetUtf16FromUtf8(pUtf8Ptr);
+            return (utf16 >= 0xdc00) && (utf16 <= 0xdfff);
+        }
+        case 0xdc:
+        case 0xdd:
+        case 0xde:
+        case 0xdf: {
+            // It's a trailing surrogate, which is not valid at this point.
+            return false;
+        }
+        case 0x20:
+        case 0xff: {
+            // It's in the range that has spaces, controls, and specials.
+            switch (utf16 & 0xfff8) {
+                case 0x2000:
+                case 0x2008:
+                case 0x2028:
+                case 0xfff0:
+                case 0xfff8: {
+                    return false;
+                }
+            }
+            break;
+        }
+    }
+
+    return true;
+}
+
+/* Return whether the given string is a valid field or method name. */
+bool dexIsValidMemberName(const char* s) {
+    bool angleName = false;
+
+    switch (*s) {
+        case '\0': {
+            // The empty string is not a valid name.
+            return false;
+        }
+        case '<': {
+            /*
+             * '<' is allowed only at the start of a name, and if present,
+             * means that the name must end with '>'.
+             */
+            angleName = true;
+            s++;
+            break;
+        }
+    }
+
+    for (;;) {
+        switch (*s) {
+            case '\0': {
+                return !angleName;
+            }
+            case '>': {
+                return angleName && s[1] == '\0';
+            }
+        }
+        if (!dexIsValidMemberNameUtf8(&s)) {
+            return false;
+        }
+    }
+}
+
+/* Helper for validating type descriptors and class names, which is parametric
+ * with respect to type vs. class and dot vs. slash. */
+static bool isValidTypeDescriptorOrClassName(const char* s, bool isClassName,
+        bool dotSeparator) {
+    int arrayCount = 0;
+
+    while (*s == '[') {
+        arrayCount++;
+        s++;
+    }
+
+    if (arrayCount > 255) {
+        // Arrays may have no more than 255 dimensions.
+        return false;
+    }
+
+    if (arrayCount != 0) {
+        /*
+         * If we're looking at an array of some sort, then it doesn't
+         * matter if what is being asked for is a class name; the
+         * format looks the same as a type descriptor in that case, so
+         * treat it as such.
+         */
+        isClassName = false;
+    }
+
+    if (!isClassName) {
+        /*
+         * We are looking for a descriptor. Either validate it as a
+         * single-character primitive type, or continue on to check the
+         * embedded class name (bracketed by "L" and ";").
+         */
+        switch (*(s++)) {
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'F':
+            case 'I':
+            case 'J':
+            case 'S':
+            case 'Z': {
+                // These are all single-character descriptors for primitive types.
+                return (*s == '\0');
+            }
+            case 'V': {
+                // Non-array void is valid, but you can't have an array of void.
+                return (arrayCount == 0) && (*s == '\0');
+            }
+            case 'L': {
+                // Class name: Break out and continue below.
+                break;
+            }
+            default: {
+                // Oddball descriptor character.
+                return false;
+            }
+        }
+    }
+
+    /*
+     * We just consumed the 'L' that introduces a class name as part
+     * of a type descriptor, or we are looking for an unadorned class
+     * name.
+     */
+
+    bool sepOrFirst = true; // first character or just encountered a separator.
+    for (;;) {
+        u1 c = (u1) *s;
+        switch (c) {
+            case '\0': {
+                /*
+                 * Premature end for a type descriptor, but valid for
+                 * a class name as long as we haven't encountered an
+                 * empty component (including the degenerate case of
+                 * the empty string "").
+                 */
+                return isClassName && !sepOrFirst;
+            }
+            case ';': {
+                /*
+                 * Invalid character for a class name, but the
+                 * legitimate end of a type descriptor. In the latter
+                 * case, make sure that this is the end of the string
+                 * and that it doesn't end with an empty component
+                 * (including the degenerate case of "L;").
+                 */
+                return !isClassName && !sepOrFirst && (s[1] == '\0');
+            }
+            case '/':
+            case '.': {
+                if (dotSeparator != (c == '.')) {
+                    // The wrong separator character.
+                    return false;
+                }
+                if (sepOrFirst) {
+                    // Separator at start or two separators in a row.
+                    return false;
+                }
+                sepOrFirst = true;
+                s++;
+                break;
+            }
+            default: {
+                if (!dexIsValidMemberNameUtf8(&s)) {
+                    return false;
+                }
+                sepOrFirst = false;
+                break;
+            }
+        }
+    }
+}
+
+/* Return whether the given string is a valid type descriptor. */
+bool dexIsValidTypeDescriptor(const char* s) {
+    return isValidTypeDescriptorOrClassName(s, false, false);
+}
+
+/* (documented in header) */
+bool dexIsValidClassName(const char* s, bool dotSeparator) {
+    return isValidTypeDescriptorOrClassName(s, true, dotSeparator);
+}
+
+/* Return whether the given string is a valid reference descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for a class or array and not a primitive type. */
+bool dexIsReferenceDescriptor(const char* s) {
+    if (!dexIsValidTypeDescriptor(s)) {
+        return false;
+    }
+
+    return (s[0] == 'L') || (s[0] == '[');
+}
+
+/* Return whether the given string is a valid class descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for a class and not an array or primitive type. */
+bool dexIsClassDescriptor(const char* s) {
+    if (!dexIsValidTypeDescriptor(s)) {
+        return false;
+    }
+
+    return s[0] == 'L';
+}
+
+/* Return whether the given string is a valid field type descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for anything but "void". */
+bool dexIsFieldDescriptor(const char* s) {
+    if (!dexIsValidTypeDescriptor(s)) {
+        return false;
+    }
+
+    return s[0] != 'V';
+}
+
diff --git a/libdex/DexUtf.h b/libdex/DexUtf.h
new file mode 100644
index 0000000..cb3d919
--- /dev/null
+++ b/libdex/DexUtf.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Validate and manipulate MUTF-8 (modified UTF-8) encoded string data.
+ */
+
+#ifndef LIBDEX_DEXUTF_H_
+#define LIBDEX_DEXUTF_H_
+
+#include "DexFile.h"
+
+/*
+ * Retrieve the next UTF-16 character from a UTF-8 string.
+ *
+ * Advances "*pUtf8Ptr" to the start of the next character.
+ *
+ * WARNING: If a string is corrupted by dropping a '\0' in the middle
+ * of a 3-byte sequence, you can end up overrunning the buffer with
+ * reads (and possibly with the writes if the length was computed and
+ * cached before the damage). For performance reasons, this function
+ * assumes that the string being parsed is known to be valid (e.g., by
+ * already being verified). Most strings we process here are coming
+ * out of dex files or other internal translations, so the only real
+ * risk comes from the JNI NewStringUTF call.
+ */
+DEX_INLINE u2 dexGetUtf16FromUtf8(const char** pUtf8Ptr)
+{
+    unsigned int one, two, three;
+
+    one = *(*pUtf8Ptr)++;
+    if ((one & 0x80) != 0) {
+        /* two- or three-byte encoding */
+        two = *(*pUtf8Ptr)++;
+        if ((one & 0x20) != 0) {
+            /* three-byte encoding */
+            three = *(*pUtf8Ptr)++;
+            return ((one & 0x0f) << 12) |
+                   ((two & 0x3f) << 6) |
+                   (three & 0x3f);
+        } else {
+            /* two-byte encoding */
+            return ((one & 0x1f) << 6) |
+                   (two & 0x3f);
+        }
+    } else {
+        /* one-byte encoding */
+        return one;
+    }
+}
+
+/* Compare two '\0'-terminated modified UTF-8 strings, using Unicode
+ * code point values for comparison. This treats different encodings
+ * for the same code point as equivalent, except that only a real '\0'
+ * byte is considered the string terminator. The return value is as
+ * for strcmp(). */
+int dexUtf8Cmp(const char* s1, const char* s2);
+
+/* for dexIsValidMemberNameUtf8(), a bit vector indicating valid low ascii */
+extern u4 DEX_MEMBER_VALID_LOW_ASCII[4];
+
+/* Helper for dexIsValidMemberUtf8(); do not call directly. */
+bool dexIsValidMemberNameUtf8_0(const char** pUtf8Ptr);
+
+/* Return whether the pointed-at modified-UTF-8 encoded character is
+ * valid as part of a member name, updating the pointer to point past
+ * the consumed character. This will consume two encoded UTF-16 code
+ * points if the character is encoded as a surrogate pair. Also, if
+ * this function returns false, then the given pointer may only have
+ * been partially advanced. */
+DEX_INLINE bool dexIsValidMemberNameUtf8(const char** pUtf8Ptr) {
+    u1 c = (u1) **pUtf8Ptr;
+    if (c <= 0x7f) {
+        // It's low-ascii, so check the table.
+        u4 wordIdx = c >> 5;
+        u4 bitIdx = c & 0x1f;
+        (*pUtf8Ptr)++;
+        return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0;
+    }
+
+    /*
+     * It's a multibyte encoded character. Call a non-inline function
+     * for the heavy lifting.
+     */
+    return dexIsValidMemberNameUtf8_0(pUtf8Ptr);
+}
+
+/* Return whether the given string is a valid field or method name. */
+bool dexIsValidMemberName(const char* s);
+
+/* Return whether the given string is a valid type descriptor. */
+bool dexIsValidTypeDescriptor(const char* s);
+
+/* Return whether the given string is a valid internal-form class
+ * name, with components separated either by dots or slashes as
+ * specified. A class name is like a type descriptor, except that it
+ * can't name a primitive type (including void). In terms of syntax,
+ * the form is either (a) the name of the class without adornment
+ * (that is, not bracketed by "L" and ";"); or (b) identical to the
+ * type descriptor syntax for array types. */
+bool dexIsValidClassName(const char* s, bool dotSeparator);
+
+/* Return whether the given string is a valid reference descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for a class or array and not a primitive type. */
+bool dexIsReferenceDescriptor(const char* s);
+
+/* Return whether the given string is a valid class descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for a class and not an array or primitive type. */
+bool dexIsClassDescriptor(const char* s);
+
+/* Return whether the given string is a valid field type descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for anything but "void". */
+bool dexIsFieldDescriptor(const char* s);
+
+#endif  // LIBDEX_DEXUTF_H_
diff --git a/libdex/InstrUtils.cpp b/libdex/InstrUtils.cpp
new file mode 100644
index 0000000..be343f0
--- /dev/null
+++ b/libdex/InstrUtils.cpp
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Dalvik instruction utility functions.
+ *
+ * IMPORTANT NOTE: Much of the contents of this file are generated
+ * automatically by the opcode-gen tool. Any edits to the generated
+ * sections will get wiped out the next time the tool is run.
+ */
+
+#include "InstrUtils.h"
+#include <stdlib.h>
+
+/*
+ * Table that maps each opcode to the full width of instructions that
+ * use that opcode, in (16-bit) code units. Unimplemented opcodes as
+ * well as the "breakpoint" opcode have a width of zero.
+ */
+static InstructionWidth gInstructionWidthTable[kNumPackedOpcodes] = {
+    // BEGIN(libdex-widths); GENERATED AUTOMATICALLY BY opcode-gen
+    1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 2, 3, 2, 2, 3, 5, 2, 2, 3, 2, 1, 1, 2,
+    2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+    0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
+    3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 3, 3,
+    3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 0,
+    // END(libdex-widths)
+};
+
+/*
+ * Table that maps each opcode to the flags associated with that
+ * opcode.
+ */
+static u1 gOpcodeFlagsTable[kNumPackedOpcodes] = {
+    // BEGIN(libdex-flags); GENERATED AUTOMATICALLY BY opcode-gen
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanReturn,
+    kInstrCanReturn,
+    kInstrCanReturn,
+    kInstrCanReturn,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanThrow,
+    kInstrCanBranch,
+    kInstrCanBranch,
+    kInstrCanBranch,
+    kInstrCanContinue|kInstrCanSwitch,
+    kInstrCanContinue|kInstrCanSwitch,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    0,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    0,
+    0,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    0,
+    kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanReturn,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    0,
+    // END(libdex-flags)
+};
+
+/*
+ * Table that maps each opcode to the instruction format associated
+ * that opcode.
+ */
+static u1 gInstructionFormatTable[kNumPackedOpcodes] = {
+    // BEGIN(libdex-formats); GENERATED AUTOMATICALLY BY opcode-gen
+    kFmt10x,  kFmt12x,  kFmt22x,  kFmt32x,  kFmt12x,  kFmt22x,  kFmt32x,
+    kFmt12x,  kFmt22x,  kFmt32x,  kFmt11x,  kFmt11x,  kFmt11x,  kFmt11x,
+    kFmt10x,  kFmt11x,  kFmt11x,  kFmt11x,  kFmt11n,  kFmt21s,  kFmt31i,
+    kFmt21h,  kFmt21s,  kFmt31i,  kFmt51l,  kFmt21h,  kFmt21c,  kFmt31c,
+    kFmt21c,  kFmt11x,  kFmt11x,  kFmt21c,  kFmt22c,  kFmt12x,  kFmt21c,
+    kFmt22c,  kFmt35c,  kFmt3rc,  kFmt31t,  kFmt11x,  kFmt10t,  kFmt20t,
+    kFmt30t,  kFmt31t,  kFmt31t,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt22t,  kFmt22t,  kFmt22t,  kFmt22t,  kFmt22t,  kFmt22t,
+    kFmt21t,  kFmt21t,  kFmt21t,  kFmt21t,  kFmt21t,  kFmt21t,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt22c,  kFmt22c,
+    kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,
+    kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,
+    kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,
+    kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt35c,  kFmt35c,
+    kFmt35c,  kFmt35c,  kFmt35c,  kFmt00x,  kFmt3rc,  kFmt3rc,  kFmt3rc,
+    kFmt3rc,  kFmt3rc,  kFmt00x,  kFmt00x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt22s,  kFmt22s,
+    kFmt22s,  kFmt22s,  kFmt22s,  kFmt22s,  kFmt22s,  kFmt22s,  kFmt22b,
+    kFmt22b,  kFmt22b,  kFmt22b,  kFmt22b,  kFmt22b,  kFmt22b,  kFmt22b,
+    kFmt22b,  kFmt22b,  kFmt22b,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,
+    kFmt22c,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,  kFmt00x,  kFmt20bc,
+    kFmt35mi, kFmt3rmi, kFmt35c,  kFmt10x,  kFmt22cs, kFmt22cs, kFmt22cs,
+    kFmt22cs, kFmt22cs, kFmt22cs, kFmt35ms, kFmt3rms, kFmt35ms, kFmt3rms,
+    kFmt22c,  kFmt21c,  kFmt21c,  kFmt00x,
+    // END(libdex-formats)
+};
+
+/*
+ * Table that maps each opcode to the index type implied by that
+ * opcode.
+ */
+static u1 gInstructionIndexTypeTable[kNumPackedOpcodes] = {
+    // BEGIN(libdex-index-types); GENERATED AUTOMATICALLY BY opcode-gen
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexStringRef,
+    kIndexStringRef,    kIndexTypeRef,      kIndexNone,
+    kIndexNone,         kIndexTypeRef,      kIndexTypeRef,
+    kIndexNone,         kIndexTypeRef,      kIndexTypeRef,
+    kIndexTypeRef,      kIndexTypeRef,      kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexMethodRef,
+    kIndexMethodRef,    kIndexMethodRef,    kIndexMethodRef,
+    kIndexMethodRef,    kIndexUnknown,      kIndexMethodRef,
+    kIndexMethodRef,    kIndexMethodRef,    kIndexMethodRef,
+    kIndexMethodRef,    kIndexUnknown,      kIndexUnknown,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexUnknown,
+    kIndexVaries,       kIndexInlineMethod, kIndexInlineMethod,
+    kIndexMethodRef,    kIndexNone,         kIndexFieldOffset,
+    kIndexFieldOffset,  kIndexFieldOffset,  kIndexFieldOffset,
+    kIndexFieldOffset,  kIndexFieldOffset,  kIndexVtableOffset,
+    kIndexVtableOffset, kIndexVtableOffset, kIndexVtableOffset,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexUnknown,
+    // END(libdex-index-types)
+};
+
+/*
+ * Global InstructionInfoTables struct.
+ */
+InstructionInfoTables gDexOpcodeInfo = {
+    gInstructionFormatTable,
+    gInstructionIndexTypeTable,
+    gOpcodeFlagsTable,
+    gInstructionWidthTable
+};
+
+/*
+ * Handy macros for helping decode instructions.
+ */
+#define FETCH(_offset)      (insns[(_offset)])
+#define FETCH_u4(_offset)   (fetch_u4_impl((_offset), insns))
+#define INST_A(_inst)       (((u2)(_inst) >> 8) & 0x0f)
+#define INST_B(_inst)       ((u2)(_inst) >> 12)
+#define INST_AA(_inst)      ((_inst) >> 8)
+
+/* Helper for FETCH_u4, above. */
+static inline u4 fetch_u4_impl(u4 offset, const u2* insns) {
+    return insns[offset] | ((u4) insns[offset+1] << 16);
+}
+
+/*
+ * Decode the instruction pointed to by "insns".
+ *
+ * Fills out the pieces of "pDec" that are affected by the current
+ * instruction.  Does not touch anything else.
+ */
+void dexDecodeInstruction(const u2* insns, DecodedInstruction* pDec)
+{
+    u2 inst = *insns;
+    Opcode opcode = dexOpcodeFromCodeUnit(inst);
+    InstructionFormat format = dexGetFormatFromOpcode(opcode);
+
+    pDec->opcode = opcode;
+    pDec->indexType = dexGetIndexTypeFromOpcode(opcode);
+
+    switch (format) {
+    case kFmt10x:       // op
+        /* nothing to do; copy the AA bits out for the verifier */
+        pDec->vA = INST_AA(inst);
+        break;
+    case kFmt12x:       // op vA, vB
+        pDec->vA = INST_A(inst);
+        pDec->vB = INST_B(inst);
+        break;
+    case kFmt11n:       // op vA, #+B
+        pDec->vA = INST_A(inst);
+        pDec->vB = (s4) (INST_B(inst) << 28) >> 28; // sign extend 4-bit value
+        break;
+    case kFmt11x:       // op vAA
+        pDec->vA = INST_AA(inst);
+        break;
+    case kFmt10t:       // op +AA
+        pDec->vA = (s1) INST_AA(inst);              // sign-extend 8-bit value
+        break;
+    case kFmt20t:       // op +AAAA
+        pDec->vA = (s2) FETCH(1);                   // sign-extend 16-bit value
+        break;
+    case kFmt20bc:      // [opt] op AA, thing@BBBB
+    case kFmt21c:       // op vAA, thing@BBBB
+    case kFmt22x:       // op vAA, vBBBB
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH(1);
+        break;
+    case kFmt21s:       // op vAA, #+BBBB
+    case kFmt21t:       // op vAA, +BBBB
+        pDec->vA = INST_AA(inst);
+        pDec->vB = (s2) FETCH(1);                   // sign-extend 16-bit value
+        break;
+    case kFmt21h:       // op vAA, #+BBBB0000[00000000]
+        pDec->vA = INST_AA(inst);
+        /*
+         * The value should be treated as right-zero-extended, but we don't
+         * actually do that here. Among other things, we don't know if it's
+         * the top bits of a 32- or 64-bit value.
+         */
+        pDec->vB = FETCH(1);
+        break;
+    case kFmt23x:       // op vAA, vBB, vCC
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH(1) & 0xff;
+        pDec->vC = FETCH(1) >> 8;
+        break;
+    case kFmt22b:       // op vAA, vBB, #+CC
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH(1) & 0xff;
+        pDec->vC = (s1) (FETCH(1) >> 8);            // sign-extend 8-bit value
+        break;
+    case kFmt22s:       // op vA, vB, #+CCCC
+    case kFmt22t:       // op vA, vB, +CCCC
+        pDec->vA = INST_A(inst);
+        pDec->vB = INST_B(inst);
+        pDec->vC = (s2) FETCH(1);                   // sign-extend 16-bit value
+        break;
+    case kFmt22c:       // op vA, vB, thing@CCCC
+    case kFmt22cs:      // [opt] op vA, vB, field offset CCCC
+        pDec->vA = INST_A(inst);
+        pDec->vB = INST_B(inst);
+        pDec->vC = FETCH(1);
+        break;
+    case kFmt30t:       // op +AAAAAAAA
+        pDec->vA = FETCH_u4(1);                     // signed 32-bit value
+        break;
+    case kFmt31t:       // op vAA, +BBBBBBBB
+    case kFmt31c:       // op vAA, string@BBBBBBBB
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH_u4(1);                     // 32-bit value
+        break;
+    case kFmt32x:       // op vAAAA, vBBBB
+        pDec->vA = FETCH(1);
+        pDec->vB = FETCH(2);
+        break;
+    case kFmt31i:       // op vAA, #+BBBBBBBB
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH_u4(1);                     // signed 32-bit value
+        break;
+    case kFmt35c:       // op {vC, vD, vE, vF, vG}, thing@BBBB
+    case kFmt35ms:      // [opt] invoke-virtual+super
+    case kFmt35mi:      // [opt] inline invoke
+        {
+            /*
+             * Note that the fields mentioned in the spec don't appear in
+             * their "usual" positions here compared to most formats. This
+             * was done so that the field names for the argument count and
+             * reference index match between this format and the corresponding
+             * range formats (3rc and friends).
+             *
+             * Bottom line: The argument count is always in vA, and the
+             * method constant (or equivalent) is always in vB.
+             */
+            u2 regList;
+            int i, count;
+
+            pDec->vA = INST_B(inst); // This is labeled A in the spec.
+            pDec->vB = FETCH(1);
+            regList = FETCH(2);
+
+            count = pDec->vA;
+
+            /*
+             * Copy the argument registers into the arg[] array, and
+             * also copy the first argument (if any) into vC. (The
+             * DecodedInstruction structure doesn't have separate
+             * fields for {vD, vE, vF, vG}, so there's no need to make
+             * copies of those.) Note that cases 5..2 fall through.
+             */
+            switch (count) {
+            case 5: {
+                if (format == kFmt35mi) {
+                    /* A fifth arg is verboten for inline invokes. */
+                    ALOGW("Invalid arg count in 35mi (5)");
+                    goto bail;
+                }
+                /*
+                 * Per note at the top of this format decoder, the
+                 * fifth argument comes from the A field in the
+                 * instruction, but it's labeled G in the spec.
+                 */
+                pDec->arg[4] = INST_A(inst);
+            }
+            case 4: pDec->arg[3] = (regList >> 12) & 0x0f;
+            case 3: pDec->arg[2] = (regList >> 8) & 0x0f;
+            case 2: pDec->arg[1] = (regList >> 4) & 0x0f;
+            case 1: pDec->vC = pDec->arg[0] = regList & 0x0f; break;
+            case 0: break; // Valid, but no need to do anything.
+            default:
+                ALOGW("Invalid arg count in 35c/35ms/35mi (%d)", count);
+                goto bail;
+            }
+        }
+        break;
+    case kFmt3rc:       // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
+    case kFmt3rms:      // [opt] invoke-virtual+super/range
+    case kFmt3rmi:      // [opt] execute-inline/range
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH(1);
+        pDec->vC = FETCH(2);
+        break;
+    case kFmt51l:       // op vAA, #+BBBBBBBBBBBBBBBB
+        pDec->vA = INST_AA(inst);
+        pDec->vB_wide = FETCH_u4(1) | ((u8) FETCH_u4(3) << 32);
+        break;
+    default:
+        ALOGW("Can't decode unexpected format %d (op=%d)", format, opcode);
+        assert(false);
+        break;
+    }
+
+bail:
+    ;
+}
+
+/*
+ * Return the width of the specified instruction, or 0 if not defined.  Also
+ * works for special OP_NOP entries, including switch statement data tables
+ * and array data.
+ */
+size_t dexGetWidthFromInstruction(const u2* insns)
+{
+    size_t width;
+
+    if (*insns == kPackedSwitchSignature) {
+        width = 4 + insns[1] * 2;
+    } else if (*insns == kSparseSwitchSignature) {
+        width = 2 + insns[1] * 4;
+    } else if (*insns == kArrayDataSignature) {
+        u2 elemWidth = insns[1];
+        u4 len = insns[2] | (((u4)insns[3]) << 16);
+        // The plus 1 is to round up for odd size and width.
+        width = 4 + (elemWidth * len + 1) / 2;
+    } else {
+        width = dexGetWidthFromOpcode(dexOpcodeFromCodeUnit(insns[0]));
+    }
+
+    return width;
+}
diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h
new file mode 100644
index 0000000..76993a5
--- /dev/null
+++ b/libdex/InstrUtils.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Dalvik instruction utility functions.
+ */
+#ifndef LIBDEX_INSTRUTILS_H_
+#define LIBDEX_INSTRUTILS_H_
+
+#include "DexFile.h"
+#include "DexOpcodes.h"
+
+/*
+ * Possible instruction formats associated with Dalvik opcodes.
+ *
+ * See the file opcode-gen/README.txt for information about updating
+ * opcodes and instruction formats.
+ */
+enum InstructionFormat {
+    kFmt00x = 0,    // unknown format (also used for "breakpoint" opcode)
+    kFmt10x,        // op
+    kFmt12x,        // op vA, vB
+    kFmt11n,        // op vA, #+B
+    kFmt11x,        // op vAA
+    kFmt10t,        // op +AA
+    kFmt20bc,       // [opt] op AA, thing@BBBB
+    kFmt20t,        // op +AAAA
+    kFmt22x,        // op vAA, vBBBB
+    kFmt21t,        // op vAA, +BBBB
+    kFmt21s,        // op vAA, #+BBBB
+    kFmt21h,        // op vAA, #+BBBB00000[00000000]
+    kFmt21c,        // op vAA, thing@BBBB
+    kFmt23x,        // op vAA, vBB, vCC
+    kFmt22b,        // op vAA, vBB, #+CC
+    kFmt22t,        // op vA, vB, +CCCC
+    kFmt22s,        // op vA, vB, #+CCCC
+    kFmt22c,        // op vA, vB, thing@CCCC
+    kFmt22cs,       // [opt] op vA, vB, field offset CCCC
+    kFmt30t,        // op +AAAAAAAA
+    kFmt32x,        // op vAAAA, vBBBB
+    kFmt31i,        // op vAA, #+BBBBBBBB
+    kFmt31t,        // op vAA, +BBBBBBBB
+    kFmt31c,        // op vAA, string@BBBBBBBB
+    kFmt35c,        // op {vC,vD,vE,vF,vG}, thing@BBBB
+    kFmt35ms,       // [opt] invoke-virtual+super
+    kFmt3rc,        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
+    kFmt3rms,       // [opt] invoke-virtual+super/range
+    kFmt51l,        // op vAA, #+BBBBBBBBBBBBBBBB
+    kFmt35mi,       // [opt] inline invoke
+    kFmt3rmi,       // [opt] inline invoke/range
+};
+
+/*
+ * Types of indexed reference that are associated with opcodes whose
+ * formats include such an indexed reference (e.g., 21c and 35c).
+ */
+enum InstructionIndexType {
+    kIndexUnknown = 0,
+    kIndexNone,         // has no index
+    kIndexVaries,       // "It depends." Used for throw-verification-error
+    kIndexTypeRef,      // type reference index
+    kIndexStringRef,    // string reference index
+    kIndexMethodRef,    // method reference index
+    kIndexFieldRef,     // field reference index
+    kIndexInlineMethod, // inline method index (for inline linked methods)
+    kIndexVtableOffset, // vtable offset (for static linked methods)
+    kIndexFieldOffset   // field offset (for static linked fields)
+};
+
+/*
+ * Instruction width implied by an opcode's format; a value in the
+ * range 0 to 5. Note that there are special "pseudo-instructions"
+ * which are used to encode switch and data tables, and these don't
+ * have a fixed width. See dexGetWidthFromInstruction(), below.
+ */
+typedef u1 InstructionWidth;
+
+/*
+ * Opcode control flow flags, used by the verifier and JIT.
+ */
+typedef u1 OpcodeFlags;
+enum OpcodeFlagsBits {
+    kInstrCanBranch     = 1,        // conditional or unconditional branch
+    kInstrCanContinue   = 1 << 1,   // flow can continue to next statement
+    kInstrCanSwitch     = 1 << 2,   // switch statement
+    kInstrCanThrow      = 1 << 3,   // could cause an exception to be thrown
+    kInstrCanReturn     = 1 << 4,   // returns, no additional statements
+    kInstrInvoke        = 1 << 5,   // a flavor of invoke
+};
+
+/*
+ * Struct that includes a pointer to each of the opcode information
+ * tables.
+ *
+ * Note: We use "u1*" here instead of the names of the enumerated
+ * types to guarantee that elements don't use much space. We hold out
+ * hope for a standard way to indicate the size of an enumerated type
+ * that works for both C and C++, but in the mean time, this will
+ * suffice.
+ */
+struct InstructionInfoTables {
+    u1*                formats;    /* InstructionFormat elements */
+    u1*                indexTypes; /* InstructionIndexType elements */
+    OpcodeFlags*       flags;
+    InstructionWidth*  widths;
+};
+
+/*
+ * Global InstructionInfoTables struct.
+ */
+extern InstructionInfoTables gDexOpcodeInfo;
+
+/*
+ * Holds the contents of a decoded instruction.
+ */
+struct DecodedInstruction {
+    u4      vA;
+    u4      vB;
+    u8      vB_wide;        /* for kFmt51l */
+    u4      vC;
+    u4      arg[5];         /* vC/D/E/F/G in invoke or filled-new-array */
+    Opcode  opcode;
+    InstructionIndexType indexType;
+};
+
+/*
+ * Return the instruction width of the specified opcode, or 0 if not defined.
+ */
+DEX_INLINE size_t dexGetWidthFromOpcode(Opcode opcode)
+{
+    assert((u4) opcode < kNumPackedOpcodes);
+    return gDexOpcodeInfo.widths[opcode];
+}
+
+/*
+ * Return the width of the specified instruction, or 0 if not defined.  Also
+ * works for special OP_NOP entries, including switch statement data tables
+ * and array data.
+ */
+size_t dexGetWidthFromInstruction(const u2* insns);
+
+/*
+ * Returns the flags for the specified opcode.
+ */
+DEX_INLINE OpcodeFlags dexGetFlagsFromOpcode(Opcode opcode)
+{
+    assert((u4) opcode < kNumPackedOpcodes);
+    return gDexOpcodeInfo.flags[opcode];
+}
+
+/*
+ * Returns true if the given flags represent a goto (unconditional branch).
+ */
+DEX_INLINE bool dexIsGoto(OpcodeFlags flags)
+{
+    return (flags & (kInstrCanBranch | kInstrCanContinue)) == kInstrCanBranch;
+}
+
+/*
+ * Return the instruction format for the specified opcode.
+ */
+DEX_INLINE InstructionFormat dexGetFormatFromOpcode(Opcode opcode)
+{
+    assert((u4) opcode < kNumPackedOpcodes);
+    return (InstructionFormat) gDexOpcodeInfo.formats[opcode];
+}
+
+/*
+ * Return the instruction index type for the specified opcode.
+ */
+DEX_INLINE InstructionIndexType dexGetIndexTypeFromOpcode(Opcode opcode)
+{
+    assert((u4) opcode < kNumPackedOpcodes);
+    return (InstructionIndexType) gDexOpcodeInfo.indexTypes[opcode];
+}
+
+/*
+ * Decode the instruction pointed to by "insns".
+ */
+void dexDecodeInstruction(const u2* insns, DecodedInstruction* pDec);
+
+#endif  // LIBDEX_INSTRUTILS_H_
diff --git a/libdex/Leb128.cpp b/libdex/Leb128.cpp
new file mode 100644
index 0000000..ed09e19
--- /dev/null
+++ b/libdex/Leb128.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions for interpreting LEB128 (little endian base 128) values
+ */
+
+#include "Leb128.h"
+
+/*
+ * Reads an unsigned LEB128 value, updating the given pointer to point
+ * just past the end of the read value and also indicating whether the
+ * value was syntactically valid. The only syntactically *invalid*
+ * values are ones that are five bytes long where the final byte has
+ * any but the low-order four bits set. Additionally, if the limit is
+ * passed as non-NULL and bytes would need to be read past the limit,
+ * then the read is considered invalid.
+ */
+int readAndVerifyUnsignedLeb128(const u1** pStream, const u1* limit,
+        bool* okay) {
+    const u1* ptr = *pStream;
+    int result = readUnsignedLeb128(pStream);
+
+    if (((limit != NULL) && (*pStream > limit))
+            || (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) {
+        *okay = false;
+    }
+
+    return result;
+}
+
+/*
+ * Reads a signed LEB128 value, updating the given pointer to point
+ * just past the end of the read value and also indicating whether the
+ * value was syntactically valid. The only syntactically *invalid*
+ * values are ones that are five bytes long where the final byte has
+ * any but the low-order four bits set. Additionally, if the limit is
+ * passed as non-NULL and bytes would need to be read past the limit,
+ * then the read is considered invalid.
+ */
+int readAndVerifySignedLeb128(const u1** pStream, const u1* limit,
+        bool* okay) {
+    const u1* ptr = *pStream;
+    int result = readSignedLeb128(pStream);
+
+    if (((limit != NULL) && (*pStream > limit))
+            || (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) {
+        *okay = false;
+    }
+
+    return result;
+}
diff --git a/libdex/Leb128.h b/libdex/Leb128.h
new file mode 100644
index 0000000..21f4eda
--- /dev/null
+++ b/libdex/Leb128.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions for interpreting LEB128 (little endian base 128) values
+ */
+
+#ifndef LIBDEX_LEB128_H_
+#define LIBDEX_LEB128_H_
+
+#include "DexFile.h"
+
+/*
+ * Reads an unsigned LEB128 value, updating the given pointer to point
+ * just past the end of the read value. This function tolerates
+ * non-zero high-order bits in the fifth encoded byte.
+ */
+DEX_INLINE int readUnsignedLeb128(const u1** pStream) {
+    const u1* ptr = *pStream;
+    int result = *(ptr++);
+
+    if (result > 0x7f) {
+        int cur = *(ptr++);
+        result = (result & 0x7f) | ((cur & 0x7f) << 7);
+        if (cur > 0x7f) {
+            cur = *(ptr++);
+            result |= (cur & 0x7f) << 14;
+            if (cur > 0x7f) {
+                cur = *(ptr++);
+                result |= (cur & 0x7f) << 21;
+                if (cur > 0x7f) {
+                    /*
+                     * Note: We don't check to see if cur is out of
+                     * range here, meaning we tolerate garbage in the
+                     * high four-order bits.
+                     */
+                    cur = *(ptr++);
+                    result |= cur << 28;
+                }
+            }
+        }
+    }
+
+    *pStream = ptr;
+    return result;
+}
+
+/*
+ * Reads a signed LEB128 value, updating the given pointer to point
+ * just past the end of the read value. This function tolerates
+ * non-zero high-order bits in the fifth encoded byte.
+ */
+DEX_INLINE int readSignedLeb128(const u1** pStream) {
+    const u1* ptr = *pStream;
+    int result = *(ptr++);
+
+    if (result <= 0x7f) {
+        result = (result << 25) >> 25;
+    } else {
+        int cur = *(ptr++);
+        result = (result & 0x7f) | ((cur & 0x7f) << 7);
+        if (cur <= 0x7f) {
+            result = (result << 18) >> 18;
+        } else {
+            cur = *(ptr++);
+            result |= (cur & 0x7f) << 14;
+            if (cur <= 0x7f) {
+                result = (result << 11) >> 11;
+            } else {
+                cur = *(ptr++);
+                result |= (cur & 0x7f) << 21;
+                if (cur <= 0x7f) {
+                    result = (result << 4) >> 4;
+                } else {
+                    /*
+                     * Note: We don't check to see if cur is out of
+                     * range here, meaning we tolerate garbage in the
+                     * high four-order bits.
+                     */
+                    cur = *(ptr++);
+                    result |= cur << 28;
+                }
+            }
+        }
+    }
+
+    *pStream = ptr;
+    return result;
+}
+
+/*
+ * Reads an unsigned LEB128 value, updating the given pointer to point
+ * just past the end of the read value and also indicating whether the
+ * value was syntactically valid. The only syntactically *invalid*
+ * values are ones that are five bytes long where the final byte has
+ * any but the low-order four bits set. Additionally, if the limit is
+ * passed as non-NULL and bytes would need to be read past the limit,
+ * then the read is considered invalid.
+ */
+int readAndVerifyUnsignedLeb128(const u1** pStream, const u1* limit,
+        bool* okay);
+
+/*
+ * Reads a signed LEB128 value, updating the given pointer to point
+ * just past the end of the read value and also indicating whether the
+ * value was syntactically valid. The only syntactically *invalid*
+ * values are ones that are five bytes long where the final byte has
+ * any but the low-order four bits set. Additionally, if the limit is
+ * passed as non-NULL and bytes would need to be read past the limit,
+ * then the read is considered invalid.
+ */
+int readAndVerifySignedLeb128(const u1** pStream, const u1* limit, bool* okay);
+
+
+/*
+ * Writes a 32-bit value in unsigned ULEB128 format.
+ *
+ * Returns the updated pointer.
+ */
+DEX_INLINE u1* writeUnsignedLeb128(u1* ptr, u4 data)
+{
+    while (true) {
+        u1 out = data & 0x7f;
+        if (out != data) {
+            *ptr++ = out | 0x80;
+            data >>= 7;
+        } else {
+            *ptr++ = out;
+            break;
+        }
+    }
+
+    return ptr;
+}
+
+/*
+ * Returns the number of bytes needed to encode "val" in ULEB128 form.
+ */
+DEX_INLINE int unsignedLeb128Size(u4 data)
+{
+    int count = 0;
+
+    do {
+        data >>= 7;
+        count++;
+    } while (data != 0);
+
+    return count;
+}
+
+#endif
diff --git a/libdex/OptInvocation.cpp b/libdex/OptInvocation.cpp
new file mode 100644
index 0000000..be7f70b
--- /dev/null
+++ b/libdex/OptInvocation.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Utility functions for dealing with optimized dex files.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <errno.h>
+
+#include "OptInvocation.h"
+#include "DexFile.h"
+
+static const char* kCacheDirectoryName = "dalvik-cache";
+static const char* kClassesDex = "classes.dex";
+
+#if defined(__aarch64__)
+static const char* kInstructionSet = "arm64";
+#elif defined(__arm__)
+static const char* kInstructionSet = "arm";
+#elif defined(__i386__)
+static const char* kInstructionSet = "x86";
+#elif defined(__mips__)
+static const char* kInstructionSet = "mips";
+#elif defined(__x86_64__)
+static const char* kInstructionSet = "x86_64";
+#else
+#error Unsupported instruction set.
+#endif
+
+static int dexOptMkdir(const char*  path, int mode)
+{
+#ifdef _WIN32
+    return mkdir(path);
+#else
+    return mkdir(path, mode);
+#endif
+}
+
+/*
+ * Given the filename of a .jar or .dex file, construct the DEX file cache
+ * name.
+ *
+ * For a Jar, "subFileName" is the name of the entry (usually "classes.dex").
+ * For a DEX, it may be NULL.
+ *
+ * Returns a newly-allocated string, or NULL on failure.
+ */
+char* dexOptGenerateCacheFileName(const char* fileName, const char* subFileName)
+{
+    char nameBuf[512];
+    char absoluteFile[sizeof(nameBuf)];
+    const size_t kBufLen = sizeof(nameBuf) - 1;
+    const char* dataRoot;
+    char* cp;
+
+    /*
+     * Get the absolute path of the Jar or DEX file.
+     */
+    absoluteFile[0] = '\0';
+    if (fileName[0] != '/') {
+        /*
+         * Generate the absolute path.  This doesn't do everything it
+         * should, e.g. if filename is "./out/whatever" it doesn't crunch
+         * the leading "./" out, but it'll do.
+         */
+        if (getcwd(absoluteFile, kBufLen) == NULL) {
+            ALOGE("Can't get CWD while opening jar file");
+            return NULL;
+        }
+        strncat(absoluteFile, "/", kBufLen);
+    }
+    strncat(absoluteFile, fileName, kBufLen);
+
+    /*
+     * Append the name of the Jar file entry, if any.  This is not currently
+     * required, but will be if we start putting more than one DEX file
+     * in a Jar.
+     */
+    if (subFileName != NULL) {
+        strncat(absoluteFile, "/", kBufLen);
+        strncat(absoluteFile, subFileName, kBufLen);
+    }
+
+    /* Turn the path into a flat filename by replacing
+     * any slashes after the first one with '@' characters.
+     */
+    cp = absoluteFile + 1;
+    while (*cp != '\0') {
+        if (*cp == '/') {
+            *cp = '@';
+        }
+        cp++;
+    }
+
+    /* Build the name of the cache directory.
+     */
+    dataRoot = getenv("ANDROID_DATA");
+    if (dataRoot == NULL)
+        dataRoot = "/data";
+    snprintf(nameBuf, kBufLen, "%s/%s", dataRoot, kCacheDirectoryName);
+    if (strcmp(dataRoot, "/data") != 0) {
+        int result = dexOptMkdir(nameBuf, 0700);
+        if (result != 0 && errno != EEXIST) {
+            ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
+            return NULL;
+        }
+    }
+    snprintf(nameBuf, kBufLen, "%s/%s/%s", dataRoot, kCacheDirectoryName, kInstructionSet);
+    if (strcmp(dataRoot, "/data") != 0) {
+        int result = dexOptMkdir(nameBuf, 0700);
+        if (result != 0 && errno != EEXIST) {
+            ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
+            return NULL;
+        }
+    }
+
+    /* Tack on the file name for the actual cache file path.
+     */
+    strncat(nameBuf, absoluteFile, kBufLen);
+
+    ALOGV("Cache file for '%s' '%s' is '%s'", fileName, subFileName, nameBuf);
+    return strdup(nameBuf);
+}
+
+/*
+ * Create a skeletal "opt" header in a new file.  Most of the fields are
+ * initialized to garbage, but we fill in "dexOffset" so others can
+ * see how large the header is.
+ *
+ * "fd" must be positioned at the start of the file.  On return, it will
+ * be positioned just past the header, and the place where the DEX data
+ * should go.
+ *
+ * Returns 0 on success, errno on failure.
+ */
+int dexOptCreateEmptyHeader(int fd)
+{
+    DexOptHeader optHdr;
+    ssize_t actual;
+
+    assert(lseek(fd, 0, SEEK_CUR) == 0);
+
+    /*
+     * The data is only expected to be readable on the current system, so
+     * we just write the structure.  We do need the file offset to be 64-bit
+     * aligned to fulfill a DEX requirement.
+     */
+    assert((sizeof(optHdr) & 0x07) == 0);
+    memset(&optHdr, 0xff, sizeof(optHdr));
+    optHdr.dexOffset = sizeof(optHdr);
+    actual = write(fd, &optHdr, sizeof(optHdr));
+    if (actual != sizeof(optHdr)) {
+        int err = errno ? errno : -1;
+        ALOGE("opt header write failed: %s", strerror(errno));
+        return errno;
+    }
+
+    return 0;
+}
diff --git a/libdex/OptInvocation.h b/libdex/OptInvocation.h
new file mode 100644
index 0000000..3f32b94
--- /dev/null
+++ b/libdex/OptInvocation.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Utility functions related to "dexopt".
+ */
+#ifndef LIBDEX_OPTINVOCATION_H_
+#define LIBDEX_OPTINVOCATION_H_
+
+/*
+ * Utility routines, used by the VM.
+ */
+char* dexOptGenerateCacheFileName(const char* fileName,
+    const char* subFileName);
+int dexOptCreateEmptyHeader(int fd);
+
+#endif  // LIBDEX_OPTINVOCATION_H_
diff --git a/libdex/SysUtil.cpp b/libdex/SysUtil.cpp
new file mode 100644
index 0000000..5650be5
--- /dev/null
+++ b/libdex/SysUtil.cpp
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * System utilities.
+ */
+#include "DexFile.h"
+#include "SysUtil.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#if !defined(__MINGW32__)
+# include <sys/mman.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+
+#include <JNIHelp.h>        // TEMP_FAILURE_RETRY may or may not be in unistd
+
+
+/*
+ * Create an anonymous shared memory segment large enough to hold "length"
+ * bytes.  The actual segment may be larger because mmap() operates on
+ * page boundaries (usually 4K).
+ */
+static void* sysCreateAnonShmem(size_t length)
+{
+#if !defined(__MINGW32__)
+    void* ptr;
+
+    ptr = mmap(NULL, length, PROT_READ | PROT_WRITE,
+            MAP_SHARED | MAP_ANON, -1, 0);
+    if (ptr == MAP_FAILED) {
+        ALOGW("mmap(%d, RW, SHARED|ANON) failed: %s", (int) length,
+            strerror(errno));
+        return NULL;
+    }
+
+    return ptr;
+#else
+    ALOGE("sysCreateAnonShmem not implemented.");
+    return NULL;
+#endif
+}
+
+/*
+ * Create a private anonymous storage area.
+ */
+int sysCreatePrivateMap(size_t length, MemMapping* pMap)
+{
+    void* memPtr;
+
+    memPtr = sysCreateAnonShmem(length);
+    if (memPtr == NULL)
+        return -1;
+
+    pMap->addr = pMap->baseAddr = memPtr;
+    pMap->length = pMap->baseLength = length;
+    return 0;
+}
+
+/*
+ * Determine the current offset and remaining length of the open file.
+ */
+static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
+{
+    off_t start, end;
+    size_t length;
+
+    assert(start_ != NULL);
+    assert(length_ != NULL);
+
+    start = lseek(fd, 0L, SEEK_CUR);
+    end = lseek(fd, 0L, SEEK_END);
+    (void) lseek(fd, start, SEEK_SET);
+
+    if (start == (off_t) -1 || end == (off_t) -1) {
+        ALOGE("could not determine length of file");
+        return -1;
+    }
+
+    length = end - start;
+    if (length == 0) {
+        ALOGE("file is empty");
+        return -1;
+    }
+
+    *start_ = start;
+    *length_ = length;
+
+    return 0;
+}
+
+#if defined(__MINGW32__)
+int sysFakeMapFile(int fd, MemMapping* pMap)
+{
+    /* No MMAP, just fake it by copying the bits.
+       For Win32 we could use MapViewOfFile if really necessary
+       (see libs/utils/FileMap.cpp).
+    */
+    off_t start;
+    size_t length;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    if (getFileStartAndLength(fd, &start, &length) < 0)
+        return -1;
+
+    memPtr = malloc(length);
+    if (read(fd, memPtr, length) < 0) {
+        ALOGW("read(fd=%d, start=%d, length=%d) failed: %s", (int) length,
+            fd, (int) start, strerror(errno));
+        return -1;
+    }
+
+    pMap->baseAddr = pMap->addr = memPtr;
+    pMap->baseLength = pMap->length = length;
+
+    return 0;
+}
+#endif
+
+/*
+ * Map a file (from fd's current offset) into a private, read-write memory
+ * segment that will be marked read-only (a/k/a "writable read-only").  The
+ * file offset must be a multiple of the system page size.
+ *
+ * In some cases the mapping will be fully writable (e.g. for files on
+ * FAT filesystems).
+ *
+ * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
+ * value and does not disturb "pMap".
+ */
+int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap)
+{
+#if !defined(__MINGW32__)
+    off_t start;
+    size_t length;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    if (getFileStartAndLength(fd, &start, &length) < 0)
+        return -1;
+
+    memPtr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
+            fd, start);
+    if (memPtr == MAP_FAILED) {
+        ALOGW("mmap(%d, R/W, FILE|PRIVATE, %d, %d) failed: %s", (int) length,
+            fd, (int) start, strerror(errno));
+        return -1;
+    }
+    if (mprotect(memPtr, length, PROT_READ) < 0) {
+        /* this fails with EACCESS on FAT filesystems, e.g. /sdcard */
+        int err = errno;
+        ALOGV("mprotect(%p, %zd, PROT_READ) failed: %s",
+            memPtr, length, strerror(err));
+        ALOGD("mprotect(RO) failed (%d), file will remain read-write", err);
+    }
+
+    pMap->baseAddr = pMap->addr = memPtr;
+    pMap->baseLength = pMap->length = length;
+
+    return 0;
+#else
+    return sysFakeMapFile(fd, pMap);
+#endif
+}
+
+/*
+ * Map part of a file into a shared, read-only memory segment.  The "start"
+ * offset is absolute, not relative.
+ *
+ * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
+ * value and does not disturb "pMap".
+ */
+int sysMapFileSegmentInShmem(int fd, off_t start, size_t length,
+    MemMapping* pMap)
+{
+#if !defined(__MINGW32__)
+    size_t actualLength;
+    off_t actualStart;
+    int adjust;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    /* adjust to be page-aligned */
+    adjust = start % SYSTEM_PAGE_SIZE;
+    actualStart = start - adjust;
+    actualLength = length + adjust;
+
+    memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
+                fd, actualStart);
+    if (memPtr == MAP_FAILED) {
+        ALOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s",
+            (int) actualLength, fd, (int) actualStart, strerror(errno));
+        return -1;
+    }
+
+    pMap->baseAddr = memPtr;
+    pMap->baseLength = actualLength;
+    pMap->addr = (char*)memPtr + adjust;
+    pMap->length = length;
+
+    LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d",
+        (int) start, (int) length,
+        pMap->baseAddr, (int) pMap->baseLength,
+        pMap->addr, (int) pMap->length);
+
+    return 0;
+#else
+    ALOGE("sysMapFileSegmentInShmem not implemented.");
+    return -1;
+#endif
+}
+
+/*
+ * Change the access rights on one or more pages to read-only or read-write.
+ *
+ * Returns 0 on success.
+ */
+int sysChangeMapAccess(void* addr, size_t length, int wantReadWrite,
+    MemMapping* pMap)
+{
+#if !defined(__MINGW32__)
+    /*
+     * Verify that "addr" is part of this mapping file.
+     */
+    if (addr < pMap->baseAddr ||
+        (u1*)addr >= (u1*)pMap->baseAddr + pMap->baseLength)
+    {
+        ALOGE("Attempted to change %p; map is %p - %p",
+            addr, pMap->baseAddr, (u1*)pMap->baseAddr + pMap->baseLength);
+        return -1;
+    }
+
+    /*
+     * Align "addr" to a page boundary and adjust "length" appropriately.
+     * (The address must be page-aligned, the length doesn't need to be,
+     * but we do need to ensure we cover the same range.)
+     */
+    u1* alignAddr = (u1*) ((uintptr_t) addr & ~(SYSTEM_PAGE_SIZE-1));
+    size_t alignLength = length + ((u1*) addr - alignAddr);
+
+    //ALOGI("%p/%zd --> %p/%zd", addr, length, alignAddr, alignLength);
+    int prot = wantReadWrite ? (PROT_READ|PROT_WRITE) : (PROT_READ);
+    if (mprotect(alignAddr, alignLength, prot) != 0) {
+        int err = errno;
+        ALOGV("mprotect (%p,%zd,%d) failed: %s",
+            alignAddr, alignLength, prot, strerror(errno));
+        return (errno != 0) ? errno : -1;
+    }
+#endif
+
+    /* for "fake" mapping, no need to do anything */
+    return 0;
+}
+
+/*
+ * Release a memory mapping.
+ */
+void sysReleaseShmem(MemMapping* pMap)
+{
+#if !defined(__MINGW32__)
+    if (pMap->baseAddr == NULL && pMap->baseLength == 0)
+        return;
+
+    if (munmap(pMap->baseAddr, pMap->baseLength) < 0) {
+        ALOGW("munmap(%p, %zd) failed: %s",
+            pMap->baseAddr, pMap->baseLength, strerror(errno));
+    } else {
+        ALOGV("munmap(%p, %zd) succeeded", pMap->baseAddr, pMap->baseLength);
+        pMap->baseAddr = NULL;
+        pMap->baseLength = 0;
+    }
+#else
+    /* Free the bits allocated by sysMapFileInShmem. */
+    if (pMap->baseAddr != NULL) {
+      free(pMap->baseAddr);
+      pMap->baseAddr = NULL;
+    }
+    pMap->baseLength = 0;
+#endif
+}
+
+/*
+ * Make a copy of a MemMapping.
+ */
+void sysCopyMap(MemMapping* dst, const MemMapping* src)
+{
+    memcpy(dst, src, sizeof(MemMapping));
+}
+
+/*
+ * Write until all bytes have been written.
+ *
+ * Returns 0 on success, or an errno value on failure.
+ */
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg)
+{
+    while (count != 0) {
+        ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count));
+        if (actual < 0) {
+            int err = errno;
+            ALOGE("%s: write failed: %s", logMsg, strerror(err));
+            return err;
+        } else if (actual != (ssize_t) count) {
+            ALOGD("%s: partial write (will retry): (%d of %zd)",
+                logMsg, (int) actual, count);
+            buf = (const void*) (((const u1*) buf) + actual);
+        }
+        count -= actual;
+    }
+
+    return 0;
+}
+
+/* See documentation comment in header file. */
+int sysCopyFileToFile(int outFd, int inFd, size_t count)
+{
+    const size_t kBufSize = 32768;
+    unsigned char buf[kBufSize];
+
+    while (count != 0) {
+        size_t getSize = (count > kBufSize) ? kBufSize : count;
+
+        ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, buf, getSize));
+        if (actual != (ssize_t) getSize) {
+            ALOGW("sysCopyFileToFile: copy read failed (%d vs %zd)",
+                (int) actual, getSize);
+            return -1;
+        }
+
+        if (sysWriteFully(outFd, buf, getSize, "sysCopyFileToFile") != 0)
+            return -1;
+
+        count -= getSize;
+    }
+
+    return 0;
+}
diff --git a/libdex/SysUtil.h b/libdex/SysUtil.h
new file mode 100644
index 0000000..c02ec6e
--- /dev/null
+++ b/libdex/SysUtil.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * System utilities.
+ */
+#ifndef LIBDEX_SYSUTIL_H_
+#define LIBDEX_SYSUTIL_H_
+
+#include <sys/types.h>
+
+/*
+ * System page size.  Normally you're expected to get this from
+ * sysconf(_SC_PAGESIZE) or some system-specific define (usually PAGESIZE
+ * or PAGE_SIZE).  If we use a simple #define the compiler can generate
+ * appropriate masks directly, so we define it here and verify it as the
+ * VM is starting up.
+ *
+ * Must be a power of 2.
+ */
+#ifdef PAGE_SHIFT
+#define SYSTEM_PAGE_SIZE        (1<<PAGE_SHIFT)
+#else
+#define SYSTEM_PAGE_SIZE        4096
+#endif
+
+/*
+ * Use this to keep track of mapped segments.
+ */
+struct MemMapping {
+    void*   addr;           /* start of data */
+    size_t  length;         /* length of data */
+
+    void*   baseAddr;       /* page-aligned base address */
+    size_t  baseLength;     /* length of mapping */
+};
+
+/*
+ * Copy a map.
+ */
+void sysCopyMap(MemMapping* dst, const MemMapping* src);
+
+/*
+ * Map a file (from fd's current offset) into a shared, read-only memory
+ * segment that can be made writable.  (In some cases, such as when
+ * mapping a file on a FAT filesystem, the result may be fully writable.)
+ *
+ * On success, "pMap" is filled in, and zero is returned.
+ */
+int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap);
+
+/*
+ * Map part of a file into a shared, read-only memory segment.
+ *
+ * On success, "pMap" is filled in, and zero is returned.
+ */
+int sysMapFileSegmentInShmem(int fd, off_t start, size_t length,
+    MemMapping* pMap);
+
+/*
+ * Create a private anonymous mapping, useful for large allocations.
+ *
+ * On success, "pMap" is filled in, and zero is returned.
+ */
+int sysCreatePrivateMap(size_t length, MemMapping* pMap);
+
+/*
+ * Change the access rights on one or more pages.  If "wantReadWrite" is
+ * zero, the pages will be made read-only; otherwise they will be read-write.
+ *
+ * Returns 0 on success.
+ */
+int sysChangeMapAccess(void* addr, size_t length, int wantReadWrite,
+    MemMapping* pmap);
+
+/*
+ * Release the pages associated with a shared memory segment.
+ *
+ * This does not free "pMap"; it just releases the memory.
+ */
+void sysReleaseShmem(MemMapping* pMap);
+
+/*
+ * Write until all bytes have been written.
+ *
+ * Returns 0 on success, or an errno value on failure.
+ */
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg);
+
+/*
+ * Copy the given number of bytes from one fd to another. Returns
+ * 0 on success, -1 on failure.
+ */
+int sysCopyFileToFile(int outFd, int inFd, size_t count);
+
+#endif  // LIBDEX_SYSUTIL_H_
diff --git a/libdex/ZipArchive.h b/libdex/ZipArchive.h
new file mode 100644
index 0000000..206afd5
--- /dev/null
+++ b/libdex/ZipArchive.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Read-only access to Zip archives, with minimal heap allocation.
+ */
+#ifndef LIBDEX_ZIPARCHIVE_H_
+#define LIBDEX_ZIPARCHIVE_H_
+
+#include <ziparchive/zip_archive.h>
+
+#include "SysUtil.h"
+#include "DexFile.h"            // need DEX_INLINE
+
+/*
+ * Open a Zip archive.
+ *
+ * On success, returns 0 and populates "pArchive".  Returns nonzero errno
+ * value on failure.
+ */
+DEX_INLINE int dexZipOpenArchive(const char* fileName, ZipArchiveHandle* pArchive) {
+    return OpenArchive(fileName, pArchive);
+}
+
+/*
+ * Like dexZipOpenArchive, but takes a file descriptor open for reading
+ * at the start of the file.  The descriptor must be mappable (this does
+ * not allow access to a stream).
+ *
+ * "debugFileName" will appear in error messages, but is not otherwise used.
+ */
+DEX_INLINE int dexZipOpenArchiveFd(int fd, const char* debugFileName,
+                                   ZipArchiveHandle* pArchive) {
+    return OpenArchiveFd(fd, debugFileName, pArchive);
+}
+
+/*
+ * Close archive, releasing resources associated with it.
+ *
+ * Depending on the implementation this could unmap pages used by classes
+ * stored in a Jar.  This should only be done after unloading classes.
+ */
+DEX_INLINE void dexZipCloseArchive(ZipArchiveHandle archive) {
+    CloseArchive(archive);
+}
+
+/*
+ * Return the archive's file descriptor.
+ */
+DEX_INLINE int dexZipGetArchiveFd(const ZipArchiveHandle pArchive) {
+    return GetFileDescriptor(pArchive);
+}
+
+/*
+ * Find an entry in the Zip archive, by name.  Returns NULL if the entry
+ * was not found.
+ */
+DEX_INLINE int  dexZipFindEntry(const ZipArchiveHandle pArchive,
+    const char* entryName, ZipEntry* data) {
+    return FindEntry(pArchive, ZipString(entryName), data);
+}
+
+/*
+ * Uncompress and write an entry to a file descriptor.
+ *
+ * Returns 0 on success.
+ */
+DEX_INLINE int dexZipExtractEntryToFile(ZipArchiveHandle handle,
+    ZipEntry* entry, int fd) {
+    return ExtractEntryToFile(handle, entry, fd);
+}
+
+#endif  // LIBDEX_ZIPARCHIVE_H_
diff --git a/libdex/sha1.cpp b/libdex/sha1.cpp
new file mode 100644
index 0000000..60c4d93
--- /dev/null
+++ b/libdex/sha1.cpp
@@ -0,0 +1,511 @@
+/*
+ * Tweaked in various ways for Google/Android:
+ *  - Changed from .cpp to .c.
+ *  - Made argument to SHA1Update a const pointer, and enabled
+ *    SHA1HANDSOFF.  This incurs a speed penalty but prevents us from
+ *    trashing the input.
+ *  - Include <endian.h> to get endian info.
+ *  - Split a small piece into a header file.
+ */
+
+/*
+sha1sum: inspired by md5sum.
+
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+bit machines
+Routine SHA1Update changed from
+    void SHA1Update(SHA1_CTX* context, unsigned char* data,
+      unsigned int len)
+to
+    void SHA1Update(SHA1_CTX* context, unsigned char* data,
+      unsigned long len)
+
+The 'len' parameter was declared an int which works fine on 32
+bit machines. However, on 16 bit machines an int is too small
+for the shifts being done against it.  This caused the hash
+function to generate incorrect values if len was greater than
+8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or
+larger would be guaranteed to generate the wrong hash (e.g.
+Test Vector #3, a million "a"s).
+
+I also changed the declaration of variables i & j in SHA1Update
+to unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit
+implementations since an int and a long are the same size in
+those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland
+C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments
+containing 'JHB'
+
+-----------------
+Modified 13 August 2000
+By Michael Paul Johnson <mpj@cryptography.org>
+Still 100% Public Domain
+
+Changed command line syntax, added feature to automatically
+check files against their previous SHA-1 check values, kind of
+like md5sum does. Added functions hexval, verifyfile,
+and sha1file. Rewrote main().
+-----------------
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#define SHA1HANDSOFF    /*Copies data before messing with it.*/
+
+/*#define CMDLINE        * include main() and file processing */
+
+#include "sha1.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef __BORLANDC__
+#include <dir.h>
+#include <dos.h>
+#include <process.h>   /*  prototype for exit() - JHB
+               needed for Win32, but chokes Linux - MPJ */
+#define X_LITTLE_ENDIAN /* This should be #define'd if true.*/
+#else
+# include <unistd.h>
+# include <stdlib.h>
+//# include <endian.h>
+//# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define X_LITTLE_ENDIAN
+//# endif
+#endif
+#include <ctype.h>
+
+#define LINESIZE 2048
+
+static void SHA1Transform(unsigned long state[5],
+    const unsigned char buffer[64]);
+
+#define rol(value,bits) \
+ (((value)<<(bits))|((value)>>(32-(bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from
+   SSLeay */
+#ifdef X_LITTLE_ENDIAN
+#define blk0(i) (block->l[i]=(rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+static void SHA1Transform(unsigned long state[5],
+    const unsigned char buffer[64])
+{
+unsigned long a, b, c, d, e;
+union CHAR64LONG16 {
+    unsigned char c[64];
+    unsigned long l[16];
+};
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+    block = (CHAR64LONG16*)workspace;
+    memcpy(block, buffer, 64);
+#else
+    block = (CHAR64LONG16*)buffer;
+#endif
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2);
+    R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5);
+    R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8);
+    R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14);
+    R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17);
+    R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20);
+    R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26);
+    R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29);
+    R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32);
+    R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38);
+    R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41);
+    R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44);
+    R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50);
+    R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53);
+    R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56);
+    R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62);
+    R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65);
+    R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68);
+    R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74);
+    R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77);
+    R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+    /* Wipe variables */
+/*    a = b = c = d = e = 0; Nice try, but the compiler
+optimizes this out, anyway, and it produces an annoying
+warning. */
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data,
+    unsigned long len)  /* JHB */
+{
+    unsigned long i, j; /* JHB */
+
+    j = (context->count[0] >> 3) & 63;
+    if ((context->count[0] += len << 3) < (len << 3))
+        context->count[1]++;
+    context->count[1] += (len >> 29);
+    if ((j + len) > 63)
+    {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1Transform(context->state, context->buffer);
+        for ( ; i + 63 < len; i += 64) {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else
+        i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[HASHSIZE], SHA1_CTX*
+context)
+{
+unsigned long i;    /* JHB */
+unsigned char finalcount[8];
+
+    for (i = 0; i < 8; i++)
+    {
+        finalcount[i] = (unsigned char)((context->count[(i>=4?
+            0:1)]>>((3-(i&3))*8))&255);
+        /* Endian independent */
+    }
+    SHA1Update(context, (unsigned char *)"\200", 1);
+    while ((context->count[0] & 504) != 448) {
+        SHA1Update(context, (unsigned char *)"\0", 1);
+    }
+    SHA1Update(context, finalcount, 8);
+    /* Should cause a SHA1Transform() */
+    for (i = 0; i < HASHSIZE; i++) {
+        digest[i] = (unsigned char)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    /* Wipe variables */
+    memset(context->buffer, 0, 64);
+    memset(context->state, 0, HASHSIZE);
+    memset(context->count, 0, 8);
+    memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF
+    /* make SHA1Transform overwrite it's own static vars */
+    SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+
+
+#ifdef CMDLINE
+
+/* sha1file computes the SHA-1 hash of the named file and puts
+   it in the 20-byte array digest. If fname is NULL, stdin is
+   assumed.
+*/
+void sha1file(char *fname, unsigned char* digest)
+{
+    int bytesread;
+    SHA1_CTX context;
+    unsigned char buffer[16384];
+    FILE* f;
+
+    if (fname)
+    {
+        f = fopen(fname, "rb");
+        if (!f)
+        {
+            fprintf(stderr, "Can't open %s\n", fname);
+            memset(digest, 0, HASHSIZE);
+            return;
+        }
+    }
+    else
+    {
+        f = stdin;
+    }
+    SHA1Init(&context);
+    while (!feof(f))
+    {
+        bytesread = fread(buffer, 1, 16384, f);
+        SHA1Update(&context, buffer, bytesread);
+    }
+    SHA1Final(digest, &context);
+    if (fname)
+        fclose(f);
+}
+
+/* Convert ASCII hexidecimal digit to 4-bit value. */
+unsigned char hexval(char c)
+{
+    unsigned char h;
+
+    c = toupper(c);
+    if (c >= 'A')
+        h = c - 'A' + 10;
+    else
+        h = c - '0';
+    return h;
+}
+
+/* Verify a file created with sha1sum by redirecting output
+   to a file. */
+int verifyfile(char *fname)
+{
+    int j, k;
+    int found = 0;
+    unsigned char digest[HASHSIZE];
+    unsigned char expected_digest[HASHSIZE];
+    FILE *checkfile;
+    char checkline[LINESIZE];
+    char *s;
+    unsigned char err;
+
+    checkfile = fopen(fname, "rt");
+    if (!checkfile)
+    {
+        fprintf(stderr, "Can't open %s\n", fname);
+        return(0);
+    }
+    do
+    {
+        s = fgets(checkline, LINESIZE, checkfile);
+        if (s)
+        {
+            if ((strlen(checkline)>26)&&
+                1 /*(!strncmp(checkline,"SHA1=", 5))*/)
+            {
+                /* Overwrite newline. */
+                checkline[strlen(checkline)-1]=0;
+                found = 1;
+
+                /* Read expected check value. */
+                for (k=0, j=5; k < HASHSIZE; k++)
+                {
+                    expected_digest[k]=hexval(checkline[j++]);
+                    expected_digest[k]=(expected_digest[k]<<4)
+                        +hexval(checkline[j++]);
+                }
+
+                /* Compute fingerprints */
+                s = checkline+46;
+                sha1file(s, digest);
+
+                /* Compare fingerprints */
+                err = 0;
+                for (k=0; k<HASHSIZE; k++)
+                    err |= digest[k]-
+                        expected_digest[k];
+                if (err)
+                {
+                    fprintf(stderr, "FAILED: %s\n"
+                        " EXPECTED: ", s);
+                    for (k=0; k<HASHSIZE; k++)
+                        fprintf(stderr, "%02X",
+                            expected_digest[k]);
+                    fprintf(stderr,"\n    FOUND: ");
+                    for (k=0; k<HASHSIZE; k++)
+                        fprintf(stderr, "%02X", digest[k]);
+                    fprintf(stderr, "\n");
+                }
+                else
+                {
+                    printf("OK: %s\n", s);
+                }
+            }
+        }
+    } while (s);
+    return found;
+}
+
+
+
+void syntax(char *progname)
+{
+    printf("\nsyntax:\n"
+     "%s [-c|-h][-q] file name[s]\n"
+     "    -c = check files against previous check values\n"
+     "    -g = generate SHA-1 check values (default action)\n"
+     "    -h = display this help\n"
+     "For example,\n"
+     "sha1sum test.txt > check.txt\n"
+     "generates check value for test.txt in check.txt, and\n"
+     "sha1sum -c check.txt\n"
+     "checks test.txt against the check value in check.txt\n",
+     progname);
+    exit(1);
+}
+
+
+/**********************************************************/
+
+int main(int argc, char** argv)
+{
+    int i, j, k;
+    int check = 0;
+    int found = 0;
+    unsigned char digest[HASHSIZE];
+    unsigned char expected_digest[HASHSIZE];
+    FILE *checkfile;
+    char checkline[LINESIZE];
+    char *s;
+#ifdef __BORLANDC__
+    struct ffblk f;
+    int done;
+    char path[MAXPATH];
+    char drive[MAXDRIVE];
+    char dir[MAXDIR];
+    char name[MAXFILE];
+    char ext[MAXEXT];
+#endif
+    unsigned char err;
+
+    for (i = 1; i < argc; i++)
+    {
+        if (argv[i][0] == '-')
+        {
+            switch (argv[i][1])
+            {
+                case 'c':
+                case 'C':
+                    check = 1;
+                    break;
+                case 'g':
+                case 'G':
+                    check = 0;
+                    break;
+                default:
+                    syntax(argv[0]);
+            }
+        }
+    }
+
+    for (i=1; i<argc; i++)
+    {
+        if (argv[i][0] != '-')
+        {
+#ifdef __BORLANDC__
+            fnsplit(argv[i], drive, dir, name, ext);
+            done = findfirst(argv[i], &f, FA_RDONLY |
+                FA_HIDDEN|FA_SYSTEM|FA_ARCH);
+             while (!done)
+            {
+                sprintf(path, "%s%s%s", drive, dir, f.ff_name);
+                s = path;
+#else
+                s = argv[i];
+#endif
+
+                if (check)
+                {   /* Check fingerprint file. */
+                    found |= verifyfile(s);
+                }
+                else
+                {   /* Generate fingerprints & write to
+                       stdout. */
+                    sha1file(s, digest);
+                    //printf("SHA1=");
+                    for (j=0; j<HASHSIZE; j++)
+                        printf("%02x", digest[j]);
+                    printf("  %s\n", s);
+                    found = 1;
+                }
+
+#ifdef __BORLANDC__
+                done = findnext(&f);
+            }
+#endif
+
+        }
+    }
+    if (!found)
+    {
+        if (check)
+        {
+            fprintf(stderr,
+                "No SHA1 lines found in %s\n",
+                argv[i]);
+        }
+        else
+        {
+            fprintf(stderr, "No files checked.\n");
+            syntax(argv[0]);
+        }
+    }
+    return(0);  /* JHB */
+}
+
+#endif  /*CMDLINE*/
diff --git a/libdex/sha1.h b/libdex/sha1.h
new file mode 100644
index 0000000..28907de
--- /dev/null
+++ b/libdex/sha1.h
@@ -0,0 +1,20 @@
+/*
+ * See "sha1.cpp" for author info.
+ */
+#ifndef LIBDEX_SHA1_H_
+#define LIBDEX_SHA1_H_
+
+struct SHA1_CTX {
+    unsigned long state[5];
+    unsigned long count[2];
+    unsigned char buffer[64];
+};
+
+#define HASHSIZE 20
+
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, const unsigned char* data,
+    unsigned long len);
+void SHA1Final(unsigned char digest[HASHSIZE], SHA1_CTX* context);
+
+#endif  // LIBDEX_SHA1_H_
diff --git a/opcode-gen/README.txt b/opcode-gen/README.txt
index ad0d6b2..a210842 100644
--- a/opcode-gen/README.txt
+++ b/opcode-gen/README.txt
@@ -24,7 +24,7 @@
 
 * Run the regen-all script, in this directory. This will regenerate a
   number of tables, definitions, and declarations in the code, in
-  dalvik/dx and libcore/dalvik.
+  dalvik/dx, dalvik/libdex, and libcore/dalvik.
 
 * Implement/update the opcode in C in vm/mterp/c/...
   * Verify new code by running with "dalvik.vm.execution-mode = int:portable"
@@ -54,6 +54,12 @@
 
 * Update the file bytecode.txt, and run regen-all, as per above.
 
+* Update the instruction format list in libdex/InstrUtils.h.
+
+* Update dexDecodeInstruction() in libdex/InstrUtils.c.
+
+* Update dumpInstruction() and its helper code in dexdump/DexDump.c.
+
 * Update the switch inside dvmCompilerMIR2LIR() in
   vm/compiler/codegen/{arm,x86}/CodegenDriver.c. (There may be other
   architectures to deal with too.)
diff --git a/opcode-gen/opcode-gen.awk b/opcode-gen/opcode-gen.awk
index 03e115b..e26a60c 100644
--- a/opcode-gen/opcode-gen.awk
+++ b/opcode-gen/opcode-gen.awk
@@ -144,6 +144,77 @@
     printf("        MAXIMUM_PACKED_VALUE = %d;\n", MAX_PACKED_OPCODE);
 }
 
+emission == "libdex-maximum-values" {
+    emissionHandled = 1;
+
+    printf("#define kMaxOpcodeValue 0x%x\n", MAX_OPCODE);
+    printf("#define kNumPackedOpcodes 0x%x\n", MAX_PACKED_OPCODE + 1);
+}
+
+emission == "libdex-opcode-enum" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        printf("    OP_%-28s = 0x%02x,\n", packedConstName[i], i);
+    }
+}
+
+emission == "libdex-goto-table" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        content = sprintf("        H(OP_%s),", packedConstName[i]);
+        printf("%-78s\\\n", content);
+    }
+}
+
+emission == "libdex-opcode-names" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        printf("    \"%s\",\n", packedName[i]);
+    }
+}
+
+emission == "libdex-widths" {
+    emissionHandled = 1;
+
+    col = 1;
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        value = sprintf("%d,", packedWidth[i]);
+        col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 16, 2, "    ");
+    }
+}
+
+emission == "libdex-flags" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        value = flagsToC(packedFlags[i]);
+        printf("    %s,\n", value);
+    }
+}
+
+emission == "libdex-formats" {
+    emissionHandled = 1;
+
+    col = 1;
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        value = sprintf("kFmt%s,", packedFormat[i]);
+        col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 7, 9, "    ");
+    }
+}
+
+emission == "libdex-index-types" {
+    emissionHandled = 1;
+
+    col = 1;
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        value = sprintf("%s,", indexTypeValues[packedIndexType[i]]);
+        col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 3, 19, "    ");
+    }
+}
+
 # Handle the end of directive processing (must appear after the directive
 # clauses).
 emission != "" {
@@ -351,6 +422,8 @@
 
 # Given a packed opcode, returns the raw (unpacked) opcode value.
 function unpackOpcode(idx) {
+    # Note: This must be the inverse of the corresponding code in
+    # libdex/DexOpcodes.h.
     if (idx <= 255) {
         return idx;
     } else {
diff --git a/opcode-gen/regen-all b/opcode-gen/regen-all
index 585d309..161cda9 100755
--- a/opcode-gen/regen-all
+++ b/opcode-gen/regen-all
@@ -38,6 +38,9 @@
 ${progdir}/opcode-gen dx/src/com/android/dx/dex/code/RopToDop.java
 ${progdir}/opcode-gen dx/src/com/android/dx/io/OpcodeInfo.java
 ${progdir}/opcode-gen dx/src/com/android/dx/io/Opcodes.java
+${progdir}/opcode-gen libdex/DexOpcodes.cpp
+${progdir}/opcode-gen libdex/DexOpcodes.h
+${progdir}/opcode-gen libdex/InstrUtils.cpp
 
 # It's a minor shame that these files live in a different top-level project.
 # So it goes.