Initial Contribution
diff --git a/emulator/keymaps/Android.mk b/emulator/keymaps/Android.mk
new file mode 100644
index 0000000..90db52e
--- /dev/null
+++ b/emulator/keymaps/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := qwerty.kcm
+include $(BUILD_KEY_CHAR_MAP)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := qwerty2.kcm
+include $(BUILD_KEY_CHAR_MAP)
+
+file := $(TARGET_OUT_KEYLAYOUT)/qwerty.kl
+ALL_PREBUILT += $(file)
+$(file): $(LOCAL_PATH)/qwerty.kl | $(ACP)
+	$(transform-prebuilt-to-target)
diff --git a/emulator/keymaps/qwerty.kcm b/emulator/keymaps/qwerty.kcm
new file mode 100644
index 0000000..8056364
--- /dev/null
+++ b/emulator/keymaps/qwerty.kcm
@@ -0,0 +1,64 @@
+[type=QWERTY]                                           
+                                                        
+# keycode       display number  base    caps    fn      caps_fn
+                                                        
+A               'A'     '2'     'a'     'A'     '#'     0x00
+B               'B'     '2'     'b'     'B'     '<'     0x00
+C               'C'     '2'     'c'     'C'     '9'     0x00E7
+D               'D'     '3'     'd'     'D'     '5'     0x00
+E               'E'     '3'     'e'     'E'     '2'     0x0301
+F               'F'     '3'     'f'     'F'     '6'     0x00A5
+G               'G'     '4'     'g'     'G'     '-'     '_'
+H               'H'     '4'     'h'     'H'     '['     '{'
+I               'I'     '4'     'i'     'I'     '$'     0x0302
+J               'J'     '5'     'j'     'J'     ']'     '}'
+K               'K'     '5'     'k'     'K'     '"'     '~'
+L               'L'     '5'     'l'     'L'     '''     '`'
+M               'M'     '6'     'm'     'M'     '!'     0x00
+N               'N'     '6'     'n'     'N'     '>'     0x0303
+O               'O'     '6'     'o'     'O'     '('     0x00
+P               'P'     '7'     'p'     'P'     ')'     0x00
+Q               'Q'     '7'     'q'     'Q'     '*'     0x0300
+R               'R'     '7'     'r'     'R'     '3'     0x20AC
+S               'S'     '7'     's'     'S'     '4'     0x00DF
+T               'T'     '8'     't'     'T'     '+'     0x00A3
+U               'U'     '8'     'u'     'U'     '&'     0x0308
+V               'V'     '8'     'v'     'V'     '='     '^'
+W               'W'     '9'     'w'     'W'     '1'     0x00
+X               'X'     '9'     'x'     'X'     '8'     0xEF00
+Y               'Y'     '9'     'y'     'Y'     '%'     0x00A1
+Z               'Z'     '9'     'z'     'Z'     '7'     0x00
+                                                        
+# on pc keyboards
+COMMA           ','     ','     ','     ';'     ';'     '|'
+PERIOD          '.'     '.'     '.'     ':'     ':'     0x2026
+AT              '@'     '0'     '@'     '0'     '0'     0x2022
+SLASH           '/'     '/'     '/'     '?'     '?'     '\'
+                                                        
+SPACE           0x20    0x20    0x20    0x20    0xEF01  0xEF01
+ENTER         0xa     0xa     0xa     0xa     0xa     0xa
+                                                        
+TAB             0x9     0x9     0x9     0x9     0x9     0x9
+0               '0'     '0'     '0'     ')'     ')'     ')'
+1               '1'     '1'     '1'     '!'     '!'     '!'
+2               '2'     '2'     '2'     '@'     '@'     '@'
+3               '3'     '3'     '3'     '#'     '#'     '#'
+4               '4'     '4'     '4'     '$'     '$'     '$'
+5               '5'     '5'     '5'     '%'     '%'     '%'
+6               '6'     '6'     '6'     '^'     '^'     '^'
+7               '7'     '7'     '7'     '&'     '&'     '&'
+8               '8'     '8'     '8'     '*'     '*'     '*'
+9               '9'     '9'     '9'     '('     '('     '('
+                                                        
+GRAVE           '`'     '`'     '`'     '~'     '`'     '~'
+MINUS           '-'     '-'     '-'     '_'     '-'     '_'
+EQUALS          '='     '='     '='     '+'     '='     '+'
+LEFT_BRACKET    '['     '['     '['     '{'     '['     '{'
+RIGHT_BRACKET   ']'     ']'     ']'     '}'     ']'     '}'
+BACKSLASH       '\'     '\'     '\'     '|'     '\'     '|'
+SEMICOLON       ';'     ';'     ';'     ':'     ';'     ':'
+APOSTROPHE      '''     '''     '''     '"'     '''     '"'
+STAR            '*'     '*'     '*'     '*'     '*'     '*'
+POUND           '#'     '#'     '#'     '#'     '#'     '#'
+PLUS            '+'     '+'     '+'     '+'     '+'     '+'
+                                                        
diff --git a/emulator/keymaps/qwerty.kl b/emulator/keymaps/qwerty.kl
new file mode 100644
index 0000000..c525fdd
--- /dev/null
+++ b/emulator/keymaps/qwerty.kl
@@ -0,0 +1,89 @@
+key 399   GRAVE
+key 2     1
+key 3     2
+key 4     3
+key 5     4
+key 6     5
+key 7     6
+key 8     7
+key 9     8
+key 10    9
+key 11    0
+key 158   BACK              WAKE_DROPPED
+key 230   SOFT_RIGHT        WAKE
+key 60    SOFT_RIGHT        WAKE
+key 107   ENDCALL           WAKE_DROPPED
+key 62    ENDCALL           WAKE_DROPPED
+key 229   MENU              WAKE_DROPPED
+key 139   MENU              WAKE_DROPPED
+key 59    MENU              WAKE_DROPPED
+key 127   SEARCH            WAKE_DROPPED
+key 217   SEARCH            WAKE_DROPPED
+key 228   POUND
+key 227   STAR
+key 231   CALL              WAKE_DROPPED
+key 61    CALL              WAKE_DROPPED
+key 232   DPAD_CENTER       WAKE_DROPPED
+key 108   DPAD_DOWN         WAKE_DROPPED
+key 103   DPAD_UP           WAKE_DROPPED
+key 102   HOME              WAKE
+key 105   DPAD_LEFT         WAKE_DROPPED
+key 106   DPAD_RIGHT        WAKE_DROPPED
+key 115   VOLUME_UP
+key 114   VOLUME_DOWN
+key 116   POWER             WAKE
+key 212   CAMERA
+
+key 16    Q
+key 17    W
+key 18    E
+key 19    R
+key 20    T
+key 21    Y
+key 22    U
+key 23    I
+key 24    O
+key 25    P
+key 26    LEFT_BRACKET
+key 27    RIGHT_BRACKET
+key 43    BACKSLASH
+
+key 30    A
+key 31    S
+key 32    D
+key 33    F
+key 34    G
+key 35    H
+key 36    J
+key 37    K
+key 38    L
+key 39    SEMICOLON
+key 40    APOSTROPHE
+key 14    DEL
+        
+key 44    Z
+key 45    X
+key 46    C
+key 47    V
+key 48    B
+key 49    N
+key 50    M
+key 51    COMMA
+key 52    PERIOD
+key 53    SLASH
+key 28    ENTER
+        
+key 56    ALT_LEFT
+key 100   ALT_RIGHT
+key 42    SHIFT_LEFT
+key 54    SHIFT_RIGHT
+key 15    TAB
+key 57    SPACE
+key 150   EXPLORER
+key 155   ENVELOPE        
+
+key 12    MINUS
+key 13    EQUALS
+key 215   AT
+
+
diff --git a/emulator/keymaps/qwerty2.kcm b/emulator/keymaps/qwerty2.kcm
new file mode 100644
index 0000000..1487fb7
--- /dev/null
+++ b/emulator/keymaps/qwerty2.kcm
@@ -0,0 +1,81 @@
+[type=QWERTY]                                           
+                                                        
+# this keymap is to be used in the emulator only. note
+# that I have liberally modified certain key strokes to
+# make it more usable in this context. the main differences
+# with the reference keyboard image are:
+#
+#  - cap-2 produces '@', and not '"', without that, typing
+#    email addresses becomes a major pain with a qwerty
+#    keyboard. note that you can type '"' with fn-E anyway.
+#
+#  - cap-COMMA and cap-PERIOD return '<' and '>', instead
+#    of nothing.
+#
+#
+                                                        
+# keycode       display  number base    caps    fn      caps_fn
+                                                        
+A               'A'     '2'     'a'     'A'     'a'     'A'
+B               'B'     '2'     'b'     'B'     'b'     'B'
+C               'C'     '2'     'c'     'C'     0x00e7  0x00E7
+D               'D'     '3'     'd'     'D'     '''     '''
+E               'E'     '3'     'e'     'E'     '"'     0x0301
+F               'F'     '3'     'f'     'F'     '['     '['
+G               'G'     '4'     'g'     'G'     ']'     ']'
+H               'H'     '4'     'h'     'H'     '<'     '<'
+I               'I'     '4'     'i'     'I'     '-'     0x0302
+J               'J'     '5'     'j'     'J'     '>'     '>'
+K               'K'     '5'     'k'     'K'     ';'     '~'
+L               'L'     '5'     'l'     'L'     ':'     '`'
+M               'M'     '6'     'm'     'M'     '%'     0x00
+N               'N'     '6'     'n'     'N'     0x00    0x0303
+O               'O'     '6'     'o'     'O'     '+'     '+'
+P               'P'     '7'     'p'     'P'     '='     0x00A5
+Q               'Q'     '7'     'q'     'Q'     '|'     0x0300
+R               'R'     '7'     'r'     'R'     '`'     0x20AC
+S               'S'     '7'     's'     'S'     '\'     0x00DF
+T               'T'     '8'     't'     'T'     '{'     0x00A3
+U               'U'     '8'     'u'     'U'     '_'     0x0308
+V               'V'     '8'     'v'     'V'     'v'     'V'
+W               'W'     '9'     'w'     'W'     '~'     '~'
+X               'X'     '9'     'x'     'X'     'x'     0xEF00
+Y               'Y'     '9'     'y'     'Y'     '}'     0x00A1
+Z               'Z'     '9'     'z'     'Z'     'z'     'Z'
+                                                        
+COMMA           ','     ','     ','     '<'     ','     ','
+PERIOD          '.'     '.'     '.'     '>'     '.'     0x2026
+AT              '@'     '@'     '@'     '@'     '@'     0x2022
+SLASH           '/'     '/'     '/'     '?'     '?'     '?'
+                                                        
+SPACE           0x20    0x20    0x20    0x20    0xEF01  0xEF01
+ENTER         0xa     0xa     0xa     0xa     0xa     0xa
+                                                        
+0               '0'     '0'     '0'     ')'     ')'     ')'
+1               '1'     '1'     '1'     '!'     '!'     '!'
+2               '2'     '2'     '2'     '@'     '@'     '@'
+3               '3'     '3'     '3'     '#'     '#'     '#'
+4               '4'     '4'     '4'     '$'     '$'     '$'
+5               '5'     '5'     '5'     '%'     '%'     '%'
+6               '6'     '6'     '6'     '^'     '^'     '^'
+7               '7'     '7'     '7'     '&'     '&'     '&'
+8               '8'     '8'     '8'     '*'     '*'     '*'
+9               '9'     '9'     '9'     '('     '('     '('
+                                                        
+# the rest is for a qwerty keyboard
+#
+TAB             0x9     0x9     0x9     0x9     0x9     0x9
+GRAVE           '`'     '`'     '`'     '~'     '`'     '~'
+MINUS           '-'     '-'     '-'     '_'     '-'     '_'
+EQUALS          '='     '='     '='     '+'     '='     '+'
+LEFT_BRACKET    '['     '['     '['     '{'     '['     '{'
+RIGHT_BRACKET   ']'     ']'     ']'     '}'     ']'     '}'
+BACKSLASH       '\'     '\'     '\'     '|'     '\'     '|'
+SEMICOLON       ';'     ';'     ';'     ':'     ';'     ':'
+APOSTROPHE      '''     '''     '''     '"'     '''     '"'
+STAR            '*'     '*'     '*'     '*'     '*'     '*'
+POUND           '#'     '#'     '#'     '#'     '#'     '#'
+PLUS            '+'     '+'     '+'     '+'     '+'     '+'
+                                                        
+                                                        
+                                                        
diff --git a/emulator/mksdcard/Android.mk b/emulator/mksdcard/Android.mk
new file mode 100644
index 0000000..a5641b4
--- /dev/null
+++ b/emulator/mksdcard/Android.mk
@@ -0,0 +1,11 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+# host executable
+#
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= mksdcard.c
+LOCAL_MODULE = mksdcard
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/emulator/mksdcard/mksdcard.c b/emulator/mksdcard/mksdcard.c
new file mode 100644
index 0000000..c85d0f8
--- /dev/null
+++ b/emulator/mksdcard/mksdcard.c
@@ -0,0 +1,304 @@
+/* mksdcard.c
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of Google Inc. nor the names of its contributors may
+**       be used to endorse or promote products derived from this software
+**       without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* a simple and portable program used to generate a blank FAT32 image file
+ *
+ * usage:  mksdcard  [-l label] <size> <filename>
+ */
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* believe me, you *don't* want to change these constants !! */
+#define  BYTES_PER_SECTOR    512
+#define  RESERVED_SECTORS    32
+#define  BACKUP_BOOT_SECTOR  6
+#define  NUM_FATS            2
+
+typedef long long      Wide;   /* might be something else if you don't use GCC */
+typedef unsigned char  Byte;
+typedef Byte*          Bytes;
+
+#define  BYTE_(p,i)      (((Bytes)(p))[(i)])
+
+#define  POKEB(p,v)     BYTE_(p,0) = (Byte)(v)
+#define  POKES(p,v)   ( BYTE_(p,0) = (Byte)(v), BYTE_(p,1) = (Byte)((v) >> 8) )
+#define  POKEW(p,v)   ( BYTE_(p,0) = (Byte)(v), BYTE_(p,1) = (Byte)((v) >> 8), BYTE_(p,2) = (Byte)((v) >> 16), BYTE_(p,3) = (Byte)((v) >> 24) )
+
+static Byte  s_boot_sector   [ BYTES_PER_SECTOR ];       /* boot sector */
+static Byte  s_fsinfo_sector [ BYTES_PER_SECTOR ];   /* FS Info sector */
+static Byte  s_fat_head      [ BYTES_PER_SECTOR ];        /* first FAT sector */
+static Byte  s_zero_sector   [ BYTES_PER_SECTOR ];     /* empty sector */
+
+/* this is the date and time when creating the disk */
+static int
+get_serial_id( void )
+{
+    unsigned short  lo, hi, mid;
+    time_t          now = time(NULL);
+    struct tm       tm  = gmtime( &now )[0];
+
+    lo  = (unsigned short)(tm.tm_mday + ((tm.tm_mon+1) << 8) + (tm.tm_sec << 8));
+    hi  = (unsigned short)(tm.tm_min + (tm.tm_hour << 8) + (tm.tm_year + 1900));
+
+    return lo + (hi << 16);
+}
+
+static int
+get_sectors_per_cluster( Wide  disk_size )
+{
+    Wide  disk_MB = disk_size/(1024*1024);
+
+    if (disk_MB < 260)
+        return 1;
+
+    if (disk_MB < 8192)
+        return 4;
+
+    if (disk_MB < 16384)
+        return 8;
+
+    if (disk_MB < 32768)
+        return 16;
+
+    return 32;
+}
+
+static int
+get_sectors_per_fat( Wide  disk_size, int  sectors_per_cluster )
+{
+    Wide   divider;
+
+    /* weird computation from MS - see fatgen103.doc for details */
+    disk_size -= RESERVED_SECTORS * BYTES_PER_SECTOR;  /* don't count 32 reserved sectors */
+    disk_size /= BYTES_PER_SECTOR;       /* disk size in sectors */
+    divider = ((256 * sectors_per_cluster) + NUM_FATS) / 2;
+
+    return (int)( (disk_size + (divider-1)) / divider );
+}
+
+static void
+boot_sector_init( Bytes  boot, Bytes  info, Wide   disk_size, const char*  label )
+{
+    int   sectors_per_cluster = get_sectors_per_cluster(disk_size);
+    int   sectors_per_fat    = get_sectors_per_fat(disk_size, sectors_per_cluster);
+    int   sectors_per_disk   = (int)(disk_size / BYTES_PER_SECTOR);
+    int   serial_id          = get_serial_id();
+    int   free_count;
+
+    if (label == NULL)
+        label = "SDCARD";
+
+    POKEB(boot, 0xeb);
+    POKEB(boot+1, 0x5a);
+    POKEB(boot+2, 0x90);
+    strcpy( (char*)boot + 3, "MSWIN4.1" );
+    POKES( boot + 0x0b, BYTES_PER_SECTOR );    /* sector size */
+    POKEB( boot + 0xd, sectors_per_cluster );  /* sectors per cluster */
+    POKES( boot + 0xe, RESERVED_SECTORS );     /* reserved sectors before first FAT */
+    POKEB( boot + 0x10, NUM_FATS );            /* number of FATs */
+    POKES( boot + 0x11, 0 );                   /* max root directory entries for FAT12/FAT16, 0 for FAT32 */
+    POKES( boot + 0x13, 0 );                   /* total sectors, 0 to use 32-bit value at offset 0x20 */
+    POKEB( boot + 0x15, 0xF8 );                /* media descriptor, 0xF8 == hard disk */
+    POKES( boot + 0x16, 0 );                   /* Sectors per FAT for FAT12/16, 0 for FAT32 */
+    POKES( boot + 0x18, 9 );                   /* Sectors per track (whatever) */
+    POKES( boot + 0x1a, 2 );                   /* Number of heads (whatever) */
+    POKEW( boot + 0x1c, 0 );                   /* Hidden sectors */
+    POKEW( boot + 0x20, sectors_per_disk );    /* Total sectors */
+
+    /* extension */
+    POKEW( boot + 0x24, sectors_per_fat );       /* Sectors per FAT */
+    POKES( boot + 0x28, 0 );         /* FAT flags */
+    POKES( boot + 0x2a, 0 );         /* version */
+    POKEW( boot + 0x2c, 2 );         /* cluster number of root directory start */
+    POKES( boot + 0x30, 1 );         /* sector number of FS information sector */
+    POKES( boot + 0x32, BACKUP_BOOT_SECTOR );         /* sector number of a copy of this boot sector */
+    POKEB( boot + 0x40, 0x80 );      /* physical drive number */
+    POKEB( boot + 0x42, 0x29 );      /* extended boot signature ?? */
+    POKEW( boot + 0x43, serial_id ); /* serial ID */
+    strncpy( (char*)boot + 0x47, label, 11 );  /* Volume Label */
+    memcpy( boot + 0x52, "FAT32   ", 8 );  /* FAT system type, padded with 0x20 */
+
+    POKEB( boot + BYTES_PER_SECTOR-2, 0x55 );    /* boot sector signature */
+    POKEB( boot + BYTES_PER_SECTOR-1, 0xAA );
+
+    /* FSInfo sector */
+    free_count = sectors_per_disk - 32 - 2*sectors_per_fat;
+
+    POKEW( info + 0,   0x41615252 );
+    POKEW( info + 484, 0x61417272 );
+    POKEW( info + 488, free_count );   /* number of free clusters */
+    POKEW( info + 492, 3 );            /* next free clusters, 0-1 reserved, 2 is used for the root dir */
+    POKEW( info + 508, 0xAA550000 );
+}
+
+static void
+fat_init( Bytes  fat )
+{
+    POKEW( fat,     0x0ffffff8 );  /* reserve cluster 1, media id in low byte */
+    POKEW( fat + 4, 0x0fffffff );  /* reserve cluster 2 */
+    POKEW( fat + 8, 0x0fffffff );  /* end of clust chain for root dir */
+}
+
+
+static int
+write_sector( FILE*  file, Bytes  sector )
+{
+    return fwrite( sector, 1, 512, file ) != 512;
+}
+
+static int
+write_empty( FILE*   file, Wide  count )
+{
+    static  Byte  empty[64*1024];
+
+    count *= 512;
+    while (count > 0) {
+        int  len = sizeof(empty);
+        if (len > count)
+            len = count;
+
+        if ( fwrite( empty, 1, len, file ) != (size_t)len )
+            return 1;
+
+        count -= len;
+    }
+    return 0;
+}
+
+static void usage (void)
+{
+    fprintf(stderr, "mksdcard: create a blank FAT32 image to be used with the Android emulator\n" );
+    fprintf(stderr, "usage: mksdcard [-l label] <size> <file>\n\n");
+    fprintf(stderr, "  if <size> is a simple integer, it specifies a size in bytes\n" );
+    fprintf(stderr, "  if <size> is an integer followed by 'K', it specifies a size in KiB\n" );
+    fprintf(stderr, "  if <size> is an integer followed by 'M', it specifies a size in MiB\n" );
+    exit(1);
+}
+
+int  main( int argc, char**  argv )
+{
+    Wide   disk_size;
+    int    sectors_per_fat;
+    int    sectors_per_disk;
+    char*  end;
+    const char*  label = NULL;
+    FILE*  f;
+
+    for ( ; argc > 1 && argv[1][0] == '-'; argc--, argv++ )
+    {
+        char*  arg = argv[1] + 1;
+        switch (arg[0]) {
+            case 'l':
+                if (arg[1] != 0)
+                    arg += 2;
+                else {
+                    argc--;
+                    argv++;
+                    if (argc <= 1)
+                        usage();
+                    arg = argv[1];
+                }
+                label = arg;
+                break;
+
+            default:
+                usage();
+        }
+    }
+
+    if (argc != 3)
+        usage();
+
+    disk_size = strtol( argv[1], &end, 10 );
+    if (disk_size == 0 && errno == EINVAL)
+        usage();
+
+    if (*end == 'K')
+        disk_size *= 1024;
+    else if (*end == 'M')
+        disk_size *= 1024*1024;
+
+    if (disk_size < 8*1024*1024)
+        fprintf(stderr, "### WARNING : SD Card images < 8 MB cannot be used with the Android emulator\n");
+
+    sectors_per_disk = disk_size / 512;
+    sectors_per_fat  = get_sectors_per_fat( disk_size, get_sectors_per_cluster( disk_size ) );
+
+    boot_sector_init( s_boot_sector, s_fsinfo_sector, disk_size, NULL );
+    fat_init( s_fat_head );
+
+    f = fopen( argv[2], "wb" );
+    if ( !f ) {
+        fprintf(stderr, "could not create file '%s', aborting...\n", argv[2] );
+    }
+
+   /* here's the layout:
+    *
+    *  boot_sector
+    *  fsinfo_sector
+    *  empty
+    *  backup boot sector
+    *  backup fsinfo sector
+    *  RESERVED_SECTORS - 4 empty sectors (if backup sectors), or RESERVED_SECTORS - 2 (if no backup)
+    *  first fat
+    *  second fat
+    *  zero sectors
+   */
+
+    if ( write_sector( f, s_boot_sector ) )  goto FailWrite;
+    if ( write_sector( f, s_fsinfo_sector ) ) goto FailWrite;
+    if ( BACKUP_BOOT_SECTOR > 0 ) {
+        if ( write_empty( f, BACKUP_BOOT_SECTOR - 2 ) ) goto FailWrite;
+        if ( write_sector( f, s_boot_sector ) ) goto FailWrite;
+        if ( write_sector( f, s_fsinfo_sector ) ) goto FailWrite;
+        if ( write_empty( f, RESERVED_SECTORS - 2 - BACKUP_BOOT_SECTOR ) ) goto FailWrite;
+    }
+    else
+        if ( write_empty( f, RESERVED_SECTORS - 2 ) ) goto FailWrite;
+
+    if ( write_sector( f, s_fat_head ) ) goto FailWrite;
+    if ( write_empty( f, sectors_per_fat-1 ) ) goto FailWrite;
+
+    if ( write_sector( f, s_fat_head ) ) goto FailWrite;
+    if ( write_empty( f, sectors_per_fat-1 ) ) goto FailWrite;
+
+    if ( write_empty( f, sectors_per_disk - RESERVED_SECTORS - 2*sectors_per_fat ) ) goto FailWrite;
+
+    fclose(f);
+    return 0;
+
+FailWrite:
+    fprintf(stderr, "could not write to '%s', aborting...\n", argv[2] );
+    unlink( argv[2] );
+    fclose(f);
+    return 1;
+}
diff --git a/emulator/mksdcard/vfat-empty-32MB.img.gz b/emulator/mksdcard/vfat-empty-32MB.img.gz
new file mode 100644
index 0000000..b205da3
--- /dev/null
+++ b/emulator/mksdcard/vfat-empty-32MB.img.gz
Binary files differ
diff --git a/emulator/qemud/Android.mk b/emulator/qemud/Android.mk
new file mode 100644
index 0000000..454f32d
--- /dev/null
+++ b/emulator/qemud/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2008 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	qemud.c
+
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+
+LOCAL_MODULE:= qemud
+
+include $(BUILD_EXECUTABLE)
diff --git a/emulator/qemud/qemud.c b/emulator/qemud/qemud.c
new file mode 100644
index 0000000..47d4d5f
--- /dev/null
+++ b/emulator/qemud/qemud.c
@@ -0,0 +1,1328 @@
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <termios.h>
+#include <cutils/sockets.h>
+
+/*
+ *  the qemud program is only used within the Android emulator as a bridge
+ *  between the emulator program and the emulated system. it really works as
+ *  a simple stream multiplexer that works as follows:
+ *
+ *    - qemud communicates with the emulator program through a single serial
+ *      port, whose name is passed through a kernel boot parameter
+ *      (e.g. android.qemud=ttyS1)
+ *
+ *    - qemud setups one or more unix local stream sockets in the
+ *      emulated system each one of these represent a different communication
+ *      'channel' between the emulator program and the emulated system.
+ *
+ *      as an example, one channel is used for the emulated GSM modem
+ *      (AT command channel), another channel is used for the emulated GPS,
+ *      etc...
+ *
+ *    - the protocol used on the serial connection is pretty simple:
+ *
+ *          offset    size    description
+ *              0       4     4-char hex string giving the payload size
+ *              4       2     2-char hex string giving the destination or
+ *                            source channel
+ *              6       n     the message payload
+ *
+ *      for emulator->system messages, the 'channel' index indicates
+ *      to which channel the payload must be sent
+ *
+ *      for system->emulator messages, the 'channel' index indicates from
+ *      which channel the payload comes from.
+ *
+ *   - a special channel index (0) is used to communicate with the qemud
+ *     program directly from the emulator. this is used for the following
+ *     commands:  (content of the payload):
+ *
+ *        request:  connect:<name>
+ *        answer:   ok:connect:<name>:XX       // succesful name lookup
+ *        answer:   ko:connect:bad name        // failed lookup
+ *
+ *           the emulator queries the index of a given channel given
+ *           its human-readable name. the answer contains a 2-char hex
+ *           string for the channel index.
+ *
+ *           not all emulated systems may need the same communication
+ *           channels, so this function may fail.
+ *
+ *     any invalid request will get an answer of:
+ *
+ *           ko:unknown command
+ *
+ *
+ *  here's a diagram of how things work:
+ *
+ *
+ *                                                  _________
+ *                        _____________   creates  |         |
+ *         ________      |             |==========>| Channel |--*--
+ *        |        |---->| Multiplexer |           |_________|
+ *   --*--| Serial |     |_____________|               || creates
+ *        |________|            |                 _____v___
+ *             A                +--------------->|         |
+ *             |                                 | Client  |--*--
+ *             +---------------------------------|_________|
+ *
+ *  which really means that:
+ *
+ *    - the multiplexer creates one Channel object per control socket qemud
+ *      handles (e.g. /dev/socket/qemud_gsm, /dev/socket/qemud_gps)
+ *
+ *    - each Channel object has a numerical index that is >= 1, and waits
+ *      for client connection. it will create a Client object when this
+ *      happens
+ *
+ *    - the Serial object receives packets from the serial port and sends them
+ *      to the multiplexer
+ *
+ *    - the multiplexer tries to find a channel the packet is addressed to,
+ *      and will send the packet to all clients that correspond to it
+ *
+ *    - when a Client receives data, it sends it directly to the Serial object
+ *
+ *    - there are two kinds of Channel objects:
+ *
+ *         CHANNEL_BROADCAST :: used for emulator -> clients broadcasts only
+ *
+ *         CHANNEL_DUPLEX    :: used for bidirectional communication with the
+ *                              emulator, with only *one* client allowed per
+ *                              duplex channel
+ */
+
+#define  DEBUG  0
+
+#if DEBUG
+#  define LOG_TAG  "qemud"
+#  include <cutils/log.h>
+#  define  D(...)   LOGD(__VA_ARGS__)
+#else
+#  define  D(...)  ((void)0)
+#endif
+
+/** UTILITIES
+ **/
+
+static void
+fatal( const char*  fmt, ... )
+{
+    va_list  args;
+    va_start(args, fmt);
+    fprintf(stderr, "PANIC: ");
+    vfprintf(stderr, fmt, args);
+    fprintf(stderr, "\n" );
+    va_end(args);
+    exit(1);
+}
+
+static void*
+xalloc( size_t   sz )
+{
+    void*  p;
+
+    if (sz == 0)
+        return NULL;
+
+    p = malloc(sz);
+    if (p == NULL)
+        fatal( "not enough memory" );
+
+    return p;
+}
+
+#define  xnew(p)   (p) = xalloc(sizeof(*(p)))
+
+static void*
+xalloc0( size_t  sz )
+{
+    void*  p = xalloc(sz);
+    memset( p, 0, sz );
+    return p;
+}
+
+#define  xnew0(p)   (p) = xalloc0(sizeof(*(p)))
+
+#define  xfree(p)    ({  free((p)), (p) = NULL; })
+
+static void*
+xrealloc( void*  block, size_t  size )
+{
+    void*  p = realloc( block, size );
+
+    if (p == NULL && size > 0)
+        fatal( "not enough memory" );
+
+    return p;
+}
+
+#define  xrenew(p,count)  (p) = xrealloc((p),sizeof(*(p))*(count))
+
+static int
+hex2int( const uint8_t*  data, int  len )
+{
+    int  result = 0;
+    while (len > 0) {
+        int       c = *data++;
+        unsigned  d;
+
+        result <<= 4;
+        do {
+            d = (unsigned)(c - '0');
+            if (d < 10)
+                break;
+
+            d = (unsigned)(c - 'a');
+            if (d < 6) {
+                d += 10;
+                break;
+            }
+
+            d = (unsigned)(c - 'A');
+            if (d < 6) {
+                d += 10;
+                break;
+            }
+
+            return -1;
+        }
+        while (0);
+
+        result |= d;
+        len    -= 1;
+    }
+    return  result;
+}
+
+
+static void
+int2hex( int  value, uint8_t*  to, int  width )
+{
+    int  nn = 0;
+    static const char hexchars[16] = "0123456789abcdef";
+
+    for ( --width; width >= 0; width--, nn++ ) {
+        to[nn] = hexchars[(value >> (width*4)) & 15];
+    }
+}
+
+static int
+fd_read(int  fd, void*  to, int  len)
+{
+    int  ret;
+
+    do {
+        ret = read(fd, to, len);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+static int
+fd_write(int  fd, const void*  from, int  len)
+{
+    int  ret;
+
+    do {
+        ret = write(fd, from, len);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+static void
+fd_setnonblock(int  fd)
+{
+    int  ret, flags;
+
+    do {
+        flags = fcntl(fd, F_GETFD);
+    } while (flags < 0 && errno == EINTR);
+
+    if (flags < 0) {
+        fatal( "%s: could not get flags for fd %d: %s",
+               __FUNCTION__, fd, strerror(errno) );
+    }
+
+    do {
+        ret = fcntl(fd, F_SETFD, flags | O_NONBLOCK);
+    } while (ret < 0 && errno == EINTR);
+
+    if (ret < 0) {
+        fatal( "%s: could not set fd %d to non-blocking: %s",
+               __FUNCTION__, fd, strerror(errno) );
+    }
+}
+
+/** FD EVENT LOOP
+ **/
+
+#include <sys/epoll.h>
+
+#define  MAX_CHANNELS  16
+#define  MAX_EVENTS    (MAX_CHANNELS+1)  /* each channel + the serial fd */
+
+typedef void (*EventFunc)( void*  user, int  events );
+
+enum {
+    HOOK_PENDING = (1 << 0),
+    HOOK_CLOSING = (1 << 1),
+};
+
+typedef struct {
+    int        fd;
+    int        wanted;
+    int        events;
+    int        state;
+    void*      ev_user;
+    EventFunc  ev_func;
+} LoopHook;
+
+typedef struct {
+    int                  epoll_fd;
+    int                  num_fds;
+    int                  max_fds;
+    struct epoll_event*  events;
+    LoopHook*            hooks;
+} Looper;
+
+static void
+looper_init( Looper*  l )
+{
+    l->epoll_fd = epoll_create(4);
+    l->num_fds  = 0;
+    l->max_fds  = 0;
+    l->events   = NULL;
+    l->hooks    = NULL;
+}
+
+static void
+looper_done( Looper*  l )
+{
+    xfree(l->events);
+    xfree(l->hooks);
+    l->max_fds = 0;
+    l->num_fds = 0;
+
+    close(l->epoll_fd);
+    l->epoll_fd  = -1;
+}
+
+static LoopHook*
+looper_find( Looper*  l, int  fd )
+{
+    LoopHook*  hook = l->hooks;
+    LoopHook*  end  = hook + l->num_fds;
+
+    for ( ; hook < end; hook++ ) {
+        if (hook->fd == fd)
+            return hook;
+    }
+    return NULL;
+}
+
+static void
+looper_grow( Looper*  l )
+{
+    int  old_max = l->max_fds;
+    int  new_max = old_max + (old_max >> 1) + 4;
+    int  n;
+
+    xrenew( l->events, new_max );
+    xrenew( l->hooks,  new_max );
+    l->max_fds = new_max;
+
+    /* now change the handles to all events */
+    for (n = 0; n < l->num_fds; n++) {
+        struct epoll_event ev;
+        LoopHook*          hook = l->hooks + n;
+
+        ev.events   = hook->wanted;
+        ev.data.ptr = hook;
+        epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, hook->fd, &ev );
+    }
+}
+
+static void
+looper_add( Looper*  l, int  fd, EventFunc  func, void*  user )
+{
+    struct epoll_event  ev;
+    LoopHook*           hook;
+
+    if (l->num_fds >= l->max_fds)
+        looper_grow(l);
+
+    hook = l->hooks + l->num_fds;
+
+    hook->fd      = fd;
+    hook->ev_user = user;
+    hook->ev_func = func;
+    hook->state   = 0;
+    hook->wanted  = 0;
+    hook->events  = 0;
+
+    fd_setnonblock(fd);
+
+    ev.events   = 0;
+    ev.data.ptr = hook;
+    epoll_ctl( l->epoll_fd, EPOLL_CTL_ADD, fd, &ev );
+
+    l->num_fds += 1;
+}
+
+static void
+looper_del( Looper*  l, int  fd )
+{
+    LoopHook*  hook = looper_find( l, fd );
+
+    if (!hook) {
+        D( "%s: invalid fd: %d", __FUNCTION__, fd );
+        return;
+    }
+    /* don't remove the hook yet */
+    hook->state |= HOOK_CLOSING;
+
+    epoll_ctl( l->epoll_fd, EPOLL_CTL_DEL, fd, NULL );
+}
+
+static void
+looper_enable( Looper*  l, int  fd, int  events )
+{
+    LoopHook*  hook = looper_find( l, fd );
+
+    if (!hook) {
+        D("%s: invalid fd: %d", __FUNCTION__, fd );
+        return;
+    }
+
+    if (events & ~hook->wanted) {
+        struct epoll_event  ev;
+
+        hook->wanted |= events;
+        ev.events   = hook->wanted;
+        ev.data.ptr = hook;
+
+        epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, fd, &ev );
+    }
+}
+
+static void
+looper_disable( Looper*  l, int  fd, int  events )
+{
+    LoopHook*  hook = looper_find( l, fd );
+
+    if (!hook) {
+        D("%s: invalid fd: %d", __FUNCTION__, fd );
+        return;
+    }
+
+    if (events & hook->wanted) {
+        struct epoll_event  ev;
+
+        hook->wanted &= ~events;
+        ev.events   = hook->wanted;
+        ev.data.ptr = hook;
+
+        epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, fd, &ev );
+    }
+}
+
+static void
+looper_loop( Looper*  l )
+{
+    for (;;) {
+        int  n, count;
+
+        do {
+            count = epoll_wait( l->epoll_fd, l->events, l->num_fds, -1 );
+        } while (count < 0 && errno == EINTR);
+
+        if (count < 0) {
+            D("%s: error: %s", __FUNCTION__, strerror(errno) );
+            return;
+        }
+
+        /* mark all pending hooks */
+        for (n = 0; n < count; n++) {
+            LoopHook*  hook = l->events[n].data.ptr;
+            hook->state  = HOOK_PENDING;
+            hook->events = l->events[n].events;
+        }
+
+        /* execute hook callbacks. this may change the 'hooks'
+         * and 'events' array, as well as l->num_fds, so be careful */
+        for (n = 0; n < l->num_fds; n++) {
+            LoopHook*  hook = l->hooks + n;
+            if (hook->state & HOOK_PENDING) {
+                hook->state &= ~HOOK_PENDING;
+                hook->ev_func( hook->ev_user, hook->events );
+            }
+        }
+
+        /* now remove all the hooks that were closed by
+         * the callbacks */
+        for (n = 0; n < l->num_fds;) {
+            LoopHook*  hook = l->hooks + n;
+
+            if (!(hook->state & HOOK_CLOSING)) {
+                n++;
+                continue;
+            }
+
+            hook[0]     = l->hooks[l->num_fds-1];
+            l->num_fds -= 1;
+        }
+    }
+}
+
+/** PACKETS
+ **/
+
+typedef struct Packet   Packet;
+
+/* we want to ensure that Packet is no more than a single page */
+#define  MAX_PAYLOAD  (4096-16-6)
+
+struct Packet {
+    Packet*   next;
+    int       len;
+    int       channel;
+    uint8_t   data[ MAX_PAYLOAD ];
+};
+
+static Packet*   _free_packets;
+
+static Packet*
+packet_alloc(void)
+{
+    Packet*  p = _free_packets;
+    if (p != NULL) {
+        _free_packets = p->next;
+    } else {
+        xnew(p);
+    }
+    p->next = NULL;
+    p->len  = 0;
+    p->channel = -1;
+    return p;
+}
+
+static void
+packet_free( Packet*  *ppacket )
+{
+    Packet*  p = *ppacket;
+    if (p) {
+        p->next       = _free_packets;
+        _free_packets = p;
+        *ppacket = NULL;
+    }
+}
+
+static Packet*
+packet_dup( Packet*  p )
+{
+    Packet*  p2 = packet_alloc();
+
+    p2->len     = p->len;
+    p2->channel = p->channel;
+    memcpy(p2->data, p->data, p->len);
+    return p2;
+}
+
+/** PACKET RECEIVER
+ **/
+
+typedef void (*PostFunc) ( void*  user, Packet*  p );
+typedef void (*CloseFunc)( void*  user );
+
+typedef struct {
+    PostFunc   post;
+    CloseFunc  close;
+    void*      user;
+} Receiver;
+
+static __inline__ void
+receiver_post( Receiver*  r, Packet*  p )
+{
+    r->post( r->user, p );
+}
+
+static __inline__ void
+receiver_close( Receiver*  r )
+{
+    r->close( r->user );
+}
+
+
+/** FD HANDLERS
+ **
+ ** these are smart listeners that send incoming packets to a receiver
+ ** and can queue one or more outgoing packets and send them when possible
+ **/
+
+typedef struct FDHandler {
+    int          fd;
+    Looper*      looper;
+    Receiver     receiver[1];
+    int          out_pos;
+    Packet*      out_first;
+    Packet**     out_ptail;
+
+} FDHandler;
+
+
+static void
+fdhandler_done( FDHandler*  f )
+{
+    /* get rid of unsent packets */
+    if (f->out_first) {
+        Packet*  p;
+        while ((p = f->out_first) != NULL) {
+            f->out_first = p->next;
+            packet_free(&p);
+        }
+    }
+
+    /* get rid of file descriptor */
+    if (f->fd >= 0) {
+        looper_del( f->looper, f->fd );
+        close(f->fd);
+        f->fd = -1;
+    }
+    f->looper = NULL;
+}
+
+
+static void
+fdhandler_enqueue( FDHandler*  f, Packet*  p )
+{
+    Packet*  first = f->out_first;
+
+    p->next         = NULL;
+    f->out_ptail[0] = p;
+    f->out_ptail    = &p->next;
+
+    if (first == NULL) {
+        f->out_pos = 0;
+        looper_enable( f->looper, f->fd, EPOLLOUT );
+    }
+}
+
+
+static void
+fdhandler_event( FDHandler*  f, int  events )
+{
+   int  len;
+
+    if (events & (EPOLLHUP|EPOLLERR)) {
+        /* disconnection */
+        D("%s: disconnect on fd %d", __FUNCTION__, f->fd);
+        receiver_close( f->receiver );
+        return;
+    }
+
+    if (events & EPOLLIN) {
+        Packet*  p = packet_alloc();
+        int      len;
+
+        if ((len = fd_read(f->fd, p->data, MAX_PAYLOAD)) < 0) {
+            D("%s: can't recv: %s", __FUNCTION__, strerror(errno));
+            packet_free(&p);
+        } else {
+            p->len     = len;
+            p->channel = -101;  /* special debug value */
+            receiver_post( f->receiver, p );
+        }
+    }
+
+    if (events & EPOLLOUT && f->out_first) {
+        Packet*  p = f->out_first;
+        int      avail, len;
+
+        avail = p->len - f->out_pos;
+        if ((len = fd_write(f->fd, p->data + f->out_pos, avail)) < 0) {
+            D("%s: can't send: %s", __FUNCTION__, strerror(errno));
+        } else {
+            f->out_pos += len;
+            if (f->out_pos >= p->len) {
+                f->out_pos   = 0;
+                f->out_first = p->next;
+                packet_free(&p);
+                if (f->out_first == NULL) {
+                    f->out_ptail = &f->out_first;
+                    looper_disable( f->looper, f->fd, EPOLLOUT );
+                }
+            }
+        }
+    }
+}
+
+
+static void
+fdhandler_init( FDHandler*      f,
+                int             fd,
+                Looper*         looper,
+                Receiver*       receiver )
+{
+    f->fd          = fd;
+    f->looper      = looper;
+    f->receiver[0] = receiver[0];
+    f->out_first   = NULL;
+    f->out_ptail   = &f->out_first;
+    f->out_pos     = 0;
+
+    looper_add( looper, fd, (EventFunc) fdhandler_event, f );
+    looper_enable( looper, fd, EPOLLIN );
+}
+
+
+static void
+fdhandler_accept_event( FDHandler*  f, int  events )
+{
+    if (events & (EPOLLHUP|EPOLLERR)) {
+        /* disconnecting !! */
+        D("%s: closing fd %d", __FUNCTION__, f->fd);
+        receiver_close( f->receiver );
+        return;
+    }
+
+    if (events & EPOLLIN) {
+        /* this is an accept - send a dummy packet to the receiver */
+        Packet*  p = packet_alloc();
+
+        D("%s: accepting on fd %d", __FUNCTION__, f->fd);
+        p->data[0] = 1;
+        p->len     = 1;
+        receiver_post( f->receiver, p );
+    }
+}
+
+
+static void
+fdhandler_init_accept( FDHandler*  f,
+                       int         fd,
+                       Looper*     looper,
+                       Receiver*   receiver )
+{
+    f->fd          = fd;
+    f->looper      = looper;
+    f->receiver[0] = receiver[0];
+
+    looper_add( looper, fd, (EventFunc) fdhandler_accept_event, f );
+    looper_enable( looper, fd, EPOLLIN );
+}
+
+/** CLIENTS
+ **/
+
+typedef struct Client {
+    struct Client*   next;
+    struct Client**  pref;
+    int              channel;
+    FDHandler        fdhandler[1];
+    Receiver         receiver[1];
+} Client;
+
+static Client*   _free_clients;
+
+static void
+client_free( Client*  c )
+{
+    c->pref[0] = c->next;
+    c->next    = NULL;
+    c->pref    = &c->next;
+
+    fdhandler_done( c->fdhandler );
+    free(c);
+}
+
+static void
+client_receive( Client*  c, Packet*  p )
+{
+    p->channel = c->channel;
+    receiver_post( c->receiver, p );
+}
+
+static void
+client_send( Client*  c, Packet*  p )
+{
+    fdhandler_enqueue( c->fdhandler, p );
+}
+
+static void
+client_close( Client*  c )
+{
+    D("disconnecting client on fd %d", c->fdhandler->fd);
+    client_free(c);
+}
+
+static Client*
+client_new( int         fd,
+            int         channel,
+            Looper*     looper,
+            Receiver*   receiver )
+{
+    Client*   c;
+    Receiver  recv;
+
+    xnew(c);
+
+    c->next = NULL;
+    c->pref = &c->next;
+    c->channel = channel;
+    c->receiver[0] = receiver[0];
+
+    recv.user  = c;
+    recv.post  = (PostFunc)  client_receive;
+    recv.close = (CloseFunc) client_close;
+
+    fdhandler_init( c->fdhandler, fd, looper, &recv );
+    return c;
+}
+
+static void
+client_link( Client*  c, Client**  plist )
+{
+    c->next  = plist[0];
+    c->pref  = plist;
+    plist[0] = c;
+}
+
+
+/** CHANNELS
+ **/
+
+typedef enum {
+    CHANNEL_BROADCAST = 0,
+    CHANNEL_DUPLEX,
+
+    CHANNEL_MAX  /* do not remove */
+
+} ChannelType;
+
+#define  CHANNEL_CONTROL   0
+
+typedef struct Channel {
+    struct Channel*     next;
+    struct Channel**    pref;
+    FDHandler           fdhandler[1];
+    ChannelType         ctype;
+    const char*         name;
+    int                 index;
+    Receiver            receiver[1];
+    Client*             clients;
+} Channel;
+
+static void
+channel_free( Channel*  c )
+{
+    while (c->clients)
+        client_free(c->clients);
+
+    c->pref[0] = c->next;
+    c->pref    = &c->next;
+    c->next    = NULL;
+
+    fdhandler_done( c->fdhandler );
+    free(c);
+}
+
+static void
+channel_close( Channel*  c )
+{
+    D("closing channel '%s' on fd %d", c->name, c->fdhandler->fd);
+    channel_free(c);
+}
+
+
+static void
+channel_accept( Channel*  c, Packet*  p )
+{
+    int   fd;
+    struct sockaddr  from;
+    socklen_t        fromlen = sizeof(from);
+
+    /* get rid of dummy packet (see fdhandler_event_accept) */
+    packet_free(&p);
+
+    do {
+        fd = accept( c->fdhandler->fd, &from, &fromlen );
+    } while (fd < 0 && errno == EINTR);
+
+    if (fd >= 0) {
+        Client*  client;
+
+        /* DUPLEX channels can only have one client at a time */
+        if (c->ctype == CHANNEL_DUPLEX && c->clients != NULL) {
+            D("refusing client connection on duplex channel '%s'", c->name);
+            close(fd);
+            return;
+        }
+        client = client_new( fd, c->index, c->fdhandler->looper, c->receiver );
+        client_link( client, &c->clients );
+        D("new client for channel '%s' on fd %d", c->name, fd);
+    }
+    else
+        D("could not accept connection: %s", strerror(errno));
+}
+
+
+static Channel*
+channel_new( int          fd,
+             ChannelType  ctype,
+             const char*  name,
+             int          index,
+             Looper*      looper,
+             Receiver*    receiver )
+{
+    Channel*  c;
+    Receiver  recv;
+
+    xnew(c);
+
+    c->next  = NULL;
+    c->pref  = &c->next;
+    c->ctype = ctype;
+    c->name  = name;
+    c->index = index;
+
+    /* saved for future clients */
+    c->receiver[0] = receiver[0];
+
+    recv.user  = c;
+    recv.post  = (PostFunc)  channel_accept;
+    recv.close = (CloseFunc) channel_close;
+
+    fdhandler_init_accept( c->fdhandler, fd, looper, &recv );
+    listen( fd, 5 );
+
+    return c;
+}
+
+static void
+channel_link( Channel*  c, Channel** plist )
+{
+    c->next  = plist[0];
+    c->pref  = plist;
+    plist[0] = c;
+}
+
+static void
+channel_send( Channel*  c, Packet*  p )
+{
+    Client*  client = c->clients;
+    for ( ; client; client = client->next ) {
+        Packet*  q = packet_dup(p);
+        client_send( client, q );
+    }
+    packet_free( &p );
+}
+
+
+/* each packet is made of a 6 byte header followed by a payload
+ * the header looks like:
+ *
+ *   offset   size    description
+ *       0       4    a 4-char hex string for the size of the payload
+ *       4       2    a 2-byte hex string for the channel number
+ *       6       n    the payload itself
+ */
+#define  HEADER_SIZE    6
+#define  LENGTH_OFFSET  0
+#define  LENGTH_SIZE    4
+#define  CHANNEL_OFFSET 4
+#define  CHANNEL_SIZE   2
+
+#define  CHANNEL_INDEX_NONE     0
+#define  CHANNEL_INDEX_CONTROL  1
+
+#define  TOSTRING(x)   _TOSTRING(x)
+#define  _TOSTRING(x)  #x
+
+/** SERIAL HANDLER
+ **/
+
+typedef struct Serial {
+    FDHandler   fdhandler[1];
+    Receiver    receiver[1];
+    int         in_len;
+    int         in_datalen;
+    int         in_channel;
+    Packet*     in_packet;
+} Serial;
+
+static void
+serial_done( Serial*  s )
+{
+    packet_free(&s->in_packet);
+    s->in_len     = 0;
+    s->in_datalen = 0;
+    s->in_channel = 0;
+    fdhandler_done(s->fdhandler);
+}
+
+static void
+serial_close( Serial*  s )
+{
+    fatal("unexpected serial port close !!");
+}
+
+/* receive packets from the serial port */
+static void
+serial_receive( Serial*  s, Packet*  p )
+{
+    int      rpos  = 0, rcount = p->len;
+    Packet*  inp   = s->in_packet;
+    int      inpos = s->in_len;
+
+    //D("received from serial: %d bytes: '%.*s'", p->len, p->len, p->data);
+
+    while (rpos < rcount)
+    {
+        int  avail = rcount - rpos;
+
+        /* first, try to read the header */
+        if (s->in_datalen == 0) {
+            int  wanted = HEADER_SIZE - inpos;
+            if (avail > wanted)
+                avail = wanted;
+
+            memcpy( inp->data + inpos, p->data + rpos, avail );
+            inpos += avail;
+            rpos  += avail;
+
+            if (inpos == HEADER_SIZE) {
+                s->in_datalen = hex2int( inp->data + LENGTH_OFFSET,  LENGTH_SIZE );
+                s->in_channel = hex2int( inp->data + CHANNEL_OFFSET, CHANNEL_SIZE );
+
+                if (s->in_datalen <= 0)
+                    D("ignoring empty packet from serial port");
+
+                //D("received %d bytes packet for channel %d", s->in_datalen, s->in_channel);
+                inpos = 0;
+            }
+        }
+        else /* then, populate the packet itself */
+        {
+            int   wanted = s->in_datalen - inpos;
+
+            if (avail > wanted)
+                avail = wanted;
+
+            memcpy( inp->data + inpos, p->data + rpos, avail );
+            inpos += avail;
+            rpos  += avail;
+
+            if (inpos == s->in_datalen) {
+                if (s->in_channel < 0) {
+                    D("ignoring %d bytes addressed to channel %d",
+                       inpos, s->in_channel);
+                } else {
+                    inp->len     = inpos;
+                    inp->channel = s->in_channel;
+                    receiver_post( s->receiver, inp );
+                    s->in_packet  = inp = packet_alloc();
+                }
+                s->in_datalen = 0;
+                inpos         = 0;
+            }
+        }
+    }
+    s->in_len = inpos;
+    packet_free(&p);
+}
+
+
+/* send a packet to the serial port */
+static void
+serial_send( Serial*  s, Packet*  p )
+{
+    Packet*  h = packet_alloc();
+
+    //D("sending to serial %d bytes from channel %d: '%.*s'", p->len, p->channel, p->len, p->data);
+
+    /* insert a small header before this packet */
+    h->len = HEADER_SIZE;
+    int2hex( p->len,     h->data + LENGTH_OFFSET,  LENGTH_SIZE );
+    int2hex( p->channel, h->data + CHANNEL_OFFSET, CHANNEL_SIZE );
+
+    fdhandler_enqueue( s->fdhandler, h );
+    fdhandler_enqueue( s->fdhandler, p );
+}
+
+
+static void
+serial_init( Serial*    s,
+             int        fd,
+             Looper*    looper,
+             Receiver*  receiver )
+{
+    Receiver  recv;
+
+    recv.user  = s;
+    recv.post  = (PostFunc)  serial_receive;
+    recv.close = (CloseFunc) serial_close;
+
+    s->receiver[0] = receiver[0];
+
+    fdhandler_init( s->fdhandler, fd, looper, &recv );
+    s->in_len     = 0;
+    s->in_datalen = 0;
+    s->in_channel = 0;
+    s->in_packet  = packet_alloc();
+}
+
+/**  GLOBAL MULTIPLEXER
+ **/
+
+typedef struct {
+    Looper     looper[1];
+    Serial     serial[1];
+    Channel*   channels;
+    uint16_t   channel_last;
+} Multiplexer;
+
+/* receive a packet from the serial port, send it to the relevant client/channel */
+static void  multiplexer_receive_serial( Multiplexer*  m, Packet*  p );
+
+static void
+multiplexer_init( Multiplexer*  m, const char*  serial_dev )
+{
+    int       fd;
+    Receiver  recv;
+
+    looper_init( m->looper );
+
+    fd = open(serial_dev, O_RDWR);
+    if (fd < 0) {
+        fatal( "%s: could not open '%s': %s", __FUNCTION__, serial_dev,
+               strerror(errno) );
+    }
+    // disable echo on serial lines
+    if ( !memcmp( serial_dev, "/dev/ttyS", 9 ) ) {
+        struct termios  ios;
+        tcgetattr( fd, &ios );
+        ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
+        tcsetattr( fd, TCSANOW, &ios );
+    }
+
+    recv.user  = m;
+    recv.post  = (PostFunc) multiplexer_receive_serial;
+    recv.close = NULL;
+
+    serial_init( m->serial, fd, m->looper, &recv );
+
+    m->channels     = NULL;
+    m->channel_last = CHANNEL_CONTROL+1;
+}
+
+static void
+multiplexer_add_channel( Multiplexer*  m, int  fd, const char*  name, ChannelType  ctype )
+{
+    Channel*  c;
+    Receiver  recv;
+
+    /* send channel client data directly to the serial port */
+    recv.user  = m->serial;
+    recv.post  = (PostFunc) serial_send;
+    recv.close = (CloseFunc) client_close;
+
+    /* connect each channel directly to the serial port */
+    c = channel_new( fd, ctype, name, m->channel_last, m->looper, &recv );
+    channel_link( c, &m->channels );
+
+    m->channel_last += 1;
+    if (m->channel_last <= CHANNEL_CONTROL)
+        m->channel_last += 1;
+}
+
+
+static void
+multiplexer_done( Multiplexer*  m )
+{
+    while (m->channels)
+        channel_close(m->channels);
+
+    serial_done( m->serial );
+    looper_done( m->looper );
+}
+
+
+static void
+multiplexer_send_answer( Multiplexer*  m, Packet*  p, const char*  answer )
+{
+    p->len = strlen( answer );
+    if (p->len >= MAX_PAYLOAD)
+        p->len = MAX_PAYLOAD-1;
+
+    memcpy( (char*)p->data, answer, p->len );
+    p->channel = CHANNEL_CONTROL;
+
+    serial_send( m->serial, p );
+}
+
+
+static void
+multiplexer_handle_connect( Multiplexer*  m, Packet*  p, char*  name )
+{
+    int       n;
+    Channel*  c;
+
+    if (p->len >= MAX_PAYLOAD) {
+        multiplexer_send_answer( m, p, "ko:connect:bad name" );
+        return;
+    }
+    p->data[p->len] = 0;
+
+    for (c = m->channels; c != NULL; c = c->next)
+        if ( !strcmp(c->name, name) )
+            break;
+
+    if (c == NULL) {
+        D("can't connect to unknown channel '%s'", name);
+        multiplexer_send_answer( m, p, "ko:connect:bad name" );
+        return;
+    }
+
+    p->channel = CHANNEL_CONTROL;
+    p->len     = snprintf( (char*)p->data, MAX_PAYLOAD,
+                       "ok:connect:%s:%02x", c->name, c->index );
+
+    serial_send( m->serial, p );
+}
+
+
+static void
+multiplexer_receive_serial( Multiplexer*  m, Packet*  p )
+{
+    Channel*  c = m->channels;
+
+    /* check the destination channel index */
+    if (p->channel != CHANNEL_CONTROL) {
+        Channel*  c;
+
+        for (c = m->channels; c; c = c->next ) {
+            if (c->index == p->channel) {
+                channel_send( c, p );
+                break;
+            }
+        }
+        if (c == NULL) {
+            D("ignoring %d bytes packet for unknown channel index %d",
+                p->len, p->channel );
+            packet_free(&p);
+        }
+    }
+    else  /* packet addressed to the control channel */
+    {
+        D("received control message:  '%.*s'", p->len, p->data);
+        if (p->len > 8 && strncmp( (char*)p->data, "connect:", 8) == 0) {
+            multiplexer_handle_connect( m, p, (char*)p->data + 8 );
+        } else {
+            /* unknown command */
+            multiplexer_send_answer( m, p, "ko:unknown command" );
+        }
+        return;
+    }
+}
+
+
+/** MAIN LOOP
+ **/
+
+static Multiplexer  _multiplexer[1];
+
+#define  QEMUD_PREFIX  "qemud_"
+
+static const struct { const char* name; ChannelType  ctype; }   default_channels[] = {
+    { "gsm", CHANNEL_DUPLEX },     /* GSM AT command channel, used by commands/rild/rild.c */
+    { "gps", CHANNEL_BROADCAST },  /* GPS NMEA commands, used by libs/hardware/qemu_gps.c  */
+    { NULL, 0 }
+};
+
+int  main( void )
+{
+    Multiplexer*  m = _multiplexer;
+
+   /* extract the name of our serial device from the kernel
+    * boot options that are stored in /proc/cmdline
+    */
+#define  KERNEL_OPTION  "android.qemud="
+
+    {
+        char          buff[1024];
+        int           fd, len;
+        char*         p;
+        char*         q;
+
+        fd = open( "/proc/cmdline", O_RDONLY );
+        if (fd < 0) {
+            D("%s: can't open /proc/cmdline !!: %s", __FUNCTION__,
+            strerror(errno));
+            exit(1);
+        }
+
+        len = fd_read( fd, buff, sizeof(buff)-1 );
+        close(fd);
+        if (len < 0) {
+            D("%s: can't read /proc/cmdline: %s", __FUNCTION__,
+            strerror(errno));
+            exit(1);
+        }
+        buff[len] = 0;
+
+        p = strstr( buff, KERNEL_OPTION );
+        if (p == NULL) {
+            D("%s: can't find '%s' in /proc/cmdline",
+            __FUNCTION__, KERNEL_OPTION );
+            exit(1);
+        }
+
+        p += sizeof(KERNEL_OPTION)-1;  /* skip option */
+        q  = p;
+        while ( *q && *q != ' ' && *q != '\t' )
+            q += 1;
+
+        snprintf( buff, sizeof(buff), "/dev/%.*s", q-p, p );
+
+        multiplexer_init( m, buff );
+    }
+
+    D("multiplexer inited, creating default channels");
+
+    /* now setup all default channels */
+    {
+        int  nn;
+
+        for (nn = 0; default_channels[nn].name != NULL; nn++) {
+            char         control_name[32];
+            int          fd;
+            Channel*     chan;
+            const char*  name  = default_channels[nn].name;
+            ChannelType  ctype = default_channels[nn].ctype;
+
+            snprintf(control_name, sizeof(control_name), "%s%s",
+                     QEMUD_PREFIX, name);
+
+            if ((fd = android_get_control_socket(control_name)) < 0) {
+                D("couldn't get fd for control socket '%s'", name);
+                continue;
+            }
+            D( "got control socket '%s' on fd %d", control_name, fd);
+            multiplexer_add_channel( m, fd, name, ctype );
+        }
+    }
+
+    D( "entering main loop");
+    looper_loop( m->looper );
+    D( "unexpected termination !!" );
+    return 0;
+}
diff --git a/emulator/qtools/Android.mk b/emulator/qtools/Android.mk
new file mode 100644
index 0000000..afbb3e8
--- /dev/null
+++ b/emulator/qtools/Android.mk
@@ -0,0 +1,141 @@
+# 
+# Copyright 2006 The Android Open Source Project
+#
+# Java method trace dump tool
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+common_includes := external/qemu
+common_cflags := -O0 -g
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := post_trace.cpp trace_reader.cpp decoder.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := post_trace
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := read_trace.cpp trace_reader.cpp decoder.cpp armdis.cpp \
+	thumbdis.cpp opcode.cpp read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := read_trace
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := check_trace.cpp trace_reader.cpp decoder.cpp \
+	opcode.cpp read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := check_trace
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := bb_dump.cpp trace_reader.cpp decoder.cpp \
+	read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := bb_dump
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := bb2sym.cpp trace_reader.cpp decoder.cpp \
+	read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := bb2sym
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := profile_trace.cpp trace_reader.cpp decoder.cpp \
+	opcode.cpp read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := profile_trace
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := bbprof.cpp trace_reader.cpp decoder.cpp armdis.cpp \
+	thumbdis.cpp opcode.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := bbprof
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := q2g.cpp trace_reader.cpp decoder.cpp \
+	opcode.cpp read_elf.cpp parse_options.cpp gtrace.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := q2g
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := q2dm.cpp trace_reader.cpp decoder.cpp armdis.cpp \
+	thumbdis.cpp opcode.cpp read_elf.cpp parse_options.cpp dmtrace.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := q2dm
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := coverage.cpp trace_reader.cpp decoder.cpp armdis.cpp \
+	thumbdis.cpp opcode.cpp read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := coverage
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := stack_dump.cpp trace_reader.cpp decoder.cpp armdis.cpp \
+	thumbdis.cpp opcode.cpp read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := stack_dump
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := hist_trace.cpp trace_reader.cpp decoder.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := hist_trace
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := read_addr.cpp trace_reader.cpp decoder.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := read_addr
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := read_pid.cpp trace_reader.cpp decoder.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := read_pid
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := exc_dump.cpp trace_reader.cpp decoder.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := exc_dump
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := read_method.cpp trace_reader.cpp decoder.cpp \
+	read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := read_method
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := profile_pid.cpp trace_reader.cpp decoder.cpp \
+	read_elf.cpp parse_options.cpp
+LOCAL_C_INCLUDES += $(common_includes)
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := profile_pid
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/emulator/qtools/armdis.cpp b/emulator/qtools/armdis.cpp
new file mode 100644
index 0000000..593f460
--- /dev/null
+++ b/emulator/qtools/armdis.cpp
@@ -0,0 +1,905 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <string.h>
+#include "armdis.h"
+#include "opcode.h"
+
+static char *cond_names[] = {
+    "eq",
+    "ne",
+    "cs",
+    "cc",
+    "mi",
+    "pl",
+    "vs",
+    "vc",
+    "hi",
+    "ls",
+    "ge",
+    "lt",
+    "gt",
+    "le",
+    "",
+    "RESERVED"
+};
+
+// Indexed by the shift type (bits 6-5)
+static const char *shift_names[] = {
+    "LSL",
+    "LSR",
+    "ASR",
+    "ROR"
+};
+
+static char* cond_to_str(int cond) {
+    return cond_names[cond];
+}
+
+char *Arm::disasm(uint32_t addr, uint32_t insn, char *result)
+{
+    static char   buf[80];
+    char          *ptr;
+
+    ptr = result ? result : buf;
+    Opcode opcode = decode(insn);
+    switch (opcode) {
+        case OP_INVALID:
+            sprintf(ptr, "Invalid");
+            return ptr;
+        case OP_UNDEFINED:
+            sprintf(ptr, "Undefined");
+            return ptr;
+        case OP_ADC:
+        case OP_ADD:
+        case OP_AND:
+        case OP_BIC:
+        case OP_CMN:
+        case OP_CMP:
+        case OP_EOR:
+        case OP_MOV:
+        case OP_MVN:
+        case OP_ORR:
+        case OP_RSB:
+        case OP_RSC:
+        case OP_SBC:
+        case OP_SUB:
+        case OP_TEQ:
+        case OP_TST:
+            return disasm_alu(opcode, insn, ptr);
+        case OP_B:
+        case OP_BL:
+            return disasm_branch(addr, opcode, insn, ptr);
+        case OP_BKPT:
+            return disasm_bkpt(insn, ptr);
+        case OP_BLX:
+            // not supported yet
+            break;
+        case OP_BX:
+            return disasm_bx(insn, ptr);
+        case OP_CDP:
+            sprintf(ptr, "cdp");
+            return ptr;
+        case OP_CLZ:
+            return disasm_clz(insn, ptr);
+        case OP_LDC:
+            sprintf(ptr, "ldc");
+            return ptr;
+        case OP_LDM:
+        case OP_STM:
+            return disasm_memblock(opcode, insn, ptr);
+        case OP_LDR:
+        case OP_LDRB:
+        case OP_LDRBT:
+        case OP_LDRT:
+        case OP_STR:
+        case OP_STRB:
+        case OP_STRBT:
+        case OP_STRT:
+            return disasm_mem(insn, ptr);
+        case OP_LDRH:
+        case OP_LDRSB:
+        case OP_LDRSH:
+        case OP_STRH:
+            return disasm_memhalf(insn, ptr);
+        case OP_MCR:
+        case OP_MRC:
+            return disasm_mcr(opcode, insn, ptr);
+        case OP_MLA:
+            return disasm_mla(opcode, insn, ptr);
+        case OP_MRS:
+            return disasm_mrs(insn, ptr);
+        case OP_MSR:
+            return disasm_msr(insn, ptr);
+        case OP_MUL:
+            return disasm_mul(opcode, insn, ptr);
+        case OP_PLD:
+            return disasm_pld(insn, ptr);
+        case OP_STC:
+            sprintf(ptr, "stc");
+            return ptr;
+        case OP_SWI:
+            return disasm_swi(insn, ptr);
+        case OP_SWP:
+        case OP_SWPB:
+            return disasm_swp(opcode, insn, ptr);
+        case OP_UMLAL:
+        case OP_UMULL:
+        case OP_SMLAL:
+        case OP_SMULL:
+            return disasm_umlal(opcode, insn, ptr);
+        default:
+            sprintf(ptr, "Error");
+            return ptr;
+    }
+    return NULL;
+}
+
+char *Arm::disasm_alu(Opcode opcode, uint32_t insn, char *ptr)
+{
+    static const uint8_t kNoOperand1 = 1;
+    static const uint8_t kNoDest = 2;
+    static const uint8_t kNoSbit = 4;
+
+    char rn_str[20];
+    char rd_str[20];
+    uint8_t flags = 0;
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t is_immed = (insn >> 25) & 0x1;
+    uint8_t bit_s = (insn >> 20) & 1;
+    uint8_t rn = (insn >> 16) & 0xf;
+    uint8_t rd = (insn >> 12) & 0xf;
+    uint8_t immed = insn & 0xff;
+
+    const char *opname = opcode_names[opcode];
+    switch (opcode) {
+        case OP_CMN:
+        case OP_CMP:
+        case OP_TEQ:
+        case OP_TST:
+            flags = kNoDest | kNoSbit;
+            break;
+        case OP_MOV:
+        case OP_MVN:
+            flags = kNoOperand1;
+            break;
+        default:
+            break;
+    }
+
+    // The "mov" instruction ignores the first operand (rn).
+    rn_str[0] = 0;
+    if ((flags & kNoOperand1) == 0) {
+        sprintf(rn_str, "r%d, ", rn);
+    }
+
+    // The following instructions do not write the result register (rd):
+    // tst, teq, cmp, cmn.
+    rd_str[0] = 0;
+    if ((flags & kNoDest) == 0) {
+        sprintf(rd_str, "r%d, ", rd);
+    }
+
+    char *sbit_str = "";
+    if (bit_s && !(flags & kNoSbit))
+        sbit_str = "s";
+
+    if (is_immed) {
+        sprintf(ptr, "%s%s%s\t%s%s#%u  ; 0x%x",
+                opname, cond_to_str(cond), sbit_str, rd_str, rn_str, immed, immed);
+        return ptr;
+    }
+
+    uint8_t shift_is_reg = (insn >> 4) & 1;
+    uint8_t rotate = (insn >> 8) & 0xf;
+    uint8_t rm = insn & 0xf;
+    uint8_t shift_type = (insn >> 5) & 0x3;
+    uint8_t rs = (insn >> 8) & 0xf;
+    uint8_t shift_amount = (insn >> 7) & 0x1f;
+    uint32_t rotated_val = immed;
+    uint8_t rotate2 = rotate << 1;
+    rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2));
+
+    if (!shift_is_reg && shift_type == 0 && shift_amount == 0) {
+        sprintf(ptr, "%s%s%s\t%s%sr%d",
+                opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm);
+        return ptr;
+    }
+
+    const char *shift_name = shift_names[shift_type];
+    if (shift_is_reg) {
+        sprintf(ptr, "%s%s%s\t%s%sr%d, %s r%d",
+                opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm,
+                shift_name, rs);
+        return ptr;
+    }
+    if (shift_amount == 0) {
+        if (shift_type == 3) {
+            sprintf(ptr, "%s%s%s\t%s%sr%d, RRX",
+                    opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm);
+            return ptr;
+        }
+        shift_amount = 32;
+    }
+    sprintf(ptr, "%s%s%s\t%s%sr%d, %s #%u",
+            opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm,
+            shift_name, shift_amount);
+    return ptr;
+}
+
+char *Arm::disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint32_t offset = insn & 0xffffff;
+    // Sign-extend the 24-bit offset
+    if ((offset >> 23) & 1)
+        offset |= 0xff000000;
+
+    // Pre-compute the left-shift and the prefetch offset
+    offset <<= 2;
+    offset += 8;
+    addr += offset;
+    const char *opname = opcode_names[opcode];
+    sprintf(ptr, "%s%s\t0x%x", opname, cond_to_str(cond), addr);
+    return ptr;
+}
+
+char *Arm::disasm_bx(uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t rn = insn & 0xf;
+    sprintf(ptr, "bx%s\tr%d", cond_to_str(cond), rn);
+    return ptr;
+}
+
+char *Arm::disasm_bkpt(uint32_t insn, char *ptr)
+{
+    uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf);
+    sprintf(ptr, "bkpt\t#%d", immed);
+    return ptr;
+}
+
+char *Arm::disasm_clz(uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t rd = (insn >> 12) & 0xf;
+    uint8_t rm = insn & 0xf;
+    sprintf(ptr, "clz%s\tr%d, r%d", cond_to_str(cond), rd, rm);
+    return ptr;
+}
+
+char *Arm::disasm_memblock(Opcode opcode, uint32_t insn, char *ptr)
+{
+    char tmp_reg[10], tmp_list[80];
+
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t write_back = (insn >> 21) & 0x1;
+    uint8_t bit_s = (insn >> 22) & 0x1;
+    uint8_t is_up = (insn >> 23) & 0x1;
+    uint8_t is_pre = (insn >> 24) & 0x1;
+    uint8_t rn = (insn >> 16) & 0xf;
+    uint16_t reg_list = insn & 0xffff;
+
+    const char *opname = opcode_names[opcode];
+
+    char *bang = "";
+    if (write_back)
+        bang = "!";
+
+    char *carret = "";
+    if (bit_s)
+        carret = "^";
+
+    char *comma = "";
+    tmp_list[0] = 0;
+    for (int ii = 0; ii < 16; ++ii) {
+        if (reg_list & (1 << ii)) {
+            sprintf(tmp_reg, "%sr%d", comma, ii);
+            strcat(tmp_list, tmp_reg);
+            comma = ",";
+        }
+    }
+
+    char *addr_mode = "";
+    if (is_pre) {
+        if (is_up) {
+            addr_mode = "ib";
+        } else {
+            addr_mode = "db";
+        }
+    } else {
+        if (is_up) {
+            addr_mode = "ia";
+        } else {
+            addr_mode = "da";
+        }
+    }
+
+    sprintf(ptr, "%s%s%s\tr%d%s, {%s}%s",
+            opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list, carret);
+    return ptr;
+}
+
+char *Arm::disasm_mem(uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t is_reg = (insn >> 25) & 0x1;
+    uint8_t is_load = (insn >> 20) & 0x1;
+    uint8_t write_back = (insn >> 21) & 0x1;
+    uint8_t is_byte = (insn >> 22) & 0x1;
+    uint8_t is_up = (insn >> 23) & 0x1;
+    uint8_t is_pre = (insn >> 24) & 0x1;
+    uint8_t rn = (insn >> 16) & 0xf;
+    uint8_t rd = (insn >> 12) & 0xf;
+    uint16_t offset = insn & 0xfff;
+
+    char *opname = "ldr";
+    if (!is_load)
+        opname = "str";
+
+    char *bang = "";
+    if (write_back)
+        bang = "!";
+
+    char *minus = "";
+    if (is_up == 0)
+        minus = "-";
+
+    char *byte = "";
+    if (is_byte)
+        byte = "b";
+
+    if (is_reg == 0) {
+        if (is_pre) {
+            if (offset == 0) {
+                sprintf(ptr, "%s%s%s\tr%d, [r%d]",
+                        opname, cond_to_str(cond), byte, rd, rn);
+            } else {
+                sprintf(ptr, "%s%s%s\tr%d, [r%d, #%s%u]%s",
+                        opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang);
+            }
+        } else {
+            char *transfer = "";
+            if (write_back)
+                transfer = "t";
+            sprintf(ptr, "%s%s%s%s\tr%d, [r%d], #%s%u",
+                    opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset);
+        }
+        return ptr;
+    }
+
+    uint8_t rm = insn & 0xf;
+    uint8_t shift_type = (insn >> 5) & 0x3;
+    uint8_t shift_amount = (insn >> 7) & 0x1f;
+
+    const char *shift_name = shift_names[shift_type];
+
+    if (is_pre) {
+        if (shift_amount == 0) {
+            if (shift_type == 0) {
+                sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d]%s",
+                        opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang);
+                return ptr;
+            }
+            if (shift_type == 3) {
+                sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, RRX]%s",
+                        opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang);
+                return ptr;
+            }
+            shift_amount = 32;
+        }
+        sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s",
+                opname, cond_to_str(cond), byte, rd, rn, minus, rm,
+                shift_name, shift_amount, bang);
+        return ptr;
+    }
+
+    char *transfer = "";
+    if (write_back)
+        transfer = "t";
+
+    if (shift_amount == 0) {
+        if (shift_type == 0) {
+            sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d",
+                    opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm);
+            return ptr;
+        }
+        if (shift_type == 3) {
+            sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, RRX",
+                    opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm);
+            return ptr;
+        }
+        shift_amount = 32;
+    }
+
+    sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u",
+            opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm,
+            shift_name, shift_amount);
+    return ptr;
+}
+
+char *Arm::disasm_memhalf(uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t is_load = (insn >> 20) & 0x1;
+    uint8_t write_back = (insn >> 21) & 0x1;
+    uint8_t is_immed = (insn >> 22) & 0x1;
+    uint8_t is_up = (insn >> 23) & 0x1;
+    uint8_t is_pre = (insn >> 24) & 0x1;
+    uint8_t rn = (insn >> 16) & 0xf;
+    uint8_t rd = (insn >> 12) & 0xf;
+    uint8_t bits_65 = (insn >> 5) & 0x3;
+    uint8_t rm = insn & 0xf;
+    uint8_t offset = (((insn >> 8) & 0xf) << 4) | (insn & 0xf);
+
+    char *opname = "ldr";
+    if (is_load == 0)
+        opname = "str";
+
+    char *width = "";
+    if (bits_65 == 1)
+        width = "h";
+    else if (bits_65 == 2)
+        width = "sb";
+    else
+        width = "sh";
+
+    char *bang = "";
+    if (write_back)
+        bang = "!";
+    char *minus = "";
+    if (is_up == 0)
+        minus = "-";
+
+    if (is_immed) {
+        if (is_pre) {
+            if (offset == 0) {
+                sprintf(ptr, "%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn);
+            } else {
+                sprintf(ptr, "%s%sh\tr%d, [r%d, #%s%u]%s",
+                        opname, cond_to_str(cond), rd, rn, minus, offset, bang);
+            }
+        } else {
+            sprintf(ptr, "%s%sh\tr%d, [r%d], #%s%u",
+                    opname, cond_to_str(cond), rd, rn, minus, offset);
+        }
+        return ptr;
+    }
+
+    if (is_pre) {
+        sprintf(ptr, "%s%sh\tr%d, [r%d, %sr%d]%s",
+                opname, cond_to_str(cond), rd, rn, minus, rm, bang);
+    } else {
+        sprintf(ptr, "%s%sh\tr%d, [r%d], %sr%d",
+                opname, cond_to_str(cond), rd, rn, minus, rm);
+    }
+    return ptr;
+}
+
+char *Arm::disasm_mcr(Opcode opcode, uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t crn = (insn >> 16) & 0xf;
+    uint8_t crd = (insn >> 12) & 0xf;
+    uint8_t cpnum = (insn >> 8) & 0xf;
+    uint8_t opcode2 = (insn >> 5) & 0x7;
+    uint8_t crm = insn & 0xf;
+
+    const char *opname = opcode_names[opcode];
+    sprintf(ptr, "%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}",
+            opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2);
+    return ptr;
+}
+
+char *Arm::disasm_mla(Opcode opcode, uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t rd = (insn >> 16) & 0xf;
+    uint8_t rn = (insn >> 12) & 0xf;
+    uint8_t rs = (insn >> 8) & 0xf;
+    uint8_t rm = insn & 0xf;
+    uint8_t bit_s = (insn >> 20) & 1;
+
+    const char *opname = opcode_names[opcode];
+    sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d",
+            opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn);
+    return ptr;
+}
+
+char *Arm::disasm_umlal(Opcode opcode, uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t rdhi = (insn >> 16) & 0xf;
+    uint8_t rdlo = (insn >> 12) & 0xf;
+    uint8_t rs = (insn >> 8) & 0xf;
+    uint8_t rm = insn & 0xf;
+    uint8_t bit_s = (insn >> 20) & 1;
+
+    const char *opname = opcode_names[opcode];
+    sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d",
+            opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs);
+    return ptr;
+}
+
+char *Arm::disasm_mul(Opcode opcode, uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t rd = (insn >> 16) & 0xf;
+    uint8_t rs = (insn >> 8) & 0xf;
+    uint8_t rm = insn & 0xf;
+    uint8_t bit_s = (insn >> 20) & 1;
+
+    const char *opname = opcode_names[opcode];
+    sprintf(ptr, "%s%s%s\tr%d, r%d, r%d",
+            opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs);
+    return ptr;
+}
+
+char *Arm::disasm_mrs(uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t rd = (insn >> 12) & 0xf;
+    uint8_t ps = (insn >> 22) & 1;
+
+    sprintf(ptr, "mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr");
+    return ptr;
+}
+
+char *Arm::disasm_msr(uint32_t insn, char *ptr)
+{
+    char flags[8];
+    int flag_index = 0;
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t is_immed = (insn >> 25) & 0x1;
+    uint8_t pd = (insn >> 22) & 1;
+    uint8_t mask = (insn >> 16) & 0xf;
+
+    if (mask & 1)
+        flags[flag_index++] = 'c';
+    if (mask & 2)
+        flags[flag_index++] = 'x';
+    if (mask & 4)
+        flags[flag_index++] = 's';
+    if (mask & 8)
+        flags[flag_index++] = 'f';
+    flags[flag_index] = 0;
+
+    if (is_immed) {
+        uint32_t immed = insn & 0xff;
+        uint8_t rotate = (insn >> 8) & 0xf;
+        uint8_t rotate2 = rotate << 1;
+        uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2));
+        sprintf(ptr, "msr%s\t%s_%s, #0x%x",
+                cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val);
+        return ptr;
+    }
+
+    uint8_t rm = insn & 0xf;
+
+    sprintf(ptr, "msr%s\t%s_%s, r%d",
+            cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm);
+    return ptr;
+}
+
+char *Arm::disasm_pld(uint32_t insn, char *ptr)
+{
+    uint8_t is_reg = (insn >> 25) & 0x1;
+    uint8_t is_up = (insn >> 23) & 0x1;
+    uint8_t rn = (insn >> 16) & 0xf;
+
+    char *minus = "";
+    if (is_up == 0)
+        minus = "-";
+
+    if (is_reg) {
+        uint8_t rm = insn & 0xf;
+        sprintf(ptr, "pld\t[r%d, %sr%d]", rn, minus, rm);
+        return ptr;
+    }
+
+    uint16_t offset = insn & 0xfff;
+    if (offset == 0) {
+        sprintf(ptr, "pld\t[r%d]", rn);
+    } else {
+        sprintf(ptr, "pld\t[r%d, #%s%u]", rn, minus, offset);
+    }
+    return ptr;
+}
+
+char *Arm::disasm_swi(uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint32_t sysnum = insn & 0x00ffffff;
+
+    sprintf(ptr, "swi%s 0x%x", cond_to_str(cond), sysnum);
+    return ptr;
+}
+
+char *Arm::disasm_swp(Opcode opcode, uint32_t insn, char *ptr)
+{
+    uint8_t cond = (insn >> 28) & 0xf;
+    uint8_t rn = (insn >> 16) & 0xf;
+    uint8_t rd = (insn >> 12) & 0xf;
+    uint8_t rm = insn & 0xf;
+
+    const char *opname = opcode_names[opcode];
+    sprintf(ptr, "%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn);
+    return ptr;
+}
+
+Opcode Arm::decode(uint32_t insn) {
+    uint32_t bits27_26 = (insn >> 26) & 0x3;
+    switch (bits27_26) {
+        case 0x0:
+            return decode00(insn);
+        case 0x1:
+            return decode01(insn);
+        case 0x2:
+            return decode10(insn);
+        case 0x3:
+            return decode11(insn);
+    }
+    return OP_INVALID;
+}
+
+Opcode Arm::decode00(uint32_t insn) {
+    uint8_t bit25 = (insn >> 25) & 0x1;
+    uint8_t bit4 = (insn >> 4) & 0x1;
+    if (bit25 == 0 && bit4 == 1) {
+        if ((insn & 0x0ffffff0) == 0x012fff10) {
+            // Bx instruction
+            return OP_BX;
+        }
+        if ((insn & 0x0ff000f0) == 0x01600010) {
+            // Clz instruction
+            return OP_CLZ;
+        }
+        if ((insn & 0xfff000f0) == 0xe1200070) {
+            // Bkpt instruction
+            return OP_BKPT;
+        }
+        uint32_t bits7_4 = (insn >> 4) & 0xf;
+        if (bits7_4 == 0x9) {
+            if ((insn & 0x0ff00ff0) == 0x01000090) {
+                // Swp instruction
+                uint8_t bit22 = (insn >> 22) & 0x1;
+                if (bit22)
+                    return OP_SWPB;
+                return OP_SWP;
+            }
+            // One of the multiply instructions
+            return decode_mul(insn);
+        }
+
+        uint8_t bit7 = (insn >> 7) & 0x1;
+        if (bit7 == 1) {
+            // One of the load/store halfword/byte instructions
+            return decode_ldrh(insn);
+        }
+    }
+
+    // One of the data processing instructions
+    return decode_alu(insn);
+}
+
+Opcode Arm::decode01(uint32_t insn) {
+    uint8_t is_reg = (insn >> 25) & 0x1;
+    uint8_t bit4 = (insn >> 4) & 0x1;
+    if (is_reg == 1 && bit4 == 1)
+        return OP_UNDEFINED;
+    uint8_t is_load = (insn >> 20) & 0x1;
+    uint8_t is_byte = (insn >> 22) & 0x1;
+    if ((insn & 0xfd70f000) == 0xf550f000) {
+        // Pre-load
+        return OP_PLD;
+    }
+    if (is_load) {
+        if (is_byte) {
+            // Load byte
+            return OP_LDRB;
+        }
+        // Load word
+        return OP_LDR;
+    }
+    if (is_byte) {
+        // Store byte
+        return OP_STRB;
+    }
+    // Store word
+    return OP_STR;
+}
+
+Opcode Arm::decode10(uint32_t insn) {
+    uint8_t bit25 = (insn >> 25) & 0x1;
+    if (bit25 == 0) {
+        // LDM/STM
+        uint8_t is_load = (insn >> 20) & 0x1;
+        if (is_load)
+            return OP_LDM;
+        return OP_STM;
+    }
+    // Branch or Branch with link
+    uint8_t is_link = (insn >> 24) & 1;
+    uint32_t offset = insn & 0xffffff;
+
+    // Sign-extend the 24-bit offset
+    if ((offset >> 23) & 1)
+        offset |= 0xff000000;
+
+    // Pre-compute the left-shift and the prefetch offset
+    offset <<= 2;
+    offset += 8;
+    if (is_link == 0)
+        return OP_B;
+    return OP_BL;
+}
+
+Opcode Arm::decode11(uint32_t insn) {
+    uint8_t bit25 = (insn >> 25) & 0x1;
+    if (bit25 == 0) {
+        // LDC, SDC
+        uint8_t is_load = (insn >> 20) & 0x1;
+        if (is_load) {
+            // LDC
+            return OP_LDC;
+        }
+        // STC
+        return OP_STC;
+    }
+
+    uint8_t bit24 = (insn >> 24) & 0x1;
+    if (bit24 == 0x1) {
+        // SWI
+        return OP_SWI;
+    }
+  
+    uint8_t bit4 = (insn >> 4) & 0x1;
+    uint8_t cpnum = (insn >> 8) & 0xf;
+
+    if (cpnum == 15) {
+        // Special case for coprocessor 15
+        uint8_t opcode = (insn >> 21) & 0x7;
+        if (bit4 == 0 || opcode != 0) {
+            // This is an unexpected bit pattern.  Create an undefined
+            // instruction in case this is ever executed.
+            return OP_UNDEFINED;
+        }
+
+        // MRC, MCR
+        uint8_t is_mrc = (insn >> 20) & 0x1;
+        if (is_mrc)
+            return OP_MRC;
+        return OP_MCR;
+    }
+
+    if (bit4 == 0) {
+        // CDP
+        return OP_CDP;
+    }
+    // MRC, MCR
+    uint8_t is_mrc = (insn >> 20) & 0x1;
+    if (is_mrc)
+        return OP_MRC;
+    return OP_MCR;
+}
+
+Opcode Arm::decode_mul(uint32_t insn) {
+    uint8_t bit24 = (insn >> 24) & 0x1;
+    if (bit24 != 0) {
+        // This is an unexpected bit pattern.  Create an undefined
+        // instruction in case this is ever executed.
+        return OP_UNDEFINED;
+    }
+    uint8_t bit23 = (insn >> 23) & 0x1;
+    uint8_t bit22_U = (insn >> 22) & 0x1;
+    uint8_t bit21_A = (insn >> 21) & 0x1;
+    if (bit23 == 0) {
+        // 32-bit multiply
+        if (bit22_U != 0) {
+            // This is an unexpected bit pattern.  Create an undefined
+            // instruction in case this is ever executed.
+            return OP_UNDEFINED;
+        }
+        if (bit21_A == 0)
+            return OP_MUL;
+        return OP_MLA;
+    }
+    // 64-bit multiply
+    if (bit22_U == 0) {
+        // Unsigned multiply long
+        if (bit21_A == 0)
+            return OP_UMULL;
+        return OP_UMLAL;
+    }
+    // Signed multiply long
+    if (bit21_A == 0)
+        return OP_SMULL;
+    return OP_SMLAL;
+}
+
+Opcode Arm::decode_ldrh(uint32_t insn) {
+    uint8_t is_load = (insn >> 20) & 0x1;
+    uint8_t bits_65 = (insn >> 5) & 0x3;
+    if (is_load) {
+        if (bits_65 == 0x1) {
+            // Load unsigned halfword
+            return OP_LDRH;
+        } else if (bits_65 == 0x2) {
+            // Load signed byte
+            return OP_LDRSB;
+        }
+        // Signed halfword
+        if (bits_65 != 0x3) {
+            // This is an unexpected bit pattern.  Create an undefined
+            // instruction in case this is ever executed.
+            return OP_UNDEFINED;
+        }
+        // Load signed halfword
+        return OP_LDRSH;
+    }
+    // Store halfword
+    if (bits_65 != 0x1) {
+        // This is an unexpected bit pattern.  Create an undefined
+        // instruction in case this is ever executed.
+        return OP_UNDEFINED;
+    }
+    // Store halfword
+    return OP_STRH;
+}
+
+Opcode Arm::decode_alu(uint32_t insn) {
+    uint8_t is_immed = (insn >> 25) & 0x1;
+    uint8_t opcode = (insn >> 21) & 0xf;
+    uint8_t bit_s = (insn >> 20) & 1;
+    uint8_t shift_is_reg = (insn >> 4) & 1;
+    uint8_t bit7 = (insn >> 7) & 1;
+    if (!is_immed && shift_is_reg && (bit7 != 0)) {
+        // This is an unexpected bit pattern.  Create an undefined
+        // instruction in case this is ever executed.
+        return OP_UNDEFINED;
+    }
+    switch (opcode) {
+        case 0x0:
+            return OP_AND;
+        case 0x1:
+            return OP_EOR;
+        case 0x2:
+            return OP_SUB;
+        case 0x3:
+            return OP_RSB;
+        case 0x4:
+            return OP_ADD;
+        case 0x5:
+            return OP_ADC;
+        case 0x6:
+            return OP_SBC;
+        case 0x7:
+            return OP_RSC;
+        case 0x8:
+            if (bit_s)
+                return OP_TST;
+            return OP_MRS;
+        case 0x9:
+            if (bit_s)
+                return OP_TEQ;
+            return OP_MSR;
+        case 0xa:
+            if (bit_s)
+                return OP_CMP;
+            return OP_MRS;
+        case 0xb:
+            if (bit_s)
+                return OP_CMN;
+            return OP_MSR;
+        case 0xc:
+            return OP_ORR;
+        case 0xd:
+            return OP_MOV;
+        case 0xe:
+            return OP_BIC;
+        case 0xf:
+            return OP_MVN;
+    }
+    // Unreachable
+    return OP_INVALID;
+}
diff --git a/emulator/qtools/armdis.h b/emulator/qtools/armdis.h
new file mode 100644
index 0000000..230f833
--- /dev/null
+++ b/emulator/qtools/armdis.h
@@ -0,0 +1,45 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef ARMDIS_H
+#define ARMDIS_H
+
+#include <inttypes.h>
+#include "opcode.h"
+
+class Arm {
+ public:
+  static char *disasm(uint32_t addr, uint32_t insn, char *buffer);
+  static Opcode decode(uint32_t insn);
+
+ private:
+  static Opcode decode00(uint32_t insn);
+  static Opcode decode01(uint32_t insn);
+  static Opcode decode10(uint32_t insn);
+  static Opcode decode11(uint32_t insn);
+  static Opcode decode_mul(uint32_t insn);
+  static Opcode decode_ldrh(uint32_t insn);
+  static Opcode decode_alu(uint32_t insn);
+
+  static char *disasm_alu(Opcode opcode, uint32_t insn, char *ptr);
+  static char *disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr);
+  static char *disasm_bx(uint32_t insn, char *ptr);
+  static char *disasm_bkpt(uint32_t insn, char *ptr);
+  static char *disasm_clz(uint32_t insn, char *ptr);
+  static char *disasm_memblock(Opcode opcode, uint32_t insn, char *ptr);
+  static char *disasm_mem(uint32_t insn, char *ptr);
+  static char *disasm_memhalf(uint32_t insn, char *ptr);
+  static char *disasm_mcr(Opcode opcode, uint32_t insn, char *ptr);
+  static char *disasm_mla(Opcode opcode, uint32_t insn, char *ptr);
+  static char *disasm_umlal(Opcode opcode, uint32_t insn, char *ptr);
+  static char *disasm_mul(Opcode opcode, uint32_t insn, char *ptr);
+  static char *disasm_mrs(uint32_t insn, char *ptr);
+  static char *disasm_msr(uint32_t insn, char *ptr);
+  static char *disasm_pld(uint32_t insn, char *ptr);
+  static char *disasm_swi(uint32_t insn, char *ptr);
+  static char *disasm_swp(Opcode opcode, uint32_t insn, char *ptr);
+};
+
+extern char *disasm_insn_thumb(uint32_t pc, uint32_t insn1, uint32_t insn2, char *result);
+extern Opcode decode_insn_thumb(uint32_t given);
+
+#endif /* ARMDIS_H */
diff --git a/emulator/qtools/bb2sym.cpp b/emulator/qtools/bb2sym.cpp
new file mode 100644
index 0000000..8a18b67
--- /dev/null
+++ b/emulator/qtools/bb2sym.cpp
@@ -0,0 +1,140 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "trace_reader.h"
+#include "parse_options.h"
+
+typedef TraceReader<> TraceReaderType;
+
+#include "parse_options-inl.h"
+
+struct MyStaticRec {
+    StaticRec   bb;
+    symbol_type *sym;
+    MyStaticRec *inner;    // pointer to an inner basic block
+    int         is_thumb;
+};
+
+MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks);
+
+void Usage(const char *program)
+{
+    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
+    OptionsUsage();
+}
+
+// This function is called from quicksort to compare addresses of basic
+// blocks.
+int cmp_inc_addr(const void *a, const void *b) {
+    MyStaticRec *bb1, *bb2;
+
+    bb1 = *(MyStaticRec**)a;
+    bb2 = *(MyStaticRec**)b;
+    if (bb1->bb.bb_addr < bb2->bb.bb_addr)
+        return -1;
+    if (bb1->bb.bb_addr > bb2->bb.bb_addr)
+        return 1;
+    return bb1->bb.bb_num - bb2->bb.bb_num;
+}
+
+int main(int argc, char **argv) {
+    uint32_t insns[kMaxInsnPerBB];
+
+    // Parse the options
+    ParseOptions(argc, argv);
+    if (argc - optind != 2) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *trace_filename = argv[optind++];
+    char *elf_file = argv[optind++];
+    TraceReader<> *trace = new TraceReader<>;
+    trace->Open(trace_filename);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+
+    TraceHeader *header = trace->GetHeader();
+    uint32_t num_static_bb = header->num_static_bb;
+
+    // Allocate space for all of the static blocks
+    MyStaticRec *blocks = new MyStaticRec[num_static_bb];
+
+    // Read in all the static blocks
+    for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
+        trace->ReadStatic(&blocks[ii].bb);
+        blocks[ii].is_thumb = blocks[ii].bb.bb_addr & 1;
+        blocks[ii].bb.bb_addr &= ~1;
+        blocks[ii].sym = NULL;
+        blocks[ii].inner = NULL;
+        trace->ReadStaticInsns(blocks[ii].bb.num_insns, insns);
+    }
+
+    MyStaticRec **sorted = assign_inner_blocks(num_static_bb, blocks);
+
+    while (1) {
+        symbol_type *sym;
+        BBEvent event;
+        BBEvent ignored;
+
+        if (GetNextValidEvent(trace, &event, &ignored, &sym))
+            break;
+
+        uint64_t bb_num = event.bb_num;
+        blocks[bb_num].sym = sym;
+    }
+        
+    printf("#     bb num_insns     bb_addr file  symbol\n");
+    for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
+        if (sorted[ii]->bb.bb_addr == 0 || sorted[ii]->bb.num_insns == 0
+            || sorted[ii]->sym == NULL)
+            continue;
+
+        printf("%8lld       %3d  0x%08x %s %s\n",
+               sorted[ii]->bb.bb_num, sorted[ii]->bb.num_insns,
+               sorted[ii]->bb.bb_addr, sorted[ii]->sym->region->path,
+               sorted[ii]->sym->name);
+    }
+    return 0;
+}
+
+// Find the basic blocks that are subsets of other basic blocks.
+MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks)
+{
+    int ii;
+    uint32_t addr_end, addr_diff;
+
+    // Create a list of pointers to the basic blocks that we can sort.
+    MyStaticRec **sorted = new MyStaticRec*[num_blocks];
+    for (ii = 0; ii < num_blocks; ++ii) {
+        sorted[ii] = &blocks[ii];
+    }
+
+    // Sort the basic blocks into increasing address order
+    qsort(sorted, num_blocks, sizeof(MyStaticRec*), cmp_inc_addr);
+
+    // Create pointers to inner blocks and break up the enclosing block
+    // so that there is no overlap.
+    for (ii = 0; ii < num_blocks - 1; ++ii) {
+        int num_bytes;
+        if (sorted[ii]->is_thumb)
+            num_bytes = sorted[ii]->bb.num_insns << 1;
+        else
+            num_bytes = sorted[ii]->bb.num_insns << 2;
+        addr_end = sorted[ii]->bb.bb_addr + num_bytes;
+        if (addr_end > sorted[ii + 1]->bb.bb_addr) {
+            sorted[ii]->inner = sorted[ii + 1];
+            addr_diff = sorted[ii + 1]->bb.bb_addr - sorted[ii]->bb.bb_addr;
+            uint32_t num_insns;
+            if (sorted[ii]->is_thumb)
+                num_insns = addr_diff >> 1;
+            else
+                num_insns = addr_diff >> 2;
+            sorted[ii]->bb.num_insns = num_insns;
+        }
+    }
+
+    return sorted;
+}
diff --git a/emulator/qtools/bb_dump.cpp b/emulator/qtools/bb_dump.cpp
new file mode 100644
index 0000000..de241fb
--- /dev/null
+++ b/emulator/qtools/bb_dump.cpp
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "trace_reader.h"
+#include "parse_options.h"
+
+typedef TraceReader<> TraceReaderType;
+
+#include "parse_options-inl.h"
+
+void Usage(const char *program)
+{
+    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
+    OptionsUsage();
+}
+
+int main(int argc, char **argv) {
+    // Parse the options
+    ParseOptions(argc, argv);
+    if (argc - optind != 2) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *trace_filename = argv[optind++];
+    char *elf_file = argv[optind++];
+    TraceReader<> *trace = new TraceReader<>;
+    trace->Open(trace_filename);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+
+    printf("#  time   bb   pid num_insns  bb_addr\n");
+    while (1) {
+        symbol_type *sym;
+        BBEvent event;
+        BBEvent ignored;
+
+        if (GetNextValidEvent(trace, &event, &ignored, &sym))
+            break;
+        printf("%7lld %4lld %5d       %3d  0x%08x %s\n",
+               event.time, event.bb_num, event.pid, event.num_insns,
+               event.bb_addr, sym->name);
+    }
+    return 0;
+}
diff --git a/emulator/qtools/bbprof.cpp b/emulator/qtools/bbprof.cpp
new file mode 100644
index 0000000..36d0941
--- /dev/null
+++ b/emulator/qtools/bbprof.cpp
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "trace_reader.h"
+#include "armdis.h"
+
+struct MyStaticRec {
+    StaticRec   bb;
+    uint32_t    *insns;
+    uint32_t    *cycles;    // number of cycles for each insn
+    uint32_t    elapsed;    // number of cycles for basic block
+    int         freq;       // execution frequency
+    MyStaticRec *inner;     // pointer to an inner basic block
+    int         is_thumb;
+};
+
+MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks);
+
+// This function is called from quicksort to compare addresses of basic
+// blocks.
+int cmp_inc_addr(const void *a, const void *b) {
+    MyStaticRec *bb1, *bb2;
+
+    bb1 = *(MyStaticRec**)a;
+    bb2 = *(MyStaticRec**)b;
+    if (bb1->bb.bb_addr < bb2->bb.bb_addr)
+        return -1;
+    if (bb1->bb.bb_addr > bb2->bb.bb_addr)
+        return 1;
+    return bb1->bb.bb_num - bb2->bb.bb_num;
+}
+
+// This function is called from quicksort to compare the elapsed time
+// of basic blocks.
+int cmp_dec_elapsed(const void *a, const void *b) {
+    MyStaticRec *bb1, *bb2;
+
+    bb1 = *(MyStaticRec**)a;
+    bb2 = *(MyStaticRec**)b;
+    if (bb1->elapsed < bb2->elapsed)
+        return 1;
+    if (bb1->elapsed > bb2->elapsed)
+        return -1;
+    return bb1->bb.bb_num - bb2->bb.bb_num;
+}
+
+// This function is called from quicksort to compare frequencies of
+// basic blocks.
+int cmp_dec_freq(const void *a, const void *b) {
+    MyStaticRec *bb1, *bb2;
+
+    bb1 = *(MyStaticRec**)a;
+    bb2 = *(MyStaticRec**)b;
+    if (bb1->freq < bb2->freq)
+        return 1;
+    if (bb1->freq > bb2->freq)
+        return -1;
+    return bb1->bb.bb_num - bb2->bb.bb_num;
+}
+
+int main(int argc, char **argv)
+{
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s trace_file\n", argv[0]);
+        exit(1);
+    }
+
+    char *trace_filename = argv[1];
+    TraceReaderBase *trace = new TraceReaderBase;
+    trace->Open(trace_filename);
+    TraceHeader *header = trace->GetHeader();
+    uint32_t num_static_bb = header->num_static_bb;
+
+    // Allocate space for all of the static blocks
+    MyStaticRec *blocks = new MyStaticRec[num_static_bb];
+
+    // Read in all the static blocks
+    for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
+        trace->ReadStatic(&blocks[ii].bb);
+        blocks[ii].is_thumb = blocks[ii].bb.bb_addr & 1;
+        blocks[ii].bb.bb_addr &= ~1;
+        uint32_t num_insns = blocks[ii].bb.num_insns;
+        blocks[ii].insns = new uint32_t[num_insns];
+        blocks[ii].cycles = new uint32_t[num_insns];
+        memset(blocks[ii].cycles, 0, num_insns * sizeof(uint32_t));
+        trace->ReadStaticInsns(num_insns, blocks[ii].insns);
+        blocks[ii].elapsed = 0;
+        blocks[ii].freq = 0;
+        blocks[ii].inner = NULL;
+    }
+
+    MyStaticRec **sorted = assign_inner_blocks(num_static_bb, blocks);
+
+    uint32_t prev_time = 0;
+    uint32_t elapsed = 0;
+    uint32_t dummy;
+    uint32_t *cycle_ptr = &dummy;
+    uint32_t *bb_elapsed_ptr = &dummy;
+    while (1) {
+        BBEvent event;
+
+        if (trace->ReadBB(&event))
+            break;
+        // Assign frequencies to each basic block
+        uint64_t bb_num = event.bb_num;
+        int num_insns = event.num_insns;
+        blocks[bb_num].freq += 1;
+        for (MyStaticRec *bptr = blocks[bb_num].inner; bptr; bptr = bptr->inner)
+            bptr->freq += 1;
+
+        // Assign simulation time to each instruction
+        for (MyStaticRec *bptr = &blocks[bb_num]; bptr; bptr = bptr->inner) {
+            uint32_t bb_num_insns = bptr->bb.num_insns;
+            for (uint32_t ii = 0; num_insns && ii < bb_num_insns; ++ii, --num_insns) {
+                uint32_t sim_time = trace->ReadInsnTime(event.time);
+                elapsed = sim_time - prev_time;
+                prev_time = sim_time;
+
+                // Attribute the elapsed time to the previous instruction and
+                // basic block.
+                *cycle_ptr += elapsed;
+                *bb_elapsed_ptr += elapsed;
+                cycle_ptr = &bptr->cycles[ii];
+                bb_elapsed_ptr = &bptr->elapsed;
+            }
+        }
+    }
+    *cycle_ptr += 1;
+    *bb_elapsed_ptr += 1;
+
+    // Sort the basic blocks into decreasing elapsed time
+    qsort(sorted, num_static_bb, sizeof(MyStaticRec*), cmp_dec_elapsed);
+
+    char spaces[80];
+    memset(spaces, ' ', 79);
+    spaces[79] = 0;
+    for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
+        printf("bb %lld addr: 0x%x, insns: %d freq: %u elapsed: %u\n",
+               sorted[ii]->bb.bb_num, sorted[ii]->bb.bb_addr,
+               sorted[ii]->bb.num_insns, sorted[ii]->freq,
+               sorted[ii]->elapsed);
+        int num_insns = sorted[ii]->bb.num_insns;
+        uint32_t addr = sorted[ii]->bb.bb_addr;
+        for (int jj = 0; jj < num_insns; ++jj) {
+            uint32_t elapsed = sorted[ii]->cycles[jj];
+            uint32_t insn = sorted[ii]->insns[jj];
+            if (insn_is_thumb(insn)) {
+                insn = insn_unwrap_thumb(insn);
+
+                // thumb_pair is true if this is the first of a pair of
+                // thumb instructions (BL or BLX).
+                bool thumb_pair = ((insn & 0xf800) == 0xf000);
+
+                // Get the next thumb instruction (if any) because we may need
+                // it for the case where insn is BL or BLX.
+                uint32_t insn2 = 0;
+                if (thumb_pair && (jj + 1 < num_insns)) {
+                    insn2 = sorted[ii]->insns[jj + 1];
+                    insn2 = insn_unwrap_thumb(insn2);
+                    jj += 1;
+                }
+                char *disasm = disasm_insn_thumb(addr, insn, insn2, NULL);
+                if (thumb_pair) {
+                    printf("  %4u %08x %04x %04x %s\n", elapsed, addr, insn,
+                           insn2, disasm);
+                    addr += 2;
+                } else {
+                    printf("  %4u %08x     %04x %s\n", elapsed, addr, insn,
+                           disasm);
+                }
+                addr += 2;
+            } else {
+                char *disasm = Arm::disasm(addr, insn, NULL);
+                printf("  %4u %08x %08x %s\n", elapsed, addr, insn, disasm);
+                addr += 4;
+            }
+        }
+    }
+
+    delete[] sorted;
+    return 0;
+}
+
+// Find the basic blocks that are subsets of other basic blocks.
+MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks)
+{
+    int ii;
+    uint32_t addr_end, addr_diff;
+
+    // Create a list of pointers to the basic blocks that we can sort.
+    MyStaticRec **sorted = new MyStaticRec*[num_blocks];
+    for (ii = 0; ii < num_blocks; ++ii) {
+        sorted[ii] = &blocks[ii];
+    }
+
+    // Sort the basic blocks into increasing address order
+    qsort(sorted, num_blocks, sizeof(MyStaticRec*), cmp_inc_addr);
+
+    // Create pointers to inner blocks and break up the enclosing block
+    // so that there is no overlap.
+    for (ii = 0; ii < num_blocks - 1; ++ii) {
+        int num_bytes;
+        if (sorted[ii]->is_thumb)
+            num_bytes = sorted[ii]->bb.num_insns << 1;
+        else
+            num_bytes = sorted[ii]->bb.num_insns << 2;
+        addr_end = sorted[ii]->bb.bb_addr + num_bytes;
+        if (addr_end > sorted[ii + 1]->bb.bb_addr) {
+            sorted[ii]->inner = sorted[ii + 1];
+            addr_diff = sorted[ii + 1]->bb.bb_addr - sorted[ii]->bb.bb_addr;
+            uint32_t num_insns;
+            if (sorted[ii]->is_thumb)
+                num_insns = addr_diff >> 1;
+            else
+                num_insns = addr_diff >> 2;
+            sorted[ii]->bb.num_insns = num_insns;
+        }
+    }
+
+    return sorted;
+}
diff --git a/emulator/qtools/bitvector.h b/emulator/qtools/bitvector.h
new file mode 100644
index 0000000..d3f5cf1
--- /dev/null
+++ b/emulator/qtools/bitvector.h
@@ -0,0 +1,40 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef BITVECTOR_H
+#define BITVECTOR_H
+
+#include <inttypes.h>
+#include <assert.h>
+
+class Bitvector {
+ public:
+  explicit Bitvector(int num_bits) {
+    num_bits_ = num_bits;
+
+    // Round up to a multiple of 32
+    num_bits = (num_bits + 31) & ~31;
+    vector_ = new uint32_t[num_bits >> 5];
+  }
+  ~Bitvector() {
+    delete[] vector_;
+  }
+
+  void        SetBit(int bitnum) {
+    assert(bitnum < num_bits_);
+    vector_[bitnum >> 5] |= 1 << (bitnum & 31);
+  }
+  void        ClearBit(int bitnum) {
+    assert(bitnum < num_bits_);
+    vector_[bitnum >> 5] &= ~(1 << (bitnum & 31));
+  }
+  bool        GetBit(int bitnum) {
+    assert(bitnum < num_bits_);
+    return (vector_[bitnum >> 5] >> (bitnum & 31)) & 1;
+  }
+
+ private:
+  int         num_bits_;
+  uint32_t    *vector_;
+};
+
+#endif  // BITVECTOR_H
diff --git a/emulator/qtools/callstack.h b/emulator/qtools/callstack.h
new file mode 100644
index 0000000..b869956
--- /dev/null
+++ b/emulator/qtools/callstack.h
@@ -0,0 +1,760 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef CALL_STACK_H
+#define CALL_STACK_H
+
+#include "opcode.h"
+#include "armdis.h"
+
+class CallStackBase {
+  public:
+    int    getId()          { return mId; }
+    void   setId(int id)    { mId = id; }
+
+  private:
+    int    mId;
+};
+
+// Define a template class for the stack frame.  The template parameter
+// SYM is the symbol_type from the TraceReader<> template class. To
+// use the CallStack class, the user derives a subclass of StackFrame
+// and defines push() and pop() methods.  This derived class is then
+// passed as a template parameter to CallStack.
+template <class SYM>
+class StackFrame {
+  public:
+
+    virtual ~StackFrame() {};
+
+    virtual void push(int stackLevel, uint64_t time, CallStackBase *base) {};
+    virtual void pop(int stackLevel, uint64_t time, CallStackBase *base) {};
+
+    typedef SYM symbol_type;
+    static const uint32_t kCausedException = 0x01;
+    static const uint32_t kInterpreted     = 0x02;
+    static const uint32_t kPopBarrier      = (kCausedException | kInterpreted);
+
+    symbol_type *function;      // the symbol for the function we entered
+    uint32_t    addr;           // return address when this function returns
+    uint32_t    flags;
+    uint32_t    time;           // for debugging when a problem occurred
+    uint32_t    global_time;    // for debugging when a problem occurred
+};
+
+template <class FRAME, class BASE = CallStackBase>
+class CallStack : public BASE {
+  public:
+    typedef typename FRAME::symbol_type symbol_type;
+    typedef typename FRAME::symbol_type::region_type region_type;
+    typedef BASE base_type;
+
+    CallStack(int id, int numFrames, TraceReaderType *trace);
+    ~CallStack();
+
+    void    updateStack(BBEvent *event, symbol_type *function);
+    void    popAll(uint64_t time);
+    void    threadStart(uint64_t time);
+    void    threadStop(uint64_t time);
+
+    // Set to true if you don't want to see any Java methods
+    void    setNativeOnly(bool nativeOnly) {
+        mNativeOnly = nativeOnly;
+    }
+
+    int         getStackLevel() { return mTop; }
+
+    uint64_t    getGlobalTime(uint64_t time) { return time + mSkippedTime; }
+    void        showStack();
+    void        showSnapshotStack();
+
+  private:
+    enum Action { NONE, PUSH, POP };
+
+    Action      getAction(BBEvent *event, symbol_type *function);
+    Action      getMethodAction(BBEvent *event, symbol_type *function);
+    void        doSimplePush(symbol_type *function, uint32_t addr,
+                             uint64_t time);
+    void        doSimplePop(uint64_t time);
+    void        doPush(BBEvent *event, symbol_type *function);
+    void        doPop(BBEvent *event, symbol_type *function, Action methodAction);
+
+    void        transitionToJava();
+    void        transitionFromJava(uint64_t time);
+
+    TraceReaderType *mTrace;
+    bool        mNativeOnly;
+
+    symbol_type mDummyFunction;
+    region_type mDummyRegion;
+
+    int         mNumFrames;
+    FRAME       *mFrames;
+    int         mTop;           // index of the next stack frame to write
+
+    int         mJavaTop;
+
+    int         mSnapshotNumFrames;
+    FRAME       *mSnapshotFrames;
+    int         mSnapshotTop;   // index of the next stack frame to write
+
+    symbol_type *mPrevFunction;
+    BBEvent     mPrevEvent;
+
+    symbol_type *mUserFunction;
+    BBEvent     mUserEvent;     // the previous user-mode event
+
+    uint64_t    mSkippedTime;
+    uint64_t    mLastRunTime;
+
+    static MethodRec    sCurrentMethod;
+    static MethodRec    sNextMethod;
+};
+
+template<class FRAME, class BASE>
+MethodRec CallStack<FRAME, BASE>::sCurrentMethod;
+template<class FRAME, class BASE>
+MethodRec CallStack<FRAME, BASE>::sNextMethod;
+
+template<class FRAME, class BASE>
+CallStack<FRAME, BASE>::CallStack(int id, int numFrames, TraceReaderType *trace)
+{
+    mNativeOnly = false;
+    mTrace = trace;
+    BASE::setId(id);
+    mNumFrames = numFrames;
+    mFrames = new FRAME[mNumFrames];
+    mTop = 0;
+
+    mSnapshotNumFrames = numFrames;
+    mSnapshotFrames = new FRAME[mSnapshotNumFrames];
+    mSnapshotTop = 0;
+
+    memset(&mDummyFunction, 0, sizeof(symbol_type));
+    memset(&mDummyRegion, 0, sizeof(region_type));
+    mDummyFunction.region = &mDummyRegion;
+    mPrevFunction = &mDummyFunction;
+    memset(&mPrevEvent, 0, sizeof(BBEvent));
+    mUserFunction = &mDummyFunction;
+    memset(&mUserEvent, 0, sizeof(BBEvent));
+    mSkippedTime = 0;
+    mLastRunTime = 0;
+    mJavaTop = 0;
+
+    // Read the first two methods from the trace if we haven't already read
+    // from the method trace yet.
+    if (sCurrentMethod.time == 0) {
+        if (mTrace->ReadMethod(&sCurrentMethod)) {
+            sCurrentMethod.time = ~0ull;
+            sNextMethod.time = ~0ull;
+        }
+        if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
+            sNextMethod.time = ~0ull;
+        }
+    }
+}
+
+template<class FRAME, class BASE>
+CallStack<FRAME, BASE>::~CallStack()
+{
+    delete mFrames;
+}
+
+template<class FRAME, class BASE>
+void
+CallStack<FRAME, BASE>::updateStack(BBEvent *event, symbol_type *function)
+{
+    if (mNativeOnly) {
+        // If this is an interpreted function, then use the native VM function
+        // instead.
+        if (function->vm_sym != NULL)
+            function = function->vm_sym;
+    }
+
+    Action action = getAction(event, function);
+    Action methodAction = getMethodAction(event, function);
+
+    // Pop off native functions before pushing or popping Java methods.
+    if (action == POP && mPrevFunction->vm_sym == NULL) {
+        // Pop off the previous function first.
+        doPop(event, function, NONE);
+        if (methodAction == POP) {
+            doPop(event, function, POP);
+        } else if (methodAction == PUSH) {
+            doPush(event, function);
+        }
+    } else {
+        if (methodAction != NONE) {
+            // If the method trace has a push or pop, then do it.
+            action = methodAction;
+        } else if (function->vm_sym != NULL) {
+            // This function is a Java method.  Don't push or pop the
+            // Java method without a corresponding method trace record.
+            action = NONE;
+        }
+        if (action == POP) {
+            doPop(event, function, methodAction);
+        } else if (action == PUSH) {
+            doPush(event, function);
+        }
+    }
+
+    // If the stack is now empty, then push the current function.
+    if (mTop == 0) {
+        uint64_t time = event->time - mSkippedTime;
+        doSimplePush(function, 0, time);
+    }
+
+    mPrevFunction = function;
+    mPrevEvent = *event;
+}
+
+template<class FRAME, class BASE>
+void
+CallStack<FRAME, BASE>::threadStart(uint64_t time)
+{
+    mSkippedTime += time - mLastRunTime;
+}
+
+template<class FRAME, class BASE>
+void
+CallStack<FRAME, BASE>::threadStop(uint64_t time)
+{
+    mLastRunTime = time;
+}
+
+template<class FRAME, class BASE>
+typename CallStack<FRAME, BASE>::Action
+CallStack<FRAME, BASE>::getAction(BBEvent *event, symbol_type *function)
+{
+    Action action;
+    uint32_t offset;
+
+    // Compute the offset from the start of the function to this basic
+    // block address.
+    offset = event->bb_addr - function->addr - function->region->base_addr;
+
+    // Get the previously executed instruction
+    Opcode op = OP_INVALID;
+    int numInsns = mPrevEvent.num_insns;
+    uint32_t insn = 0;
+    if (numInsns > 0) {
+        insn = mPrevEvent.insns[numInsns - 1];
+        if (mPrevEvent.is_thumb) {
+            insn = insn_unwrap_thumb(insn);
+            op = decode_insn_thumb(insn);
+        } else {
+            op = Arm::decode(insn);
+        }
+    }
+
+    // The number of bytes in the previous basic block depends on
+    // whether the basic block was ARM or THUMB instructions.
+    int numBytes;
+    if (mPrevEvent.is_thumb) {
+        numBytes = numInsns << 1;
+    } else {
+        numBytes = numInsns << 2;
+    }
+
+    // If this basic block follows the previous one, then return NONE.
+    // If we don't do this, then we may be fooled into thinking this
+    // is a POP if the previous block ended with a conditional
+    // (non-executed) ldmia instruction.  We do this check before
+    // checking if we are in a different function because we otherwise
+    // we might be fooled into thinking this is a PUSH to a new function
+    // when it is really just a fall-thru into a local kernel symbol
+    // that just looks like a new function.
+    uint32_t prev_end_addr = mPrevEvent.bb_addr + numBytes;
+    if (prev_end_addr == event->bb_addr) {
+        return NONE;
+    }
+
+    // If this basic block is in the same function as the last basic block,
+    // then just return NONE (but see the exceptions below).
+    // Exception 1: if the function calls itself (offset == 0) then we
+    // want to push this function.
+    // Exception 2: if the function returns to itself, then we want
+    // to pop this function.  We detect this case by checking if the last
+    // instruction in the previous basic block was a load-multiple (ldm)
+    // and included r15 as one of the loaded registers.
+    if (function == mPrevFunction) {
+        if (numInsns > 0) {
+            // If this is the beginning of the function and the previous
+            // instruction was not a branch, then it's a PUSH.
+            if (offset == 0 && op != OP_B && op != OP_THUMB_B)
+                return PUSH;
+
+            // If the previous instruction was an ldm that loaded r15,
+            // then it's a POP.
+            if (offset != 0 && ((op == OP_LDM && (insn & 0x8000))
+                                || (op == OP_THUMB_POP && (insn & 0x100)))) {
+                return POP;
+            }
+        }
+
+        return NONE;
+    }
+
+    // We have to figure out if this new function is a call or a
+    // return.  We don't necessarily have a complete call stack (since
+    // we could have started tracing at any point), so we have to use
+    // heuristics.  If the address we are jumping to is the beginning
+    // of a function, or if the instruction that took us there was
+    // either "bl" or "blx" then this is a PUSH.  Also, if the
+    // function offset is non-zero and the previous instruction is a
+    // branch instruction, we will call it a PUSH.  This happens in
+    // the kernel a lot when there is a branch to an offset from a
+    // label. A couple more special cases:
+    //
+    //   - entering a .plt section ("procedure linkage table") is a PUSH,
+    //   - an exception that jumps into the kernel vector entry point
+    //     is also a push.
+    // 
+    // If the function offset is non-zero and the previous instruction
+    // is a bx or some non-branch instruction, then it's a POP.
+    //
+    // There's another special case that comes up.  The user code
+    // might execute an instruction that returns but before the pc
+    // starts executing in the caller, a kernel interrupt occurs.
+    // But it may be hard to tell if this is a return until after
+    // the kernel interrupt code is done and returns to user space.
+    // So we save the last user basic block and look at it when
+    // we come back into user space.
+
+    const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
+
+    if (((mPrevFunction->region->flags & kIsKernelRegion) == 0)
+        && (function->region->flags & kIsKernelRegion)) {
+        // We just switched into the kernel.  Save the previous
+        // user-mode basic block and function.
+        mUserEvent = mPrevEvent;
+        mUserFunction = mPrevFunction;
+    } else if ((mPrevFunction->region->flags & kIsKernelRegion)
+               && ((function->region->flags & kIsKernelRegion) == 0)) {
+        // We just switched from kernel to user mode.
+        return POP;
+    }
+
+    action = PUSH;
+    if (offset != 0 && mPrevFunction != &mDummyFunction) {
+        // We are jumping into the middle of a function, so this is
+        // probably a return, not a function call.  But look at the
+        // previous instruction first to see if it was a branch-and-link.
+
+        // If the previous instruction was not a branch (and not a
+        // branch-and-link) then POP; or if it is a "bx" instruction
+        // then POP because that is used to return from functions.
+        if (!isBranch(op) || op == OP_BX || op == OP_THUMB_BX) {
+            action = POP;
+        } else if (isBranch(op) && !isBranchLink(op)) {
+            // If the previous instruction was a normal branch to a
+            // local symbol then don't count it as a push or a pop.
+            action = NONE;
+        }
+
+        if (function->flags & symbol_type::kIsVectorTable)
+            action = PUSH;
+    }
+    return action;
+}
+
+
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::doPush(BBEvent *event, symbol_type *function)
+{
+    uint64_t time = event->time - mSkippedTime;
+
+    // Check for stack overflow
+    if (mTop >= mNumFrames) {
+#if 0
+        showStack();
+#endif
+        fprintf(stderr, "Error: stack overflow (%d frames)\n", mTop);
+        exit(1);
+    }
+
+    // Compute the return address here because we may need to change
+    // it if we are popping off a frame for a vector table.
+    int numBytes;
+    if (mPrevEvent.is_thumb) {
+        numBytes = mPrevEvent.num_insns << 1;
+    } else {
+        numBytes = mPrevEvent.num_insns << 2;
+    }
+    uint32_t retAddr = mPrevEvent.bb_addr + numBytes;
+
+    // If this is a Java method then set the return address to zero.
+    // We won't be using it for popping the method and it may lead
+    // to false matches when searching the stack.
+    if (function->vm_sym != NULL) {
+        retAddr = 0;
+    }
+
+#if 0
+    if (function->flags & symbol_type::kIsVectorStart) {
+        printf("stack before entering exception\n");
+        showStack();
+    }
+#endif
+
+    // If the previous function was a vector table, then pop it
+    // off before pushing on the new function.  Also, change the
+    // return address for the new function to the return address
+    // from the vector table.
+    if ((mPrevFunction->flags & symbol_type::kIsVectorTable) && mTop > 0) {
+        retAddr = mFrames[mTop - 1].addr;
+        doSimplePop(time);
+    }
+
+    const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
+
+    // The following code handles the case where one function, F1,
+    // calls another function, F2, but the before F2 can start
+    // executing, it takes a page fault (on the first instruction
+    // in F2).  The kernel is entered, handles the page fault, and
+    // then returns to the called function.  The problem is that
+    // this looks like a new function call to F2 from the kernel.
+    // The following code cleans up the stack by popping the
+    // kernel frames back to F1 (but not including F1).  The
+    // return address for F2 also has to be fixed up to point to
+    // F1 instead of the kernel.
+    //
+    // We detect this case by checking if the previous basic block
+    // was in the kernel and the current basic block is not.
+    if ((mPrevFunction->region->flags & kIsKernelRegion)
+        && ((function->region->flags & kIsKernelRegion) == 0)
+        && mTop > 0) {
+        // We are switching from kernel mode to user mode.
+#if 0
+        printf("  doPush(): popping to user mode, bb_addr: 0x%08x\n",
+               event->bb_addr);
+        showStack();
+#endif
+        do {
+            // Pop off the kernel frames until we reach the one that
+            // caused the exception.
+            doSimplePop(time);
+
+            // If the next stack frame is the one that caused an
+            // exception then stop popping frames.
+            if (mTop > 0
+                && (mFrames[mTop - 1].flags & FRAME::kCausedException)) {
+                mFrames[mTop - 1].flags &= ~FRAME::kCausedException;
+                retAddr = mFrames[mTop].addr;
+                break;
+            }
+        } while (mTop > 0);
+#if 0
+        printf("  doPush() popping to level %d, using retAddr 0x%08x\n",
+               mTop, retAddr);
+#endif
+    }
+
+    // If we are starting an exception handler, then mark the previous
+    // stack frame so that we know where to return when the exception
+    // handler finishes.
+    if ((function->flags & symbol_type::kIsVectorStart) && mTop > 0)
+        mFrames[mTop - 1].flags |= FRAME::kCausedException;
+
+    doSimplePush(function, retAddr, time);
+}
+
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function,
+                                          uint32_t addr, uint64_t time)
+{
+    // Check for stack overflow
+    if (mTop >= mNumFrames) {
+        showStack();
+        fprintf(stderr, "too many stack frames (%d)\n", mTop);
+        exit(1);
+    }
+
+    // Keep track of the number of Java methods we push on the stack.
+    if (!mNativeOnly && function->vm_sym != NULL) {
+        // If we are pushing the first Java method on the stack, then
+        // save a snapshot of the stack so that we can clean things up
+        // later when we pop off the last Java stack frame.
+        if (mJavaTop == 0) {
+            transitionToJava();
+        }
+        mJavaTop += 1;
+    }
+
+    mFrames[mTop].addr = addr;
+    mFrames[mTop].function = function;
+    mFrames[mTop].flags = 0;
+    mFrames[mTop].time = time;
+    mFrames[mTop].global_time = time + mSkippedTime;
+
+    // If the function being pushed is a Java method, then mark it on
+    // the stack so that we don't pop it off until we get a matching
+    // trace record from the method trace file.
+    if (function->vm_sym != NULL) {
+        mFrames[mTop].flags = FRAME::kInterpreted;
+    }
+
+    mFrames[mTop].push(mTop, time, this);
+    mTop += 1;
+}
+
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::doSimplePop(uint64_t time)
+{
+    if (mTop <= 0) {
+        return;
+    }
+
+    mTop -= 1;
+    mFrames[mTop].pop(mTop, time, this);
+
+    // Keep track of the number of Java methods we have on the stack.
+    symbol_type *function = mFrames[mTop].function;
+    if (!mNativeOnly && function->vm_sym != NULL) {
+        mJavaTop -= 1;
+
+        // When there are no more Java stack frames, then clean up
+        // the client's stack.  We need to do this because the client
+        // doesn't see the changes to the native stack underlying the
+        // fake Java stack until the last Java method is popped off.
+        if (mJavaTop == 0) {
+            transitionFromJava(time);
+        }
+    }
+}
+
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::doPop(BBEvent *event, symbol_type *function,
+                                   Action methodAction)
+{
+    uint64_t time = event->time - mSkippedTime;
+
+    // Search backward on the stack for a matching return address.
+    // The most common case is that we pop one stack frame, but
+    // sometimes we pop more than one.
+    int stackLevel;
+    bool allowMethodPop = (methodAction == POP);
+    for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
+        if (event->bb_addr == mFrames[stackLevel].addr) {
+            // We found a matching return address on the stack.
+            break;
+        }
+
+        // If this stack frame caused an exception, then do not pop
+        // this stack frame.
+        if (mFrames[stackLevel].flags & FRAME::kPopBarrier) {
+            // If this is a Java method, then allow a pop only if we
+            // have a matching trace record.
+            if (mFrames[stackLevel].flags & FRAME::kInterpreted) {
+                if (allowMethodPop) {
+                    // Allow at most one method pop
+                    allowMethodPop = false;
+                    continue;
+                }
+            }
+            stackLevel += 1;
+            break;
+        }
+    }
+
+    // If we didn't find a matching return address then search the stack
+    // again for a matching function.
+    if (stackLevel < 0 || event->bb_addr != mFrames[stackLevel].addr) {
+        bool allowMethodPop = (methodAction == POP);
+        for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
+            // Compare the function with the one in the stack frame.
+            if (function == mFrames[stackLevel].function) {
+                // We found a matching function.  We want to pop up to but not
+                // including this frame.
+                stackLevel += 1;
+                break;
+            }
+
+            // If this stack frame caused an exception, then do not pop
+            // this stack frame.
+            if (mFrames[stackLevel].flags & FRAME::kPopBarrier) {
+                // If this is a Java method, then allow a pop only if we
+                // have a matching trace record.
+                if (mFrames[stackLevel].flags & FRAME::kInterpreted) {
+                    if (allowMethodPop) {
+                        // Allow at most one method pop
+                        allowMethodPop = false;
+                        continue;
+                    }
+                }
+                stackLevel += 1;
+                break;
+            }
+        }
+        if (stackLevel < 0)
+            stackLevel = 0;
+    }
+
+    // Note that if we didn't find a matching stack frame, we will pop
+    // the whole stack (unless there is a Java method or exception
+    // frame on the stack).  This is intentional because we may have
+    // started the trace in the middle of an executing program that is
+    // returning up the stack and we do not know the whole stack.  So
+    // the right thing to do is to empty the stack.
+
+    // If we are emptying the stack, then add the current function
+    // on top.  If the current function is the same as the top of
+    // stack, then avoid an extraneous pop and push.
+    if (stackLevel == 0 && mFrames[0].function == function)
+        stackLevel = 1;
+
+#if 0
+    if (mTop - stackLevel > 7) {
+        printf("popping thru level %d\n", stackLevel);
+        showStack();
+    }
+#endif
+
+    // Pop the stack frames
+    for (int ii = mTop - 1; ii >= stackLevel; --ii)
+        doSimplePop(time);
+
+    // Clear the "caused exception" bit on the current stack frame
+    if (mTop > 0) {
+        mFrames[mTop - 1].flags &= ~FRAME::kCausedException;
+    }
+
+    // Also handle the case where F1 calls F2 and F2 returns to
+    // F1, but before we can execute any instructions in F1, we
+    // switch to the kernel.  Then when we return from the kernel
+    // we want to pop off F2 from the stack instead of pushing F1
+    // on top of F2.  To handle this case, we saved the last
+    // user-mode basic block when we entered the kernel (in
+    // the getAction() function) and now we can check to see if
+    // that was a return to F1 instead of a call.  We use the
+    // getAction() function to determine this.
+    const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
+    if ((mPrevFunction->region->flags & kIsKernelRegion)
+        && ((function->region->flags & kIsKernelRegion) == 0)) {
+        mPrevEvent = mUserEvent;
+        mPrevFunction = mUserFunction;
+        if (getAction(event, function) == POP) {
+            // We may need to pop more than one frame, so just
+            // call doPop() again.  This won't be an infinite loop
+            // here because we changed mPrevEvent to the last
+            // user-mode event.
+            doPop(event, function, methodAction);
+            return;
+        }
+    }
+}
+
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::popAll(uint64_t time)
+{
+    time -= mSkippedTime;
+    while (mTop != 0) {
+        doSimplePop(time);
+    }
+}
+
+template<class FRAME, class BASE>
+typename CallStack<FRAME, BASE>::Action
+CallStack<FRAME, BASE>::getMethodAction(BBEvent *event, symbol_type *function)
+{
+    if (function->vm_sym == NULL && mPrevFunction->vm_sym == NULL) {
+        return NONE;
+    }
+
+    Action action = NONE;
+    uint32_t prevAddr = mPrevFunction->addr + mPrevFunction->region->base_addr;
+    uint32_t addr = function->addr + function->region->base_addr;
+
+    // If the events get ahead of the method trace, then read ahead until we
+    // sync up again.  This can happen if there is a pop of a method in the
+    // method trace for which we don't have a previous push.
+    while (event->time >= sNextMethod.time) {
+        sCurrentMethod = sNextMethod;
+        if (mTrace->ReadMethod(&sNextMethod)) {
+            sNextMethod.time = ~0ull;
+        }
+    }
+
+    if (event->time >= sCurrentMethod.time) {
+        if (addr == sCurrentMethod.addr || prevAddr == sCurrentMethod.addr) {
+            action = (sCurrentMethod.flags == 0) ? PUSH : POP;
+            // We found a match, so read the next record.
+            sCurrentMethod = sNextMethod;
+            if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
+                sNextMethod.time = ~0ull;
+            }
+        }
+    }
+    return action;
+}
+
+// When the first Java method is pushed on the stack, this method is
+// called to save a snapshot of the current native stack so that the
+// client's view of the native stack can be patched up later when the
+// Java stack is empty.
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::transitionToJava()
+{
+    mSnapshotTop = mTop;
+    for (int ii = 0; ii < mTop; ++ii) {
+        mSnapshotFrames[ii] = mFrames[ii];
+    }
+}
+
+// When the Java stack becomes empty, the native stack becomes
+// visible.  This method is called when the Java stack becomes empty
+// to patch up the client's view of the native stack, which may have
+// changed underneath the Java stack.  The stack snapshot is used to
+// create a sequence of pops and pushes to make the client's view of
+// the native stack match the current native stack.
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::transitionFromJava(uint64_t time)
+{
+    int top = mTop;
+    if (top > mSnapshotTop) {
+        top = mSnapshotTop;
+    }
+    for (int ii = 0; ii < top; ++ii) {
+        if (mSnapshotFrames[ii].function->addr == mFrames[ii].function->addr) {
+            continue;
+        }
+
+        // Pop off all the rest of the frames from the snapshot
+        for (int jj = top - 1; jj >= ii; --jj) {
+            mSnapshotFrames[jj].pop(jj, time, this);
+        }
+
+        // Push the new frames from the native stack
+        for (int jj = ii; jj < mTop; ++jj) {
+            mFrames[jj].push(jj, time, this);
+        }
+        break;
+    }
+}
+
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::showStack()
+{
+    fprintf(stderr, "mTop: %d skippedTime: %llu\n", mTop, mSkippedTime);
+    for (int ii = 0; ii < mTop; ++ii) {
+        fprintf(stderr, "  %d: t %d gt %d f %x 0x%08x 0x%08x %s\n",
+                ii, mFrames[ii].time, mFrames[ii].global_time,
+                mFrames[ii].flags,
+                mFrames[ii].addr, mFrames[ii].function->addr,
+                mFrames[ii].function->name);
+    }
+}
+
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::showSnapshotStack()
+{
+    fprintf(stderr, "mSnapshotTop: %d\n", mSnapshotTop);
+    for (int ii = 0; ii < mSnapshotTop; ++ii) {
+        fprintf(stderr, "  %d: t %d f %x 0x%08x 0x%08x %s\n",
+                ii, mSnapshotFrames[ii].time, mSnapshotFrames[ii].flags,
+                mSnapshotFrames[ii].addr, mSnapshotFrames[ii].function->addr,
+                mSnapshotFrames[ii].function->name);
+    }
+}
+
+#endif /* CALL_STACK_H */
diff --git a/emulator/qtools/check_trace.cpp b/emulator/qtools/check_trace.cpp
new file mode 100644
index 0000000..d933a87
--- /dev/null
+++ b/emulator/qtools/check_trace.cpp
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "trace_reader.h"
+#include "armdis.h"
+#include "parse_options.h"
+
+typedef TraceReader<> TraceReaderType;
+
+#include "parse_options-inl.h"
+
+static const uint32_t kOffsetThreshold = 0x100000;
+
+void Usage(const char *program)
+{
+    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
+    OptionsUsage();
+}
+
+int main(int argc, char **argv) {
+    // Parse the options
+    ParseOptions(argc, argv);
+    if (argc - optind != 2) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *trace_filename = argv[optind++];
+    char *elf_file = argv[optind++];
+    TraceReader<> *trace = new TraceReader<>;
+    trace->Open(trace_filename);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+
+    while (1) {
+        symbol_type *sym;
+        BBEvent event;
+        BBEvent ignored;
+
+        if (GetNextValidEvent(trace, &event, &ignored, &sym))
+            break;
+        if (event.bb_num == 0)
+            break;
+        //printf("t%llu bb %lld %d\n", event.time, event.bb_num, event.num_insns);
+        uint64_t insn_time = trace->ReadInsnTime(event.time);
+        if (insn_time != event.time) {
+            printf("time: %llu insn time: %llu bb: %llu addr: 0x%x num_insns: %d, pid: %d\n",
+                   event.time, insn_time, event.bb_num, event.bb_addr,
+                   event.num_insns, event.pid);
+            exit(1);
+        }
+        for (int ii = 1; ii < event.num_insns; ++ii) {
+            trace->ReadInsnTime(event.time);
+        }
+    }
+
+    delete trace;
+    return 0;
+}
diff --git a/emulator/qtools/coverage.cpp b/emulator/qtools/coverage.cpp
new file mode 100644
index 0000000..fb1fe52
--- /dev/null
+++ b/emulator/qtools/coverage.cpp
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "trace_reader.h"
+#include "parse_options.h"
+#include "opcode.h"
+
+const int kMillion = 1000000;
+const int kMHz = 200 * kMillion;
+
+struct symbol {
+    int    numCalls;    // number of times this function is called
+};
+
+typedef TraceReader<symbol> TraceReaderType;
+
+#include "parse_options-inl.h"
+#include "callstack.h"
+
+class MyFrame : public StackFrame<symbol_type> {
+  public:
+    void    push(int stackLevel, uint64_t time, CallStackBase *base) {
+        function->numCalls += 1;
+    }
+    void    pop(int stackLevel, uint64_t time, CallStackBase *base) {
+    }
+};
+
+typedef CallStack<MyFrame> CallStackType;
+
+static const int kNumStackFrames = 500;
+static const int kMaxThreads = (32 * 1024);
+CallStackType *stacks[kMaxThreads];
+
+// This comparison function is called from qsort() to sort symbols
+// into decreasing number of calls.
+int cmp_sym_calls(const void *a, const void *b) {
+    const symbol_type *syma, *symb;
+    uint64_t calls1, calls2;
+
+    syma = static_cast<symbol_type const *>(a);
+    symb = static_cast<symbol_type const *>(b);
+    calls1 = syma->numCalls;
+    calls2 = symb->numCalls;
+    if (calls1 < calls2)
+        return 1;
+    if (calls1 == calls2) {
+        int cmp = strcmp(syma->name, symb->name);
+        if (cmp == 0)
+            cmp = strcmp(syma->region->path, symb->region->path);
+        return cmp;
+    }
+    return -1;
+}
+
+// This comparison function is called from qsort() to sort symbols
+// into alphabetical order.
+int cmp_sym_names(const void *a, const void *b) {
+    const symbol_type *syma, *symb;
+
+    syma = static_cast<symbol_type const *>(a);
+    symb = static_cast<symbol_type const *>(b);
+    int cmp = strcmp(syma->region->path, symb->region->path);
+    if (cmp == 0)
+        cmp = strcmp(syma->name, symb->name);
+    return cmp;
+}
+
+void Usage(const char *program)
+{
+    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
+    OptionsUsage();
+}
+
+int main(int argc, char **argv)
+{
+    ParseOptions(argc, argv);
+    if (argc - optind != 2) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *trace_filename = argv[optind++];
+    char *elf_file = argv[optind++];
+    TraceReader<symbol> *trace = new TraceReader<symbol>;
+    trace->Open(trace_filename);
+    trace->SetDemangle(demangle);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+
+    BBEvent event;
+    while (1) {
+        BBEvent ignored;
+        symbol_type *function;
+
+        if (GetNextValidEvent(trace, &event, &ignored, &function))
+            break;
+        if (event.bb_num == 0)
+            break;
+
+        // Get the stack for the current thread
+        CallStackType *pStack = stacks[event.pid];
+
+        // If the stack does not exist, then allocate a new one.
+        if (pStack == NULL) {
+            pStack = new CallStackType(event.pid, kNumStackFrames, trace);
+            stacks[event.pid] = pStack;
+        }
+
+        // Update the stack
+        pStack->updateStack(&event, function);
+    }
+
+    for (int ii = 0; ii < kMaxThreads; ++ii) {
+        if (stacks[ii])
+            stacks[ii]->popAll(event.time);
+    }
+
+    int nsyms;
+    symbol_type *syms = trace->GetSymbols(&nsyms);
+
+    // Sort the symbols into decreasing number of calls
+    qsort(syms, nsyms, sizeof(symbol_type), cmp_sym_names);
+
+    symbol_type *psym = syms;
+    for (int ii = 0; ii < nsyms; ++ii, ++psym) {
+        // Ignore functions with non-zero calls
+        if (psym->numCalls)
+            continue;
+
+        // Ignore some symbols
+        if (strcmp(psym->name, "(end)") == 0)
+            continue;
+        if (strcmp(psym->name, "(unknown)") == 0)
+            continue;
+        if (strcmp(psym->name, ".plt") == 0)
+            continue;
+        char *ksym = " ";
+        if (psym->region->flags & region_type::kIsKernelRegion)
+            ksym = "k";
+        printf("%s %s %s\n", ksym, psym->name, psym->region->path);
+#if 0
+        printf("#%d %5d %s %s %s\n", ii + 1, psym->numCalls, ksym, psym->name,
+               psym->region->path);
+#endif
+    }
+    delete[] syms;
+    delete trace;
+
+    return 0;
+}
diff --git a/emulator/qtools/decoder.cpp b/emulator/qtools/decoder.cpp
new file mode 100644
index 0000000..ec53181
--- /dev/null
+++ b/emulator/qtools/decoder.cpp
@@ -0,0 +1,278 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "decoder.h"
+#include "trace_common.h"
+
+// This array provides a fast conversion from the initial byte in
+// a varint-encoded object to the length (in bytes) of that object.
+int prefix_to_len[] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 9, 9, 17, 17
+};
+
+// This array provides a fast conversion from the initial byte in
+// a varint-encoded object to the initial data bits for that object.
+int prefix_to_data[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+    64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+    80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+    96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+    112, 113, 114, 115, 116, 117, 118, 119,
+    120, 121, 122, 123, 124, 125, 126, 127,
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+    0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0
+};
+
+signed char prefix_to_signed_data[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+    0x00, 0x01, 0x02, 0x03, 0xfc, 0xfd, 0xfe, 0xff,
+    0x00, 0x01, 0xfe, 0xff, 0x00, 0xff, 0x00, 0xff,
+};
+
+Decoder::Decoder()
+{
+    filename_ = NULL;
+    fstream_ = NULL;
+    next_ = NULL;
+    end_ = NULL;
+}
+
+Decoder::~Decoder()
+{
+    Close();
+    delete[] filename_;
+}
+
+void Decoder::Close()
+{
+    if (fstream_) {
+        fclose(fstream_);
+        fstream_ = NULL;
+    }
+}
+
+void Decoder::Open(char *filename)
+{
+    if (filename_ != NULL) {
+        delete[] filename_;
+    }
+    filename_ = new char[strlen(filename) + 1];
+    strcpy(filename_, filename);
+    fstream_ = fopen(filename_, "r");
+    if (fstream_ == NULL) {
+        perror(filename_);
+        exit(1);
+    }
+
+    int rval = fread(buf_, 1, kBufSize, fstream_);
+    if (rval != kBufSize) {
+        if (ferror(fstream_)) {
+            perror(filename_);
+            exit(1);
+        }
+        if (!feof(fstream_)) {
+            fprintf(stderr, "Unexpected short fread() before eof\n");
+            exit(1);
+        }
+    }
+    next_ = buf_;
+    end_ = buf_ + rval;
+}
+
+void Decoder::FillBuffer()
+{
+    assert(next_ <= end_);
+  
+    if (end_ - next_ < kDecodingSpace && end_ == &buf_[kBufSize]) {
+        // Copy the unused bytes left at the end to the beginning of the
+        // buffer.
+        int len = end_ - next_;
+        if (len > 0)
+            memcpy(buf_, next_, len);
+
+        // Read enough bytes to fill up the buffer, if possible.
+        int nbytes = kBufSize - len;
+        int rval = fread(buf_ + len, 1, nbytes, fstream_);
+        if (rval < nbytes) {
+            if (ferror(fstream_)) {
+                perror(filename_);
+                exit(1);
+            }
+            if (!feof(fstream_)) {
+                fprintf(stderr, "Unexpected short fread() before eof\n");
+                exit(1);
+            }
+        }
+        end_ = &buf_[len + rval];
+        next_ = buf_;
+    }
+}
+
+void Decoder::Read(char *dest, int len)
+{
+    while (len > 0) {
+        int nbytes = end_ - next_;
+        if (nbytes == 0) {
+            FillBuffer();
+            nbytes = end_ - next_;
+            if (nbytes == 0)
+                break;
+        }
+        if (nbytes > len)
+            nbytes = len;
+        memcpy(dest, next_, nbytes);
+        dest += nbytes;
+        len -= nbytes;
+        next_ += nbytes;
+    }
+}
+
+// Decode a varint-encoded object starting at the current position in
+// the array "buf_" and return the decoded value as a 64-bit integer.
+// A varint-encoded object has an initial prefix that specifies how many
+// data bits follow.  If the first bit is zero, for example, then there
+// are 7 data bits that follow.  The table below shows the prefix values
+// and corresponding data bits.
+//
+// Prefix     Bytes  Data bits
+// 0          1      7
+// 10         2      14
+// 110        3      21
+// 1110       4      28
+// 11110      5      35
+// 111110     6      42
+// 11111100   9      64
+// 11111101   reserved
+// 11111110   reserved
+// 11111111   reserved
+int64_t Decoder::Decode(bool is_signed)
+{
+    int64_t val64;
+
+    if (end_ - next_ < kDecodingSpace)
+        FillBuffer();
+
+#if BYTE_ORDER == BIG_ENDIAN
+    uint8_t byte0 = *next_;
+
+    // Get the number of bytes to decode based on the first byte.
+    int len = prefix_to_len[byte0];
+
+    if (next_ + len > end_) {
+        fprintf(stderr, "%s: decoding past end of file.\n", filename_);
+        exit(1);
+    }
+
+    // Get the first data byte.
+    if (is_signed)
+        val64 = prefix_to_signed_data[byte0];
+    else
+        val64 = prefix_to_data[byte0];
+
+    next_ += 1;
+    for (int ii = 1; ii < len; ++ii) {
+        val64 = (val64 << 8) | *next_++;
+    }
+#else
+    // If we are on a little-endian machine, then use large, unaligned loads.
+    uint64_t data = *(reinterpret_cast<uint64_t*>(next_));
+    uint8_t byte0 = data;
+    data = bswap64(data);
+
+    // Get the number of bytes to decode based on the first byte.
+    int len = prefix_to_len[byte0];
+
+    if (next_ + len > end_) {
+        fprintf(stderr, "%s: decoding past end of file.\n", filename_);
+        exit(1);
+    }
+
+    // Get the first data byte.
+    if (is_signed)
+        val64 = prefix_to_signed_data[byte0];
+    else
+        val64 = prefix_to_data[byte0];
+
+    switch (len) {
+        case 1:
+            break;
+        case 2:
+            val64 = (val64 << 8) | ((data >> 48) & 0xffull);
+            break;
+        case 3:
+            val64 = (val64 << 16) | ((data >> 40) & 0xffffull);
+            break;
+        case 4:
+            val64 = (val64 << 24) | ((data >> 32) & 0xffffffull);
+            break;
+        case 5:
+            val64 = (val64 << 32) | ((data >> 24) & 0xffffffffull);
+            break;
+        case 6:
+            val64 = (val64 << 40) | ((data >> 16) & 0xffffffffffull);
+            break;
+        case 9:
+            data = *(reinterpret_cast<uint64_t*>(&next_[1]));
+            val64 = bswap64(data);
+            break;
+    }
+    next_ += len;
+#endif
+    return val64;
+}
diff --git a/emulator/qtools/decoder.h b/emulator/qtools/decoder.h
new file mode 100644
index 0000000..44905fd
--- /dev/null
+++ b/emulator/qtools/decoder.h
@@ -0,0 +1,28 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <inttypes.h>
+
+class Decoder {
+ public:
+  Decoder();
+  ~Decoder();
+
+  void          Open(char *filename);
+  void          Close();
+  int64_t       Decode(bool is_signed);
+  void          Read(char *dest, int len);
+  bool          IsEOF()          { return (end_ == next_) && feof(fstream_); }
+
+ private:
+  static const int kBufSize = 4096;
+  static const int kDecodingSpace = 9;
+
+  void          FillBuffer();
+
+  char          *filename_;
+  FILE          *fstream_;
+  uint8_t       buf_[kBufSize];
+  uint8_t       *next_;
+  uint8_t       *end_;
+};
diff --git a/emulator/qtools/dmtrace.cpp b/emulator/qtools/dmtrace.cpp
new file mode 100644
index 0000000..a27193a
--- /dev/null
+++ b/emulator/qtools/dmtrace.cpp
@@ -0,0 +1,253 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include "dmtrace.h"
+
+static const short kVersion = 2;
+
+const DmTrace::Header DmTrace::header = {
+    0x574f4c53, kVersion, sizeof(DmTrace::Header), 0LL
+};
+
+static char *keyHeader = "*version\n" "2\n" "clock=thread-cpu\n";
+static char *keyThreadHeader = "*threads\n";
+static char *keyFunctionHeader = "*methods\n";
+static char *keyEnd = "*end\n";
+
+DmTrace::DmTrace() {
+    fData = NULL;
+    fTrace = NULL;
+    threads = new std::vector<ThreadRecord*>;
+    functions = new std::vector<FunctionRecord*>;
+}
+
+DmTrace::~DmTrace() {
+    delete threads;
+    delete functions;
+}
+
+void DmTrace::open(const char *dmtrace_file, uint64_t start_time)
+{
+    fTrace = fopen(dmtrace_file, "w");
+    if (fTrace == NULL) {
+        perror(dmtrace_file);
+        exit(1);
+    }
+
+    // Make a temporary file to write the data into.
+    char tmpData[32];
+    strcpy(tmpData, "/tmp/dmtrace-data-XXXXXX");
+    int data_fd = mkstemp(tmpData);
+    if (data_fd < 0) {
+        perror("Cannot create temporary file");
+        exit(1);
+    }
+
+    // Ensure it goes away on exit.
+    unlink(tmpData);
+    fData = fdopen(data_fd, "w+");
+    if (fData == NULL) {
+        perror("Can't make temp data file");
+        exit(1);
+    }
+
+    writeHeader(fData, start_time);
+}
+
+void DmTrace::close()
+{
+    if (fTrace == NULL)
+        return;
+    writeKeyFile(fTrace);
+
+    // Take down how much data we wrote to the temp data file.
+    long size = ftell(fData);
+    // Rewind the data file and append its contents to the trace file.
+    rewind(fData);
+    char *data = (char *)malloc(size);
+    fread(data, size, 1, fData);
+    fwrite(data, size, 1, fTrace);
+    free(data);
+    fclose(fData);
+    fclose(fTrace);
+}
+
+/*
+ * Write values to the binary data file.
+ */
+void DmTrace::write2LE(FILE* fstream, unsigned short val)
+{
+    putc(val & 0xff, fstream);
+    putc(val >> 8, fstream);
+}
+
+void DmTrace::write4LE(FILE* fstream, unsigned int val)
+{
+    putc(val & 0xff, fstream);
+    putc((val >> 8) & 0xff, fstream);
+    putc((val >> 16) & 0xff, fstream);
+    putc((val >> 24) & 0xff, fstream);
+}
+
+void DmTrace::write8LE(FILE* fstream, unsigned long long val)
+{
+    putc(val & 0xff, fstream);
+    putc((val >> 8) & 0xff, fstream);
+    putc((val >> 16) & 0xff, fstream);
+    putc((val >> 24) & 0xff, fstream);
+    putc((val >> 32) & 0xff, fstream);
+    putc((val >> 40) & 0xff, fstream);
+    putc((val >> 48) & 0xff, fstream);
+    putc((val >> 56) & 0xff, fstream);
+}
+
+void DmTrace::writeHeader(FILE *fstream, uint64_t startTime)
+{
+    write4LE(fstream, header.magic);
+    write2LE(fstream, header.version);
+    write2LE(fstream, header.offset);
+    write8LE(fstream, startTime);
+}
+
+void DmTrace::writeDataRecord(FILE *fstream, int threadId,
+                             unsigned int methodVal,
+                             unsigned int elapsedTime)
+{
+    write2LE(fstream, threadId);
+    write4LE(fstream, methodVal);
+    write4LE(fstream, elapsedTime);
+}
+
+void DmTrace::addFunctionEntry(int functionId, uint32_t cycle, uint32_t pid)
+{
+    writeDataRecord(fData, pid, functionId, cycle);
+}
+
+void DmTrace::addFunctionExit(int functionId, uint32_t cycle, uint32_t pid)
+{
+    writeDataRecord(fData, pid, functionId | 1, cycle);
+}
+
+void DmTrace::addFunction(int functionId, const char *name)
+{
+    FunctionRecord *rec = new FunctionRecord;
+    rec->id = functionId;
+    rec->name = name;
+    functions->push_back(rec);
+}
+
+void DmTrace::addFunction(int functionId, const char *clazz,
+                          const char *method, const char *sig)
+{
+    // Allocate space for all the strings, plus 2 tab separators plus null byte.
+    // We currently don't reclaim this space.
+    int len = strlen(clazz) + strlen(method) + strlen(sig) + 3;
+    char *name = new char[len];
+    sprintf(name, "%s\t%s\t%s", clazz, method, sig);
+
+    addFunction(functionId, name);
+}
+
+void DmTrace::parseAndAddFunction(int functionId, const char *name)
+{
+    // Parse the "name" string into "class", "method" and "signature".
+    // The "name" string should look something like this:
+    //   name = "java.util.LinkedList.size()I"
+    // and it will be parsed into this:
+    //   clazz = "java.util.LinkedList"
+    //   method = "size"
+    //   sig = "()I"
+
+    // Find the first parenthesis, the start of the signature.
+    char *paren = strchr(name, '(');
+
+    // If not found, then add the original name.
+    if (paren == NULL) {
+        addFunction(functionId, name);
+        return;
+    }
+
+    // Copy the signature
+    int len = strlen(paren) + 1;
+    char *sig = new char[len];
+    strcpy(sig, paren);
+
+    // Zero the parenthesis so that we can search backwards from the signature
+    *paren = 0;
+
+    // Search for the last period, the start of the method name
+    char *dot = strrchr(name, '.');
+
+    // If not found, then add the original name.
+    if (dot == NULL || dot == name) {
+        delete[] sig;
+        *paren = '(';
+        addFunction(functionId, name);
+        return;
+    }
+
+    // Copy the method, not including the dot
+    len = strlen(dot + 1) + 1;
+    char *method = new char[len];
+    strcpy(method, dot + 1);
+
+    // Zero the dot to delimit the class name
+    *dot = 0;
+
+    addFunction(functionId, name, method, sig);
+
+    // Free the space we allocated.
+    delete[] sig;
+    delete[] method;
+}
+
+void DmTrace::addThread(int threadId, const char *name)
+{
+    ThreadRecord *rec = new ThreadRecord;
+    rec->id = threadId;
+    rec->name = name;
+    threads->push_back(rec);
+}
+
+void DmTrace::updateName(int threadId, const char *name)
+{
+    std::vector<ThreadRecord*>::iterator iter;
+
+    for (iter = threads->begin(); iter != threads->end(); ++iter) {
+        if ((*iter)->id == threadId) {
+            (*iter)->name = name;
+            return;
+        }
+    }
+}
+
+void DmTrace::writeKeyFile(FILE *fstream)
+{
+    fwrite(keyHeader, strlen(keyHeader), 1, fstream);
+    writeThreads(fstream);
+    writeFunctions(fstream);
+    fwrite(keyEnd, strlen(keyEnd), 1, fstream);
+}
+
+void DmTrace::writeThreads(FILE *fstream)
+{
+    std::vector<ThreadRecord*>::iterator iter;
+
+    fwrite(keyThreadHeader, strlen(keyThreadHeader), 1, fstream);
+    for (iter = threads->begin(); iter != threads->end(); ++iter) {
+        fprintf(fstream, "%d\t%s\n", (*iter)->id, (*iter)->name);
+    }
+}
+
+void DmTrace::writeFunctions(FILE *fstream)
+{
+    std::vector<FunctionRecord*>::iterator iter;
+
+    fwrite(keyFunctionHeader, strlen(keyFunctionHeader), 1, fstream);
+    for (iter = functions->begin(); iter != functions->end(); ++iter) {
+        fprintf(fstream, "0x%x\t%s\n", (*iter)->id, (*iter)->name);
+    }
+}
diff --git a/emulator/qtools/dmtrace.h b/emulator/qtools/dmtrace.h
new file mode 100644
index 0000000..6e20921
--- /dev/null
+++ b/emulator/qtools/dmtrace.h
@@ -0,0 +1,61 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef DMTRACE_H
+#define DMTRACE_H
+
+#include <vector>
+
+class DmTrace {
+  public:
+    struct Header {
+        uint32_t        magic;
+        uint16_t        version;
+        uint16_t        offset;
+        uint64_t        date_time;
+    };
+
+    DmTrace();
+    ~DmTrace();
+
+    void        open(const char *dmtrace_file, uint64_t startTime);
+    void        close();
+    void        addFunctionEntry(int methodId, uint32_t cycle, uint32_t pid);
+    void        addFunctionExit(int methodId, uint32_t cycle, uint32_t pid);
+    void        addFunction(int functionId, const char *name);
+    void        addFunction(int functionId, const char *clazz, const char *method,
+                            const char *sig);
+    void        parseAndAddFunction(int functionId, const char *name);
+    void        addThread(int threadId, const char *name);
+    void        updateName(int threadId, const char *name);
+
+  private:
+    static const Header header;
+
+    struct ThreadRecord {
+        int             id;
+        const char      *name;
+    };
+
+    struct FunctionRecord {
+        int             id;
+        const char      *name;
+    };
+
+    void        write2LE(FILE* fstream, unsigned short val);
+    void        write4LE(FILE* fstream, unsigned int val);
+    void        write8LE(FILE* fstream, unsigned long long val);
+    void        writeHeader(FILE *fstream, uint64_t startTime);
+    void        writeDataRecord(FILE *fstream, int threadId,
+                                unsigned int methodVal,
+                                unsigned int elapsedTime);
+    void        writeKeyFile(FILE *fstream);
+    void        writeThreads(FILE *fstream);
+    void        writeFunctions(FILE *fstream);
+
+    FILE        *fData;
+    FILE        *fTrace;
+    std::vector<ThreadRecord*> *threads;
+    std::vector<FunctionRecord*> *functions;
+};
+
+#endif  // DMTRACE_H
diff --git a/emulator/qtools/exc_dump.cpp b/emulator/qtools/exc_dump.cpp
new file mode 100644
index 0000000..166586f
--- /dev/null
+++ b/emulator/qtools/exc_dump.cpp
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "trace_reader_base.h"
+
+int main(int argc, char **argv) {
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s trace_file\n", argv[0]);
+        exit(1);
+    }
+
+    char *trace_filename = argv[1];
+    TraceReaderBase *trace = new TraceReaderBase;
+    trace->Open(trace_filename);
+
+    while (1) {
+        uint64_t time, recnum, bb_num, bb_start_time;
+        uint32_t pc, target_pc;
+        int num_insns;
+
+        if (trace->ReadExc(&time, &pc, &recnum, &target_pc, &bb_num,
+                           &bb_start_time, &num_insns))
+            break;
+        printf("time: %lld rec: %llu pc: %08x target: %08x bb: %llu bb_start: %llu insns: %d\n",
+               time, recnum, pc, target_pc, bb_num, bb_start_time, num_insns);
+    }
+    return 0;
+}
diff --git a/emulator/qtools/gtrace.cpp b/emulator/qtools/gtrace.cpp
new file mode 100644
index 0000000..673d8a4
--- /dev/null
+++ b/emulator/qtools/gtrace.cpp
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "gtrace.h"
+
+// A buffer of zeros
+static char zeros[Gtrace::kGtraceEntriesPerBlock * sizeof(Gtrace::trace_entry)];
+
+Gtrace::Gtrace() {
+  gtrace_file_ = NULL;
+  ftrace_ = NULL;
+  fnames_ = NULL;
+  start_sec_ = 0;
+  pdate_ = 0;
+  ptime_ = 0;
+  num_entries_ = 0;
+  blockno_ = 1;
+  current_pid_ = 0;
+}
+
+Gtrace::~Gtrace() {
+  if (ftrace_) {
+    // Extend the trace file to a multiple of 8k. Otherwise gtracepost64
+    // complains.
+    long pos = ftell(ftrace_);
+    long pos_end = (pos + 0x1fff) & ~0x1fff;
+    if (pos_end > pos) {
+      char ch = 0;
+      fseek(ftrace_, pos_end - 1, SEEK_SET);
+      fwrite(&ch, 1, 1, ftrace_);
+    }
+    fclose(ftrace_);
+  }
+  if (fnames_)
+    fclose(fnames_);
+}
+
+void Gtrace::Open(const char *gtrace_file, uint32_t pdate, uint32_t ptime)
+{
+  ftrace_ = fopen(gtrace_file, "w");
+  if (ftrace_ == NULL) {
+    perror(gtrace_file);
+    exit(1);
+  }
+  gtrace_file_ = gtrace_file;
+
+  pdate_ = pdate;
+  ptime_ = ptime;
+  sprintf(gname_file_, "gname_%x_%06x.txt", pdate, ptime);
+  fnames_ = fopen(gname_file_, "w");
+  if (fnames_ == NULL) {
+    perror(gname_file_);
+    exit(1);
+  }
+  fprintf(fnames_, "# File# Proc# Line# Name\n");
+}
+
+void Gtrace::WriteFirstHeader(uint32_t start_sec, uint32_t pid)
+{
+  first_header fh;
+  current_pid_ = pid;
+  start_sec_ = start_sec;
+  FillFirstHeader(start_sec, pid, &fh);
+  fwrite(&fh, sizeof(fh), 1, ftrace_);
+  num_entries_ = 8;
+}
+
+void Gtrace::FillFirstHeader(uint32_t start_sec, uint32_t pid,
+                             first_header *fh) {
+  int cpu = 0;
+  int max_files = 16;
+  int max_procedures = 12;
+
+  fh->common.blockno = 0;
+  fh->common.entry_width = 8;
+  fh->common.block_tic = kBaseTic;
+  fh->common.block_time = start_sec;
+  //fh->common.usec_cpu = (start_usec << 8) | (cpu & 0xff);
+  fh->common.usec_cpu = cpu & 0xff;
+  fh->common.pid = pid;
+  fh->common.bug_count = 0;
+  fh->common.zero_count = 0;
+
+  fh->tic = kBaseTic + 1;
+  fh->one = 1;
+  fh->tics_per_second = kTicsPerSecond;
+  fh->trace_time = start_sec;
+  fh->version = 5;
+  fh->file_proc = (max_files << 8) | max_procedures;
+  fh->pdate = pdate_;
+  fh->ptime = ptime_;
+}
+
+void Gtrace::WriteBlockHeader(uint32_t cycle, uint32_t pid)
+{
+  int cpu = 0;
+  block_header bh;
+
+  bh.blockno = blockno_++;
+  bh.entry_width = 8;
+  bh.block_tic = cycle + kBaseTic;
+  bh.block_time = start_sec_ + cycle / kTicsPerSecond;
+  //bh.usec_cpu = (start_usec << 8) | (cpu & 0xff);
+  bh.usec_cpu = cpu & 0xff;
+  bh.pid = pid;
+  bh.bug_count = 0;
+  bh.zero_count = 0;
+  fwrite(&bh, sizeof(bh), 1, ftrace_);
+}
+
+void Gtrace::AddGtraceRecord(int filenum, int procnum, uint32_t cycle, uint32_t pid,
+                             int is_exit)
+{
+  trace_entry	entry;
+
+  if (current_pid_ != pid) {
+    current_pid_ = pid;
+
+    // We are switching to a new process id, so pad the current block
+    // with zeros.
+    int num_zeros = (kGtraceEntriesPerBlock - num_entries_) * sizeof(entry);
+    fwrite(zeros, num_zeros, 1, ftrace_);
+    WriteBlockHeader(cycle, pid);
+    num_entries_ = 4;
+  }
+
+  // If the current block is full, write out a new block header
+  if (num_entries_ == kGtraceEntriesPerBlock) {
+    WriteBlockHeader(cycle, pid);
+    num_entries_ = 4;
+  }
+
+  entry.cycle = cycle + kBaseTic;
+  entry.event = (filenum << 13) | (procnum << 1) | is_exit;
+  fwrite(&entry, sizeof(entry), 1, ftrace_);
+  num_entries_ += 1;
+}
+
+void Gtrace::AddProcEntry(int filenum, int procnum, uint32_t cycle, uint32_t pid)
+{
+  AddGtraceRecord(filenum, procnum, cycle, pid, 0);
+}
+
+void Gtrace::AddProcExit(int filenum, int procnum, uint32_t cycle, uint32_t pid)
+{
+  AddGtraceRecord(filenum, procnum, cycle, pid, 1);
+}
+
+void Gtrace::AddProcedure(int filenum, int procnum, const char *proc_name)
+{
+  fprintf(fnames_, "%d %d %d %s\n", filenum, procnum, procnum, proc_name);
+}
diff --git a/emulator/qtools/gtrace.h b/emulator/qtools/gtrace.h
new file mode 100644
index 0000000..542adc2
--- /dev/null
+++ b/emulator/qtools/gtrace.h
@@ -0,0 +1,69 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef GTRACE_H
+#define GTRACE_H
+
+class Gtrace {
+ public:
+  static const int kGtraceEntriesPerBlock = 1024;
+  static const uint32_t kMillion = 1000000;
+  static const uint32_t kTicsPerSecond = 200 * kMillion;
+  static const int kBaseTic = 0x1000;
+
+  struct trace_entry {
+    uint32_t	cycle;
+    uint32_t	event;
+  };
+
+  struct block_header {
+    uint32_t	blockno;
+    uint32_t	entry_width;
+    uint32_t	block_tic;
+    uint32_t	block_time;
+    uint32_t	usec_cpu;
+    uint32_t	pid;
+    uint32_t	bug_count;
+    uint32_t	zero_count;
+  };
+
+  struct first_header {
+    block_header	common;
+    uint32_t		tic;
+    uint32_t		one;
+    uint32_t		tics_per_second;
+    uint32_t		trace_time;
+    uint32_t		version;
+    uint32_t		file_proc;
+    uint32_t		pdate;
+    uint32_t		ptime;
+  };
+
+  Gtrace();
+  ~Gtrace();
+
+  void		Open(const char *gtrace_file, uint32_t pdate, uint32_t ptime);
+  void		WriteFirstHeader(uint32_t start_sec, uint32_t pid);
+  void		AddProcedure(int filenum, int procnum, const char *proc_name);
+  void		AddProcEntry(int filenum, int procnum, uint32_t cycle, uint32_t pid);
+  void		AddProcExit(int filenum, int procnum, uint32_t cycle, uint32_t pid);
+
+ private:
+  void		AddGtraceRecord(int filenum, int procnum, uint32_t cycle, uint32_t pid,
+                                int is_exit);
+  void		FillFirstHeader(uint32_t start_sec, uint32_t pid,
+                                first_header *fh);
+  void		WriteBlockHeader(uint32_t cycle, uint32_t pid);
+
+  const char	*gtrace_file_;
+  char		gname_file_[100];
+  FILE		*ftrace_;
+  FILE		*fnames_;
+  uint32_t	start_sec_;
+  uint32_t	pdate_;
+  uint32_t	ptime_;
+  int		num_entries_;
+  int		blockno_;
+  uint32_t	current_pid_;
+};
+
+#endif  // GTRACE_H
diff --git a/emulator/qtools/hash_table.h b/emulator/qtools/hash_table.h
new file mode 100644
index 0000000..45786ec
--- /dev/null
+++ b/emulator/qtools/hash_table.h
@@ -0,0 +1,193 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef HASH_TABLE_H
+#define HASH_TABLE_H
+
+#include <string.h>
+#include <inttypes.h>
+
+template<class T>
+class HashTable {
+  public:
+    HashTable(int size, T default_value = T());
+    ~HashTable();
+
+    typedef struct entry {
+        entry    *next;
+        char     *key;
+        T        value;
+    } entry_type;
+
+    typedef T value_type;
+
+    void         Update(const char *key, T value);
+    T            Find(const char *key);
+    entry_type*  GetFirst();
+    entry_type*  GetNext();
+
+  private:
+    uint32_t     HashFunction(const char *key);
+
+    int          size_;
+    int          mask_;
+    T            default_value_;
+    entry_type   **table_;
+    int          num_entries_;
+    int          current_index_;
+    entry_type   *current_ptr_;
+};
+
+template<class T>
+HashTable<T>::HashTable(int size, T default_value)
+{
+    int pow2;
+
+    // Round up size to a power of two
+    for (pow2 = 2; pow2 < size; pow2 <<= 1)
+        ;    // empty body
+
+    size_ = pow2;
+    mask_ = pow2 - 1;
+    default_value_ = default_value;
+
+    // Allocate a table of pointers and initialize them all to NULL.
+    table_ = new entry_type*[size_];
+    for (int ii = 0; ii < size_; ++ii)
+        table_[ii] = NULL;
+    num_entries_ = 0;
+    current_index_ = 0;
+    current_ptr_ = NULL;
+}
+
+template<class T>
+HashTable<T>::~HashTable()
+{
+    for (int ii = 0; ii < size_; ++ii) {
+        entry_type *ptr, *next;
+
+        // Delete all the pointers in the chain at this table position.
+        // Save the next pointer before deleting each entry so that we
+        // don't dereference part of a deallocated object.
+        for (ptr = table_[ii]; ptr; ptr = next) {
+            next = ptr->next;
+            delete[] ptr->key;
+            delete ptr;
+        }
+    }
+    delete[] table_;
+}
+
+// Professor Daniel J. Bernstein's hash function.  See
+// http://www.partow.net/programming/hashfunctions/
+template<class T>
+uint32_t HashTable<T>::HashFunction(const char *key)
+{
+    uint32_t hash = 5381;
+
+    int len = strlen(key);
+    for(int ii = 0; ii < len; ++key, ++ii)
+        hash = ((hash << 5) + hash) + *key;
+
+    return hash;
+}
+
+template<class T>
+void HashTable<T>::Update(const char *key, T value)
+{
+    // Hash the key to get the table position
+    int len = strlen(key);
+    int pos = HashFunction(key) & mask_;
+
+    // Search the chain for a matching key
+    for (entry_type *ptr = table_[pos]; ptr; ptr = ptr->next) {
+        if (strcmp(ptr->key, key) == 0) {
+            ptr->value = value;
+            return;
+        }
+    }
+
+    // Create a new hash entry and fill in the values
+    entry_type *ptr = new entry_type;
+
+    // Copy the string
+    ptr->key = new char[len + 1];
+    strcpy(ptr->key, key);
+    ptr->value = value;
+
+    // Insert the new entry at the beginning of the list
+    ptr->next = table_[pos];
+    table_[pos] = ptr;
+    num_entries_ += 1;
+}
+
+template<class T>
+typename HashTable<T>::value_type HashTable<T>::Find(const char *key)
+{
+    // Hash the key to get the table position
+    int pos = HashFunction(key) & mask_;
+
+    // Search the chain for a matching key
+    for (entry_type *ptr = table_[pos]; ptr; ptr = ptr->next) {
+        if (strcmp(ptr->key, key) == 0)
+            return ptr->value;
+    }
+
+    // If we get here, then we didn't find the key
+    return default_value_;
+}
+
+template<class T>
+typename HashTable<T>::entry_type* HashTable<T>::GetFirst()
+{
+    // Find the first non-NULL table entry.
+    for (current_index_ = 0; current_index_ < size_; ++current_index_) {
+        if (table_[current_index_])
+            break;
+    }
+
+    // If there are no table entries, then return NULL.
+    if (current_index_ == size_)
+        return NULL;
+
+    // Remember and return the current element.
+    current_ptr_ = table_[current_index_];
+    return current_ptr_;
+}
+
+template<class T>
+typename HashTable<T>::entry_type* HashTable<T>::GetNext()
+{
+    // If we already iterated part way through the hash table, then continue
+    // to the next element.
+    if (current_ptr_) {
+        current_ptr_ = current_ptr_->next;
+
+        // If we are pointing to a valid element, then return it.
+        if (current_ptr_)
+            return current_ptr_;
+
+        // Otherwise, start searching at the next table index.
+        current_index_ += 1;
+    }
+
+    // Find the next non-NULL table entry.
+    for (; current_index_ < size_; ++current_index_) {
+        if (table_[current_index_])
+            break;
+    }
+
+    // If there are no more non-NULL table entries, then return NULL.
+    if (current_index_ == size_) {
+        // Reset the current index so that we will start over from the
+        // beginning on the next call to GetNext().
+        current_index_ = 0;
+        return NULL;
+    }
+
+    // Remember and return the current element.
+    current_ptr_ = table_[current_index_];
+    return current_ptr_;
+}
+
+
+#endif  // HASH_TABLE_H
diff --git a/emulator/qtools/hist_trace.cpp b/emulator/qtools/hist_trace.cpp
new file mode 100644
index 0000000..d2c6a90
--- /dev/null
+++ b/emulator/qtools/hist_trace.cpp
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "trace_reader.h"
+
+static const int kMaxHistEntries = 256;
+static const int kMaxHistEntries2 = kMaxHistEntries /  2;
+int hist[kMaxHistEntries];
+int underflow, overflow;
+
+int main(int argc, char **argv) {
+  if (argc != 2) {
+    fprintf(stderr, "Usage: %s trace_file\n", argv[0]);
+    exit(1);
+  }
+
+  char *trace_filename = argv[1];
+  TraceReaderBase *trace = new TraceReaderBase;
+  trace->Open(trace_filename);
+
+  uint64_t prev_bb_num = 0;
+  uint64_t prev_time = 0;
+  int total = 0;
+  
+  while (1) {
+    BBEvent event;
+
+    if (trace->ReadBB(&event))
+      break;
+    int bb_diff = event.bb_num - prev_bb_num;
+    //int time_diff = event.time - prev_time;
+    //printf("bb_num: %llu prev: %llu, diff: %d\n",
+    // event.bb_num, prev_bb_num, bb_diff);
+    prev_bb_num = event.bb_num;
+    prev_time = event.time;
+
+    bb_diff += kMaxHistEntries2;
+    if (bb_diff < 0)
+      underflow += 1;
+    else if (bb_diff >= kMaxHistEntries)
+      overflow += 1;
+    else
+      hist[bb_diff] += 1;
+    total += 1;
+  }
+
+  int sum = 0;
+  double sum_per = 0;
+  double per = 0;
+  for (int ii = 0; ii < kMaxHistEntries; ++ii) {
+    if (hist[ii] == 0)
+      continue;
+    per = 100.0 * hist[ii] / total;
+    sum += hist[ii];
+    sum_per = 100.0 * sum / total;
+    printf(" %4d: %6d %6.2f %6.2f\n", ii - kMaxHistEntries2, hist[ii], per, sum_per);
+  }
+  per = 100.0 * underflow / total;
+  printf("under: %6d %6.2f\n", underflow, per);
+  per = 100.0 * overflow / total;
+  printf("over:  %6d %6.2f\n", overflow, per);
+  printf("total: %6d\n", total);
+  return 0;
+}
diff --git a/emulator/qtools/opcode.cpp b/emulator/qtools/opcode.cpp
new file mode 100644
index 0000000..41bef3a
--- /dev/null
+++ b/emulator/qtools/opcode.cpp
@@ -0,0 +1,204 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <inttypes.h>
+#include "opcode.h"
+
+// Note: this array depends on the Opcode enum defined in opcode.h
+uint32_t opcode_flags[] = {
+    0,                                             // OP_INVALID
+    0,                                             // OP_UNDEFINED
+    kCatAlu,                                       // OP_ADC
+    kCatAlu,                                       // OP_ADD
+    kCatAlu,                                       // OP_AND
+    kCatBranch,                                    // OP_B
+    kCatBranch | kCatBranchLink,                   // OP_BL
+    kCatAlu,                                       // OP_BIC
+    0,                                             // OP_BKPT
+    kCatBranch | kCatBranchLink | kCatBranchExch,  // OP_BLX
+    kCatBranch | kCatBranchExch,                   // OP_BX
+    kCatCoproc,                                    // OP_CDP
+    kCatAlu,                                       // OP_CLZ
+    kCatAlu,                                       // OP_CMN
+    kCatAlu,                                       // OP_CMP
+    kCatAlu,                                       // OP_EOR
+    kCatCoproc | kCatLoad,                         // OP_LDC
+    kCatLoad | kCatMultiple,                       // OP_LDM
+    kCatLoad | kCatWord,                           // OP_LDR
+    kCatLoad | kCatByte,                           // OP_LDRB
+    kCatLoad | kCatByte,                           // OP_LDRBT
+    kCatLoad | kCatHalf,                           // OP_LDRH
+    kCatLoad | kCatByte | kCatSigned,              // OP_LDRSB
+    kCatLoad | kCatHalf | kCatSigned,              // OP_LDRSH
+    kCatLoad | kCatWord,                           // OP_LDRT
+    kCatCoproc,                                    // OP_MCR
+    kCatAlu,                                       // OP_MLA
+    kCatAlu,                                       // OP_MOV
+    kCatCoproc,                                    // OP_MRC
+    0,                                             // OP_MRS
+    0,                                             // OP_MSR
+    kCatAlu,                                       // OP_MUL
+    kCatAlu,                                       // OP_MVN
+    kCatAlu,                                       // OP_ORR
+    0,                                             // OP_PLD
+    kCatAlu,                                       // OP_RSB
+    kCatAlu,                                       // OP_RSC
+    kCatAlu,                                       // OP_SBC
+    kCatAlu,                                       // OP_SMLAL
+    kCatAlu,                                       // OP_SMULL
+    kCatCoproc | kCatStore,                        // OP_STC
+    kCatStore | kCatMultiple,                      // OP_STM
+    kCatStore | kCatWord,                          // OP_STR
+    kCatStore | kCatByte,                          // OP_STRB
+    kCatStore | kCatByte,                          // OP_STRBT
+    kCatStore | kCatHalf,                          // OP_STRH
+    kCatStore | kCatWord,                          // OP_STRT
+    kCatAlu,                                       // OP_SUB
+    0,                                             // OP_SWI
+    kCatLoad | kCatStore,                          // OP_SWP
+    kCatLoad | kCatStore | kCatByte,               // OP_SWPB
+    kCatAlu,                                       // OP_TEQ
+    kCatAlu,                                       // OP_TST
+    kCatAlu,                                       // OP_UMLAL
+    kCatAlu,                                       // OP_UMULL
+
+    0,                                             // OP_THUMB_UNDEFINED,
+    kCatAlu,                                       // OP_THUMB_ADC,
+    kCatAlu,                                       // OP_THUMB_ADD,
+    kCatAlu,                                       // OP_THUMB_AND,
+    kCatAlu,                                       // OP_THUMB_ASR,
+    kCatBranch,                                    // OP_THUMB_B,
+    kCatAlu,                                       // OP_THUMB_BIC,
+    0,                                             // OP_THUMB_BKPT,
+    kCatBranch | kCatBranchLink,                   // OP_THUMB_BL,
+    kCatBranch | kCatBranchLink | kCatBranchExch,  // OP_THUMB_BLX,
+    kCatBranch | kCatBranchExch,                   // OP_THUMB_BX,
+    kCatAlu,                                       // OP_THUMB_CMN,
+    kCatAlu,                                       // OP_THUMB_CMP,
+    kCatAlu,                                       // OP_THUMB_EOR,
+    kCatLoad | kCatMultiple,                       // OP_THUMB_LDMIA,
+    kCatLoad | kCatWord,                           // OP_THUMB_LDR,
+    kCatLoad | kCatByte,                           // OP_THUMB_LDRB,
+    kCatLoad | kCatHalf,                           // OP_THUMB_LDRH,
+    kCatLoad | kCatByte | kCatSigned,              // OP_THUMB_LDRSB,
+    kCatLoad | kCatHalf | kCatSigned,              // OP_THUMB_LDRSH,
+    kCatAlu,                                       // OP_THUMB_LSL,
+    kCatAlu,                                       // OP_THUMB_LSR,
+    kCatAlu,                                       // OP_THUMB_MOV,
+    kCatAlu,                                       // OP_THUMB_MUL,
+    kCatAlu,                                       // OP_THUMB_MVN,
+    kCatAlu,                                       // OP_THUMB_NEG,
+    kCatAlu,                                       // OP_THUMB_ORR,
+    kCatLoad | kCatMultiple,                       // OP_THUMB_POP,
+    kCatStore | kCatMultiple,                      // OP_THUMB_PUSH,
+    kCatAlu,                                       // OP_THUMB_ROR,
+    kCatAlu,                                       // OP_THUMB_SBC,
+    kCatStore | kCatMultiple,                      // OP_THUMB_STMIA,
+    kCatStore | kCatWord,                          // OP_THUMB_STR,
+    kCatStore | kCatByte,                          // OP_THUMB_STRB,
+    kCatStore | kCatHalf,                          // OP_THUMB_STRH,
+    kCatAlu,                                       // OP_THUMB_SUB,
+    0,                                             // OP_THUMB_SWI,
+    kCatAlu,                                       // OP_THUMB_TST,
+
+    0,                                             // OP_END
+};
+
+const char *opcode_names[] = {
+    "invalid",
+    "undefined",
+    "adc",
+    "add",
+    "and",
+    "b",
+    "bl",
+    "bic",
+    "bkpt",
+    "blx",
+    "bx",
+    "cdp",
+    "clz",
+    "cmn",
+    "cmp",
+    "eor",
+    "ldc",
+    "ldm",
+    "ldr",
+    "ldrb",
+    "ldrbt",
+    "ldrh",
+    "ldrsb",
+    "ldrsh",
+    "ldrt",
+    "mcr",
+    "mla",
+    "mov",
+    "mrc",
+    "mrs",
+    "msr",
+    "mul",
+    "mvn",
+    "orr",
+    "pld",
+    "rsb",
+    "rsc",
+    "sbc",
+    "smlal",
+    "smull",
+    "stc",
+    "stm",
+    "str",
+    "strb",
+    "strbt",
+    "strh",
+    "strt",
+    "sub",
+    "swi",
+    "swp",
+    "swpb",
+    "teq",
+    "tst",
+    "umlal",
+    "umull",
+
+    "undefined",
+    "adc",
+    "add",
+    "and",
+    "asr",
+    "b",
+    "bic",
+    "bkpt",
+    "bl",
+    "blx",
+    "bx",
+    "cmn",
+    "cmp",
+    "eor",
+    "ldmia",
+    "ldr",
+    "ldrb",
+    "ldrh",
+    "ldrsb",
+    "ldrsh",
+    "lsl",
+    "lsr",
+    "mov",
+    "mul",
+    "mvn",
+    "neg",
+    "orr",
+    "pop",
+    "push",
+    "ror",
+    "sbc",
+    "stmia",
+    "str",
+    "strb",
+    "strh",
+    "sub",
+    "swi",
+    "tst",
+
+    NULL
+};
diff --git a/emulator/qtools/opcode.h b/emulator/qtools/opcode.h
new file mode 100644
index 0000000..c8b67a6
--- /dev/null
+++ b/emulator/qtools/opcode.h
@@ -0,0 +1,166 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef OPCODE_H
+#define OPCODE_H
+
+#include <inttypes.h>
+
+// Note: this list of opcodes must match the list used to initialize
+// the opflags[] array in opcode.cpp.
+enum Opcode {
+    OP_INVALID,
+    OP_UNDEFINED,
+    OP_ADC,
+    OP_ADD,
+    OP_AND,
+    OP_B,
+    OP_BL,
+    OP_BIC,
+    OP_BKPT,
+    OP_BLX,
+    OP_BX,
+    OP_CDP,
+    OP_CLZ,
+    OP_CMN,
+    OP_CMP,
+    OP_EOR,
+    OP_LDC,
+    OP_LDM,
+    OP_LDR,
+    OP_LDRB,
+    OP_LDRBT,
+    OP_LDRH,
+    OP_LDRSB,
+    OP_LDRSH,
+    OP_LDRT,
+    OP_MCR,
+    OP_MLA,
+    OP_MOV,
+    OP_MRC,
+    OP_MRS,
+    OP_MSR,
+    OP_MUL,
+    OP_MVN,
+    OP_ORR,
+    OP_PLD,
+    OP_RSB,
+    OP_RSC,
+    OP_SBC,
+    OP_SMLAL,
+    OP_SMULL,
+    OP_STC,
+    OP_STM,
+    OP_STR,
+    OP_STRB,
+    OP_STRBT,
+    OP_STRH,
+    OP_STRT,
+    OP_SUB,
+    OP_SWI,
+    OP_SWP,
+    OP_SWPB,
+    OP_TEQ,
+    OP_TST,
+    OP_UMLAL,
+    OP_UMULL,
+
+    // Define thumb opcodes
+    OP_THUMB_UNDEFINED,
+    OP_THUMB_ADC,
+    OP_THUMB_ADD,
+    OP_THUMB_AND,
+    OP_THUMB_ASR,
+    OP_THUMB_B,
+    OP_THUMB_BIC,
+    OP_THUMB_BKPT,
+    OP_THUMB_BL,
+    OP_THUMB_BLX,
+    OP_THUMB_BX,
+    OP_THUMB_CMN,
+    OP_THUMB_CMP,
+    OP_THUMB_EOR,
+    OP_THUMB_LDMIA,
+    OP_THUMB_LDR,
+    OP_THUMB_LDRB,
+    OP_THUMB_LDRH,
+    OP_THUMB_LDRSB,
+    OP_THUMB_LDRSH,
+    OP_THUMB_LSL,
+    OP_THUMB_LSR,
+    OP_THUMB_MOV,
+    OP_THUMB_MUL,
+    OP_THUMB_MVN,
+    OP_THUMB_NEG,
+    OP_THUMB_ORR,
+    OP_THUMB_POP,
+    OP_THUMB_PUSH,
+    OP_THUMB_ROR,
+    OP_THUMB_SBC,
+    OP_THUMB_STMIA,
+    OP_THUMB_STR,
+    OP_THUMB_STRB,
+    OP_THUMB_STRH,
+    OP_THUMB_SUB,
+    OP_THUMB_SWI,
+    OP_THUMB_TST,
+
+    OP_END                // must be last
+};
+
+extern uint32_t opcode_flags[];
+extern const char *opcode_names[];
+
+// Define bit flags for the opcode categories
+static const uint32_t kCatByte          = 0x0001;
+static const uint32_t kCatHalf          = 0x0002;
+static const uint32_t kCatWord          = 0x0004;
+static const uint32_t kCatLong          = 0x0008;
+static const uint32_t kCatNumBytes      = (kCatByte | kCatHalf | kCatWord | kCatLong);
+static const uint32_t kCatMultiple      = 0x0010;
+static const uint32_t kCatSigned        = 0x0020;
+static const uint32_t kCatLoad          = 0x0040;
+static const uint32_t kCatStore         = 0x0080;
+static const uint32_t kCatMemoryRef     = (kCatLoad | kCatStore);
+static const uint32_t kCatAlu           = 0x0100;
+static const uint32_t kCatBranch        = 0x0200;
+static const uint32_t kCatBranchLink    = 0x0400;
+static const uint32_t kCatBranchExch    = 0x0800;
+static const uint32_t kCatCoproc        = 0x1000;
+static const uint32_t kCatLoadMultiple  = (kCatLoad | kCatMultiple);
+static const uint32_t kCatStoreMultiple = (kCatStore | kCatMultiple);
+
+inline bool isALU(Opcode op)    { return (opcode_flags[op] & kCatAlu) != 0; }
+inline bool isBranch(Opcode op) { return (opcode_flags[op] & kCatBranch) != 0; }
+inline bool isBranchLink(Opcode op) {
+    return (opcode_flags[op] & kCatBranchLink) != 0;
+}
+inline bool isBranchExch(Opcode op) {
+    return (opcode_flags[op] & kCatBranchExch) != 0;
+}
+inline bool isLoad(Opcode op)   { return (opcode_flags[op] & kCatLoad) != 0; }
+inline bool isLoadMultiple(Opcode op) {
+    return (opcode_flags[op] & kCatLoadMultiple) == kCatLoadMultiple;
+}
+inline bool isStoreMultiple(Opcode op) {
+    return (opcode_flags[op] & kCatStoreMultiple) == kCatStoreMultiple;
+}
+inline bool isStore(Opcode op)  { return (opcode_flags[op] & kCatStore) != 0; }
+inline bool isSigned(Opcode op) { return (opcode_flags[op] & kCatSigned) != 0; }
+inline bool isMemoryRef(Opcode op) {
+    return (opcode_flags[op] & kCatMemoryRef) != 0;
+}
+inline int getAccessSize(Opcode op) { return opcode_flags[op] & kCatNumBytes; }
+inline bool isCoproc(Opcode op) { return (opcode_flags[op] & kCatCoproc) != 0; }
+inline int getNumAccesses(Opcode op, uint32_t binary) {
+  extern int num_one_bits[];
+  int num_accesses = 0;
+  if (opcode_flags[op] & kCatNumBytes)
+    num_accesses = 1;
+  else if (opcode_flags[op] & kCatMultiple) {
+    num_accesses = num_one_bits[(binary >> 8) & 0xff]
+                   + num_one_bits[binary & 0xff];
+  }
+  return num_accesses;
+}
+
+#endif  // OPCODE_H
diff --git a/emulator/qtools/parse_options-inl.h b/emulator/qtools/parse_options-inl.h
new file mode 100644
index 0000000..f218cc1
--- /dev/null
+++ b/emulator/qtools/parse_options-inl.h
@@ -0,0 +1,147 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef PARSE_OPTIONS_INL_H
+#define PARSE_OPTIONS_INL_H
+
+// Define a typedef for TraceReaderType and include "parse_options.h"
+// before including this header file in a C++ source file.
+//
+// For example:
+// 
+// struct symbol {
+//   int  elapsed;
+// };
+// 
+// typedef TraceReader<symbol> TraceReaderType;
+
+
+typedef TraceReaderType::symbol_type symbol_type;
+typedef TraceReaderType::region_type region_type;
+typedef TraceReaderType::ProcessState ProcessState;
+
+symbol_type *kernel_sym;
+symbol_type *library_sym;
+
+// Returns true if the given event is included (or not excluded)
+// from the list of valid events specified by the user on the
+// command line.
+inline bool IsValidEvent(BBEvent *event, symbol_type *sym)
+{
+  if (include_some_pids && pid_include_vector.GetBit(event->pid) == 0)
+      return false;
+  if (exclude_some_pids && pid_exclude_vector.GetBit(event->pid))
+      return false;
+  if (include_some_procedures) {
+    if (sym == NULL || included_procedures.Find(sym->name) == 0)
+      return false;
+  }
+  if (exclude_some_procedures) {
+    if (sym == NULL || excluded_procedures.Find(sym->name))
+      return false;
+  }
+  return true;
+}
+
+inline symbol_type *GetSymbol(TraceReaderType *trace, int pid, uint32_t addr,
+                              uint64_t time)
+{
+  symbol_type *sym = trace->LookupFunction(pid, addr, time);
+
+  if (lump_kernel && (sym->region->flags & region_type::kIsKernelRegion)) {
+    if (kernel_sym == NULL) {
+      kernel_sym = sym;
+      sym->name = ":kernel";
+    } else {
+      sym = kernel_sym;
+    }
+  }
+
+  if (lump_libraries && (sym->region->flags & region_type::kIsLibraryRegion)) {
+    if (library_sym == NULL) {
+      library_sym = sym;
+      sym->name = ":libs";
+    } else {
+      sym = library_sym;
+    }
+  }
+
+  return sym;
+}
+
+inline bool IsIncludedProcedure(symbol_type *sym)
+{
+  if (include_kernel_syms && (sym->region->flags & region_type::kIsKernelRegion))
+    return true;
+  if (include_library_syms && (sym->region->flags & region_type::kIsLibraryRegion))
+    return true;
+  return included_procedures.Find(sym->name);
+}
+
+inline bool IsExcludedProcedure(symbol_type *sym)
+{
+  if (exclude_kernel_syms && (sym->region->flags & region_type::kIsKernelRegion))
+    return true;
+  if (exclude_library_syms && (sym->region->flags & region_type::kIsLibraryRegion))
+    return true;
+  return excluded_procedures.Find(sym->name);
+}
+
+// Returns true on end-of-file.
+inline bool GetNextValidEvent(TraceReaderType *trace,
+                              BBEvent *event,
+                              BBEvent *first_ignored_event,
+                              symbol_type **sym_ptr)
+{
+  symbol_type *sym = NULL;
+  first_ignored_event->time = 0;
+  if (trace->ReadBB(event))
+    return true;
+  bool recheck = true;
+  while (recheck) {
+    recheck = false;
+    if (include_some_pids) {
+      while (pid_include_vector.GetBit(event->pid) == 0) {
+        if (first_ignored_event->time == 0)
+          *first_ignored_event = *event;
+        if (trace->ReadBB(event))
+          return true;
+      }
+    } else if (exclude_some_pids) {
+      while (pid_exclude_vector.GetBit(event->pid)) {
+        if (first_ignored_event->time == 0)
+          *first_ignored_event = *event;
+        if (trace->ReadBB(event))
+          return true;
+      }
+    }
+
+    if (include_some_procedures) {
+      sym = GetSymbol(trace, event->pid, event->bb_addr, event->time);
+      while (!IsIncludedProcedure(sym)) {
+        if (first_ignored_event->time == 0)
+          *first_ignored_event = *event;
+        if (trace->ReadBB(event))
+          return true;
+        recheck = true;
+        sym = GetSymbol(trace, event->pid, event->bb_addr, event->time);
+      }
+    } else if (exclude_some_procedures) {
+      sym = GetSymbol(trace, event->pid, event->bb_addr, event->time);
+      while (IsExcludedProcedure(sym)) {
+        if (first_ignored_event->time == 0)
+          *first_ignored_event = *event;
+        if (trace->ReadBB(event))
+          return true;
+        recheck = true;
+        sym = GetSymbol(trace, event->pid, event->bb_addr, event->time);
+      }
+    }
+  }
+  if (sym == NULL)
+    sym = GetSymbol(trace, event->pid, event->bb_addr, event->time);
+
+  *sym_ptr = sym;
+  return false;
+}
+
+#endif  // PARSE_OPTIONS_INL_H
diff --git a/emulator/qtools/parse_options.cpp b/emulator/qtools/parse_options.cpp
new file mode 100644
index 0000000..395e9a1
--- /dev/null
+++ b/emulator/qtools/parse_options.cpp
@@ -0,0 +1,119 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include "bitvector.h"
+#include "parse_options.h"
+#include "hash_table.h"
+
+const char *root = "";
+bool lump_kernel;
+bool lump_libraries;
+Bitvector pid_include_vector(32768);
+Bitvector pid_exclude_vector(32768);
+bool include_some_pids;
+bool exclude_some_pids;
+
+HashTable<int> excluded_procedures(2000);
+HashTable<int> included_procedures(2000);
+bool exclude_some_procedures;
+bool include_some_procedures;
+
+bool exclude_kernel_syms;
+bool exclude_library_syms;
+bool include_kernel_syms;
+bool include_library_syms;
+bool demangle = true;
+
+static const char *OptionsUsageStr =
+    "  -e :kernel exclude all kernel symbols\n"
+    "  -e :libs   exclude all library symbols\n"
+    "  -e <func>  exclude function <func>\n"
+    "  -e <pid>   exclude process <pid>\n"
+    "  -i :kernel include all kernel symbols\n"
+    "  -i :libs   include all library symbols\n"
+    "  -i <func>  include function <func>\n"
+    "  -i <pid>   include process <pid>\n"
+    "  -l :kernel lump all the kernel symbols together\n"
+    "  -l :libs   lump all the library symbols together\n"
+    "  -m         do not demangle C++ symbols (m for 'mangle')\n"
+    "  -r <root>  use <root> as the path for finding ELF executables\n"
+    ;
+
+void OptionsUsage()
+{
+    fprintf(stderr, "%s", OptionsUsageStr);
+}
+
+void ParseOptions(int argc, char **argv)
+{
+    bool err = false;
+    while (!err) {
+        int opt = getopt(argc, argv, "+e:i:l:mr:");
+        if (opt == -1)
+            break;
+        switch (opt) {
+        case 'e':
+            if (*optarg == ':') {
+                if (strcmp(optarg, ":kernel") == 0)
+                    exclude_kernel_syms = true;
+                else if (strcmp(optarg, ":libs") == 0)
+                    exclude_library_syms = true;
+                else
+                    err = true;
+                excluded_procedures.Update(optarg, 1);
+                exclude_some_procedures = true;
+            } else if (isdigit(*optarg)) {
+                int bitnum = atoi(optarg);
+                pid_exclude_vector.SetBit(bitnum);
+                exclude_some_pids = true;
+            } else {
+                excluded_procedures.Update(optarg, 1);
+                exclude_some_procedures = true;
+            }
+            break;
+        case 'i':
+            if (*optarg == ':') {
+                if (strcmp(optarg, ":kernel") == 0)
+                    include_kernel_syms = true;
+                else if (strcmp(optarg, ":libs") == 0)
+                    include_library_syms = true;
+                else
+                    err = true;
+                included_procedures.Update(optarg, 1);
+                include_some_procedures = true;
+            } else if (isdigit(*optarg)) {
+                int bitnum = atoi(optarg);
+                pid_include_vector.SetBit(bitnum);
+                include_some_pids = true;
+            } else {
+                included_procedures.Update(optarg, 1);
+                include_some_procedures = true;
+            }
+            break;
+        case 'l':
+            if (strcmp(optarg, ":kernel") == 0)
+                lump_kernel = true;
+            else if (strcmp(optarg, ":libs") == 0)
+                lump_libraries = true;
+            else
+                err = true;
+            break;
+        case 'm':
+            demangle = false;
+            break;
+        case 'r':
+            root = optarg;
+            break;
+        default:
+            err = true;
+            break;
+        }
+    }
+
+    if (err) {
+        Usage(argv[0]);
+        exit(1);
+    }
+}
diff --git a/emulator/qtools/parse_options.h b/emulator/qtools/parse_options.h
new file mode 100644
index 0000000..aacbb9e
--- /dev/null
+++ b/emulator/qtools/parse_options.h
@@ -0,0 +1,32 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef PARSE_OPTIONS_H
+#define PARSE_OPTIONS_H
+
+#include "bitvector.h"
+#include "hash_table.h"
+
+extern const char *root;
+extern bool lump_kernel;
+extern bool lump_libraries;
+extern Bitvector pid_include_vector;
+extern Bitvector pid_exclude_vector;
+extern bool include_some_pids;
+extern bool exclude_some_pids;
+
+extern HashTable<int> excluded_procedures;
+extern HashTable<int> included_procedures;
+extern bool exclude_some_procedures;
+extern bool include_some_procedures;
+
+extern bool exclude_kernel_syms;
+extern bool exclude_library_syms;
+extern bool include_kernel_syms;
+extern bool include_library_syms;
+extern bool demangle;
+
+extern void Usage(const char *program);
+extern void ParseOptions(int argc, char **argv);
+extern void OptionsUsage();
+
+#endif  // PARSE_OPTIONS_H
diff --git a/emulator/qtools/post_trace.cpp b/emulator/qtools/post_trace.cpp
new file mode 100644
index 0000000..99525fb
--- /dev/null
+++ b/emulator/qtools/post_trace.cpp
@@ -0,0 +1,151 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "trace_reader.h"
+
+typedef struct MyStaticRec {
+  StaticRec bb;
+  uint32_t  *insns;
+} MyStaticRec;
+
+const int kNumPids = 32768;
+char usedPids[kNumPids];
+
+int main(int argc, char **argv) {
+  uint32_t insns[kMaxInsnPerBB];
+
+  if (argc != 2) {
+    fprintf(stderr, "Usage: %s trace_file\n", argv[0]);
+    exit(1);
+  }
+
+  char *trace_filename = argv[1];
+  TraceReaderBase *trace = new TraceReaderBase;
+  trace->SetPostProcessing(true);
+  trace->Open(trace_filename);
+
+  // Count the number of static basic blocks and instructions.
+  uint64_t num_static_bb = 0;
+  uint64_t num_static_insn = 0;
+  while (1) {
+    StaticRec static_rec;
+
+    if (trace->ReadStatic(&static_rec))
+      break;
+    if (static_rec.bb_num != num_static_bb) {
+      fprintf(stderr,
+              "Error: basic block numbers out of order; expected %lld, got %lld\n",
+              num_static_bb, static_rec.bb_num);
+      exit(1);
+    }
+    num_static_bb += 1;
+    num_static_insn += static_rec.num_insns;
+    trace->ReadStaticInsns(static_rec.num_insns, insns);
+  }
+  trace->Close();
+
+  // Allocate space for all of the static blocks
+  MyStaticRec *blocks = new MyStaticRec[num_static_bb];
+
+  // Read the static blocks again and save pointers to them
+  trace->Open(trace_filename);
+  for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
+    trace->ReadStatic(&blocks[ii].bb);
+    uint32_t num_insns = blocks[ii].bb.num_insns;
+    if (num_insns > 0) {
+      blocks[ii].insns = new uint32_t[num_insns];
+      trace->ReadStaticInsns(num_insns, blocks[ii].insns);
+    }
+  }
+
+  // Check the last basic block.  If it contains a special undefined
+  // instruction, then truncate the basic block at that point.
+  uint32_t num_insns = blocks[num_static_bb - 1].bb.num_insns;
+  uint32_t *insn_ptr = blocks[num_static_bb - 1].insns;
+  for (uint32_t ii = 0; ii < num_insns; ++ii, ++insn_ptr) {
+    if (*insn_ptr == 0xe6c00110) {
+      uint32_t actual_num_insns = ii + 1;
+      blocks[num_static_bb - 1].bb.num_insns = actual_num_insns;
+      num_static_insn -= (num_insns - actual_num_insns);
+
+      // Write the changes back to the trace file
+      trace->TruncateLastBlock(actual_num_insns);
+      break;
+    }
+  }
+  TraceHeader *header = trace->GetHeader();
+  strcpy(header->ident, TRACE_IDENT);
+  header->num_static_bb = num_static_bb;
+  header->num_dynamic_bb = 0;
+  header->num_static_insn = num_static_insn;
+  header->num_dynamic_insn = 0;
+  trace->WriteHeader(header);
+
+  // Reopen the trace file in order to force the trace manager to reread
+  // the static blocks now that we have written that information to the
+  // header.
+  trace->Close();
+  trace->Open(trace_filename);
+
+  // Count the number of dynamic executions of basic blocks and instructions.
+  // Also keep track of which process ids are used.
+  uint64_t num_dynamic_bb = 0;
+  uint64_t num_dynamic_insn = 0;
+  while (1) {
+    BBEvent event;
+
+    if (trace->ReadBB(&event))
+      break;
+    if (event.bb_num >= num_static_bb) {
+      fprintf(stderr,
+              "Error: basic block number (%lld) too large (num blocks: %lld)\n",
+              event.bb_num, num_static_bb);
+      exit(1);
+    }
+    usedPids[event.pid] = 1;
+    num_dynamic_bb += 1;
+    num_dynamic_insn += event.num_insns;
+  }
+
+  // Count the number of process ids that are used and remember the first
+  // unused pid.
+  int numUsedPids = 0;
+  int unusedPid = -1;
+  for (int pid = 0; pid < kNumPids; pid++) {
+      if (usedPids[pid] == 1) {
+          numUsedPids += 1;
+      } else if (unusedPid == -1) {
+          unusedPid = pid;
+      }
+  }
+
+  // Rewrite the header with the dynamic counts
+  header->num_dynamic_bb = num_dynamic_bb;
+  header->num_dynamic_insn = num_dynamic_insn;
+  header->num_used_pids = numUsedPids;
+  header->first_unused_pid = unusedPid;
+  trace->WriteHeader(header);
+  trace->Close();
+
+  printf("Static basic blocks: %llu, Dynamic basic blocks: %llu\n",
+         num_static_bb, num_dynamic_bb);
+  printf("Static instructions: %llu, Dynamic instructions: %llu\n",
+         num_static_insn, num_dynamic_insn);
+
+  double elapsed_secs = header->elapsed_usecs / 1000000.0;
+  double insn_per_sec = 0;
+  if (elapsed_secs != 0)
+    insn_per_sec = num_dynamic_insn / elapsed_secs;
+  char *suffix = "";
+  if (insn_per_sec >= 1000000) {
+    insn_per_sec /= 1000000.0;
+    suffix = "M";
+  } else if (insn_per_sec > 1000) {
+    insn_per_sec /= 1000.0;
+    suffix = "K";
+  }
+  printf("Elapsed seconds: %.2f, simulated instructions/sec: %.1f%s\n",
+         elapsed_secs, insn_per_sec, suffix);
+  return 0;
+}
diff --git a/emulator/qtools/profile_pid.cpp b/emulator/qtools/profile_pid.cpp
new file mode 100644
index 0000000..aa37847
--- /dev/null
+++ b/emulator/qtools/profile_pid.cpp
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include "trace_reader.h"
+#include "parse_options.h"
+
+typedef TraceReader<> TraceReaderType;
+
+#include "parse_options-inl.h"
+
+// This function is called from quicksort to compare the cpu time
+// of processes and sort into decreasing order.
+int cmp_dec_cpu_time(const void *a, const void *b) {
+  ProcessState *proc1, *proc2;
+
+  proc1 = (ProcessState*)a;
+  proc2 = (ProcessState*)b;
+  if (proc1 == NULL) {
+    if (proc2 == NULL)
+      return 0;
+    return 1;
+  }
+  if (proc2 == NULL)
+    return -1;
+  if (proc1->cpu_time < proc2->cpu_time)
+    return 1;
+  if (proc1->cpu_time > proc2->cpu_time)
+    return -1;
+  // If the cpu_time times are the same, then sort into increasing
+  // order of pid.
+  return proc1->pid - proc2->pid;
+}
+
+void Usage(const char *program)
+{
+  fprintf(stderr, "Usage: %s [options] trace_file\n", program);
+  OptionsUsage();
+}
+
+int main(int argc, char **argv) {
+  // Parse the options
+  ParseOptions(argc, argv);
+  if (argc - optind != 1) {
+    Usage(argv[0]);
+    exit(1);
+  }
+
+  char *trace_filename = argv[optind];
+  TraceReader<> *trace = new TraceReader<>;
+  trace->Open(trace_filename);
+  trace->SetRoot(root);
+
+  while (1) {
+    BBEvent event, ignored;
+    symbol_type *dummy_sym;
+
+    if (GetNextValidEvent(trace, &event, &ignored, &dummy_sym))
+      break;
+  }
+
+  int num_procs;
+  ProcessState *processes = trace->GetProcesses(&num_procs);
+  qsort(processes, num_procs, sizeof(ProcessState), cmp_dec_cpu_time);
+
+  uint64_t total_time = 0;
+  for (int ii = 0; ii < num_procs; ++ii) {
+    total_time += processes[ii].cpu_time;
+  }
+
+  uint64_t sum_time = 0;
+  printf("  pid parent   cpu_time      %%      %% flags argv\n"); 
+  ProcessState *pstate = &processes[0];
+  for (int ii = 0; ii < num_procs; ++ii, ++pstate) {
+    sum_time += pstate->cpu_time;
+    double per = 100.0 * pstate->cpu_time / total_time;
+    double sum_per = 100.0 * sum_time / total_time;
+    char *print_flags = "";
+    if ((pstate->flags & ProcessState::kCalledExec) == 0)
+      print_flags = "T";
+    if (pstate->name == NULL)
+      pstate->name = "";
+    printf("%5d  %5d %10llu %6.2f %6.2f %5s %s",
+           pstate->pid, pstate->parent_pid, pstate->cpu_time,
+           per, sum_per, print_flags, pstate->name);
+    for (int ii = 1; ii < pstate->argc; ++ii) {
+      printf(" %s", pstate->argv[ii]);
+    }
+    printf("\n");
+  }
+  return 0;
+}
diff --git a/emulator/qtools/profile_trace.cpp b/emulator/qtools/profile_trace.cpp
new file mode 100644
index 0000000..9d14a03
--- /dev/null
+++ b/emulator/qtools/profile_trace.cpp
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "trace_reader.h"
+#include "parse_options.h"
+
+const int kMillion = 1000000;
+const int kMHz = 200 * kMillion;
+
+struct symbol {
+    int         count;      // number of times a function is executed
+    uint64_t    elapsed;    // elapsed time for this function
+};
+
+typedef TraceReader<symbol> TraceReaderType;
+
+#include "parse_options-inl.h"
+
+static const uint32_t kOffsetThreshold = 0x100000;
+
+// This comparison function is called from qsort() to sort
+// symbols into decreasing elapsed time.
+int cmp_sym_elapsed(const void *a, const void *b) {
+    const symbol_type *syma, *symb;
+    uint64_t elapsed1, elapsed2;
+
+    syma = static_cast<symbol_type const *>(a);
+    symb = static_cast<symbol_type const *>(b);
+    elapsed1 = syma->elapsed;
+    elapsed2 = symb->elapsed;
+    if (elapsed1 < elapsed2)
+        return 1;
+    if (elapsed1 == elapsed2)
+        return strcmp(syma->name, symb->name);
+    return -1;
+}
+
+void Usage(const char *program)
+{
+    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
+    OptionsUsage();
+}
+
+int main(int argc, char **argv)
+{
+    ParseOptions(argc, argv);
+    if (argc - optind != 2) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *trace_filename = argv[optind++];
+    char *elf_file = argv[optind++];
+    TraceReader<symbol> *trace = new TraceReader<symbol>;
+    trace->Open(trace_filename);
+    trace->SetDemangle(demangle);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+
+    symbol_type dummy;
+    dummy.count = 0;
+    dummy.elapsed = 0;
+    symbol_type *prev_sym = &dummy;
+    uint64_t prev_bb_time = 0;
+    while (1) {
+        symbol_type *sym;
+        BBEvent event;
+        BBEvent first_ignored_event;
+
+        bool eof = GetNextValidEvent(trace, &event, &first_ignored_event, &sym);
+
+        // Assign the elapsed time to the previous function symbol
+        uint64_t elapsed = 0;
+        if (first_ignored_event.time != 0)
+            elapsed = first_ignored_event.time - prev_bb_time;
+        else if (!eof)
+            elapsed = event.time - prev_bb_time;
+        prev_sym->elapsed += elapsed;
+
+        if (eof)
+            break;
+
+        prev_bb_time = event.time;
+        sym->count += 1;
+        prev_sym = sym;
+#if 0
+        printf("t%lld bb_num: %d, bb_addr: 0x%x func: %s, addr: 0x%x, count: %d\n",
+               bb_time, bb_num, bb_addr, sym->name, sym->addr, sym->count);
+#endif
+    }
+
+    int nsyms;
+    symbol_type *syms = trace->GetSymbols(&nsyms);
+
+    // Sort the symbols into decreasing order of elapsed time
+    qsort(syms, nsyms, sizeof(symbol_type), cmp_sym_elapsed);
+
+    // Add up all the cycles
+    uint64_t total = 0;
+    symbol_type *sym = syms;
+    for (int ii = 0; ii < nsyms; ++ii, ++sym) {
+        total += sym->elapsed;
+    }
+
+    double secs = 1.0 * total / kMHz;
+    printf("Total seconds: %.2f, total cycles: %lld, MHz: %d\n\n",
+           secs, total, kMHz / kMillion);
+
+    uint64_t sum = 0;
+    printf("Elapsed secs Elapsed cyc      %%      %%    Function\n");
+    sym = syms;
+    for (int ii = 0; ii < nsyms; ++ii, ++sym) {
+        if (sym->elapsed == 0)
+            break;
+        sum += sym->elapsed;
+        double per = 100.0 * sym->elapsed / total;
+        double sum_per = 100.0 * sum / total;
+        double secs = 1.0 * sym->elapsed / kMHz;
+        char *ksym = " ";
+        if (sym->region->flags & region_type::kIsKernelRegion)
+            ksym = "k";
+        printf("%12.2f %11lld %6.2f %6.2f  %s %s\n",
+               secs, sym->elapsed, per, sum_per, ksym, sym->name);
+    }
+    delete[] syms;
+    delete trace;
+
+    return 0;
+}
diff --git a/emulator/qtools/q2dm.cpp b/emulator/qtools/q2dm.cpp
new file mode 100644
index 0000000..7f987dc
--- /dev/null
+++ b/emulator/qtools/q2dm.cpp
@@ -0,0 +1,275 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "trace_reader.h"
+#include "bitvector.h"
+#include "parse_options.h"
+#include "dmtrace.h"
+#include "armdis.h"
+
+struct symbol {
+    uint32_t id;
+};
+
+typedef TraceReader<symbol> TraceReaderType;
+
+#include "parse_options-inl.h"
+#include "callstack.h"
+
+DmTrace *dmtrace;
+
+class MyFrame : public StackFrame<symbol_type> {
+  public:
+    void push(int stackLevel, uint64_t time, CallStackBase *base);
+    void pop(int stackLevel, uint64_t time, CallStackBase *base);
+};
+
+typedef CallStack<MyFrame> CallStackType;
+
+static const int kNumStackFrames = 500;
+static const int kMaxThreads = (32 * 1024);
+uint64_t thread_time[kMaxThreads];
+
+class FunctionStack {
+  public:
+    FunctionStack() {
+        top = 0;
+    }
+    void push(symbol_type *sym) {
+        if (top >= kNumStackFrames)
+            return;
+        frames[top] = sym;
+        top += 1;
+    }
+
+    symbol_type* pop() {
+        if (top <= 0) {
+            return NULL;
+        }
+        top -= 1;
+        return frames[top];
+    }
+
+    void showStack() {
+        fprintf(stderr, "top %d\n", top);
+        for (int ii = 0; ii < top; ii++) {
+            fprintf(stderr, "  %d: %s\n", ii, frames[ii]->name);
+        }
+    }
+
+  private:
+    int top;
+    symbol_type *frames[kNumStackFrames];
+};
+
+FunctionStack *dmtrace_stack[kMaxThreads];
+
+void MyFrame::push(int stackLevel, uint64_t time, CallStackBase *base)
+{
+    int pid = base->getId();
+    CallStackType *stack = (CallStackType *) base;
+
+#if 0
+    fprintf(stderr, "native push t %llu p %d s %d fid %d 0x%x %s\n",
+            stack->getGlobalTime(time), pid, stackLevel,
+            function->id, function->addr, function->name);
+#endif
+
+    FunctionStack *fstack = dmtrace_stack[pid];
+    if (fstack == NULL) {
+        fstack = new FunctionStack();
+        dmtrace_stack[pid] = fstack;
+    }
+
+    fstack->push(function);
+    thread_time[pid] = time;
+    dmtrace->addFunctionEntry(function->id, time, pid);
+}
+
+void MyFrame::pop(int stackLevel, uint64_t time, CallStackBase *base)
+{
+    int pid = base->getId();
+    CallStackType *stack = (CallStackType *) base;
+
+#if 0
+    fprintf(stderr, "native pop  t %llu p %d s %d fid %d 0x%x %s\n",
+            stack->getGlobalTime(time), pid, stackLevel,
+            function->id, function->addr, function->name);
+#endif
+
+    FunctionStack *fstack = dmtrace_stack[pid];
+    if (fstack == NULL) {
+        fstack = new FunctionStack();
+        dmtrace_stack[pid] = fstack;
+    }
+
+    symbol_type *sym = fstack->pop();
+    if (sym != NULL && sym != function) {
+        fprintf(stderr, "Error: q2dm function mismatch at time %llu pid %d sym %s\n",
+                stack->getGlobalTime(time), pid, sym->name);
+        fstack->showStack();
+        exit(1);
+    }
+
+    thread_time[pid] = time;
+    dmtrace->addFunctionExit(function->id, time, pid);
+}
+
+uint32_t nextFunctionId = 4;
+CallStackType *stacks[kMaxThreads];
+
+void Usage(const char *program)
+{
+    fprintf(stderr, "Usage: %s [options] trace_name elf_file dmtrace_name\n",
+            program);
+    OptionsUsage();
+}
+
+int main(int argc, char **argv)
+{
+    bool useKernelStack = true;
+
+    ParseOptions(argc, argv);
+    if (argc - optind != 3) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *qemu_trace_file = argv[optind++];
+    char *elf_file = argv[optind++];
+    char *dmtrace_file = argv[optind++];
+    TraceReaderType *trace = new TraceReaderType;
+    trace->Open(qemu_trace_file);
+    trace->SetDemangle(demangle);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+    TraceHeader *qheader = trace->GetHeader();
+    uint64_t startTime = qheader->start_sec;
+    startTime = (startTime << 32) | qheader->start_usec;
+    int kernelPid = qheader->first_unused_pid;
+
+    dmtrace = new DmTrace;
+    dmtrace->open(dmtrace_file, startTime);
+
+    bool inKernel = false;
+    CallStackType *kernelStack = NULL;
+    if (useKernelStack) {
+        // Create a fake kernel thread stack where we will put all the kernel
+        // code.
+        kernelStack = new CallStackType(kernelPid, kNumStackFrames, trace);
+        dmtrace->addThread(kernelPid, "(kernel)");
+    }
+
+    CallStackType *prevStack = NULL;
+    BBEvent event;
+    while (1) {
+        BBEvent ignored;
+        symbol_type *function;
+
+        if (GetNextValidEvent(trace, &event, &ignored, &function))
+            break;
+        if (event.bb_num == 0)
+            break;
+#if 0
+        fprintf(stderr, "event t %llu p %d %s\n",
+                event.time, event.pid, function->name);
+#endif
+
+        CallStackType *pStack;
+        if (useKernelStack) {
+            uint32_t flags = function->region->flags;
+            uint32_t region_mask = region_type::kIsKernelRegion
+                    | region_type::kIsUserMappedRegion;
+            if ((flags & region_mask) == region_type::kIsKernelRegion) {
+                // Use the kernel stack
+                pStack = kernelStack;
+                inKernel = true;
+            } else {
+                // If we were just in the kernel then pop off all of the
+                // stack frames for the kernel thread.
+                if (inKernel == true) {
+                    inKernel = false;
+                    kernelStack->popAll(event.time);
+                }
+                
+                // Get the stack for the current thread
+                pStack = stacks[event.pid];
+            }
+        } else {
+            // Get the stack for the current thread
+            pStack = stacks[event.pid];
+        }
+
+        // If the stack does not exist, then allocate a new one.
+        if (pStack == NULL) {
+            pStack = new CallStackType(event.pid, kNumStackFrames, trace);
+            stacks[event.pid] = pStack;
+            char *name = trace->GetProcessName(event.pid);
+            dmtrace->addThread(event.pid, name);
+        }
+
+        if (prevStack != pStack) {
+            pStack->threadStart(event.time);
+            if (prevStack)
+                prevStack->threadStop(event.time);
+        }
+        prevStack = pStack;
+
+        // If we have never seen this function before, then add it to the
+        // list of known functions.
+        if (function->id == 0) {
+            function->id = nextFunctionId;
+            nextFunctionId += 4;
+            uint32_t flags = function->region->flags;
+            const char *name = function->name;
+            if (flags & region_type::kIsKernelRegion) {
+                // To distinguish kernel function names from user library
+                // names, add a marker to the name.
+                int len = strlen(name) + strlen(" [kernel]") + 1;
+                char *kernelName = new char[len];
+                strcpy(kernelName, name);
+                strcat(kernelName, " [kernel]");
+                name = kernelName;
+            }
+            dmtrace->parseAndAddFunction(function->id, name);
+        }
+
+        // Update the stack
+        pStack->updateStack(&event, function);
+    }
+
+    if (prevStack == NULL) {
+        fprintf(stderr, "Error: no events in trace.\n");
+        exit(1);
+    }
+    prevStack->threadStop(event.time);
+    for (int ii = 0; ii < kMaxThreads; ++ii) {
+        if (stacks[ii]) {
+            stacks[ii]->threadStart(event.time);
+            stacks[ii]->popAll(event.time);
+        }
+    }
+    if (useKernelStack) {
+        kernelStack->popAll(event.time);
+    }
+
+    // Read the pid events to find the names of the processes
+    while (1) {
+        PidEvent pid_event;
+        if (trace->ReadPidEvent(&pid_event))
+            break;
+        if (pid_event.rec_type == kPidName) {
+            dmtrace->updateName(pid_event.pid, pid_event.path);
+        }
+    }
+
+
+    dmtrace->close();
+    delete dmtrace;
+    delete trace;
+    return 0;
+}
diff --git a/emulator/qtools/q2g.cpp b/emulator/qtools/q2g.cpp
new file mode 100644
index 0000000..6b2ae92
--- /dev/null
+++ b/emulator/qtools/q2g.cpp
@@ -0,0 +1,108 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "trace_reader.h"
+#include "gtrace.h"
+#include "bitvector.h"
+#include "parse_options.h"
+
+struct symbol {
+  int		filenum;	// the file number (for gtrace)
+  int		procnum;	// the procedure number (for gtrace)
+};
+
+typedef TraceReader<symbol> TraceReaderType;
+
+#include "parse_options-inl.h"
+
+const int kMaxProcNum = 4095;
+int next_filenum = 1;
+int next_procnum = 1;
+
+void Usage(const char *program)
+{
+  fprintf(stderr, "Usage: %s [options] trace_file elf_file gtrace_file\n",
+          program);
+  OptionsUsage();
+}
+
+int main(int argc, char **argv)
+{
+  ParseOptions(argc, argv);
+  if (argc - optind != 3) {
+    Usage(argv[0]);
+    exit(1);
+  }
+
+  char *qemu_trace_file = argv[optind++];
+  char *elf_file = argv[optind++];
+  char *gtrace_file = argv[optind++];
+  TraceReader<symbol> *trace = new TraceReader<symbol>;
+  trace->Open(qemu_trace_file);
+  trace->ReadKernelSymbols(elf_file);
+  trace->SetRoot(root);
+  TraceHeader *qheader = trace->GetHeader();
+
+  // Get the first valid event to get the process id for the gtrace header.
+  BBEvent event;
+  BBEvent ignored;
+  symbol_type *sym;
+  if (GetNextValidEvent(trace, &event, &ignored, &sym))
+    return 0;
+
+  Gtrace *gtrace = new Gtrace;
+  gtrace->Open(gtrace_file, qheader->pdate, qheader->ptime);
+  gtrace->WriteFirstHeader(qheader->start_sec, event.pid);
+
+  symbol_type *prev_sym = NULL;
+  bool eof = false;
+  while (!eof) {
+    if (sym != prev_sym) {
+      // This procedure is different from the previous procedure.
+
+      // If we have never seen this symbol before, then add it to the
+      // list of known procedures.
+      if (sym->filenum == 0) {
+        sym->filenum = next_filenum;
+        sym->procnum = next_procnum;
+        gtrace->AddProcedure(sym->filenum, sym->procnum, sym->name);
+        next_procnum += 1;
+        if (next_procnum > kMaxProcNum) {
+          next_filenum += 1;
+          next_procnum = 1;
+        }
+      }
+
+      // If we haven't yet recorded the procedure exit for the previous
+      // procedure, then do it now.
+      if (prev_sym) {
+        gtrace->AddProcExit(prev_sym->filenum, prev_sym->procnum, event.time,
+                            event.pid);
+      }
+
+      // If this is not the terminating record, then record a procedure
+      // entry.
+      if (event.bb_num != 0) {
+        gtrace->AddProcEntry(sym->filenum, sym->procnum, event.time, event.pid);
+        prev_sym = sym;
+      }
+    }
+
+    eof = GetNextValidEvent(trace, &event, &ignored, &sym);
+    if (ignored.time != 0 && prev_sym) {
+      // We read an event that we are ignoring.
+      // If we haven't already recorded a procedure exit, then do so.
+      gtrace->AddProcExit(prev_sym->filenum, prev_sym->procnum, ignored.time,
+                          ignored.pid);
+      prev_sym = NULL;
+    }
+  }
+
+  delete gtrace;
+  delete trace;
+  return 0;
+}
diff --git a/emulator/qtools/read_addr.cpp b/emulator/qtools/read_addr.cpp
new file mode 100644
index 0000000..38fc62a
--- /dev/null
+++ b/emulator/qtools/read_addr.cpp
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "trace_reader.h"
+
+int main(int argc, char **argv) {
+  if (argc != 2) {
+    fprintf(stderr, "Usage: %s trace_file\n", argv[0]);
+    exit(1);
+  }
+
+  char *trace_filename = argv[1];
+  TraceReaderBase *trace = new TraceReaderBase;
+  trace->Open(trace_filename);
+
+  while (1) {
+    uint64_t time;
+    uint32_t addr;
+    int flags;
+
+    if (trace->ReadAddr(&time, &addr, &flags))
+      break;
+    char *op = "ld";
+    if (flags == 1)
+        op = "st";
+    printf("%lld 0x%08x %s\n", time, addr, op);
+  }
+  return 0;
+}
diff --git a/emulator/qtools/read_elf.cpp b/emulator/qtools/read_elf.cpp
new file mode 100644
index 0000000..1d1a74a
--- /dev/null
+++ b/emulator/qtools/read_elf.cpp
@@ -0,0 +1,210 @@
+/*************************************************************************
+    Copyright (C) 2002,2003,2004,2005 Wei Qin
+    See file COPYING for more information.
+
+    This program is free software; you can redistribute it and/or modify    
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+*************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include "read_elf.h"
+
+#define SwapHalf(a) (((a & 0x00ff) << 8) | ((a & 0xff00) >> 8))
+#define SwapWord(a) (((a & 0xff000000) >> 24) | ((a & 0x00ff0000) >> 8) | ((a & 0x0000ff00) << 8) | ((a & 0x000000ff) << 24))
+#define SwapAddr(a) SwapWord(a)
+#define SwapOff(a) SwapWord(a)
+#define SwapSection(a) SwapHalf(a)
+
+int LittleEndian()
+{
+  Elf32_Word a = 0x01020304;
+  return *(char *) &a == 0x04;
+}
+
+void SwapElfHeader(Elf32_Ehdr *hdr)
+{
+  hdr->e_type = SwapHalf(hdr->e_type);
+  hdr->e_machine = SwapHalf(hdr->e_machine);
+  hdr->e_version = SwapWord(hdr->e_version);
+  hdr->e_entry = SwapAddr(hdr->e_entry);
+  hdr->e_phoff = SwapOff(hdr->e_phoff);
+  hdr->e_shoff = SwapOff(hdr->e_shoff);
+  hdr->e_flags = SwapWord(hdr->e_flags);
+  hdr->e_ehsize = SwapHalf(hdr->e_ehsize);
+  hdr->e_phentsize = SwapHalf(hdr->e_phentsize);
+  hdr->e_phnum = SwapHalf(hdr->e_phnum);
+  hdr->e_shentsize = SwapHalf(hdr->e_shentsize);
+  hdr->e_shnum = SwapHalf(hdr->e_shnum);
+  hdr->e_shstrndx = SwapHalf(hdr->e_shstrndx);
+}
+
+void SwapSectionHeader(Elf32_Shdr *shdr)
+{
+  shdr->sh_name = SwapWord(shdr->sh_name);
+  shdr->sh_type = SwapWord(shdr->sh_type);
+  shdr->sh_flags = SwapWord(shdr->sh_flags);
+  shdr->sh_addr = SwapAddr(shdr->sh_addr);
+  shdr->sh_offset = SwapOff(shdr->sh_offset);
+  shdr->sh_size = SwapWord(shdr->sh_size);
+  shdr->sh_link = SwapWord(shdr->sh_link);
+  shdr->sh_info = SwapWord(shdr->sh_info);
+  shdr->sh_addralign = SwapWord(shdr->sh_addralign);
+  shdr->sh_entsize = SwapWord(shdr->sh_entsize);
+}
+
+void SwapElfSymbol(Elf32_Sym *sym)
+{
+    sym->st_name = SwapWord(sym->st_name);
+    sym->st_value = SwapAddr(sym->st_value);
+    sym->st_size = SwapWord(sym->st_size);
+    sym->st_shndx = SwapSection(sym->st_shndx);
+}
+
+void AdjustElfHeader(Elf32_Ehdr *hdr)
+{
+  switch(hdr->e_ident[EI_DATA])
+  {
+    case ELFDATA2LSB:
+      if (!LittleEndian())
+        SwapElfHeader(hdr);
+      break;
+    case ELFDATA2MSB:
+      if (LittleEndian())
+        SwapElfHeader(hdr);
+      break;
+  }
+}
+
+void AdjustSectionHeader(Elf32_Ehdr *hdr, Elf32_Shdr *shdr)
+{
+  switch(hdr->e_ident[EI_DATA])
+  {
+    case ELFDATA2LSB:
+      if (!LittleEndian())
+        SwapSectionHeader(shdr);
+      break;
+    case ELFDATA2MSB:
+      if (LittleEndian())
+        SwapSectionHeader(shdr);
+      break;
+  }
+}
+
+void AdjustElfSymbols(Elf32_Ehdr *hdr, Elf32_Sym *elf_symbols, int num_entries)
+{
+    if (hdr->e_ident[EI_DATA] == ELFDATA2LSB && LittleEndian())
+        return;
+    if (hdr->e_ident[EI_DATA] == ELFDATA2MSB && !LittleEndian())
+        return;
+    for (int ii = 0; ii < num_entries; ++ii) {
+        SwapElfSymbol(&elf_symbols[ii]);
+    }
+}
+
+Elf32_Ehdr *ReadElfHeader(FILE *fobj)
+{
+  Elf32_Ehdr *hdr = new Elf32_Ehdr;
+  int rval = fread(hdr, sizeof(Elf32_Ehdr), 1, fobj);
+  if (rval != 1) {
+    delete hdr;
+    return NULL;
+  }
+  if (hdr->e_ident[EI_MAG0] != 0x7f || hdr->e_ident[EI_MAG1] != 'E' ||
+      hdr->e_ident[EI_MAG2] != 'L' || hdr->e_ident[EI_MAG3] != 'F') {
+    delete hdr;
+    return NULL;
+  }
+  AdjustElfHeader(hdr);
+  return hdr;
+}
+
+Elf32_Shdr *ReadSectionHeaders(Elf32_Ehdr *hdr, FILE *f)
+{
+  int i;
+  unsigned long sz = hdr->e_shnum * hdr->e_shentsize;
+  assert(sizeof(Elf32_Shdr) == hdr->e_shentsize);
+  Elf32_Shdr *shdr = new Elf32_Shdr[hdr->e_shnum];
+
+  if (fseek(f, hdr->e_shoff, SEEK_SET) != 0)
+  {
+    delete[] shdr;
+    return NULL;
+  }
+  if (fread(shdr, sz, 1, f) != 1)
+  {
+    delete[] shdr;
+    return NULL;
+  }
+
+  for(i = 0; i < hdr->e_shnum; i++)
+    AdjustSectionHeader(hdr, shdr + i);
+
+  return shdr;
+}
+
+
+char *ReadStringTable(Elf32_Ehdr *hdr, Elf32_Shdr *shdr_table, FILE *f)
+{
+  Elf32_Shdr *shdr = shdr_table + hdr->e_shstrndx;
+  char *string_table;
+
+  string_table = new char[shdr->sh_size];
+  fseek(f, shdr->sh_offset, SEEK_SET);
+  fread(string_table, shdr->sh_size, 1, f);
+
+  return string_table;
+}
+
+int ReadSection(Elf32_Shdr *shdr, void *buffer, FILE *f)
+{
+  if (fseek(f, shdr->sh_offset, SEEK_SET) != 0)
+    return -1;
+  if (fread(buffer, shdr->sh_size, 1, f) != 1)
+    return -1;
+  return 0;
+}
+
+char *GetSymbolName(Elf32_Half index, char *string_table)
+{
+  return string_table + index;
+}
+
+Elf32_Shdr *FindSymbolTableSection(Elf32_Ehdr *hdr,
+                                   Elf32_Shdr *shdr,
+                                   char *string_table)
+{
+  for(int ii = 0; ii < hdr->e_shnum; ii++) {
+    if (shdr[ii].sh_type == SHT_SYMTAB &&
+       strcmp(GetSymbolName(shdr[ii].sh_name, string_table),
+              ".symtab") == 0)
+    {
+      return &shdr[ii];
+    }
+  }
+  return NULL;
+}
+
+Elf32_Shdr *FindSymbolStringTableSection(Elf32_Ehdr *hdr,
+                                         Elf32_Shdr *shdr,
+                                         char *string_table)
+{
+  for(int ii = 0; ii < hdr->e_shnum; ii++) {
+    if (shdr[ii].sh_type == SHT_STRTAB &&
+       strcmp(GetSymbolName(shdr[ii].sh_name, string_table),
+              ".strtab") == 0)
+    {
+      return &shdr[ii];
+    }
+  }
+  return NULL;
+}
diff --git a/emulator/qtools/read_elf.h b/emulator/qtools/read_elf.h
new file mode 100644
index 0000000..72266c3
--- /dev/null
+++ b/emulator/qtools/read_elf.h
@@ -0,0 +1,20 @@
+#ifndef READ_ELF_H
+#define READ_ELF_H
+
+#include <stdio.h>
+#include <elf.h>
+
+Elf32_Ehdr *ReadElfHeader(FILE *fobj);
+Elf32_Shdr *ReadSectionHeaders(Elf32_Ehdr *hdr, FILE *fobj);
+char *ReadStringTable(Elf32_Ehdr *hdr, Elf32_Shdr *shdr, FILE *fobj);
+Elf32_Shdr *FindSymbolTableSection(Elf32_Ehdr *hdr,
+                                   Elf32_Shdr *shdr,
+                                   char *string_table);
+Elf32_Shdr *FindSymbolStringTableSection(Elf32_Ehdr *hdr,
+                                         Elf32_Shdr *shdr,
+                                         char *string_table);
+int ReadSection(Elf32_Shdr *shdr, void *buffer, FILE *f);
+void AdjustElfSymbols(Elf32_Ehdr *hdr, Elf32_Sym *elf_symbols,
+                      int num_entries);
+
+#endif /* READ_ELF_H */
diff --git a/emulator/qtools/read_method.cpp b/emulator/qtools/read_method.cpp
new file mode 100644
index 0000000..e48edad
--- /dev/null
+++ b/emulator/qtools/read_method.cpp
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "trace_reader.h"
+#include "parse_options.h"
+
+typedef TraceReader<> TraceReaderType;
+
+#include "parse_options-inl.h"
+
+void Usage(const char *program)
+{
+    fprintf(stderr, "Usage: %s [options] trace_name elf_file\n",
+            program);
+    OptionsUsage();
+}
+
+int main(int argc, char **argv) {
+    ParseOptions(argc, argv);
+    if (argc - optind != 2) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *qemu_trace_file = argv[optind++];
+    char *elf_file = argv[optind++];
+    TraceReaderType *trace = new TraceReaderType;
+    trace->Open(qemu_trace_file);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+
+    while (1) {
+        MethodRec method_record;
+        symbol_type *sym;
+        TraceReaderType::ProcessState *proc;
+
+        if (trace->ReadMethodSymbol(&method_record, &sym, &proc))
+            break;
+        if (sym != NULL) {
+            printf("%lld p %d 0x%x %d %s\n",
+                   method_record.time, proc->pid, method_record.addr,
+                   method_record.flags, sym->name);
+        } else {
+            printf("%lld p %d 0x%x %d\n",
+                   method_record.time, proc->pid, method_record.addr,
+                   method_record.flags);
+        }
+        proc->DumpStack();
+    }
+    return 0;
+}
diff --git a/emulator/qtools/read_pid.cpp b/emulator/qtools/read_pid.cpp
new file mode 100644
index 0000000..a2d69d4
--- /dev/null
+++ b/emulator/qtools/read_pid.cpp
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "trace_reader.h"
+
+int main(int argc, char **argv) {
+  if (argc != 2) {
+    fprintf(stderr, "Usage: %s trace_file\n", argv[0]);
+    exit(1);
+  }
+
+  char *trace_filename = argv[1];
+  TraceReaderBase *trace = new TraceReaderBase;
+  trace->Open(trace_filename);
+
+  while (1) {
+    PidEvent event;
+    if (trace->ReadPidEvent(&event))
+      break;
+    switch (event.rec_type) {
+      case kPidFork:
+        printf("t%lld fork tgid %d pid %d\n", event.time, event.tgid, event.pid);
+        break;
+      case kPidClone:
+        printf("t%lld clone tgid %d pid %d\n", event.time, event.tgid, event.pid);
+        break;
+      case kPidSwitch:
+        printf("t%lld switch %d\n", event.time, event.pid);
+        break;
+      case kPidExit:
+        printf("t%lld exit %d\n", event.time, event.pid);
+        break;
+      case kPidMmap:
+        printf("t%lld mmap %08x - %08x, offset %08x '%s'\n",
+               event.time, event.vstart, event.vend, event.offset, event.path);
+        delete[] event.path;
+        break;
+      case kPidMunmap:
+        printf("t%lld munmap %08x - %08x\n",
+               event.time, event.vstart, event.vend);
+        break;
+      case kPidSymbolAdd:
+        printf("t%lld add sym %08x '%s'\n",
+               event.time, event.vstart, event.path);
+        delete[] event.path;
+        break;
+      case kPidSymbolRemove:
+        printf("t%lld remove %08x\n", event.time, event.vstart);
+        break;
+      case kPidExec:
+        printf("t%lld argc: %d\n", event.time, event.argc);
+        for (int ii = 0; ii < event.argc; ++ii) {
+          printf("  argv[%d]: %s\n", ii, event.argv[ii]);
+          delete[] event.argv[ii];
+        }
+        delete[] event.argv;
+        break;
+      case kPidKthreadName:
+        printf("t%lld kthread tgid %d pid %d %s\n",
+               event.time, event.tgid, event.pid, event.path);
+        delete[] event.path;
+        break;
+      case kPidName:
+        printf("t%lld name %d %s\n",
+               event.time, event.pid, event.path);
+        delete[] event.path;
+        break;
+    }
+  }
+  return 0;
+}
diff --git a/emulator/qtools/read_trace.cpp b/emulator/qtools/read_trace.cpp
new file mode 100644
index 0000000..fb4917c
--- /dev/null
+++ b/emulator/qtools/read_trace.cpp
@@ -0,0 +1,165 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "trace_reader.h"
+#include "armdis.h"
+#include "parse_options.h"
+
+typedef TraceReader<> TraceReaderType;
+
+#include "parse_options-inl.h"
+
+static const uint32_t kOffsetThreshold = 0x100000;
+static uint64_t startTime = 0;
+
+void Usage(const char *program)
+{
+    fprintf(stderr,
+            "Usage: %s [options] [-- -s start_time] trace_file elf_file\n",
+            program);
+    OptionsUsage();
+}
+
+
+bool localParseOptions(int argc, char **argv)
+{
+    bool err = false;
+    while (!err) {
+        int opt = getopt(argc, argv, "+s:");
+        if (opt == -1)
+            break;
+        switch (opt) {
+        case 's':
+            startTime = strtoull(optarg, NULL, 0);
+            break;
+        default:
+            err = true;
+            break;
+        }
+    }
+    return err;
+}
+
+int main(int argc, char **argv) {
+    // Parse the options
+    ParseOptions(argc, argv);
+    localParseOptions(argc, argv);
+    if (argc - optind != 2) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *trace_filename = argv[optind++];
+    char *elf_file = argv[optind++];
+    TraceReader<> *trace = new TraceReader<>;
+    trace->Open(trace_filename);
+    trace->SetDemangle(demangle);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+
+    while (1) {
+        symbol_type *sym;
+        char buf[1024];
+        BBEvent event;
+        BBEvent ignored;
+
+        if (GetNextValidEvent(trace, &event, &ignored, &sym))
+            break;
+#if 0
+        fprintf(stderr, "t%llu bb %lld %d\n",
+                event.time, event.bb_num, event.num_insns);
+#endif
+
+        uint32_t *insns = event.insns;
+        uint32_t addr = event.bb_addr;
+        uint32_t offset = addr - sym->addr - sym->region->base_addr;
+        symbol_type *vm_sym = sym->vm_sym;
+        const char *vm_name = NULL;
+        if (vm_sym != NULL) {
+            vm_name = vm_sym->name;
+            offset = addr - vm_sym->addr - vm_sym->region->base_addr;
+        }
+#if 0
+        if (strcmp(sym->name, "(unknown)") == 0 || offset > kOffsetThreshold) {
+            ProcessState *process = trace->GetCurrentProcess();
+            ProcessState *manager = process->addr_manager;
+            for (int ii = 0; ii < manager->nregions; ++ii) {
+                printf("  %2d: %08x - %08x base: %08x offset: %u nsyms: %4d flags: 0x%x %s\n",
+                       ii,
+                       manager->regions[ii]->vstart,
+                       manager->regions[ii]->vend,
+                       manager->regions[ii]->base_addr,
+                       manager->regions[ii]->file_offset,
+                       manager->regions[ii]->nsymbols,
+                       manager->regions[ii]->flags,
+                       manager->regions[ii]->path);
+                int nsymbols = manager->regions[ii]->nsymbols;
+                for (int jj = 0; jj < 10 && jj < nsymbols; ++jj) {
+                    printf("    %08x %s\n",
+                           manager->regions[ii]->symbols[jj].addr,
+                           manager->regions[ii]->symbols[jj].name);
+                }
+            }
+        }
+#endif
+#if 1
+        for (int ii = 0; ii < event.num_insns; ++ii) {
+            uint64_t sim_time = trace->ReadInsnTime(event.time);
+            if (sim_time < startTime)
+                continue;
+
+            uint32_t insn = insns[ii];
+            char *disasm;
+            int bytes;
+            if (vm_name != NULL) {
+                sprintf(buf, "%s+%02x: %s", vm_name, offset, sym->name);
+            } else {
+                sprintf(buf, "%s+%02x", sym->name, offset);
+            }
+
+            if (insn_is_thumb(insn)) {
+                bytes = 2;
+                insn = insn_unwrap_thumb(insn);
+
+                // thumb_pair is true if this is the first of a pair of
+                // thumb instructions (BL or BLX).
+                bool thumb_pair = ((insn & 0xf800) == 0xf000);
+
+                // Get the next thumb instruction (if any) because we may need
+                // it for the case where insn is BL or BLX.
+                uint32_t insn2 = 0;
+                if (thumb_pair && (ii + 1 < event.num_insns)) {
+                    insn2 = insns[ii + 1];
+                    insn2 = insn_unwrap_thumb(insn2);
+                    bytes = 4;
+                    ii += 1;
+                }
+                disasm = disasm_insn_thumb(addr, insn, insn2, NULL);
+                if (thumb_pair) {
+                    printf("%llu p%-4d %08x %04x %04x %-30s %s\n",
+                           sim_time, event.pid, addr, insn, insn2, buf, disasm);
+                } else {
+                    printf("%llu p%-4d %08x     %04x %-30s %s\n",
+                           sim_time, event.pid, addr, insn, buf, disasm);
+                }
+            } else {
+                bytes = 4;
+                disasm = Arm::disasm(addr, insn, NULL);
+                printf("%llu p%-4d %08x %08x %-30s %s\n",
+                       sim_time, event.pid, addr, insn, buf, disasm);
+            }
+            //printf("t%llu \t%08x\n", sim_time, addr);
+            addr += bytes;
+            offset += bytes;
+        }
+#endif
+#if 0
+        assert(offset < kOffsetThreshold);
+#endif
+    }
+
+    delete trace;
+    return 0;
+}
diff --git a/emulator/qtools/stack_dump.cpp b/emulator/qtools/stack_dump.cpp
new file mode 100644
index 0000000..b5014ef
--- /dev/null
+++ b/emulator/qtools/stack_dump.cpp
@@ -0,0 +1,105 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "trace_reader.h"
+#include "bitvector.h"
+#include "parse_options.h"
+#include "armdis.h"
+
+typedef TraceReader<> TraceReaderType;
+
+#include "parse_options-inl.h"
+#include "callstack.h"
+
+class MyFrame : public StackFrame<symbol_type> {
+  public:
+    void    push(int stackLevel, uint64_t time, CallStackBase *base);
+    void    pop(int stackLevel, uint64_t time, CallStackBase *base);
+};
+
+typedef CallStack<MyFrame> CallStackType;
+
+void MyFrame::push(int stackLevel, uint64_t time, CallStackBase *base)
+{
+    printf("%llu en thr %d %3d", time, base->getId(), stackLevel);
+    for (int ii = 0; ii < stackLevel; ++ii)
+        printf(".");
+    printf(" 0x%08x %s\n", addr, function->name);
+}
+
+void MyFrame::pop(int stackLevel, uint64_t time, CallStackBase *base)
+{
+    printf("%llu x  thr %d %3d", time, base->getId(), stackLevel);
+    for (int ii = 0; ii < stackLevel; ++ii)
+        printf(".");
+    printf(" 0x%08x %s\n", addr, function->name);
+}
+
+static const int kNumStackFrames = 500;
+static const int kMaxThreads = (32 * 1024);
+CallStackType *stacks[kMaxThreads];
+
+static uint64_t debugTime;
+
+void Usage(const char *program)
+{
+    fprintf(stderr, "Usage: %s [options] trace_name elf_file\n",
+            program);
+    OptionsUsage();
+}
+
+int main(int argc, char **argv)
+{
+    ParseOptions(argc, argv);
+    if (argc - optind != 2) {
+        Usage(argv[0]);
+        exit(1);
+    }
+
+    char *qemu_trace_file = argv[optind++];
+    char *elf_file = argv[optind++];
+    TraceReaderType *trace = new TraceReaderType;
+    trace->Open(qemu_trace_file);
+    trace->ReadKernelSymbols(elf_file);
+    trace->SetRoot(root);
+    TraceHeader *qheader = trace->GetHeader();
+    uint64_t startTime = qheader->start_sec;
+    startTime = (startTime << 32) | qheader->start_usec;
+
+    BBEvent event;
+    while (1) {
+        BBEvent ignored;
+        symbol_type *function;
+
+        if (GetNextValidEvent(trace, &event, &ignored, &function))
+            break;
+        if (event.bb_num == 0)
+            break;
+
+        // Get the stack for the current thread
+        CallStackType *pStack = stacks[event.pid];
+
+        // If the stack does not exist, then allocate a new one.
+        if (pStack == NULL) {
+            pStack = new CallStackType(event.pid, kNumStackFrames, trace);
+            stacks[event.pid] = pStack;
+        }
+        if (debugTime != 0 && event.time >= debugTime)
+            printf("debug time: %lld\n", debugTime);
+
+        // Update the stack
+        pStack->updateStack(&event, function);
+    }
+
+    for (int ii = 0; ii < kMaxThreads; ++ii) {
+        if (stacks[ii])
+            stacks[ii]->popAll(event.time);
+    }
+
+    delete trace;
+    return 0;
+}
diff --git a/emulator/qtools/tests/common_head.mk b/emulator/qtools/tests/common_head.mk
new file mode 100644
index 0000000..e8170e9
--- /dev/null
+++ b/emulator/qtools/tests/common_head.mk
@@ -0,0 +1,25 @@
+CC := arm-elf-gcc
+LD := arm-elf-ld
+AS := arm-elf-as
+OBJCOPY := arm-elf-objcopy
+OBJDUMP := arm-elf-objdump
+
+OPT := -g
+CFLAGS := $(OPT) -mcpu=arm9
+
+.SUFFIXES: .dis .bin .elf
+
+.c.elf:
+	$(CC) $(CFLAGS)  -Xlinker --script ../tests.ld -o $@ $< -nostdlib
+
+.c.s:
+	$(CC) $(CFLAGS) -static -S $<
+
+.S.elf:
+	$(CC) $(CFLAGS) -Xlinker --script ../tests.ld -nostdlib -o $@ $<
+
+.elf.dis:
+	$(OBJDUMP) -adx $< > $@
+
+.elf.bin:
+	$(OBJCOPY) -O binary $< $@
diff --git a/emulator/qtools/tests/common_tail.mk b/emulator/qtools/tests/common_tail.mk
new file mode 100644
index 0000000..be1c141
--- /dev/null
+++ b/emulator/qtools/tests/common_tail.mk
@@ -0,0 +1,3 @@
+
+clean:
+	rm -f *.elf *.dis *.bin *.o *~ a.out
diff --git a/emulator/qtools/tests/gtrace/Makefile b/emulator/qtools/tests/gtrace/Makefile
new file mode 100644
index 0000000..1d2050c
--- /dev/null
+++ b/emulator/qtools/tests/gtrace/Makefile
@@ -0,0 +1,18 @@
+include ../common_head.mk
+
+P4ROOT=/work/android
+QEMU=$(P4ROOT)/device/tools/qemu/arm-softmmu/qemu-system-arm
+QTOOLS=$(P4ROOT)/device/tools/qtools
+
+all: test.elf test.bin test.dis
+
+trace: test.elf test.bin
+	$(QEMU) -QEMU -kernel test.bin -trace foo
+	$(QTOOLS)/post_trace foo
+	$(QTOOLS)/read_trace foo test.elf > t1
+
+gtrace: trace
+	$(QTOOLS)/q2g -r $(P4ROOT)/device/out/linux-arm-release/symbols foo test.elf foo.gtrace
+	gtracepost64 foo.gtrace > t2
+
+include ../common_tail.mk
diff --git a/emulator/qtools/tests/gtrace/test.c b/emulator/qtools/tests/gtrace/test.c
new file mode 100644
index 0000000..e56a0f1
--- /dev/null
+++ b/emulator/qtools/tests/gtrace/test.c
@@ -0,0 +1,201 @@
+#include "../macros.h"
+
+int foo1();
+int foo2();
+void bar();
+int child1();
+int child2();
+int child3();
+int child4();
+int child5();
+
+int global;
+
+void start()
+{
+  // Set the stack pointer
+  asm("  mov r13,#0x200000");
+  PRINT_STR("hello\n");
+  TRACE_INIT_NAME(701, "proc_foo");
+  TRACE_INIT_NAME(702, "proc_bar");
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo1();
+  TRACE_SWITCH(702);
+  if (global++ > 0)
+      global++;
+  bar();
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo2();
+  TRACE_SWITCH(703);
+  if (global++ > 0)
+      global++;
+  foo1();
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(704);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(705);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(706);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(707);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(708);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(709);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(701);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_SWITCH(710);
+  if (global++ > 0)
+      global++;
+  foo1();
+
+  TRACE_STOP_EMU();
+}
+
+int foo1()
+{
+  int a = 0;
+
+  int ii;
+  for (ii = 0; ii < 3; ++ii) {
+    a += child1();
+    a += child2();
+    a += child3();
+  }
+  return a;
+}
+
+int foo2()
+{
+  int a = 0;
+
+  int ii;
+  for (ii = 0; ii < 2; ++ii) {
+    a += child3();
+    a += child4();
+    a += child5();
+  }
+  return a;
+}
+
+#define kStride 64
+void bar()
+{
+  int a = 0;
+
+  static char mem[1000 * kStride];
+
+  int ii, jj;
+
+  for (ii = 0; ii < 4; ++ii) {
+    for (jj = 0; jj < 10; ++jj)
+      a += mem[jj * kStride];
+    foo1();
+    foo2();
+  }
+}
+
+int child1()
+{
+  int a = 0;
+
+  int ii;
+  for (ii = 0; ii < 2; ++ii)
+    a += ii;
+  return a;
+}
+
+int child2()
+{
+  int a = 0;
+
+  int ii;
+  for (ii = 0; ii < 4; ++ii)
+    a += ii;
+  return a;
+}
+
+int child3()
+{
+  int a = 0;
+
+  int ii;
+  for (ii = 0; ii < 6; ++ii)
+    a += ii;
+  return a;
+}
+
+int child4()
+{
+  int a = 0;
+
+  int ii;
+  for (ii = 0; ii < 8; ++ii)
+    a += ii;
+  return a;
+}
+
+int child5()
+{
+  int a = 0;
+
+  int ii;
+  for (ii = 0; ii < 10; ++ii)
+    a += ii;
+  return a;
+}
diff --git a/emulator/qtools/tests/macros.h b/emulator/qtools/tests/macros.h
new file mode 100644
index 0000000..066374b
--- /dev/null
+++ b/emulator/qtools/tests/macros.h
@@ -0,0 +1,93 @@
+#ifndef _TEST_TRACE_C_H_
+#define _TEST_TRACE_C_H_
+
+/* the base address of trace device */
+#define TRACE_DEV_BASE_ADDR             0x21000000
+
+/*the register addresses of the trace device */
+#define TRACE_DEV_REG_SWITCH            0
+#define TRACE_DEV_REG_FORK              1
+#define TRACE_DEV_REG_EXECVE_PID        2
+#define TRACE_DEV_REG_EXECVE_VMSTART    3
+#define TRACE_DEV_REG_EXECVE_VMEND      4
+#define TRACE_DEV_REG_EXECVE_OFFSET     5
+#define TRACE_DEV_REG_EXECVE_EXEPATH    6
+#define TRACE_DEV_REG_EXIT              7
+#define TRACE_DEV_REG_CMDLINE           8
+#define TRACE_DEV_REG_CMDLINE_LEN       9
+#define TRACE_DEV_REG_MMAP_EXEPATH      10
+#define TRACE_DEV_REG_INIT_PID          11
+#define TRACE_DEV_REG_INIT_NAME         12
+#define TRACE_DEV_REG_CLONE             13
+#define TRACE_DEV_REG_DYN_SYM           50
+#define TRACE_DEV_REG_DYN_SYM_ADDR      51
+#define TRACE_DEV_REG_PRINT_STR         60
+#define TRACE_DEV_REG_PRINT_NUM_DEC     61
+#define TRACE_DEV_REG_PRINT_NUM_HEX     62
+#define TRACE_DEV_REG_STOP_EMU          90
+#define TRACE_DEV_REG_ENABLE            100
+#define TRACE_DEV_REG_DISABLE           101
+
+/* write a word to a trace device register */
+#define DEV_WRITE_WORD(addr,value)\
+    (*(volatile unsigned long *)(TRACE_DEV_BASE_ADDR + ((addr) << 2)) = (value))
+
+/*************************************************************/
+/* generates test events */
+
+/* context switch */
+#define TRACE_SWITCH(pid)            DEV_WRITE_WORD(TRACE_DEV_REG_SWITCH, (pid))
+/* fork */
+#define TRACE_FORK(pid)              DEV_WRITE_WORD(TRACE_DEV_REG_FORK, (pid))
+/* clone */
+#define TRACE_CLONE(pid)             DEV_WRITE_WORD(TRACE_DEV_REG_CLONE, (pid))
+/* dump name and path of threads executed before trace device created */
+#define TRACE_INIT_NAME(pid,path)\
+do {\
+    DEV_WRITE_WORD(TRACE_DEV_REG_INIT_PID, (pid));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_INIT_NAME, (unsigned long)(path));\
+}while(0)
+/* dump exec mapping of threads executed before trace device created */
+#define TRACE_INIT_EXEC(vstart,vend,eoff,path)\
+do {\
+    DEV_WRITE_WORD(TRACE_DEV_REG_EXECVE_VMSTART, (vstart));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_EXECVE_VMEND, (vend));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_EXECVE_OFFSET, (eoff));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_EXECVE_EXEPATH, (unsigned long)(path));\
+}while(0)
+/* mmap */
+#define TRACE_MMAP(vstart,vend,eoff,path)\
+do {\
+    DEV_WRITE_WORD(TRACE_DEV_REG_EXECVE_VMSTART, (vstart));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_EXECVE_VMEND, (vend));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_EXECVE_OFFSET, (eoff));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_MMAP_EXEPATH, (unsigned long)(path));\
+}while(0)
+/* execve */
+#define TRACE_EXECVE(cmdlen,cmd)\
+do {\
+    DEV_WRITE_WORD(TRACE_DEV_REG_CMDLINE_LEN, (cmdlen));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_CMDLINE, (unsigned long)(cmd));\
+}while(0)
+/* exit */
+#define TRACE_EXIT(retv)             DEV_WRITE_WORD(TRACE_DEV_REG_EXIT, (retv))
+
+/* other commands */
+
+/* stop emulation */
+#define TRACE_STOP_EMU()             DEV_WRITE_WORD(TRACE_DEV_REG_STOP_EMU, 1)
+/* enable/disable tracing */
+#define TRACE_ENABLE_TRACING()       DEV_WRITE_WORD(TRACE_DEV_REG_ENABLE, 1)
+#define TRACE_DISABLE_TRACING()      DEV_WRITE_WORD(TRACE_DEV_REG_DISABLE, 1)
+/* dynamic symbols */
+#define TRACE_DYN_SYM(addr,sym)\
+do {\
+    DEV_WRITE_WORD(TRACE_DEV_REG_DYN_SYM_ADDR, (addr));\
+    DEV_WRITE_WORD(TRACE_DEV_REG_DYN_SYM, (unsigned long)(sym));\
+}while(0)
+/* prints */
+#define PRINT_STR(str)         DEV_WRITE_WORD(TRACE_DEV_REG_PRINT_STR, (unsigned long)(str))
+#define PRINT_NUM_DEC(num)     DEV_WRITE_WORD(TRACE_DEV_REG_PRINT_NUM_DEC, (num))
+#define PRINT_NUM_HEX(num)     DEV_WRITE_WORD(TRACE_DEV_REG_PRINT_NUM_HEX, (num))
+
+#endif
diff --git a/emulator/qtools/tests/tests.ld b/emulator/qtools/tests/tests.ld
new file mode 100644
index 0000000..05fe41b
--- /dev/null
+++ b/emulator/qtools/tests/tests.ld
@@ -0,0 +1,10 @@
+SECTIONS {
+  TEXT_START = 0x00010000 ;
+  DATA_START = 0x00200000 ;
+  handlers 0x0 : { *(handlers) }
+  .text TEXT_START : { *(.text) }
+  .data DATA_START : { *(.data) }
+  .bss  : { *(.bss) *(COMMON) }
+  p00300000 0x00300000 : { *(p00300000) }
+  p00400000 0x00400000 : { *(p00400000) }
+}
diff --git a/emulator/qtools/thumbdis.cpp b/emulator/qtools/thumbdis.cpp
new file mode 100644
index 0000000..f4294dd
--- /dev/null
+++ b/emulator/qtools/thumbdis.cpp
@@ -0,0 +1,503 @@
+/* Instruction printing code for the ARM
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
+   Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
+   Modification by James G. Smith (jsmith@cygnus.co.uk)
+
+This file is part of libopcodes. 
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version. 
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details. 
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Modified to fit into the qtools framework.  The main differences are:
+ *
+ * - The disassembly function returns a string instead of writing it to a
+ * file stream.
+ *
+ * - All the references to the struct "disassemble_info" have been removed.
+ *
+ * - A set of enums for the thumb opcodes have been defined, along with a
+ * "decode()" function that maps a thumb instruction to an opcode enum.
+ *
+ * - Eliminated uses of the special characters ', `, and ? from the
+ * thumb_opcodes[] table so that we can easily specify separate opcodes
+ * for distinct instructions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "opcode.h"
+
+
+struct thumb_opcode
+{
+    unsigned short value, mask;  /* recognise instruction if (op&mask)==value */
+    Opcode opcode;
+    char * assembler;            /* how to disassemble this instruction */
+};
+
+/* format of the assembler string :
+   
+   %%                   %
+   %<bitfield>d         print the bitfield in decimal
+   %<bitfield>x         print the bitfield in hex
+   %<bitfield>X         print the bitfield as 1 hex digit without leading "0x"
+   %<bitfield>r         print as an ARM register
+   %<bitfield>f         print a floating point constant if >7 else a
+                          floating point register
+   %<code>y             print a single precision VFP reg.
+                          Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair
+   %<code>z             print a double precision VFP reg
+                          Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list
+   %c                   print condition code (always bits 28-31)
+   %P                   print floating point precision in arithmetic insn
+   %Q                   print floating point precision in ldf/stf insn
+   %R                   print floating point rounding mode
+   %<bitnum>'c          print specified char iff bit is one
+   %<bitnum>`c          print specified char iff bit is zero
+   %<bitnum>?ab         print a if bit is one else print b
+   %p                   print 'p' iff bits 12-15 are 15
+   %t                   print 't' iff bit 21 set and bit 24 clear
+   %o                   print operand2 (immediate or register + shift)
+   %a                   print address for ldr/str instruction
+   %s                   print address for ldr/str halfword/signextend instruction
+   %b                   print branch destination
+   %B                   print arm BLX(1) destination
+   %A                   print address for ldc/stc/ldf/stf instruction
+   %m                   print register mask for ldm/stm instruction
+   %C                   print the PSR sub type.
+   %F                   print the COUNT field of a LFM/SFM instruction.
+Thumb specific format options:
+   %D                   print Thumb register (bits 0..2 as high number if bit 7 set)
+   %S                   print Thumb register (bits 3..5 as high number if bit 6 set)
+   %<bitfield>I         print bitfield as a signed decimal
+                          (top bit of range being the sign bit)
+   %M                   print Thumb register mask
+   %N                   print Thumb register mask (with LR)
+   %O                   print Thumb register mask (with PC)
+   %T                   print Thumb condition code (always bits 8-11)
+   %I                   print cirrus signed shift immediate: bits 0..3|4..6
+   %<bitfield>B         print Thumb branch destination (signed displacement)
+   %<bitfield>W         print (bitfield * 4) as a decimal
+   %<bitfield>H         print (bitfield * 2) as a decimal
+   %<bitfield>a         print (bitfield * 4) as a pc-rel offset + decoded symbol
+*/
+
+
+static struct thumb_opcode thumb_opcodes[] =
+{
+    /* Thumb instructions.  */
+
+    /* ARM V5 ISA extends Thumb.  */
+    {0xbe00, 0xff00, OP_THUMB_BKPT, "bkpt\t%0-7x"},
+    {0x4780, 0xff87, OP_THUMB_BLX, "blx\t%3-6r"},  /* note: 4 bit register number.  */
+    /* Format 5 instructions do not update the PSR.  */
+    {0x1C00, 0xFFC0, OP_THUMB_MOV, "mov\t%0-2r, %3-5r"},
+    /* Format 4.  */
+    {0x4000, 0xFFC0, OP_THUMB_AND, "and\t%0-2r, %3-5r"},
+    {0x4040, 0xFFC0, OP_THUMB_EOR, "eor\t%0-2r, %3-5r"},
+    {0x4080, 0xFFC0, OP_THUMB_LSL, "lsl\t%0-2r, %3-5r"},
+    {0x40C0, 0xFFC0, OP_THUMB_LSR, "lsr\t%0-2r, %3-5r"},
+    {0x4100, 0xFFC0, OP_THUMB_ASR, "asr\t%0-2r, %3-5r"},
+    {0x4140, 0xFFC0, OP_THUMB_ADC, "adc\t%0-2r, %3-5r"},
+    {0x4180, 0xFFC0, OP_THUMB_SBC, "sbc\t%0-2r, %3-5r"},
+    {0x41C0, 0xFFC0, OP_THUMB_ROR, "ror\t%0-2r, %3-5r"},
+    {0x4200, 0xFFC0, OP_THUMB_TST, "tst\t%0-2r, %3-5r"},
+    {0x4240, 0xFFC0, OP_THUMB_NEG, "neg\t%0-2r, %3-5r"},
+    {0x4280, 0xFFC0, OP_THUMB_CMP, "cmp\t%0-2r, %3-5r"},
+    {0x42C0, 0xFFC0, OP_THUMB_CMN, "cmn\t%0-2r, %3-5r"},
+    {0x4300, 0xFFC0, OP_THUMB_ORR, "orr\t%0-2r, %3-5r"},
+    {0x4340, 0xFFC0, OP_THUMB_MUL, "mul\t%0-2r, %3-5r"},
+    {0x4380, 0xFFC0, OP_THUMB_BIC, "bic\t%0-2r, %3-5r"},
+    {0x43C0, 0xFFC0, OP_THUMB_MVN, "mvn\t%0-2r, %3-5r"},
+    /* format 13 */
+    {0xB000, 0xFF80, OP_THUMB_ADD, "add\tsp, #%0-6W"},
+    {0xB080, 0xFF80, OP_THUMB_SUB, "sub\tsp, #%0-6W"},
+    /* format 5 */
+    {0x4700, 0xFF80, OP_THUMB_BX, "bx\t%S"},
+    {0x4400, 0xFF00, OP_THUMB_ADD, "add\t%D, %S"},
+    {0x4500, 0xFF00, OP_THUMB_CMP, "cmp\t%D, %S"},
+    {0x4600, 0xFF00, OP_THUMB_MOV, "mov\t%D, %S"},
+    /* format 14 */
+    {0xB400, 0xFE00, OP_THUMB_PUSH, "push\t%N"},
+    {0xBC00, 0xFE00, OP_THUMB_POP, "pop\t%O"},
+    /* format 2 */
+    {0x1800, 0xFE00, OP_THUMB_ADD, "add\t%0-2r, %3-5r, %6-8r"},
+    {0x1A00, 0xFE00, OP_THUMB_SUB, "sub\t%0-2r, %3-5r, %6-8r"},
+    {0x1C00, 0xFE00, OP_THUMB_ADD, "add\t%0-2r, %3-5r, #%6-8d"},
+    {0x1E00, 0xFE00, OP_THUMB_SUB, "sub\t%0-2r, %3-5r, #%6-8d"},
+    /* format 8 */
+    {0x5200, 0xFE00, OP_THUMB_STRH, "strh\t%0-2r, [%3-5r, %6-8r]"},
+    {0x5A00, 0xFE00, OP_THUMB_LDRH, "ldrh\t%0-2r, [%3-5r, %6-8r]"},
+    {0x5600, 0xFE00, OP_THUMB_LDRSB, "ldrsb\t%0-2r, [%3-5r, %6-8r]"},
+    {0x5E00, 0xFE00, OP_THUMB_LDRSH, "ldrsh\t%0-2r, [%3-5r, %6-8r]"},
+    /* format 7 */
+    {0x5000, 0xFE00, OP_THUMB_STR, "str\t%0-2r, [%3-5r, %6-8r]"},
+    {0x5400, 0xFE00, OP_THUMB_STRB, "strb\t%0-2r, [%3-5r, %6-8r]"},
+    {0x5800, 0xFE00, OP_THUMB_LDR, "ldr\t%0-2r, [%3-5r, %6-8r]"},
+    {0x5C00, 0xFE00, OP_THUMB_LDRB, "ldrb\t%0-2r, [%3-5r, %6-8r]"},
+    /* format 1 */
+    {0x0000, 0xF800, OP_THUMB_LSL, "lsl\t%0-2r, %3-5r, #%6-10d"},
+    {0x0800, 0xF800, OP_THUMB_LSR, "lsr\t%0-2r, %3-5r, #%6-10d"},
+    {0x1000, 0xF800, OP_THUMB_ASR, "asr\t%0-2r, %3-5r, #%6-10d"},
+    /* format 3 */
+    {0x2000, 0xF800, OP_THUMB_MOV, "mov\t%8-10r, #%0-7d"},
+    {0x2800, 0xF800, OP_THUMB_CMP, "cmp\t%8-10r, #%0-7d"},
+    {0x3000, 0xF800, OP_THUMB_ADD, "add\t%8-10r, #%0-7d"},
+    {0x3800, 0xF800, OP_THUMB_SUB, "sub\t%8-10r, #%0-7d"},
+    /* format 6 */
+    /* TODO: Disassemble PC relative "LDR rD,=<symbolic>" */
+    {0x4800, 0xF800, OP_THUMB_LDR, "ldr\t%8-10r, [pc, #%0-7W]\t(%0-7a)"},
+    /* format 9 */
+    {0x6000, 0xF800, OP_THUMB_STR, "str\t%0-2r, [%3-5r, #%6-10W]"},
+    {0x6800, 0xF800, OP_THUMB_LDR, "ldr\t%0-2r, [%3-5r, #%6-10W]"},
+    {0x7000, 0xF800, OP_THUMB_STRB, "strb\t%0-2r, [%3-5r, #%6-10d]"},
+    {0x7800, 0xF800, OP_THUMB_LDRB, "ldrb\t%0-2r, [%3-5r, #%6-10d]"},
+    /* format 10 */
+    {0x8000, 0xF800, OP_THUMB_STRH, "strh\t%0-2r, [%3-5r, #%6-10H]"},
+    {0x8800, 0xF800, OP_THUMB_LDRH, "ldrh\t%0-2r, [%3-5r, #%6-10H]"},
+    /* format 11 */
+    {0x9000, 0xF800, OP_THUMB_STR, "str\t%8-10r, [sp, #%0-7W]"},
+    {0x9800, 0xF800, OP_THUMB_LDR, "ldr\t%8-10r, [sp, #%0-7W]"},
+    /* format 12 */
+    {0xA000, 0xF800, OP_THUMB_ADD, "add\t%8-10r, pc, #%0-7W\t(adr %8-10r,%0-7a)"},
+    {0xA800, 0xF800, OP_THUMB_ADD, "add\t%8-10r, sp, #%0-7W"},
+    /* format 15 */
+    {0xC000, 0xF800, OP_THUMB_STMIA, "stmia\t%8-10r!,%M"},
+    {0xC800, 0xF800, OP_THUMB_LDMIA, "ldmia\t%8-10r!,%M"},
+    /* format 18 */
+    {0xE000, 0xF800, OP_THUMB_B, "b\t%0-10B"},
+    /* format 19 */
+    /* special processing required in disassembler */
+    {0xF000, 0xF800, OP_THUMB_BL, ""},
+    {0xF800, 0xF800, OP_THUMB_BL, "second half of BL instruction %0-15x"},
+    {0xE800, 0xF800, OP_THUMB_BLX, "second half of BLX instruction %0-15x"},
+    /* format 16 */
+    {0xD000, 0xFF00, OP_THUMB_B, "beq\t%0-7B"},
+    {0xD100, 0xFF00, OP_THUMB_B, "bne\t%0-7B"},
+    {0xD200, 0xFF00, OP_THUMB_B, "bcs\t%0-7B"},
+    {0xD300, 0xFF00, OP_THUMB_B, "bcc\t%0-7B"},
+    {0xD400, 0xFF00, OP_THUMB_B, "bmi\t%0-7B"},
+    {0xD500, 0xFF00, OP_THUMB_B, "bpl\t%0-7B"},
+    {0xD600, 0xFF00, OP_THUMB_B, "bvs\t%0-7B"},
+    {0xD700, 0xFF00, OP_THUMB_B, "bvc\t%0-7B"},
+    {0xD800, 0xFF00, OP_THUMB_B, "bhi\t%0-7B"},
+    {0xD900, 0xFF00, OP_THUMB_B, "bls\t%0-7B"},
+    {0xDA00, 0xFF00, OP_THUMB_B, "bge\t%0-7B"},
+    {0xDB00, 0xFF00, OP_THUMB_B, "blt\t%0-7B"},
+    {0xDC00, 0xFF00, OP_THUMB_B, "bgt\t%0-7B"},
+    {0xDD00, 0xFF00, OP_THUMB_B, "ble\t%0-7B"},
+    /* format 17 */
+    {0xDE00, 0xFF00, OP_THUMB_UNDEFINED, "undefined"},
+    {0xDF00, 0xFF00, OP_THUMB_SWI, "swi\t%0-7d"},
+    /* format 9 */
+    {0x6000, 0xF800, OP_THUMB_STR, "str\t%0-2r, [%3-5r, #%6-10W]"},
+    {0x6800, 0xF800, OP_THUMB_LDR, "ldr\t%0-2r, [%3-5r, #%6-10W]"},
+    {0x7000, 0xF800, OP_THUMB_STRB, "strb\t%0-2r, [%3-5r, #%6-10d]"},
+    {0x7800, 0xF800, OP_THUMB_LDRB, "ldrb\t%0-2r, [%3-5r, #%6-10d]"},
+    /* the rest */
+    {0x0000, 0x0000, OP_THUMB_UNDEFINED, "undefined instruction %0-15x"},
+    {0x0000, 0x0000, OP_END, 0}
+};
+
+#define BDISP23(x,y) ((((((x) & 0x07ff) << 11) | ((y) & 0x07ff)) \
+                     ^ 0x200000) - 0x200000) /* 23bit */
+
+static char * arm_conditional[] =
+{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
+
+typedef struct
+{
+  const char * name;
+  const char * description;
+  const char * reg_names[16];
+}
+arm_regname;
+
+static arm_regname regnames[] =
+{
+  { "raw" , "Select raw register names",
+    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
+  { "gcc",  "Select register names used by GCC",
+    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl",  "fp",  "ip",  "sp",  "lr",  "pc" }},
+  { "std",  "Select register names used in ARM's ISA documentation",
+    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp",  "lr",  "pc" }},
+  { "apcs", "Select register names used in the APCS",
+    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl",  "fp",  "ip",  "sp",  "lr",  "pc" }},
+  { "atpcs", "Select register names used in the ATPCS",
+    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7",  "v8",  "IP",  "SP",  "LR",  "PC" }},
+  { "special-atpcs", "Select special register names used in the ATPCS",
+    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL",  "FP",  "IP",  "SP",  "LR",  "PC" }}
+};
+
+/* Default to STD register name set.  */
+static unsigned int regname_selected = 2;
+
+#define NUM_ARM_REGNAMES  NUM_ELEM (regnames)
+#define arm_regnames      regnames[regname_selected].reg_names
+
+Opcode decode_insn_thumb(uint32_t given)
+{
+    struct thumb_opcode * insn;
+
+    for (insn = thumb_opcodes; insn->assembler; insn++) {
+        if ((given & insn->mask) == insn->value)
+            return insn->opcode;
+    }
+    return OP_THUMB_UNDEFINED;
+}
+
+// Generates the disassembly string for the thumb instruction "insn1".
+// If "insn1" is a BL or BLX instruction that is the first of two Thumb
+// instructions, then insn2 is the second of two instructions.  Otherwise,
+// insn2 is ignored.
+char *disasm_insn_thumb(uint32_t pc, uint32_t insn1, uint32_t insn2, char *result)
+{
+    struct thumb_opcode * insn;
+    static char buf[80];
+    char *ptr;
+    uint32_t addr;
+    int len;
+
+    if (result == NULL)
+        result = buf;
+    ptr = result;
+
+    for (insn = thumb_opcodes; insn->assembler; insn++) {
+        if ((insn1 & insn->mask) != insn->value)
+            continue;
+
+        char * c = insn->assembler;
+
+        /* Special processing for Thumb 2-instruction BL sequence:  */
+        if (!*c) { /* Check for empty (not NULL) assembler string.  */
+            uint32_t offset;
+
+            offset = BDISP23 (insn1, insn2);
+            offset = offset * 2 + pc + 4;
+            
+            if ((insn2 & 0x1000) == 0) {
+                len = sprintf(ptr, "blx\t");
+                offset &= 0xfffffffc;
+            } else {
+                len = sprintf(ptr, "bl\t");
+            }
+            ptr += len;
+            
+            sprintf(ptr, "0x%x", offset);
+            return result;
+        }
+        
+        insn1 &= 0xffff;
+        
+        for (; *c; c++) {
+            if (*c != '%') {
+                len = sprintf(ptr, "%c", *c);
+                ptr += len;
+                continue;
+            }
+
+            int domaskpc = 0;
+            int domasklr = 0;
+            
+            switch (*++c) {
+                case '%':
+                    len = sprintf(ptr, "%%");
+                    ptr += len;
+                    break;
+                    
+                case 'S': {
+                    uint32_t reg;
+                    
+                    reg = (insn1 >> 3) & 0x7;
+                    if (insn1 & (1 << 6))
+                        reg += 8;
+                    
+                    len = sprintf(ptr, "%s", arm_regnames[reg]);
+                    ptr += len;
+                    break;
+                }
+                    
+                case 'D': {
+                    uint32_t reg;
+                    
+                    reg = insn1 & 0x7;
+                    if (insn1 & (1 << 7))
+                        reg += 8;
+                    
+                    len = sprintf(ptr, "%s", arm_regnames[reg]);
+                    ptr += len;
+                    break;
+                }
+                    
+                case 'T':
+                    len = sprintf(ptr, "%s",
+                          arm_conditional [(insn1 >> 8) & 0xf]);
+                    ptr += len;
+                    break;
+                    
+                case 'N':
+                    if (insn1 & (1 << 8))
+                        domasklr = 1;
+                    /* Fall through.  */
+                case 'O':
+                    if (*c == 'O' && (insn1 & (1 << 8)))
+                        domaskpc = 1;
+                    /* Fall through.  */
+                case 'M': {
+                    int started = 0;
+                    int reg;
+                    
+                    len = sprintf(ptr, "{");
+                    ptr += len;
+                    
+                    /* It would be nice if we could spot
+                       ranges, and generate the rS-rE format: */
+                    for (reg = 0; (reg < 8); reg++)
+                        if ((insn1 & (1 << reg)) != 0) {
+                            if (started) {
+                                len = sprintf(ptr, ", ");
+                                ptr += len;
+                            }
+                            started = 1;
+                            len = sprintf(ptr, "%s", arm_regnames[reg]);
+                            ptr += len;
+                        }
+                    
+                    if (domasklr) {
+                        if (started) {
+                            len = sprintf(ptr, ", ");
+                            ptr += len;
+                        }
+                        started = 1;
+                        len = sprintf(ptr, arm_regnames[14] /* "lr" */);
+                        ptr += len;
+                    }
+                    
+                    if (domaskpc) {
+                        if (started) {
+                            len = sprintf(ptr, ", ");
+                            ptr += len;
+                        }
+                        len = sprintf(ptr, arm_regnames[15] /* "pc" */);
+                        ptr += len;
+                    }
+                    
+                    len = sprintf(ptr, "}");
+                    ptr += len;
+                    break;
+                }
+                    
+                case '0': case '1': case '2': case '3': case '4': 
+                case '5': case '6': case '7': case '8': case '9': {
+                    int bitstart = *c++ - '0';
+                    int bitend = 0;
+                    
+                    while (*c >= '0' && *c <= '9')
+                        bitstart = (bitstart * 10) + *c++ - '0';
+                    
+                    switch (*c) {
+                        case '-': {
+                            uint32_t reg;
+                            
+                            c++;
+                            while (*c >= '0' && *c <= '9')
+                                bitend = (bitend * 10) + *c++ - '0';
+                            if (!bitend)
+                                abort ();
+                            reg = insn1 >> bitstart;
+                            reg &= (2 << (bitend - bitstart)) - 1;
+                            switch (*c) {
+                                case 'r':
+                                    len = sprintf(ptr, "%s", arm_regnames[reg]);
+                                    break;
+                                    
+                                case 'd':
+                                    len = sprintf(ptr, "%d", reg);
+                                    break;
+                                    
+                                case 'H':
+                                    len = sprintf(ptr, "%d", reg << 1);
+                                    break;
+                                    
+                                case 'W':
+                                    len = sprintf(ptr, "%d", reg << 2);
+                                    break;
+                                    
+                                case 'a':
+                                    /* PC-relative address -- the bottom two
+                                       bits of the address are dropped
+                                       before the calculation.  */
+                                    addr = ((pc + 4) & ~3) + (reg << 2);
+                                    len = sprintf(ptr, "0x%x", addr);
+                                    break;
+                                    
+                                case 'x':
+                                    len = sprintf(ptr, "0x%04x", reg);
+                                    break;
+                                    
+                                case 'I':
+                                    reg = ((reg ^ (1 << bitend)) - (1 << bitend));
+                                    len = sprintf(ptr, "%d", reg);
+                                    break;
+                                    
+                                case 'B':
+                                    reg = ((reg ^ (1 << bitend)) - (1 << bitend));
+                                    addr = reg * 2 + pc + 4;
+                                    len = sprintf(ptr, "0x%x", addr);
+                                    break;
+                                    
+                                default:
+                                    abort ();
+                            }
+                            ptr += len;
+                            break;
+                        }
+                            
+                        case '\'':
+                            c++;
+                            if ((insn1 & (1 << bitstart)) != 0) {
+                                len = sprintf(ptr, "%c", *c);
+                                ptr += len;
+                            }
+                            break;
+                            
+                        case '?':
+                            ++c;
+                            if ((insn1 & (1 << bitstart)) != 0)
+                                len = sprintf(ptr, "%c", *c++);
+                            else
+                                len = sprintf(ptr, "%c", *++c);
+                            ptr += len;
+                            break;
+                            
+                        default:
+                            abort ();
+                    }
+                    break;
+                }
+                    
+                default:
+                    abort ();
+            }
+        }
+        return result;
+    }
+    
+    /* No match.  */
+    abort ();
+}
diff --git a/emulator/qtools/trace_reader.cpp b/emulator/qtools/trace_reader.cpp
new file mode 100644
index 0000000..b38c0b4
--- /dev/null
+++ b/emulator/qtools/trace_reader.cpp
@@ -0,0 +1,1201 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <elf.h>
+#include "trace_reader.h"
+#include "decoder.h"
+
+// A struct for creating temporary linked-lists of DexSym structs
+struct DexSymList {
+    DexSymList  *next;
+    DexSym      sym;
+};
+
+// Declare static functions used in this file
+static char *ExtractDexPathFromMmap(const char *mmap_path);
+static void CopyDexSymbolsToArray(DexFileList *dexfile,
+                                  DexSymList *head, int num_symbols);
+
+// This function creates the pathname to the a specific trace file.  The
+// string space is allocated in this routine and must be freed by the
+// caller.
+static char *CreateTracePath(const char *filename, const char *ext)
+{
+    char *fname;
+    const char *base_start, *base_end;
+    int ii, len, base_len, dir_len, path_len, qtrace_len;
+
+    // Handle error cases
+    if (filename == NULL || *filename == 0 || strcmp(filename, "/") == 0)
+        return NULL;
+
+    // Ignore a trailing slash, if any
+    len = strlen(filename);
+    if (filename[len - 1] == '/')
+        len -= 1;
+
+    // Find the basename.  We don't use basename(3) because there are
+    // different behaviors for GNU and Posix in the case where the
+    // last character is a slash.
+    base_start = base_end = &filename[len];
+    for (ii = 0; ii < len; ++ii) {
+        base_start -= 1;
+        if (*base_start == '/') {
+            base_start += 1;
+            break;
+        }
+    }
+    base_len = base_end - base_start;
+    dir_len = len - base_len;
+    qtrace_len = strlen("/qtrace");
+
+    // Create space for the pathname: "/dir/basename/qtrace.ext"
+    // The "ext" string already contains the dot, so just add a byte
+    // for the terminating zero.
+    path_len = dir_len + base_len + qtrace_len + strlen(ext) + 1;
+    fname = new char[path_len];
+    if (dir_len > 0)
+        strncpy(fname, filename, dir_len);
+    fname[dir_len] = 0;
+    strncat(fname, base_start, base_len);
+    strcat(fname, "/qtrace");
+    strcat(fname, ext);
+    return fname;
+}
+
+inline BBReader::Future *BBReader::AllocFuture()
+{
+    Future *future = free_;
+    free_ = free_->next;
+    return future;
+}
+
+inline void BBReader::FreeFuture(Future *future)
+{
+    future->next = free_;
+    free_ = future;
+}
+
+inline void BBReader::InsertFuture(Future *future)
+{
+    uint64_t future_time = future->bb.next_time;
+    Future *prev = NULL;
+    Future *ptr;
+    for (ptr = head_; ptr; prev = ptr, ptr = ptr->next) {
+        if (future_time <= ptr->bb.next_time)
+            break;
+    }
+    if (prev == NULL) {
+        // link it at the front
+        future->next = head_;
+        head_ = future;
+    } else {
+        // link it after "prev"
+        future->next = prev->next;
+        prev->next = future;
+    }
+}
+
+// Decodes the next basic block record from the file.  Returns 1
+// at end-of-file, otherwise returns 0.
+inline int BBReader::DecodeNextRec()
+{
+    int64_t bb_diff = decoder_->Decode(true);
+    uint64_t time_diff = decoder_->Decode(false);
+    nextrec_.bb_rec.repeat = decoder_->Decode(false);
+    if (time_diff == 0)
+        return 1;
+    if (nextrec_.bb_rec.repeat)
+        nextrec_.bb_rec.time_diff = decoder_->Decode(false);
+    nextrec_.bb_rec.bb_num += bb_diff;
+    nextrec_.bb_rec.start_time += time_diff;
+    return 0;
+}
+
+BBReader::BBReader(TraceReaderBase *trace)
+{
+    trace_ = trace;
+    decoder_ = new Decoder;
+}
+
+BBReader::~BBReader()
+{
+    delete decoder_;
+}
+
+void BBReader::Open(char *filename)
+{
+    // Initialize the class variables
+    memset(&nextrec_, 0, sizeof(TimeRec));
+    memset(futures_, 0, sizeof(Future) * kMaxNumBasicBlocks);
+    head_ = NULL;
+
+    // Link all of the futures_[] array elements on the free list.
+    for (int ii = 0; ii < kMaxNumBasicBlocks - 1; ++ii) {
+        futures_[ii].next = &futures_[ii + 1];
+    }
+    futures_[kMaxNumBasicBlocks - 1].next = 0;
+    free_ = &futures_[0];
+
+    // Open the trace.bb file
+    char *fname = CreateTracePath(filename, ".bb");
+    decoder_->Open(fname);
+    is_eof_ = DecodeNextRec();
+    delete[] fname;
+}
+
+void BBReader::Close()
+{
+    decoder_->Close();
+}
+
+// Returns true at end of file.
+bool BBReader::ReadBB(BBEvent *event)
+{
+    if (is_eof_ && head_ == NULL) {
+        return true;
+    }
+
+#if 0
+    if (nextrec_) {
+        printf("nextrec: buffer[%d], bb_num: %lld start: %d diff %d repeat %d next %u\n",
+               nextrec_ - &buffer_[0],
+               nextrec_->bb_rec.bb_num, nextrec_->bb_rec.start_time,
+               nextrec_->bb_rec.time_diff, nextrec_->bb_rec.repeat,
+               nextrec_->next_time);
+    }
+    if (head_) {
+        printf("head: 0x%x, bb_num: %lld start: %d diff %d repeat %d next %u\n",
+               head_,
+               head_->bb->bb_rec.bb_num, head_->bb->bb_rec.start_time,
+               head_->bb->bb_rec.time_diff, head_->bb->bb_rec.repeat,
+               head_->bb->next_time);
+    }
+#endif
+    if (!is_eof_) {
+        if (head_) {
+            TimeRec *bb = &head_->bb;
+            if (bb->next_time < nextrec_.bb_rec.start_time) {
+                // The head is earlier.
+                event->time = bb->next_time;
+                event->bb_num = bb->bb_rec.bb_num;
+                event->bb_addr = trace_->GetBBAddr(event->bb_num);
+                event->insns = trace_->GetInsns(event->bb_num);
+                event->num_insns = trace_->FindNumInsns(event->bb_num, event->time);
+                event->pid = trace_->FindCurrentPid(event->time);
+                event->is_thumb = trace_->GetIsThumb(event->bb_num);
+
+                // Remove the head element from the list
+                Future *future = head_;
+                head_ = head_->next;
+                if (bb->bb_rec.repeat > 0) {
+                    // there are more repetitions of this bb
+                    bb->bb_rec.repeat -= 1;
+                    bb->next_time += bb->bb_rec.time_diff;
+
+                    // Insert this future into the sorted list
+                    InsertFuture(future);
+                } else {
+                    // Add this future to the free list
+                    FreeFuture(future);
+                }
+                return false;
+            }
+        }
+        // The nextrec is earlier (or there was no head)
+        event->time = nextrec_.bb_rec.start_time;
+        event->bb_num = nextrec_.bb_rec.bb_num;
+        event->bb_addr = trace_->GetBBAddr(event->bb_num);
+        event->insns = trace_->GetInsns(event->bb_num);
+        event->num_insns = trace_->FindNumInsns(event->bb_num, event->time);
+        event->pid = trace_->FindCurrentPid(event->time);
+        event->is_thumb = trace_->GetIsThumb(event->bb_num);
+        if (nextrec_.bb_rec.repeat > 0) {
+            Future *future = AllocFuture();
+            future->bb.bb_rec = nextrec_.bb_rec;
+            future->bb.bb_rec.repeat -= 1;
+            future->bb.next_time = nextrec_.bb_rec.start_time + nextrec_.bb_rec.time_diff;
+            InsertFuture(future);
+        }
+
+        is_eof_ = DecodeNextRec();
+        return false;
+    }
+
+    //printf("using head_ 0x%x\n", head_);
+    assert(head_);
+    TimeRec *bb = &head_->bb;
+    event->time = bb->next_time;
+    event->bb_num = bb->bb_rec.bb_num;
+    event->bb_addr = trace_->GetBBAddr(event->bb_num);
+    event->insns = trace_->GetInsns(event->bb_num);
+    event->num_insns = trace_->FindNumInsns(event->bb_num, event->time);
+    event->pid = trace_->FindCurrentPid(event->time);
+    event->is_thumb = trace_->GetIsThumb(event->bb_num);
+
+    // Remove the head element from the list
+    Future *future = head_;
+    head_ = head_->next;
+    if (bb->bb_rec.repeat > 0) {
+        // there are more repetitions of this bb
+        bb->bb_rec.repeat -= 1;
+        bb->next_time += bb->bb_rec.time_diff;
+
+        // Insert this future into the sorted list
+        InsertFuture(future);
+    } else {
+        // Add this future to the free list
+        FreeFuture(future);
+    }
+    return false;
+}
+
+InsnReader::InsnReader()
+{
+    decoder_ = new Decoder;
+}
+
+InsnReader::~InsnReader()
+{
+    delete decoder_;
+}
+
+void InsnReader::Open(char *filename)
+{
+    prev_time_ = 0;
+    time_diff_ = 0;
+    repeat_ = -1;
+
+    // Open the trace.insn file
+    char *fname = CreateTracePath(filename, ".insn");
+    decoder_->Open(fname);
+    delete[] fname;
+}
+
+void InsnReader::Close()
+{
+    decoder_->Close();
+}
+
+uint64_t InsnReader::ReadInsnTime(uint64_t min_time)
+{
+    do {
+        if (repeat_ == -1) {
+            time_diff_ = decoder_->Decode(false);
+            repeat_ = decoder_->Decode(false);
+        }
+        prev_time_ += time_diff_;
+        repeat_ -= 1;
+    } while (prev_time_ < min_time);
+    return prev_time_;
+}
+
+AddrReader::AddrReader()
+{
+    decoder_ = new Decoder;
+    opened_ = false;
+}
+
+AddrReader::~AddrReader()
+{
+    delete decoder_;
+}
+
+// Returns true if there is an error opening the file
+bool AddrReader::Open(char *filename, char *suffix)
+{
+    struct stat stat_buf;
+
+    prev_addr_ = 0;
+    prev_time_ = 0;
+
+    // Open the trace.addr file
+    char *fname = CreateTracePath(filename, suffix);
+    int rval = stat(fname, &stat_buf);
+    if (rval == -1) {
+        // The file does not exist
+        delete[] fname;
+        return true;
+    }
+    decoder_->Open(fname);
+    opened_ = true;
+    delete[] fname;
+    return false;
+}
+
+void AddrReader::Close()
+{
+    decoder_->Close();
+}
+
+// Returns true at end of file.
+bool AddrReader::ReadAddr(uint64_t *time, uint32_t *addr)
+{
+    if (!opened_) {
+        fprintf(stderr, "Cannot read address trace\n");
+        exit(1);
+    }
+    uint32_t addr_diff = decoder_->Decode(true);
+    uint64_t time_diff = decoder_->Decode(false);
+    if (time_diff == 0 && addr_diff == 0) {
+        *addr = 0;
+        *time = 0;
+        return true;
+    }
+    prev_addr_ += addr_diff;
+    prev_time_ += time_diff;
+    *addr = prev_addr_;
+    *time = prev_time_;
+    return false;
+}
+
+ExcReader::ExcReader()
+{
+    decoder_ = new Decoder;
+}
+
+ExcReader::~ExcReader()
+{
+    delete decoder_;
+}
+
+void ExcReader::Open(char *filename)
+{
+    prev_time_ = 0;
+    prev_recnum_ = 0;
+
+    // Open the trace.exc file
+    char *fname = CreateTracePath(filename, ".exc");
+    decoder_->Open(fname);
+    delete[] fname;
+}
+
+void ExcReader::Close()
+{
+    decoder_->Close();
+}
+
+// Returns true at end of file.
+bool ExcReader::ReadExc(uint64_t *time, uint32_t *current_pc, uint64_t *recnum,
+                        uint32_t *target_pc, uint64_t *bb_num,
+                        uint64_t *bb_start_time, int *num_insns)
+{
+    uint64_t time_diff = decoder_->Decode(false);
+    uint32_t pc = decoder_->Decode(false);
+    if ((time_diff | pc) == 0) {
+        decoder_->Decode(false);
+        decoder_->Decode(false);
+        decoder_->Decode(false);
+        decoder_->Decode(false);
+        decoder_->Decode(false);
+        return true;
+    }
+    uint64_t recnum_diff = decoder_->Decode(false);
+    prev_time_ += time_diff;
+    prev_recnum_ += recnum_diff;
+    *time = prev_time_;
+    *current_pc = pc;
+    *recnum = prev_recnum_;
+    *target_pc = decoder_->Decode(false);
+    *bb_num = decoder_->Decode(false);
+    *bb_start_time = decoder_->Decode(false);
+    *num_insns = decoder_->Decode(false);
+    return false;
+}
+
+PidReader::PidReader()
+{
+    decoder_ = new Decoder;
+}
+
+PidReader::~PidReader()
+{
+    delete decoder_;
+}
+
+void PidReader::Open(char *filename)
+{
+    prev_time_ = 0;
+
+    // Open the trace.pid file
+    char *fname = CreateTracePath(filename, ".pid");
+    decoder_->Open(fname);
+    delete[] fname;
+}
+
+void PidReader::Close()
+{
+    decoder_->Close();
+}
+
+// Returns true at end of file.
+bool PidReader::ReadPidEvent(PidEvent *event)
+{
+    uint64_t time_diff = decoder_->Decode(false);
+    int rec_type = decoder_->Decode(false);
+    prev_time_ += time_diff;
+    event->time = prev_time_;
+    event->rec_type = rec_type;
+    switch(rec_type) {
+        case kPidEndOfFile:
+            return true;
+        case kPidSwitch:
+        case kPidExit:
+            event->pid = decoder_->Decode(false);
+            break;
+        case kPidFork:
+        case kPidClone:
+            event->tgid = decoder_->Decode(false);
+            event->pid = decoder_->Decode(false);
+            break;
+        case kPidMmap:
+            {
+                event->vstart = decoder_->Decode(false);
+                event->vend = decoder_->Decode(false);
+                event->offset = decoder_->Decode(false);
+                int len = decoder_->Decode(false);
+                char *path = new char[len + 1];
+                decoder_->Read(path, len);
+                path[len] = 0;
+                event->path = path;
+                event->mmap_path = path;
+                char *dexfile = ExtractDexPathFromMmap(path);
+                if (dexfile != NULL) {
+                    delete[] event->path;
+                    event->path = dexfile;
+                }
+            }
+            break;
+        case kPidMunmap:
+            {
+                event->vstart = decoder_->Decode(false);
+                event->vend = decoder_->Decode(false);
+            }
+            break;
+        case kPidSymbolAdd:
+            {
+                event->vstart = decoder_->Decode(false);
+                int len = decoder_->Decode(false);
+                char *path = new char[len + 1];
+                decoder_->Read(path, len);
+                path[len] = 0;
+                event->path = path;
+            }
+            break;
+        case kPidSymbolRemove:
+            event->vstart = decoder_->Decode(false);
+            break;
+        case kPidExec:
+            {
+                int argc = decoder_->Decode(false);
+                event->argc = argc;
+                char **argv = new char*[argc];
+                event->argv = argv;
+                for (int ii = 0; ii < argc; ++ii) {
+                    int alen = decoder_->Decode(false);
+                    argv[ii] = new char[alen + 1];
+                    decoder_->Read(argv[ii], alen);
+                    argv[ii][alen] = 0;
+                }
+            }
+            break;
+        case kPidName:
+        case kPidKthreadName:
+            {
+                if (rec_type == kPidKthreadName) {
+                    event->tgid = decoder_->Decode(false);
+                }
+                event->pid = decoder_->Decode(false);
+                int len = decoder_->Decode(false);
+                char *path = new char[len + 1];
+                decoder_->Read(path, len);
+                path[len] = 0;
+                event->path = path;
+            }
+            break;
+    }
+    return false;
+}
+
+// Frees the memory that might have been allocated for the given event.
+void PidReader::Dispose(PidEvent *event)
+{
+    switch(event->rec_type) {
+        case kPidMmap:
+        case kPidSymbolAdd:
+        case kPidName:
+        case kPidKthreadName:
+            delete[] event->path;
+            event->path = NULL;
+            event->mmap_path = NULL;
+            break;
+
+        case kPidExec:
+            for (int ii = 0; ii < event->argc; ++ii) {
+                delete[] event->argv[ii];
+            }
+            delete[] event->argv;
+            event->argv = NULL;
+            event->argc = 0;
+            break;
+    }
+}
+
+
+MethodReader::MethodReader()
+{
+    decoder_ = new Decoder;
+    opened_ = false;
+}
+
+MethodReader::~MethodReader()
+{
+    delete decoder_;
+}
+
+bool MethodReader::Open(char *filename)
+{
+    struct stat stat_buf;
+
+    prev_time_ = 0;
+    prev_addr_ = 0;
+    prev_pid_ = 0;
+
+    // Open the trace.method file
+    char *fname = CreateTracePath(filename, ".method");
+    int rval = stat(fname, &stat_buf);
+    if (rval == -1) {
+        // The file does not exist
+        delete[] fname;
+        return true;
+    }
+    decoder_->Open(fname);
+    delete[] fname;
+    opened_ = true;
+    return false;
+}
+
+void MethodReader::Close()
+{
+    decoder_->Close();
+}
+
+// Returns true at end of file.
+bool MethodReader::ReadMethod(MethodRec *method_record)
+{
+    if (!opened_)
+        return true;
+    uint64_t time_diff = decoder_->Decode(false);
+    int32_t addr_diff = decoder_->Decode(true);
+    if (time_diff == 0) {
+        method_record->time = 0;
+        method_record->addr = 0;
+        method_record->flags = 0;
+        return true;
+    }
+    int32_t pid_diff = decoder_->Decode(true);
+    prev_time_ += time_diff;
+    prev_addr_ += addr_diff;
+    prev_pid_ += pid_diff;
+    method_record->time = prev_time_;
+    method_record->addr = prev_addr_;
+    method_record->pid = prev_pid_;
+    method_record->flags = decoder_->Decode(false);
+    return false;
+}
+
+TraceReaderBase::TraceReaderBase()
+{
+    static_filename_ = NULL;
+    static_fstream_ = NULL;
+    header_ = new TraceHeader;
+    bb_reader_ = new BBReader(this);
+    insn_reader_ = new InsnReader;
+    load_addr_reader_ = new AddrReader;
+    store_addr_reader_ = new AddrReader;
+    exc_reader_ = new ExcReader;
+    pid_reader_ = new PidReader;
+    method_reader_ = new MethodReader;
+    internal_exc_reader_ = new ExcReader;
+    internal_pid_reader_ = new PidReader;
+    internal_method_reader_ = new MethodReader;
+    blocks_ = NULL;
+    bb_recnum_ = 0;
+    exc_recnum_ = 0;
+    exc_end_ = false;
+    exc_bb_num_ = 0;
+    exc_time_ = 0;
+    exc_num_insns_ = 0;
+    current_pid_ = 0;
+    next_pid_ = 0;
+    next_pid_switch_time_ = 0;
+    post_processing_ = false;
+    dex_hash_ = NULL;
+    load_eof_ = false;
+    load_time_ = 0;
+    load_addr_ = 0;
+    store_eof_ = false;
+    store_time_ = 0;
+    store_addr_ = 0;
+}
+
+TraceReaderBase::~TraceReaderBase()
+{
+    Close();
+    delete bb_reader_;
+    delete insn_reader_;
+    delete load_addr_reader_;
+    delete store_addr_reader_;
+    delete exc_reader_;
+    delete pid_reader_;
+    delete method_reader_;
+    delete internal_exc_reader_;
+    delete internal_pid_reader_;
+    delete internal_method_reader_;
+    if (blocks_) {
+        int num_static_bb = header_->num_static_bb;
+        for (int ii = 0; ii < num_static_bb; ++ii) {
+            delete[] blocks_[ii].insns;
+        }
+        delete[] blocks_;
+    }
+    delete header_;
+    if (dex_hash_ != NULL) {
+        HashTable<DexFileList*>::entry_type *ptr;
+        for (ptr = dex_hash_->GetFirst(); ptr; ptr = dex_hash_->GetNext()) {
+            DexFileList *dexfile = ptr->value;
+            delete[] dexfile->path;
+            int nsymbols = dexfile->nsymbols;
+            DexSym *symbols = dexfile->symbols;
+            for (int ii = 0; ii < nsymbols; ii++) {
+                delete[] symbols[ii].name;
+            }
+            delete[] dexfile->symbols;
+            delete dexfile;
+        }
+    }
+    delete dex_hash_;
+    delete[] static_filename_;
+}
+
+void TraceReaderBase::ReadTraceHeader(FILE *fstream, char *filename,
+                                      char *tracename, TraceHeader *header)
+{
+    int rval = fread(header, sizeof(TraceHeader), 1, fstream);
+    if (rval != 1) {
+        perror(filename);
+        exit(1);
+    }
+
+    if (!post_processing_ && strcmp(header->ident, TRACE_IDENT) != 0) {
+        fprintf(stderr, "%s: missing trace header; run 'post_trace %s' first\n",
+                filename, tracename);
+        exit(1);
+    }
+
+    if (header->version != TRACE_VERSION) {
+        fprintf(stderr,
+                "%s: trace header version (%d) does not match compiled tools version (%d)\n",
+                tracename, header->version, TRACE_VERSION);
+        exit(1);
+    }
+
+    convert32(header->version);
+    convert32(header->start_sec);
+    convert32(header->start_usec);
+    convert32(header->pdate);
+    convert32(header->ptime);
+    convert64(header->num_static_bb);
+    convert64(header->num_static_insn);
+    convert64(header->num_dynamic_bb);
+    convert64(header->num_dynamic_insn);
+    convert64(header->elapsed_usecs);
+}
+
+
+void TraceReaderBase::Open(char *filename)
+{
+    char *fname;
+    FILE *fstream;
+
+    // Open the qtrace.bb file
+    bb_reader_->Open(filename);
+
+    // Open the qtrace.insn file
+    insn_reader_->Open(filename);
+
+    // Open the qtrace.load file and read the first line
+    load_eof_ = load_addr_reader_->Open(filename, ".load");
+    if (!load_eof_)
+        load_eof_ = load_addr_reader_->ReadAddr(&load_time_, &load_addr_);
+
+    // Open the qtrace.store file and read the first line
+    store_eof_ = store_addr_reader_->Open(filename, ".store");
+    if (!store_eof_)
+        store_eof_ = store_addr_reader_->ReadAddr(&store_time_, &store_addr_);
+
+    // Open the qtrace.exc file
+    exc_reader_->Open(filename);
+
+    // Open another file stream to the qtrace.exc file for internal reads.
+    // This allows the caller to also read from the qtrace.exc file.
+    internal_exc_reader_->Open(filename);
+
+    // Open the qtrace.pid file
+    pid_reader_->Open(filename);
+    internal_pid_reader_->Open(filename);
+
+    // Open the qtrace.method file
+    method_reader_->Open(filename);
+    internal_method_reader_->Open(filename);
+
+    // Open the qtrace.static file
+    fname = CreateTracePath(filename, ".static");
+    static_filename_ = fname;
+
+    fstream = fopen(fname, "r");
+    if (fstream == NULL) {
+        perror(fname);
+        exit(1);
+    }
+    static_fstream_ = fstream;
+
+    // Read the header
+    ReadTraceHeader(fstream, fname, filename, header_);
+
+    // Allocate space for all of the static blocks
+    int num_static_bb = header_->num_static_bb;
+    if (num_static_bb) {
+        blocks_ = new StaticBlock[num_static_bb];
+
+        // Read in all the static blocks
+        for (int ii = 0; ii < num_static_bb; ++ii) {
+            ReadStatic(&blocks_[ii].rec);
+            int num_insns = blocks_[ii].rec.num_insns;
+            if (num_insns > 0) {
+                blocks_[ii].insns = new uint32_t[num_insns];
+                ReadStaticInsns(num_insns, blocks_[ii].insns);
+            } else {
+                blocks_[ii].insns = NULL;
+            }
+        }
+        fseek(static_fstream_, sizeof(TraceHeader), SEEK_SET);
+    }
+
+    ParseDexList(filename);
+
+    // If the dex_hash_ is NULL, then assign it a small hash table
+    // so that we can simply do a Find() operation without having
+    // to check for NULL first.
+    if (dex_hash_ == NULL) {
+        dex_hash_ = new HashTable<DexFileList*>(1, NULL);
+    }
+}
+
+// Reads the list of pid events looking for an mmap of a dex file.
+PidEvent * TraceReaderBase::FindMmapDexFileEvent()
+{
+    static PidEvent event;
+
+    while (!pid_reader_->ReadPidEvent(&event)) {
+        if (event.rec_type == kPidMmap && event.path != event.mmap_path) {
+            return &event;
+        }
+        pid_reader_->Dispose(&event);
+    }
+    return NULL;
+}
+
+static void CopyDexSymbolsToArray(DexFileList *dexfile,
+                                  DexSymList *head, int num_symbols)
+{
+    if (dexfile == NULL)
+        return;
+
+    DexSym *symbols = NULL;
+    if (num_symbols > 0) {
+        symbols = new DexSym[num_symbols];
+    }
+    dexfile->nsymbols = num_symbols;
+    dexfile->symbols = symbols;
+    
+    // Copy the linked-list to the array.
+    DexSymList *next_sym = NULL;
+    int next_index = 0;
+    for (DexSymList *sym = head; sym; sym = next_sym) {
+        next_sym = sym->next;
+        symbols[next_index].addr = sym->sym.addr;
+        symbols[next_index].len = sym->sym.len;
+        symbols[next_index].name = sym->sym.name;
+        next_index += 1;
+        delete sym;
+    }
+}
+
+void TraceReaderBase::ParseDexList(char *filename)
+{
+    struct stat stat_buf;
+    static const int kBufSize = 4096;
+    char buf[kBufSize];
+    char current_file[kBufSize];
+
+    // Find an example dex file in the list of mmaps
+    PidEvent *event = FindMmapDexFileEvent();
+
+    // Reset the pid_reader to the beginning of the file.
+    pid_reader_->Close();
+    pid_reader_->Open(filename);
+
+    // If there were no mmapped dex files, then there is no need to parse
+    // the dexlist.
+    if (event == NULL)
+        return;
+    char *mmap_dexfile = event->path;
+
+    // Check if the dexlist file exists.  It should have the name
+    // "qtrace.dexlist"
+    char *fname = CreateTracePath(filename, ".dexlist");
+    int rval = stat(fname, &stat_buf);
+    if (rval == -1) {
+        // The file does not exist
+        delete[] fname;
+        return;
+    }
+
+    // Open the qtrace.dexlist file
+    FILE *fstream = fopen(fname, "r");
+    if (fstream == NULL) {
+        perror(fname);
+        exit(1);
+    }
+
+    // First pass: read all the filenames, looking for a match for the
+    // example mmap dex filename.  Also count the files so that we
+    // know how big to make the hash table.
+    char *match = NULL;
+    int num_files = 0;
+    while (fgets(buf, kBufSize, fstream)) {
+        if (buf[0] != '#')
+            continue;
+        num_files += 1;
+        match = strstr(buf + 1, mmap_dexfile);
+
+        // Check that the dexlist file ends with the string mmap_dexfile.
+        // We add one to the length of the mmap_dexfile because buf[]
+        // ends with a newline.  The strlen(mmap_dexfile) computation
+        // could be moved above the loop but it should only ever be
+        // executed once.
+        if (match != NULL && strlen(match) == strlen(mmap_dexfile) + 1)
+            break;
+    }
+
+    // Count the rest of the files
+    while (fgets(buf, kBufSize, fstream)) {
+        if (buf[0] == '#')
+            num_files += 1;
+    }
+
+    if (match == NULL) {
+        fprintf(stderr,
+                "Cannot find the mmapped dex file '%s' in the dexlist\n",
+                mmap_dexfile);
+        exit(1);
+    }
+    delete[] mmap_dexfile;
+
+    // The prefix length includes the leading '#'.
+    int prefix_len = match - buf;
+
+    // Allocate a hash table
+    dex_hash_ = new HashTable<DexFileList*>(4 * num_files, NULL);
+
+    // Reset the file stream to the beginning
+    rewind(fstream);
+
+    // Second pass: read the filenames, stripping off the common prefix.
+    // And read all the (address, method) mappings.  When we read a new
+    // filename, create a new DexFileList and add it to the hash table.
+    // Add new symbol mappings to a linked list until we have the whole
+    // list and then create an array for them so that we can use binary
+    // search on the address to find the symbol name quickly.
+
+    // Use a linked list for storing the symbols
+    DexSymList *head = NULL;
+    DexSymList *prev = NULL;
+    int num_symbols = 0;
+
+    DexFileList *dexfile = NULL;
+    int linenum = 0;
+    while (fgets(buf, kBufSize, fstream)) {
+        linenum += 1;
+        if (buf[0] == '#') {
+            // Everything after the '#' is a filename.
+            // Ignore the common prefix.
+
+            // First, save all the symbols from the previous file (if any).
+            CopyDexSymbolsToArray(dexfile, head, num_symbols);
+
+            dexfile = new DexFileList;
+            // Subtract one because buf[] contains a trailing newline
+            int pathlen = strlen(buf) - prefix_len - 1;
+            char *path = new char[pathlen + 1];
+            strncpy(path, buf + prefix_len, pathlen);
+            path[pathlen] = 0;
+            dexfile->path = path;
+            dexfile->nsymbols = 0;
+            dexfile->symbols = NULL;
+            dex_hash_->Update(path, dexfile);
+            num_symbols = 0;
+            head = NULL;
+            prev = NULL;
+            continue;
+        }
+
+        uint32_t addr;
+        int len, line;
+        char clazz[kBufSize], method[kBufSize], sig[kBufSize], file[kBufSize];
+        if (sscanf(buf, "0x%x %d %s %s %s %s %d",
+                   &addr, &len, clazz, method, sig, file, &line) != 7) {
+            fprintf(stderr, "Cannot parse line %d of file %s:\n%s",
+                    linenum, fname, buf);
+            exit(1);
+        }
+
+        // Concatenate the class name, method name, and signature
+        // plus one for the period separating the class and method.
+        int nchars = strlen(clazz) + strlen(method) + strlen(sig) + 1;
+        char *name = new char[nchars + 1];
+        strcpy(name, clazz);
+        strcat(name, ".");
+        strcat(name, method);
+        strcat(name, sig);
+
+        DexSymList *symbol = new DexSymList;
+        symbol->sym.addr = addr;
+        symbol->sym.len = len;
+        symbol->sym.name = name;
+        symbol->next = NULL;
+
+        // Keep the list in the same order as the file
+        if (head == NULL)
+            head = symbol;
+        if (prev != NULL)
+            prev->next = symbol;
+        prev = symbol;
+        num_symbols += 1;
+    }
+    fclose(fstream);
+
+    // Copy the symbols from the last file.
+    CopyDexSymbolsToArray(dexfile, head, num_symbols);
+    delete[] fname;
+}
+
+// Extracts the pathname to a jar file (or .apk file) from the mmap pathname.
+// An example mmap pathname looks something like this:
+//   /data/dalvik-cache/system@app@TestHarness.apk@classes.dex
+// We want to convert that to this:
+//   /system/app/TestHarness.apk
+// If the pathname is not of the expected form, then NULL is returned.
+// The space for the extracted path is allocated in this routine and should
+// be freed by the caller after it is no longer needed.
+static char *ExtractDexPathFromMmap(const char *mmap_path)
+{
+    char *end = rindex(mmap_path, '@');
+    if (end == NULL)
+        return NULL;
+    char *start = rindex(mmap_path, '/');
+    if (start == NULL)
+        return NULL;
+    int len = end - start;
+    char *path = new char[len + 1];
+    strncpy(path, start, len);
+    path[len] = 0;
+
+    // Replace all the occurrences of '@' with '/'
+    for (int ii = 0; ii < len; ii++) {
+        if (path[ii] == '@')
+            path[ii] = '/';
+    }
+    return path;
+}
+
+void TraceReaderBase::Close()
+{
+    bb_reader_->Close();
+    insn_reader_->Close();
+    load_addr_reader_->Close();
+    store_addr_reader_->Close();
+    exc_reader_->Close();
+    pid_reader_->Close();
+    method_reader_->Close();
+    internal_exc_reader_->Close();
+    internal_pid_reader_->Close();
+    internal_method_reader_->Close();
+    fclose(static_fstream_);
+    static_fstream_ = NULL;
+}
+
+void TraceReaderBase::WriteHeader(TraceHeader *header)
+{
+    TraceHeader swappedHeader;
+
+    freopen(static_filename_, "r+", static_fstream_);
+    fseek(static_fstream_, 0, SEEK_SET);
+
+    memcpy(&swappedHeader, header, sizeof(TraceHeader));
+
+    convert32(swappedHeader.version);
+    convert32(swappedHeader.start_sec);
+    convert32(swappedHeader.start_usec);
+    convert32(swappedHeader.pdate);
+    convert32(swappedHeader.ptime);
+    convert64(swappedHeader.num_static_bb);
+    convert64(swappedHeader.num_static_insn);
+    convert64(swappedHeader.num_dynamic_bb);
+    convert64(swappedHeader.num_dynamic_insn);
+    convert64(swappedHeader.elapsed_usecs);
+
+    fwrite(&swappedHeader, sizeof(TraceHeader), 1, static_fstream_);
+}
+
+// Reads the next StaticRec from the trace file (not including the list
+// of instructions).  On end-of-file, this function returns true.
+int TraceReaderBase::ReadStatic(StaticRec *rec)
+{
+    int rval = fread(rec, sizeof(StaticRec), 1, static_fstream_);
+    if (rval != 1) {
+        if (feof(static_fstream_)) {
+            return true;
+        }
+        perror(static_filename_);
+        exit(1);
+    }
+    convert64(rec->bb_num);
+    convert32(rec->bb_addr);
+    convert32(rec->num_insns);
+    return false;
+}
+
+// Reads "num" instructions into the array "insns" which must be large
+// enough to hold the "num" instructions.
+// Returns the actual number of instructions read.  This will usually
+// be "num" but may be less if end-of-file occurred.
+int TraceReaderBase::ReadStaticInsns(int num, uint32_t *insns)
+{
+    if (num == 0)
+        return 0;
+    int rval = fread(insns, sizeof(uint32_t), num, static_fstream_);
+
+    // Convert from little-endian, if necessary
+    for (int ii = 0; ii < num; ++ii)
+        convert32(insns[ii]);
+
+    if (rval != num) {
+        if (feof(static_fstream_)) {
+            return rval;
+        }
+        perror(static_filename_);
+        exit(1);
+    }
+    return rval;
+}
+
+void TraceReaderBase::TruncateLastBlock(uint32_t num_insns)
+{
+    uint32_t insns[kMaxInsnPerBB];
+    StaticRec static_rec;
+    long loc = 0, prev_loc = 0;
+
+    freopen(static_filename_, "r+", static_fstream_);
+    fseek(static_fstream_, sizeof(TraceHeader), SEEK_SET);
+
+    // Find the last record
+    while (1) {
+        prev_loc = loc;
+        loc = ftell(static_fstream_);
+
+        // We don't need to byte-swap static_rec here because we are just
+        // reading the records until we get to the last one.
+        int rval = fread(&static_rec, sizeof(StaticRec), 1, static_fstream_);
+        if (rval != 1)
+            break;
+        ReadStaticInsns(static_rec.num_insns, insns);
+    }
+    if (prev_loc != 0) {
+        fseek(static_fstream_, prev_loc, SEEK_SET);
+        static_rec.num_insns = num_insns;
+
+        // Now we need to byte-swap, but just the field that we changed.
+        convert32(static_rec.num_insns);
+        fwrite(&static_rec, sizeof(StaticRec), 1, static_fstream_);
+        int fd = fileno(static_fstream_);
+        long len = ftell(static_fstream_);
+        len += num_insns * sizeof(uint32_t);
+        ftruncate(fd, len);
+    }
+}
+
+int TraceReaderBase::FindNumInsns(uint64_t bb_num, uint64_t bb_start_time)
+{
+    int num_insns;
+
+    // Read the exception trace file.  "bb_recnum_" is the number of
+    // basic block records that have been read so far, and "exc_recnum_"
+    // is the record number from the exception trace.
+    while (!exc_end_ && exc_recnum_ < bb_recnum_) {
+        uint32_t current_pc, target_pc;
+        uint64_t time;
+
+        exc_end_ = internal_exc_reader_->ReadExc(&time, &current_pc, &exc_recnum_,
+                                                 &target_pc, &exc_bb_num_,
+                                                 &exc_time_, &exc_num_insns_);
+    }
+
+    // If an exception occurred in this basic block, then use the
+    // number of instructions specified in the exception record.
+    if (!exc_end_ && exc_recnum_ == bb_recnum_) {
+        num_insns = exc_num_insns_;
+    } else {
+        // Otherwise, use the number of instructions specified in the
+        // static basic block.
+        num_insns = blocks_[bb_num].rec.num_insns;
+    }
+    return num_insns;
+}
+
+// Finds the current pid for the given time.  This routine reads the pid
+// trace file and assumes that the "time" parameter is monotonically
+// increasing.
+int TraceReaderBase::FindCurrentPid(uint64_t time)
+{
+    PidEvent event;
+
+    if (time < next_pid_switch_time_)
+        return current_pid_;
+
+    current_pid_ = next_pid_;
+    while (1) {
+        if (internal_pid_reader_->ReadPidEvent(&event)) {
+            next_pid_switch_time_ = ~0ull;
+            break;
+        }
+        if (event.rec_type != kPidSwitch)
+            continue;
+        if (event.time > time) {
+            next_pid_ = event.pid;
+            next_pid_switch_time_ = event.time;
+            break;
+        }
+        current_pid_ = event.pid;
+    }
+    return current_pid_;
+}
diff --git a/emulator/qtools/trace_reader.h b/emulator/qtools/trace_reader.h
new file mode 100644
index 0000000..4123014
--- /dev/null
+++ b/emulator/qtools/trace_reader.h
@@ -0,0 +1,1408 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef TRACE_READER_H
+#define TRACE_READER_H
+
+#include <string.h>
+#include <inttypes.h>
+#include <elf.h>
+#include <assert.h>
+#include <cxxabi.h>
+#include "read_elf.h"
+#include "trace_reader_base.h"
+#include "hash_table.h"
+
+struct TraceReaderEmptyStruct {
+};
+
+template <class T = TraceReaderEmptyStruct>
+class TraceReader : public TraceReaderBase {
+  public:
+
+    struct region_entry;
+    typedef struct symbol_entry : public T {
+        typedef region_entry region_type;
+
+        // Define flag values
+        static const uint32_t kIsPlt = 0x01;
+        static const uint32_t kIsVectorStart = 0x02;
+        static const uint32_t kIsVectorTable = (kIsPlt | kIsVectorStart);
+        static const uint32_t kIsInterpreter = 0x04;
+        static const uint32_t kIsMethod = 0x08;
+
+        uint32_t        addr;
+
+        // This may hold the name of the interpreted method instead of
+        // the name of the native function if the native function is a
+        // virtual machine interpreter.
+        const char      *name;
+
+        // The symbol for the virtual machine interpreter, or NULL
+        symbol_entry    *vm_sym;
+        region_type     *region;
+        uint32_t        flags;
+    } symbol_type;
+
+    typedef struct region_entry {
+        // Define flag values
+        static const uint32_t kIsKernelRegion           = 0x01;
+        static const uint32_t kSharedSymbols            = 0x02;
+        static const uint32_t kIsLibraryRegion          = 0x04;
+        static const uint32_t kIsUserMappedRegion       = 0x08;
+
+        region_entry() : refs(0), path(NULL), vstart(0), vend(0), base_addr(0),
+                         file_offset(0), flags(0), nsymbols(0), symbols(NULL) {}
+
+        symbol_type    *LookupFunctionByName(char *name) {
+            // Just do a linear search
+            for (int ii = 0; ii < nsymbols; ++ii) {
+                if (strcmp(symbols[ii].name, name) == 0)
+                    return &symbols[ii];
+            }
+            return NULL;
+        }
+
+        int             refs;        // reference count
+        char            *path;
+        uint32_t        vstart;
+        uint32_t        vend;
+        uint32_t        base_addr;
+        uint32_t        file_offset;
+        uint32_t        flags;
+        int             nsymbols;
+        symbol_type     *symbols;
+    } region_type;
+
+    typedef typename HashTable<region_type*>::entry_type hash_entry_type;
+
+    class ProcessState {
+      public:
+
+        // The "regions" array below is a pointer to array of pointers to
+        // regions.  The size of the pointer array is kInitialNumRegions,
+        // but grows if needed.  There is a separate region for each mmap
+        // call which includes shared libraries as well as .dex and .jar
+        // files.  In addition, there is a region for the main executable
+        // for this process, as well as a few regions for the kernel.
+        //
+        // If a child process is a clone of a parent process, the
+        // regions array is unused.  Instead, the "addr_manager" pointer is
+        // used to find the process that is the address space manager for
+        // both the parent and child processes.
+        static const int kInitialNumRegions = 10;
+
+        static const int kMaxMethodStackSize = 1000;
+
+        // Define values for the ProcessState flag bits
+        static const int kCalledExec            = 0x01;
+        static const int kCalledExit            = 0x02;
+        static const int kIsClone               = 0x04;
+        static const int kHasKernelRegion       = 0x08;
+        static const int kHasFirstMmap          = 0x10;
+
+        ProcessState() {
+            cpu_time = 0;
+            tgid = 0;
+            pid = 0;
+            parent_pid = 0;
+            exit_val = 0;
+            flags = 0;
+            argc = 0;
+            argv = NULL;
+            name = NULL;
+            nregions = 0;
+            max_regions = 0;
+            // Don't allocate space yet until we know if we are a clone.
+            regions = NULL;
+            parent = NULL;
+            addr_manager = this;
+            next = NULL;
+            current_method_sym = NULL;
+            method_stack_top = 0;
+        }
+
+        ~ProcessState() {
+            delete[] name;
+            if ((flags & kIsClone) != 0) {
+                return;
+            }
+
+            // Free the regions.  We must be careful not to free the symbols
+            // within each region because the symbols are sometimes shared
+            // between multiple regions.  The TraceReader class has a hash
+            // table containing all the unique regions and it will free the
+            // region symbols in its destructor.  We need to free only the
+            // regions and the array of region pointers.
+            //
+            // Each region is also reference-counted.  The count is zero
+            // if no other processes are sharing this region.
+            for (int ii = 0; ii < nregions; ii++) {
+                if (regions[ii]->refs > 0) {
+                    regions[ii]->refs -= 1;
+                    continue;
+                }
+
+                delete regions[ii];
+            }
+
+            delete[] regions;
+
+            for (int ii = 0; ii < argc; ++ii)
+                delete[] argv[ii];
+            delete[] argv;
+        }
+
+        // Dumps the stack contents to standard output.  For debugging.
+        void            DumpStack();
+
+        uint64_t        cpu_time;
+        uint64_t        start_time;
+        uint64_t        end_time;
+        int             tgid;
+        int             pid;
+        int             parent_pid;
+        int             exit_val;
+        uint32_t        flags;
+        int             argc;
+        char            **argv;
+        char            *name;
+        int             nregions;        // num regions in use
+        int             max_regions;     // max regions allocated
+        region_type     **regions;
+        ProcessState    *parent;
+        ProcessState    *addr_manager;   // the address space manager process
+        ProcessState    *next;
+        int             method_stack_top;
+        uint32_t        method_stack[kMaxMethodStackSize];
+        symbol_type     *current_method_sym;
+    };
+
+    TraceReader();
+    ~TraceReader();
+
+    void                ReadKernelSymbols(const char *kernel_file);
+    void                CopyKernelRegion(ProcessState *pstate);
+    void                ClearRegions(ProcessState *pstate);
+    void                CopyRegions(ProcessState *parent, ProcessState *child);
+    symbol_type         *LookupFunction(int pid, uint32_t addr, uint64_t time);
+    symbol_type         *GetSymbols(int *num_syms);
+    ProcessState        *GetCurrentProcess()            { return current_; }
+    ProcessState        *GetProcesses(int *num_procs);
+    ProcessState        *GetNextProcess();
+    char                *GetProcessName(int pid);
+    void                SetRoot(const char *root)       { root_ = root; }
+    void                SetDemangle(bool demangle)      { demangle_ = demangle; }
+    bool                ReadMethodSymbol(MethodRec *method_record,
+                                         symbol_type **psym,
+                                         ProcessState **pproc);
+
+  protected:
+    virtual int FindCurrentPid(uint64_t time);
+
+  private:
+
+    static const int kNumPids = 32768;
+    static const uint32_t kIncludeLocalSymbols = 0x1;
+
+    void                AddPredefinedRegion(region_type *region, const char *path,
+                                            uint32_t vstart, uint32_t vend,
+                                            uint32_t base);
+    void                InitRegionSymbols(region_type *region, int nsymbols);
+    void                AddRegionSymbol(region_type *region, int idx,
+                                        uint32_t addr, const char *name,
+                                        uint32_t flags);
+    void                AddPredefinedRegions(ProcessState *pstate);
+    void                demangle_names(int nfuncs, symbol_type *functions);
+    bool                ReadElfSymbols(region_type *region, uint32_t flags);
+    void                AddRegion(ProcessState *pstate, region_type *region);
+    region_type         *FindRegion(uint32_t addr, int nregions,
+                                    region_type **regions);
+    symbol_type         *FindFunction(uint32_t addr, int nsyms,
+                                      symbol_type *symbols, bool exact_match);
+    symbol_type         *FindCurrentMethod(int pid, uint64_t time);
+    void                PopulateSymbolsFromDexFile(const DexFileList *dexfile,
+                                                   region_type *region);
+    void                HandlePidEvent(PidEvent *event);
+    void                HandleMethodRecord(ProcessState *pstate,
+                                           MethodRec *method_rec);
+
+    int                 cached_pid_;
+    symbol_type         *cached_func_;
+    symbol_type         unknown_;
+    int                 next_pid_;
+
+    PidEvent            next_pid_event_;
+    ProcessState        *processes_[kNumPids];
+    ProcessState        *current_;
+    MethodRec           next_method_;
+    uint64_t            function_start_time_;
+    const char          *root_;
+    HashTable<region_type*> *hash_;
+    bool                demangle_;
+};
+
+template<class T>
+TraceReader<T>::TraceReader()
+{
+    static PidEvent event_no_action;
+
+    cached_pid_ = -1;
+    cached_func_ = NULL;
+
+    memset(&unknown_, 0, sizeof(symbol_type));
+    unknown_.name = "(unknown)";
+    next_pid_ = 0;
+
+    memset(&event_no_action, 0, sizeof(PidEvent));
+    event_no_action.rec_type = kPidNoAction;
+    next_pid_event_ = event_no_action;
+    for (int ii = 1; ii < kNumPids; ++ii)
+        processes_[ii] = NULL;
+    current_ = new ProcessState;
+    processes_[0] = current_;
+    next_method_.time = 0;
+    next_method_.addr = 0;
+    next_method_.flags = 0;
+    function_start_time_ = 0;
+    root_ = "";
+    hash_ = new HashTable<region_type*>(512);
+    AddPredefinedRegions(current_);
+    demangle_ = true;
+}
+
+template<class T>
+TraceReader<T>::~TraceReader()
+{
+    hash_entry_type *ptr;
+    for (ptr = hash_->GetFirst(); ptr; ptr = hash_->GetNext()) {
+        region_type *region = ptr->value;
+        int nsymbols = region->nsymbols;
+        for (int ii = 0; ii < nsymbols; ii++) {
+            delete[] region->symbols[ii].name;
+        }
+        delete[] region->symbols;
+        delete[] region->path;
+
+        // Do not delete the region itself here.  Each region
+        // is reference-counted and deleted by the ProcessState
+        // object that owns it.
+    }
+    delete hash_;
+
+    // Delete the ProcessState objects after the region symbols in
+    // the hash table above so that we still have valid region pointers
+    // when deleting the region symbols.
+    for (int ii = 0; ii < kNumPids; ++ii) {
+        delete processes_[ii];
+    }
+}
+
+// This function is used by the qsort() routine to sort symbols
+// into increasing address order.
+template<class T>
+int cmp_symbol_addr(const void *a, const void *b) {
+    typedef typename TraceReader<T>::symbol_type stype;
+
+    const stype *syma = static_cast<stype const *>(a);
+    const stype *symb = static_cast<stype const *>(b);
+    uint32_t addr1 = syma->addr;
+    uint32_t addr2 = symb->addr;
+    if (addr1 < addr2)
+        return -1;
+    if (addr1 > addr2)
+        return 1;
+
+    // The addresses are the same, sort the symbols into
+    // increasing alphabetical order.  But put symbols that
+    // that start with "_" last.
+    if (syma->name[0] == '_' || symb->name[0] == '_') {
+        // Count the number of leading underscores and sort the
+        // symbol with the most underscores last.
+        int aCount = 0;
+        while (syma->name[aCount] == '_')
+            aCount += 1;
+        int bCount = 0;
+        while (symb->name[bCount] == '_')
+            bCount += 1;
+        if (aCount < bCount) {
+            return -1;
+        }
+        if (aCount > bCount) {
+            return 1;
+        }
+        // If the symbols have the same number of underscores, then
+        // fall through and sort by the whole name.
+    }
+    return strcmp(syma->name, symb->name);
+}
+
+// This function is used by the qsort() routine to sort region entries
+// into increasing address order.
+template<class T>
+int cmp_region_addr(const void *a, const void *b) {
+    typedef typename TraceReader<T>::region_type rtype;
+
+    const rtype *ma = *static_cast<rtype* const *>(a);
+    const rtype *mb = *static_cast<rtype* const *>(b);
+    uint32_t addr1 = ma->vstart;
+    uint32_t addr2 = mb->vstart;
+    if (addr1 < addr2)
+        return -1;
+    if (addr1 == addr2)
+        return 0;
+    return 1;
+}
+
+// This routine returns a new array containing all the symbols.
+template<class T>
+typename TraceReader<T>::symbol_type*
+TraceReader<T>::GetSymbols(int *num_syms)
+{
+    // Count the symbols
+    int nsyms = 0;
+    for (hash_entry_type *ptr = hash_->GetFirst(); ptr; ptr = hash_->GetNext()) {
+        region_type *region = ptr->value;
+        nsyms += region->nsymbols;
+    }
+    *num_syms = nsyms;
+
+    // Allocate space
+    symbol_type *syms = new symbol_type[nsyms];
+    symbol_type *next_sym = syms;
+
+    // Copy the symbols
+    for (hash_entry_type *ptr = hash_->GetFirst(); ptr; ptr = hash_->GetNext()) {
+        region_type *region = ptr->value;
+        memcpy(next_sym, region->symbols, region->nsymbols * sizeof(symbol_type));
+        next_sym += region->nsymbols;
+    }
+
+    return syms;
+}
+
+// This routine returns all the valid processes.
+template<class T>
+typename TraceReader<T>::ProcessState*
+TraceReader<T>::GetProcesses(int *num_procs)
+{
+    // Count the valid processes
+    int nprocs = 0;
+    for (int ii = 0; ii < kNumPids; ++ii) {
+        if (processes_[ii])
+            nprocs += 1;
+    }
+
+    // Allocate a new array to hold the valid processes.
+    ProcessState *procs = new ProcessState[nprocs];
+
+    // Copy the processes to the new array.
+    ProcessState *pstate = procs;
+    for (int ii = 0; ii < kNumPids; ++ii) {
+        if (processes_[ii])
+            memcpy(pstate++, processes_[ii], sizeof(ProcessState));
+    }
+
+    *num_procs = nprocs;
+    return procs;
+}
+
+// This routine returns the next valid process, or NULL if there are no
+// more valid processes.
+template<class T>
+typename TraceReader<T>::ProcessState*
+TraceReader<T>::GetNextProcess()
+{
+    while (next_pid_ < kNumPids) {
+        if (processes_[next_pid_])
+            return processes_[next_pid_++];
+        next_pid_ += 1;
+    }
+    next_pid_ = 0;
+    return NULL;
+}
+
+template<class T>
+char* TraceReader<T>::GetProcessName(int pid)
+{
+    if (pid < 0 || pid >= kNumPids || processes_[pid] == NULL)
+        return "(unknown)";
+    return processes_[pid]->name;
+}
+
+template<class T>
+void TraceReader<T>::AddPredefinedRegion(region_type *region, const char *path,
+                                         uint32_t vstart, uint32_t vend,
+                                         uint32_t base)
+{
+    // Copy the path to make it easy to delete later.
+    int len = strlen(path);
+    region->path = new char[len + 1];
+    strcpy(region->path, path);
+    region->vstart = vstart;
+    region->vend = vend;
+    region->base_addr = base;
+    region->flags = region_type::kIsKernelRegion;
+}
+
+template<class T>
+void TraceReader<T>::InitRegionSymbols(region_type *region, int nsymbols)
+{
+    region->nsymbols = nsymbols;
+    region->symbols = new symbol_type[nsymbols];
+    memset(region->symbols, 0, nsymbols * sizeof(symbol_type));
+}
+
+template<class T>
+void TraceReader<T>::AddRegionSymbol(region_type *region, int idx,
+                                     uint32_t addr, const char *name,
+                                     uint32_t flags)
+{
+    region->symbols[idx].addr = addr;
+    region->symbols[idx].name = Strdup(name);
+    region->symbols[idx].vm_sym = NULL;
+    region->symbols[idx].region = region;
+    region->symbols[idx].flags = flags;
+}
+
+template<class T>
+void TraceReader<T>::AddPredefinedRegions(ProcessState *pstate)
+{
+    region_type *region = new region_type;
+    AddPredefinedRegion(region, "(bootloader)", 0, 0x14, 0);
+    InitRegionSymbols(region, 2);
+    AddRegionSymbol(region, 0, 0, "(bootloader_start)", 0);
+    AddRegionSymbol(region, 1, 0x14, "(bootloader_end)", 0);
+    AddRegion(pstate, region);
+    hash_->Update(region->path, region);
+
+    region = new region_type;
+    AddPredefinedRegion(region, "(exception vectors)", 0xffff0000, 0xffff0500,
+                        0xffff0000);
+    InitRegionSymbols(region, 2);
+    AddRegionSymbol(region, 0, 0x0, "(vector_start)",
+                    symbol_type::kIsVectorStart);
+    AddRegionSymbol(region, 1, 0x500, "(vector_end)", 0);
+    AddRegion(pstate, region);
+    hash_->Update(region->path, region);
+
+    region = new region_type;
+    AddPredefinedRegion(region, "(atomic ops)", 0xffff0f80, 0xffff1000,
+                        0xffff0f80);
+    // Mark this region as also being mapped in user-space.
+    // This isn't used anywhere in this code but client code can test for
+    // this flag and decide whether to treat this as kernel or user code.
+    region->flags |= region_type::kIsUserMappedRegion;
+
+    InitRegionSymbols(region, 4);
+    AddRegionSymbol(region, 0, 0x0, "(kuser_atomic_inc)", 0);
+    AddRegionSymbol(region, 1, 0x20, "(kuser_atomic_dec)", 0);
+    AddRegionSymbol(region, 2, 0x40, "(kuser_cmpxchg)", 0);
+    AddRegionSymbol(region, 3, 0x80, "(kuser_end)", 0);
+    AddRegion(pstate, region);
+    hash_->Update(region->path, region);
+}
+
+template<class T>
+void TraceReader<T>::ReadKernelSymbols(const char *kernel_file)
+{
+    region_type *region = new region_type;
+    // Copy the path to make it easy to delete later.
+    int len = strlen(kernel_file);
+    region->path = new char[len + 1];
+    strcpy(region->path, kernel_file);
+    region->flags = region_type::kIsKernelRegion;
+    ReadElfSymbols(region, kIncludeLocalSymbols);
+    region->vend = 0xffff0000;
+    AddRegion(processes_[0], region);
+    processes_[0]->flags |= ProcessState::kHasKernelRegion;
+    hash_->Update(region->path, region);
+}
+
+template<class T>
+void TraceReader<T>::demangle_names(int nfuncs, symbol_type *functions)
+{
+    char *demangled;
+    int status;
+
+    for (int ii = 0; ii < nfuncs; ++ii) {
+        demangled = NULL;
+        int len = strlen(functions[ii].name);
+
+        // If we don't check for "len > 1" then the demangler will incorrectly
+        // expand 1-letter function names.  For example, "b" becomes "bool",
+        // "c" becomes "char" and "d" becomes "double".  Also check that the
+        // first character is an underscore.  Otherwise, on some strings
+        // the demangler will try to read past the end of the string (because
+        // the string is not really a C++ mangled name) and valgrind will
+        // complain.
+        if (demangle_ && len > 1 && functions[ii].name[0] == '_') {
+            demangled = abi::__cxa_demangle(functions[ii].name, 0, NULL,
+                                            &status);
+        }
+
+        if (demangled != NULL) {
+            delete[] functions[ii].name;
+            functions[ii].name = Strdup(demangled);
+            free(demangled);
+        }
+    }
+}
+
+// Adds the symbols from the given ELF file to the given process.
+// Returns false if the file was not an ELF file or if there was an
+// error trying to read the sections of the ELF file.
+template<class T>
+bool TraceReader<T>::ReadElfSymbols(region_type *region, uint32_t flags)
+{
+    static char full_path[4096];
+    Elf32_Shdr  *symtab, *symstr;
+    Elf32_Ehdr  *hdr;
+    Elf32_Shdr  *shdr;
+
+    full_path[0] = 0;
+    if (root_ && strcmp(root_, "/")) {
+        strcpy(full_path, root_);
+    }
+    strcat(full_path, region->path);
+    FILE *fobj = fopen(full_path, "r");
+    if(fobj == NULL) {
+    EmptyRegion:
+        // we need to create an (unknown) symbol with address 0, otherwise some
+        // other parts of the trace reader will simply crash when dealing with
+        // an empty region
+        region->vstart = 0;
+        region->nsymbols = 1;
+        region->symbols  = new symbol_type[1];
+        memset(region->symbols, 0, sizeof(symbol_type));
+
+        region->symbols[0].addr   = 0;
+        region->symbols[0].name   = Strdup("(unknown)");
+        region->symbols[0].vm_sym = NULL;
+        region->symbols[0].region = region;
+        region->symbols[0].flags  = 0;
+
+        if (fobj != NULL)
+            fclose(fobj);
+        return false;
+    }
+
+    hdr = ReadElfHeader(fobj);
+    if (hdr == NULL) {
+        fprintf(stderr, "Cannot read ELF header from '%s'\n", full_path);
+        goto EmptyRegion;
+    }
+
+    shdr = ReadSectionHeaders(hdr, fobj);
+    if(shdr == NULL) {
+        fprintf(stderr, "Can't read section headers from executable\n");
+        goto EmptyRegion;
+    }
+    char *section_names = ReadStringTable(hdr, shdr, fobj);
+
+    // Get the symbol table section
+    symtab = FindSymbolTableSection(hdr, shdr, section_names);
+    if (symtab == NULL || symtab->sh_size == 0) {
+        fprintf(stderr, "Can't read symbol table from '%s'\n", full_path);
+        goto EmptyRegion;
+    }
+
+    // Get the symbol string table section
+    symstr = FindSymbolStringTableSection(hdr, shdr, section_names);
+    if (symstr == NULL || symstr->sh_size == 0) {
+        fprintf(stderr, "Can't read symbol string table from '%s'\n", full_path);
+        goto EmptyRegion;
+    }
+
+    // Load the symbol string table data
+    char *symbol_names = new char[symstr->sh_size];
+    ReadSection(symstr, symbol_names, fobj);
+
+    int num_entries = symtab->sh_size / symtab->sh_entsize;
+    Elf32_Sym *elf_symbols = new Elf32_Sym[num_entries];
+    ReadSection(symtab, elf_symbols, fobj);
+    AdjustElfSymbols(hdr, elf_symbols, num_entries);
+#if 0
+    printf("size: %d, ent_size: %d, num_entries: %d\n",
+           symtab->sh_size, symtab->sh_entsize, num_entries);
+#endif
+    int nfuncs = 0;
+
+    // Allocate space for all of the symbols for now.  We will
+    // reallocate space for just the function symbols after we
+    // know how many there are.  Also, make sure there is room
+    // for some extra symbols, including the text section names.
+    int num_alloc = num_entries + hdr->e_shnum + 1;
+    symbol_type *func_symbols = new symbol_type[num_alloc];
+    memset(func_symbols, 0, num_alloc * sizeof(symbol_type));
+
+    // If this is the shared library for a virtual machine, then
+    // set the IsInterpreter flag for all symbols in that shared library.
+    // This will allow us to replace the symbol names with the name of
+    // the currently executing method on the virtual machine.
+    int symbol_flags = 0;
+    char *cp = strrchr(region->path, '/');
+    if (cp != NULL) {
+        // Move past the '/'
+        cp += 1;
+    } else {
+        // There was no '/', so use the whole path
+        cp = region->path;
+    }
+    if (strcmp(cp, "libdvm.so") == 0) {
+        symbol_flags = symbol_type::kIsInterpreter;
+    }
+
+    bool zero_found = false;
+    for (int ii = 1; ii < num_entries; ++ii) {
+        int idx = elf_symbols[ii].st_name;
+
+        // If the symbol does not have a name, or if the name starts with a
+        // dollar sign ($), then skip it.
+        if (idx == 0 || symbol_names[idx] == 0 || symbol_names[idx] == '$')
+            continue;
+
+        // If the section index is not executable, then skip it.
+        uint32_t section = elf_symbols[ii].st_shndx;
+        if (section == 0 || section >= hdr->e_shnum)
+            continue;
+        if ((shdr[section].sh_flags & SHF_EXECINSTR) == 0)
+            continue;
+
+        uint8_t sym_type = ELF32_ST_TYPE(elf_symbols[ii].st_info);
+        uint8_t sym_bind = ELF32_ST_BIND(elf_symbols[ii].st_info);
+
+        // Allow the caller to decide if we want local non-function
+        // symbols to be included.  We currently include these symbols
+        // only for the kernel, where it is useful because the kernel
+        // has lots of assembly language labels that have meaningful names.
+        if ((flags & kIncludeLocalSymbols) == 0 && sym_bind == STB_LOCAL
+            && sym_type != STT_FUNC) {
+            continue;
+        }
+#if 0
+        printf("%08x %x %x %s\n",
+               elf_symbols[ii].st_value,
+               sym_bind,
+               sym_type,
+               &symbol_names[idx]);
+#endif
+        if (sym_type != STT_FUNC && sym_type != STT_NOTYPE)
+            continue;
+
+        if (elf_symbols[ii].st_value == 0)
+            zero_found = true;
+
+        // The address of thumb functions seem to have the low bit set,
+        // even though the instructions are really at an even address.
+        uint32_t addr = elf_symbols[ii].st_value & ~0x1;
+        func_symbols[nfuncs].addr = addr;
+        func_symbols[nfuncs].name = Strdup(&symbol_names[idx]);
+        func_symbols[nfuncs].flags = symbol_flags;
+
+        nfuncs += 1;
+    }
+
+    // Add a [0, "(unknown)"] symbol pair if there is not already a
+    // symbol with the address zero.  We don't need to reallocate space
+    // because we already have more than we need.
+    if (!zero_found) {
+        func_symbols[nfuncs].addr = 0;
+        func_symbols[nfuncs].name = Strdup("(0 unknown)");
+        nfuncs += 1;
+    }
+
+    // Add another entry at the end
+    func_symbols[nfuncs].addr = 0xffffffff;
+    func_symbols[nfuncs].name = Strdup("(end)");
+    nfuncs += 1;
+
+    // Add in the names of the text sections, but only if there
+    // are no symbols with that address already.
+    for (int section = 0; section < hdr->e_shnum; ++section) {
+        if ((shdr[section].sh_flags & SHF_EXECINSTR) == 0)
+            continue;
+
+        uint32_t addr = shdr[section].sh_addr;
+        // Search for a symbol with a matching address.  The symbols aren't
+        // sorted yet so we just search the whole list.
+        int ii;
+        for (ii = 0; ii < nfuncs; ++ii) {
+            if (addr == func_symbols[ii].addr)
+                break;
+        }
+        if (ii == nfuncs) {
+            // Symbol at address "addr" does not exist, so add the text
+            // section name.  This will usually add the ".plt" section
+            // (procedure linkage table).
+            int idx = shdr[section].sh_name;
+            func_symbols[nfuncs].addr = addr;
+            func_symbols[nfuncs].name = Strdup(&section_names[idx]);
+            if (strcmp(func_symbols[nfuncs].name, ".plt") == 0) {
+                func_symbols[nfuncs].flags |= symbol_type::kIsPlt;
+                // Change the name of the symbol to include the
+                // name of the library.  Otherwise we will have lots
+                // of ".plt" symbols.
+                int len = strlen(region->path);
+                len += strlen(":.plt");
+                char *name = new char[len + 1];
+                strcpy(name, region->path);
+                strcat(name, ":.plt");
+                delete[] func_symbols[nfuncs].name;
+                func_symbols[nfuncs].name = name;
+
+                // Check if this is part of the virtual machine interpreter
+                char *cp = strrchr(region->path, '/');
+                if (cp != NULL) {
+                    // Move past the '/'
+                    cp += 1;
+                } else {
+                    // There was no '/', so use the whole path
+                    cp = region->path;
+                }
+                if (strcmp(cp, "libdvm.so") == 0) {
+                    func_symbols[nfuncs].flags |= symbol_type::kIsInterpreter;
+                }
+            }
+            nfuncs += 1;
+        }
+    }
+
+    // Allocate just the space we need now that we know exactly
+    // how many symbols we have.
+    symbol_type *functions = new symbol_type[nfuncs];
+
+    // Copy the symbols to the functions array
+    memcpy(functions, func_symbols, nfuncs * sizeof(symbol_type));
+    delete[] func_symbols;
+
+    // Assign the region pointers
+    for (int ii = 0; ii < nfuncs; ++ii) {
+        functions[ii].region = region;
+    }
+
+    // Sort the symbols into increasing address order
+    qsort(functions, nfuncs, sizeof(symbol_type), cmp_symbol_addr<T>);
+
+    // If there are multiple symbols with the same address, then remove
+    // the duplicates.  First, count the number of duplicates.
+    uint32_t prev_addr = ~0;
+    int num_duplicates = 0;
+    for (int ii = 0; ii < nfuncs; ++ii) {
+        if (prev_addr == functions[ii].addr)
+            num_duplicates += 1;
+        prev_addr = functions[ii].addr;
+    }
+ 
+    if (num_duplicates > 0) {
+        int num_uniq = nfuncs - num_duplicates;
+
+        // Allocate space for the unique functions
+        symbol_type *uniq_functions = new symbol_type[num_uniq];
+
+        // Copy the unique functions
+        prev_addr = ~0;
+        int next_uniq = 0;
+        for (int ii = 0; ii < nfuncs; ++ii) {
+            if (prev_addr == functions[ii].addr) {
+                delete[] functions[ii].name;
+                continue;
+            }
+            memcpy(&uniq_functions[next_uniq++], &functions[ii],
+                   sizeof(symbol_type));
+            prev_addr = functions[ii].addr;
+        }
+        assert(next_uniq == num_uniq);
+
+        delete[] functions;
+        functions = uniq_functions;
+        nfuncs = num_uniq;
+    }
+
+    // Finally, demangle all of the symbol names
+    demangle_names(nfuncs, functions);
+
+    uint32_t min_addr = 0;
+    if (!zero_found)
+        min_addr = functions[1].addr;
+    if (region->vstart == 0)
+        region->vstart = min_addr;
+    region->nsymbols = nfuncs;
+    region->symbols = functions;
+
+#if 0
+    printf("%s num symbols: %d min_addr: 0x%x\n", region->path, nfuncs, min_addr);
+    for (int ii = 0; ii < nfuncs; ++ii) {
+        printf("0x%08x %s\n", functions[ii].addr, functions[ii].name);
+    }
+#endif
+    delete[] elf_symbols;
+    delete[] symbol_names;
+    delete[] section_names;
+    delete[] shdr;
+    delete hdr;
+    fclose(fobj);
+    
+    return true;
+}
+
+template<class T>
+void TraceReader<T>::CopyKernelRegion(ProcessState *pstate)
+{
+    ProcessState *manager = pstate->addr_manager;
+    if (manager->flags & ProcessState::kHasKernelRegion)
+        return;
+
+    int nregions = processes_[0]->nregions;
+    region_type **regions = processes_[0]->regions;
+    for (int ii = 0; ii < nregions; ii++) {
+        if (regions[ii]->flags & region_type::kIsKernelRegion) {
+            AddRegion(manager, regions[ii]);
+            regions[ii]->refs += 1;
+        }
+    }
+    manager->flags |= ProcessState::kHasKernelRegion;
+}
+
+template<class T>
+void TraceReader<T>::ClearRegions(ProcessState *pstate)
+{
+    assert(pstate->pid != 0);
+    int nregions = pstate->nregions;
+    region_type **regions = pstate->regions;
+
+    // Decrement the reference count on all the regions
+    for (int ii = 0; ii < nregions; ii++) {
+        if (regions[ii]->refs > 0) {
+            regions[ii]->refs -= 1;
+            continue;
+        }
+
+        delete regions[ii];
+    }
+    delete[] pstate->regions;
+    pstate->regions = NULL;
+    pstate->nregions = 0;
+    pstate->max_regions = 0;
+    pstate->addr_manager = pstate;
+    pstate->flags &= ~ProcessState::kIsClone;
+    pstate->flags &= ~ProcessState::kHasKernelRegion;
+    CopyKernelRegion(pstate);
+}
+
+template<class T>
+void TraceReader<T>::AddRegion(ProcessState *pstate, region_type *region)
+{
+    ProcessState *manager = pstate->addr_manager;
+    if (manager->regions == NULL) {
+        manager->max_regions = ProcessState::kInitialNumRegions;
+        manager->regions = new region_type*[manager->max_regions];
+        manager->nregions = 0;
+    }
+
+    // Check if we need to grow the array
+    int nregions = manager->nregions;
+    int max_regions = manager->max_regions;
+    if (nregions >= max_regions) {
+        max_regions <<= 1;
+        manager->max_regions = max_regions;
+        region_type **regions = new region_type*[max_regions];
+        for (int ii = 0; ii < nregions; ii++) {
+            regions[ii] = manager->regions[ii];
+        }
+        delete[] manager->regions;
+        manager->regions = regions;
+    }
+
+    // Add the new region to the end of the array and resort
+    manager->regions[nregions] = region;
+    nregions += 1;
+    manager->nregions = nregions;
+
+    // Resort the regions into increasing start address
+    qsort(manager->regions, nregions, sizeof(region_type*), cmp_region_addr<T>);
+}
+
+template<class T>
+void TraceReader<T>::CopyRegions(ProcessState *parent, ProcessState *child)
+{
+    // Copy the parent's address space
+    ProcessState *manager = parent->addr_manager;
+    int nregions = manager->nregions;
+    child->nregions = nregions;
+    child->max_regions = manager->max_regions;
+    region_type **regions = new region_type*[manager->max_regions];
+    child->regions = regions;
+    memcpy(regions, manager->regions, nregions * sizeof(region_type*));
+
+    // Increment the reference count on all the regions
+    for (int ii = 0; ii < nregions; ii++) {
+        regions[ii]->refs += 1;
+    }
+}
+
+template<class T>
+typename TraceReader<T>::region_type *
+TraceReader<T>::FindRegion(uint32_t addr, int nregions, region_type **regions)
+{
+    int high = nregions;
+    int low = -1;
+    while (low + 1 < high) {
+        int middle = (high + low) / 2;
+        uint32_t middle_addr = regions[middle]->vstart;
+        if (middle_addr == addr)
+            return regions[middle];
+        if (middle_addr > addr)
+            high = middle;
+        else
+            low = middle;
+    }
+
+    // If we get here then we did not find an exact address match.  So use
+    // the closest region address that is less than the given address.
+    if (low < 0)
+        low = 0;
+    return regions[low];
+}
+
+template<class T>
+typename TraceReader<T>::symbol_type *
+TraceReader<T>::FindFunction(uint32_t addr, int nsyms, symbol_type *symbols,
+                             bool exact_match)
+{
+    int high = nsyms;
+    int low = -1;
+    while (low + 1 < high) {
+        int middle = (high + low) / 2;
+        uint32_t middle_addr = symbols[middle].addr;
+        if (middle_addr == addr)
+            return &symbols[middle];
+        if (middle_addr > addr)
+            high = middle;
+        else
+            low = middle;
+    }
+
+    // If we get here then we did not find an exact address match.  So use
+    // the closest function address that is less than the given address.
+    // We added a symbol with address zero so if there is no known
+    // function containing the given address, then we will return the
+    // "(unknown)" symbol.
+    if (low >= 0 && !exact_match)
+        return &symbols[low];
+    return NULL;
+}
+
+template<class T>
+typename TraceReader<T>::symbol_type *
+TraceReader<T>::LookupFunction(int pid, uint32_t addr, uint64_t time)
+{
+    // Check if the previous match is still a good match.
+    if (cached_pid_ == pid) {
+        uint32_t vstart = cached_func_->region->vstart;
+        uint32_t vend = cached_func_->region->vend;
+        if (addr >= vstart && addr < vend) {
+            uint32_t sym_addr = addr - cached_func_->region->base_addr;
+            if (sym_addr >= cached_func_->addr
+                && sym_addr < (cached_func_ + 1)->addr) {
+                // If this function is the virtual machine interpreter, then
+                // read the method trace to find the "real" method name based
+                // on the current time and pid.
+                if (cached_func_->flags & symbol_type::kIsInterpreter) {
+                    symbol_type *sym = FindCurrentMethod(pid, time);
+                    if (sym != NULL) {
+                        sym->vm_sym = cached_func_;
+                        return sym;
+                    }
+                }
+                return cached_func_;
+            }
+        }
+    }
+
+    ProcessState *pstate = processes_[pid];
+    if (pstate == NULL) {
+        // There is no process state for the specified pid.
+        // This should never happen.
+        cached_pid_ = -1;
+        cached_func_ = NULL;
+        return NULL;
+    }
+    ProcessState *manager = pstate->addr_manager;
+    cached_pid_ = pid;
+    region_type *region = FindRegion(addr, manager->nregions, manager->regions);
+    uint32_t sym_addr = addr - region->base_addr;
+
+    cached_func_ = FindFunction(sym_addr, region->nsymbols, region->symbols,
+                                false /* no exact match */);
+    if (cached_func_ != NULL) {
+        cached_func_->region = region;
+
+        // If this function is the virtual machine interpreter, then
+        // read the method trace to find the "real" method name based
+        // on the current time and pid.
+        if (cached_func_->flags & symbol_type::kIsInterpreter) {
+            symbol_type *sym = FindCurrentMethod(pid, time);
+            if (sym != NULL) {
+                sym->vm_sym = cached_func_;
+                return sym;
+            }
+        }
+    }
+
+    return cached_func_;
+}
+
+template <class T>
+void TraceReader<T>::HandlePidEvent(PidEvent *event)
+{
+    switch (event->rec_type) {
+    case kPidFork:
+    case kPidClone:
+        // event->pid is the process id of the child
+        if (event->pid >= kNumPids) {
+            fprintf(stderr, "Error: pid (%d) too large\n", event->pid);
+            exit(1);
+        }
+        // Create a new ProcessState struct for the child
+        // and link it in at the front of the list for that
+        // pid.
+        {
+            ProcessState *child = new ProcessState;
+            processes_[event->pid] = child;
+            child->pid = event->pid;
+            child->tgid = event->tgid;
+
+            // Link the new child at the front of the list (only needed if
+            // pids wrap around, which will probably never happen when
+            // tracing because it would take so long).
+            child->next = processes_[event->pid];
+            child->parent_pid = current_->pid;
+            child->parent = current_;
+            child->start_time = event->time;
+            child->name = Strdup(current_->name);
+            if (event->rec_type == kPidFork) {
+                CopyRegions(current_, child);
+            } else {
+                // Share the parent's address space
+                child->flags |= ProcessState::kIsClone;
+
+                // The address space manager for the clone is the same
+                // as the address space manager for the parent.  This works
+                // even if the child later clones itself.
+                child->addr_manager = current_->addr_manager;
+            }
+        }
+        break;
+    case kPidSwitch:
+        // event->pid is the process id of the process we are
+        // switching to.
+        {
+            uint64_t elapsed = event->time - function_start_time_;
+            function_start_time_ = event->time;
+            current_->cpu_time += elapsed;
+        }
+        if (current_->flags & ProcessState::kCalledExit)
+            current_->end_time = event->time;
+
+        if (event->pid >= kNumPids) {
+            fprintf(stderr, "Error: pid (%d) too large\n", event->pid);
+            exit(1);
+        }
+
+        // If the process we are switching to does not exist, then
+        // create one.  This can happen because the tracing code does
+        // not start tracing from the very beginning of the kernel.
+        current_ = processes_[event->pid];
+        if (current_ == NULL) {
+            current_ = new ProcessState;
+            processes_[event->pid] = current_;
+            current_->pid = event->pid;
+            current_->start_time = event->time;
+            CopyKernelRegion(current_);
+        }
+#if 0
+        {
+            printf("switching to p%d\n", current_->pid);
+            ProcessState *manager = current_->addr_manager;
+            for (int ii = 0; ii < manager->nregions; ++ii) {
+                printf("  %08x - %08x offset: %d nsyms: %4d %s\n",
+                       manager->regions[ii]->vstart,
+                       manager->regions[ii]->vend,
+                       manager->regions[ii]->file_offset,
+                       manager->regions[ii]->nsymbols,
+                       manager->regions[ii]->path);
+            }
+        }
+#endif
+        break;
+    case kPidExit:
+        current_->exit_val = event->pid;
+        current_->flags |= ProcessState::kCalledExit;
+        break;
+    case kPidMmap:
+        {
+            region_type *region;
+            region_type *existing_region = hash_->Find(event->path);
+            if (existing_region == NULL || existing_region->vstart != event->vstart) {
+                // Create a new region and add it to the current process'
+                // address space.
+                region = new region_type;
+
+                // The event->path is allocated by ReadPidEvent() and owned
+                // by us.
+                region->path = event->path;
+                region->vstart = event->vstart;
+                region->vend = event->vend;
+                region->file_offset = event->offset;
+                if (existing_region == NULL) {
+                    DexFileList *dexfile = dex_hash_->Find(event->path);
+                    if (dexfile != NULL) {
+                        PopulateSymbolsFromDexFile(dexfile, region);
+                    } else {
+                        ReadElfSymbols(region, 0);
+                    }
+                    hash_->Update(region->path, region);
+                } else {
+                    region->nsymbols = existing_region->nsymbols;
+                    region->symbols = existing_region->symbols;
+                    region->path = existing_region->path;
+                    delete[] event->path;
+                    region->flags |= region_type::kSharedSymbols;
+                }
+
+                // The base_addr is subtracted from an address before the
+                // symbol name lookup and is either zero or event->vstart.
+                // HACK: Determine if base_addr is non-zero by looking at the
+                // second symbol address (skip the first symbol because that is
+                // the special symbol "(unknown)" with an address of zero).
+                if (region->nsymbols > 2 && region->symbols[1].addr < event->vstart)
+                    region->base_addr = event->vstart;
+
+                // Treat all mmapped regions after the first as "libraries".
+                // Profiling tools can test for this property.
+                if (current_->flags & ProcessState::kHasFirstMmap)
+                    region->flags |= region_type::kIsLibraryRegion;
+                else
+                    current_->flags |= ProcessState::kHasFirstMmap;
+#if 0
+                printf("%s vstart: 0x%x vend: 0x%x offset: 0x%x\n",
+                       region->path, region->vstart, region->vend, region->file_offset);
+#endif
+            } else {
+                region = existing_region;
+                region->refs += 1;
+                delete[] event->path;
+            }
+            AddRegion(current_, region);
+        }
+        break;
+    case kPidExec:
+        if (current_->argc > 0) {
+            for (int ii = 0; ii < current_->argc; ii++) {
+                delete[] current_->argv[ii];
+            }
+            delete[] current_->argv;
+        }
+        delete[] current_->name;
+
+        current_->argc = event->argc;
+        current_->argv = event->argv;
+        current_->name = Strdup(current_->argv[0]);
+        current_->flags |= ProcessState::kCalledExec;
+        ClearRegions(current_);
+        break;
+    case kPidName:
+    case kPidKthreadName:
+        {
+            ProcessState *pstate = processes_[event->pid];
+            if (pstate == NULL) {
+                pstate = new ProcessState;
+                if (event->rec_type == kPidKthreadName) {
+                    pstate->tgid = event->tgid;
+                }
+                pstate->pid = event->pid;
+                pstate->start_time = event->time;
+                processes_[event->pid] = pstate;
+                CopyKernelRegion(pstate);
+            } else {
+                delete[] pstate->name;
+            }
+            pstate->name = event->path;
+        }
+        break;
+    case kPidNoAction:
+        break;
+    case kPidSymbolAdd:
+        delete[] event->path;
+        break;
+    case kPidSymbolRemove:
+        break;
+    }
+}
+
+// Finds the current pid for the given time.  This routine reads the pid
+// trace file and assumes that the "time" parameter is monotonically
+// increasing.
+template <class T>
+int TraceReader<T>::FindCurrentPid(uint64_t time)
+{
+    if (time < next_pid_event_.time)
+        return current_->pid;
+
+    while (1) {
+        HandlePidEvent(&next_pid_event_);
+
+        if (internal_pid_reader_->ReadPidEvent(&next_pid_event_)) {
+            next_pid_event_.time = ~0ull;
+            break;
+        }
+        if (next_pid_event_.time > time)
+            break;
+    }
+    return current_->pid;
+}
+
+template <class T>
+void TraceReader<T>::ProcessState::DumpStack()
+{
+    for (int ii = 0; ii < method_stack_top; ii++) {
+        printf("%2d: 0x%08x\n", ii, method_stack[ii]);
+    }
+}
+
+template <class T>
+void TraceReader<T>::HandleMethodRecord(ProcessState *pstate,
+                                        MethodRec *method_rec)
+{
+    uint32_t addr;
+    int top = pstate->method_stack_top;
+    if (method_rec->flags == kMethodEnter) {
+        // Push this method on the stack
+        if (top >= pstate->kMaxMethodStackSize) {
+            fprintf(stderr, "Stack overflow at time %llu\n", method_rec->time);
+            exit(1);
+        }
+        pstate->method_stack[top] = method_rec->addr;
+        pstate->method_stack_top = top + 1;
+        addr = method_rec->addr;
+    } else {
+        if (top <= 0) {
+            // If the stack underflows, then set the current method to NULL.
+            pstate->current_method_sym = NULL;
+            return;
+        }
+        top -= 1;
+        addr = pstate->method_stack[top];
+        if (addr != method_rec->addr) {
+            fprintf(stderr,
+                    "Stack method (0x%x) at index %d does not match trace record (0x%x) at time %llu\n",
+                    addr, top, method_rec->addr, method_rec->time);
+            for (int ii = 0; ii <= top; ii++) {
+                fprintf(stderr, "  %d: 0x%x\n", ii, pstate->method_stack[ii]);
+            }
+            exit(1);
+        }
+
+        pstate->method_stack_top = top;
+        if (top == 0) {
+            // When we empty the stack, set the current method to NULL
+            pstate->current_method_sym = NULL;
+            return;
+        }
+        addr = pstate->method_stack[top - 1];
+    }
+    ProcessState *manager = pstate->addr_manager;
+    region_type *region = FindRegion(addr, manager->nregions, manager->regions);
+    uint32_t sym_addr = addr - region->base_addr;
+    symbol_type *sym = FindFunction(sym_addr, region->nsymbols,
+                                    region->symbols, true /* exact match */);
+
+    pstate->current_method_sym = sym;
+    if (sym != NULL) {
+        sym->region = region;
+    }
+}
+
+template <class T>
+typename TraceReader<T>::symbol_type*
+TraceReader<T>::FindCurrentMethod(int pid, uint64_t time)
+{
+    ProcessState *procState = processes_[pid];
+
+    if (time < next_method_.time) {
+        return procState->current_method_sym;
+    }
+
+    while (1) {
+        if (next_method_.time != 0) {
+            // We may have to process methods from a different pid so use
+            // a local variable here so that we don't overwrite procState.
+            ProcessState *pState = processes_[next_method_.pid];
+            HandleMethodRecord(pState, &next_method_);
+        }
+
+        if (internal_method_reader_->ReadMethod(&next_method_)) {
+            next_method_.time = ~0ull;
+            break;
+        }
+        if (next_method_.time > time)
+            break;
+    }
+    return procState->current_method_sym;
+}
+
+template <class T>
+void TraceReader<T>::PopulateSymbolsFromDexFile(const DexFileList *dexfile,
+                                                region_type *region)
+                                                
+{
+    int nsymbols = dexfile->nsymbols;
+    DexSym *dexsyms = dexfile->symbols;
+    region->nsymbols = nsymbols + 1;
+    symbol_type *symbols = new symbol_type[nsymbols + 1];
+    memset(symbols, 0, (nsymbols + 1) * sizeof(symbol_type));
+    region->symbols = symbols;
+    for (int ii = 0; ii < nsymbols; ii++) {
+        symbols[ii].addr = dexsyms[ii].addr;
+        symbols[ii].name = Strdup(dexsyms[ii].name);
+        symbols[ii].vm_sym = NULL;
+        symbols[ii].region = region;
+        symbols[ii].flags = symbol_type::kIsMethod;
+    }
+
+    // Add an entry at the end with an address of 0xffffffff.  This
+    // is required for LookupFunction() to work.
+    symbol_type *symbol = &symbols[nsymbols];
+    symbol->addr = 0xffffffff;
+    symbol->name = Strdup("(end)");
+    symbol->vm_sym = NULL;
+    symbol->region = region;
+    symbol->flags = symbol_type::kIsMethod;
+}
+
+template <class T>
+bool TraceReader<T>::ReadMethodSymbol(MethodRec *method_record,
+                                      symbol_type **psym,
+                                      ProcessState **pproc)
+{
+    if (internal_method_reader_->ReadMethod(&next_method_)) {
+        return true;
+    }
+
+    // Copy the whole MethodRec struct
+    *method_record = next_method_;
+
+    uint64_t time = next_method_.time;
+    
+    // Read the pid trace file up to this point to make sure the
+    // process state is valid.
+    FindCurrentPid(time);
+
+    ProcessState *pstate = processes_[next_method_.pid];
+    *pproc = pstate;
+    HandleMethodRecord(pstate, &next_method_);
+    *psym = pstate->current_method_sym;
+    return false;
+}
+
+#endif /* TRACE_READER_H */
diff --git a/emulator/qtools/trace_reader_base.h b/emulator/qtools/trace_reader_base.h
new file mode 100644
index 0000000..281d085
--- /dev/null
+++ b/emulator/qtools/trace_reader_base.h
@@ -0,0 +1,332 @@
+// Copyright 2006 The Android Open Source Project
+
+#ifndef TRACE_READER_BASE_H
+#define TRACE_READER_BASE_H
+
+#include <inttypes.h>
+#include "trace_common.h"
+#include "hash_table.h"
+
+class BBReader;
+class InsnReader;
+class AddrReader;
+class ExcReader;
+class PidReader;
+class MethodReader;
+
+struct StaticRec {
+    uint64_t    bb_num;
+    uint32_t    bb_addr;
+    uint32_t    num_insns;
+};
+
+struct StaticBlock {
+    StaticRec   rec;
+    uint32_t    *insns;
+};
+
+struct BBEvent {
+    uint64_t    time;
+    uint64_t    bb_num;
+    uint32_t    bb_addr;
+    uint32_t    *insns;
+    int         num_insns;
+    int         pid;
+    int         is_thumb;
+};
+
+struct PidEvent {
+    uint64_t    time;
+    int         rec_type;       // record type: fork, context switch, exit ...
+    int         tgid;           // thread group id
+    int         pid;            // for fork: child pid; for switch: next pid;
+                                //   for exit: exit value
+    uint32_t    vstart;         // virtual start address (only used with mmap)
+    uint32_t    vend;           // virtual end address (only used with mmap)
+    uint32_t    offset;         // virtual file offset (only used with mmap)
+
+    // Dynamically allocated path to executable (or lib). In the case of
+    // an mmapped dex file, the path is modified to be more useful for
+    // comparing against the output of dexlist.  For example, instead of this:
+    //   /data/dalvik-cache/system@app@TestHarness.apk@classes.dex
+    // We convert to this:
+    //   /system/app/TestHarness.apk
+    char        *path;
+    char        *mmap_path;     // unmodified mmap path
+    int         argc;           // number of args
+    char        **argv;         // dynamically allocated array of args
+};
+
+struct MethodRec {
+    uint64_t    time;
+    uint32_t    addr;
+    int         pid;
+    int         flags;
+};
+
+struct DexSym {
+    uint32_t    addr;
+    int         len;
+    char        *name;
+};
+
+struct DexFileList {
+    char        *path;
+    int         nsymbols;
+    DexSym      *symbols;
+};
+
+class TraceReaderBase {
+  public:
+    TraceReaderBase();
+    virtual ~TraceReaderBase();
+
+    friend class BBReader;
+
+    void                Open(char *filename);
+    void                Close();
+    void                WriteHeader(TraceHeader *header);
+    inline bool         ReadBB(BBEvent *event);
+    int                 ReadStatic(StaticRec *rec);
+    int                 ReadStaticInsns(int num, uint32_t *insns);
+    TraceHeader         *GetHeader()                { return header_; }
+    inline uint64_t     ReadInsnTime(uint64_t min_time);
+    void                TruncateLastBlock(uint32_t num_insns);
+    inline bool         ReadAddr(uint64_t *time, uint32_t *addr, int *flags);
+    inline bool         ReadExc(uint64_t *time, uint32_t *current_pc,
+                                uint64_t *recnum, uint32_t *target_pc,
+                                uint64_t *bb_num, uint64_t *bb_start_time,
+                                int *num_insns);
+    inline bool         ReadPidEvent(PidEvent *event);
+    inline bool         ReadMethod(MethodRec *method_record);
+    StaticBlock         *GetStaticBlock(uint64_t bb_num) { return &blocks_[bb_num]; }
+    uint32_t            *GetInsns(uint64_t bb_num) { return blocks_[bb_num].insns; }
+    uint32_t            GetBBAddr(uint64_t bb_num) {
+        return blocks_[bb_num].rec.bb_addr & ~1;
+    }
+    int                 GetIsThumb(uint64_t bb_num) {
+        return blocks_[bb_num].rec.bb_addr & 1;
+    }
+    void                SetPostProcessing(bool val) { post_processing_ = val; }
+
+  protected:
+    virtual int         FindCurrentPid(uint64_t time);
+    int                 current_pid_;
+    int                 next_pid_;
+    uint64_t            next_pid_switch_time_;
+    PidReader           *internal_pid_reader_;
+    MethodReader        *internal_method_reader_;
+    HashTable<DexFileList*> *dex_hash_;
+
+  private:
+    int          FindNumInsns(uint64_t bb_num, uint64_t bb_start_time);
+    void         ReadTraceHeader(FILE *fstream, char *filename,
+                                char *tracename, TraceHeader *header);
+    PidEvent     *FindMmapDexFileEvent();
+    void         ParseDexList(char *filename);
+
+    char         *static_filename_;
+    FILE         *static_fstream_;
+    TraceHeader  *header_;
+    BBReader     *bb_reader_;
+    InsnReader   *insn_reader_;
+    AddrReader   *load_addr_reader_;
+    AddrReader   *store_addr_reader_;
+    ExcReader    *exc_reader_;
+    PidReader    *pid_reader_;
+    MethodReader *method_reader_;
+    ExcReader    *internal_exc_reader_;
+    StaticBlock  *blocks_;
+    bool         exc_end_;
+    uint64_t     bb_recnum_;
+    uint64_t     exc_recnum_;
+    uint64_t     exc_bb_num_;
+    uint64_t     exc_time_;
+    int          exc_num_insns_;
+    bool         post_processing_;
+
+    bool         load_eof_;
+    uint64_t     load_time_;
+    uint32_t     load_addr_;
+    bool         store_eof_;
+    uint64_t     store_time_;
+    uint32_t     store_addr_;
+};
+
+class Decoder;
+
+class BBReader {
+  public:
+    explicit BBReader(TraceReaderBase *trace);
+    ~BBReader();
+    void     Open(char *filename);
+    void     Close();
+    bool     ReadBB(BBEvent *event);
+
+  private:
+    struct TimeRec {
+        BBRec       bb_rec;
+        uint64_t    next_time;
+    };
+
+    struct Future {
+        Future      *next;
+        TimeRec     bb;
+    };
+
+    inline Future   *AllocFuture();
+    inline void     FreeFuture(Future *future);
+    inline void     InsertFuture(Future *future);
+    inline int      DecodeNextRec();
+
+    TimeRec         nextrec_;
+    Future          futures_[kMaxNumBasicBlocks];
+    Future          *head_;
+    Future          *free_;
+    Decoder         *decoder_;
+    bool            is_eof_;
+    TraceReaderBase *trace_;
+};
+
+class InsnReader {
+  public:
+    InsnReader();
+    ~InsnReader();
+
+    void        Open(char *filename);
+    void        Close();
+    uint64_t    ReadInsnTime(uint64_t min_time);
+
+  private:
+    Decoder     *decoder_;
+    uint64_t    prev_time_;
+    uint64_t    time_diff_;
+    int         repeat_;
+};
+
+class AddrReader {
+  public:
+    AddrReader();
+    ~AddrReader();
+
+    bool        Open(char *filename, char *suffix);
+    void        Close();
+    bool        ReadAddr(uint64_t *time, uint32_t *addr);
+
+  private:
+    Decoder     *decoder_;
+    uint32_t    prev_addr_;
+    uint64_t    prev_time_;
+    bool        opened_;        // true after file is opened
+};
+
+class ExcReader {
+  public:
+    ExcReader();
+    ~ExcReader();
+
+    void        Open(char *filename);
+    void        Close();
+    bool        ReadExc(uint64_t *time, uint32_t *current_pc,
+                        uint64_t *recnum, uint32_t *target_pc,
+                        uint64_t *bb_num, uint64_t *bb_start_time,
+                        int *num_insns);
+
+  private:
+    Decoder     *decoder_;
+    uint64_t    prev_time_;
+    uint64_t    prev_recnum_;
+};
+
+class PidReader {
+  public:
+    PidReader();
+    ~PidReader();
+
+    void        Open(char *filename);
+    void        Close();
+    bool        ReadPidEvent(struct PidEvent *event);
+    void        Dispose(struct PidEvent *event);
+
+  private:
+    Decoder     *decoder_;
+    uint64_t    prev_time_;
+};
+
+class MethodReader {
+  public:
+    MethodReader();
+    ~MethodReader();
+
+    bool        Open(char *filename);
+    void        Close();
+    bool        ReadMethod(MethodRec *method_record);
+
+  private:
+    Decoder     *decoder_;
+    uint64_t    prev_time_;
+    uint32_t    prev_addr_;
+    int32_t     prev_pid_;
+    bool        opened_;        // true after file is opened
+};
+
+// Reads the next dynamic basic block from the trace.
+// Returns true on end-of-file.
+inline bool TraceReaderBase::ReadBB(BBEvent *event)
+{
+    bb_recnum_ += 1;
+    return bb_reader_->ReadBB(event);
+}
+
+inline uint64_t TraceReaderBase::ReadInsnTime(uint64_t min_time)
+{
+    return insn_reader_->ReadInsnTime(min_time);
+}
+
+inline bool TraceReaderBase::ReadAddr(uint64_t *time, uint32_t *addr, int *flags)
+{
+    if (load_eof_ && store_eof_)
+        return true;
+
+    if (store_eof_ || (!load_eof_ && load_time_ <= store_time_)) {
+        *time = load_time_;
+        *addr = load_addr_;
+        *flags = 0;
+        load_eof_ = load_addr_reader_->ReadAddr(&load_time_, &load_addr_);
+    } else {
+        *time = store_time_;
+        *addr = store_addr_;
+        *flags = 1;
+        store_eof_ = store_addr_reader_->ReadAddr(&store_time_, &store_addr_);
+    }
+    return false;
+}
+
+inline bool TraceReaderBase::ReadExc(uint64_t *time, uint32_t *current_pc,
+                                     uint64_t *recnum, uint32_t *target_pc,
+                                     uint64_t *bb_num, uint64_t *bb_start_time,
+                                     int *num_insns)
+{
+    return exc_reader_->ReadExc(time, current_pc, recnum, target_pc, bb_num,
+                                bb_start_time, num_insns);
+}
+
+inline bool TraceReaderBase::ReadPidEvent(PidEvent *event)
+{
+    return pid_reader_->ReadPidEvent(event);
+}
+
+inline bool TraceReaderBase::ReadMethod(MethodRec *method_record)
+{
+    return method_reader_->ReadMethod(method_record);
+}
+
+// Duplicates a string, allocating space using new[].
+inline char * Strdup(const char *src) {
+    int len = strlen(src);
+    char *copy = new char[len + 1];
+    strcpy(copy, src);
+    return copy;
+}
+
+#endif /* TRACE_READER_BASE_H */
diff --git a/emulator/skins/HVGA-L/arrow_down.png b/emulator/skins/HVGA-L/arrow_down.png
new file mode 100644
index 0000000..374299c
--- /dev/null
+++ b/emulator/skins/HVGA-L/arrow_down.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/arrow_left.png b/emulator/skins/HVGA-L/arrow_left.png
new file mode 100644
index 0000000..ba7dd3f
--- /dev/null
+++ b/emulator/skins/HVGA-L/arrow_left.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/arrow_right.png b/emulator/skins/HVGA-L/arrow_right.png
new file mode 100644
index 0000000..271311d
--- /dev/null
+++ b/emulator/skins/HVGA-L/arrow_right.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/arrow_up.png b/emulator/skins/HVGA-L/arrow_up.png
new file mode 100644
index 0000000..01f4554
--- /dev/null
+++ b/emulator/skins/HVGA-L/arrow_up.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/back.png b/emulator/skins/HVGA-L/back.png
new file mode 100644
index 0000000..46cca3d
--- /dev/null
+++ b/emulator/skins/HVGA-L/back.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/background.png b/emulator/skins/HVGA-L/background.png
new file mode 100644
index 0000000..fde44b5
--- /dev/null
+++ b/emulator/skins/HVGA-L/background.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/end.png b/emulator/skins/HVGA-L/end.png
new file mode 100644
index 0000000..760a614
--- /dev/null
+++ b/emulator/skins/HVGA-L/end.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/home.png b/emulator/skins/HVGA-L/home.png
new file mode 100644
index 0000000..47beb77
--- /dev/null
+++ b/emulator/skins/HVGA-L/home.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/key.png b/emulator/skins/HVGA-L/key.png
new file mode 100644
index 0000000..7a3f563
--- /dev/null
+++ b/emulator/skins/HVGA-L/key.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/layout b/emulator/skins/HVGA-L/layout
new file mode 100644
index 0000000..1a98bfd
--- /dev/null
+++ b/emulator/skins/HVGA-L/layout
@@ -0,0 +1,332 @@
+display {
+	width  480
+	height 320
+	x 145
+	y 78
+}
+
+background {
+	image background.png
+	x 0
+	y 0
+}
+
+button {
+	1 {
+	   image  key.png
+	   x  224
+	   y  468
+	}
+	2 {
+	   image  key.png
+	   x 261
+	   y 468
+	}
+	3 {
+	   image  key.png
+	   x 298
+	   y 468
+	}
+	4 {
+	   image  key.png
+	   x 335
+	   y 468
+	}
+	5 {
+	   image  key.png
+	   x 372
+	   y 468
+	}
+	6 {
+	   image  key.png
+	   x 409
+	   y 468
+	}
+	7 {
+	   image  key.png
+	   x 446
+	   y 468
+	}
+	8 {
+	   image  key.png
+	   x 482
+	   y 468
+	}
+	9 {
+	   image  key.png
+	   x 520
+	   y 468
+	}
+	0 {
+	   image  key.png
+	   x 557
+	   y 468
+	}
+
+	q {
+	   image  key.png
+	   x  224
+	   y  504
+	}
+	w {
+	   image  key.png
+	   x 261
+	   y 504
+	}
+	e {
+	   image  key.png
+	   x 298
+	   y 504
+	}
+	r {
+	   image  key.png
+	   x 335
+	   y 504
+	}
+	t {
+	   image  key.png
+	   x 372
+	   y 504
+	}
+	y {
+	   image  key.png
+	   x 409
+	   y 504
+	}
+	u {
+	   image  key.png
+	   x 446
+	   y 504
+	}
+	i {
+	   image  key.png
+	   x 482
+	   y 504
+	}
+	o {
+	   image  key.png
+	   x 520
+	   y 504
+	}
+	p {
+	   image  key.png
+	   x 557
+	   y 504
+	}
+
+	a {
+	   image  key.png
+	   x  224
+	   y  540
+	}
+	s {
+	   image  key.png
+	   x 261
+	   y 540
+	}
+	d {
+	   image  key.png
+	   x 298
+	   y 540
+	}
+	f {
+	   image  key.png
+	   x 335
+	   y 540
+	}
+	g {
+	   image  key.png
+	   x 372
+	   y 540
+	}
+	h {
+	   image  key.png
+	   x 409
+	   y 540
+	}
+	j {
+	   image  key.png
+	   x 446
+	   y 540
+	}
+	k {
+	   image  key.png
+	   x 482
+	   y 540
+	}
+	l {
+	   image  key.png
+	   x 520
+	   y 540
+	}
+	DEL {
+	   image  key.png
+	   x 557
+	   y 540
+	}
+
+	CAP {
+	   image  key.png
+	   x  224
+	   y  576
+	}
+	z {
+	   image  key.png
+	   x 261
+	   y 576
+	}
+	x {
+	   image  key.png
+	   x 298
+	   y 576
+	}
+	c {
+	   image  key.png
+	   x 335
+	   y 576
+	}
+	v {
+	   image  key.png
+	   x 372
+	   y 576
+	}
+	b {
+	   image  key.png
+	   x 409
+	   y 576
+	}
+	n {
+	   image  key.png
+	   x 446
+	   y 576
+	}
+	m {
+	   image  key.png
+	   x 482
+	   y 576
+	}
+	PERIOD {
+	   image  key.png
+	   x 520
+	   y 576
+	}
+	ENTER {
+	   image  key.png
+	   x 557
+	   y 576
+	}
+
+	ALT {
+	   image  key.png
+	   x  224
+	   y  612
+	}
+	SYM {
+	   image  key.png
+	   x 261
+	   y 612
+	}
+	AT {
+	   image  key.png
+	   x 298
+	   y 612
+	}
+	SPACE {
+	   image  spacebar.png
+	   x 335
+	   y 612
+	}
+	SLASH {
+	   image  key.png
+	   x 482
+	   y 612
+	}
+	COMMA {
+	   image  key.png
+	   x 520
+	   y 612
+	}
+	ALT2 {
+	   image  key.png
+	   x 557
+	   y 612
+	}
+
+	soft-left {
+		image menu.png
+		x 630
+		y 196
+	}
+	home {
+		image home.png
+		x 665
+		y 334
+	}
+	back {
+		image back.png
+		x 664
+		y 96
+	}
+	dpad-up {
+		image arrow_up.png
+		x 671
+		y 160
+	}
+	dpad-down {
+		image arrow_down.png
+		x 671
+		y 270
+	}
+	dpad-left {
+		image arrow_left.png
+		x 669
+		y 190
+	}
+	dpad-right {
+		image arrow_right.png
+		x 730
+		y 190
+	}
+	dpad-center {
+		image select.png
+		x 698
+		y 190
+	}
+	phone-dial {
+		image send.png
+		x 720
+		y 334
+	}
+	phone-hangup {
+		image end.png
+		x 720
+		y 96
+	}
+
+	power {
+		image power.png
+		x 128
+		y 407
+	}
+
+	volume-up {
+		image volume_up.png
+		x 336
+		y 0
+	}
+
+	volume-down {
+		image volume_down.png
+		x 386
+		y 0
+	}
+}
+
+network {
+    speed  full
+    delay  none
+}
+
+keyboard {
+    charmap qwerty2
+}
diff --git a/emulator/skins/HVGA-L/menu.png b/emulator/skins/HVGA-L/menu.png
new file mode 100644
index 0000000..7510f33
--- /dev/null
+++ b/emulator/skins/HVGA-L/menu.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/power.png b/emulator/skins/HVGA-L/power.png
new file mode 100644
index 0000000..e947d4d
--- /dev/null
+++ b/emulator/skins/HVGA-L/power.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/select.png b/emulator/skins/HVGA-L/select.png
new file mode 100644
index 0000000..82fb762
--- /dev/null
+++ b/emulator/skins/HVGA-L/select.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/send.png b/emulator/skins/HVGA-L/send.png
new file mode 100644
index 0000000..2669515
--- /dev/null
+++ b/emulator/skins/HVGA-L/send.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/spacebar.png b/emulator/skins/HVGA-L/spacebar.png
new file mode 100644
index 0000000..19fe604
--- /dev/null
+++ b/emulator/skins/HVGA-L/spacebar.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/volume_down.png b/emulator/skins/HVGA-L/volume_down.png
new file mode 100644
index 0000000..f1c0fbf
--- /dev/null
+++ b/emulator/skins/HVGA-L/volume_down.png
Binary files differ
diff --git a/emulator/skins/HVGA-L/volume_up.png b/emulator/skins/HVGA-L/volume_up.png
new file mode 100644
index 0000000..67d2d2a
--- /dev/null
+++ b/emulator/skins/HVGA-L/volume_up.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/arrow_down.png b/emulator/skins/HVGA-P/arrow_down.png
new file mode 100644
index 0000000..19b3764
--- /dev/null
+++ b/emulator/skins/HVGA-P/arrow_down.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/arrow_left.png b/emulator/skins/HVGA-P/arrow_left.png
new file mode 100644
index 0000000..113e584
--- /dev/null
+++ b/emulator/skins/HVGA-P/arrow_left.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/arrow_right.png b/emulator/skins/HVGA-P/arrow_right.png
new file mode 100644
index 0000000..ffe3356
--- /dev/null
+++ b/emulator/skins/HVGA-P/arrow_right.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/arrow_up.png b/emulator/skins/HVGA-P/arrow_up.png
new file mode 100644
index 0000000..81c54df
--- /dev/null
+++ b/emulator/skins/HVGA-P/arrow_up.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/back.png b/emulator/skins/HVGA-P/back.png
new file mode 100644
index 0000000..41034d9
--- /dev/null
+++ b/emulator/skins/HVGA-P/back.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/background.png b/emulator/skins/HVGA-P/background.png
new file mode 100644
index 0000000..bab8c6d
--- /dev/null
+++ b/emulator/skins/HVGA-P/background.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/end.png b/emulator/skins/HVGA-P/end.png
new file mode 100644
index 0000000..6830a60
--- /dev/null
+++ b/emulator/skins/HVGA-P/end.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/home.png b/emulator/skins/HVGA-P/home.png
new file mode 100644
index 0000000..7d02136
--- /dev/null
+++ b/emulator/skins/HVGA-P/home.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/key.png b/emulator/skins/HVGA-P/key.png
new file mode 100644
index 0000000..7a3f563
--- /dev/null
+++ b/emulator/skins/HVGA-P/key.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/layout b/emulator/skins/HVGA-P/layout
new file mode 100644
index 0000000..1189ca5
--- /dev/null
+++ b/emulator/skins/HVGA-P/layout
@@ -0,0 +1,332 @@
+display {
+	width  320
+	height 480
+	x 75
+	y 84
+}
+
+background {
+	image background.png
+	x 0
+	y 0
+}
+
+button {
+	1 {
+	   image  key.png
+	   x  468
+	   y  276
+	}
+	2 {
+	   image  key.png
+	   x 505
+	   y 276
+	}
+	3 {
+	   image  key.png
+	   x 543
+	   y 276
+	}
+	4 {
+	   image  key.png
+	   x 579
+	   y 276
+	}
+	5 {
+	   image  key.png
+	   x 616
+	   y 276
+	}
+	6 {
+	   image  key.png
+	   x 653
+	   y 276
+	}
+	7 {
+	   image  key.png
+	   x 690
+	   y 276
+	}
+	8 {
+	   image  key.png
+	   x 727
+	   y 276
+	}
+	9 {
+	   image  key.png
+	   x 763
+	   y 276
+	}
+	0 {
+	   image  key.png
+	   x 801
+	   y 276
+	}
+
+	q {
+	   image  key.png
+	   x  468
+	   y  312
+	}
+	w {
+	   image  key.png
+	   x 505
+	   y 312
+	}
+	e {
+	   image  key.png
+	   x 543
+	   y 312
+	}
+	r {
+	   image  key.png
+	   x 579
+	   y 312
+	}
+	t {
+	   image  key.png
+	   x 616
+	   y 312
+	}
+	y {
+	   image  key.png
+	   x 653
+	   y 312
+	}
+	u {
+	   image  key.png
+	   x 690
+	   y 312
+	}
+	i {
+	   image  key.png
+	   x 727
+	   y 312
+	}
+	o {
+	   image  key.png
+	   x 763
+	   y 312
+	}
+	p {
+	   image  key.png
+	   x 801
+	   y 312
+	}
+
+	a {
+	   image  key.png
+	   x  468
+	   y  348
+	}
+	s {
+	   image  key.png
+	   x 505
+	   y 348
+	}
+	d {
+	   image  key.png
+	   x 543
+	   y 348
+	}
+	f {
+	   image  key.png
+	   x 579
+	   y 348
+	}
+	g {
+	   image  key.png
+	   x 616
+	   y 348
+	}
+	h {
+	   image  key.png
+	   x 653
+	   y 348
+	}
+	j {
+	   image  key.png
+	   x 690
+	   y 348
+	}
+	k {
+	   image  key.png
+	   x 727
+	   y 348
+	}
+	l {
+	   image  key.png
+	   x 763
+	   y 348
+	}
+	DEL {
+	   image  key.png
+	   x 801
+	   y 348
+	}
+
+	CAP {
+	   image  key.png
+	   x  468
+	   y  384
+	}
+	z {
+	   image  key.png
+	   x 505
+	   y 384
+	}
+	x {
+	   image  key.png
+	   x 543
+	   y 384
+	}
+	c {
+	   image  key.png
+	   x 579
+	   y 384
+	}
+	v {
+	   image  key.png
+	   x 616
+	   y 384
+	}
+	b {
+	   image  key.png
+	   x 653
+	   y 384
+	}
+	n {
+	   image  key.png
+	   x 690
+	   y 384
+	}
+	m {
+	   image  key.png
+	   x 727
+	   y 384
+	}
+	PERIOD {
+	   image  key.png
+	   x 763
+	   y 384
+	}
+	ENTER {
+	   image  key.png
+	   x 801
+	   y 384
+	}
+
+	ALT {
+	   image  key.png
+	   x  468
+	   y  420
+	}
+	SYM {
+	   image  key.png
+	   x 505
+	   y 420
+	}
+	AT {
+	   image  key.png
+	   x 543
+	   y 420
+	}
+	SPACE {
+	   image  spacebar.png
+	   x 579
+	   y 420
+	}
+	SLASH {
+	   image  key.png
+	   x 727
+	   y 420
+	}
+	COMMA {
+	   image  key.png
+	   x 763
+	   y 420
+	}
+	ALT2 {
+	   image  key.png
+	   x 801
+	   y 420
+	}
+
+	soft-left {
+		image menu.png
+		x 192
+		y 569
+	}
+	home {
+		image home.png
+		x 93
+		y 602
+	}
+	back {
+		image back.png
+		x 331
+		y 602
+	}
+	dpad-up {
+		image arrow_up.png
+		x 185
+		y 608
+	}
+	dpad-down {
+		image arrow_down.png
+		x 185
+		y 669
+	}
+	dpad-left {
+		image arrow_left.png
+		x 155
+		y 610
+	}
+	dpad-right {
+		image arrow_right.png
+		x 266
+		y 610
+	}
+	dpad-center {
+		image select.png
+		x 186
+		y 637
+	}
+	phone-dial {
+		image send.png
+		x 93
+		y 658
+	}
+	phone-hangup {
+		image end.png
+		x 331
+		y 658
+	}
+
+	power {
+		image power.png
+		x 7
+		y 66
+	}
+
+	volume-up {
+		image volume_up.png
+		x 407
+		y 274
+	}
+
+	volume-down {
+		image volume_down.png
+		x 407
+		y 324
+	}
+}
+
+keyboard {
+    charmap qwerty2
+}
+
+network {
+    speed  full
+    delay  none
+}
diff --git a/emulator/skins/HVGA-P/menu.png b/emulator/skins/HVGA-P/menu.png
new file mode 100644
index 0000000..e81d8ab
--- /dev/null
+++ b/emulator/skins/HVGA-P/menu.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/power.png b/emulator/skins/HVGA-P/power.png
new file mode 100644
index 0000000..5894288
--- /dev/null
+++ b/emulator/skins/HVGA-P/power.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/select.png b/emulator/skins/HVGA-P/select.png
new file mode 100644
index 0000000..803d493
--- /dev/null
+++ b/emulator/skins/HVGA-P/select.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/send.png b/emulator/skins/HVGA-P/send.png
new file mode 100644
index 0000000..f547c88
--- /dev/null
+++ b/emulator/skins/HVGA-P/send.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/spacebar.png b/emulator/skins/HVGA-P/spacebar.png
new file mode 100644
index 0000000..19fe604
--- /dev/null
+++ b/emulator/skins/HVGA-P/spacebar.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/volume_down.png b/emulator/skins/HVGA-P/volume_down.png
new file mode 100644
index 0000000..f8a88de
--- /dev/null
+++ b/emulator/skins/HVGA-P/volume_down.png
Binary files differ
diff --git a/emulator/skins/HVGA-P/volume_up.png b/emulator/skins/HVGA-P/volume_up.png
new file mode 100644
index 0000000..940457f
--- /dev/null
+++ b/emulator/skins/HVGA-P/volume_up.png
Binary files differ
diff --git a/emulator/skins/HVGA/arrow_down.png b/emulator/skins/HVGA/arrow_down.png
new file mode 100644
index 0000000..19b3764
--- /dev/null
+++ b/emulator/skins/HVGA/arrow_down.png
Binary files differ
diff --git a/emulator/skins/HVGA/arrow_left.png b/emulator/skins/HVGA/arrow_left.png
new file mode 100644
index 0000000..113e584
--- /dev/null
+++ b/emulator/skins/HVGA/arrow_left.png
Binary files differ
diff --git a/emulator/skins/HVGA/arrow_right.png b/emulator/skins/HVGA/arrow_right.png
new file mode 100644
index 0000000..ffe3356
--- /dev/null
+++ b/emulator/skins/HVGA/arrow_right.png
Binary files differ
diff --git a/emulator/skins/HVGA/arrow_up.png b/emulator/skins/HVGA/arrow_up.png
new file mode 100644
index 0000000..81c54df
--- /dev/null
+++ b/emulator/skins/HVGA/arrow_up.png
Binary files differ
diff --git a/emulator/skins/HVGA/back.png b/emulator/skins/HVGA/back.png
new file mode 100644
index 0000000..41034d9
--- /dev/null
+++ b/emulator/skins/HVGA/back.png
Binary files differ
diff --git a/emulator/skins/HVGA/device.png b/emulator/skins/HVGA/device.png
new file mode 100644
index 0000000..465eb02
--- /dev/null
+++ b/emulator/skins/HVGA/device.png
Binary files differ
diff --git a/emulator/skins/HVGA/end.png b/emulator/skins/HVGA/end.png
new file mode 100644
index 0000000..6830a60
--- /dev/null
+++ b/emulator/skins/HVGA/end.png
Binary files differ
diff --git a/emulator/skins/HVGA/home.png b/emulator/skins/HVGA/home.png
new file mode 100644
index 0000000..7d02136
--- /dev/null
+++ b/emulator/skins/HVGA/home.png
Binary files differ
diff --git a/emulator/skins/HVGA/key.png b/emulator/skins/HVGA/key.png
new file mode 100644
index 0000000..7a3f563
--- /dev/null
+++ b/emulator/skins/HVGA/key.png
Binary files differ
diff --git a/emulator/skins/HVGA/keyboard.png b/emulator/skins/HVGA/keyboard.png
new file mode 100644
index 0000000..bb076d3
--- /dev/null
+++ b/emulator/skins/HVGA/keyboard.png
Binary files differ
diff --git a/emulator/skins/HVGA/layout b/emulator/skins/HVGA/layout
new file mode 100644
index 0000000..4c3d764
--- /dev/null
+++ b/emulator/skins/HVGA/layout
@@ -0,0 +1,380 @@
+parts {
+    device {
+        background {
+            image   device.png
+        }
+        display {
+            width   320
+            height  480
+            x       31
+            y       72
+        }
+
+        buttons {
+            soft-left {
+                    image menu.png
+                    x 147
+                    y 555
+            }
+            home {
+                    image home.png
+                    x 48
+                    y 590
+            }
+            back {
+                    image back.png
+                    x 286
+                    y 590
+            }
+            dpad-up {
+                    image arrow_up.png
+                    x 140
+                    y 595
+            }
+            dpad-down {
+                    image arrow_down.png
+                    x 140
+                    y 656
+            }
+            dpad-left {
+                    image arrow_left.png
+                    x 111
+                    y 598
+            }
+            dpad-right {
+                    image arrow_right.png
+                    x 222
+                    y 598
+            }
+            dpad-center {
+                    image select.png
+                    x 142
+                    y 626
+            }
+            phone-dial {
+                    image send.png
+                    x 48
+                    y 646
+            }
+            phone-hangup {
+                    image end.png
+                    x 286
+                    y 646
+            }
+
+            power {
+                    image power.png
+                    x -38
+                    y 52
+            }
+
+            volume-up {
+                    image volume_up.png
+                    x 362
+                    y 260
+            }
+
+            volume-down {
+                    image volume_down.png
+                    x 362
+                    y 310
+            }
+        }
+    }
+
+    keyboard {
+        background {
+            image   keyboard.png
+        }
+        buttons {
+            1 {
+                image  key.png
+                x  0
+                y  0
+            }
+            2 {
+                image  key.png
+                x 37
+                y 0
+            }
+            3 {
+                image  key.png
+                x 74
+                y 0
+            }
+            4 {
+                image  key.png
+                x 111
+                y 0
+            }
+            5 {
+                image  key.png
+                x 148
+                y 0
+            }
+            6 {
+                image  key.png
+                x 185
+                y 0
+            }
+            7 {
+                image  key.png
+                x 222
+                y 0
+            }
+            8 {
+                image  key.png
+                x 259
+                y 0
+            }
+            9 {
+                image  key.png
+                x 296
+                y 0
+            }
+            0 {
+                image  key.png
+                x 333
+                y 0
+            }
+
+            q {
+                image  key.png
+                x  0
+                y  36
+            }
+            w {
+                image  key.png
+                x 37
+                y 36
+            }
+            e {
+                image  key.png
+                x 74
+                y 36
+            }
+            r {
+                image  key.png
+                x 111
+                y 36
+            }
+            t {
+                image  key.png
+                x 148
+                y 36
+            }
+            y {
+                image  key.png
+                x 185
+                y 36
+            }
+            u {
+                image  key.png
+                x 222
+                y 36
+            }
+            i {
+                image  key.png
+                x 259
+                y 36
+            }
+            o {
+                image  key.png
+                x 296
+                y 36
+            }
+            p {
+                image  key.png
+                x 333
+                y 36
+            }
+
+            a {
+                image  key.png
+                x  0
+                y  72
+            }
+            s {
+                image  key.png
+                x 37
+                y 72
+            }
+            d {
+                image  key.png
+                x 74
+                y 72
+            }
+            f {
+                image  key.png
+                x 111
+                y 72
+            }
+            g {
+                image  key.png
+                x 148
+                y 72
+            }
+            h {
+                image  key.png
+                x 185
+                y 72
+            }
+            j {
+                image  key.png
+                x 222
+                y 72
+            }
+            k {
+                image  key.png
+                x 259
+                y 72
+            }
+            l {
+                image  key.png
+                x 296
+                y 72
+            }
+            DEL {
+                image  key.png
+                x 333
+                y 72
+            }
+
+            CAP {
+                image  key.png
+                x  0
+                y  108
+            }
+            z {
+                image  key.png
+                x 37
+                y 108
+            }
+            x {
+                image  key.png
+                x 74
+                y 108
+            }
+            c {
+                image  key.png
+                x 111
+                y 108
+            }
+            v {
+                image  key.png
+                x 148
+                y 108
+            }
+            b {
+                image  key.png
+                x 185
+                y 108
+            }
+            n {
+                image  key.png
+                x 222
+                y 108
+            }
+            m {
+                image  key.png
+                x 259
+                y 108
+            }
+            PERIOD {
+                image  key.png
+                x 296
+                y 108
+            }
+            ENTER {
+                image  key.png
+                x 333
+                y 108
+            }
+
+            ALT {
+                image  key.png
+                x  0
+                y  144
+            }
+            SYM {
+                image  key.png
+                x 37
+                y 144
+            }
+            AT {
+                image  key.png
+                x 74
+                y 144
+            }
+            SPACE {
+                image  spacebar.png
+                x 111
+                y 144
+            }
+            SLASH {
+                image  key.png
+                x 259
+                y 144
+            }
+            COMMA {
+                image  key.png
+                x 296
+                y 144
+            }
+            ALT2 {
+                image  key.png
+                x 333
+                y 144
+            }
+
+        }
+    }
+}
+
+layouts {
+    portrait {
+        width     900
+        height    730
+        color     0xe0e0e0
+        event     EV_SW:0:1
+
+        part1 {
+            name    device
+            x       40
+            y       -18
+        }
+        part2 {
+            name    keyboard
+            x       480
+            y       200
+        }
+    }
+
+    landscape {
+        width     900
+        height    670
+        color     0xe0e0e0
+        event     EV_SW:0:0
+
+        part1 {
+            name      device
+            x         50
+            y         440
+            rotation  3
+        }
+        part2 {
+            name     keyboard
+            x        250
+            y        470
+        }
+    }
+}
+
+keyboard {
+    charmap qwerty2
+}
+
+network {
+    speed  full
+    delay  none
+}
diff --git a/emulator/skins/HVGA/menu.png b/emulator/skins/HVGA/menu.png
new file mode 100644
index 0000000..e81d8ab
--- /dev/null
+++ b/emulator/skins/HVGA/menu.png
Binary files differ
diff --git a/emulator/skins/HVGA/power.png b/emulator/skins/HVGA/power.png
new file mode 100644
index 0000000..5894288
--- /dev/null
+++ b/emulator/skins/HVGA/power.png
Binary files differ
diff --git a/emulator/skins/HVGA/select.png b/emulator/skins/HVGA/select.png
new file mode 100644
index 0000000..803d493
--- /dev/null
+++ b/emulator/skins/HVGA/select.png
Binary files differ
diff --git a/emulator/skins/HVGA/send.png b/emulator/skins/HVGA/send.png
new file mode 100644
index 0000000..f547c88
--- /dev/null
+++ b/emulator/skins/HVGA/send.png
Binary files differ
diff --git a/emulator/skins/HVGA/spacebar.png b/emulator/skins/HVGA/spacebar.png
new file mode 100644
index 0000000..19fe604
--- /dev/null
+++ b/emulator/skins/HVGA/spacebar.png
Binary files differ
diff --git a/emulator/skins/HVGA/volume_down.png b/emulator/skins/HVGA/volume_down.png
new file mode 100644
index 0000000..f8a88de
--- /dev/null
+++ b/emulator/skins/HVGA/volume_down.png
Binary files differ
diff --git a/emulator/skins/HVGA/volume_up.png b/emulator/skins/HVGA/volume_up.png
new file mode 100644
index 0000000..940457f
--- /dev/null
+++ b/emulator/skins/HVGA/volume_up.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/arrow_down.png b/emulator/skins/QVGA-L/arrow_down.png
new file mode 100644
index 0000000..7398bae
--- /dev/null
+++ b/emulator/skins/QVGA-L/arrow_down.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/arrow_left.png b/emulator/skins/QVGA-L/arrow_left.png
new file mode 100644
index 0000000..f7e3c12
--- /dev/null
+++ b/emulator/skins/QVGA-L/arrow_left.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/arrow_right.png b/emulator/skins/QVGA-L/arrow_right.png
new file mode 100644
index 0000000..33fa169
--- /dev/null
+++ b/emulator/skins/QVGA-L/arrow_right.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/arrow_up.png b/emulator/skins/QVGA-L/arrow_up.png
new file mode 100644
index 0000000..f21105a
--- /dev/null
+++ b/emulator/skins/QVGA-L/arrow_up.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/back.png b/emulator/skins/QVGA-L/back.png
new file mode 100644
index 0000000..883b4ca
--- /dev/null
+++ b/emulator/skins/QVGA-L/back.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/background.png b/emulator/skins/QVGA-L/background.png
new file mode 100644
index 0000000..81832ec
--- /dev/null
+++ b/emulator/skins/QVGA-L/background.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/end.png b/emulator/skins/QVGA-L/end.png
new file mode 100644
index 0000000..7a6ae1c
--- /dev/null
+++ b/emulator/skins/QVGA-L/end.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/favorites.png b/emulator/skins/QVGA-L/favorites.png
new file mode 100644
index 0000000..ad85c5c
--- /dev/null
+++ b/emulator/skins/QVGA-L/favorites.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/home.png b/emulator/skins/QVGA-L/home.png
new file mode 100644
index 0000000..36f314e
--- /dev/null
+++ b/emulator/skins/QVGA-L/home.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/key.png b/emulator/skins/QVGA-L/key.png
new file mode 100644
index 0000000..3c17cec
--- /dev/null
+++ b/emulator/skins/QVGA-L/key.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/layout b/emulator/skins/QVGA-L/layout
new file mode 100644
index 0000000..fd86934
--- /dev/null
+++ b/emulator/skins/QVGA-L/layout
@@ -0,0 +1,275 @@
+display {
+	width  320
+	height 240
+	x 78
+	y 96
+}
+
+background {
+	image background.png
+	x 0
+	y 0
+}
+
+button {
+	soft-left {
+		image menu.png
+		x 136
+		y 378
+	}
+	home {
+		image home.png
+		x 312
+		y 372
+	}
+	back {
+		image back.png
+		x 137
+		y 420
+	}
+	dpad-up {
+		image arrow_up.png
+		x 190
+		y 364
+	}
+	dpad-down {
+		image arrow_down.png
+		x 190
+		y 421
+	}
+	dpad-left {
+		image arrow_left.png
+		x 181
+		y 372
+	}
+	dpad-right {
+		image arrow_right.png
+		x 257
+		y 372
+	}
+	dpad-center {
+		image select.png
+		x 216
+		y 394
+	}
+	phone-dial {
+		image send.png
+		x 76
+		y 394
+	}
+	phone-hangup {
+		image end.png
+		x 358
+		y 394
+	}
+	
+	q {
+	       image  key.png
+	       x  55
+	       y  480
+	}
+	w {
+	       image  key.png
+	       x 91
+	       y 480
+	}
+	e {
+	       image  key.png
+	       x 128
+	       y 480
+	}
+	r {
+	       image  key.png
+	       x 163
+	       y 480
+	}
+	t {
+	       image  key.png
+	       x 200
+	       y 480
+	}
+	y {
+	       image  key.png
+	       x 237
+	       y 480
+	}
+	u {
+	       image  key.png
+	       x 273
+	       y 480
+	}
+	i {
+	       image  key.png
+	       x 310
+	       y 480
+	}
+	o {
+	       image  key.png
+	       x 346
+	       y 480
+	}
+	p {
+	       image  key.png
+	       x 382
+	       y 480
+	}
+
+	a {
+	       image  key.png
+	       x  55
+	       y  530
+	}
+	s {
+	       image  key.png
+	       x 91
+	       y 530
+	}
+	d {
+	       image  key.png
+	       x 128
+	       y 530
+	}
+	f {
+	       image  key.png
+	       x 163
+	       y 530
+	}
+	g {
+	       image  key.png
+	       x 200
+	       y 530
+	}
+	h {
+	       image  key.png
+	       x 237
+	       y 530
+	}
+	j {
+	       image  key.png
+	       x 273
+	       y 530
+	}
+	k {
+	       image  key.png
+	       x 310
+	       y 530
+	}
+	l {
+	       image  key.png
+	       x 346
+	       y 530
+	}
+	DEL {
+	       image  key.png
+	       x 382
+	       y 530
+	}
+	
+	CAP {
+	       image  key.png
+	       x  55
+	       y  580
+	}
+	z {
+	       image  key.png
+	       x 91
+	       y 580
+	}
+	x {
+	       image  key.png
+	       x 128
+	       y 580
+	}
+	c {
+	       image  key.png
+	       x 163
+	       y 580
+	}
+	v {
+	       image  key.png
+	       x 200
+	       y 580
+	}
+	b {
+	       image  key.png
+	       x 237
+	       y 580
+	}
+	n {
+	       image  key.png
+	       x 273
+	       y 580
+	}
+	m {
+	       image  key.png
+	       x 310
+	       y 580
+	}
+	PERIOD {
+	       image  key.png
+	       x 346
+	       y 580
+	}
+	ENTER {
+	       image  key.png
+	       x 382
+	       y 580
+	}
+
+	ALT {
+	       image  key.png
+	       x  55
+	       y  630
+	}
+	SYM {
+	       image  key.png
+	       x 91
+	       y 630
+	}
+	AT {
+	       image  key.png
+	       x 128
+	       y 630
+	}
+	SPACE {
+	       image  spacebar.png
+	       x 165
+	       y 630
+	}
+	SLASH {
+	       image  key.png
+	       x 310
+	       y 630
+	}
+	COMMA {
+	       image  key.png
+	       x 346
+	       y 630
+	}
+	CAP2 {
+	       image  key.png
+	       x 382
+	       y 630
+	}
+	
+	power {
+		image power.png
+		x     4
+		y     38
+	}
+	volume-up {
+		image volume_up.png
+		x     420
+		y     165
+	}
+	volume-down {
+		image volume_down.png
+		x     420
+		y     218
+	}
+}
+
+network {
+    speed  full
+    delay  none
+}
diff --git a/emulator/skins/QVGA-L/menu.png b/emulator/skins/QVGA-L/menu.png
new file mode 100644
index 0000000..224b077
--- /dev/null
+++ b/emulator/skins/QVGA-L/menu.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/power.png b/emulator/skins/QVGA-L/power.png
new file mode 100644
index 0000000..7886a16
--- /dev/null
+++ b/emulator/skins/QVGA-L/power.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/select.png b/emulator/skins/QVGA-L/select.png
new file mode 100644
index 0000000..8691f53
--- /dev/null
+++ b/emulator/skins/QVGA-L/select.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/send.png b/emulator/skins/QVGA-L/send.png
new file mode 100644
index 0000000..8519ebd
--- /dev/null
+++ b/emulator/skins/QVGA-L/send.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/spacebar.png b/emulator/skins/QVGA-L/spacebar.png
new file mode 100644
index 0000000..c45a580
--- /dev/null
+++ b/emulator/skins/QVGA-L/spacebar.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/volume_down.png b/emulator/skins/QVGA-L/volume_down.png
new file mode 100644
index 0000000..09175b1
--- /dev/null
+++ b/emulator/skins/QVGA-L/volume_down.png
Binary files differ
diff --git a/emulator/skins/QVGA-L/volume_up.png b/emulator/skins/QVGA-L/volume_up.png
new file mode 100644
index 0000000..ab52c63
--- /dev/null
+++ b/emulator/skins/QVGA-L/volume_up.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/arrow_down.png b/emulator/skins/QVGA-P/arrow_down.png
new file mode 100644
index 0000000..7398bae
--- /dev/null
+++ b/emulator/skins/QVGA-P/arrow_down.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/arrow_left.png b/emulator/skins/QVGA-P/arrow_left.png
new file mode 100644
index 0000000..f7e3c12
--- /dev/null
+++ b/emulator/skins/QVGA-P/arrow_left.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/arrow_right.png b/emulator/skins/QVGA-P/arrow_right.png
new file mode 100644
index 0000000..33fa169
--- /dev/null
+++ b/emulator/skins/QVGA-P/arrow_right.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/arrow_up.png b/emulator/skins/QVGA-P/arrow_up.png
new file mode 100644
index 0000000..f21105a
--- /dev/null
+++ b/emulator/skins/QVGA-P/arrow_up.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/background.png b/emulator/skins/QVGA-P/background.png
new file mode 100644
index 0000000..39348c4
--- /dev/null
+++ b/emulator/skins/QVGA-P/background.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/button.png b/emulator/skins/QVGA-P/button.png
new file mode 100644
index 0000000..8519ebd
--- /dev/null
+++ b/emulator/skins/QVGA-P/button.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/key.png b/emulator/skins/QVGA-P/key.png
new file mode 100644
index 0000000..7a3f563
--- /dev/null
+++ b/emulator/skins/QVGA-P/key.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/layout b/emulator/skins/QVGA-P/layout
new file mode 100644
index 0000000..a9abb1b
--- /dev/null
+++ b/emulator/skins/QVGA-P/layout
@@ -0,0 +1,329 @@
+display {
+	width  240
+	height 320
+	x 50
+	y 83
+}
+
+background {
+	image background.png
+	x 0
+	y 0
+}
+
+button {
+	soft-left {
+		image button.png
+		x 148
+		y 418
+	}
+	home {
+		image button.png
+		x 94
+		y 418
+	}
+	back {
+		image button.png
+		x 202
+		y 418
+	}
+	dpad-up {
+		image arrow_up.png
+		x 122
+		y 475
+	}
+	dpad-down {
+		image arrow_down.png
+		x 122
+		y 534
+	}
+	dpad-left {
+		image arrow_left.png
+		x 113
+		y 483
+	}
+	dpad-right {
+		image arrow_right.png
+		x 189
+		y 483
+	}
+	dpad-center {
+		image select.png
+		x 148
+		y 506
+	}
+	phone-dial {
+		image button.png
+		x 40
+		y 418
+	}
+	phone-hangup {
+		image button.png
+		x 256
+		y 418
+	}
+	power {
+		image power.png
+		x     5
+		y     18
+	}
+	volume-up {
+		image volume_up.png
+		x     306
+		y     192
+	}
+	volume-down {
+		image volume_down.png
+		x     306
+		y     245
+	}
+	1 {
+	   image  key.png
+	   x  367
+	   y  242
+	}
+	2 {
+	   image  key.png
+	   x 404
+	   y 242
+	}
+	3 {
+	   image  key.png
+	   x 441
+	   y 242
+	}
+	4 {
+	   image  key.png
+	   x 478
+	   y 242
+	}
+	5 {
+	   image  key.png
+	   x 515
+	   y 242
+	}
+	6 {
+	   image  key.png
+	   x 552
+	   y 242
+	}
+	7 {
+	   image  key.png
+	   x 589
+	   y 242
+	}
+	8 {
+	   image  key.png
+	   x 626
+	   y 242
+	}
+	9 {
+	   image  key.png
+	   x 663
+	   y 242
+	}
+	0 {
+	   image  key.png
+	   x 700
+	   y 242
+	}
+
+	q {
+	   image  key.png
+	   x  367
+	   y  278
+	}
+	w {
+	   image  key.png
+	   x 404
+	   y 278
+	}
+	e {
+	   image  key.png
+	   x 441
+	   y 278
+	}
+	r {
+	   image  key.png
+	   x 478
+	   y 278
+	}
+	t {
+	   image  key.png
+	   x 515
+	   y 278
+	}
+	y {
+	   image  key.png
+	   x 552
+	   y 278
+	}
+	u {
+	   image  key.png
+	   x 589
+	   y 278
+	}
+	i {
+	   image  key.png
+	   x 626
+	   y 278
+	}
+	o {
+	   image  key.png
+	   x 663
+	   y 278
+	}
+	p {
+	   image  key.png
+	   x 700
+	   y 278
+	}
+
+	a {
+	   image  key.png
+	   x  367
+	   y  314
+	}
+	s {
+	   image  key.png
+	   x 404
+	   y 314
+	}
+	d {
+	   image  key.png
+	   x 441
+	   y 314
+	}
+	f {
+	   image  key.png
+	   x 478
+	   y 314
+	}
+	g {
+	   image  key.png
+	   x 515
+	   y 314
+	}
+	h {
+	   image  key.png
+	   x 552
+	   y 314
+	}
+	j {
+	   image  key.png
+	   x 589
+	   y 314
+	}
+	k {
+	   image  key.png
+	   x 626
+	   y 314
+	}
+	l {
+	   image  key.png
+	   x 663
+	   y 314
+	}
+	DEL {
+	   image  key.png
+	   x 700
+	   y 314
+	}
+
+	CAP {
+	   image  key.png
+	   x  367
+	   y  350
+	}
+	z {
+	   image  key.png
+	   x 404
+	   y 350
+	}
+	x {
+	   image  key.png
+	   x 441
+	   y 350
+	}
+	c {
+	   image  key.png
+	   x 478
+	   y 350
+	}
+	v {
+	   image  key.png
+	   x 515
+	   y 350
+	}
+	b {
+	   image  key.png
+	   x 552
+	   y 350
+	}
+	n {
+	   image  key.png
+	   x 589
+	   y 350
+	}
+	m {
+	   image  key.png
+	   x 626
+	   y 350
+	}
+	PERIOD {
+	   image  key.png
+	   x 663
+	   y 350
+	}
+	ENTER {
+	   image  key.png
+	   x 700
+	   y 350
+	}
+
+	ALT {
+	   image  key.png
+	   x  367
+	   y  386
+	}
+	SYM {
+	   image  key.png
+	   x 404
+	   y 386
+	}
+	AT {
+	   image  key.png
+	   x 441
+	   y 386
+	}
+	SPACE {
+	   image  spacebar.png
+	   x 478
+	   y 386
+	}
+	SLASH {
+	   image  key.png
+	   x 626
+	   y 386
+	}
+	COMMA {
+	   image  key.png
+	   x 663
+	   y 386
+	}
+	ALT2 {
+	   image  key.png
+	   x 408
+	   y 855
+	}
+
+}
+
+network {
+    speed  full
+    delay  none
+}
+
+keyboard {
+    charmap qwerty2
+}
diff --git a/emulator/skins/QVGA-P/power.png b/emulator/skins/QVGA-P/power.png
new file mode 100644
index 0000000..0c04ced
--- /dev/null
+++ b/emulator/skins/QVGA-P/power.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/select.png b/emulator/skins/QVGA-P/select.png
new file mode 100644
index 0000000..8691f53
--- /dev/null
+++ b/emulator/skins/QVGA-P/select.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/spacebar.png b/emulator/skins/QVGA-P/spacebar.png
new file mode 100644
index 0000000..19fe604
--- /dev/null
+++ b/emulator/skins/QVGA-P/spacebar.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/volume_down.png b/emulator/skins/QVGA-P/volume_down.png
new file mode 100644
index 0000000..09175b1
--- /dev/null
+++ b/emulator/skins/QVGA-P/volume_down.png
Binary files differ
diff --git a/emulator/skins/QVGA-P/volume_up.png b/emulator/skins/QVGA-P/volume_up.png
new file mode 100644
index 0000000..ab52c63
--- /dev/null
+++ b/emulator/skins/QVGA-P/volume_up.png
Binary files differ