Fix potential buffer overrun. am: 38025bc7fa am: 805b415be6 am: 0e17e18496 am: 8e37aa191f am: e5c4e849e2 am: 46464a20e0 am: 3bbe8817e6 am: 63e01f731f am: a0af385aae am: f984fa7d59
am: c423f55f64

* commit 'c423f55f64f430d0e56a1809db49129f03760230':
  Fix potential buffer overrun.

Change-Id: I09a8473dcbd22482cdc8015538e82d0a33d86dac
diff --git a/Android.mk b/Android.mk
index 5401832..79e084c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,7 +17,6 @@
 subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
 		libdex \
 		dexgen \
-		dexlist \
 		dexdump \
 		dx \
 		tools \
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
index e92c8cc..47cb4fd 100644
--- a/dexdump/Android.mk
+++ b/dexdump/Android.mk
@@ -42,11 +42,8 @@
 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
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_EXECUTABLE)
 
 endif # !SDK_ONLY
@@ -59,16 +56,11 @@
 ##
 include $(CLEAR_VARS)
 LOCAL_MODULE := dexdump
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_HOST_OS := darwin linux windows
 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
-# TODO: Move dexdump from libdex to libart and lose the 32-bit limitation.
-LOCAL_32_BIT_ONLY := true
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_STATIC_LIBRARIES_windows += libz
+LOCAL_LDLIBS_darwin += -lpthread -lz
+LOCAL_LDLIBS_linux += -lpthread -lz
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
index bfb5aa1..d3735d6 100644
--- a/dexdump/DexDump.cpp
+++ b/dexdump/DexDump.cpp
@@ -49,6 +49,7 @@
 #include <getopt.h>
 #include <errno.h>
 #include <assert.h>
+#include <inttypes.h>
 
 static const char* gProgName = "dexdump";
 
@@ -605,7 +606,7 @@
     }
 }
 
-static int dumpPositionsCb(void *cnxt, u4 address, u4 lineNum)
+static int dumpPositionsCb(void * /* cnxt */, u4 address, u4 lineNum)
 {
     printf("        0x%04x line=%d\n", address, lineNum);
     return 0;
@@ -627,7 +628,7 @@
             pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
 }
 
-static void dumpLocalsCb(void *cnxt, u2 reg, u4 startAddress,
+static void dumpLocalsCb(void * /* cnxt */, u2 reg, u4 startAddress,
         u4 endAddress, const char *name, const char *descriptor,
         const char *signature)
 {
@@ -854,7 +855,9 @@
     const u2* insns = pCode->insns;
     int i;
 
-    printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
+    // 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) {
@@ -939,7 +942,7 @@
                 pDecInsn->vA, value, (u2)pDecInsn->vB);
         } else {
             s8 value = ((s8) pDecInsn->vB) << 48;
-            printf(" v%d, #long %lld // #%x",
+            printf(" v%d, #long %" PRId64 " // #%x",
                 pDecInsn->vA, value, (u2)pDecInsn->vB);
         }
         break;
@@ -1033,7 +1036,7 @@
                 u8 j;
             } conv;
             conv.j = pDecInsn->vB_wide;
-            printf(" v%d, #double %f // #%016llx",
+            printf(" v%d, #double %f // #%016" PRIx64,
                 pDecInsn->vA, conv.d, pDecInsn->vB_wide);
         }
         break;
@@ -1066,6 +1069,10 @@
     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);
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
deleted file mode 100644
index 7ac2b73..0000000
--- a/dexlist/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-#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
-# TODO: Move dexlist from libdex to libart and lose the 32-bit limitation.
-LOCAL_32_BIT_ONLY := true
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlist/DexList.cpp b/dexlist/DexList.cpp
deleted file mode 100644
index 03f0230..0000000
--- a/dexlist/DexList.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * 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/dx/etc/mainDexClasses b/dx/etc/mainDexClasses
index 178ab18..0a83c3d 100755
--- a/dx/etc/mainDexClasses
+++ b/dx/etc/mainDexClasses
@@ -102,6 +102,10 @@
 fi
 
 if [ ! -r "${proguard}" ]; then
+  proguard="${ANDROID_BUILD_TOP}"/external/proguard/bin/${proguardExec}
+fi
+
+if [ ! -r "${proguard}" ]; then
     proguard="`which proguard`"
 fi
 
diff --git a/dx/src/com/android/dx/Version.java b/dx/src/com/android/dx/Version.java
index 1e15d55..0e77941 100644
--- a/dx/src/com/android/dx/Version.java
+++ b/dx/src/com/android/dx/Version.java
@@ -21,5 +21,5 @@
  */
 public class Version {
     /** {@code non-null;} version string */
-    public static final String VERSION = "1.11";
+    public static final String VERSION = "1.12";
 }
diff --git a/dx/src/com/android/dx/cf/code/Simulator.java b/dx/src/com/android/dx/cf/code/Simulator.java
index 35e6228..55a9ac8 100644
--- a/dx/src/com/android/dx/cf/code/Simulator.java
+++ b/dx/src/com/android/dx/cf/code/Simulator.java
@@ -141,14 +141,19 @@
      * actually present on the stack.</p>
      *
      * <p>In the case where there is a known-null on the stack where
-     * an array is expected, we just fall back to the implied type of
-     * the instruction. Due to the quirk described above, this means
-     * that source code that uses <code>boolean[]</code> might get
-     * translated surprisingly -- but correctly -- into an instruction
-     * that specifies a <code>byte[]</code>. It will be correct,
-     * because should the code actually execute, it will necessarily
-     * throw a <code>NullPointerException</code>, and it won't matter
-     * what opcode variant is used to achieve that result.</p>
+     * an array is expected, our behavior depends on the implied type
+     * of the instruction. When the implied type is a reference, we
+     * don't attempt to infer anything, as we don't know the dimension
+     * of the null constant and thus any explicit inferred type could
+     * be wrong. When the implied type is a primitive, we fall back to
+     * the implied type of the instruction. Due to the quirk described
+     * above, this means that source code that uses
+     * <code>boolean[]</code> might get translated surprisingly -- but
+     * correctly -- into an instruction that specifies a
+     * <code>byte[]</code>. It will be correct, because should the
+     * code actually execute, it will necessarily throw a
+     * <code>NullPointerException</code>, and it won't matter what
+     * opcode variant is used to achieve that result.</p>
      *
      * @param impliedType {@code non-null;} type implied by the
      * instruction; is <i>not</i> an array type
@@ -160,7 +165,9 @@
     private static Type requiredArrayTypeFor(Type impliedType,
             Type foundArrayType) {
         if (foundArrayType == Type.KNOWN_NULL) {
-            return impliedType.getArrayType();
+            return impliedType.isReference()
+                ? Type.KNOWN_NULL
+                : impliedType.getArrayType();
         }
 
         if ((impliedType == Type.OBJECT)
@@ -317,7 +324,9 @@
                         requiredArrayTypeFor(type, foundArrayType);
 
                     // Make type agree with the discovered requiredArrayType.
-                    type = requiredArrayType.getComponentType();
+                    type = (requiredArrayType == Type.KNOWN_NULL)
+                        ? Type.KNOWN_NULL
+                        : requiredArrayType.getComponentType();
 
                     machine.popArgs(frame, requiredArrayType, Type.INT);
                     break;
@@ -375,7 +384,9 @@
                      * if it has local info.
                      */
                     if (foundArrayLocal) {
-                        type = requiredArrayType.getComponentType();
+                        type = (requiredArrayType == Type.KNOWN_NULL)
+                            ? Type.KNOWN_NULL
+                            : requiredArrayType.getComponentType();
                     }
 
                     machine.popArgs(frame, requiredArrayType, Type.INT, type);
diff --git a/dx/src/com/android/dx/cf/direct/DirectClassFile.java b/dx/src/com/android/dx/cf/direct/DirectClassFile.java
index f908547..089e43a 100644
--- a/dx/src/com/android/dx/cf/direct/DirectClassFile.java
+++ b/dx/src/com/android/dx/cf/direct/DirectClassFile.java
@@ -415,21 +415,29 @@
     }
 
     /**
-     * Sees if the .class file header magic/version are within
-     * range.
+     * Sees if the .class file header magic has the good value.
      *
      * @param magic the value of a classfile "magic" field
+     * @return true if the magic is valid
+     */
+    private boolean isGoodMagic(int magic) {
+        return magic == CLASS_FILE_MAGIC;
+    }
+
+    /**
+     * Sees if the .class file header version are within
+     * range.
+     *
      * @param minorVersion the value of a classfile "minor_version" field
      * @param majorVersion the value of a classfile "major_version" field
-     * @return true iff the parameters are valid and within range
+     * @return true if the parameters are valid and within range
      */
-    private boolean isGoodVersion(int magic, int minorVersion,
-            int majorVersion) {
+    private boolean isGoodVersion(int minorVersion, int majorVersion) {
         /* Valid version ranges are typically of the form
          * "A.0 through B.C inclusive" where A <= B and C >= 0,
          * which is why we don't have a CLASS_FILE_MIN_MINOR_VERSION.
          */
-        if (magic == CLASS_FILE_MAGIC && minorVersion >= 0) {
+        if (minorVersion >= 0) {
             /* Check against max first to handle the case where
              * MIN_MAJOR == MAX_MAJOR.
              */
@@ -467,13 +475,14 @@
             /* Make sure that this looks like a valid class file with a
              * version that we can handle.
              */
-            if (!isGoodVersion(getMagic0(), getMinorVersion0(),
-                               getMajorVersion0())) {
-                throw new ParseException("bad class file magic (" +
-                                         Hex.u4(getMagic0()) +
-                                         ") or version (" +
-                                         Hex.u2(getMajorVersion0()) + "." +
-                                         Hex.u2(getMinorVersion0()) + ")");
+            if (!isGoodMagic(getMagic0())) {
+                throw new ParseException("bad class file magic (" + Hex.u4(getMagic0()) + ")");
+            }
+
+            if (!isGoodVersion(getMinorVersion0(), getMajorVersion0())) {
+                throw new ParseException("unsupported class file version " +
+                                         getMajorVersion0() + "." +
+                                         getMinorVersion0());
             }
         }
 
diff --git a/dx/src/com/android/dx/command/dexer/Main.java b/dx/src/com/android/dx/command/dexer/Main.java
index e93c6a3..e42eb54 100644
--- a/dx/src/com/android/dx/command/dexer/Main.java
+++ b/dx/src/com/android/dx/command/dexer/Main.java
@@ -595,7 +595,12 @@
                     // class translation and adding to dex.
                     int count = errors.incrementAndGet();
                     if (count < 10) {
-                        DxConsole.err.println("Uncaught translation error: " + ex.getCause());
+                        if (args.debug) {
+                            DxConsole.err.println("Uncaught translation error:");
+                            ex.getCause().printStackTrace(DxConsole.err);
+                        } else {
+                            DxConsole.err.println("Uncaught translation error: " + ex.getCause());
+                        }
                     } else {
                         throw new InterruptedException("Too many errors");
                     }
@@ -748,6 +753,9 @@
         try {
             new DirectClassFileConsumer(name, bytes, null).call(
                     new ClassParserTask(name, bytes).call());
+        } catch (ParseException ex) {
+            // handled in FileBytesConsumer
+            throw ex;
         } catch(Exception ex) {
             throw new RuntimeException("Exception parsing classes", ex);
         }
@@ -1653,6 +1661,14 @@
                 DxConsole.err.println("\nEXCEPTION FROM SIMULATION:");
                 DxConsole.err.println(ex.getMessage() + "\n");
                 DxConsole.err.println(((SimException) ex).getContext());
+            } else if (ex instanceof ParseException) {
+                DxConsole.err.println("\nPARSE ERROR:");
+                ParseException parseException = (ParseException) ex;
+                if (args.debug) {
+                    parseException.printStackTrace(DxConsole.err);
+                } else {
+                    parseException.printContext(DxConsole.err);
+                }
             } else {
                 DxConsole.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
                 ex.printStackTrace(DxConsole.err);
diff --git a/dx/src/com/android/dx/merge/DexMerger.java b/dx/src/com/android/dx/merge/DexMerger.java
index 041ebd2..ea4cb2c 100644
--- a/dx/src/com/android/dx/merge/DexMerger.java
+++ b/dx/src/com/android/dx/merge/DexMerger.java
@@ -168,7 +168,7 @@
         contentsOut.header.size = 1;
         contentsOut.fileSize = dexOut.getLength();
         contentsOut.computeSizesFromOffsets();
-        contentsOut.writeHeader(headerOut);
+        contentsOut.writeHeader(headerOut, mergeApiLevels());
         contentsOut.writeMap(mapListOut);
 
         // generate and write the hashes
@@ -357,6 +357,17 @@
         }
     }
 
+    private int mergeApiLevels() {
+        int maxApi = -1;
+        for (int i = 0; i < dexes.length; i++) {
+            int dexMinApi = dexes[i].getTableOfContents().apiLevel;
+            if (maxApi < dexMinApi) {
+                maxApi = dexMinApi;
+            }
+        }
+        return maxApi;
+    }
+
     private void mergeStringIds() {
         new IdMerger<String>(idsDefsOut) {
             @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
@@ -1057,8 +1068,9 @@
             } else {
                 // at most 1/4 of the bytes in a code section are uleb/sleb
                 code += (int) Math.ceil(contents.codes.byteCount * 1.25);
-                // at most 1/3 of the bytes in a class data section are uleb/sleb
-                classData += (int) Math.ceil(contents.classDatas.byteCount * 1.34);
+                // at most 2/3 of the bytes in a class data section are uleb/sleb that may change
+                // (assuming the worst case that section contains only methods and no fields)
+                classData += (int) Math.ceil(contents.classDatas.byteCount * 1.67);
                 // all of the bytes in an encoding arrays section may be uleb/sleb
                 encodedArray += contents.encodedArrays.byteCount * 2;
                 // all of the bytes in an annotations section may be uleb/sleb
diff --git a/dx/src/com/android/multidex/ClassReferenceListBuilder.java b/dx/src/com/android/multidex/ClassReferenceListBuilder.java
index 8218693..6901ece 100644
--- a/dx/src/com/android/multidex/ClassReferenceListBuilder.java
+++ b/dx/src/com/android/multidex/ClassReferenceListBuilder.java
@@ -17,14 +17,14 @@
 package com.android.multidex;
 
 import com.android.dx.cf.direct.DirectClassFile;
+import com.android.dx.cf.iface.FieldList;
+import com.android.dx.cf.iface.MethodList;
 import com.android.dx.rop.cst.Constant;
-import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstBaseMethodRef;
 import com.android.dx.rop.cst.CstFieldRef;
-import com.android.dx.rop.cst.CstMethodRef;
 import com.android.dx.rop.cst.CstType;
 import com.android.dx.rop.type.Prototype;
 import com.android.dx.rop.type.StdTypeList;
-import com.android.dx.rop.type.Type;
 import com.android.dx.rop.type.TypeList;
 
 import java.io.FileNotFoundException;
@@ -87,8 +87,7 @@
                     throw new IOException("Class " + name +
                             " is missing form original class path " + path, e);
                 }
-
-                addDependencies(classFile.getConstantPool());
+                addDependencies(classFile);
             }
         }
     }
@@ -97,34 +96,48 @@
         return classNames;
     }
 
-    private void addDependencies(ConstantPool pool) {
-        for (Constant constant : pool.getEntries()) {
+    private void addDependencies(DirectClassFile classFile) {
+        for (Constant constant : classFile.getConstantPool().getEntries()) {
             if (constant instanceof CstType) {
-                checkDescriptor(((CstType) constant).getClassType());
+                checkDescriptor(((CstType) constant).getClassType().getDescriptor());
             } else if (constant instanceof CstFieldRef) {
-                checkDescriptor(((CstFieldRef) constant).getType());
-            } else if (constant instanceof CstMethodRef) {
-                Prototype proto = ((CstMethodRef) constant).getPrototype();
-                checkDescriptor(proto.getReturnType());
-                StdTypeList args = proto.getParameterTypes();
-                for (int i = 0; i < args.size(); i++) {
-                    checkDescriptor(args.get(i));
-                }
+                checkDescriptor(((CstFieldRef) constant).getType().getDescriptor());
+            } else if (constant instanceof CstBaseMethodRef) {
+                checkPrototype(((CstBaseMethodRef) constant).getPrototype());
             }
         }
+
+        FieldList fields = classFile.getFields();
+        int nbField = fields.size();
+        for (int i = 0; i < nbField; i++) {
+          checkDescriptor(fields.get(i).getDescriptor().getString());
+        }
+
+        MethodList methods = classFile.getMethods();
+        int nbMethods = methods.size();
+        for (int i = 0; i < nbMethods; i++) {
+          checkPrototype(Prototype.intern(methods.get(i).getDescriptor().getString()));
+        }
     }
 
-    private void checkDescriptor(Type type) {
-        String descriptor = type.getDescriptor();
-        if (descriptor.endsWith(";")) {
-            int lastBrace = descriptor.lastIndexOf('[');
+    private void checkPrototype(Prototype proto) {
+      checkDescriptor(proto.getReturnType().getDescriptor());
+      StdTypeList args = proto.getParameterTypes();
+      for (int i = 0; i < args.size(); i++) {
+          checkDescriptor(args.get(i).getDescriptor());
+      }
+    }
+
+    private void checkDescriptor(String typeDescriptor) {
+        if (typeDescriptor.endsWith(";")) {
+            int lastBrace = typeDescriptor.lastIndexOf('[');
             if (lastBrace < 0) {
-                addClassWithHierachy(descriptor.substring(1, descriptor.length()-1));
+                addClassWithHierachy(typeDescriptor.substring(1, typeDescriptor.length()-1));
             } else {
-                assert descriptor.length() > lastBrace + 3
-                && descriptor.charAt(lastBrace + 1) == 'L';
-                addClassWithHierachy(descriptor.substring(lastBrace + 2,
-                        descriptor.length() - 1));
+                assert typeDescriptor.length() > lastBrace + 3
+                && typeDescriptor.charAt(lastBrace + 1) == 'L';
+                addClassWithHierachy(typeDescriptor.substring(lastBrace + 2,
+                        typeDescriptor.length() - 1));
             }
         }
     }
diff --git a/dx/tests/029-unit-Bits/run b/dx/tests/029-unit-Bits/run
index 9937ce5..73c3dd6 100644
--- a/dx/tests/029-unit-Bits/run
+++ b/dx/tests/029-unit-Bits/run
@@ -14,7 +14,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-dx --junit com.android.dx.util._tests._Bits > unit-out.txt
+prog=`which dx`
+progdir=`dirname "${prog}"`
+dxjar=$progdir/../framework/dx.jar
+dxtestsjar=$progdir/../framework/dx-tests.jar
+junitjar=$progdir/../framework/junit.jar
+
+java -cp $dxtestsjar:$dxjar:$junitjar junit.textui.TestRunner com.android.dx.util.BitsTest > unit-out.txt 2>&1
 
 if [ "$?" = "0" ]; then
     echo "Yay!"
diff --git a/dx/tests/033-unit-IntList/run b/dx/tests/033-unit-IntList/run
index 16ca6fb..92071b1 100644
--- a/dx/tests/033-unit-IntList/run
+++ b/dx/tests/033-unit-IntList/run
@@ -14,7 +14,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-dx --junit com.android.dx.util._tests._IntList > unit-out.txt
+prog=`which dx`
+progdir=`dirname "${prog}"`
+dxjar=$progdir/../framework/dx.jar
+dxtestsjar=$progdir/../framework/dx-tests.jar
+junitjar=$progdir/../framework/junit.jar
+
+java -cp $dxtestsjar:$dxjar:$junitjar junit.textui.TestRunner com.android.dx.util.IntListTest > unit-out.txt 2>&1
 
 if [ "$?" = "0" ]; then
     echo "Yay!"
diff --git a/dx/tests/111-use-null-as-array/expected.txt b/dx/tests/111-use-null-as-array/expected.txt
index 7e2116b..cbb49ea 100644
--- a/dx/tests/111-use-null-as-array/expected.txt
+++ b/dx/tests/111-use-null-as-array/expected.txt
@@ -114,3 +114,137 @@
   0003: const/16 v2, #int 16 // #0010
   0005: aput v2, v0, v1
   0007: return-void
+multidimensional.test_getBooleanArray:()Z:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget-byte v0, v0, v1
+  0006: return v0
+multidimensional.test_getByteArray:()B:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget-byte v0, v0, v1
+  0006: return v0
+multidimensional.test_getCharArray:()C:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget-char v0, v0, v1
+  0006: return v0
+multidimensional.test_getDoubleArray:()D:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget-wide v0, v0, v1
+  0006: return-wide v0
+multidimensional.test_getFloatArray:()F:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget v0, v0, v1
+  0006: return v0
+multidimensional.test_getIntArray:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget v0, v0, v1
+  0006: return v0
+multidimensional.test_getLongArray:()J:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget-wide v0, v0, v1
+  0006: return-wide v0
+multidimensional.test_getObjectArray:()Ljava/lang/Object;:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget-object v0, v0, v1
+  0006: return-object v0
+multidimensional.test_getShortArray:()S:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: aget-short v0, v0, v1
+  0006: return v0
+multidimensional.test_setBooleanArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v2, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v2
+  0004: const/4 v1, #int 0 // #0
+  0005: aput v1, v0, v2
+  0007: return-void
+multidimensional.test_setByteArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v2, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v2
+  0004: const/4 v1, #int 0 // #0
+  0005: aput v1, v0, v2
+  0007: return-void
+multidimensional.test_setCharArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v2, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v2
+  0004: const/4 v1, #int 0 // #0
+  0005: aput v1, v0, v2
+  0007: return-void
+multidimensional.test_setDoubleArray:()V:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: const-wide/16 v2, #double 0.0 // #0000
+  0006: aput-wide v2, v0, v1
+  0008: return-void
+multidimensional.test_setFloatArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v2, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v2
+  0004: const/4 v1, #float 0.0 // #0
+  0005: aput v1, v0, v2
+  0007: return-void
+multidimensional.test_setIntArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v2, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v2
+  0004: const/4 v1, #int 0 // #0
+  0005: aput v1, v0, v2
+  0007: return-void
+multidimensional.test_setLongArray:()V:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v1
+  0004: const-wide/16 v2, #long 0 // #0000
+  0006: aput-wide v2, v0, v1
+  0008: return-void
+multidimensional.test_setObjectArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v2, #null // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: aget-object v0, v2, v1
+  0004: aput-object v2, v0, v1
+  0006: return-void
+multidimensional.test_setShortArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v2, #int 1 // #1
+  0001: const/4 v0, #null // #0
+  0002: aget-object v0, v0, v2
+  0004: const/4 v1, #int 0 // #0
+  0005: aput v1, v0, v2
+  0007: return-void
diff --git a/dx/tests/111-use-null-as-array/multidimensional.sh b/dx/tests/111-use-null-as-array/multidimensional.sh
new file mode 100644
index 0000000..d1afede
--- /dev/null
+++ b/dx/tests/111-use-null-as-array/multidimensional.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+echo '
+.class multidimensional
+.super java/lang/Object
+'
+
+function onetype() {
+local typename=$1
+local stacksize=$2
+local defaultvalue=$3
+local descriptor=$4
+local defaultload=$5
+local loadstoreprefix=$6
+local returnprefix=${7:-$loadstoreprefix}
+echo "
+; Output from some versions of javac on:
+; public static $typename test_get${typename^}Array() {
+;     $typename[][] array = null;
+;     return array[1][1];
+; }
+.method public static test_get${typename^}Array()$descriptor
+    .limit locals 1
+    .limit stack 2
+
+    aconst_null
+    astore_0
+    aload_0
+    iconst_1
+    aaload
+    iconst_1
+    ${loadstoreprefix}aload
+    ${returnprefix}return
+.end method
+
+; Output from some versions of javac on:
+; public static void test_set${typename^}Array() {
+;     $typename[][] array = null;
+;     array[1][1] = $defaultvalue;
+; }
+.method public static test_set${typename^}Array()V
+    .limit locals 1
+    .limit stack $((stacksize+2))
+
+    aconst_null
+    astore_0
+    aload_0
+    iconst_1
+    aaload
+    iconst_1
+    $defaultload
+    ${loadstoreprefix}astore
+    return
+.end method
+"
+}
+
+onetype Object 1 null 'Ljava/lang/Object;' aconst_null a
+onetype boolean 1 false Z iconst_0 b i
+onetype byte 1 0 B iconst_0 b i
+onetype char 1 0 C iconst_0 c i
+onetype short 1 0 S iconst_0 s i
+onetype int 1 0 I iconst_0 i
+onetype long 2 0 J lconst_0 l
+onetype float 1 0 F fconst_0 f
+onetype double 2 0 D dconst_0 d
diff --git a/dx/tests/111-use-null-as-array/run b/dx/tests/111-use-null-as-array/run
index 7e4e1e8..ee89d3e 100644
--- a/dx/tests/111-use-null-as-array/run
+++ b/dx/tests/111-use-null-as-array/run
@@ -16,4 +16,9 @@
 
 $JAVAC -g -d . Blort.java
 dx --debug --dex --positions=none --no-locals \
-    --dump-to=- --dump-method="Blort.test*" *.class
+    --dump-to=- --dump-method="Blort.test*" Blort.class
+
+bash multidimensional.sh > multidimensional.j
+jasmin -d . multidimensional.j >/dev/null
+dx --debug --dex --positions=none --no-locals \
+    --dump-to=- --dump-method="multidimensional.*" multidimensional.class
diff --git a/dx/tests/115-merge/run b/dx/tests/115-merge/run
index 83e5b3d..517800d 100644
--- a/dx/tests/115-merge/run
+++ b/dx/tests/115-merge/run
@@ -18,8 +18,10 @@
 prog=`which dx`
 progdir=`dirname "${prog}"`
 dxjar=$progdir/../framework/dx.jar
+junitjar=$progdir/../framework/junit.jar
+junitdex=$progdir/../framework/junit-hostdex.jar
 
-javac -cp $dxjar `find . -name "*.java"`
+javac -cp $dxjar:$junitjar `find . -name "*.java"`
 dx --dex --output=test.jar com/android/dx/merge/* $dxjar
 
 # Build a resource .jar containing the .dex files to merge
@@ -30,8 +32,8 @@
 dx --dex --output=testdata/TryCatchFinally.dex testdata/TryCatchFinally*
 jar cfM resources.jar testdata/*.dex
 
-dalvik -classpath test.jar:resources.jar \
-  junit.textui.TestRunner com.android.dx.merge.DexMergeTest > unit-out.txt
+art -classpath test.jar:$junitdex:resources.jar \
+  junit.textui.TestRunner com.android.dx.merge.DexMergeTest > unit-out.txt 2>&1
 
 if [ "$?" = "0" ]; then
     echo "Yay!"
diff --git a/dx/tests/116-leb128/run b/dx/tests/116-leb128/run
index 5f36cd9..53a7ee3 100644
--- a/dx/tests/116-leb128/run
+++ b/dx/tests/116-leb128/run
@@ -18,9 +18,10 @@
 prog=`which dx`
 progdir=`dirname "${prog}"`
 dxjar=$progdir/../framework/dx.jar
+junitjar=$progdir/../framework/junit.jar
 
-javac -cp $dxjar `find . -name "*.java"`
-java -classpath $dxjar:. junit.textui.TestRunner com.android.dx.util.Leb128UtilsTest > unit-out.txt
+javac -cp $dxjar:$junitjar `find . -name "*.java"`
+java -classpath $dxjar:$junitjar:. junit.textui.TestRunner com.android.dx.util.Leb128UtilsTest > unit-out.txt 2>&1
 
 if [ "$?" = "0" ]; then
     echo "Yay!"
diff --git a/dx/tests/117-modified-utf8/run b/dx/tests/117-modified-utf8/run
index a4c202e..7199349 100644
--- a/dx/tests/117-modified-utf8/run
+++ b/dx/tests/117-modified-utf8/run
@@ -18,9 +18,10 @@
 prog=`which dx`
 progdir=`dirname "${prog}"`
 dxjar=$progdir/../framework/dx.jar
+junitjar=$progdir/../framework/junit.jar
 
-javac -cp $dxjar `find . -name "*.java"`
-java -classpath $dxjar:. junit.textui.TestRunner com.android.dx.util.Mutf8Test > unit-out.txt
+javac -cp $dxjar:$junitjar `find . -name "*.java"`
+java -classpath $dxjar:$junitjar:. junit.textui.TestRunner com.android.dx.util.Mutf8Test > unit-out.txt 2>&1
 
 if [ "$?" = "0" ]; then
     echo "Yay!"
diff --git a/dx/tests/119-merge-conflict/run b/dx/tests/119-merge-conflict/run
index 28c152d..cac754e 100644
--- a/dx/tests/119-merge-conflict/run
+++ b/dx/tests/119-merge-conflict/run
@@ -18,8 +18,10 @@
 prog=`which dx`
 progdir=`dirname "${prog}"`
 dxjar=$progdir/../framework/dx.jar
+junitjar=$progdir/../framework/junit.jar
+junitdex=$progdir/../framework/junit-hostdex.jar
 
-javac -cp $dxjar `find . -name "*.java"`
+javac -cp $dxjar:$junitjar `find . -name "*.java"`
 dx --dex --output=test.jar com/android/dx/merge/* $dxjar
 
 # Build a resource .jar containing the .dex files to merge
@@ -27,8 +29,8 @@
 dx --dex --output=testdata/B.dex testdata/B.class
 jar cfM resources.jar testdata/*.dex
 
-dalvik -classpath test.jar:resources.jar \
-  junit.textui.TestRunner com.android.dx.merge.MergeConflictTest > unit-out.txt
+art -classpath test.jar:$junitdex:resources.jar \
+  junit.textui.TestRunner com.android.dx.merge.MergeConflictTest > unit-out.txt 2>&1
 
 if [ "$?" = "0" ]; then
     echo "Yay!"
diff --git a/dx/tests/125-main-dex-list/run b/dx/tests/125-main-dex-list/run
index 6cba980..4860625 100644
--- a/dx/tests/125-main-dex-list/run
+++ b/dx/tests/125-main-dex-list/run
@@ -24,7 +24,7 @@
 dx -JXmx1024m --dex --no-optimize --multi-dex --main-dex-list=main.list --minimal-main-dex --output=out classes
 
 
-dalvik -classpath test.jar com.android.dx.multidex.MainDexListTest > unit-out.txt
+art -classpath test.jar com.android.dx.multidex.MainDexListTest > unit-out.txt 2>&1
 
 if [ "$?" = "0" ]; then
     echo "Yay!"
diff --git a/libdex/Android.mk b/libdex/Android.mk
index 15e7ba7..960d689 100644
--- a/libdex/Android.mk
+++ b/libdex/Android.mk
@@ -56,7 +56,6 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := libdex
 LOCAL_32_BIT_ONLY := true
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 endif # !SDK_ONLY
@@ -73,8 +72,6 @@
 LOCAL_CPPFLAGS := -std=gnu++11
 LOCAL_STATIC_LIBRARIES := liblog libutils
 LOCAL_WHOLE_STATIC_LIBRARIES := libziparchive-host
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_MODULE := libdex
-LOCAL_32_BIT_ONLY := true
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libdex/CmdUtils.cpp b/libdex/CmdUtils.cpp
index cdb7bb9..8244a11 100644
--- a/libdex/CmdUtils.cpp
+++ b/libdex/CmdUtils.cpp
@@ -54,7 +54,7 @@
         goto bail;
     }
 
-    fd = open(outFileName, O_RDWR | O_CREAT | O_EXCL, 0600);
+    fd = open(outFileName, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
     if (fd < 0) {
         fprintf(stderr, "Unable to create output file '%s': %s\n",
             outFileName, strerror(errno));
diff --git a/libdex/DexDataMap.cpp b/libdex/DexDataMap.cpp
index 8405e8c..65da14c 100644
--- a/libdex/DexDataMap.cpp
+++ b/libdex/DexDataMap.cpp
@@ -36,7 +36,8 @@
     /*
      * Avoiding pulling in safe_iop for safe_iopf.
      */
-    if (!safe_mul(&size, maxCount, sizeof(u4) + sizeof(u2)) ||
+    const u4 sizeOfItems = (u4) (sizeof(u4) + sizeof(u2));
+    if (!safe_mul(&size, maxCount, sizeOfItems) ||
         !safe_add(&size, size, sizeof(DexDataMap))) {
       return NULL;
     }
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index e8ab319..593d414 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -87,6 +87,11 @@
 /* DEX file magic number */
 #define DEX_MAGIC       "dex\n"
 
+/* The version for android N, encoded in 4 bytes of ASCII. This differentiates dex files that may
+ * use default methods.
+ */
+#define DEX_MAGIC_VERS_37  "037\0"
+
 /* current version, encoded in 4 bytes of ASCII */
 #define DEX_MAGIC_VERS  "036\0"
 
diff --git a/libdex/DexSwapVerify.cpp b/libdex/DexSwapVerify.cpp
index 7f18831..2b653b8 100644
--- a/libdex/DexSwapVerify.cpp
+++ b/libdex/DexSwapVerify.cpp
@@ -378,8 +378,8 @@
 
     SWAP_FIELD4(pMap->size);
     count = pMap->size;
-
-    CHECK_LIST_SIZE(item, count, sizeof(DexMapItem));
+    const u4 sizeOfItem = (u4) sizeof(DexMapItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
 
     while (count--) {
         SWAP_FIELD2(item->type);
@@ -1044,7 +1044,8 @@
     bool first = true;
     u4 lastIdx = 0;
 
-    CHECK_LIST_SIZE(item, count, sizeof(DexFieldAnnotationsItem));
+    const u4 sizeOfItem = (u4) sizeof(DexFieldAnnotationsItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
 
     while (count--) {
         SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize);
@@ -1073,7 +1074,8 @@
     bool first = true;
     u4 lastIdx = 0;
 
-    CHECK_LIST_SIZE(item, count, sizeof(DexMethodAnnotationsItem));
+    const u4 sizeOfItem = (u4) sizeof(DexMethodAnnotationsItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
 
     while (count--) {
         SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
@@ -1103,7 +1105,8 @@
     bool first = true;
     u4 lastIdx = 0;
 
-    CHECK_LIST_SIZE(item, count, sizeof(DexParameterAnnotationsItem));
+    const u4 sizeOfItem = (u4) sizeof(DexParameterAnnotationsItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
 
     while (count--) {
         SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
@@ -1305,7 +1308,9 @@
     SWAP_FIELD4(pTypeList->size);
     count = pTypeList->size;
     pType = pTypeList->list;
-    CHECK_LIST_SIZE(pType, count, sizeof(DexTypeItem));
+
+    const u4 sizeOfItem = (u4) sizeof(DexTypeItem);
+    CHECK_LIST_SIZE(pType, count, sizeOfItem);
 
     while (count--) {
         SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize);
@@ -1326,7 +1331,9 @@
     SWAP_FIELD4(list->size);
     count = list->size;
     item = list->list;
-    CHECK_LIST_SIZE(item, count, sizeof(DexAnnotationSetRefItem));
+
+    const u4 sizeOfItem = (u4) sizeof(DexAnnotationSetRefItem);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
 
     while (count--) {
         SWAP_OFFSET4(item->annotationsOff);
@@ -1365,7 +1372,9 @@
     SWAP_FIELD4(set->size);
     count = set->size;
     item = set->entries;
-    CHECK_LIST_SIZE(item, count, sizeof(u4));
+
+    const u4 sizeOfItem = (u4) sizeof(u4);
+    CHECK_LIST_SIZE(item, count, sizeOfItem);
 
     while (count--) {
         SWAP_OFFSET4(*item);
@@ -1739,7 +1748,8 @@
     u4 count = code->triesSize;
     u4 lastEnd = 0;
 
-    CHECK_LIST_SIZE(tries, count, sizeof(DexTry));
+    const u4 sizeOfItem = (u4) sizeof(DexTry);
+    CHECK_LIST_SIZE(tries, count, sizeOfItem);
 
     while (count--) {
         u4 i;
@@ -1818,7 +1828,9 @@
 
     count = item->insnsSize;
     insns = item->insns;
-    CHECK_LIST_SIZE(insns, count, sizeof(u2));
+
+    const u4 sizeOfItem = (u4) sizeof(u2);
+    CHECK_LIST_SIZE(insns, count, sizeOfItem);
 
     while (count--) {
         *insns = SWAP2(*insns);
@@ -2780,7 +2792,8 @@
     }
 
     if ((memcmp(version, DEX_MAGIC_VERS, 4) != 0) &&
-            (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0)) {
+            (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0) &&
+            (memcmp(version, DEX_MAGIC_VERS_37, 4) != 0)) {
         /*
          * Magic was correct, but this is an unsupported older or
          * newer format variant.
diff --git a/libdex/ZipArchive.h b/libdex/ZipArchive.h
index e293bf0..206afd5 100644
--- a/libdex/ZipArchive.h
+++ b/libdex/ZipArchive.h
@@ -70,7 +70,7 @@
  */
 DEX_INLINE int  dexZipFindEntry(const ZipArchiveHandle pArchive,
     const char* entryName, ZipEntry* data) {
-    return FindEntry(pArchive, ZipEntryName(entryName), data);
+    return FindEntry(pArchive, ZipString(entryName), data);
 }
 
 /*
diff --git a/tools/dexdeps/src/com/android/dexdeps/DexData.java b/tools/dexdeps/src/com/android/dexdeps/DexData.java
index 89dff18..6f4fe80 100644
--- a/tools/dexdeps/src/com/android/dexdeps/DexData.java
+++ b/tools/dexdeps/src/com/android/dexdeps/DexData.java
@@ -18,6 +18,7 @@
 
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 
 /**
@@ -66,8 +67,8 @@
      * Verifies the given magic number.
      */
     private static boolean verifyMagic(byte[] magic) {
-        return Arrays.equals(magic, HeaderItem.DEX_FILE_MAGIC) ||
-            Arrays.equals(magic, HeaderItem.DEX_FILE_MAGIC_API_13);
+        return Arrays.equals(magic, HeaderItem.DEX_FILE_MAGIC_v035) ||
+            Arrays.equals(magic, HeaderItem.DEX_FILE_MAGIC_v037);
     }
 
     /**
@@ -538,10 +539,16 @@
         public int classDefsSize, classDefsOff;
 
         /* expected magic values */
-        public static final byte[] DEX_FILE_MAGIC = {
-            0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x36, 0x00 };
-        public static final byte[] DEX_FILE_MAGIC_API_13 = {
-            0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
+        public static final byte[] DEX_FILE_MAGIC_v035 =
+            "dex\n035\0".getBytes(StandardCharsets.US_ASCII);
+
+        // Dex version 036 skipped because of an old dalvik bug on some versions
+        // of android where dex files with that version number would erroneously
+        // be accepted and run. See: art/runtime/dex_file.cc
+
+        // V037 was introduced in API LEVEL 24
+        public static final byte[] DEX_FILE_MAGIC_v037 =
+            "dex\n037\0".getBytes(StandardCharsets.US_ASCII);
         public static final int ENDIAN_CONSTANT = 0x12345678;
         public static final int REVERSE_ENDIAN_CONSTANT = 0x78563412;
     }
diff --git a/tools/dmtracedump/Android.mk b/tools/dmtracedump/Android.mk
deleted file mode 100644
index 933f4e5..0000000
--- a/tools/dmtracedump/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright 2006 The Android Open Source Project
-#
-# Java method trace dump tool
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := TraceDump.c
-LOCAL_CFLAGS += -O0 -g
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := dmtracedump
-include $(BUILD_HOST_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := CreateTestTrace.c
-LOCAL_CFLAGS += -O0 -g
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := create_test_dmtrace
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/dmtracedump/CreateTestTrace.c b/tools/dmtracedump/CreateTestTrace.c
deleted file mode 100644
index a4ae02e..0000000
--- a/tools/dmtracedump/CreateTestTrace.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/* //device/tools/dmtracedump/CreateTrace.c
-**
-** Copyright 2006, 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.
-*/
-
-/*
- * Create a test file in the format required by dmtrace.
- */
-#define NOT_VM
-#include "Profile.h"        // from VM header
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <time.h>
-#include <ctype.h>
-
-/*
- * Values from the header of the data file.
- */
-typedef struct DataHeader {
-    unsigned int magic;
-    short version;
-    short offsetToData;
-    long long startWhen;
-} DataHeader;
-
-#define VERSION 2
-int versionNumber = VERSION;
-int verbose = 0;
-
-DataHeader header = { 0x574f4c53, VERSION, sizeof(DataHeader), 0LL };
-
-char *versionHeader = "*version\n";
-char *clockDef = "clock=thread-cpu\n";
-
-char *keyThreads =
-"*threads\n"
-"1      main\n"
-"2      foo\n"
-"3      bar\n"
-"4      blah\n";
-
-char *keyEnd = "*end\n";
-
-typedef struct dataRecord {
-    unsigned int        time;
-    int                 threadId;
-    unsigned int        action;         /* 0=entry, 1=exit, 2=exception exit */
-    char                *fullName;
-    char                *className;
-    char                *methodName;
-    char                *signature;
-    unsigned int        methodId;
-} dataRecord;
-
-dataRecord *records;
-
-#define BUF_SIZE 1024
-char buf[BUF_SIZE];
-
-typedef struct stack {
-    dataRecord  **frames;
-    int         indentLevel;
-} stack;
-
-/* Mac OS doesn't have strndup(), so implement it here.
- */
-char *strndup(const char *src, size_t len)
-{
-    char *dest = (char *) malloc(len + 1);
-    strncpy(dest, src, len);
-    dest[len] = 0;
-    return dest;
-}
-
-/*
- * Parse the input file.  It looks something like this:
- * # This is a comment line
- * 4  1 A
- * 6  1  B
- * 8  1  B
- * 10 1 A
- *
- * where the first column is the time, the second column is the thread id,
- * and the third column is the method (actually just the class name).  The
- * number of spaces between the 2nd and 3rd columns is the indentation and
- * determines the call stack.  Each called method must be indented by one
- * more space.  In the example above, A is called at time 4, A calls B at
- * time 6, B returns at time 8, and A returns at time 10.  Thread 1 is the
- * only thread that is running.
- *
- * An alternative file format leaves out the first two columns:
- * A
- *  B
- *  B
- * A
- *
- * In this file format, the thread id is always 1, and the time starts at
- * 2 and increments by 2 for each line.
- */
-void parseInputFile(const char *inputFileName)
-{
-    unsigned int time = 0, threadId;
-    int len;
-    int linenum = 0;
-    int nextRecord = 0;
-    int indentLevel = 0;
-    stack *callStack;
-
-    FILE *inputFp = fopen(inputFileName, "r");
-    if (inputFp == NULL) {
-        perror(inputFileName);
-        exit(1);
-    }
-
-    /* Count the number of lines in the buffer */
-    int numRecords = 0;
-    int maxThreadId = 1;
-    int maxFrames = 0;
-    char *indentEnd;
-    while (fgets(buf, BUF_SIZE, inputFp)) {
-        char *cp = buf;
-        if (*cp == '#')
-            continue;
-        numRecords += 1;
-        if (isdigit(*cp)) {
-            int time = strtoul(cp, &cp, 0);
-            while (isspace(*cp))
-                cp += 1;
-            int threadId = strtoul(cp, &cp, 0);
-            if (maxThreadId < threadId)
-                maxThreadId = threadId;
-        }
-        indentEnd = cp;
-        while (isspace(*indentEnd))
-            indentEnd += 1;
-        if (indentEnd - cp + 1 > maxFrames)
-            maxFrames = indentEnd - cp + 1;
-    }
-    int numThreads = maxThreadId + 1;
-
-    /* Add space for a sentinel record at the end */
-    numRecords += 1;
-    records = (dataRecord *) malloc(sizeof(dataRecord) * numRecords);
-    callStack = (stack *) malloc(sizeof(stack) * numThreads);
-    int ii;
-    for (ii = 0; ii < numThreads; ++ii) {
-        callStack[ii].frames = NULL;
-        callStack[ii].indentLevel = 0;
-    }
-
-    rewind(inputFp);
-    while (fgets(buf, BUF_SIZE, inputFp)) {
-        int indent;
-        int action;
-        char *save_cp;
-
-        linenum += 1;
-        char *cp = buf;
-
-        /* Skip lines that start with '#' */
-        if (*cp == '#')
-            continue;
-
-        /* Get time and thread id */
-        if (!isdigit(*cp)) {
-            /* If the line does not begin with a digit, then fill in
-             * default values for the time and threadId.
-             */
-            time += 2;
-            threadId = 1;
-        } else {
-            time = strtoul(cp, &cp, 0);
-            while (isspace(*cp))
-                cp += 1;
-            threadId = strtoul(cp, &cp, 0);
-            cp += 1;
-        }
-
-        // Allocate space for the thread stack, if necessary
-        if (callStack[threadId].frames == NULL) {
-            dataRecord **stk;
-            stk = (dataRecord **) malloc(sizeof(dataRecord *) * maxFrames);
-            callStack[threadId].frames = stk;
-        }
-        indentLevel = callStack[threadId].indentLevel;
-
-        save_cp = cp;
-        while (isspace(*cp)) {
-            cp += 1;
-        }
-        indent = cp - save_cp + 1;
-        records[nextRecord].time = time;
-        records[nextRecord].threadId = threadId;
-
-        save_cp = cp;
-        while (*cp != '\n')
-            cp += 1;
-
-        /* Remove trailing spaces */
-        cp -= 1;
-        while (isspace(*cp))
-            cp -= 1;
-        cp += 1;
-        len = cp - save_cp;
-        records[nextRecord].fullName = strndup(save_cp, len);
-
-        /* Parse the name to support "class.method signature" */
-        records[nextRecord].className = NULL;
-        records[nextRecord].methodName = NULL;
-        records[nextRecord].signature = NULL;
-        cp = strchr(save_cp, '.');
-        if (cp) {
-            len = cp - save_cp;
-            if (len > 0)
-                records[nextRecord].className = strndup(save_cp, len);
-            save_cp = cp + 1;
-            cp = strchr(save_cp, ' ');
-            if (cp == NULL)
-                cp = strchr(save_cp, '\n');
-            if (cp && cp > save_cp) {
-                len = cp - save_cp;
-                records[nextRecord].methodName = strndup(save_cp, len);
-                save_cp = cp + 1;
-                cp = strchr(save_cp, ' ');
-                if (cp == NULL)
-                    cp = strchr(save_cp, '\n');
-                if (cp && cp > save_cp) {
-                    len = cp - save_cp;
-                    records[nextRecord].signature = strndup(save_cp, len);
-                }
-            }
-        }
-
-        if (verbose) {
-            printf("Indent: %d; IndentLevel: %d; Line: %s", indent, indentLevel, buf);
-        }
-
-        action = 0;
-        if (indent == indentLevel + 1) { // Entering a method
-            if (verbose)
-                printf("  Entering %s\n", records[nextRecord].fullName);
-            callStack[threadId].frames[indentLevel] = &records[nextRecord];
-        } else if (indent == indentLevel) { // Exiting a method
-            // Exiting method must be currently on top of stack (unless stack is empty)
-            if (callStack[threadId].frames[indentLevel - 1] == NULL) {
-                if (verbose)
-                    printf("  Exiting %s (past bottom of stack)\n", records[nextRecord].fullName);
-                callStack[threadId].frames[indentLevel - 1] = &records[nextRecord];
-                action = 1;
-            } else {
-                if (indentLevel < 1) {
-                    fprintf(stderr, "Error: line %d: %s", linenum, buf);
-                    fprintf(stderr, "  expected positive (>0) indentation, found %d\n",
-                            indent);
-                    exit(1);
-                }
-                char *name = callStack[threadId].frames[indentLevel - 1]->fullName;
-                if (strcmp(name, records[nextRecord].fullName) == 0) {
-                    if (verbose)
-                        printf("  Exiting %s\n", name);
-                    action = 1;
-                } else { // exiting method doesn't match stack's top method
-                    fprintf(stderr, "Error: line %d: %s", linenum, buf);
-                    fprintf(stderr, "  expected exit from %s\n",
-                            callStack[threadId].frames[indentLevel - 1]->fullName);
-                    exit(1);
-                }
-            }
-        } else {
-            if (nextRecord != 0) {
-                fprintf(stderr, "Error: line %d: %s", linenum, buf);
-                fprintf(stderr, "  expected indentation %d [+1], found %d\n",
-                        indentLevel, indent);
-                exit(1);
-            }
-
-            if (verbose) {
-                printf("  Nonzero indent at first record\n");
-                printf("  Entering %s\n", records[nextRecord].fullName);
-            }
-
-            // This is the first line of data, so we allow a larger
-            // initial indent.  This allows us to test popping off more
-            // frames than we entered.
-            indentLevel = indent - 1;
-            callStack[threadId].frames[indentLevel] = &records[nextRecord];
-        }
-
-        if (action == 0)
-            indentLevel += 1;
-        else
-            indentLevel -= 1;
-        records[nextRecord].action = action;
-        callStack[threadId].indentLevel = indentLevel;
-
-        nextRecord += 1;
-    }
-
-    /* Mark the last record with a sentinel */
-    memset(&records[nextRecord], 0, sizeof(dataRecord));
-}
-
-
-/*
- * Write values to the binary data file.
- */
-void write2LE(FILE* fp, unsigned short val)
-{
-    putc(val & 0xff, fp);
-    putc(val >> 8, fp);
-}
-
-void write4LE(FILE* fp, unsigned int val)
-{
-    putc(val & 0xff, fp);
-    putc((val >> 8) & 0xff, fp);
-    putc((val >> 16) & 0xff, fp);
-    putc((val >> 24) & 0xff, fp);
-}
-
-void write8LE(FILE* fp, unsigned long long val)
-{
-    putc(val & 0xff, fp);
-    putc((val >> 8) & 0xff, fp);
-    putc((val >> 16) & 0xff, fp);
-    putc((val >> 24) & 0xff, fp);
-    putc((val >> 32) & 0xff, fp);
-    putc((val >> 40) & 0xff, fp);
-    putc((val >> 48) & 0xff, fp);
-    putc((val >> 56) & 0xff, fp);
-}
-
-void writeDataRecord(FILE *dataFp, int threadId, unsigned int methodVal,
-                   unsigned int elapsedTime)
-{
-    if (versionNumber == 1)
-        putc(threadId, dataFp);
-    else
-        write2LE(dataFp, threadId);
-    write4LE(dataFp, methodVal);
-    write4LE(dataFp, elapsedTime);
-}
-
-void writeDataHeader(FILE *dataFp)
-{
-    struct timeval tv;
-    struct timezone tz;
-
-    gettimeofday(&tv, &tz);
-    unsigned long long startTime = tv.tv_sec;
-    startTime = (startTime << 32) | tv.tv_usec;
-    header.version = versionNumber;
-    write4LE(dataFp, header.magic);
-    write2LE(dataFp, header.version);
-    write2LE(dataFp, header.offsetToData);
-    write8LE(dataFp, startTime);
-}
-
-void writeKeyMethods(FILE *keyFp)
-{
-    dataRecord *pRecord, *pNext;
-    char *methodStr = "*methods\n";
-    fwrite(methodStr, strlen(methodStr), 1, keyFp);
-
-    /* Assign method ids in multiples of 4 */
-    unsigned int methodId = 0;
-    for (pRecord = records; pRecord->fullName; ++pRecord) {
-        if (pRecord->methodId)
-            continue;
-        unsigned int id = ++methodId << 2;
-        pRecord->methodId = id;
-
-        /* Assign this id to all the other records that have the
-         * same name.
-         */
-        for (pNext = pRecord + 1; pNext->fullName; ++pNext) {
-            if (pNext->methodId)
-                continue;
-            if (strcmp(pRecord->fullName, pNext->fullName) == 0)
-                pNext->methodId = id;
-        }
-        if (pRecord->className == NULL || pRecord->methodName == NULL) {
-            fprintf(keyFp, "%#x        %s      m       ()\n",
-                    pRecord->methodId, pRecord->fullName);
-        } else if (pRecord->signature == NULL) {
-            fprintf(keyFp, "%#x        %s      %s      ()\n",
-                    pRecord->methodId, pRecord->className,
-                    pRecord->methodName);
-        } else {
-            fprintf(keyFp, "%#x        %s      %s      %s\n",
-                    pRecord->methodId, pRecord->className,
-                    pRecord->methodName, pRecord->signature);
-        }
-    }
-}
-
-void writeKeys(FILE *keyFp)
-{
-    fprintf(keyFp, "%s%d\n%s", versionHeader, versionNumber, clockDef);
-    fwrite(keyThreads, strlen(keyThreads), 1, keyFp);
-    writeKeyMethods(keyFp);
-    fwrite(keyEnd, strlen(keyEnd), 1, keyFp);
-}
-
-void writeDataRecords(FILE *dataFp)
-{
-    dataRecord *pRecord;
-
-    for (pRecord = records; pRecord->fullName; ++pRecord) {
-        unsigned int val = METHOD_COMBINE(pRecord->methodId, pRecord->action);
-        writeDataRecord(dataFp, pRecord->threadId, val, pRecord->time);
-    }
-}
-
-void writeTrace(const char* traceFileName)
-{
-    FILE *fp = fopen(traceFileName, "w");
-    if (fp == NULL) {
-        perror(traceFileName);
-        exit(1);
-    }
-    writeKeys(fp);
-    writeDataHeader(fp);
-    writeDataRecords(fp);
-    fclose(fp);
-}
-
-int parseOptions(int argc, char **argv)
-{
-    int err = 0;
-    while (1) {
-        int opt = getopt(argc, argv, "v:d");
-        if (opt == -1)
-            break;
-        switch (opt) {
-            case 'v':
-                versionNumber = strtoul(optarg, NULL, 0);
-                if (versionNumber != 1 && versionNumber != 2) {
-                    fprintf(stderr, "Error: version number (%d) must be 1 or 2\n",
-                            versionNumber);
-                    err = 1;
-                }
-                break;
-            case 'd':
-                verbose = 1;
-                break;
-            default:
-                err = 1;
-                break;
-        }
-    }
-    return err;
-}
-
-int main(int argc, char** argv)
-{
-    char *inputFile;
-    char *traceFileName = NULL;
-    int len;
-
-    if (parseOptions(argc, argv) || argc - optind != 2) {
-        fprintf(stderr, "Usage: %s [-v version] [-d] input_file trace_prefix\n",
-                argv[0]);
-        exit(1);
-    }
-
-    inputFile = argv[optind++];
-    parseInputFile(inputFile);
-    traceFileName = argv[optind++];
-
-    writeTrace(traceFileName);
-
-    return 0;
-}
diff --git a/tools/dmtracedump/Profile.h b/tools/dmtracedump/Profile.h
deleted file mode 100644
index efbedb3..0000000
--- a/tools/dmtracedump/Profile.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Android's method call profiling goodies.
- */
-#ifndef DALVIK_PROFILE_H_
-#define DALVIK_PROFILE_H_
-
-/*
- * Enumeration for the two "action" bits.
- */
-enum {
-    METHOD_TRACE_ENTER = 0x00,      // method entry
-    METHOD_TRACE_EXIT = 0x01,       // method exit
-    METHOD_TRACE_UNROLL = 0x02,     // method exited by exception unrolling
-    // 0x03 currently unused
-};
-
-#define TOKEN_CHAR      '*'
-
-/*
- * Common definitions, shared with the dump tool.
- */
-#define METHOD_ACTION_MASK      0x03            /* two bits */
-#define METHOD_ID(_method)      ((_method) & (~METHOD_ACTION_MASK))
-#define METHOD_ACTION(_method)  (((unsigned int)(_method)) & METHOD_ACTION_MASK)
-#define METHOD_COMBINE(_method, _action)    ((_method) | (_action))
-
-#endif  // DALVIK_PROFILE_H_
diff --git a/tools/dmtracedump/TraceDump.c b/tools/dmtracedump/TraceDump.c
deleted file mode 100644
index 7ec067d..0000000
--- a/tools/dmtracedump/TraceDump.c
+++ /dev/null
@@ -1,2910 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-/*
- * Process dmtrace output.
- *
- * This is the wrong way to go about it -- C is a clumsy language for
- * shuffling data around.  It'll do for a first pass.
- */
-#define NOT_VM
-#include "Profile.h"        // from VM header
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <time.h>
-#include <errno.h>
-#include <assert.h>
-
-/* Version number in the key file.
- * Version 1 uses one byte for the thread id.
- * Version 2 uses two bytes for the thread ids.
- * Version 3 encodes the record size and adds an optional extra timestamp field.
- */
-int versionNumber;
-
-/* arbitrarily limit indentation */
-#define MAX_STACK_DEPTH 10000
-
-/* thread list in key file is not reliable, so just max out */
-#define MAX_THREADS     32768
-
-/* Size of temporary buffers for escaping html strings */
-#define HTML_BUFSIZE 10240
-
-char *htmlHeader =
-"<html>\n<head>\n<script type=\"text/javascript\" src=\"%ssortable.js\"></script>\n"
-"<script langugage=\"javascript\">\n"
-"function toggle(item) {\n"
-"    obj=document.getElementById(item);\n"
-"    visible=(obj.style.display!=\"none\" && obj.style.display!=\"\");\n"
-"    key=document.getElementById(\"x\" + item);\n"
-"    if (visible) {\n"
-"        obj.style.display=\"none\";\n"
-"        key.innerHTML=\"+\";\n"
-"    } else {\n"
-"        obj.style.display=\"block\";\n"
-"        key.innerHTML=\"-\";\n"
-"    }\n"
-"}\n"
-"function onMouseOver(obj) {\n"
-"    obj.style.background=\"lightblue\";\n"
-"}\n"
-"function onMouseOut(obj) {\n"
-"    obj.style.background=\"white\";\n"
-"}\n"
-"</script>\n"
-"<style type=\"text/css\">\n"
-"div { font-family: courier; font-size: 13 }\n"
-"div.parent { margin-left: 15; display: none }\n"
-"div.leaf { margin-left: 10 }\n"
-"div.header { margin-left: 10 }\n"
-"div.link { margin-left: 10; cursor: move }\n"
-"span.parent { padding-right: 10; }\n"
-"span.leaf { padding-right: 10; }\n"
-"a img { border: 0;}\n"
-"table.sortable th { border-width: 0px 1px 1px 1px; background-color: #ccc;}\n"
-"a { text-decoration: none; }\n"
-"a:hover { text-decoration: underline; }\n"
-"table.sortable th, table.sortable td { text-align: left;}"
-"table.sortable tr.odd td { background-color: #ddd; }\n"
-"table.sortable tr.even td { background-color: #fff; }\n"
-"</style>\n"
-"</head><body>\n\n";
-
-char *htmlFooter = "\n</body>\n</html>\n";
-char *profileSeparator =
-    "======================================================================";
-
-const char* tableHeader =
-    "<table class='sortable' id='%s'><tr>\n"
-    "<th>Method</th>\n"
-    "<th>Run 1 (us)</th>\n"
-    "<th>Run 2 (us)</th>\n"
-    "<th>Diff (us)</th>\n"
-    "<th>Diff (%%)</th>\n"
-    "<th>1: # calls</th>\n"
-    "<th>2: # calls</th>\n"
-    "</tr>\n";
-
-const char* tableHeaderMissing =
-    "<table class='sortable' id='%s'>\n"
-    "<th>Method</th>\n"
-    "<th>Exclusive</th>\n"
-    "<th>Inclusive</th>\n"
-    "<th># calls</th>\n";
-
-#define GRAPH_LABEL_VISITED 0x0001
-#define GRAPH_NODE_VISITED  0x0002
-
-/*
- * Values from the header of the data file.
- */
-typedef struct DataHeader {
-    unsigned int magic;
-    short version;
-    short offsetToData;
-    long long startWhen;
-    short recordSize;
-} DataHeader;
-
-/*
- * Entry from the thread list.
- */
-typedef struct ThreadEntry {
-    int         threadId;
-    const char* threadName;
-} ThreadEntry;
-
-struct MethodEntry;
-typedef struct TimedMethod {
-    struct TimedMethod *next;
-    uint64_t elapsedInclusive;
-    int numCalls;
-    struct MethodEntry *method;
-} TimedMethod;
-
-typedef struct ClassEntry {
-    const char *className;
-    uint64_t elapsedExclusive;
-    int numMethods;
-    struct MethodEntry **methods;       /* list of methods in this class */
-    int numCalls[2];                    /* 0=normal, 1=recursive */
-} ClassEntry;
-
-typedef struct UniqueMethodEntry {
-    uint64_t elapsedExclusive;
-    int numMethods;
-    struct MethodEntry **methods;       /* list of methods with same name */
-    int numCalls[2];                    /* 0=normal, 1=recursive */
-} UniqueMethodEntry;
-
-/*
- * Entry from the method list.
- */
-typedef struct MethodEntry {
-    int64_t methodId;
-    const char* className;
-    const char* methodName;
-    const char* signature;
-    const char* fileName;
-    int lineNum;
-    uint64_t elapsedExclusive;
-    uint64_t elapsedInclusive;
-    uint64_t topExclusive;              /* non-recursive exclusive time */
-    uint64_t recursiveInclusive;
-    struct TimedMethod *parents[2];     /* 0=normal, 1=recursive */
-    struct TimedMethod *children[2];    /* 0=normal, 1=recursive */
-    int numCalls[2];                    /* 0=normal, 1=recursive */
-    int index;                  /* used after sorting to number methods */
-    int recursiveEntries;       /* number of entries on the stack */
-    int graphState;             /* used when graphing to see if this method has been visited before */
-} MethodEntry;
-
-/*
- * The parsed contents of the key file.
- */
-typedef struct DataKeys {
-    char*        fileData;      /* contents of the entire file */
-    long         fileLen;
-    int          numThreads;
-    ThreadEntry* threads;
-    int          numMethods;
-    MethodEntry* methods;       /* 2 extra methods: "toplevel" and "unknown" */
-} DataKeys;
-
-#define TOPLEVEL_INDEX 0
-#define UNKNOWN_INDEX 1
-
-typedef struct StackEntry {
-    MethodEntry *method;
-    uint64_t    entryTime;
-} StackEntry;
-
-typedef struct CallStack {
-    int         top;
-    StackEntry  calls[MAX_STACK_DEPTH];
-    uint64_t    lastEventTime;
-    uint64_t    threadStartTime;
-} CallStack;
-
-typedef struct DiffEntry {
-    MethodEntry* method1;
-    MethodEntry* method2;
-    int64_t differenceExclusive;
-    int64_t differenceInclusive;
-    double differenceExclusivePercentage;
-    double differenceInclusivePercentage;
-} DiffEntry;
-
-// Global options
-typedef struct Options {
-    const char* traceFileName;
-    const char* diffFileName;
-    const char* graphFileName;
-    int keepDotFile;
-    int dump;
-    int outputHtml;
-    const char* sortableUrl;
-    int threshold;
-} Options;
-
-typedef struct TraceData {
-    int numClasses;
-    ClassEntry *classes;
-    CallStack *stacks[MAX_THREADS];
-    int depth[MAX_THREADS];
-    int numUniqueMethods;
-    UniqueMethodEntry *uniqueMethods;
-} TraceData;
-
-static Options gOptions;
-
-/* Escapes characters in the source string that are html special entities.
- * The escaped string is written to "dest" which must be large enough to
- * hold the result.  A pointer to "dest" is returned.  The characters and
- * their corresponding escape sequences are:
- *  '<'  &lt;
- *  '>'  &gt;
- *  '&'  &amp;
- */
-char *htmlEscape(const char *src, char *dest, int len)
-{
-    char *destStart = dest;
-
-    if (src == NULL)
-        return NULL;
-
-    int nbytes = 0;
-    while (*src) {
-        if (*src == '<') {
-            nbytes += 4;
-            if (nbytes >= len)
-                break;
-            *dest++ = '&';
-            *dest++ = 'l';
-            *dest++ = 't';
-            *dest++ = ';';
-        } else if (*src == '>') {
-            nbytes += 4;
-            if (nbytes >= len)
-                break;
-            *dest++ = '&';
-            *dest++ = 'g';
-            *dest++ = 't';
-            *dest++ = ';';
-        } else if (*src == '&') {
-            nbytes += 5;
-            if (nbytes >= len)
-                break;
-            *dest++ = '&';
-            *dest++ = 'a';
-            *dest++ = 'm';
-            *dest++ = 'p';
-            *dest++ = ';';
-        } else {
-            nbytes += 1;
-            if (nbytes >= len)
-                break;
-            *dest++ = *src;
-        }
-        src += 1;
-    }
-    if (nbytes >= len) {
-        fprintf(stderr, "htmlEscape(): buffer overflow\n");
-        exit(1);
-    }
-    *dest = 0;
-
-    return destStart;
-}
-
-/* Initializes a MethodEntry
- */
-void initMethodEntry(MethodEntry *method, int64_t methodId,
-                     const char *className, const char *methodName,
-                     const char *signature, const char* fileName,
-                     const char* lineNumStr)
-{
-    method->methodId = methodId;
-    method->className = className;
-    method->methodName = methodName;
-    method->signature = signature;
-    method->fileName = fileName;
-    method->lineNum = (lineNumStr != NULL) ? atoi(lineNumStr) : -1;
-    method->elapsedExclusive = 0;
-    method->elapsedInclusive = 0;
-    method->topExclusive = 0;
-    method->recursiveInclusive = 0;
-    method->parents[0] = NULL;
-    method->parents[1] = NULL;
-    method->children[0] = NULL;
-    method->children[1] = NULL;
-    method->numCalls[0] = 0;
-    method->numCalls[1] = 0;
-    method->index = 0;
-    method->recursiveEntries = 0;
-}
-
-/*
- * This comparison function is called from qsort() to sort
- * methods into decreasing order of exclusive elapsed time.
- */
-int compareElapsedExclusive(const void *a, const void *b) {
-    uint64_t elapsed1, elapsed2;
-    int result;
-
-    const MethodEntry *methodA = *(const MethodEntry**)a;
-    const MethodEntry *methodB = *(const MethodEntry**)b;
-    elapsed1 = methodA->elapsedExclusive;
-    elapsed2 = methodB->elapsedExclusive;
-    if (elapsed1 < elapsed2)
-        return 1;
-    if (elapsed1 > elapsed2)
-        return -1;
-
-    /* If the elapsed times of two methods are equal, then sort them
-     * into alphabetical order.
-     */
-    result = strcmp(methodA->className, methodB->className);
-    if (result == 0) {
-        if (methodA->methodName == NULL || methodB->methodName == NULL) {
-            int64_t idA = methodA->methodId;
-            int64_t idB = methodB->methodId;
-            if (idA < idB)
-                return -1;
-            if (idA > idB)
-                return 1;
-            return 0;
-        }
-        result = strcmp(methodA->methodName, methodB->methodName);
-        if (result == 0)
-            result = strcmp(methodA->signature, methodB->signature);
-    }
-    return result;
-}
-
-/*
- * This comparison function is called from qsort() to sort
- * methods into decreasing order of inclusive elapsed time.
- */
-int compareElapsedInclusive(const void *a, const void *b) {
-    const MethodEntry *methodA, *methodB;
-    uint64_t elapsed1, elapsed2;
-    int result;
-
-    methodA = *(MethodEntry const **)a;
-    methodB = *(MethodEntry const **)b;
-    elapsed1 = methodA->elapsedInclusive;
-    elapsed2 = methodB->elapsedInclusive;
-    if (elapsed1 < elapsed2)
-        return 1;
-    if (elapsed1 > elapsed2)
-        return -1;
-
-    /* If the elapsed times of two methods are equal, then sort them
-     * into alphabetical order.
-     */
-    result = strcmp(methodA->className, methodB->className);
-    if (result == 0) {
-        if (methodA->methodName == NULL || methodB->methodName == NULL) {
-            int64_t idA = methodA->methodId;
-            int64_t idB = methodB->methodId;
-            if (idA < idB)
-                return -1;
-            if (idA > idB)
-                return 1;
-            return 0;
-        }
-        result = strcmp(methodA->methodName, methodB->methodName);
-        if (result == 0)
-            result = strcmp(methodA->signature, methodB->signature);
-    }
-    return result;
-}
-
-/*
- * This comparison function is called from qsort() to sort
- * TimedMethods into decreasing order of inclusive elapsed time.
- */
-int compareTimedMethod(const void *a, const void *b) {
-    const TimedMethod *timedA, *timedB;
-    uint64_t elapsed1, elapsed2;
-    int result;
-
-    timedA = (TimedMethod const *)a;
-    timedB = (TimedMethod const *)b;
-    elapsed1 = timedA->elapsedInclusive;
-    elapsed2 = timedB->elapsedInclusive;
-    if (elapsed1 < elapsed2)
-        return 1;
-    if (elapsed1 > elapsed2)
-        return -1;
-
-    /* If the elapsed times of two methods are equal, then sort them
-     * into alphabetical order.
-     */
-    MethodEntry *methodA = timedA->method;
-    MethodEntry *methodB = timedB->method;
-    result = strcmp(methodA->className, methodB->className);
-    if (result == 0) {
-        if (methodA->methodName == NULL || methodB->methodName == NULL) {
-            int64_t idA = methodA->methodId;
-            int64_t idB = methodB->methodId;
-            if (idA < idB)
-                return -1;
-            if (idA > idB)
-                return 1;
-            return 0;
-        }
-        result = strcmp(methodA->methodName, methodB->methodName);
-        if (result == 0)
-            result = strcmp(methodA->signature, methodB->signature);
-    }
-    return result;
-}
-
-/*
- * This comparison function is called from qsort() to sort
- * MethodEntry pointers into alphabetical order of class names.
- */
-int compareClassNames(const void *a, const void *b) {
-    int result;
-
-    const MethodEntry *methodA = *(const MethodEntry**)a;
-    const MethodEntry *methodB = *(const MethodEntry**)b;
-    result = strcmp(methodA->className, methodB->className);
-    if (result == 0) {
-        int64_t idA = methodA->methodId;
-        int64_t idB = methodB->methodId;
-        if (idA < idB)
-            return -1;
-        if (idA > idB)
-            return 1;
-        return 0;
-    }
-    return result;
-}
-
-/*
- * This comparison function is called from qsort() to sort
- * classes into decreasing order of exclusive elapsed time.
- */
-int compareClassExclusive(const void *a, const void *b) {
-    uint64_t elapsed1, elapsed2;
-    int result;
-
-    const ClassEntry *classA = *(const ClassEntry**)a;
-    const ClassEntry *classB = *(const ClassEntry**)b;
-    elapsed1 = classA->elapsedExclusive;
-    elapsed2 = classB->elapsedExclusive;
-    if (elapsed1 < elapsed2)
-        return 1;
-    if (elapsed1 > elapsed2)
-        return -1;
-
-    /* If the elapsed times of two classs are equal, then sort them
-     * into alphabetical order.
-     */
-    result = strcmp(classA->className, classB->className);
-    if (result == 0) {
-        /* Break ties with the first method id.  This is probably not
-         * needed.
-         */
-        int64_t idA = classA->methods[0]->methodId;
-        int64_t idB = classB->methods[0]->methodId;
-        if (idA < idB)
-            return -1;
-        if (idA > idB)
-            return 1;
-        return 0;
-    }
-    return result;
-}
-
-/*
- * This comparison function is called from qsort() to sort
- * MethodEntry pointers into alphabetical order by method name,
- * then by class name.
- */
-int compareMethodNames(const void *a, const void *b) {
-    int result;
-
-    const MethodEntry *methodA = *(const MethodEntry**)a;
-    const MethodEntry *methodB = *(const MethodEntry**)b;
-    if (methodA->methodName == NULL || methodB->methodName == NULL) {
-        return compareClassNames(a, b);
-    }
-    result = strcmp(methodA->methodName, methodB->methodName);
-    if (result == 0) {
-        result = strcmp(methodA->className, methodB->className);
-        if (result == 0) {
-            int64_t idA = methodA->methodId;
-            int64_t idB = methodB->methodId;
-            if (idA < idB)
-                return -1;
-            if (idA > idB)
-                return 1;
-            return 0;
-        }
-    }
-    return result;
-}
-
-/*
- * This comparison function is called from qsort() to sort
- * unique methods into decreasing order of exclusive elapsed time.
- */
-int compareUniqueExclusive(const void *a, const void *b) {
-    uint64_t elapsed1, elapsed2;
-    int result;
-
-    const UniqueMethodEntry *uniqueA = *(const UniqueMethodEntry**)a;
-    const UniqueMethodEntry *uniqueB = *(const UniqueMethodEntry**)b;
-    elapsed1 = uniqueA->elapsedExclusive;
-    elapsed2 = uniqueB->elapsedExclusive;
-    if (elapsed1 < elapsed2)
-        return 1;
-    if (elapsed1 > elapsed2)
-        return -1;
-
-    /* If the elapsed times of two methods are equal, then sort them
-     * into alphabetical order.
-     */
-    result = strcmp(uniqueA->methods[0]->className,
-                    uniqueB->methods[0]->className);
-    if (result == 0) {
-        int64_t idA = uniqueA->methods[0]->methodId;
-        int64_t idB = uniqueB->methods[0]->methodId;
-        if (idA < idB)
-            return -1;
-        if (idA > idB)
-            return 1;
-        return 0;
-    }
-    return result;
-}
-
-/*
- * Free a DataKeys struct.
- */
-void freeDataKeys(DataKeys* pKeys)
-{
-    if (pKeys == NULL)
-        return;
-
-    free(pKeys->fileData);
-    free(pKeys->threads);
-    free(pKeys->methods);
-    free(pKeys);
-}
-
-/*
- * Find the offset to the next occurrence of the specified character.
- *
- * "data" should point somewhere within the current line.  "len" is the
- * number of bytes left in the buffer.
- *
- * Returns -1 if we hit the end of the buffer.
- */
-int findNextChar(const char* data, int len, char lookFor)
-{
-    const char* start = data;
-
-    while (len > 0) {
-        if (*data == lookFor)
-            return data - start;
-
-        data++;
-        len--;
-    }
-
-    return -1;
-}
-
-/*
- * Count the number of lines until the next token.
- *
- * Returns -1 if none found before EOF.
- */
-int countLinesToToken(const char* data, int len)
-{
-    int count = 0;
-    int next;
-
-    while (*data != TOKEN_CHAR) {
-        next = findNextChar(data, len, '\n');
-        if (next < 0)
-            return -1;
-        count++;
-        data += next+1;
-        len -= next+1;
-    }
-
-    return count;
-}
-
-/*
- * Make sure we're at the start of the right section.
- *
- * Returns the length of the token line, or -1 if something is wrong.
- */
-int checkToken(const char* data, int len, const char* cmpStr)
-{
-    int cmpLen = strlen(cmpStr);
-    int next;
-
-    if (*data != TOKEN_CHAR) {
-        fprintf(stderr,
-            "ERROR: not at start of %s (found '%.10s')\n", cmpStr, data);
-        return -1;
-    }
-
-    next = findNextChar(data, len, '\n');
-    if (next < cmpLen+1)
-        return -1;
-
-    if (strncmp(data+1, cmpStr, cmpLen) != 0) {
-        fprintf(stderr, "ERROR: '%s' not found (got '%.7s')\n", cmpStr, data+1);
-        return -1;
-    }
-
-    return next+1;
-}
-
-/*
- * Parse the "*version" section.
- */
-long parseVersion(DataKeys* pKeys, long offset, int verbose)
-{
-    char* data;
-    char* dataEnd;
-    int i, count, next;
-
-    if (offset < 0)
-        return -1;
-
-    data = pKeys->fileData + offset;
-    dataEnd = pKeys->fileData + pKeys->fileLen;
-    next = checkToken(data, dataEnd - data, "version");
-    if (next <= 0)
-        return -1;
-
-    data += next;
-
-    /*
-     * Count the number of items in the "version" section.
-     */
-    count = countLinesToToken(data, dataEnd - data);
-    if (count <= 0) {
-        fprintf(stderr,
-            "ERROR: failed while reading version (found %d)\n", count);
-        return -1;
-    }
-
-    /* find the end of the line */
-    next = findNextChar(data, dataEnd - data, '\n');
-    if (next < 0)
-        return -1;
-
-    data[next] = '\0';
-    versionNumber = strtoul(data, NULL, 0);
-    if (verbose)
-        printf("VERSION: %d\n", versionNumber);
-
-    data += next+1;
-
-    /* skip over the rest of the stuff, which is "name=value" lines */
-    for (i = 1; i < count; i++) {
-        next = findNextChar(data, dataEnd - data, '\n');
-        if (next < 0)
-            return -1;
-        //data[next] = '\0';
-        //printf("IGNORING: '%s'\n", data);
-        data += next+1;
-    }
-
-    return data - pKeys->fileData;
-}
-
-/*
- * Parse the "*threads" section.
- */
-long parseThreads(DataKeys* pKeys, long offset)
-{
-    char* data;
-    char* dataEnd;
-    int i, next, tab, count;
-
-    if (offset < 0)
-        return -1;
-
-    data = pKeys->fileData + offset;
-    dataEnd = pKeys->fileData + pKeys->fileLen;
-    next = checkToken(data, dataEnd - data, "threads");
-
-    data += next;
-
-    /*
-     * Count the number of thread entries (one per line).
-     */
-    count = countLinesToToken(data, dataEnd - data);
-    if (count <= 0) {
-        fprintf(stderr,
-            "ERROR: failed while reading threads (found %d)\n", count);
-        return -1;
-    }
-
-    //printf("+++ found %d threads\n", count);
-    pKeys->threads = (ThreadEntry*) malloc(sizeof(ThreadEntry) * count);
-    if (pKeys->threads == NULL)
-        return -1;
-
-    /*
-     * Extract all entries.
-     */
-    for (i = 0; i < count; i++) {
-        next = findNextChar(data, dataEnd - data, '\n');
-        assert(next > 0);
-        data[next] = '\0';
-
-        tab = findNextChar(data, next, '\t');
-        data[tab] = '\0';
-
-        pKeys->threads[i].threadId = atoi(data);
-        pKeys->threads[i].threadName = data + tab +1;
-
-        data += next+1;
-    }
-
-    pKeys->numThreads = count;
-    return data - pKeys->fileData;
-}
-
-/*
- * Parse the "*methods" section.
- */
-long parseMethods(DataKeys* pKeys, long offset)
-{
-    char* data;
-    char* dataEnd;
-    int i, next, count;
-
-    if (offset < 0)
-        return -1;
-
-    data = pKeys->fileData + offset;
-    dataEnd = pKeys->fileData + pKeys->fileLen;
-    next = checkToken(data, dataEnd - data, "methods");
-    if (next < 0)
-        return -1;
-
-    data += next;
-
-    /*
-     * Count the number of method entries (one per line).
-     */
-    count = countLinesToToken(data, dataEnd - data);
-    if (count <= 0) {
-        fprintf(stderr,
-            "ERROR: failed while reading methods (found %d)\n", count);
-        return -1;
-    }
-
-    /* Reserve an extra method at location 0 for the "toplevel" method,
-     * and another extra method for all other "unknown" methods.
-     */
-    count += 2;
-    pKeys->methods = (MethodEntry*) malloc(sizeof(MethodEntry) * count);
-    if (pKeys->methods == NULL)
-        return -1;
-    initMethodEntry(&pKeys->methods[TOPLEVEL_INDEX], -2, "(toplevel)",
-        NULL, NULL, NULL, NULL);
-    initMethodEntry(&pKeys->methods[UNKNOWN_INDEX], -1, "(unknown)",
-        NULL, NULL, NULL, NULL);
-
-    /*
-     * Extract all entries, starting with index 2.
-     */
-    for (i = UNKNOWN_INDEX + 1; i < count; i++) {
-        int tab1, tab2, tab3, tab4, tab5;
-        int64_t id;
-        char* endptr;
-
-        next = findNextChar(data, dataEnd - data, '\n');
-        assert(next > 0);
-        data[next] = '\0';
-
-        tab1 = findNextChar(data, next, '\t');
-        tab2 = findNextChar(data+(tab1+1), next-(tab1+1), '\t');
-        tab3 = findNextChar(data+(tab1+tab2+2), next-(tab1+tab2+2), '\t');
-        tab4 = findNextChar(data+(tab1+tab2+tab3+3),
-                            next-(tab1+tab2+tab3+3), '\t');
-        tab5 = findNextChar(data+(tab1+tab2+tab3+tab4+4),
-                            next-(tab1+tab2+tab3+tab4+4), '\t');
-        if (tab1 < 0) {
-            fprintf(stderr, "ERROR: missing field on method line: '%s'\n",
-                    data);
-            return -1;
-        }
-        assert(data[tab1] == '\t');
-        data[tab1] = '\0';
-
-        id = strtoul(data, &endptr, 0);
-        if (*endptr != '\0') {
-            fprintf(stderr, "ERROR: bad method ID '%s'\n", data);
-            return -1;
-        }
-
-        // Allow files that specify just a function name, instead of requiring
-        // "class \t method \t signature"
-        if (tab2 > 0 && tab3 > 0) {
-            tab2 += tab1+1;
-            tab3 += tab2+1;
-            assert(data[tab2] == '\t');
-            assert(data[tab3] == '\t');
-            data[tab2] = data[tab3] = '\0';
-
-            // This is starting to get awkward.  Allow filename and line #.
-            if (tab4 > 0 && tab5 > 0) {
-                tab4 += tab3+1;
-                tab5 += tab4+1;
-
-                assert(data[tab4] == '\t');
-                assert(data[tab5] == '\t');
-                data[tab4] = data[tab5] = '\0';
-
-                initMethodEntry(&pKeys->methods[i], id, data + tab1 +1,
-                        data + tab2 +1, data + tab3 +1, data + tab4 +1,
-                        data + tab5 +1);
-            } else {
-                initMethodEntry(&pKeys->methods[i], id, data + tab1 +1,
-                        data + tab2 +1, data + tab3 +1, NULL, NULL);
-            }
-        } else {
-            initMethodEntry(&pKeys->methods[i], id, data + tab1 +1,
-                NULL, NULL, NULL, NULL);
-        }
-
-        data += next+1;
-    }
-
-    pKeys->numMethods = count;
-    return data - pKeys->fileData;
-}
-
-/*
- * Parse the "*end" section.
- */
-long parseEnd(DataKeys* pKeys, long offset)
-{
-    char* data;
-    char* dataEnd;
-    int next;
-
-    if (offset < 0)
-        return -1;
-
-    data = pKeys->fileData + offset;
-    dataEnd = pKeys->fileData + pKeys->fileLen;
-    next = checkToken(data, dataEnd - data, "end");
-    if (next < 0)
-        return -1;
-
-    data += next;
-
-    return data - pKeys->fileData;
-}
-
-/*
- * Sort the thread list entries.
- */
-static int compareThreads(const void* thread1, const void* thread2)
-{
-    return ((const ThreadEntry*) thread1)->threadId -
-            ((const ThreadEntry*) thread2)->threadId;
-}
-
-void sortThreadList(DataKeys* pKeys)
-{
-    qsort(pKeys->threads, pKeys->numThreads, sizeof(pKeys->threads[0]),
-        compareThreads);
-}
-
-/*
- * Sort the method list entries.
- */
-static int compareMethods(const void* meth1, const void* meth2)
-{
-    int64_t id1, id2;
-
-    id1 = ((const MethodEntry*) meth1)->methodId;
-    id2 = ((const MethodEntry*) meth2)->methodId;
-    if (id1 < id2)
-        return -1;
-    if (id1 > id2)
-        return 1;
-    return 0;
-}
-
-void sortMethodList(DataKeys* pKeys)
-{
-    qsort(pKeys->methods, pKeys->numMethods, sizeof(MethodEntry),
-        compareMethods);
-}
-
-/*
- * Parse the key section, and return a copy of the parsed contents.
- */
-DataKeys* parseKeys(FILE *fp, int verbose)
-{
-    DataKeys* pKeys = NULL;
-    long offset;
-    int i;
-
-    pKeys = (DataKeys*) calloc(1, sizeof(DataKeys));
-    if (pKeys == NULL)
-        goto fail;
-
-    /*
-     * We load the entire file into memory.  We do this, rather than memory-
-     * mapping it, because we want to change some whitespace to NULs.
-     */
-    if (fseek(fp, 0L, SEEK_END) != 0) {
-        perror("fseek");
-        goto fail;
-    }
-    pKeys->fileLen = ftell(fp);
-    if (pKeys->fileLen == 0) {
-        fprintf(stderr, "Key file is empty.\n");
-        goto fail;
-    }
-    rewind(fp);
-
-    pKeys->fileData = (char*) malloc(pKeys->fileLen);
-    if (pKeys->fileData == NULL) {
-        fprintf(stderr, "ERROR: unable to alloc %ld bytes\n", pKeys->fileLen);
-        goto fail;
-    }
-
-    if (fread(pKeys->fileData, 1, pKeys->fileLen, fp) != (size_t) pKeys->fileLen)
-    {
-        fprintf(stderr, "ERROR: unable to read %ld bytes from trace file\n",
-            pKeys->fileLen);
-        goto fail;
-    }
-
-    offset = 0;
-
-    offset = parseVersion(pKeys, offset, verbose);
-    offset = parseThreads(pKeys, offset);
-    offset = parseMethods(pKeys, offset);
-    offset = parseEnd(pKeys, offset);
-    if (offset < 0)
-        goto fail;
-
-    /* Reduce our allocation now that we know where the end of the key section is. */
-    pKeys->fileData = (char *)realloc(pKeys->fileData, offset);
-    pKeys->fileLen = offset;
-    /* Leave fp pointing to the beginning of the data section. */
-    fseek(fp, offset, SEEK_SET);
-
-    sortThreadList(pKeys);
-    sortMethodList(pKeys);
-
-    /*
-     * Dump list of threads.
-     */
-    if (verbose) {
-        printf("Threads (%d):\n", pKeys->numThreads);
-        for (i = 0; i < pKeys->numThreads; i++) {
-            printf("%2d %s\n",
-                   pKeys->threads[i].threadId, pKeys->threads[i].threadName);
-        }
-    }
-
-#if 0
-    /*
-     * Dump list of methods.
-     */
-    if (verbose) {
-        printf("Methods (%d):\n", pKeys->numMethods);
-        for (i = 0; i < pKeys->numMethods; i++) {
-            printf("0x%08x %s : %s : %s\n",
-                   pKeys->methods[i].methodId, pKeys->methods[i].className,
-                   pKeys->methods[i].methodName, pKeys->methods[i].signature);
-        }
-    }
-#endif
-
-    return pKeys;
-
-fail:
-    freeDataKeys(pKeys);
-    return NULL;
-}
-
-
-/*
- * Read values from the binary data file.
- */
-
-/* Make the return value "unsigned int" instead of "unsigned short" so that
- * we can detect EOF.
- */
-unsigned int read2LE(FILE* fp)
-{
-    unsigned int val;
-
-    val = getc(fp);
-    val |= getc(fp) << 8;
-    return val;
-}
-unsigned int read4LE(FILE* fp)
-{
-    unsigned int val;
-
-    val = getc(fp);
-    val |= getc(fp) << 8;
-    val |= getc(fp) << 16;
-    val |= getc(fp) << 24;
-    return val;
-}
-unsigned long long read8LE(FILE* fp)
-{
-    unsigned long long val;
-
-    val = getc(fp);
-    val |= (unsigned long long) getc(fp) << 8;
-    val |= (unsigned long long) getc(fp) << 16;
-    val |= (unsigned long long) getc(fp) << 24;
-    val |= (unsigned long long) getc(fp) << 32;
-    val |= (unsigned long long) getc(fp) << 40;
-    val |= (unsigned long long) getc(fp) << 48;
-    val |= (unsigned long long) getc(fp) << 56;
-    return val;
-}
-
-/*
- * Parse the header of the data section.
- *
- * Returns with the file positioned at the start of the record data.
- */
-int parseDataHeader(FILE *fp, DataHeader* pHeader)
-{
-    int bytesToRead;
-
-    pHeader->magic = read4LE(fp);
-    pHeader->version = read2LE(fp);
-    pHeader->offsetToData = read2LE(fp);
-    pHeader->startWhen = read8LE(fp);
-    bytesToRead = pHeader->offsetToData - 16;
-    if (pHeader->version == 1) {
-        pHeader->recordSize = 9;
-    } else if (pHeader->version == 2) {
-        pHeader->recordSize = 10;
-    } else if (pHeader->version == 3) {
-        pHeader->recordSize = read2LE(fp);
-        bytesToRead -= 2;
-    } else {
-        fprintf(stderr, "Unsupported trace file version: %d\n", pHeader->version);
-        return -1;
-    }
-
-    if (fseek(fp, bytesToRead, SEEK_CUR) != 0) {
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Look up a method by it's method ID.
- *
- * Returns NULL if no matching method was found.
- */
-MethodEntry* lookupMethod(DataKeys* pKeys, int64_t methodId)
-{
-    int hi, lo, mid;
-    int64_t id;
-
-    lo = 0;
-    hi = pKeys->numMethods - 1;
-
-    while (hi >= lo) {
-        mid = (hi + lo) / 2;
-
-        id = pKeys->methods[mid].methodId;
-        if (id == methodId)           /* match */
-            return &pKeys->methods[mid];
-        else if (id < methodId)       /* too low */
-            lo = mid + 1;
-        else                          /* too high */
-            hi = mid - 1;
-    }
-
-    return NULL;
-}
-
-/*
- * Reads the next data record, and assigns the data values to threadId,
- * methodVal and elapsedTime.  On end-of-file, the threadId, methodVal,
- * and elapsedTime are unchanged.  Returns 1 on end-of-file, otherwise
- * returns 0.
- */
-int readDataRecord(FILE *dataFp, DataHeader* dataHeader,
-        int *threadId, unsigned int *methodVal, uint64_t *elapsedTime)
-{
-    int id;
-    int bytesToRead;
-
-    bytesToRead = dataHeader->recordSize;
-    if (dataHeader->version == 1) {
-        id = getc(dataFp);
-        bytesToRead -= 1;
-    } else {
-        id = read2LE(dataFp);
-        bytesToRead -= 2;
-    }
-    if (id == EOF)
-        return 1;
-    *threadId = id;
-
-    *methodVal = read4LE(dataFp);
-    *elapsedTime = read4LE(dataFp);
-    bytesToRead -= 8;
-
-    while (bytesToRead-- > 0) {
-        getc(dataFp);
-    }
-
-    if (feof(dataFp)) {
-        fprintf(stderr, "WARNING: hit EOF mid-record\n");
-        return 1;
-    }
-    return 0;
-}
-
-/*
- * Read the key file and use it to produce formatted output from the
- * data file.
- */
-void dumpTrace()
-{
-    static const char* actionStr[] = { "ent", "xit", "unr", "???" };
-    MethodEntry bogusMethod = { 0, "???", "???", "???", "???", -1, 0, 0, 0, 0,
-                                {NULL, NULL}, {NULL, NULL}, {0, 0}, 0, 0, -1 };
-    char bogusBuf[80];
-    char spaces[MAX_STACK_DEPTH+1];
-    FILE* dataFp = NULL;
-    DataHeader dataHeader;
-    DataKeys* pKeys = NULL;
-    int i;
-    TraceData traceData;
-
-    //printf("Dumping '%s' '%s'\n", dataFileName, keyFileName);
-
-    memset(spaces, '.', MAX_STACK_DEPTH);
-    spaces[MAX_STACK_DEPTH] = '\0';
-
-    for (i = 0; i < MAX_THREADS; i++)
-        traceData.depth[i] = 2;       // adjust for return from start function
-
-    dataFp = fopen(gOptions.traceFileName, "rb");
-    if (dataFp == NULL)
-        goto bail;
-
-    if ((pKeys = parseKeys(dataFp, 1)) == NULL)
-        goto bail;
-
-    if (parseDataHeader(dataFp, &dataHeader) < 0)
-        goto bail;
-
-    printf("Trace (threadID action usecs class.method signature):\n");
-
-    while (1) {
-        MethodEntry* method;
-        int threadId;
-        unsigned int methodVal;
-        uint64_t elapsedTime;
-        int action, printDepth;
-        int64_t methodId, lastEnter = 0;
-        int mismatch = 0;
-        char depthNote;
-
-        /*
-         * Extract values from file.
-         */
-        if (readDataRecord(dataFp, &dataHeader, &threadId, &methodVal, &elapsedTime))
-            break;
-
-        action = METHOD_ACTION(methodVal);
-        methodId = METHOD_ID(methodVal);
-
-        /*
-         * Generate a line of output.
-         */
-        if (action == METHOD_TRACE_ENTER) {
-            traceData.depth[threadId]++;
-            lastEnter = methodId;
-        } else {
-            /* quick test for mismatched adjacent enter/exit */
-            if (lastEnter != 0 && lastEnter != methodId)
-                mismatch = 1;
-        }
-
-        printDepth = traceData.depth[threadId];
-        depthNote = ' ';
-        if (printDepth < 0) {
-            printDepth = 0;
-            depthNote = '-';
-        } else if (printDepth > MAX_STACK_DEPTH) {
-            printDepth = MAX_STACK_DEPTH;
-            depthNote = '+';
-        }
-
-        method = lookupMethod(pKeys, methodId);
-        if (method == NULL) {
-            method = &bogusMethod;
-            sprintf(bogusBuf, "methodId: %#" PRIx64 "", methodId);
-            method->signature = bogusBuf;
-        }
-
-	if (method->methodName) {
-	    printf("%2d %s%c %8lld%c%s%s.%s %s\n", threadId,
-		   actionStr[action], mismatch ? '!' : ' ',
-		   elapsedTime, depthNote,
-		   spaces + (MAX_STACK_DEPTH - printDepth),
-		   method->className, method->methodName, method->signature);
-	} else {
-	    printf("%2d %s%c %8lld%c%s%s\n", threadId,
-		   actionStr[action], mismatch ? '!' : ' ',
-		   elapsedTime, depthNote,
-		   spaces + (MAX_STACK_DEPTH - printDepth),
-		   method->className);
-	}
-
-        if (action != METHOD_TRACE_ENTER) {
-            traceData.depth[threadId]--;  /* METHOD_TRACE_EXIT or METHOD_TRACE_UNROLL */
-            lastEnter = 0;
-        }
-
-        mismatch = 0;
-    }
-
-bail:
-    if (dataFp != NULL)
-        fclose(dataFp);
-    if (pKeys != NULL)
-        freeDataKeys(pKeys);
-}
-
-/* This routine adds the given time to the parent and child methods.
- * This is called when the child routine exits, after the child has
- * been popped from the stack.  The elapsedTime parameter is the
- * duration of the child routine, including time spent in called routines.
- */
-void addInclusiveTime(MethodEntry *parent, MethodEntry *child,
-                      uint64_t elapsedTime)
-{
-    TimedMethod *pTimed;
-
-#if 0
-    bool verbose = false;
-    if (strcmp(child->className, debugClassName) == 0)
-        verbose = true;
-#endif
-
-    int childIsRecursive = (child->recursiveEntries > 0);
-    int parentIsRecursive = (parent->recursiveEntries > 1);
-
-    if (child->recursiveEntries == 0) {
-        child->elapsedInclusive += elapsedTime;
-    } else if (child->recursiveEntries == 1) {
-        child->recursiveInclusive += elapsedTime;
-    }
-    child->numCalls[childIsRecursive] += 1;
-
-#if 0
-    if (verbose) {
-        fprintf(stderr,
-                "%s %d elapsedTime: %lld eI: %lld, rI: %lld\n",
-                child->className, child->recursiveEntries,
-                elapsedTime, child->elapsedInclusive,
-                child->recursiveInclusive);
-    }
-#endif
-
-    /* Find the child method in the parent */
-    TimedMethod *children = parent->children[parentIsRecursive];
-    for (pTimed = children; pTimed; pTimed = pTimed->next) {
-        if (pTimed->method == child) {
-            pTimed->elapsedInclusive += elapsedTime;
-            pTimed->numCalls += 1;
-            break;
-        }
-    }
-    if (pTimed == NULL) {
-        /* Allocate a new TimedMethod */
-        pTimed = (TimedMethod *) malloc(sizeof(TimedMethod));
-        pTimed->elapsedInclusive = elapsedTime;
-        pTimed->numCalls = 1;
-        pTimed->method = child;
-
-        /* Add it to the front of the list */
-        pTimed->next = children;
-        parent->children[parentIsRecursive] = pTimed;
-    }
-
-    /* Find the parent method in the child */
-    TimedMethod *parents = child->parents[childIsRecursive];
-    for (pTimed = parents; pTimed; pTimed = pTimed->next) {
-        if (pTimed->method == parent) {
-            pTimed->elapsedInclusive += elapsedTime;
-            pTimed->numCalls += 1;
-            break;
-        }
-    }
-    if (pTimed == NULL) {
-        /* Allocate a new TimedMethod */
-        pTimed = (TimedMethod *) malloc(sizeof(TimedMethod));
-        pTimed->elapsedInclusive = elapsedTime;
-        pTimed->numCalls = 1;
-        pTimed->method = parent;
-
-        /* Add it to the front of the list */
-        pTimed->next = parents;
-        child->parents[childIsRecursive] = pTimed;
-    }
-
-#if 0
-    if (verbose) {
-        fprintf(stderr,
-                "  %s %d eI: %lld\n",
-                parent->className, parent->recursiveEntries,
-                pTimed->elapsedInclusive);
-    }
-#endif
-}
-
-/* Sorts a linked list and returns a newly allocated array containing
- * the sorted entries.
- */
-TimedMethod *sortTimedMethodList(TimedMethod *list, int *num)
-{
-    int ii;
-    TimedMethod *pTimed, *sorted;
-
-    /* Count the elements */
-    int num_entries = 0;
-    for (pTimed = list; pTimed; pTimed = pTimed->next)
-        num_entries += 1;
-    *num = num_entries;
-    if (num_entries == 0)
-        return NULL;
-
-    /* Copy all the list elements to a new array and sort them */
-    sorted = (TimedMethod *) malloc(sizeof(TimedMethod) * num_entries);
-    for (ii = 0, pTimed = list; pTimed; pTimed = pTimed->next, ++ii)
-        memcpy(&sorted[ii], pTimed, sizeof(TimedMethod));
-    qsort(sorted, num_entries, sizeof(TimedMethod), compareTimedMethod);
-
-    /* Fix up the "next" pointers so that they work. */
-    for (ii = 0; ii < num_entries - 1; ++ii)
-        sorted[ii].next = &sorted[ii + 1];
-    sorted[num_entries - 1].next = NULL;
-
-    return sorted;
-}
-
-/* Define flag values for printInclusiveMethod() */
-static const int kIsRecursive = 1;
-
-/* This prints the inclusive stats for all the parents or children of a
- * method, depending on the list that is passed in.
- */
-void printInclusiveMethod(MethodEntry *method, TimedMethod *list, int numCalls,
-                          int flags)
-{
-    int num;
-    TimedMethod *pTimed;
-    char buf[80];
-    char *anchor_close;
-    char *spaces = "      ";    /* 6 spaces */
-    int num_spaces = strlen(spaces);
-    char *space_ptr = &spaces[num_spaces];
-    char *className, *methodName, *signature;
-    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
-    char signatureBuf[HTML_BUFSIZE];
-
-    anchor_close = "";
-    if (gOptions.outputHtml)
-        anchor_close = "</a>";
-
-    TimedMethod *sorted = sortTimedMethodList(list,  &num);
-    double methodTotal = method->elapsedInclusive;
-    for (pTimed = sorted; pTimed; pTimed = pTimed->next) {
-        MethodEntry *relative = pTimed->method;
-        className = (char*)(relative->className);
-        methodName = (char*)(relative->methodName);
-        signature = (char*)(relative->signature);
-        double per = 100.0 * pTimed->elapsedInclusive / methodTotal;
-        sprintf(buf, "[%d]", relative->index);
-        if (gOptions.outputHtml) {
-            int len = strlen(buf);
-            if (len > num_spaces)
-                len = num_spaces;
-            sprintf(buf, "<a href=\"#m%d\">[%d]",
-                    relative->index, relative->index);
-            space_ptr = &spaces[len];
-            className = htmlEscape(className, classBuf, HTML_BUFSIZE);
-            methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
-            signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
-        }
-        int nCalls = numCalls;
-        if (nCalls == 0)
-            nCalls = relative->numCalls[0] + relative->numCalls[1];
-        if (relative->methodName) {
-            if (flags & kIsRecursive) {
-                // Don't display percentages for recursive functions
-                printf("%6s %5s   %6s %s%6s%s %6d/%-6d %9llu %s.%s %s\n",
-                       "", "", "",
-                       space_ptr, buf, anchor_close,
-                       pTimed->numCalls, nCalls,
-                       pTimed->elapsedInclusive,
-                       className, methodName, signature);
-            } else {
-                printf("%6s %5s   %5.1f%% %s%6s%s %6d/%-6d %9llu %s.%s %s\n",
-                       "", "", per,
-                       space_ptr, buf, anchor_close,
-                       pTimed->numCalls, nCalls,
-                       pTimed->elapsedInclusive,
-                       className, methodName, signature);
-            }
-        } else {
-            if (flags & kIsRecursive) {
-                // Don't display percentages for recursive functions
-                printf("%6s %5s   %6s %s%6s%s %6d/%-6d %9llu %s\n",
-                       "", "", "",
-                       space_ptr, buf, anchor_close,
-                       pTimed->numCalls, nCalls,
-                       pTimed->elapsedInclusive,
-                       className);
-            } else {
-                printf("%6s %5s   %5.1f%% %s%6s%s %6d/%-6d %9llu %s\n",
-                       "", "", per,
-                       space_ptr, buf, anchor_close,
-                       pTimed->numCalls, nCalls,
-                       pTimed->elapsedInclusive,
-                       className);
-            }
-        }
-    }
-}
-
-void countRecursiveEntries(CallStack *pStack, int top, MethodEntry *method)
-{
-    int ii;
-
-    method->recursiveEntries = 0;
-    for (ii = 0; ii < top; ++ii) {
-        if (pStack->calls[ii].method == method)
-            method->recursiveEntries += 1;
-    }
-}
-
-void stackDump(CallStack *pStack, int top)
-{
-    int ii;
-
-    for (ii = 0; ii < top; ++ii) {
-        MethodEntry *method = pStack->calls[ii].method;
-        uint64_t entryTime = pStack->calls[ii].entryTime;
-        if (method->methodName) {
-            fprintf(stderr, "  %2d: %8llu %s.%s %s\n", ii, entryTime,
-                   method->className, method->methodName, method->signature);
-        } else {
-            fprintf(stderr, "  %2d: %8llu %s\n", ii, entryTime, method->className);
-        }
-    }
-}
-
-void outputTableOfContents()
-{
-    printf("<a name=\"contents\"></a>\n");
-    printf("<h2>Table of Contents</h2>\n");
-    printf("<ul>\n");
-    printf("  <li><a href=\"#exclusive\">Exclusive profile</a></li>\n");
-    printf("  <li><a href=\"#inclusive\">Inclusive profile</a></li>\n");
-    printf("  <li><a href=\"#class\">Class/method profile</a></li>\n");
-    printf("  <li><a href=\"#method\">Method/class profile</a></li>\n");
-    printf("</ul>\n\n");
-}
-
-void outputNavigationBar()
-{
-    printf("<a href=\"#contents\">[Top]</a>\n");
-    printf("<a href=\"#exclusive\">[Exclusive]</a>\n");
-    printf("<a href=\"#inclusive\">[Inclusive]</a>\n");
-    printf("<a href=\"#class\">[Class]</a>\n");
-    printf("<a href=\"#method\">[Method]</a>\n");
-    printf("<br><br>\n");
-}
-
-void printExclusiveProfile(MethodEntry **pMethods, int numMethods,
-                           uint64_t sumThreadTime)
-{
-    int ii;
-    MethodEntry* method;
-    double total, sum, per, sum_per;
-    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
-    char signatureBuf[HTML_BUFSIZE];
-    char anchor_buf[80];
-    char *anchor_close = "";
-
-    total = sumThreadTime;
-    anchor_buf[0] = 0;
-    if (gOptions.outputHtml) {
-        anchor_close = "</a>";
-        printf("<a name=\"exclusive\"></a>\n");
-        printf("<hr>\n");
-        outputNavigationBar();
-    } else {
-        printf("\n%s\n", profileSeparator);
-    }
-
-    /* First, sort the methods into decreasing order of inclusive
-     * elapsed time so that we can assign the method indices.
-     */
-    qsort(pMethods, numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
-
-    for (ii = 0; ii < numMethods; ++ii)
-        pMethods[ii]->index = ii;
-
-    /* Sort the methods into decreasing order of exclusive elapsed time.
-     */
-    qsort(pMethods, numMethods, sizeof(MethodEntry*),
-          compareElapsedExclusive);
-
-    printf("Total cycles: %llu\n\n", sumThreadTime);
-    if (gOptions.outputHtml) {
-        printf("<br><br>\n");
-    }
-    printf("Exclusive elapsed times for each method, not including time spent in\n");
-    printf("children, sorted by exclusive time.\n\n");
-    if (gOptions.outputHtml) {
-        printf("<br><br>\n<pre>\n");
-    }
-
-    printf("    Usecs  self %%  sum %%  Method\n");
-    sum = 0;
-
-    for (ii = 0; ii < numMethods; ++ii) {
-        char *className, *methodName, *signature;
-
-        method = pMethods[ii];
-        /* Don't show methods with zero cycles */
-        if (method->elapsedExclusive == 0)
-            break;
-        className = (char*)(method->className);
-        methodName = (char*)(method->methodName);
-        signature = (char*)(method->signature);
-        sum += method->elapsedExclusive;
-        per = 100.0 * method->elapsedExclusive / total;
-        sum_per = 100.0 * sum / total;
-        if (gOptions.outputHtml) {
-            sprintf(anchor_buf, "<a href=\"#m%d\">", method->index);
-            className = htmlEscape(className, classBuf, HTML_BUFSIZE);
-            methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
-            signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
-        }
-        if (method->methodName) {
-            printf("%9llu  %6.2f %6.2f  %s[%d]%s %s.%s %s\n",
-                   method->elapsedExclusive, per, sum_per,
-                   anchor_buf, method->index, anchor_close,
-                   className, methodName, signature);
-        } else {
-            printf("%9llu  %6.2f %6.2f  %s[%d]%s %s\n",
-                   method->elapsedExclusive, per, sum_per,
-                   anchor_buf, method->index, anchor_close,
-                   className);
-        }
-    }
-    if (gOptions.outputHtml) {
-        printf("</pre>\n");
-    }
-}
-
-/* check to make sure that the child method meets the threshold of the parent */
-int checkThreshold(MethodEntry* parent, MethodEntry* child)
-{
-    double parentTime = parent->elapsedInclusive;
-    double childTime = child->elapsedInclusive;
-    int64_t percentage = (childTime / parentTime) * 100.0;
-    return (percentage < gOptions.threshold) ? 0 : 1;
-}
-
-void createLabels(FILE* file, MethodEntry* method)
-{
-    fprintf(file, "node%d[label = \"[%d] %s.%s (%llu, %llu, %d)\"]\n",
-             method->index, method->index, method->className, method->methodName,
-             method->elapsedInclusive / 1000,
-             method->elapsedExclusive / 1000,
-             method->numCalls[0]);
-
-    method->graphState = GRAPH_LABEL_VISITED;
-
-    TimedMethod* child;
-    for (child = method->children[0] ; child ; child = child->next) {
-        MethodEntry* childMethod = child->method;
-
-        if ((childMethod->graphState & GRAPH_LABEL_VISITED) == 0 && checkThreshold(method, childMethod)) {
-            createLabels(file, child->method);
-        }
-    }
-}
-
-void createLinks(FILE* file, MethodEntry* method)
-{
-    method->graphState |= GRAPH_NODE_VISITED;
-
-    TimedMethod* child;
-    for (child = method->children[0] ; child ; child = child->next) {
-        MethodEntry* childMethod = child->method;
-        if (checkThreshold(method, child->method)) {
-            fprintf(file, "node%d -> node%d\n", method->index, child->method->index);
-            // only visit children that haven't been visited before
-            if ((childMethod->graphState & GRAPH_NODE_VISITED) == 0) {
-                createLinks(file, child->method);
-            }
-        }
-    }
-}
-
-void createInclusiveProfileGraphNew(DataKeys* dataKeys)
-{
-    // create a temporary file in /tmp
-    char path[FILENAME_MAX];
-    if (gOptions.keepDotFile) {
-        snprintf(path, FILENAME_MAX, "%s.dot", gOptions.graphFileName);
-    } else {
-        snprintf(path, FILENAME_MAX, "dot-%d-%d.dot", (int)time(NULL), rand());
-    }
-
-    FILE* file = fopen(path, "w+");
-
-    fprintf(file, "digraph g {\nnode [shape = record,height=.1];\n");
-
-    createLabels(file, dataKeys->methods);
-    createLinks(file, dataKeys->methods);
-
-    fprintf(file, "}");
-    fclose(file);
-
-    // now that we have the dot file generate the image
-    char command[1024];
-    snprintf(command, 1024, "dot -Tpng -o \"%s\" \"%s\"", gOptions.graphFileName, path);
-
-    system(command);
-
-    if (! gOptions.keepDotFile) {
-        remove(path);
-    }
-}
-
-void printInclusiveProfile(MethodEntry **pMethods, int numMethods,
-                           uint64_t sumThreadTime)
-{
-    int ii;
-    MethodEntry* method;
-    double total, sum, per, sum_per;
-    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
-    char signatureBuf[HTML_BUFSIZE];
-    char anchor_buf[80];
-    char *anchor_close = "";
-
-    total = sumThreadTime;
-    anchor_buf[0] = 0;
-    if (gOptions.outputHtml) {
-        anchor_close = "</a>";
-        printf("<a name=\"inclusive\"></a>\n");
-        printf("<hr>\n");
-        outputNavigationBar();
-    } else {
-        printf("\n%s\n", profileSeparator);
-    }
-
-    /* Sort the methods into decreasing order of inclusive elapsed time. */
-    qsort(pMethods, numMethods, sizeof(MethodEntry*),
-          compareElapsedInclusive);
-
-    printf("\nInclusive elapsed times for each method and its parents and children,\n");
-    printf("sorted by inclusive time.\n\n");
-
-    if (gOptions.outputHtml) {
-        printf("<br><br>\n<pre>\n");
-    }
-
-    printf("index  %%/total %%/self  index     calls         usecs name\n");
-    for (ii = 0; ii < numMethods; ++ii) {
-        int num;
-        TimedMethod *pTimed;
-        double excl_per;
-        char buf[40];
-        char *className, *methodName, *signature;
-
-        method = pMethods[ii];
-        /* Don't show methods with zero cycles */
-        if (method->elapsedInclusive == 0)
-            break;
-
-        className = (char*)(method->className);
-        methodName = (char*)(method->methodName);
-        signature = (char*)(method->signature);
-
-        if (gOptions.outputHtml) {
-            printf("<a name=\"m%d\"></a>", method->index);
-            className = htmlEscape(className, classBuf, HTML_BUFSIZE);
-            methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
-            signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
-        }
-        printf("----------------------------------------------------\n");
-
-        /* Sort and print the parents */
-        int numCalls = method->numCalls[0] + method->numCalls[1];
-        printInclusiveMethod(method, method->parents[0], numCalls, 0);
-        if (method->parents[1]) {
-            printf("               +++++++++++++++++++++++++\n");
-            printInclusiveMethod(method, method->parents[1], numCalls,
-                                 kIsRecursive);
-        }
-
-        per = 100.0 * method->elapsedInclusive / total;
-        sprintf(buf, "[%d]", ii);
-        if (method->methodName) {
-            printf("%-6s %5.1f%%   %5s %6s %6d+%-6d %9llu %s.%s %s\n",
-                   buf,
-                   per, "", "", method->numCalls[0], method->numCalls[1],
-                   method->elapsedInclusive,
-                   className, methodName, signature);
-        } else {
-            printf("%-6s %5.1f%%   %5s %6s %6d+%-6d %9llu %s\n",
-                   buf,
-                   per, "", "", method->numCalls[0], method->numCalls[1],
-                   method->elapsedInclusive,
-                   className);
-        }
-        excl_per = 100.0 * method->topExclusive / method->elapsedInclusive;
-        printf("%6s %5s   %5.1f%% %6s %6s %6s %9llu\n",
-               "", "", excl_per, "excl", "", "", method->topExclusive);
-
-        /* Sort and print the children */
-        printInclusiveMethod(method, method->children[0], 0, 0);
-        if (method->children[1]) {
-            printf("               +++++++++++++++++++++++++\n");
-            printInclusiveMethod(method, method->children[1], 0,
-                                 kIsRecursive);
-        }
-    }
-    if (gOptions.outputHtml) {
-        printf("</pre>\n");
-    }
-}
-
-void createClassList(TraceData* traceData, MethodEntry **pMethods, int numMethods)
-{
-    int ii;
-
-    /* Sort the methods into alphabetical order to find the unique class
-     * names.
-     */
-    qsort(pMethods, numMethods, sizeof(MethodEntry*), compareClassNames);
-
-    /* Count the number of unique class names. */
-    const char *currentClassName = "";
-    const char *firstClassName = NULL;
-    traceData->numClasses = 0;
-    for (ii = 0; ii < numMethods; ++ii) {
-        if (pMethods[ii]->methodName == NULL) {
-            continue;
-        }
-        if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
-            // Remember the first one
-            if (firstClassName == NULL) {
-                firstClassName = pMethods[ii]->className;
-            }
-            traceData->numClasses += 1;
-            currentClassName = pMethods[ii]->className;
-        }
-    }
-
-    if (traceData->numClasses == 0) {
-        traceData->classes = NULL;
-        return;
-    }
-
-    /* Allocate space for all of the unique class names */
-    traceData->classes = (ClassEntry *) malloc(sizeof(ClassEntry) * traceData->numClasses);
-
-    /* Initialize the classes array */
-    memset(traceData->classes, 0, sizeof(ClassEntry) * traceData->numClasses);
-    ClassEntry *pClass = traceData->classes;
-    pClass->className = currentClassName = firstClassName;
-    int prevNumMethods = 0;
-    for (ii = 0; ii < numMethods; ++ii) {
-        if (pMethods[ii]->methodName == NULL) {
-            continue;
-        }
-        if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
-            pClass->numMethods = prevNumMethods;
-            (++pClass)->className = currentClassName = pMethods[ii]->className;
-            prevNumMethods = 0;
-        }
-        prevNumMethods += 1;
-    }
-    pClass->numMethods = prevNumMethods;
-
-    /* Create the array of MethodEntry pointers for each class */
-    pClass = NULL;
-    currentClassName = "";
-    int nextMethod = 0;
-    for (ii = 0; ii < numMethods; ++ii) {
-        if (pMethods[ii]->methodName == NULL) {
-            continue;
-        }
-        if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
-            currentClassName = pMethods[ii]->className;
-            if (pClass == NULL)
-                pClass = traceData->classes;
-            else
-                pClass++;
-            /* Allocate space for the methods array */
-            int nbytes = sizeof(MethodEntry*) * pClass->numMethods;
-            pClass->methods = (MethodEntry**) malloc(nbytes);
-            nextMethod = 0;
-        }
-        pClass->methods[nextMethod++] = pMethods[ii];
-    }
-}
-
-/* Prints a number of html non-breaking spaces according so that the length
- * of the string "buf" is at least "width" characters wide.  If width is
- * negative, then trailing spaces are added instead of leading spaces.
- */
-void printHtmlField(char *buf, int width)
-{
-    int ii;
-
-    int leadingSpaces = 1;
-    if (width < 0) {
-        width = -width;
-        leadingSpaces = 0;
-    }
-    int len = strlen(buf);
-    int numSpaces = width - len;
-    if (numSpaces <= 0) {
-        printf("%s", buf);
-        return;
-    }
-    if (leadingSpaces == 0)
-        printf("%s", buf);
-    for (ii = 0; ii < numSpaces; ++ii)
-        printf("&nbsp;");
-    if (leadingSpaces == 1)
-        printf("%s", buf);
-}
-
-void printClassProfiles(TraceData* traceData, uint64_t sumThreadTime)
-{
-    int ii, jj;
-    MethodEntry* method;
-    double total, sum, per, sum_per;
-    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
-    char signatureBuf[HTML_BUFSIZE];
-
-    total = sumThreadTime;
-    if (gOptions.outputHtml) {
-        printf("<a name=\"class\"></a>\n");
-        printf("<hr>\n");
-        outputNavigationBar();
-    } else {
-        printf("\n%s\n", profileSeparator);
-    }
-
-    if (traceData->numClasses == 0) {
-        printf("\nNo classes.\n");
-        if (gOptions.outputHtml) {
-            printf("<br><br>\n");
-        }
-        return;
-    }
-
-    printf("\nExclusive elapsed time for each class, summed over all the methods\n");
-    printf("in the class.\n\n");
-    if (gOptions.outputHtml) {
-        printf("<br><br>\n");
-    }
-
-    /* For each class, sum the exclusive times in all of the methods
-     * in that class.  Also sum the number of method calls.  Also
-     * sort the methods so the most expensive appear at the top.
-     */
-    ClassEntry *pClass = traceData->classes;
-    for (ii = 0; ii < traceData->numClasses; ++ii, ++pClass) {
-        //printf("%s %d methods\n", pClass->className, pClass->numMethods);
-        int numMethods = pClass->numMethods;
-        for (jj = 0; jj < numMethods; ++jj) {
-            method = pClass->methods[jj];
-            pClass->elapsedExclusive += method->elapsedExclusive;
-            pClass->numCalls[0] += method->numCalls[0];
-            pClass->numCalls[1] += method->numCalls[1];
-        }
-
-        /* Sort the methods into decreasing order of exclusive time */
-        qsort(pClass->methods, numMethods, sizeof(MethodEntry*),
-              compareElapsedExclusive);
-    }
-
-    /* Allocate an array of pointers to the classes for more efficient
-     * sorting.
-     */
-    ClassEntry **pClasses;
-    pClasses = (ClassEntry**) malloc(sizeof(ClassEntry*) * traceData->numClasses);
-    for (ii = 0; ii < traceData->numClasses; ++ii)
-        pClasses[ii] = &traceData->classes[ii];
-
-    /* Sort the classes into decreasing order of exclusive time */
-    qsort(pClasses, traceData->numClasses, sizeof(ClassEntry*), compareClassExclusive);
-
-    if (gOptions.outputHtml) {
-        printf("<div class=\"header\"><span class=\"parent\">&nbsp;</span>&nbsp;&nbsp;&nbsp;");
-        printf("Cycles %%/total Cumul.%% &nbsp;Calls+Recur&nbsp; Class</div>\n");
-    } else {
-        printf("   Cycles %%/total Cumul.%%  Calls+Recur  Class\n");
-    }
-
-    sum = 0;
-    for (ii = 0; ii < traceData->numClasses; ++ii) {
-        char *className, *methodName, *signature;
-
-        /* Skip classes with zero cycles */
-        pClass = pClasses[ii];
-        if (pClass->elapsedExclusive == 0)
-            break;
-
-        per = 100.0 * pClass->elapsedExclusive / total;
-        sum += pClass->elapsedExclusive;
-        sum_per = 100.0 * sum / total;
-        className = (char*)(pClass->className);
-        if (gOptions.outputHtml) {
-            char buf[80];
-
-            className = htmlEscape(className, classBuf, HTML_BUFSIZE);
-            printf("<div class=\"link\" onClick=\"javascript:toggle('d%d')\" onMouseOver=\"javascript:onMouseOver(this)\" onMouseOut=\"javascript:onMouseOut(this)\"><span class=\"parent\" id=\"xd%d\">+</span>", ii, ii);
-            sprintf(buf, "%llu", pClass->elapsedExclusive);
-            printHtmlField(buf, 9);
-            printf(" ");
-            sprintf(buf, "%.1f", per);
-            printHtmlField(buf, 7);
-            printf(" ");
-            sprintf(buf, "%.1f", sum_per);
-            printHtmlField(buf, 7);
-            printf(" ");
-            sprintf(buf, "%d", pClass->numCalls[0]);
-            printHtmlField(buf, 6);
-            printf("+");
-            sprintf(buf, "%d", pClass->numCalls[1]);
-            printHtmlField(buf, -6);
-            printf(" ");
-            printf("%s", className);
-            printf("</div>\n");
-            printf("<div class=\"parent\" id=\"d%d\">\n", ii);
-        } else {
-            printf("---------------------------------------------\n");
-            printf("%9llu %7.1f %7.1f %6d+%-6d %s\n",
-                   pClass->elapsedExclusive, per, sum_per,
-                   pClass->numCalls[0], pClass->numCalls[1],
-                   className);
-        }
-
-        int numMethods = pClass->numMethods;
-        double classExclusive = pClass->elapsedExclusive;
-        double sumMethods = 0;
-        for (jj = 0; jj < numMethods; ++jj) {
-            method = pClass->methods[jj];
-            methodName = (char*)(method->methodName);
-            signature = (char*)(method->signature);
-            per = 100.0 * method->elapsedExclusive / classExclusive;
-            sumMethods += method->elapsedExclusive;
-            sum_per = 100.0 * sumMethods / classExclusive;
-            if (gOptions.outputHtml) {
-                char buf[80];
-
-                methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
-                signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
-                printf("<div class=\"leaf\"><span class=\"leaf\">&nbsp;</span>");
-                sprintf(buf, "%llu", method->elapsedExclusive);
-                printHtmlField(buf, 9);
-                printf("&nbsp;");
-                sprintf(buf, "%llu", method->elapsedInclusive);
-                printHtmlField(buf, 9);
-                printf("&nbsp;");
-                sprintf(buf, "%.1f", per);
-                printHtmlField(buf, 7);
-                printf("&nbsp;");
-                sprintf(buf, "%.1f", sum_per);
-                printHtmlField(buf, 7);
-                printf("&nbsp;");
-                sprintf(buf, "%d", method->numCalls[0]);
-                printHtmlField(buf, 6);
-                printf("+");
-                sprintf(buf, "%d", method->numCalls[1]);
-                printHtmlField(buf, -6);
-                printf("&nbsp;");
-                printf("<a href=\"#m%d\">[%d]</a>&nbsp;%s&nbsp;%s",
-                       method->index, method->index, methodName, signature);
-                printf("</div>\n");
-            } else {
-                printf("%9llu %9llu %7.1f %7.1f %6d+%-6d [%d] %s %s\n",
-                       method->elapsedExclusive,
-                       method->elapsedInclusive,
-                       per, sum_per,
-                       method->numCalls[0], method->numCalls[1],
-                       method->index, methodName, signature);
-            }
-        }
-        if (gOptions.outputHtml) {
-            printf("</div>\n");
-        }
-    }
-}
-
-void createUniqueMethodList(TraceData* traceData, MethodEntry **pMethods, int numMethods)
-{
-    int ii;
-
-    /* Sort the methods into alphabetical order of method names
-     * to find the unique method names.
-     */
-    qsort(pMethods, numMethods, sizeof(MethodEntry*), compareMethodNames);
-
-    /* Count the number of unique method names, ignoring class and
-     * signature.
-     */
-    const char *currentMethodName = "";
-    traceData->numUniqueMethods = 0;
-    for (ii = 0; ii < numMethods; ++ii) {
-        if (pMethods[ii]->methodName == NULL)
-            continue;
-        if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
-            traceData->numUniqueMethods += 1;
-            currentMethodName = pMethods[ii]->methodName;
-        }
-    }
-    if (traceData->numUniqueMethods == 0)
-        return;
-
-    /* Allocate space for pointers to all of the unique methods */
-    int nbytes = sizeof(UniqueMethodEntry) * traceData->numUniqueMethods;
-    traceData->uniqueMethods = (UniqueMethodEntry *) malloc(nbytes);
-
-    /* Initialize the uniqueMethods array */
-    memset(traceData->uniqueMethods, 0, nbytes);
-    UniqueMethodEntry *pUnique = traceData->uniqueMethods;
-    currentMethodName = NULL;
-    int prevNumMethods = 0;
-    for (ii = 0; ii < numMethods; ++ii) {
-        if (pMethods[ii]->methodName == NULL)
-            continue;
-        if (currentMethodName == NULL)
-            currentMethodName = pMethods[ii]->methodName;
-        if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
-            currentMethodName = pMethods[ii]->methodName;
-            pUnique->numMethods = prevNumMethods;
-            pUnique++;
-            prevNumMethods = 0;
-        }
-        prevNumMethods += 1;
-    }
-    pUnique->numMethods = prevNumMethods;
-
-    /* Create the array of MethodEntry pointers for each unique method */
-    pUnique = NULL;
-    currentMethodName = "";
-    int nextMethod = 0;
-    for (ii = 0; ii < numMethods; ++ii) {
-        if (pMethods[ii]->methodName == NULL)
-            continue;
-        if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
-            currentMethodName = pMethods[ii]->methodName;
-            if (pUnique == NULL)
-                pUnique = traceData->uniqueMethods;
-            else
-                pUnique++;
-            /* Allocate space for the methods array */
-            int nbytes = sizeof(MethodEntry*) * pUnique->numMethods;
-            pUnique->methods = (MethodEntry**) malloc(nbytes);
-            nextMethod = 0;
-        }
-        pUnique->methods[nextMethod++] = pMethods[ii];
-    }
-}
-
-void printMethodProfiles(TraceData* traceData, uint64_t sumThreadTime)
-{
-    int ii, jj;
-    MethodEntry* method;
-    double total, sum, per, sum_per;
-    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
-    char signatureBuf[HTML_BUFSIZE];
-
-    if (traceData->numUniqueMethods == 0)
-        return;
-
-    total = sumThreadTime;
-    if (gOptions.outputHtml) {
-        printf("<a name=\"method\"></a>\n");
-        printf("<hr>\n");
-        outputNavigationBar();
-    } else {
-        printf("\n%s\n", profileSeparator);
-    }
-
-    printf("\nExclusive elapsed time for each method, summed over all the classes\n");
-    printf("that contain a method with the same name.\n\n");
-    if (gOptions.outputHtml) {
-        printf("<br><br>\n");
-    }
-
-    /* For each unique method, sum the exclusive times in all of the methods
-     * with the same name.  Also sum the number of method calls.  Also
-     * sort the methods so the most expensive appear at the top.
-     */
-    UniqueMethodEntry *pUnique = traceData->uniqueMethods;
-    for (ii = 0; ii < traceData->numUniqueMethods; ++ii, ++pUnique) {
-        int numMethods = pUnique->numMethods;
-        for (jj = 0; jj < numMethods; ++jj) {
-            method = pUnique->methods[jj];
-            pUnique->elapsedExclusive += method->elapsedExclusive;
-            pUnique->numCalls[0] += method->numCalls[0];
-            pUnique->numCalls[1] += method->numCalls[1];
-        }
-
-        /* Sort the methods into decreasing order of exclusive time */
-        qsort(pUnique->methods, numMethods, sizeof(MethodEntry*),
-              compareElapsedExclusive);
-    }
-
-    /* Allocate an array of pointers to the methods for more efficient
-     * sorting.
-     */
-    UniqueMethodEntry **pUniqueMethods;
-    int nbytes = sizeof(UniqueMethodEntry*) * traceData->numUniqueMethods;
-    pUniqueMethods = (UniqueMethodEntry**) malloc(nbytes);
-    for (ii = 0; ii < traceData->numUniqueMethods; ++ii)
-        pUniqueMethods[ii] = &traceData->uniqueMethods[ii];
-
-    /* Sort the methods into decreasing order of exclusive time */
-    qsort(pUniqueMethods, traceData->numUniqueMethods, sizeof(UniqueMethodEntry*),
-          compareUniqueExclusive);
-
-    if (gOptions.outputHtml) {
-        printf("<div class=\"header\"><span class=\"parent\">&nbsp;</span>&nbsp;&nbsp;&nbsp;");
-        printf("Cycles %%/total Cumul.%% &nbsp;Calls+Recur&nbsp; Method</div>\n");
-    } else {
-        printf("   Cycles %%/total Cumul.%%  Calls+Recur  Method\n");
-    }
-
-    sum = 0;
-    for (ii = 0; ii < traceData->numUniqueMethods; ++ii) {
-        char *className, *methodName, *signature;
-
-        /* Skip methods with zero cycles */
-        pUnique = pUniqueMethods[ii];
-        if (pUnique->elapsedExclusive == 0)
-            break;
-
-        per = 100.0 * pUnique->elapsedExclusive / total;
-        sum += pUnique->elapsedExclusive;
-        sum_per = 100.0 * sum / total;
-        methodName = (char*)(pUnique->methods[0]->methodName);
-        if (gOptions.outputHtml) {
-            char buf[80];
-
-            methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
-            printf("<div class=\"link\" onClick=\"javascript:toggle('e%d')\" onMouseOver=\"javascript:onMouseOver(this)\" onMouseOut=\"javascript:onMouseOut(this)\"><span class=\"parent\" id=\"xe%d\">+</span>", ii, ii);
-            sprintf(buf, "%llu", pUnique->elapsedExclusive);
-            printHtmlField(buf, 9);
-            printf(" ");
-            sprintf(buf, "%.1f", per);
-            printHtmlField(buf, 7);
-            printf(" ");
-            sprintf(buf, "%.1f", sum_per);
-            printHtmlField(buf, 7);
-            printf(" ");
-            sprintf(buf, "%d", pUnique->numCalls[0]);
-            printHtmlField(buf, 6);
-            printf("+");
-            sprintf(buf, "%d", pUnique->numCalls[1]);
-            printHtmlField(buf, -6);
-            printf(" ");
-            printf("%s", methodName);
-            printf("</div>\n");
-            printf("<div class=\"parent\" id=\"e%d\">\n", ii);
-        } else {
-            printf("---------------------------------------------\n");
-            printf("%9llu %7.1f %7.1f %6d+%-6d %s\n",
-                   pUnique->elapsedExclusive, per, sum_per,
-                   pUnique->numCalls[0], pUnique->numCalls[1],
-                   methodName);
-        }
-        int numMethods = pUnique->numMethods;
-        double methodExclusive = pUnique->elapsedExclusive;
-        double sumMethods = 0;
-        for (jj = 0; jj < numMethods; ++jj) {
-            method = pUnique->methods[jj];
-            className = (char*)(method->className);
-            signature = (char*)(method->signature);
-            per = 100.0 * method->elapsedExclusive / methodExclusive;
-            sumMethods += method->elapsedExclusive;
-            sum_per = 100.0 * sumMethods / methodExclusive;
-            if (gOptions.outputHtml) {
-                char buf[80];
-
-                className = htmlEscape(className, classBuf, HTML_BUFSIZE);
-                signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
-                printf("<div class=\"leaf\"><span class=\"leaf\">&nbsp;</span>");
-                sprintf(buf, "%llu", method->elapsedExclusive);
-                printHtmlField(buf, 9);
-                printf("&nbsp;");
-                sprintf(buf, "%llu", method->elapsedInclusive);
-                printHtmlField(buf, 9);
-                printf("&nbsp;");
-                sprintf(buf, "%.1f", per);
-                printHtmlField(buf, 7);
-                printf("&nbsp;");
-                sprintf(buf, "%.1f", sum_per);
-                printHtmlField(buf, 7);
-                printf("&nbsp;");
-                sprintf(buf, "%d", method->numCalls[0]);
-                printHtmlField(buf, 6);
-                printf("+");
-                sprintf(buf, "%d", method->numCalls[1]);
-                printHtmlField(buf, -6);
-                printf("&nbsp;");
-                printf("<a href=\"#m%d\">[%d]</a>&nbsp;%s.%s&nbsp;%s",
-                       method->index, method->index,
-                       className, methodName, signature);
-                printf("</div>\n");
-            } else {
-                printf("%9llu %9llu %7.1f %7.1f %6d+%-6d [%d] %s.%s %s\n",
-                       method->elapsedExclusive,
-                       method->elapsedInclusive,
-                       per, sum_per,
-                       method->numCalls[0], method->numCalls[1],
-                       method->index, className, methodName, signature);
-            }
-        }
-        if (gOptions.outputHtml) {
-            printf("</div>\n");
-        }
-    }
-}
-
-/*
- * Read the key and data files and return the MethodEntries for those files
- */
-DataKeys* parseDataKeys(TraceData* traceData, const char* traceFileName, uint64_t* threadTime)
-{
-    DataKeys* dataKeys = NULL;
-    MethodEntry **pMethods = NULL;
-    MethodEntry* method;
-    FILE* dataFp = NULL;
-    DataHeader dataHeader;
-    int ii;
-    uint64_t currentTime;
-    MethodEntry* caller;
-
-    dataFp = fopen(traceFileName, "rb");
-    if (dataFp == NULL)
-        goto bail;
-
-    if ((dataKeys = parseKeys(dataFp, 0)) == NULL)
-        goto bail;
-
-    if (parseDataHeader(dataFp, &dataHeader) < 0)
-        goto bail;
-
-#if 0
-    FILE *dumpStream = fopen("debug", "w");
-#endif
-    while (1) {
-        int threadId;
-        unsigned int methodVal;
-        int action;
-        int64_t methodId;
-        CallStack *pStack;
-        /*
-         * Extract values from file.
-         */
-        if (readDataRecord(dataFp, &dataHeader, &threadId, &methodVal, &currentTime))
-            break;
-
-        action = METHOD_ACTION(methodVal);
-        methodId = METHOD_ID(methodVal);
-
-        /* Get the call stack for this thread */
-        pStack = traceData->stacks[threadId];
-
-        /* If there is no call stack yet for this thread, then allocate one */
-        if (pStack == NULL) {
-            pStack = malloc(sizeof(CallStack));
-            pStack->top = 0;
-            pStack->lastEventTime = currentTime;
-            pStack->threadStartTime = currentTime;
-            traceData->stacks[threadId] = pStack;
-        }
-
-        /* Lookup the current method */
-        method = lookupMethod(dataKeys, methodId);
-        if (method == NULL)
-            method = &dataKeys->methods[UNKNOWN_INDEX];
-
-#if 0
-        if (method->methodName) {
-            fprintf(dumpStream, "%2d %-8llu %d %8llu r %d c %d %s.%s %s\n",
-                    threadId, currentTime, action, pStack->threadStartTime,
-                    method->recursiveEntries,
-                    pStack->top, method->className, method->methodName,
-                    method->signature);
-        } else {
-            fprintf(dumpStream, "%2d %-8llu %d %8llu r %d c %d %s\n",
-                    threadId, currentTime, action, pStack->threadStartTime,
-                    method->recursiveEntries,
-                    pStack->top, method->className);
-        }
-#endif
-
-        if (action == METHOD_TRACE_ENTER) {
-            /* This is a method entry */
-            if (pStack->top >= MAX_STACK_DEPTH) {
-                fprintf(stderr, "Stack overflow (exceeded %d frames)\n",
-                        MAX_STACK_DEPTH);
-                exit(1);
-            }
-
-            /* Get the caller method */
-            if (pStack->top >= 1)
-                caller = pStack->calls[pStack->top - 1].method;
-            else
-                caller = &dataKeys->methods[TOPLEVEL_INDEX];
-            countRecursiveEntries(pStack, pStack->top, caller);
-            caller->elapsedExclusive += currentTime - pStack->lastEventTime;
-#if 0
-            if (caller->elapsedExclusive > 10000000)
-                fprintf(dumpStream, "%llu current %llu last %llu diff %llu\n",
-                        caller->elapsedExclusive, currentTime,
-                        pStack->lastEventTime,
-                        currentTime - pStack->lastEventTime);
-#endif
-            if (caller->recursiveEntries <= 1) {
-                caller->topExclusive += currentTime - pStack->lastEventTime;
-            }
-
-            /* Push the method on the stack for this thread */
-            pStack->calls[pStack->top].method = method;
-            pStack->calls[pStack->top++].entryTime = currentTime;
-        } else {
-            /* This is a method exit */
-            uint64_t entryTime = 0;
-
-            /* Pop the method off the stack for this thread */
-            if (pStack->top > 0) {
-                pStack->top -= 1;
-                entryTime = pStack->calls[pStack->top].entryTime;
-                if (method != pStack->calls[pStack->top].method) {
-                    if (method->methodName) {
-                        fprintf(stderr,
-                            "Exit from method %s.%s %s does not match stack:\n",
-                            method->className, method->methodName,
-                            method->signature);
-                    } else {
-                        fprintf(stderr,
-                            "Exit from method %s does not match stack:\n",
-                            method->className);
-                    }
-                    stackDump(pStack, pStack->top + 1);
-                    exit(1);
-                }
-            }
-
-            /* Get the caller method */
-            if (pStack->top >= 1)
-                caller = pStack->calls[pStack->top - 1].method;
-            else
-                caller = &dataKeys->methods[TOPLEVEL_INDEX];
-            countRecursiveEntries(pStack, pStack->top, caller);
-            countRecursiveEntries(pStack, pStack->top, method);
-            uint64_t elapsed = currentTime - entryTime;
-            addInclusiveTime(caller, method, elapsed);
-            method->elapsedExclusive += currentTime - pStack->lastEventTime;
-            if (method->recursiveEntries == 0) {
-                method->topExclusive += currentTime - pStack->lastEventTime;
-            }
-        }
-        /* Remember the time of the last entry or exit event */
-        pStack->lastEventTime = currentTime;
-    }
-
-    /* If we have calls on the stack when the trace ends, then clean
-     * up the stack and add time to the callers by pretending that we
-     * are exiting from their methods now.
-     */
-    CallStack *pStack;
-    int threadId;
-    uint64_t sumThreadTime = 0;
-    for (threadId = 0; threadId < MAX_THREADS; ++threadId) {
-        pStack = traceData->stacks[threadId];
-
-        /* If this thread never existed, then continue with next thread */
-        if (pStack == NULL)
-            continue;
-
-        /* Also, add up the time taken by all of the threads */
-        sumThreadTime += pStack->lastEventTime - pStack->threadStartTime;
-
-        for (ii = 0; ii < pStack->top; ++ii) {
-            if (ii == 0)
-                caller = &dataKeys->methods[TOPLEVEL_INDEX];
-            else
-                caller = pStack->calls[ii - 1].method;
-            method = pStack->calls[ii].method;
-            countRecursiveEntries(pStack, ii, caller);
-            countRecursiveEntries(pStack, ii, method);
-
-            uint64_t entryTime = pStack->calls[ii].entryTime;
-            uint64_t elapsed = pStack->lastEventTime - entryTime;
-            addInclusiveTime(caller, method, elapsed);
-        }
-    }
-    caller = &dataKeys->methods[TOPLEVEL_INDEX];
-    caller->elapsedInclusive = sumThreadTime;
-
-#if 0
-    fclose(dumpStream);
-#endif
-
-    if (threadTime != NULL) {
-        *threadTime = sumThreadTime;
-    }
-
-bail:
-    if (dataFp != NULL)
-        fclose(dataFp);
-
-    return dataKeys;
-}
-
-MethodEntry** parseMethodEntries(DataKeys* dataKeys)
-{
-    int ii;
-    /* Create a new array of pointers to the methods and sort the pointers
-     * instead of the actual MethodEntry structs.  We need to do this
-     * because there are other lists that contain pointers to the
-     * MethodEntry structs.
-     */
-    MethodEntry** pMethods = (MethodEntry**) malloc(sizeof(MethodEntry*) * dataKeys->numMethods);
-    for (ii = 0; ii < dataKeys->numMethods; ++ii) {
-        MethodEntry* entry = &dataKeys->methods[ii];
-        pMethods[ii] = entry;
-    }
-
-    return pMethods;
-}
-
-/*
- * Produce a function profile from the following methods
- */
-void profileTrace(TraceData* traceData, MethodEntry **pMethods, int numMethods, uint64_t sumThreadTime)
-{
-    /* Print the html header, if necessary */
-    if (gOptions.outputHtml) {
-        printf(htmlHeader, gOptions.sortableUrl);
-        outputTableOfContents();
-    }
-
-    printExclusiveProfile(pMethods, numMethods, sumThreadTime);
-    printInclusiveProfile(pMethods, numMethods, sumThreadTime);
-
-    createClassList(traceData, pMethods, numMethods);
-    printClassProfiles(traceData, sumThreadTime);
-
-    createUniqueMethodList(traceData, pMethods, numMethods);
-    printMethodProfiles(traceData, sumThreadTime);
-
-    if (gOptions.outputHtml) {
-        printf("%s", htmlFooter);
-    }
-}
-
-int compareMethodNamesForDiff(const void *a, const void *b)
-{
-    int result;
-
-    const MethodEntry *methodA = *(const MethodEntry**)a;
-    const MethodEntry *methodB = *(const MethodEntry**)b;
-    if (methodA->methodName == NULL || methodB->methodName == NULL) {
-        return compareClassNames(a, b);
-    }
-    result = strcmp(methodA->methodName, methodB->methodName);
-    if (result == 0) {
-        result = strcmp(methodA->signature, methodB->signature);
-        if (result == 0) {
-           return strcmp(methodA->className, methodB->className);
-        }
-    }
-    return result;
-}
-
-int findMatch(MethodEntry** methods, int size, MethodEntry* matchThis)
-{
-    int i;
-
-    for (i = 0 ; i < size ; i++) {
-        MethodEntry* method = methods[i];
-
-        if (method != NULL && !compareMethodNamesForDiff(&method, &matchThis)) {
-//            printf("%s.%s == %s.%s<br>\n", matchThis->className, matchThis->methodName,
-  //              method->className, method->methodName);
-
-            return i;
-/*            if (!compareMethodNames(&method, &matchThis)) {
-                return i;
-            }
-*/        }
-    }
-
-    return -1;
-}
-
-int compareDiffEntriesExculsive(const void *a, const void *b)
-{
-    int result;
-
-    const DiffEntry* entryA = (const DiffEntry*)a;
-    const DiffEntry* entryB = (const DiffEntry*)b;
-
-    if (entryA->differenceExclusive < entryB->differenceExclusive) {
-        return 1;
-    } else if (entryA->differenceExclusive > entryB->differenceExclusive) {
-        return -1;
-    }
-
-    return 0;
-}
-
-int compareDiffEntriesInculsive(const void *a, const void *b)
-{
-    int result;
-
-    const DiffEntry* entryA = (const DiffEntry*)a;
-    const DiffEntry* entryB = (const DiffEntry*)b;
-
-    if (entryA->differenceInclusive < entryB->differenceInclusive) {
-        return 1;
-    } else if (entryA->differenceInclusive > entryB->differenceInclusive) {
-        return -1;
-    }
-
-    return 0;
-}
-
-void printMissingMethod(MethodEntry* method)
-{
-    char classBuf[HTML_BUFSIZE];
-    char methodBuf[HTML_BUFSIZE];
-    char* className;
-    char* methodName;
-
-    className = htmlEscape(method->className, classBuf, HTML_BUFSIZE);
-    methodName = htmlEscape(method->methodName, methodBuf, HTML_BUFSIZE);
-
-    if (gOptions.outputHtml) printf("<tr><td>\n");
-
-    printf("%s.%s ", className, methodName);
-    if (gOptions.outputHtml) printf("</td><td>");
-
-    printf("%lld ", method->elapsedExclusive);
-    if (gOptions.outputHtml) printf("</td><td>");
-
-    printf("%lld ", method->elapsedInclusive);
-    if (gOptions.outputHtml) printf("</td><td>");
-
-    printf("%d\n", method->numCalls[0]);
-    if (gOptions.outputHtml) printf("</td><td>\n");
-}
-
-
-void createDiff(DataKeys* d1, uint64_t sum1, DataKeys* d2, uint64_t sum2)
-{
-    MethodEntry** methods1 = parseMethodEntries(d1);
-    MethodEntry** methods2 = parseMethodEntries(d2);
-
-    // sort and assign the indicies
-    int i;
-    qsort(methods1, d1->numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
-    for (i = 0; i < d1->numMethods; ++i) {
-        methods1[i]->index = i;
-    }
-
-    qsort(methods2, d2->numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
-    for (i = 0; i < d2->numMethods; ++i) {
-        methods2[i]->index = i;
-    }
-
-    int max = (d1->numMethods < d2->numMethods) ? d2->numMethods : d1->numMethods;
-    max++;
-    DiffEntry* diffs = (DiffEntry*)malloc(max * sizeof(DiffEntry));
-    memset(diffs, 0, max * sizeof(DiffEntry));
-    DiffEntry* ptr = diffs;
-
-//    printf("<br>d1->numMethods: %d d1->numMethods: %d<br>\n", d1->numMethods, d2->numMethods);
-
-    int matches = 0;
-
-    for (i = 0 ; i < d1->numMethods ; i++) {
-        int match = findMatch(methods2, d2->numMethods, methods1[i]);
-        if (match >= 0) {
-            ptr->method1 = methods1[i];
-            ptr->method2 = methods2[match];
-
-            uint64_t e1 = ptr->method1->elapsedExclusive;
-            uint64_t e2 = ptr->method2->elapsedExclusive;
-            if (e1 > 0) {
-                ptr->differenceExclusive = e2 - e1;
-                ptr->differenceExclusivePercentage = ((double)e2 / (double)e1) * 100.0;
-            }
-
-            uint64_t i1 = ptr->method1->elapsedInclusive;
-            uint64_t i2 = ptr->method2->elapsedInclusive;
-            if (i1 > 0) {
-                ptr->differenceInclusive = i2 - i1;
-                ptr->differenceInclusivePercentage = ((double)i2 / (double)i1) * 100.0;
-            }
-
-            // clear these out so we don't find them again and we know which ones
-            // we have left over
-            methods1[i] = NULL;
-            methods2[match] = NULL;
-            ptr++;
-
-            matches++;
-        }
-    }
-    ptr->method1 = NULL;
-    ptr->method2 = NULL;
-
-    qsort(diffs, matches, sizeof(DiffEntry), compareDiffEntriesExculsive);
-    ptr = diffs;
-
-    if (gOptions.outputHtml) {
-        printf(htmlHeader, gOptions.sortableUrl);
-        printf("<h3>Table of Contents</h3>\n");
-        printf("<ul>\n");
-        printf("<li><a href='#exclusive'>Exclusive</a>\n");
-        printf("<li><a href='#inclusive'>Inclusive</a>\n");
-        printf("</ul>\n");
-        printf("Run 1: %s<br>\n", gOptions.diffFileName);
-        printf("Run 2: %s<br>\n", gOptions.traceFileName);
-        printf("<a name=\"exclusive\"></a><h3 id=\"exclusive\">Exclusive</h3>\n");
-        printf(tableHeader, "exclusive_table");
-    }
-
-    char classBuf[HTML_BUFSIZE];
-    char methodBuf[HTML_BUFSIZE];
-    char* className;
-    char* methodName;
-
-    while (ptr->method1 != NULL && ptr->method2 != NULL) {
-        if (gOptions.outputHtml) printf("<tr><td>\n");
-
-        className = htmlEscape(ptr->method1->className, classBuf, HTML_BUFSIZE);
-        methodName = htmlEscape(ptr->method1->methodName, methodBuf, HTML_BUFSIZE);
-
-        printf("%s.%s ", className, methodName);
-        if (gOptions.outputHtml) printf("</td><td>");
-
-        printf("%lld ", ptr->method1->elapsedExclusive);
-        if (gOptions.outputHtml) printf("</td><td>");
-
-        printf("%llu ", ptr->method2->elapsedExclusive);
-        if (gOptions.outputHtml) printf("</td><td>");
-
-        printf("%lld ", ptr->differenceExclusive);
-        if (gOptions.outputHtml) printf("</td><td>");
-
-        printf("%.2f\n", ptr->differenceExclusivePercentage);
-        if (gOptions.outputHtml) printf("</td><td>\n");
-
-        printf("%d\n", ptr->method1->numCalls[0]);
-        if (gOptions.outputHtml) printf("</td><td>\n");
-
-        printf("%d\n", ptr->method2->numCalls[0]);
-        if (gOptions.outputHtml) printf("</td></tr>\n");
-
-        ptr++;
-    }
-
-    if (gOptions.outputHtml) printf("</table>\n");
-
-    if (gOptions.outputHtml) {
-        printf(htmlHeader, gOptions.sortableUrl);
-        printf("Run 1: %s<br>\n", gOptions.diffFileName);
-        printf("Run 2: %s<br>\n", gOptions.traceFileName);
-        printf("<a name=\"inclusive\"></a><h3 id=\"inculisve\">Inclusive</h3>\n");
-        printf(tableHeader, "inclusive_table");
-    }
-
-    qsort(diffs, matches, sizeof(DiffEntry), compareDiffEntriesInculsive);
-    ptr = diffs;
-
-    while (ptr->method1 != NULL && ptr->method2 != NULL) {
-        if (gOptions.outputHtml) printf("<tr><td>\n");
-
-        className = htmlEscape(ptr->method1->className, classBuf, HTML_BUFSIZE);
-        methodName = htmlEscape(ptr->method1->methodName, methodBuf, HTML_BUFSIZE);
-
-        printf("%s.%s ", className, methodName);
-        if (gOptions.outputHtml) printf("</td><td>");
-
-        printf("%lld ", ptr->method1->elapsedInclusive);
-        if (gOptions.outputHtml) printf("</td><td>");
-
-        printf("%llu ", ptr->method2->elapsedInclusive);
-        if (gOptions.outputHtml) printf("</td><td>");
-
-        printf("%lld ", ptr->differenceInclusive);
-        if (gOptions.outputHtml) printf("</td><td>");
-
-        printf("%.2f\n", ptr->differenceInclusivePercentage);
-        if (gOptions.outputHtml) printf("</td><td>\n");
-
-        printf("%d\n", ptr->method1->numCalls[0]);
-        if (gOptions.outputHtml) printf("</td><td>\n");
-
-        printf("%d\n", ptr->method2->numCalls[0]);
-        if (gOptions.outputHtml) printf("</td></tr>\n");
-
-        ptr++;
-    }
-
-    if (gOptions.outputHtml) {
-        printf("</table>\n");
-        printf("<h3>Run 1 methods not found in Run 2</h3>");
-        printf(tableHeaderMissing, "?");
-    }
-
-    for (i = 0; i < d1->numMethods; ++i) {
-        if (methods1[i] != NULL) {
-           printMissingMethod(methods1[i]);
-        }
-    }
-
-    if (gOptions.outputHtml) {
-        printf("</table>\n");
-        printf("<h3>Run 2 methods not found in Run 1</h3>");
-        printf(tableHeaderMissing, "?");
-    }
-
-    for (i = 0; i < d2->numMethods; ++i) {
-        if (methods2[i] != NULL) {
-            printMissingMethod(methods2[i]);
-        }
-    }
-
-    if (gOptions.outputHtml) printf("</body></html\n");
-}
-
-int usage(const char *program)
-{
-    fprintf(stderr, "Copyright (C) 2006 The Android Open Source Project\n\n");
-    fprintf(stderr, "usage: %s [-ho] [-s sortable] [-d trace-file-name] [-g outfile] trace-file-name\n", program);
-    fprintf(stderr, "  -d trace-file-name  - Diff with this trace\n");
-    fprintf(stderr, "  -g outfile          - Write graph to 'outfile'\n");
-    fprintf(stderr, "  -k                  - When writing a graph, keep the intermediate DOT file\n");
-    fprintf(stderr, "  -h                  - Turn on HTML output\n");
-    fprintf(stderr, "  -o                  - Dump the dmtrace file instead of profiling\n");
-    fprintf(stderr, "  -s                  - URL base to where the sortable javascript file\n");
-    fprintf(stderr, "  -t threshold        - Threshold percentage for including nodes in the graph\n");
-    return 2;
-}
-
-// Returns true if there was an error
-int parseOptions(int argc, char **argv)
-{
-    while (1) {
-        int opt = getopt(argc, argv, "d:hg:kos:t:");
-        if (opt == -1)
-            break;
-        switch (opt) {
-            case 'd':
-                gOptions.diffFileName = optarg;
-                break;
-            case 'g':
-                gOptions.graphFileName = optarg;
-                break;
-            case 'k':
-                gOptions.keepDotFile = 1;
-                break;
-            case 'h':
-                gOptions.outputHtml = 1;
-                break;
-            case 'o':
-                gOptions.dump = 1;
-                break;
-            case 's':
-                gOptions.sortableUrl = optarg;
-                break;
-            case 't':
-                gOptions.threshold = atoi(optarg);
-                break;
-            default:
-                return 1;
-        }
-    }
-    return 0;
-}
-
-/*
- * Parse args.
- */
-int main(int argc, char** argv)
-{
-    gOptions.threshold = -1;
-
-    // Parse the options
-    if (parseOptions(argc, argv) || argc - optind != 1)
-        return usage(argv[0]);
-
-    gOptions.traceFileName = argv[optind];
-
-    if (gOptions.threshold < 0 || 100 <= gOptions.threshold) {
-        gOptions.threshold = 20;
-    }
-
-    if (gOptions.dump) {
-        dumpTrace();
-        return 0;
-    }
-
-    uint64_t sumThreadTime = 0;
-
-    TraceData data1;
-    DataKeys* dataKeys = parseDataKeys(&data1, gOptions.traceFileName,
-                                       &sumThreadTime);
-    if (dataKeys == NULL) {
-        fprintf(stderr, "Cannot read \"%s\".\n", gOptions.traceFileName);
-        exit(1);
-    }
-
-    if (gOptions.diffFileName != NULL) {
-        uint64_t sum2;
-        TraceData data2;
-        DataKeys* d2 = parseDataKeys(&data2, gOptions.diffFileName, &sum2);
-        if (d2 == NULL) {
-            fprintf(stderr, "Cannot read \"%s\".\n", gOptions.diffFileName);
-            exit(1);
-        }
-
-        createDiff(d2, sum2, dataKeys, sumThreadTime);
-
-        freeDataKeys(d2);
-    } else {
-        MethodEntry** methods = parseMethodEntries(dataKeys);
-        profileTrace(&data1, methods, dataKeys->numMethods, sumThreadTime);
-        if (gOptions.graphFileName != NULL) {
-            createInclusiveProfileGraphNew(dataKeys);
-        }
-        free(methods);
-    }
-
-    freeDataKeys(dataKeys);
-
-    return 0;
-}
diff --git a/tools/dmtracedump/dmtracedump.pl b/tools/dmtracedump/dmtracedump.pl
deleted file mode 100755
index 6e487c6..0000000
--- a/tools/dmtracedump/dmtracedump.pl
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/perl
-
-opendir(DIR, ".") || die "can't opendir $some_dir: $!";
-@traces = grep { /.*\.dmtrace\.data/ } readdir(DIR);
-
-foreach (@traces)
-{
-    $input = $_;
-    $input =~ s/\.data$//;
-
-    $output = "$input.html";
-
-    print("dmtracedump -h -p $input > $output\n");
-    system("dmtracedump -h -p '$input' > '$output'");
-
-}
-
-closedir DIR;
diff --git a/tools/dmtracedump/dumpdir.sh b/tools/dmtracedump/dumpdir.sh
deleted file mode 100644
index 81992a2..0000000
--- a/tools/dmtracedump/dumpdir.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-FILES=`ls $1/*.data | sed "s/^\\(.*\\).data$/\\1/"`
-
-mkdir -p $2
-
-for F in $FILES
-do
-    G=$2/`echo $F | sed "s/.*\\///g"`.html
-    dmtracedump -h -p $F > $G
-done
diff --git a/tools/hprof-conv/Android.mk b/tools/hprof-conv/Android.mk
index dad399e..5f74eb4 100644
--- a/tools/hprof-conv/Android.mk
+++ b/tools/hprof-conv/Android.mk
@@ -16,6 +16,6 @@
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := HprofConv.c
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_MODULE := hprof-conv
 include $(BUILD_HOST_EXECUTABLE)