auto import from //depot/cupcake/@135843
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
new file mode 100644
index 0000000..d9fe367
--- /dev/null
+++ b/dexdump/Android.mk
@@ -0,0 +1,69 @@
+# 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.c \
+		OpCodeNames.c
+
+dexdump_c_includes := \
+		dalvik \
+		$(JNI_H_INCLUDE)
+
+dexdump_shared_libraries :=
+
+dexdump_static_libraries := \
+		libdex
+
+##
+##
+## 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 := $(dexdump_shared_libraries) libz liblog
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries)
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug development
+LOCAL_LDLIBS +=
+include $(BUILD_EXECUTABLE)
+
+endif # !SDK_ONLY
+
+
+##
+##
+## Build the host command line tool dexdump
+##
+##
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexdump
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_SHARED_LIBRARIES := $(dexdump_shared_libraries)
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries) liblog
+LOCAL_LDLIBS += -lpthread -lz
+include $(BUILD_HOST_EXECUTABLE)
+endif # !TARGET_SIMULATOR
+
diff --git a/dexdump/DexDump.c b/dexdump/DexDump.c
new file mode 100644
index 0000000..a4d97eb
--- /dev/null
+++ b/dexdump/DexDump.c
@@ -0,0 +1,1171 @@
+/*
+ * 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 output format to be more regexp-friendly
+ */
+#include "libdex/DexFile.h"
+#include "libdex/DexCatch.h"
+#include "libdex/DexClass.h"
+#include "libdex/DexProto.h"
+#include "libdex/InstrUtils.h"
+#include "libdex/SysUtil.h"
+#include "libdex/CmdUtils.h"
+
+#include "dexdump/OpCodeNames.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>
+
+static const char* gProgName = "dexdump";
+
+static InstructionWidth* gInstrWidth;
+static InstructionFormat* gInstrFormat;
+
+/* command-line options */
+struct {
+    bool disassemble;
+    bool showFileHeaders;
+    bool showSectionHeaders;
+    const char* tempFileName;
+} gOptions;
+
+/* basic info about a field or method */
+typedef struct FieldMethodInfo {
+    const char* classDescriptor;
+    const char* name;
+    const char* signature;
+} FieldMethodInfo;
+
+/*
+ * Get 2 little-endian bytes. 
+ */ 
+static inline u2 get2LE(unsigned char const* pSrc)
+{
+    return pSrc[0] | (pSrc[1] << 8);
+}   
+
+/*
+ * 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 = malloc(at + 1); /* Add one for the '\0'. */
+    newStr[at] = '\0';
+
+    while (at > 0) {
+        at--;
+        newStr[at] = (str[at] == '/') ? '.' : str[at];
+    }
+
+    return newStr;
+}
+
+/*
+ * Count the number of '1' bits in a word.
+ *
+ * Having completed this, I'm ready for an interview at Google.
+ *
+ * TODO? there's a parallel version w/o loops.  Performance not currently
+ * important.
+ */
+static int countOnes(u4 val)
+{
+    int count = 0;
+
+    while (val != 0) {
+        val &= val-1;
+        count++;
+    }
+
+    return count;
+}
+
+
+/*
+ * Flag for use with createAccessFlagStr().
+ */
+typedef enum AccessFor {
+    kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
+    kAccessForMAX
+} AccessFor;
+
+/*
+ * 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;
+}
+
+
+/*
+ * Dump the file header.
+ */
+void dumpFileHeader(const DexFile* pDexFile)
+{
+    const DexHeader* pHeader = pDexFile->pHeader;
+
+    printf("DEX file header:\n");
+    printf("magic               : '%.8s'\n", pHeader->magic);
+    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("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 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.
+ */
+void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
+    int i)
+{
+    const char* interfaceName =
+        dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
+
+    printf("    #%d              : '%s'\n", i, interfaceName);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Dump a single instruction.
+ */
+void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
+    int insnWidth, const DecodedInstruction* pDecInsn)
+{
+    static const float gSpecialTab[16] = {
+        -2.0f, -1.0f, -0.5f, -0.25f, -0.1f, 0.1f, 0.25f, 0.5f,
+        1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 10.0f, 100.0f, 1000.0f
+    };
+    const u2* insns = pCode->insns;
+    int i;
+
+    printf("%06x:", ((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, getOpcodeName(pDecInsn->opCode));
+    }
+
+    switch (dexGetInstrFormat(gInstrFormat, 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 %lld // #%x",
+                pDecInsn->vA, value, (u2)pDecInsn->vB);
+        }
+        break;
+    case kFmt21c:        // op vAA, thing@BBBB
+        if (pDecInsn->opCode == OP_CONST_STRING) {
+            printf(" v%d, \"%s\" // string@%04x", pDecInsn->vA,
+                dexStringById(pDexFile, pDecInsn->vB), pDecInsn->vB);
+        } else if (pDecInsn->opCode == OP_CHECK_CAST ||
+                   pDecInsn->opCode == OP_NEW_INSTANCE ||
+                   pDecInsn->opCode == OP_CONST_CLASS)
+        {
+            printf(" v%d, %s // class@%04x", pDecInsn->vA,
+                getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB);
+        } else /* OP_SGET* */ {
+            FieldMethodInfo fieldInfo;
+            if (getFieldInfo(pDexFile, pDecInsn->vB, &fieldInfo)) {
+                printf(" v%d, %s.%s:%s // field@%04x", pDecInsn->vA,
+                    fieldInfo.classDescriptor, fieldInfo.name,
+                    fieldInfo.signature, pDecInsn->vB);
+            } else {
+                printf(" v%d, ??? // field@%04x", pDecInsn->vA, pDecInsn->vB);
+            }
+        }
+        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
+        if (pDecInsn->opCode >= OP_IGET && pDecInsn->opCode <= OP_IPUT_SHORT) {
+            FieldMethodInfo fieldInfo;
+            if (getFieldInfo(pDexFile, pDecInsn->vC, &fieldInfo)) {
+                printf(" v%d, v%d, %s.%s:%s // field@%04x", pDecInsn->vA,
+                    pDecInsn->vB, fieldInfo.classDescriptor, fieldInfo.name,
+                    fieldInfo.signature, pDecInsn->vC);
+            } else {
+                printf(" v%d, v%d, ??? // field@%04x", pDecInsn->vA,
+                    pDecInsn->vB, pDecInsn->vC);
+            }
+        } else {
+            printf(" v%d, v%d, %s // class@%04x",
+                pDecInsn->vA, pDecInsn->vB,
+                getClassDescriptor(pDexFile, pDecInsn->vC), pDecInsn->vC);
+        }
+        break;
+    case kFmt22cs:       // [opt] op vA, vB, field offset CCCC
+        printf(" v%d, v%d, [obj+%04x]",
+            pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
+        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 kFmt31c:        // op vAA, thing@BBBBBBBB
+        printf(" v%d, \"%s\" // string@%08x", pDecInsn->vA,
+            dexStringById(pDexFile, pDecInsn->vB), 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 vB, {vD, vE, vF, vG, vA}, thing@CCCC
+        {
+            /* NOTE: decoding of 35c doesn't quite match spec */
+            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]);
+            }
+            if (pDecInsn->opCode == OP_FILLED_NEW_ARRAY) {
+                printf("}, %s // class@%04x",
+                    getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB);
+            } else {
+                FieldMethodInfo methInfo;
+                if (getMethodInfo(pDexFile, pDecInsn->vB, &methInfo)) {
+                    printf("}, %s.%s:%s // method@%04x",
+                        methInfo.classDescriptor, methInfo.name,
+                        methInfo.signature, pDecInsn->vB);
+                } else {
+                    printf("}, ??? // method@%04x", pDecInsn->vB);
+                }
+            }
+        }
+        break;
+    case kFmt35ms:       // [opt] invoke-virtual+super
+    case kFmt35fs:       // [opt] invoke-interface
+        {
+            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("}, [%04x] // vtable #%04x", pDecInsn->vB, pDecInsn->vB);
+        }
+        break;
+    case kFmt3rc:        // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
+        {
+            /*
+             * 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);
+            }
+            if (pDecInsn->opCode == OP_FILLED_NEW_ARRAY_RANGE) {
+                printf("}, %s // class@%04x",
+                    getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB);
+            } else {
+                FieldMethodInfo methInfo;
+                if (getMethodInfo(pDexFile, pDecInsn->vB, &methInfo)) {
+                    printf("}, %s.%s:%s // method@%04x",
+                        methInfo.classDescriptor, methInfo.name,
+                        methInfo.signature, pDecInsn->vB);
+                } else {
+                    printf("}, ??? // method@%04x", pDecInsn->vB);
+                }
+            }
+        }
+        break;
+    case kFmt3rms:       // [opt] invoke-virtual+super/range
+    case kFmt3rfs:       // [opt] invoke-interface/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("}, [%04x] // vtable #%04x", pDecInsn->vB, pDecInsn->vB);
+        }
+        break;
+    case kFmt3inline:    // [opt] inline invoke
+        {
+#if 0
+            const InlineOperation* inlineOpsTable = dvmGetInlineOpsTable();
+            u4 tableLen = dvmGetInlineOpsTableLength();
+#endif
+
+            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]);
+            }
+#if 0
+            if (pDecInsn->vB < tableLen) {
+                printf("}, %s.%s:%s // inline #%04x",
+                    inlineOpsTable[pDecInsn->vB].classDescriptor,
+                    inlineOpsTable[pDecInsn->vB].methodName,
+                    inlineOpsTable[pDecInsn->vB].methodSignature,
+                    pDecInsn->vB);
+            } else {
+#endif
+                printf("}, [%04x] // inline #%04x", pDecInsn->vB, pDecInsn->vB);
+#if 0
+            }
+#endif
+        }
+        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 // #%016llx",
+                pDecInsn->vA, conv.d, pDecInsn->vB_wide);
+        }
+        break;
+    case kFmtUnknown:
+        break;
+    default:
+        printf(" ???");
+        break;
+    }
+
+
+    putchar('\n');
+
+}
+
+/*
+ * 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;
+
+    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);
+
+    insnIdx = 0;
+    while (insnIdx < (int) pCode->insnsSize) {
+        int insnWidth;
+        OpCode opCode;
+        DecodedInstruction decInsn;
+        u2 instr;
+
+        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 = instr & 0xff;
+            insnWidth = dexGetInstrWidthAbs(gInstrWidth, opCode);
+            if (insnWidth == 0) {
+                fprintf(stderr,
+                    "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
+                break;
+            }
+        }
+
+        dexDecodeInstruction(gInstrFormat, 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;
+    char* accessStr;
+
+    pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    name = dexStringById(pDexFile, pMethodId->nameIdx);
+    typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+
+    backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    accessStr = createAccessFlagStr(pDexMethod->accessFlags,
+                    kAccessForMethod);
+
+    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');
+
+    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;
+
+    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);
+
+    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);
+
+    free(accessStr);
+}
+
+/*
+ * Dump an instance field.
+ */
+void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
+{
+    const DexFieldId* pFieldId;
+    const char* backDescriptor;
+    const char* name;
+    const char* typeDescriptor;
+    char* accessStr;
+
+    pFieldId = dexGetFieldId(pDexFile, pIField->fieldIdx);
+    name = dexStringById(pDexFile, pFieldId->nameIdx);
+    typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+    backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
+
+    accessStr = createAccessFlagStr(pIField->accessFlags, kAccessForField);
+
+    printf("    #%d              : (in %s)\n", i, backDescriptor);
+    printf("      name          : '%s'\n", name);
+    printf("      type          : '%s'\n", typeDescriptor);
+    printf("      access        : 0x%04x (%s)\n",
+        pIField->accessFlags, accessStr);
+
+    free(accessStr);
+}
+
+/*
+ * Dump the class.
+ */
+void dumpClass(DexFile* pDexFile, int idx)
+{
+    const DexTypeList* pInterfaces;
+    const DexClassDef* pClassDef;
+    DexClassData* pClassData;
+    const u1* pEncodedData;
+    const char* fileName;
+    const char* classDescriptor;
+    const char* superclassDescriptor;
+    char* accessStr;
+    int i;
+
+    pClassDef = dexGetClassDef(pDexFile, idx);
+    printf("Class #%d            -\n", idx);
+
+    pEncodedData = dexGetClassData(pDexFile, pClassDef);
+    pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+
+    if (pClassData == NULL) {
+        printf("Trouble reading class data\n");
+        return;
+    }
+    
+    classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+    printf("  Class descriptor  : '%s'\n", classDescriptor);
+
+    accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
+    printf("  Access flags      : 0x%04x (%s)\n",
+        pClassDef->accessFlags, accessStr);
+
+    if (pClassDef->superclassIdx == kDexNoIndex)
+        superclassDescriptor = "(none)";
+    else {
+        superclassDescriptor =
+            dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
+        printf("  Superclass        : '%s'\n", superclassDescriptor);
+    }
+
+    printf("  Interfaces        -\n");
+    pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
+    if (pInterfaces != NULL) {
+        for (i = 0; i < (int) pInterfaces->size; i++)
+            dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
+    }
+
+    printf("  Static fields     -\n");
+    for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
+        dumpSField(pDexFile, &pClassData->staticFields[i], i);
+    }
+
+    printf("  Instance fields   -\n");
+    for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
+        dumpIField(pDexFile, &pClassData->instanceFields[i], i);
+    }
+
+    printf("  Direct methods    -\n");
+    for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
+        dumpMethod(pDexFile, &pClassData->directMethods[i], i);
+    }
+
+    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";
+    printf("  source_file_idx   : %d (%s)\n",
+        pClassDef->sourceFileIdx, fileName);
+
+    printf("\n");
+
+    free(pClassData);
+    free(accessStr);
+}
+
+/*
+ * Dump the requested sections of the file.
+ */
+void processDexFile(const char* fileName, DexFile* pDexFile)
+{
+    int i;
+
+    printf("Opened '%s', DEX version '%.3s'\n", fileName,
+        pDexFile->pHeader->magic +4);
+
+    if (gOptions.showFileHeaders)
+        dumpFileHeader(pDexFile);
+
+    for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
+        if (gOptions.showSectionHeaders)
+            dumpClassDef(pDexFile, i);
+
+        dumpClass(pDexFile, i);
+    }
+}
+
+
+/*
+ * Process one file.
+ */
+int process(const char* fileName)
+{
+    DexFile* pDexFile = NULL;
+    MemMapping map;
+    bool mapped = false;
+    int result = -1;
+
+    printf("Processing '%s'...\n", fileName);
+
+    if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0)
+        goto bail;
+    mapped = true;
+
+    pDexFile = dexFileParse(map.addr, map.length,
+        kDexParseVerifyChecksum | kDexParseContinueOnError);
+    if (pDexFile == NULL) {
+        fprintf(stderr, "ERROR: DEX parse failed\n");
+        goto bail;
+    }
+
+    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: [-d] [-f] [-h] [-t tempfile] dexfile...\n", gProgName);
+    fprintf(stderr, "\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, " -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));
+
+    while (1) {
+        ic = getopt(argc, argv, "dfht:");
+        if (ic < 0)
+            break;
+
+        switch (ic) {
+        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 't':       // temp file, used when opening compressed Jar
+            gOptions.tempFileName = argv[optind];
+            break;
+        default:
+            wantUsage = true;
+            break;
+        }
+    }
+
+    if (optind == argc) {
+        fprintf(stderr, "%s: no file specified\n", gProgName);
+        wantUsage = true;
+    }
+
+    /* initialize some VM tables */
+    gInstrWidth = dexCreateInstrWidthTable();
+    gInstrFormat = dexCreateInstrFormatTable();
+
+    if (wantUsage) {
+        usage();
+        return 2;
+    }
+
+    while (optind < argc)
+        process(argv[optind++]);
+
+    free(gInstrWidth);
+    free(gInstrFormat);
+
+    return 0;
+}
diff --git a/dexdump/OpCodeNames.c b/dexdump/OpCodeNames.c
new file mode 100644
index 0000000..378dcf7
--- /dev/null
+++ b/dexdump/OpCodeNames.c
@@ -0,0 +1,330 @@
+/*
+ * 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.
+ */
+#include "OpCodeNames.h"
+
+/*
+ * The following two lines work, but slashes and dashes both turn into
+ * underscores, and the strings are all upper case.  The output is easier
+ * to read if we do the strings by hand (could probably write a
+ * post-processing function easily enough if maintenance becomes annoying).
+ */
+//#define H(_op) #_op
+//DEFINE_GOTO_TABLE(gOpNames)
+
+/*
+ * Dalvik opcode names.
+ */
+static const char* gOpNames[256] = {
+    /* 0x00 */
+    "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",
+
+    /* 0x10 */
+    "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",
+
+    /* 0x20 */
+    "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",
+
+    /* 0x30 */
+    "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",
+    "UNUSED",
+
+    /* 0x40 */
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "aget",
+    "aget-wide",
+    "aget-object",
+    "aget-boolean",
+    "aget-byte",
+    "aget-char",
+    "aget-short",
+    "aput",
+    "aput-wide",
+    "aput-object",
+    "aput-boolean",
+    "aput-byte",
+
+    /* 0x50 */
+    "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",
+
+    /* 0x60 */
+    "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",
+
+    /* 0x70 */
+    "invoke-direct",
+    "invoke-static",
+    "invoke-interface",
+    "UNUSED",
+    "invoke-virtual/range",
+    "invoke-super/range",
+    "invoke-direct/range",
+    "invoke-static/range",
+    "invoke-interface/range",
+    "UNUSED",
+    "UNUSED",
+    "neg-int",
+    "not-int",
+    "neg-long",
+    "not-long",
+    "neg-float",
+
+    /* 0x80 */
+    "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",
+
+    /* 0x90 */
+    "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",
+
+    /* 0xa0 */
+    "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",
+
+    /* 0xb0 */
+    "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",
+
+    /* 0xc0 */
+    "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",
+
+    /* 0xd0 */
+    "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",
+
+    /* 0xe0 */
+    "shl-int/lit8",
+    "shr-int/lit8",
+    "ushr-int/lit8",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "+execute-inline",
+    "UNUSED",
+
+    /* 0xf0 */
+    "+invoke-direct-empty",
+    "UNUSED",
+    "+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",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+    "UNUSED",
+};
+
+/*
+ * Return the name of an opcode.
+ */
+const char* getOpcodeName(OpCode op)
+{
+    return gOpNames[op];
+}
+
diff --git a/dexdump/OpCodeNames.h b/dexdump/OpCodeNames.h
new file mode 100644
index 0000000..1aec0d1
--- /dev/null
+++ b/dexdump/OpCodeNames.h
@@ -0,0 +1,26 @@
+/*
+ * 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 names.
+ */ 
+#ifndef _DEXDUMP_OPCODENAMES
+#define _DEXDUMP_OPCODENAMES
+
+#include "libdex/OpCode.h"
+
+const char* getOpcodeName(OpCode op);
+
+#endif /*_DEXDUMP_OPCODENAMES*/