Merge memory checking from sandbox

Change-id: Ibce845d0
diff --git a/.gitignore b/.gitignore
index c4f7346..e31aaec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
 images/android_icon.o
 objs/*
+*.*~
+distrib
+
diff --git a/Makefile.android b/Makefile.android
index 02518e3..35e2fcf 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -16,7 +16,7 @@
     MY_OPTIM := -O0 -g
 endif
 
-MY_CFLAGS := $(CONFIG_INCLUDES) $(MY_OPTIM)
+MY_CFLAGS := $(CONFIG_INCLUDES) $(MY_OPTIM) -DCONFIG_MEMCHECK
 
 # Overwrite configuration for debug builds.
 #
@@ -193,6 +193,71 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 ##############################################################################
+# build the ELF/DWARF stuff
+# This library is used by emulator's memory checker to extract debug information
+# from the symbol files when reporting memory allocation violations. In
+# particular, this library is used to extract routine name and source file
+# location for the code address where violation has been detected.
+#
+include $(CLEAR_VARS)
+
+LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
+LOCAL_CC                        := $(MY_CC)
+LOCAL_MODULE                    := emulator-elff
+LOCAL_CPP_EXTENSION             := .cc
+
+ELFF_CFLAGS    := -I$(LOCAL_PATH)/elff
+
+LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/target-arm -I$(LOCAL_PATH)/fpu $(ELFF_CFLAGS)
+LOCAL_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
+
+ELFF_SOURCES := \
+    dwarf_cu.cc \
+    dwarf_die.cc \
+    dwarf_utils.cc \
+    elf_alloc.cc \
+    elf_file.cc \
+    elf_mapped_section.cc \
+    elff_api.cc \
+
+LOCAL_SRC_FILES += $(ELFF_SOURCES:%=elff/%)
+ELFF_LDLIBS := -lstdc++
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+##############################################################################
+# build the memory access checking support
+# Memory access checker uses information collected by instrumented code in
+# libc.so in order to keep track of memory blocks allocated from heap. Memory
+# checker then uses this information to make sure that every access to allocated
+# memory is within allocated block. This information also allows detecting
+# memory leaks and attempts to free/realloc invalid pointers.
+#
+include $(CLEAR_VARS)
+
+LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
+LOCAL_CC                        := $(MY_CC)
+LOCAL_MODULE                    := emulator-memcheck
+
+MCHK_CFLAGS    := -I$(LOCAL_PATH)/memcheck -I$(LOCAL_PATH)/elff
+
+LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/target-arm -I$(LOCAL_PATH)/fpu $(MCHK_CFLAGS)
+LOCAL_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
+
+MCHK_SOURCES := \
+    memcheck.c \
+    memcheck_proc_management.c \
+    memcheck_malloc_map.c \
+    memcheck_mmrange_map.c \
+    memcheck_util.c \
+
+LOCAL_SRC_FILES += $(MCHK_SOURCES:%=memcheck/%)
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+##############################################################################
 # build the ARM-specific emulation engine sources
 #
 include $(CLEAR_VARS)
@@ -231,6 +296,7 @@
                    trace.c \
                    varint.c \
                    dcache.c \
+                   softmmu_outside_jit.c \
 
 LOCAL_SRC_FILES += fpu/softfloat.c
 
@@ -360,7 +426,8 @@
 LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
 LOCAL_CC                        := $(MY_CC)
 LOCAL_MODULE                    := emulator
-LOCAL_STATIC_LIBRARIES          := emulator-hw emulator-arm emulator-tcg
+LOCAL_STATIC_LIBRARIES          := emulator-memcheck emulator-hw emulator-arm emulator-tcg
+LOCAL_STATIC_LIBRARIES          += emulator-elff
 LOCAL_LDLIBS                    := $(MY_LDLIBS)
 
 # don't remove the -fno-strict-aliasing, or you'll break things
@@ -593,6 +660,10 @@
 LOCAL_STATIC_LIBRARIES += libSDL libSDLmain
 LOCAL_STATIC_LIBRARIES += libSDL libSDLmain
 
+# add ELFF-specific flags
+#
+LOCAL_LDLIBS += $(ELFF_LDLIBS)
+
 # on Windows, link the icon file as well into the executable
 # unfortunately, our build system doesn't help us much, so we need
 # to use some weird pathnames to make this work...
@@ -689,6 +760,7 @@
 LOCAL_CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
 LOCAL_LDLIBS += -lm -lpthread
 
+
 ifeq ($(HOST_OS),windows)
     LOCAL_LDLIBS += -lwinmm -lws2_32 -liphlpapi
 endif
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
index fabac5c..20d308f 100644
--- a/android/cmdline-options.h
+++ b/android/cmdline-options.h
@@ -140,6 +140,9 @@
 OPT_PARAM( nand_limits, "<nlimits>", "enforce NAND/Flash read/write thresholds" )
 #endif
 
+#ifdef CONFIG_MEMCHECK
+OPT_PARAM( memcheck, "<flags>", "enable memory access checking" )
+#endif  // CONFIG_MEMCHECK
 
 #undef CFG_FLAG
 #undef CFG_PARAM
diff --git a/android/help.c b/android/help.c
index cbca332..fe724a6 100644
--- a/android/help.c
+++ b/android/help.c
@@ -78,7 +78,7 @@
     "  Before using the SDK, you need to create an Android Virtual Device (AVD)\n"
     "  (see -help-virtual-device for details). Each AVD is created in reference\n"
     "  to a given SDK platform *or* add-on, and will search the corresponding\n"
-    "  directories for system image files, in the following order:\n\n" 
+    "  directories for system image files, in the following order:\n\n"
 
     "    - in the AVD's content directory.\n"
     "    - in the AVD's SDK add-on directory, if any.\n"
@@ -885,6 +885,45 @@
     );
 }
 
+#ifdef CONFIG_MEMCHECK
+static void
+help_memcheck(stralloc_t*  out)
+{
+    PRINTF(
+    "  use '-memcheck <flags>' to start the emulator with memory access checking\n"
+    "  support.\n\n"
+
+    "  <flags> enables, or disables memory access checking, and also controls\n"
+    "  what events are going to be logged by the memory access checker.\n"
+    "  <flags> can be one of the following:\n"
+    "  1 - Enables memory access checking with default logging (\"LIRW\"), or\n"
+    "  0 - Disables memory access checking, or\n"
+    "  A combination (in no particular order) of the following:\n"
+    "     L - Logs memory leaks on process exit.\n"
+    "     I - Logs attempts to use invalid pointers in free, or realloc routines.\n"
+    "     R - Logs memory access violation on read operations.\n"
+    "     W - Logs memory access violation on write operations.\n"
+    "     N - Logs new process ID allocation.\n"
+    "     F - Logs guest's process forking.\n"
+    "     S - Logs guest's process starting.\n"
+    "     E - Logs guest's process exiting.\n"
+    "     C - Logs guest's thread creation (clone).\n"
+    "     B - Logs libc.so initialization in the guest system.\n"
+    "     M - Logs module mapping and unmapping in the guest system.\n"
+    "     A - Logs all emulator events. Equala to \"LIRWFSECANBM\" combination.\n"
+    "     e - Logs error messages, received from the guest system.\n"
+    "     d - Logs debug messages, received from the guest system.\n"
+    "     i - Logs information messages, received from the guest system.\n"
+    "     a - Logs all messages, received from the guest system.\n"
+    "         This is equal to \"edi\" combination.\n\n"
+
+    "  note that execution might be significantly slower when enabling memory access\n"
+    "  checking, this is a necessary requirement of the operations being performed\n"
+    "  to analyze memory allocations and memory access.\n\n"
+    );
+}
+#endif  // CONFIG_MEMCHECK
+
 static void
 help_show_kernel(stralloc_t*  out)
 {
@@ -1416,7 +1455,7 @@
 }
 
 
-extern void  
+extern void
 android_help_list_options( stralloc_t*  out )
 {
     const OptionHelp*  oo;
diff --git a/android/main.c b/android/main.c
index de048b9..309adf6 100644
--- a/android/main.c
+++ b/android/main.c
@@ -63,6 +63,9 @@
 #include "android/cmdline-option.h"
 #include "android/help.h"
 #include "hw/goldfish_nand.h"
+#ifdef CONFIG_MEMCHECK
+#include "memcheck/memcheck.h"
+#endif  // CONFIG_MEMCHECK
 
 #include "android/globals.h"
 #include "tcpdump.h"
@@ -1054,7 +1057,7 @@
             if(x && isdigit(x[1])) {
                 int width = atoi(name);
                 int height = atoi(x + 1);
-                sprintf(tmp,"display {\n  width %d\n  height %d\n}\n", 
+                sprintf(tmp,"display {\n  width %d\n  height %d\n}\n",
                         width, height);
                 aconfig_load(root, strdup(tmp));
                 path = ":";
@@ -1075,7 +1078,7 @@
             path = tmp;
             goto found_a_skin;
         } else {
-            dwarning("could not load skin file '%s', using built-in one\n", 
+            dwarning("could not load skin file '%s', using built-in one\n",
                      tmp);
         }
     }
@@ -1215,7 +1218,7 @@
     }
 
     if (android_modem)
-        amodem_set_data_network_type( android_modem, 
+        amodem_set_data_network_type( android_modem,
                                       android_parse_network_type(speed) );
     return 0;
 }
@@ -1739,8 +1742,8 @@
 }
 
 static void
-_forceAvdImagePath( AvdImageType  imageType, 
-                   const char*   path, 
+_forceAvdImagePath( AvdImageType  imageType,
+                   const char*   path,
                    const char*   description,
                    int           required )
 {
@@ -1993,7 +1996,7 @@
      * Android build system, we'll need to perform some auto-detection
      * magic :-)
      */
-    if (opts->avd == NULL && !android_build_out) 
+    if (opts->avd == NULL && !android_build_out)
     {
         char   dataDirIsSystem = 0;
 
@@ -2297,6 +2300,12 @@
         opts->trace = tracePath;
     }
 
+#ifdef CONFIG_MEMCHECK
+    if (opts->memcheck) {
+        memcheck_init(opts->memcheck);
+    }
+#endif  // CONFIG_MEMCHECK
+
     if (opts->tcpdump) {
         if (qemu_tcpdump_start(opts->tcpdump) < 0) {
             dwarning( "could not start packet capture: %s", strerror(errno));
@@ -2705,6 +2714,14 @@
             p = bufprint(p, end, " android.tracing=1");
         }
 
+#ifdef CONFIG_MEMCHECK
+        if (opts->memcheck) {
+            /* This will set ro.kernel.memcheck system property
+             * to memcheck's tracing flags. */
+            p = bufprint(p, end, " memcheck=%s", opts->memcheck);
+        }
+#endif  // CONFIG_MEMCHECK
+
         if (!opts->no_jni) {
             p = bufprint(p, end, " android.checkjni=1");
         }
diff --git a/android/utils/debug.h b/android/utils/debug.h
index d6bd3f9..06b9baf 100644
--- a/android/utils/debug.h
+++ b/android/utils/debug.h
@@ -34,6 +34,7 @@
     _VERBOSE_TAG(hw_control,   "emulated power/flashlight/led/vibrator") \
     _VERBOSE_TAG(avd_config,   "android virtual device configuration") \
     _VERBOSE_TAG(sensors,      "emulated sensors") \
+    _VERBOSE_TAG(memcheck,     "memory checker") \
 
 #define  _VERBOSE_TAG(x,y)  VERBOSE_##x,
 typedef enum {
diff --git a/android/utils/path.h b/android/utils/path.h
index e822834..e15e6ed 100644
--- a/android/utils/path.h
+++ b/android/utils/path.h
@@ -28,8 +28,10 @@
 /* define  PATH_SEP as a string containing the directory separateor */
 #ifdef _WIN32
 #  define  PATH_SEP   "\\"
+#  define  PATH_SEP_C '\\'
 #else
 #  define  PATH_SEP   "/"
+#  define  PATH_SEP_C '/'
 #endif
 
 /* get MAX_PATH, note that PATH_MAX is set to 260 on Windows for
@@ -65,7 +67,7 @@
 /* try to make a directory */
 extern APosixStatus   path_mkdir( const char*  path, int  mode );
 
-/* ensure that a given directory exists, create it if not, 
+/* ensure that a given directory exists, create it if not,
    0 on success, -1 on error */
 extern APosixStatus   path_mkdir_if_needed( const char*  path, int  mode );
 
diff --git a/docs/ANDROID-ELFF.TXT b/docs/ANDROID-ELFF.TXT
new file mode 100644
index 0000000..afb3015
--- /dev/null
+++ b/docs/ANDROID-ELFF.TXT
@@ -0,0 +1,23 @@
+ANDROID ELFF LIBRARY
+
+The docs/ANDROID-ELFF.TXT document contains notes about the ELFF library used
+by the emulator to extract debugging information from symbol files of the
+emulated system.
+
+The ELFF library has been introduced to provide the emulator's memory checker
+subsystem with information about routine name, source file name and location
+when a memory access violation detected at runtime. This requires parsing symbol
+files corresponding to the libraries of the emulated system, in order to extract
+relevant information from them.
+
+Due to lack of windows support on available open source projects, this is a
+full new implementation of an ELF/DWARF parser.
+
+The library exposes a simple API that at this point allows:
+- Extract information about routine, containing given PC address in the emulated
+  system. Routine information, collected by the library includes:
+  * Routine name
+  * Source file name and line corresponded to the given emulated PC.
+  * If routine happens to be inlined, library traces inclusion up to the first
+    routine that is not inlined, providing names and source file location
+    information for all inlined routines in that chain.
diff --git a/docs/ANDROID-MEMCHECK.TXT b/docs/ANDROID-MEMCHECK.TXT
new file mode 100644
index 0000000..0c5e716
--- /dev/null
+++ b/docs/ANDROID-MEMCHECK.TXT
@@ -0,0 +1,57 @@
+ANDROID MEMORY CHECKER COMPONENT
+
+The docs/ANDROID-MEMCHECK.TXT document contains description of a memory checker
+implemented in the emulator
+
+The memory checker is intended to catch simple memory access violations in the
+emulated system, including:
+- Memory leaks
+- Attempts to free / reallocate invalid pointers (including pointers that have
+  already been freed, or reallocated).
+- Attempts to read from / write to areas outside of allocated blocks.
+
+To provide this functionality, the memory checker works in conjunction with
+an instrumented version of libc.so library used by the emulated system. Both,
+emulator's memory checking, and libc's instrumentation are turned on by the
+-memcheck command-line option. If this argument is omitted, libc.so will run in
+the regular, not instrumented mode, and the emulator will not perform any
+actions related to the memory checking.
+
+The way emulator and instrumented libc.so work together is as such:
+libc.so hooks up every memory allocation call (malloc, free, calloc, realloc,
+and memalign). For each such call, libc sends a notification message to the
+emulator, providing an allocation descriptor that contains information about
+allocation block and operation that is being performed on this block. Emulator
+and libc use a "magic page" that is set up in such a way that every write to
+that page on the emulated system produces some sort of event in the emulator,
+allowing emulator to receive data that emulated system has written to the "magic
+page". For more info on that, see hw/goldfish-trace.c
+
+In response to events, received from libc.so, emulator keep tracks of all blocks
+that have been allocated from the heap on emulated system. Block descriptors are
+kept in a per-process basis, so when a process exits, emulator can list all the
+leaked blocks the process left behind.
+
+When a free, or realloc operation is performed on the emulated system, emulator
+can verify that the pointer passed to free/realloc matches the address of a
+block recorded in the current process' descriptors table. This way emulator can
+detect and report attempts to free/reallocate invalid pointers.
+
+To detect read/write violations, emulator uses prefix and suffix guarding areas
+that were added to the allocated blocks by the instrumented libc. To watch for
+access violations, emulator instruments ld_/st_mmu routines to verify that
+accessed memory doesn't belong to a guarding area of a block allocated in
+context of the current process.
+
+There are some tricky things like:
+- invalidating every page containing allocated blocks every time anything has
+  been read, or written to that page, so we can be sure that we don't miss AV
+  on condition that page has been cached and ld_/st_mmu is omitted when
+  accessing memory in that page.
+- Keeping track of each thread calling stack, so when access violation is
+  reported, we can pinpoint violation to precise location in the source code.
+- etc.
+
+All the code related to memory checking is guarded in emulator's code by
+CONFIG_MEMCHECK macro, making it easy to spot changes related to it in the
+sources.
diff --git a/elff/dwarf.h b/elff/dwarf.h
new file mode 100644
index 0000000..31ef714
--- /dev/null
+++ b/elff/dwarf.h
@@ -0,0 +1,1055 @@
+/*
+  Copyright (C) 2000,2001,2003,2004,2005,2006 Silicon Graphics, Inc.  All Rights Reserved.
+  Portions Copyright 2002,2007 Sun Microsystems, Inc. All rights reserved.
+  Portions Copyright 2007-2009 David Anderson. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2.1 of the GNU Lesser General Public License
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it would be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+  Further, this software is distributed without any warranty that it is
+  free of the rightful claim of any third person regarding infringement
+  or the like.  Any license provided herein, whether implied or
+  otherwise, applies only to this software file.  Patent licenses, if
+  any, provided herein do not apply to combinations of this program with
+  other software, or any other product whatsoever.
+
+  You should have received a copy of the GNU Lesser General Public 
+  License along with this program; if not, write the Free Software 
+  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, 
+  USA.
+
+  Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
+  Mountain View, CA 94043, or:
+
+  http://www.sgi.com
+
+  For further information regarding this notice, see:
+
+  http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+#ifndef __DWARF_H
+#define __DWARF_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+        dwarf.h   DWARF  debugging information values
+        $Revision: 1.41 $    $Date: 2006/04/17 00:09:56 $
+
+        The comment "DWARF3" appears where there are
+        new entries from DWARF3 as of 2004, "DWARF3f"
+        where there are new entries as of the November 2005
+        public review document and other comments apply
+        where extension entries appear.
+
+        Extensions part of DWARF4 are marked DWARF4.
+
+        A few extension names have omitted the 'vendor id'
+        (See chapter 7, "Vendor Extensibility"). Please
+        always use a 'vendor id' string in extension names.
+
+        Vendors should use a vendor string in names and
+        whereever possible avoid duplicating values used by
+        other vendor extensions
+
+*/
+
+
+#define DW_TAG_array_type               0x01
+#define DW_TAG_class_type               0x02
+#define DW_TAG_entry_point              0x03
+#define DW_TAG_enumeration_type         0x04
+#define DW_TAG_formal_parameter         0x05
+#define DW_TAG_imported_declaration     0x08
+#define DW_TAG_label                    0x0a
+#define DW_TAG_lexical_block            0x0b
+#define DW_TAG_member                   0x0d
+#define DW_TAG_pointer_type             0x0f
+#define DW_TAG_reference_type           0x10
+#define DW_TAG_compile_unit             0x11
+#define DW_TAG_string_type              0x12
+#define DW_TAG_structure_type           0x13
+#define DW_TAG_subroutine_type          0x15
+#define DW_TAG_typedef                  0x16
+#define DW_TAG_union_type               0x17
+#define DW_TAG_unspecified_parameters   0x18
+#define DW_TAG_variant                  0x19
+#define DW_TAG_common_block             0x1a
+#define DW_TAG_common_inclusion         0x1b
+#define DW_TAG_inheritance              0x1c
+#define DW_TAG_inlined_subroutine       0x1d
+#define DW_TAG_module                   0x1e
+#define DW_TAG_ptr_to_member_type       0x1f
+#define DW_TAG_set_type                 0x20
+#define DW_TAG_subrange_type            0x21
+#define DW_TAG_with_stmt                0x22
+#define DW_TAG_access_declaration       0x23
+#define DW_TAG_base_type                0x24
+#define DW_TAG_catch_block              0x25
+#define DW_TAG_const_type               0x26
+#define DW_TAG_constant                 0x27
+#define DW_TAG_enumerator               0x28
+#define DW_TAG_file_type                0x29
+#define DW_TAG_friend                   0x2a
+#define DW_TAG_namelist                 0x2b
+        /* Early releases of this header had the following
+           misspelled with a trailing 's' */
+#define DW_TAG_namelist_item            0x2c /* DWARF3/2 spelling */
+#define DW_TAG_namelist_items           0x2c /* SGI misspelling/typo */
+#define DW_TAG_packed_type              0x2d
+#define DW_TAG_subprogram               0x2e
+        /* The DWARF2 document had two spellings of the following
+           two TAGs, DWARF3 specifies the longer spelling. */
+#define DW_TAG_template_type_parameter  0x2f /* DWARF3/2 spelling*/
+#define DW_TAG_template_type_param      0x2f /* DWARF2   spelling*/
+#define DW_TAG_template_value_parameter 0x30 /* DWARF3/2 spelling*/
+#define DW_TAG_template_value_param     0x30 /* DWARF2   spelling*/
+#define DW_TAG_thrown_type              0x31
+#define DW_TAG_try_block                0x32
+#define DW_TAG_variant_part             0x33
+#define DW_TAG_variable                 0x34
+#define DW_TAG_volatile_type            0x35
+#define DW_TAG_dwarf_procedure          0x36  /* DWARF3 */
+#define DW_TAG_restrict_type            0x37  /* DWARF3 */
+#define DW_TAG_interface_type           0x38  /* DWARF3 */
+#define DW_TAG_namespace                0x39  /* DWARF3 */
+#define DW_TAG_imported_module          0x3a  /* DWARF3 */
+#define DW_TAG_unspecified_type         0x3b  /* DWARF3 */
+#define DW_TAG_partial_unit             0x3c  /* DWARF3 */
+#define DW_TAG_imported_unit            0x3d  /* DWARF3 */
+        /* Do not use DW_TAG_mutable_type */
+#define DW_TAG_mutable_type 0x3e /* Withdrawn from DWARF3 by DWARF3f. */
+#define DW_TAG_condition                0x3f  /* DWARF3f */
+#define DW_TAG_shared_type              0x40  /* DWARF3f */
+#define DW_TAG_type_unit                0x41  /* DWARF4 */
+#define DW_TAG_rvalue_reference_type    0x42  /* DWARF4 */
+#define DW_TAG_template_alias           0x43  /* DWARF4 */
+#define DW_TAG_lo_user                  0x4080
+
+#define DW_TAG_MIPS_loop                0x4081
+
+/* HP extensions: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz  */
+#define DW_TAG_HP_array_descriptor      0x4090 /* HP */
+
+/* GNU extensions.  The first 3 missing the GNU_. */
+#define DW_TAG_format_label             0x4101 /* GNU. Fortran. */
+#define DW_TAG_function_template        0x4102 /* GNU. For C++ */
+#define DW_TAG_class_template           0x4103 /* GNU. For C++ */
+#define DW_TAG_GNU_BINCL                0x4104 /* GNU */
+#define DW_TAG_GNU_EINCL                0x4105 /* GNU */
+
+/* ALTIUM extensions */
+    /* DSP-C/Starcore __circ qualifier */
+#define DW_TAG_ALTIUM_circ_type         0x5101 /* ALTIUM */
+    /* Starcore __mwa_circ qualifier */ 
+#define DW_TAG_ALTIUM_mwa_circ_type     0x5102 /* ALTIUM */
+    /* Starcore __rev_carry qualifier */
+#define DW_TAG_ALTIUM_rev_carry_type    0x5103 /* ALTIUM */
+    /* M16 __rom qualifier */
+#define DW_TAG_ALTIUM_rom               0x5111 /* ALTIUM */
+
+/* The following 3 are extensions to support UPC */
+#define DW_TAG_upc_shared_type          0x8765 /* UPC */
+#define DW_TAG_upc_strict_type          0x8766 /* UPC */
+#define DW_TAG_upc_relaxed_type         0x8767 /* UPC */
+
+/* PGI (STMicroelectronics) extensions. */
+#define DW_TAG_PGI_kanji_type           0xa000 /* PGI */
+#define DW_TAG_PGI_interface_block      0xa020 /* PGI */
+/* The following are SUN extensions */
+#define DW_TAG_SUN_function_template    0x4201 /* SUN */
+#define DW_TAG_SUN_class_template       0x4202 /* SUN */
+#define DW_TAG_SUN_struct_template      0x4203 /* SUN */
+#define DW_TAG_SUN_union_template       0x4204 /* SUN */
+#define DW_TAG_SUN_indirect_inheritance 0x4205 /* SUN */
+#define DW_TAG_SUN_codeflags            0x4206 /* SUN */
+#define DW_TAG_SUN_memop_info           0x4207 /* SUN */
+#define DW_TAG_SUN_omp_child_func       0x4208 /* SUN */
+#define DW_TAG_SUN_rtti_descriptor      0x4209 /* SUN */
+#define DW_TAG_SUN_dtor_info            0x420a /* SUN */
+#define DW_TAG_SUN_dtor                 0x420b /* SUN */
+#define DW_TAG_SUN_f90_interface        0x420c /* SUN */
+#define DW_TAG_SUN_fortran_vax_structure 0x420d /* SUN */
+#define DW_TAG_SUN_hi                   0x42ff /* SUN */
+    
+
+#define DW_TAG_hi_user                  0xffff
+
+#define DW_children_no                  0
+#define DW_children_yes                 1
+
+
+
+#define DW_FORM_addr                    0x01
+#define DW_FORM_block2                  0x03
+#define DW_FORM_block4                  0x04
+#define DW_FORM_data2                   0x05
+#define DW_FORM_data4                   0x06
+#define DW_FORM_data8                   0x07
+#define DW_FORM_string                  0x08
+#define DW_FORM_block                   0x09
+#define DW_FORM_block1                  0x0a
+#define DW_FORM_data1                   0x0b
+#define DW_FORM_flag                    0x0c
+#define DW_FORM_sdata                   0x0d
+#define DW_FORM_strp                    0x0e
+#define DW_FORM_udata                   0x0f
+#define DW_FORM_ref_addr                0x10
+#define DW_FORM_ref1                    0x11
+#define DW_FORM_ref2                    0x12
+#define DW_FORM_ref4                    0x13
+#define DW_FORM_ref8                    0x14
+#define DW_FORM_ref_udata               0x15
+#define DW_FORM_indirect                0x16
+#define DW_FORM_sec_offset              0x17 /* DWARF4 */
+#define DW_FORM_exprloc                 0x18 /* DWARF4 */
+#define DW_FORM_flag_present            0x19 /* DWARF4 */
+#define DW_FORM_ref_sig8                0x20 /* DWARF4 */
+
+#define DW_AT_sibling                           0x01
+#define DW_AT_location                          0x02
+#define DW_AT_name                              0x03
+#define DW_AT_ordering                          0x09
+#define DW_AT_subscr_data                       0x0a
+#define DW_AT_byte_size                         0x0b
+#define DW_AT_bit_offset                        0x0c
+#define DW_AT_bit_size                          0x0d
+#define DW_AT_element_list                      0x0f
+#define DW_AT_stmt_list                         0x10
+#define DW_AT_low_pc                            0x11
+#define DW_AT_high_pc                           0x12
+#define DW_AT_language                          0x13
+#define DW_AT_member                            0x14
+#define DW_AT_discr                             0x15
+#define DW_AT_discr_value                       0x16
+#define DW_AT_visibility                        0x17
+#define DW_AT_import                            0x18
+#define DW_AT_string_length                     0x19
+#define DW_AT_common_reference                  0x1a
+#define DW_AT_comp_dir                          0x1b
+#define DW_AT_const_value                       0x1c
+#define DW_AT_containing_type                   0x1d
+#define DW_AT_default_value                     0x1e
+#define DW_AT_inline                            0x20
+#define DW_AT_is_optional                       0x21
+#define DW_AT_lower_bound                       0x22
+#define DW_AT_producer                          0x25
+#define DW_AT_prototyped                        0x27
+#define DW_AT_return_addr                       0x2a
+#define DW_AT_start_scope                       0x2c
+#define DW_AT_bit_stride                        0x2e /* DWARF3 name */
+#define DW_AT_stride_size                       0x2e /* DWARF2 name */
+#define DW_AT_upper_bound                       0x2f
+#define DW_AT_abstract_origin                   0x31
+#define DW_AT_accessibility                     0x32
+#define DW_AT_address_class                     0x33
+#define DW_AT_artificial                        0x34
+#define DW_AT_base_types                        0x35
+#define DW_AT_calling_convention                0x36
+#define DW_AT_count                             0x37
+#define DW_AT_data_member_location              0x38
+#define DW_AT_decl_column                       0x39
+#define DW_AT_decl_file                         0x3a
+#define DW_AT_decl_line                         0x3b
+#define DW_AT_declaration                       0x3c
+#define DW_AT_discr_list                        0x3d
+#define DW_AT_encoding                          0x3e
+#define DW_AT_external                          0x3f
+#define DW_AT_frame_base                        0x40
+#define DW_AT_friend                            0x41
+#define DW_AT_identifier_case                   0x42
+#define DW_AT_macro_info                        0x43
+#define DW_AT_namelist_item                     0x44
+#define DW_AT_priority                          0x45
+#define DW_AT_segment                           0x46
+#define DW_AT_specification                     0x47
+#define DW_AT_static_link                       0x48
+#define DW_AT_type                              0x49
+#define DW_AT_use_location                      0x4a
+#define DW_AT_variable_parameter                0x4b
+#define DW_AT_virtuality                        0x4c
+#define DW_AT_vtable_elem_location              0x4d
+#define DW_AT_allocated                         0x4e /* DWARF3 */
+#define DW_AT_associated                        0x4f /* DWARF3 */
+#define DW_AT_data_location                     0x50 /* DWARF3 */
+#define DW_AT_byte_stride                       0x51 /* DWARF3f */
+#define DW_AT_stride                            0x51 /* DWARF3 (do not use) */
+#define DW_AT_entry_pc                          0x52 /* DWARF3 */
+#define DW_AT_use_UTF8                          0x53 /* DWARF3 */
+#define DW_AT_extension                         0x54 /* DWARF3 */
+#define DW_AT_ranges                            0x55 /* DWARF3 */
+#define DW_AT_trampoline                        0x56 /* DWARF3 */
+#define DW_AT_call_column                       0x57 /* DWARF3 */
+#define DW_AT_call_file                         0x58 /* DWARF3 */
+#define DW_AT_call_line                         0x59 /* DWARF3 */
+#define DW_AT_description                       0x5a /* DWARF3 */
+#define DW_AT_binary_scale                      0x5b /* DWARF3f */
+#define DW_AT_decimal_scale                     0x5c /* DWARF3f */
+#define DW_AT_small                             0x5d /* DWARF3f */
+#define DW_AT_decimal_sign                      0x5e /* DWARF3f */
+#define DW_AT_digit_count                       0x5f /* DWARF3f */
+#define DW_AT_picture_string                    0x60 /* DWARF3f */
+#define DW_AT_mutable                           0x61 /* DWARF3f */
+#define DW_AT_threads_scaled                    0x62 /* DWARF3f */
+#define DW_AT_explicit                          0x63 /* DWARF3f */
+#define DW_AT_object_pointer                    0x64 /* DWARF3f */
+#define DW_AT_endianity                         0x65 /* DWARF3f */
+#define DW_AT_elemental                         0x66 /* DWARF3f */
+#define DW_AT_pure                              0x67 /* DWARF3f */
+#define DW_AT_recursive                         0x68 /* DWARF3f */
+#define DW_AT_signature                         0x69 /* DWARF4 */
+#define DW_AT_main_subprogram                   0x6a /* DWARF4 */
+#define DW_AT_data_bit_offset                   0x6b /* DWARF4 */
+#define DW_AT_const_expr                        0x6c /* DWARF4 */
+#define DW_AT_enum_class                        0x6d /* DWARF4 */
+#define DW_AT_linkage_name                      0x6e /* DWARF4 */
+
+/* In extensions, we attempt to include the vendor extension
+   in the name even when the vendor leaves it out. */
+
+/* HP extensions. */
+#define DW_AT_HP_block_index                    0x2000  /* HP */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_AT_lo_user                           0x2000
+
+#define DW_AT_MIPS_fde                          0x2001 /* MIPS/SGI */
+#define DW_AT_MIPS_loop_begin                   0x2002 /* MIPS/SGI */
+#define DW_AT_MIPS_tail_loop_begin              0x2003 /* MIPS/SGI */
+#define DW_AT_MIPS_epilog_begin                 0x2004 /* MIPS/SGI */
+#define DW_AT_MIPS_loop_unroll_factor           0x2005 /* MIPS/SGI */
+#define DW_AT_MIPS_software_pipeline_depth      0x2006 /* MIPS/SGI */
+#define DW_AT_MIPS_linkage_name                 0x2007 /* MIPS/SGI, GNU, and others.*/
+#define DW_AT_MIPS_stride                       0x2008 /* MIPS/SGI */
+#define DW_AT_MIPS_abstract_name                0x2009 /* MIPS/SGI */
+#define DW_AT_MIPS_clone_origin                 0x200a /* MIPS/SGI */
+#define DW_AT_MIPS_has_inlines                  0x200b /* MIPS/SGI */
+#define DW_AT_MIPS_stride_byte                  0x200c /* MIPS/SGI */
+#define DW_AT_MIPS_stride_elem                  0x200d /* MIPS/SGI */
+#define DW_AT_MIPS_ptr_dopetype                 0x200e /* MIPS/SGI */
+#define DW_AT_MIPS_allocatable_dopetype         0x200f /* MIPS/SGI */
+#define DW_AT_MIPS_assumed_shape_dopetype       0x2010 /* MIPS/SGI */
+#define DW_AT_MIPS_assumed_size                 0x2011 /* MIPS/SGI */
+
+/* HP extensions. */
+#define DW_AT_HP_unmodifiable                   0x2001 /* conflict: MIPS */
+#define DW_AT_HP_actuals_stmt_list              0x2010 /* conflict: MIPS */
+#define DW_AT_HP_proc_per_section               0x2011 /* conflict: MIPS */
+#define DW_AT_HP_raw_data_ptr                   0x2012 /* HP */
+#define DW_AT_HP_pass_by_reference              0x2013 /* HP */
+#define DW_AT_HP_opt_level                      0x2014 /* HP */
+#define DW_AT_HP_prof_version_id                0x2015 /* HP */
+#define DW_AT_HP_opt_flags                      0x2016 /* HP */
+#define DW_AT_HP_cold_region_low_pc             0x2017 /* HP */
+#define DW_AT_HP_cold_region_high_pc            0x2018 /* HP */
+#define DW_AT_HP_all_variables_modifiable       0x2019 /* HP */
+#define DW_AT_HP_linkage_name                   0x201a /* HP */
+#define DW_AT_HP_prof_flags                     0x201b /* HP */
+
+#define DW_AT_CPQ_discontig_ranges              0x2001 /* COMPAQ/HP */
+#define DW_AT_CPQ_semantic_events               0x2002 /* COMPAQ/HP */
+#define DW_AT_CPQ_split_lifetimes_var           0x2003 /* COMPAQ/HP */
+#define DW_AT_CPQ_split_lifetimes_rtn           0x2004 /* COMPAQ/HP */
+#define DW_AT_CPQ_prologue_length               0x2005 /* COMPAQ/HP */
+
+#define DW_AT_INTEL_other_endian                0x2026 /* Intel, 1 if byte swapped. */
+
+/* GNU extensions. */
+#define DW_AT_sf_names                          0x2101 /* GNU */
+#define DW_AT_src_info                          0x2102 /* GNU */
+#define DW_AT_mac_info                          0x2103 /* GNU */
+#define DW_AT_src_coords                        0x2104 /* GNU */
+#define DW_AT_body_begin                        0x2105 /* GNU */
+#define DW_AT_body_end                          0x2106 /* GNU */
+#define DW_AT_GNU_vector                        0x2107 /* GNU */
+
+/* ALTIUM extension: ALTIUM Compliant location lists (flag) */
+#define DW_AT_ALTIUM_loclist    0x2300          /* ALTIUM  */
+
+/* Sun extensions */
+#define DW_AT_SUN_template                      0x2201 /* SUN */
+#define DW_AT_VMS_rtnbeg_pd_address             0x2201 /* VMS */
+#define DW_AT_SUN_alignment                     0x2202 /* SUN */
+#define DW_AT_SUN_vtable                        0x2203 /* SUN */
+#define DW_AT_SUN_count_guarantee               0x2204 /* SUN */
+#define DW_AT_SUN_command_line                  0x2205 /* SUN */
+#define DW_AT_SUN_vbase                         0x2206 /* SUN */
+#define DW_AT_SUN_compile_options               0x2207 /* SUN */
+#define DW_AT_SUN_language                      0x2208 /* SUN */
+#define DW_AT_SUN_browser_file                  0x2209 /* SUN */
+#define DW_AT_SUN_vtable_abi                    0x2210 /* SUN */
+#define DW_AT_SUN_func_offsets                  0x2211 /* SUN */
+#define DW_AT_SUN_cf_kind                       0x2212 /* SUN */
+#define DW_AT_SUN_vtable_index                  0x2213 /* SUN */
+#define DW_AT_SUN_omp_tpriv_addr                0x2214 /* SUN */
+#define DW_AT_SUN_omp_child_func                0x2215 /* SUN */
+#define DW_AT_SUN_func_offset                   0x2216 /* SUN */
+#define DW_AT_SUN_memop_type_ref                0x2217 /* SUN */
+#define DW_AT_SUN_profile_id                    0x2218 /* SUN */
+#define DW_AT_SUN_memop_signature               0x2219 /* SUN */
+#define DW_AT_SUN_obj_dir                       0x2220 /* SUN */
+#define DW_AT_SUN_obj_file                      0x2221 /* SUN */
+#define DW_AT_SUN_original_name                 0x2222 /* SUN */
+#define DW_AT_SUN_hwcprof_signature             0x2223 /* SUN */
+#define DW_AT_SUN_amd64_parmdump                0x2224 /* SUN */
+#define DW_AT_SUN_part_link_name                0x2225 /* SUN */
+#define DW_AT_SUN_link_name                     0x2226 /* SUN */
+#define DW_AT_SUN_pass_with_const               0x2227 /* SUN */
+#define DW_AT_SUN_return_with_const             0x2228 /* SUN */
+#define DW_AT_SUN_import_by_name                0x2229 /* SUN */
+#define DW_AT_SUN_f90_pointer                   0x222a /* SUN */
+#define DW_AT_SUN_pass_by_ref                   0x222b /* SUN */
+#define DW_AT_SUN_f90_allocatable               0x222c /* SUN */
+#define DW_AT_SUN_f90_assumed_shape_array       0x222d /* SUN */
+#define DW_AT_SUN_c_vla                         0x222e /* SUN */
+#define DW_AT_SUN_return_value_ptr              0x2230 /* SUN */
+#define DW_AT_SUN_dtor_start                    0x2231 /* SUN */
+#define DW_AT_SUN_dtor_length                   0x2232 /* SUN */
+#define DW_AT_SUN_dtor_state_initial            0x2233 /* SUN */
+#define DW_AT_SUN_dtor_state_final              0x2234 /* SUN */
+#define DW_AT_SUN_dtor_state_deltas             0x2235 /* SUN */
+#define DW_AT_SUN_import_by_lname               0x2236 /* SUN */
+#define DW_AT_SUN_f90_use_only                  0x2237 /* SUN */
+#define DW_AT_SUN_namelist_spec                 0x2238 /* SUN */
+#define DW_AT_SUN_is_omp_child_func             0x2239 /* SUN */
+#define DW_AT_SUN_fortran_main_alias            0x223a /* SUN */
+#define DW_AT_SUN_fortran_based                 0x223b /* SUN */
+
+/* UPC extension */
+#define DW_AT_upc_threads_scaled                0x3210 /* UPC */
+
+/* PGI (STMicroelectronics) extensions. */
+#define DW_AT_PGI_lbase                         0x3a00 /* PGI. Block, constant, reference. This attribute is an ASTPLAB extension used to describe the array local base.  */
+#define DW_AT_PGI_soffset                       0x3a01  /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the section offset, or the offset to the first element in the dimension. */ 
+#define DW_AT_PGI_lstride                       0x3a02  /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the linear stride or the distance between elements in the dimension. */
+
+/* Apple Extensions for closures  */
+#define DW_AT_APPLE_closure                     0x3fe4 /* Apple */
+/* Apple Extensions for Objective-C runtime info */
+#define DW_AT_APPLE_major_runtime_vers          0x3fe5 /* Apple */
+#define DW_AT_APPLE_runtime_class               0x3fe6 /* Apple */
+
+
+#define DW_AT_hi_user                           0x3fff
+
+#define DW_OP_addr                      0x03
+#define DW_OP_deref                     0x06
+#define DW_OP_const1u                   0x08
+#define DW_OP_const1s                   0x09
+#define DW_OP_const2u                   0x0a
+#define DW_OP_const2s                   0x0b
+#define DW_OP_const4u                   0x0c
+#define DW_OP_const4s                   0x0d
+#define DW_OP_const8u                   0x0e
+#define DW_OP_const8s                   0x0f
+#define DW_OP_constu                    0x10
+#define DW_OP_consts                    0x11
+#define DW_OP_dup                       0x12
+#define DW_OP_drop                      0x13
+#define DW_OP_over                      0x14
+#define DW_OP_pick                      0x15
+#define DW_OP_swap                      0x16
+#define DW_OP_rot                       0x17
+#define DW_OP_xderef                    0x18
+#define DW_OP_abs                       0x19
+#define DW_OP_and                       0x1a
+#define DW_OP_div                       0x1b
+#define DW_OP_minus                     0x1c
+#define DW_OP_mod                       0x1d
+#define DW_OP_mul                       0x1e
+#define DW_OP_neg                       0x1f
+#define DW_OP_not                       0x20
+#define DW_OP_or                        0x21
+#define DW_OP_plus                      0x22
+#define DW_OP_plus_uconst               0x23
+#define DW_OP_shl                       0x24
+#define DW_OP_shr                       0x25
+#define DW_OP_shra                      0x26
+#define DW_OP_xor                       0x27
+#define DW_OP_bra                       0x28
+#define DW_OP_eq                        0x29
+#define DW_OP_ge                        0x2a
+#define DW_OP_gt                        0x2b
+#define DW_OP_le                        0x2c
+#define DW_OP_lt                        0x2d
+#define DW_OP_ne                        0x2e
+#define DW_OP_skip                      0x2f
+#define DW_OP_lit0                      0x30
+#define DW_OP_lit1                      0x31
+#define DW_OP_lit2                      0x32
+#define DW_OP_lit3                      0x33
+#define DW_OP_lit4                      0x34
+#define DW_OP_lit5                      0x35
+#define DW_OP_lit6                      0x36
+#define DW_OP_lit7                      0x37
+#define DW_OP_lit8                      0x38
+#define DW_OP_lit9                      0x39
+#define DW_OP_lit10                     0x3a
+#define DW_OP_lit11                     0x3b
+#define DW_OP_lit12                     0x3c
+#define DW_OP_lit13                     0x3d
+#define DW_OP_lit14                     0x3e
+#define DW_OP_lit15                     0x3f
+#define DW_OP_lit16                     0x40
+#define DW_OP_lit17                     0x41
+#define DW_OP_lit18                     0x42
+#define DW_OP_lit19                     0x43
+#define DW_OP_lit20                     0x44
+#define DW_OP_lit21                     0x45
+#define DW_OP_lit22                     0x46
+#define DW_OP_lit23                     0x47
+#define DW_OP_lit24                     0x48
+#define DW_OP_lit25                     0x49
+#define DW_OP_lit26                     0x4a
+#define DW_OP_lit27                     0x4b
+#define DW_OP_lit28                     0x4c
+#define DW_OP_lit29                     0x4d
+#define DW_OP_lit30                     0x4e
+#define DW_OP_lit31                     0x4f
+#define DW_OP_reg0                      0x50
+#define DW_OP_reg1                      0x51
+#define DW_OP_reg2                      0x52
+#define DW_OP_reg3                      0x53
+#define DW_OP_reg4                      0x54
+#define DW_OP_reg5                      0x55
+#define DW_OP_reg6                      0x56
+#define DW_OP_reg7                      0x57
+#define DW_OP_reg8                      0x58
+#define DW_OP_reg9                      0x59
+#define DW_OP_reg10                     0x5a
+#define DW_OP_reg11                     0x5b
+#define DW_OP_reg12                     0x5c
+#define DW_OP_reg13                     0x5d
+#define DW_OP_reg14                     0x5e
+#define DW_OP_reg15                     0x5f
+#define DW_OP_reg16                     0x60
+#define DW_OP_reg17                     0x61
+#define DW_OP_reg18                     0x62
+#define DW_OP_reg19                     0x63
+#define DW_OP_reg20                     0x64
+#define DW_OP_reg21                     0x65
+#define DW_OP_reg22                     0x66
+#define DW_OP_reg23                     0x67
+#define DW_OP_reg24                     0x68
+#define DW_OP_reg25                     0x69
+#define DW_OP_reg26                     0x6a
+#define DW_OP_reg27                     0x6b
+#define DW_OP_reg28                     0x6c
+#define DW_OP_reg29                     0x6d
+#define DW_OP_reg30                     0x6e
+#define DW_OP_reg31                     0x6f
+#define DW_OP_breg0                     0x70
+#define DW_OP_breg1                     0x71
+#define DW_OP_breg2                     0x72
+#define DW_OP_breg3                     0x73
+#define DW_OP_breg4                     0x74
+#define DW_OP_breg5                     0x75
+#define DW_OP_breg6                     0x76
+#define DW_OP_breg7                     0x77
+#define DW_OP_breg8                     0x78
+#define DW_OP_breg9                     0x79
+#define DW_OP_breg10                    0x7a
+#define DW_OP_breg11                    0x7b
+#define DW_OP_breg12                    0x7c
+#define DW_OP_breg13                    0x7d
+#define DW_OP_breg14                    0x7e
+#define DW_OP_breg15                    0x7f
+#define DW_OP_breg16                    0x80
+#define DW_OP_breg17                    0x81
+#define DW_OP_breg18                    0x82
+#define DW_OP_breg19                    0x83
+#define DW_OP_breg20                    0x84
+#define DW_OP_breg21                    0x85
+#define DW_OP_breg22                    0x86
+#define DW_OP_breg23                    0x87
+#define DW_OP_breg24                    0x88
+#define DW_OP_breg25                    0x89
+#define DW_OP_breg26                    0x8a
+#define DW_OP_breg27                    0x8b
+#define DW_OP_breg28                    0x8c
+#define DW_OP_breg29                    0x8d
+#define DW_OP_breg30                    0x8e
+#define DW_OP_breg31                    0x8f
+#define DW_OP_regx                      0x90
+#define DW_OP_fbreg                     0x91
+#define DW_OP_bregx                     0x92
+#define DW_OP_piece                     0x93
+#define DW_OP_deref_size                0x94
+#define DW_OP_xderef_size               0x95
+#define DW_OP_nop                       0x96
+#define DW_OP_push_object_address       0x97 /* DWARF3 */
+#define DW_OP_call2                     0x98 /* DWARF3 */
+#define DW_OP_call4                     0x99 /* DWARF3 */
+#define DW_OP_call_ref                  0x9a /* DWARF3 */
+#define DW_OP_form_tls_address          0x9b /* DWARF3f */
+#define DW_OP_call_frame_cfa            0x9c /* DWARF3f */
+#define DW_OP_bit_piece                 0x9d /* DWARF3f */
+#define DW_OP_implicit_value            0x9e /* DWARF4 */
+#define DW_OP_stack_value               0x9f /* DWARF4 */
+
+
+    /* GNU extensions. */
+#define DW_OP_GNU_push_tls_address      0xe0 /* GNU */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_OP_lo_user                   0xe0
+
+    /* HP extensions. */
+#define DW_OP_HP_unknown                0xe0 /* HP conflict: GNU */
+#define DW_OP_HP_is_value               0xe1 /* HP */
+#define DW_OP_HP_fltconst4              0xe2 /* HP */
+#define DW_OP_HP_fltconst8              0xe3 /* HP */
+#define DW_OP_HP_mod_range              0xe4 /* HP */
+#define DW_OP_HP_unmod_range            0xe5 /* HP */
+#define DW_OP_HP_tls                    0xe6 /* HP */
+
+#define DW_OP_INTEL_bit_piece           0xe8 /* Intel: made obsolete by DW_OP_bit_piece above. */
+
+
+   /* Apple extension. */
+#define DW_OP_APPLE_uninit              0xf0 /* Apple */ 
+
+#define DW_OP_hi_user                   0xff
+
+#define DW_ATE_address                  0x1
+#define DW_ATE_boolean                  0x2
+#define DW_ATE_complex_float            0x3
+#define DW_ATE_float                    0x4
+#define DW_ATE_signed                   0x5
+#define DW_ATE_signed_char              0x6
+#define DW_ATE_unsigned                 0x7
+#define DW_ATE_unsigned_char            0x8
+#define DW_ATE_imaginary_float          0x9  /* DWARF3 */
+#define DW_ATE_packed_decimal           0xa  /* DWARF3f */
+#define DW_ATE_numeric_string           0xb  /* DWARF3f */
+#define DW_ATE_edited                   0xc  /* DWARF3f */
+#define DW_ATE_signed_fixed             0xd  /* DWARF3f */
+#define DW_ATE_unsigned_fixed           0xe  /* DWARF3f */
+#define DW_ATE_decimal_float            0xf  /* DWARF3f */
+
+
+/* ALTIUM extensions. x80, x81 */
+#define DW_ATE_ALTIUM_fract           0x80 /* ALTIUM __fract type */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_ATE_lo_user                  0x80
+
+/* Shown here to help dwarfdump build script. */
+#define DW_ATE_ALTIUM_accum           0x81 /* ALTIUM __accum type */
+
+/* HP Floating point extensions. */
+#define DW_ATE_HP_float80             0x80 /* (80 bit). HP */
+
+
+#define DW_ATE_HP_complex_float80     0x81 /* Complex (80 bit). HP  */
+#define DW_ATE_HP_float128            0x82 /* (128 bit). HP */
+#define DW_ATE_HP_complex_float128    0x83 /* Complex (128 bit). HP */
+#define DW_ATE_HP_floathpintel        0x84 /* (82 bit IA64). HP */
+#define DW_ATE_HP_imaginary_float80   0x85 /* HP */
+#define DW_ATE_HP_imaginary_float128  0x86 /* HP */
+
+/* Sun extensions */
+#define DW_ATE_SUN_interval_float       0x91
+#define DW_ATE_SUN_imaginary_float      0x92 /* Obsolete: See DW_ATE_imaginary_float */
+
+#define DW_ATE_hi_user                  0xff
+
+
+/* Decimal Sign codes. */
+#define DW_DS_unsigned                  0x01 /* DWARF3f */
+#define DW_DS_leading_overpunch         0x02 /* DWARF3f */
+#define DW_DS_trailing_overpunch        0x03 /* DWARF3f */
+#define DW_DS_leading_separate          0x04 /* DWARF3f */
+
+#define DW_DS_trailing_separate         0x05 /* DWARF3f */
+
+/* Endian code name. */
+#define DW_END_default                  0x00 /* DWARF3f */
+#define DW_END_big                      0x01 /* DWARF3f */
+#define DW_END_little                   0x02 /* DWARF3f */
+
+#define DW_END_lo_user                  0x40 /* DWARF3f */
+#define DW_END_hi_user                  0xff /* DWARF3f */
+
+/* For use with DW_TAG_SUN_codeflags
+ * If DW_TAG_SUN_codeflags is accepted as a dwarf standard, then
+ * standard dwarf ATCF entries start at 0x01
+ */
+#define DW_ATCF_lo_user                 0x40 /* SUN */
+#define DW_ATCF_SUN_mop_bitfield        0x41 /* SUN */
+#define DW_ATCF_SUN_mop_spill           0x42 /* SUN */
+#define DW_ATCF_SUN_mop_scopy           0x43 /* SUN */
+#define DW_ATCF_SUN_func_start          0x44 /* SUN */
+#define DW_ATCF_SUN_end_ctors           0x45 /* SUN */
+#define DW_ATCF_SUN_branch_target       0x46 /* SUN */
+#define DW_ATCF_SUN_mop_stack_probe     0x47 /* SUN */
+#define DW_ATCF_SUN_func_epilog         0x48 /* SUN */
+#define DW_ATCF_hi_user                 0xff /* SUN */   
+
+/* Accessibility code name. */
+#define DW_ACCESS_public                0x01
+#define DW_ACCESS_protected             0x02
+#define DW_ACCESS_private               0x03
+
+/* Visibility code name. */
+#define DW_VIS_local                    0x01
+#define DW_VIS_exported                 0x02
+#define DW_VIS_qualified                0x03
+
+/* Virtuality code name. */
+#define DW_VIRTUALITY_none              0x00
+#define DW_VIRTUALITY_virtual           0x01
+#define DW_VIRTUALITY_pure_virtual      0x02
+
+#define DW_LANG_C89                     0x0001
+#define DW_LANG_C                       0x0002
+#define DW_LANG_Ada83                   0x0003
+#define DW_LANG_C_plus_plus             0x0004
+#define DW_LANG_Cobol74                 0x0005
+#define DW_LANG_Cobol85                 0x0006
+#define DW_LANG_Fortran77               0x0007
+#define DW_LANG_Fortran90               0x0008
+#define DW_LANG_Pascal83                0x0009
+#define DW_LANG_Modula2                 0x000a
+#define DW_LANG_Java                    0x000b /* DWARF3 */
+#define DW_LANG_C99                     0x000c /* DWARF3 */
+#define DW_LANG_Ada95                   0x000d /* DWARF3 */
+#define DW_LANG_Fortran95               0x000e /* DWARF3 */
+#define DW_LANG_PLI                     0x000f /* DWARF3 */
+#define DW_LANG_ObjC                    0x0010 /* DWARF3f */
+#define DW_LANG_ObjC_plus_plus          0x0011 /* DWARF3f */
+#define DW_LANG_UPC                     0x0012 /* DWARF3f */
+#define DW_LANG_D                       0x0013 /* DWARF3f */
+#define DW_LANG_Python                  0x0014 /* DWARF4 */
+#define DW_LANG_lo_user                 0x8000
+#define DW_LANG_Mips_Assembler          0x8001 /* MIPS   */
+#define DW_LANG_Upc                     0x8765 /* UPC, use
+                                        DW_LANG_UPC instead. */
+/* ALTIUM extension */
+#define DW_LANG_ALTIUM_Assembler        0x9101  /* ALTIUM */
+
+/* Sun extensions */
+#define DW_LANG_SUN_Assembler           0x9001 /* SUN */
+
+#define DW_LANG_hi_user                 0xffff
+
+/* Identifier case name. */
+#define DW_ID_case_sensitive            0x00
+#define DW_ID_up_case                   0x01
+#define DW_ID_down_case                 0x02
+#define DW_ID_case_insensitive          0x03
+
+/* Calling Convention Name. */
+#define DW_CC_normal                    0x01
+#define DW_CC_program                   0x02
+#define DW_CC_nocall                    0x03
+#define DW_CC_lo_user                   0x40
+
+/* ALTIUM extensions. */
+/* Function is an interrupt handler, return address on system stack. */
+#define DW_CC_ALTIUM_interrupt          0x65  /* ALTIUM*/
+
+/* Near function model, return address on system stack. */
+#define DW_CC_ALTIUM_near_system_stack  0x66  /*ALTIUM */
+
+/* Near function model, return address on user stack. */
+#define DW_CC_ALTIUM_near_user_stack    0x67  /* ALTIUM */  
+
+/* Huge function model, return address on user stack.  */
+#define DW_CC_ALTIUM_huge_user_stack    0x68  /* ALTIUM */    
+
+
+#define DW_CC_hi_user                   0xff
+
+/* Inline Code Name. */
+#define DW_INL_not_inlined              0x00
+#define DW_INL_inlined                  0x01
+#define DW_INL_declared_not_inlined     0x02
+#define DW_INL_declared_inlined         0x03
+
+/* Ordering Name. */
+#define DW_ORD_row_major                0x00
+#define DW_ORD_col_major                0x01
+
+/* Discriminant Descriptor Name. */
+#define DW_DSC_label                    0x00
+#define DW_DSC_range                    0x01
+
+/* Line number standard opcode name. */
+#define DW_LNS_copy                     0x01
+#define DW_LNS_advance_pc               0x02
+#define DW_LNS_advance_line             0x03
+#define DW_LNS_set_file                 0x04
+#define DW_LNS_set_column               0x05
+#define DW_LNS_negate_stmt              0x06
+#define DW_LNS_set_basic_block          0x07
+#define DW_LNS_const_add_pc             0x08
+#define DW_LNS_fixed_advance_pc         0x09
+#define DW_LNS_set_prologue_end         0x0a /* DWARF3 */
+#define DW_LNS_set_epilogue_begin       0x0b /* DWARF3 */
+#define DW_LNS_set_isa                  0x0c /* DWARF3 */
+
+/* Line number extended opcode name. */
+#define DW_LNE_end_sequence             0x01
+#define DW_LNE_set_address              0x02
+#define DW_LNE_define_file              0x03
+#define DW_LNE_set_discriminator        0x04  /* DWARF4 */
+
+/* HP extensions. */
+#define DW_LNE_HP_negate_is_UV_update       0x11 /* 17 HP */
+#define DW_LNE_HP_push_context              0x12 /* 18 HP */
+#define DW_LNE_HP_pop_context               0x13 /* 19 HP */
+#define DW_LNE_HP_set_file_line_column      0x14 /* 20 HP */
+#define DW_LNE_HP_set_routine_name          0x15 /* 21 HP */
+#define DW_LNE_HP_set_sequence              0x16 /* 22 HP */
+#define DW_LNE_HP_negate_post_semantics     0x17 /* 23 HP */
+#define DW_LNE_HP_negate_function_exit      0x18 /* 24 HP */
+#define DW_LNE_HP_negate_front_end_logical  0x19 /* 25 HP */
+#define DW_LNE_HP_define_proc               0x20 /* 32 HP */
+
+#define DW_LNE_lo_user                  0x80 /* DWARF3 */
+#define DW_LNE_hi_user                  0xff /* DWARF3 */
+
+/* Macro information. */
+#define DW_MACINFO_define               0x01
+#define DW_MACINFO_undef                0x02
+#define DW_MACINFO_start_file           0x03
+#define DW_MACINFO_end_file             0x04
+#define DW_MACINFO_vendor_ext           0xff
+
+/* CFA operator compaction (a space saving measure, see
+   the DWARF standard) means DW_CFA_extended and DW_CFA_nop 
+   have the same value here.  */
+#define DW_CFA_advance_loc        0x40
+#define DW_CFA_offset             0x80
+#define DW_CFA_restore            0xc0
+#define DW_CFA_extended           0
+
+#define DW_CFA_nop              0x00
+#define DW_CFA_set_loc          0x01
+#define DW_CFA_advance_loc1     0x02
+#define DW_CFA_advance_loc2     0x03
+#define DW_CFA_advance_loc4     0x04
+#define DW_CFA_offset_extended  0x05
+#define DW_CFA_restore_extended 0x06
+#define DW_CFA_undefined        0x07
+#define DW_CFA_same_value       0x08
+#define DW_CFA_register         0x09
+#define DW_CFA_remember_state   0x0a
+#define DW_CFA_restore_state    0x0b
+#define DW_CFA_def_cfa          0x0c
+#define DW_CFA_def_cfa_register 0x0d
+#define DW_CFA_def_cfa_offset   0x0e
+#define DW_CFA_def_cfa_expression 0x0f     /* DWARF3 */
+#define DW_CFA_expression       0x10       /* DWARF3 */
+#define DW_CFA_offset_extended_sf 0x11     /* DWARF3 */
+#define DW_CFA_def_cfa_sf       0x12       /* DWARF3 */
+#define DW_CFA_def_cfa_offset_sf 0x13      /* DWARF3 */
+#define DW_CFA_val_offset        0x14      /* DWARF3f */
+#define DW_CFA_val_offset_sf     0x15      /* DWARF3f */
+#define DW_CFA_val_expression    0x16      /* DWARF3f */
+
+#define DW_CFA_lo_user           0x1c
+#define DW_CFA_low_user          0x1c  /* Incorrect spelling, do not use. */
+
+/* SGI/MIPS extension. */
+#define DW_CFA_MIPS_advance_loc8 0x1d   /* MIPS */
+
+/* GNU extensions. */
+#define DW_CFA_GNU_window_save   0x2d  /* GNU */
+#define DW_CFA_GNU_args_size     0x2e /* GNU  */
+#define DW_CFA_GNU_negative_offset_extended  0x2f /* GNU */
+
+#define DW_CFA_high_user         0x3f
+
+/* GNU exception header encoding.  See the Generic
+   Elf Specification of the Linux Standard Base (LSB). 
+   http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
+   The upper 4 bits indicate how the value is to be applied. 
+   The lower 4 bits indicate the format of the data.
+*/
+#define DW_EH_PE_absptr   0x00  /* GNU */
+#define DW_EH_PE_uleb128  0x01  /* GNU */
+#define DW_EH_PE_udata2   0x02  /* GNU */
+#define DW_EH_PE_udata4   0x03  /* GNU */
+#define DW_EH_PE_udata8   0x04  /* GNU */
+#define DW_EH_PE_sleb128  0x09  /* GNU */
+#define DW_EH_PE_sdata2   0x0A  /* GNU */
+#define DW_EH_PE_sdata4   0x0B  /* GNU */
+#define DW_EH_PE_sdata8   0x0C  /* GNU */
+
+#define DW_EH_PE_pcrel    0x10  /* GNU */
+#define DW_EH_PE_textrel  0x20  /* GNU */
+#define DW_EH_PE_datarel  0x30  /* GNU */
+#define DW_EH_PE_funcrel  0x40  /* GNU */
+#define DW_EH_PE_aligned  0x50  /* GNU */
+
+#define DW_EH_PE_omit     0xff  /* GNU.  Means no value present. */
+
+
+/* Mapping from machine registers and pseudo-regs into the .debug_frame table.
+   DW_FRAME entries are machine specific. These describe
+   MIPS/SGI R3000, R4K, R4400 and all later MIPS/SGI IRIX machines.
+   They describe a mapping from hardware register number to
+   the number used in the table to identify that register.
+
+   The CFA (Canonical Frame Address) described in DWARF is called
+   the Virtual Frame Pointer on MIPS/SGI machines.
+
+   The DW_FRAME* names here are MIPS/SGI specfic.
+   Libdwarf interfaces defined in 2008 make the FRAME definitions
+   here (and the fixed table sizes they imply) obsolete.
+   They are left here for compatibility. 
+   
+*/
+/* Column used for CFA. Assumes reg 0 never appears as
+   a register in DWARF info.  */
+#define DW_FRAME_CFA_COL 0  
+
+#define DW_FRAME_REG1   1  /* integer reg 1 */
+#define DW_FRAME_REG2   2  /* integer reg 2 */
+#define DW_FRAME_REG3   3  /* integer reg 3 */
+#define DW_FRAME_REG4   4  /* integer reg 4 */
+#define DW_FRAME_REG5   5  /* integer reg 5 */
+#define DW_FRAME_REG6   6  /* integer reg 6 */
+#define DW_FRAME_REG7   7  /* integer reg 7 */
+#define DW_FRAME_REG8   8  /* integer reg 8 */
+#define DW_FRAME_REG9   9  /* integer reg 9 */
+#define DW_FRAME_REG10  10 /* integer reg 10 */
+#define DW_FRAME_REG11  11 /* integer reg 11 */
+#define DW_FRAME_REG12  12 /* integer reg 12 */
+#define DW_FRAME_REG13  13 /* integer reg 13 */
+#define DW_FRAME_REG14  14 /* integer reg 14 */
+#define DW_FRAME_REG15  15 /* integer reg 15 */
+#define DW_FRAME_REG16  16 /* integer reg 16 */
+#define DW_FRAME_REG17  17 /* integer reg 17 */
+#define DW_FRAME_REG18  18 /* integer reg 18 */
+#define DW_FRAME_REG19  19 /* integer reg 19 */
+#define DW_FRAME_REG20  20 /* integer reg 20 */
+#define DW_FRAME_REG21  21 /* integer reg 21 */
+#define DW_FRAME_REG22  22 /* integer reg 22 */
+#define DW_FRAME_REG23  23 /* integer reg 23 */
+#define DW_FRAME_REG24  24 /* integer reg 24 */
+#define DW_FRAME_REG25  25 /* integer reg 25 */
+#define DW_FRAME_REG26  26 /* integer reg 26 */
+#define DW_FRAME_REG27  27 /* integer reg 27 */
+#define DW_FRAME_REG28  28 /* integer reg 28 */
+#define DW_FRAME_REG29  29 /* integer reg 29 */
+#define DW_FRAME_REG30  30 /* integer reg 30 */
+#define DW_FRAME_REG31  31 /* integer reg 31, aka ra */
+
+        /* MIPS1, 2 have only some of these 64-bit registers.
+        ** MIPS1  save/restore takes 2 instructions per 64-bit reg, and
+        ** in that case, the register is considered stored after the second
+        ** swc1.
+        */
+#define DW_FRAME_FREG0  32 /* 64-bit floating point reg 0 */
+#define DW_FRAME_FREG1  33 /* 64-bit floating point reg 1 */
+#define DW_FRAME_FREG2  34 /* 64-bit floating point reg 2 */
+#define DW_FRAME_FREG3  35 /* 64-bit floating point reg 3 */
+#define DW_FRAME_FREG4  36 /* 64-bit floating point reg 4 */
+#define DW_FRAME_FREG5  37 /* 64-bit floating point reg 5 */
+#define DW_FRAME_FREG6  38 /* 64-bit floating point reg 6 */
+#define DW_FRAME_FREG7  39 /* 64-bit floating point reg 7 */
+#define DW_FRAME_FREG8  40 /* 64-bit floating point reg 8 */
+#define DW_FRAME_FREG9  41 /* 64-bit floating point reg 9 */
+#define DW_FRAME_FREG10 42 /* 64-bit floating point reg 10 */
+#define DW_FRAME_FREG11 43 /* 64-bit floating point reg 11 */
+#define DW_FRAME_FREG12 44 /* 64-bit floating point reg 12 */
+#define DW_FRAME_FREG13 45 /* 64-bit floating point reg 13 */
+#define DW_FRAME_FREG14 46 /* 64-bit floating point reg 14 */
+#define DW_FRAME_FREG15 47 /* 64-bit floating point reg 15 */
+#define DW_FRAME_FREG16 48 /* 64-bit floating point reg 16 */
+#define DW_FRAME_FREG17 49 /* 64-bit floating point reg 17 */
+#define DW_FRAME_FREG18 50 /* 64-bit floating point reg 18 */
+#define DW_FRAME_FREG19 51 /* 64-bit floating point reg 19 */
+#define DW_FRAME_FREG20 52 /* 64-bit floating point reg 20 */
+#define DW_FRAME_FREG21 53 /* 64-bit floating point reg 21 */
+#define DW_FRAME_FREG22 54 /* 64-bit floating point reg 22 */
+#define DW_FRAME_FREG23 55 /* 64-bit floating point reg 23 */
+#define DW_FRAME_FREG24 56 /* 64-bit floating point reg 24 */
+#define DW_FRAME_FREG25 57 /* 64-bit floating point reg 25 */
+#define DW_FRAME_FREG26 58 /* 64-bit floating point reg 26 */
+#define DW_FRAME_FREG27 59 /* 64-bit floating point reg 27 */
+#define DW_FRAME_FREG28 60 /* 64-bit floating point reg 28 */
+#define DW_FRAME_FREG29 61 /* 64-bit floating point reg 29 */
+#define DW_FRAME_FREG30 62 /* 64-bit floating point reg 30 */
+#define DW_FRAME_FREG31 63 /* 64-bit floating point reg 31 */
+
+/*  ***IMPORTANT NOTE, TARGET DEPENDENCY ****
+    The following 4 #defines are dependent on 
+    the target cpu(s) that you apply libdwarf to.
+    Ensure that DW_FRAME_UNDEFINED_VAL  and DW_FRAME_SAME_VAL
+    do not conflict with the range [0-DW_FRAME_STATIC_LINK].
+    The value 63 works for MIPS cpus at least up to the R16000.
+
+    For a cpu with more than 63 real registers
+    DW_FRAME_HIGHEST_NORMAL_REGISTER
+    must be increased for things to work properly!
+    Also ensure that DW_FRAME_UNDEFINED_VAL DW_FRAME_SAME_VAL
+    are not in the range [0-DW_FRAME_STATIC_LINK]
+
+    Having DW_FRAME_HIGHEST_NORMAL_REGISTER be higher than
+    is strictly needed is safe.
+
+*/
+
+#ifndef DW_FRAME_HIGHEST_NORMAL_REGISTER
+#define DW_FRAME_HIGHEST_NORMAL_REGISTER 63
+#endif
+/* This is the number of columns in the Frame Table. 
+   This constant should
+   be kept in sync with DW_REG_TABLE_SIZE defined in libdwarf.h 
+   It must also be large enough to be beyond the highest 
+   compiler-defined-register (meaning DW_FRAME_RA_COL DW_FRAME_STATIC_LINK
+   in the MIPS/IRIX case */
+#ifndef DW_FRAME_LAST_REG_NUM
+#define DW_FRAME_LAST_REG_NUM   (DW_FRAME_HIGHEST_NORMAL_REGISTER + 3)
+#endif
+
+
+/* Column recording ra (return addrress from a function call). 
+   This is common to many architectures, but as a 'simple register'
+   is not necessarily adequate for all architectures.
+   For MIPS/IRIX this register number is actually recorded on disk
+   in the .debug_frame section.
+   */
+#define DW_FRAME_RA_COL  (DW_FRAME_HIGHEST_NORMAL_REGISTER + 1)
+
+/* Column recording static link applicable to up-level      
+   addressing, as in IRIX mp code, pascal, etc.
+   This is common to many architectures but
+   is not necessarily adequate for all architectures.
+   For MIPS/IRIX this register number is actually recorded on disk
+   in the .debug_frame section.
+*/
+#define DW_FRAME_STATIC_LINK (DW_FRAME_HIGHEST_NORMAL_REGISTER + 2)
+
+
+
+/*
+  DW_FRAME_UNDEFINED_VAL and  DW_FRAME_SAME_VAL  are
+  never on disk, just generated by libdwarf. See libdwarf.h
+  for their values.
+*/
+
+
+
+#define DW_CHILDREN_no               0x00
+#define DW_CHILDREN_yes              0x01
+
+#define DW_ADDR_none            0
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __DWARF_H */
diff --git a/elff/dwarf_cu.cc b/elff/dwarf_cu.cc
new file mode 100644
index 0000000..8e7da98
--- /dev/null
+++ b/elff/dwarf_cu.cc
@@ -0,0 +1,758 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains implementation of a class DwarfCU, that encapsulates a compilation

+ * unit in the .debug_info section of the mapped ELF file.

+ */

+

+#include "string.h"

+#include "stdio.h"

+#include "elf_file.h"

+#include "dwarf_cu.h"

+#include "dwarf_utils.h"

+

+DwarfCU::DwarfCU(ElfFile* elf)

+    : elf_file_(elf),

+      cu_die_(NULL),

+      prev_cu_(NULL) {

+}

+

+DwarfCU::~DwarfCU() {

+  if (cu_die_ != NULL) {

+    delete cu_die_;

+  }

+  abbrs_.empty();

+}

+

+DwarfCU* DwarfCU::create_instance(ElfFile* elf, const void* hdr) {

+  DwarfCU* ret;

+

+  /* 64-bit DWARF CU has first 4 bytes in its header set to 0xFFFFFFFF. */

+  if (*reinterpret_cast<const Elf_Word*>(hdr) == 0xFFFFFFFF) {

+    ret = new(elf) DwarfCUImpl<Dwarf64_CUHdr, Dwarf64_Off>

+                      (elf, reinterpret_cast<const Dwarf64_CUHdr*>(hdr));

+  } else {

+    ret = new(elf) DwarfCUImpl<Dwarf32_CUHdr, Dwarf32_Off>

+                      (elf, reinterpret_cast<const Dwarf32_CUHdr*>(hdr));

+  }

+  assert(ret != NULL);

+  if (ret == NULL) {

+    _set_errno(ENOMEM);

+  }

+  return ret;

+}

+

+const Elf_Byte* DwarfCU::process_attrib(const Elf_Byte* prop,

+                                        Dwarf_Form form,

+                                        Dwarf_Value* attr_value) const {

+  assert(form != 0);

+  Dwarf_Value tmp_val;

+  Dwarf_Value leb128;

+

+  attr_value->type = DWARF_VALUE_UNKNOWN;

+  attr_value->encoded_size = 0;

+  attr_value->u64 = 0;

+

+  switch (form) {

+    /* Property is a block of data, contained in .debug_info section. Block

+     * size is encoded with 1 byte value, and block data immediately follows

+     * block size. */

+    case DW_FORM_block1:

+      attr_value->type = DWARF_VALUE_BLOCK;

+      attr_value->block.block_size = *prop;

+      attr_value->block.block_ptr = prop + 1;

+      attr_value->encoded_size =

+          static_cast<Elf_Word>(attr_value->block.block_size + 1);

+      break;

+

+    /* Property is a block of data, contained in .debug_info section. Block

+     * size is encoded with 2 bytes value, and block data immediately follows

+     * block size. */

+    case DW_FORM_block2:

+      attr_value->type = DWARF_VALUE_BLOCK;

+      attr_value->block.block_size =

+          elf_file_->pull_val(reinterpret_cast<const Elf_Half*>(prop));

+      attr_value->block.block_ptr = prop + 2;

+      attr_value->encoded_size =

+          static_cast<Elf_Word>(attr_value->block.block_size + 2);

+      break;

+

+    /* Property is a block of data, contained in .debug_info section. Block

+     * size is encoded with 4 bytes value, and block data immediately follows

+     * block size. */

+    case DW_FORM_block4:

+      attr_value->type = DWARF_VALUE_BLOCK;

+      attr_value->block.block_size =

+          elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));

+      attr_value->block.block_ptr = prop + 4;

+      attr_value->encoded_size =

+          static_cast<Elf_Word>(attr_value->block.block_size + 4);

+      break;

+

+    /* Property is a block of data, contained in .debug_info section. Block

+     * size is encoded with unsigned LEB128 value, and block data immediately

+     * follows block size. */

+    case DW_FORM_block:

+      reinterpret_cast<const Dwarf_Leb128*>(prop)->process_unsigned(&leb128);

+      attr_value->type = DWARF_VALUE_BLOCK;

+      attr_value->block.block_size = leb128.u32;

+      attr_value->block.block_ptr = prop + leb128.encoded_size;

+      attr_value->encoded_size =

+          static_cast<Elf_Word>(attr_value->block.block_size +

+                                leb128.encoded_size);

+      break;

+

+    /* Property is unsigned 1 byte value. */

+    case DW_FORM_flag:

+    case DW_FORM_data1:

+    case DW_FORM_ref1:

+      attr_value->type = DWARF_VALUE_U8;

+      attr_value->u8 = *prop;

+      attr_value->encoded_size = 1;

+      break;

+

+    /* Property is unsigned 2 bytes value. */

+    case DW_FORM_data2:

+    case DW_FORM_ref2:

+      attr_value->type = DWARF_VALUE_U16;

+      attr_value->u16 =

+          elf_file_->pull_val(reinterpret_cast<const Elf_Half*>(prop));

+      attr_value->encoded_size = 2;

+      break;

+

+    /* Property is unsigned 4 bytes value. */

+    case DW_FORM_data4:

+    case DW_FORM_ref4:

+      attr_value->type = DWARF_VALUE_U32;

+      attr_value->u32 =

+          elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));

+      attr_value->encoded_size = 4;

+      break;

+

+    /* Property is unsigned 8 bytes value. */

+    case DW_FORM_data8:

+    case DW_FORM_ref8:

+    case DW_FORM_ref_sig8:

+      attr_value->type = DWARF_VALUE_U64;

+      attr_value->u64 =

+          elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));

+      attr_value->encoded_size = 8;

+      break;

+

+    /* Property is signed LEB128 value. */

+    case DW_FORM_sdata:

+      reinterpret_cast<const Dwarf_Leb128*>(prop)->process_signed(attr_value);

+      break;

+

+    /* Property is unsigned LEB128 value. */

+    case DW_FORM_ref_udata:

+    case DW_FORM_udata:

+      reinterpret_cast<const Dwarf_Leb128*>(prop)->process_unsigned(attr_value);

+      break;

+

+    /* Property is a string contained directly in .debug_info section. */

+    case DW_FORM_string:

+      attr_value->type = DWARF_VALUE_STR;

+      attr_value->str = reinterpret_cast<const char*>(prop);

+      attr_value->encoded_size = strlen(attr_value->str) + 1;

+      break;

+

+    /* Property is an offset of a string contained in .debug_str section.

+     * We will process the reference here, converting it into the actual

+     * string value. */

+    case DW_FORM_strp:

+      attr_value->type = DWARF_VALUE_STR;

+      if (elf_file_->is_DWARF_64()) {

+        Elf_Xword str_offset =

+            elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));

+        attr_value->str = elf_file_->get_debug_str(str_offset);

+        attr_value->encoded_size = 8;

+      } else {

+        Elf_Word str_offset =

+            elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));

+        attr_value->str = elf_file_->get_debug_str(str_offset);

+        attr_value->encoded_size = 4;

+      }

+      break;

+

+    /* Property is an address. */

+    case DW_FORM_addr:

+      if (addr_sizeof_ == 4) {

+        attr_value->type = DWARF_VALUE_PTR32;

+        attr_value->u32 =

+            elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));

+      } else {

+        attr_value->type = DWARF_VALUE_PTR64;

+        attr_value->u64 =

+            elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));

+      }

+      attr_value->encoded_size = addr_sizeof_;

+      break;

+

+    /* Reference from the beginning of .debug_info section. */

+    case DW_FORM_ref_addr:

+      /* DWARF3+ requires that encoding size of this property must be 4 bytes

+       * in 32-bit DWARF, and 8 bytes in 64-bit DWARF, while DWARF2- requires

+       * encoding size to be equal to CU's pointer size. */

+      if (is_DWARF3_or_higher()) {

+        if (elf_file_->is_DWARF_64()) {

+          attr_value->type = DWARF_VALUE_U64;

+          attr_value->u64 =

+              elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));

+          attr_value->encoded_size = 4;

+        } else {

+          attr_value->type = DWARF_VALUE_U32;

+          attr_value->u32 =

+              elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));

+          attr_value->encoded_size = 8;

+        }

+      } else {

+        if (addr_sizeof_ == 4) {

+          attr_value->type = DWARF_VALUE_U32;

+          attr_value->u32 =

+              elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));

+        } else {

+          attr_value->type = DWARF_VALUE_U64;

+          attr_value->u64 =

+              elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));

+        }

+        attr_value->encoded_size = addr_sizeof_;

+      }

+      break;

+

+    /* Reference to a section, other than .debug_info, or .debug_str */

+    case DW_FORM_sec_offset:

+      if (elf_file_->is_DWARF_64()) {

+        attr_value->type = DWARF_VALUE_U64;

+        attr_value->u64 =

+            elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));

+        attr_value->encoded_size = 4;

+      } else {

+        attr_value->type = DWARF_VALUE_U32;

+        attr_value->u32 =

+            elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));

+        attr_value->encoded_size = 8;

+      }

+      break;

+

+    /* This is a replacement for DW_FORM_flag, which doesn't consume memory

+     * in .debug_info section, and only by the fact of its existence it is

+     * equal to DW_FORM_flag with value set to 1. */

+    case DW_FORM_flag_present:

+      attr_value->type = DWARF_VALUE_U8;

+      attr_value->u8 = 1;

+      attr_value->encoded_size = 0;

+      break;

+

+    /* Encodes the actual form to be used. */

+    case DW_FORM_indirect:

+      // Starts with ULEB128

+      prop = reinterpret_cast<const Elf_Byte*>

+                (reinterpret_cast<const Dwarf_Leb128*>

+                    (prop)->process_unsigned(&tmp_val));

+      /* ULEB128 encodes the actual form to be used to process this entry. */

+      process_attrib(prop, tmp_val.u16, attr_value);

+      attr_value->encoded_size += tmp_val.encoded_size;

+      break;

+

+    /* This form is defined for DWARF4, and has no documentation whatsoever. */

+    case DW_FORM_exprloc:

+    default:

+      attr_value->type = DWARF_VALUE_U32;

+      attr_value->u32 =

+          elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));

+      attr_value->encoded_size = 4;

+      break;

+  }

+

+  return prop + attr_value->encoded_size;

+}

+

+void DwarfCU::dump() const {

+  printf("\n\n>>>>>>>>>>>>>>> CU %p (version %u, address size %u)\n",

+         cu_die_->die(), static_cast<Elf_Word>(version_),

+         static_cast<Elf_Word>(addr_sizeof_));

+  printf(">>>>> Build dir path:  %s\n", comp_dir_path());

+  printf(">>>>> Build file path: %s\n", rel_cu_path());

+  if (cu_die_ != NULL) {

+    cu_die_->dump(false);

+  }

+}

+

+//=============================================================================

+// DwarfCUImpl implementation

+//=============================================================================

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::DwarfCUImpl(ElfFile* elf,

+                                                 const Dwarf_CUHdr* hdr)

+    : DwarfCU(elf),

+      cu_header_(hdr) {

+  /* Cache CU's DIE abbreviation descriptor in the array. This MUST be done

+   * BEFORE first call to array's cache_to() method. */

+  const Dwarf_Abbr_DIE* cu_abbr_die = reinterpret_cast<const Dwarf_Abbr_DIE*>

+                                 (INC_CPTR(elf->get_debug_abbrev_data(),

+                                           elf->pull_val(hdr->abbrev_offset)));

+  abbrs_.add(cu_abbr_die);

+

+  cu_size_ = elf->pull_val(hdr->size_hdr.size);

+  version_ = elf->pull_val(hdr->version);

+  addr_sizeof_ = hdr->address_size;

+  memset(&stmtl_header_, 0, sizeof(stmtl_header_));

+}

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+bool DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::parse(

+    const DwarfParseContext* parse_context,

+    const void** next_cu_die) {

+  /* Start parsing with the DIE for this CU. */

+  if (process_DIE(parse_context, get_DIE(), NULL) == NULL) {

+    return false;

+  }

+

+  /* CU area size (thus, next CU header offset) in .debug_info section equals

+   * to CU size, plus number of bytes, required to encode CU size in CU header

+   * (4 for 32-bit CU, and 12 for 64-bit CU. */

+  *next_cu_die =

+      INC_CPTR(cu_header_, cu_size_ + ELFF_FIELD_OFFSET(Dwarf_CUHdr, version));

+

+  return true;

+}

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+const Elf_Byte* DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::process_DIE(

+    const DwarfParseContext* parse_context,

+    const Dwarf_DIE* die,

+    DIEObject* parent_obj) {

+  while (is_attrib_ptr_valid(die) && !die->is_separator()) {

+    Dwarf_AbbrNum abbr_num;

+    Dwarf_Tag     die_tag;

+    Elf_Word      sibling_off = 0;

+

+    /* Get DIE's abbreviation number, and advance to DIE's properties. */

+    const Elf_Byte* die_attr = die->process(&abbr_num);

+

+    /* Get abbreviation for the current DIE. */

+    const Dwarf_Abbr_DIE* die_abbr = abbrs_.cache_to(abbr_num);

+    if (die_abbr == NULL) {

+      return NULL;

+    }

+

+    /* Get base DIE properties, and advance to the DIE's

+     * attribute descriptors. */

+    const Dwarf_Abbr_AT* at_abbr = die_abbr->process(NULL, &die_tag);

+

+    /* Instantiate DIE object for this DIE, and get list of properties,

+     * that should be collected while processing that DIE. */

+    DIEObject* die_obj =

+      create_die_object(parse_context, die, parent_obj, die_tag);

+    if (die_obj == NULL && errno != 0) {

+      return NULL;

+    }

+

+    if (die_obj != NULL) {

+      if (parent_obj != NULL) {

+        /* Update list of parent's children. */

+        die_obj->link_sibling(parent_obj->last_child());

+        parent_obj->link_child(die_obj);

+      } else {

+        /* NULL parent object is allowed only for CU DIE itself. */

+        assert(cu_die_ == NULL && die_tag == DW_TAG_compile_unit);

+        if (cu_die_ == NULL && die_tag != DW_TAG_compile_unit) {

+          _set_errno(EINVAL);

+          return NULL;

+        }

+        cu_die_ = die_obj;

+        /* This CU DIE object will be used as a parent for all DIE

+         * objects, created in this method. */

+        parent_obj = cu_die_;

+      }

+    }

+

+    // Loop through all DIE properties.

+    while (elf_file_->is_valid_abbr_ptr(at_abbr, sizeof(Dwarf_Abbr_AT)) &&

+           !at_abbr->is_separator()) {

+      Dwarf_At    at_value;

+      Dwarf_Form  at_form;

+      Dwarf_Value attr_value;

+

+      // Obtain next property value.

+      at_abbr = at_abbr->process(&at_value, &at_form);

+      die_attr = process_attrib(die_attr, at_form, &attr_value);

+

+      if (at_value == DW_AT_sibling) {

+        /* DW_AT_sibling means that next DIE is a child of the one that's

+         * being currently processed. We need to cache value of this property

+         * in order to correctly calculate next sibling of this DIE after

+         * child's DIE has been processed. */

+        assert(sibling_off == 0);

+        sibling_off = attr_value.u32;

+      }

+    }

+

+    /* Next DIE immediately follows last property for the current DIE. */

+    die = reinterpret_cast<const Dwarf_DIE*>(die_attr);

+    if (sibling_off != 0) {

+      // Process child DIE.

+      process_DIE(parse_context, die, die_obj != NULL ? die_obj : parent_obj);

+      // Next sibling DIE offset is relative to this CU's header beginning.

+      die = INC_CPTR_T(Dwarf_DIE, cu_header_, sibling_off);

+    }

+  }

+

+  return INC_CPTR_T(Elf_Byte, die, 1);

+}

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+DIEObject* DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::create_die_object(

+    const DwarfParseContext* parse_context,

+    const Dwarf_DIE* die,

+    DIEObject* parent,

+    Dwarf_Tag tag) {

+  DIEObject* ret = NULL;

+

+  /* We will always create a DIE object for CU DIE. */

+  if (tag == DW_TAG_compile_unit || collect_die(parse_context, tag)) {

+    ret = new(elf_file_) DIEObject(die, this, parent);

+    assert(ret != NULL);

+    if (ret == NULL) {

+      _set_errno(ENOMEM);

+    }

+  } else {

+    _set_errno(0);

+  }

+  return ret;

+}

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+bool DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::init_stmtl() {

+  if (stmtl_header_.unit_length != 0) {

+    return true;

+  }

+

+  assert(cu_die_ != NULL);

+  if (cu_die_ == NULL) {

+    _set_errno(EINVAL);

+    return false;

+  }

+

+  DIEAttrib stmtl;

+  if (!cu_die()->get_attrib(DW_AT_stmt_list, &stmtl)) {

+    _set_errno(EINVAL);

+    return false;

+  }

+

+  const void* stmtl_start =

+      INC_CPTR(elf_file()->get_debug_line_data(), stmtl.value()->u32);

+  if (*reinterpret_cast<const Elf_Word*>(stmtl_start) == 0xFFFFFFFF) {

+    cache_stmtl<Dwarf64_STMTLHdr>(reinterpret_cast<const Dwarf64_STMTLHdr*>(stmtl_start));

+  } else {

+    cache_stmtl<Dwarf32_STMTLHdr>(reinterpret_cast<const Dwarf32_STMTLHdr*>(stmtl_start));

+  }

+

+  return true;

+}

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+bool DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::get_pc_address_file_info(

+    Elf_Xword address,

+    Dwarf_AddressInfo* info) {

+  /* Make sure STMTL header is cached. */

+  if (!init_stmtl()) {

+    return false;

+  }

+  /* Flags address match, that should trigger return next time

+   * source line gets adjusted. */

+  bool found = false;

+  /* Create new state machine. */

+  DwarfStateMachine state(stmtl_header_.default_is_stmt != 0);

+

+  /* Start the "Line Number Program" */

+  const Elf_Byte* go = stmtl_header_.start;

+  while (go < stmtl_header_.end) {

+    const Elf_Byte op = *go;

+    go++;

+

+    if (op == 0) {

+      /* This is an extended opcode. */

+      Dwarf_Value op_size;

+

+      /* First ULEB128 contains opcode size, (excluding ULEB128 itself). */

+      go = reinterpret_cast<const Elf_Byte*>

+             (reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&op_size));

+      /* Next is the extended opcode. */

+      const Elf_Byte* ex_op_ptr = go;

+      switch (*ex_op_ptr) {

+        case DW_LNE_end_sequence:

+          state.end_sequence_ = true;

+          state.reset(stmtl_header_.default_is_stmt != 0);

+          found = false;

+          break;

+

+        case DW_LNE_set_address: {

+          Elf_Xword prev_address = state.address_;

+          if (is_CU_address_64()) {

+            state.address_ =

+              elf_file()->pull_val(reinterpret_cast<const Elf_Xword*>(ex_op_ptr + 1));

+          } else {

+            state.address_ =

+              elf_file()->pull_val(reinterpret_cast<const Elf_Word*>(ex_op_ptr + 1));

+          }

+          if (prev_address != 0 &&

+              address >= prev_address && address < state.address_) {

+            return set_source_info(&state, info);

+          } else if (address == state.address_) {

+            found = true;

+          }

+          break;

+        }

+

+        case DW_LNE_define_file: {

+          /* Parameters start with the directly encoded zero-terminated

+           * file name. */

+          state.set_file_info_ = INC_CPTR_T(Dwarf_STMTL_FileDesc, ex_op_ptr, 1);

+          assert(state.set_file_info_ != NULL);

+          if (state.set_file_info_ != NULL) {

+            ex_op_ptr = reinterpret_cast<const Elf_Byte*>(state.set_file_info_->process(NULL));

+          }

+          break;

+        }

+

+        case DW_LNE_set_discriminator: {

+          Dwarf_Value discr_val;

+          /* One parameter: discriminator's ULEB128 value. */

+          reinterpret_cast<const Dwarf_Leb128*>(ex_op_ptr + 1)->process_unsigned(&discr_val);

+          state.discriminator_ = discr_val.u32;

+          break;

+        }

+

+        default:

+          assert(0);

+          return false;

+      }

+      go += op_size.u32;

+    } else if (op < stmtl_header_.opcode_base) {

+      /* This is a standard opcode. */

+      switch (op) {

+        case DW_LNS_copy:

+          /* No parameters. */

+          state.basic_block_ = false;

+          state.prologue_end_ = false;

+          state.epilogue_begin_ = false;

+          break;

+

+        case DW_LNS_advance_pc: {

+          /* One parameter: ULEB128 value to add to the current address value

+           * in the state machine. */

+          Dwarf_Value addr_add;

+          go = reinterpret_cast<const Elf_Byte*>

+              (reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&addr_add));

+          Elf_Xword prev_address = state.address_;

+          state.address_ += addr_add.u64;

+          if (prev_address != 0 &&

+              address >= prev_address && address < state.address_) {

+            return set_source_info(&state, info);

+          } else if (address == state.address_) {

+            found = true;

+          }

+          break;

+        }

+

+        case DW_LNS_advance_line: {

+          /* One parameter: signed LEB128 value to add to the current line

+           * number in the state machine. */

+          Dwarf_Value line_add;

+          go = reinterpret_cast<const Elf_Byte*>

+              (reinterpret_cast<const Dwarf_Leb128*>(go)->process_signed(&line_add));

+          state.line_ += line_add.s32;

+          if (found) {

+            return set_source_info(&state, info);

+          }

+          break;

+        }

+

+        case DW_LNS_set_file: {

+          /* One parameter: ULEB128 value encoding current file number. */

+          Dwarf_Value file_num;

+          go = reinterpret_cast<const Elf_Byte*>

+              (reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&file_num));

+          state.file_ = file_num.u32;

+          /* This operation should discard previously saved file information. */

+          state.set_file_info_ = NULL;

+          break;

+        }

+

+        case DW_LNS_set_column: {

+          /* One parameter: ULEB128 value encoding current column number. */

+          Dwarf_Value column_num;

+          go = reinterpret_cast<const Elf_Byte*>

+              (reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&column_num));

+          state.column_ = column_num.u32;

+          break;

+        }

+

+        case DW_LNS_negate_stmt:

+          /* No parameters. */

+          state.is_stmt_ = !state.is_stmt_;

+          break;

+

+        case DW_LNS_set_basic_block:

+          /* No parameters. */

+          state.basic_block_ = true;

+          break;

+

+        case DW_LNS_const_add_pc: {

+          Elf_Xword prev_address = state.address_;

+          /* No parameters. This operation does the same thing, as special

+           * opcode 255 would do to the current address. */

+          Elf_Word adjusted =

+              static_cast<Elf_Word>(255) - stmtl_header_.opcode_base;

+          state.address_ += (adjusted / stmtl_header_.line_range) *

+                            stmtl_header_.min_instruction_len;

+          if (prev_address != 0 &&

+              address >= prev_address && address < state.address_) {

+            return set_source_info(&state, info);

+          } else if (address == state.address_) {

+            found = true;

+          }

+          break;

+        }

+

+        case DW_LNS_fixed_advance_pc: {

+          Elf_Xword prev_address = state.address_;

+          /* One parameter: directly encoded 16-bit value to add to the

+           * current address. */

+          state.address_ +=

+              elf_file()->pull_val(reinterpret_cast<const Elf_Half*>(go));

+          if (prev_address != 0 &&

+              address >= prev_address && address < state.address_) {

+            return set_source_info(&state, info);

+          } else if (address == state.address_) {

+            found = true;

+          }

+          go += sizeof(Elf_Half);

+          break;

+        }

+

+        case DW_LNS_set_prologue_end:

+          /* No parameters. */

+          state.prologue_end_ = true;

+          break;

+

+        case DW_LNS_set_epilogue_begin:

+          /* No parameters. */

+          state.epilogue_begin_ = true;

+          break;

+

+        case DW_LNS_set_isa: {

+          /* One parameter: ISA value encoded as ULEB128. */

+          Dwarf_Value isa_val;

+          go = reinterpret_cast<const Elf_Byte*>

+              (reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&isa_val));

+          state.isa_ = isa_val.u32;

+          break;

+        }

+

+        default:

+          /* Unknown opcode. Just skip it. */

+          for (Elf_Byte uleb = 0;

+               uleb < stmtl_header_.standard_opcode_lengths[op - 1]; uleb++) {

+            Dwarf_Value tmp;

+            go = reinterpret_cast<const Elf_Byte*>

+              (reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&tmp));

+          }

+          break;

+      }

+    } else {

+      Elf_Xword prev_address = state.address_;

+      /* This is a special opcode. */

+      const Elf_Word adjusted = op - stmtl_header_.opcode_base;

+      /* Advance address. */

+      state.address_ += (adjusted / stmtl_header_.line_range) *

+                        stmtl_header_.min_instruction_len;

+      if (prev_address != 0 &&

+          address >= prev_address && address < state.address_) {

+        return set_source_info(&state, info);

+      }

+      /* Advance line. */

+      state.line_ += stmtl_header_.line_base +

+                     (adjusted % stmtl_header_.line_range);

+      if (state.address_ == address) {

+        return set_source_info(&state, info);

+      }

+      /* Do the woodoo. */

+      state.basic_block_ = false;

+      state.prologue_end_ = false;

+      state.epilogue_begin_ = false;

+    }

+  }

+

+  return false;

+}

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+const Dwarf_STMTL_FileDesc* DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::get_stmt_file_info(

+    Elf_Word index) {

+  /* Index must be 1-based. */

+  if (index == 0) {

+    return NULL;

+  }

+

+  const Dwarf_STMTL_FileDesc* cur_desc = stmtl_header_.file_infos;

+  while (index != 1 && !cur_desc->is_last_entry()) {

+    cur_desc = cur_desc->process(NULL);

+    index--;

+  }

+  assert(!cur_desc->is_last_entry());

+  return cur_desc->is_last_entry() ? NULL : cur_desc;

+}

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+const char* DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::get_stmt_dir_name(

+    Elf_Word dir_index) {

+  if (dir_index == 0) {

+    /* Requested is current compilation directory. */

+    return comp_dir_path();

+  }

+  if (dir_index > stmtl_header_.inc_dir_num) {

+    return NULL;

+  }

+

+  const char* cur_dir = stmtl_header_.include_directories;

+  while (dir_index != 1) {

+    cur_dir += strlen(cur_dir) + 1;

+    dir_index--;

+  }

+  return cur_dir;

+}

+

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+bool DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::set_source_info(

+    const DwarfStateMachine* state,

+    Dwarf_AddressInfo* info) {

+  info->line_number = state->line_;

+  const Dwarf_STMTL_FileDesc* file_info = state->set_file_info_;

+  if (file_info == NULL) {

+    file_info = get_stmt_file_info(state->file_);

+    if (file_info == NULL) {

+      info->file_name = rel_cu_path();

+      info->dir_name = comp_dir_path();

+      return true;

+    }

+  }

+  info->file_name = file_info->get_file_name();

+  const Elf_Word dir_index = file_info->get_dir_index();

+  info->dir_name = get_stmt_dir_name(dir_index);

+  return true;

+}

+

diff --git a/elff/dwarf_cu.h b/elff/dwarf_cu.h
new file mode 100644
index 0000000..a8f0578
--- /dev/null
+++ b/elff/dwarf_cu.h
@@ -0,0 +1,513 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains declaration of a class DwarfCU, that encapsulates a compilation

+ * unit in the .debug_info section of the mapped ELF file.

+ */

+

+#ifndef ELFF_DWARF_CU_H_

+#define ELFF_DWARF_CU_H_

+

+#include "dwarf_defs.h"

+#include "dwarf_die.h"

+

+/* Address information descriptor. */

+typedef struct Dwarf_AddressInfo {

+  /* Routine DIE containing the address. */

+  const DIEObject*  die_obj;

+

+  /* Source file name for the address. */

+  const char*       file_name;

+

+  /* Source file directory path for the address. */

+  const char*       dir_name;

+

+  /* Source file line number for the address. */

+  Elf_Word          line_number;

+} Dwarf_AddressInfo;

+

+/* STMTL header cached by compilation unit. This header is contained in

+ * the .debug_line section of the ELF file. */

+typedef struct Dwarf_STMTL_Hdr {

+  /* The size in bytes of the line number information for this compilation

+   * unit, not including the unit_length field itself. */

+  Elf_Xword                   unit_length;

+

+  /* A version number. This number is specific to the line number information

+   * and is independent of the DWARF version number. */

+  Elf_Half                    version;

+

+  /* The number of bytes following the header_length field to the beginning of

+   * the first byte of the line number program itself. In the 32-bit DWARF

+   * format, this is a 4-byte unsigned length; in the 64-bit DWARF format,

+   * this field is an 8-byte unsigned length. */

+  Elf_Xword                   header_length;

+

+  /* The size in bytes of the smallest target machine instruction. Line number

+   * program opcodes that alter the address register first multiply their

+   * operands by this value. */

+  Elf_Byte                    min_instruction_len;

+

+  /* The initial value of the is_stmt register. */

+  Elf_Byte                    default_is_stmt;

+

+  /* This parameter affects the meaning of the special opcodes. */

+  Elf_Sbyte                   line_base;

+

+  /* This parameter affects the meaning of the special opcodes. */

+  Elf_Byte                    line_range;

+

+  /* The number assigned to the first special opcode. */

+  Elf_Byte                    opcode_base;

+

+  /* Points to standard_opcode_lengths array in the actual STMTL header in

+   * the mapped .debug_line section. */

+  const Elf_Byte*             standard_opcode_lengths;

+

+  /* Pointer to the beginning of the list of include directories in the mapped

+   * .debug_line section. */

+  const char*                 include_directories;

+

+  /* Number of include directories in the list that begins with

+   * include_directories. */

+  Elf_Word                    inc_dir_num;

+

+  /* Pointer to the beginning of the list of file information in the mapped

+   * .debug_line section. Each entry in this list begins with zero-terminated

+   * file name, followed by ULEB128 encoding directory index for the file,

+   * followed by ULEB128 encoding last modification time, followed by ULEB128

+   * encoding length of file in bytes. */

+  const Dwarf_STMTL_FileDesc* file_infos;

+

+  /* Start of the "Line Number Program" in the mapped .debug_line section. */

+  const Elf_Byte*             start;

+

+  /* End of the "Line Number Program" in the mapped .debug_line section. */

+  const Elf_Byte*             end;

+} Dwarf_STMTL_Hdr;

+

+/* Encapsulates architecture-independent functionality of a

+ * compilation unit.

+ */

+class DwarfCU : public DwarfAllocBase {

+friend class ElfFile;

+ public:

+  /* Constructs DwarfCU instance.

+   * Param:

+   *  elf - Instance of ElfFile containing this compilation unit.

+   */

+  explicit DwarfCU(ElfFile* elf);

+

+  /* Destructs DwarfCU instance. */

+  virtual ~DwarfCU();

+

+  /* Creates DwarfCUImpl instance, depending on DWARF format.

+   * Param:

+   *  elf - Instance of ElfFile containing this compilation unit.

+   *  hdr - Pointer to compilation unit header inside mapped .debug_info

+   *    section of the ELF file. Actual data addressed by this pointer

+   *    must be Dwarf32_CUHdr for 32 bit DWARFs, or Dwarf64_CUHdr for

+   *    64 bit DWARFs.

+   * Return:

+   *  Created DwarfCUImpl instance (typecasted back to DwarfCU) on success,

+   *  or NULL on failure.

+   */

+  static DwarfCU* create_instance(ElfFile* elf, const void* hdr);

+

+  /* Process a DIE attribute.

+   * Param:

+   *  attr - Attribute list inside the mapped .debug_info section of the ELF

+   *    file.

+   *  form - Attribute's form, definig representation of attribute value in the

+   *    mapped .debug_info section of the ELF file.

+   *  attr_value - Upon return contains attribute value.

+   * Return:

+   *  Pointer to the next DIE attribute inside the mapped .debug_info section

+   *  of the ELF file.

+   */

+  const Elf_Byte* process_attrib(const Elf_Byte* attr,

+                                 Dwarf_Form form,

+                                 Dwarf_Value* attr_value) const;

+

+  /* Dumps this compilation unit to the stdout. */

+  void dump() const;

+

+  /* Gets instance of ElfFile containing this compilation unit. */

+  ElfFile* elf_file() const {

+    return elf_file_;

+  }

+

+  /* Gets DIE object for this CU. */

+  DIEObject* cu_die() const {

+    return cu_die_;

+  }

+

+  /* Gets byte size of the pointer type for this compilation unit. */

+  Elf_Byte addr_sizeof() const {

+    return addr_sizeof_;

+  }

+

+  /* Gets full path to the compilation directory (DW_AT_comp_dir attribute).

+   * Return:

+   *  Full path to the compilation directory (DW_AT_comp_dir attribute),

+   *  or NULL, if that attribute was missing in CU's attribute list.

+   */

+  const char* comp_dir_path() const {

+    DIEAttrib attr;

+    return cu_die()->get_attrib(DW_AT_comp_dir, &attr) ? attr.value()->str :

+                                                         NULL;

+  }

+

+  /* Gets relative (from the compilation directory) path to the compiled file.

+   * (DW_AT_name attribute).

+   * Return:

+   *  Relative path to the compiled file (DW_AT_name attribute), or NULL, if

+   *  that attribute was missing in CU's attribute list.

+   */

+  const char* rel_cu_path() const {

+    DIEAttrib attr;

+    return cu_die()->get_attrib(DW_AT_name, &attr) ? attr.value()->str :

+                                                     NULL;

+  }

+

+  /* Gets next compilation unit in the list. NULL indicates the last CU. */

+  DwarfCU* prev_cu() const {

+    return prev_cu_;

+  }

+

+  /* Links this CU to the list of prevoiusly discovered CUs. */

+  void set_prev_cu(DwarfCU* prev) {

+    prev_cu_ = prev;

+  }

+

+  /* Checks if DWARF version for this CU is higher than 2. */

+  bool is_DWARF3_or_higher() const {

+    return version_ >= 3;

+  }

+

+  /* Gets DIE abbreviation for given abbreviation number.

+   * See DwarfAbbrDieArray::get() */

+  const Dwarf_Abbr_DIE* get_die_abbr(Dwarf_AbbrNum num) const {

+    return abbrs_.get(num);

+  }

+

+  /* Gets DIE object containing given address.

+   * DIE address ranges may overlap (for instance, address range for an inlined

+   * routine will be contained within the address range of a routine where it

+   * was inlined). This method will return a DIE object that is a "leaf" in

+   * that inlining tree. I.e the returned DIE object represents the last DIE

+   * in the branch of all DIEs containing given address.

+   * Param:

+   *  address - Address to get a DIE for. NOTE: for the sake of simplicity we

+   *    explicitly use 64-bit type for an address.

+   * Return:

+   *  Leaf DIE containing given address, or NULL if this CU doesn't contain

+   *  the given address.

+   */

+  DIEObject* get_leaf_die_for_address(Elf_Xword address) const {

+    return cu_die_->get_leaf_for_address(address);

+  }

+

+  /* Checks if this CU contains 64, or 32-bit addresses. */

+  bool is_CU_address_64() const {

+    return addr_sizeof_ == 8;

+  }

+  bool is_CU_address_32() const {

+    return addr_sizeof_ == 4;

+  }

+

+//=============================================================================

+// DWARF format dependent methods

+//=============================================================================

+

+ public:

+  /* Parses this compilation unit in .debug_info section, collecting children

+   * DIEs of this compilation unit.

+   * Param:

+   *  parse_context - Parsing context that lists tags for DIEs that should be

+   *    collected during parsing. NULL passed in this parameter indicates DIEs

+   *    for all tags should be collected.

+   *  next_cu_die - Upon successful return contains pointer to the next

+   *    compilation unit descriptor inside mapped .debug_info section of

+   *    the ELF file.

+   * Return:

+   *  true on success, false on failure.

+   */

+  virtual bool parse(const DwarfParseContext* parse_context,

+                     const void** next_cu_die) = 0;

+

+  /* Gets a DIE object referenced by an offset from the beginning of

+   * this CU in the mapped .debug_info section.

+   */

+  virtual DIEObject* get_referenced_die_object(Elf_Word ref) const = 0;

+

+  /* Gets a reference to a DIE object (offset of the DIE from the

+   * beginning of this CU in the mapped .debug_info section.

+   */

+  virtual Elf_Word get_die_reference(const Dwarf_DIE* die) const = 0;

+

+  /* Gets PC address information.

+   * Param:

+   *  address - PC address to get information for.

+   *  info - Upon success contains information about routine that belongs to

+   *    this compilation unit, containing the given address.

+   * Return:

+   *  true on success, or false if this CU doesn't contain the given address.

+   */

+  virtual bool get_pc_address_file_info(Elf_Xword address,

+                                        Dwarf_AddressInfo* info) = 0;

+

+  /* Gets file descriptor in the mapped .debug_line section of ELF file for a

+   * given index in the file descriptor list.

+   * Param:

+   *  index - 1-based index of file descriptor in the file descriptor list.

+   * Return:

+   *  File descriptor for the given index, or NULL if index was too big.

+   *  NOTE: pointer returned from this method addressed mapped section of

+   *  ELF file.

+   */

+  virtual const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index) = 0;

+

+  /* Gets directory name by an index in the mapped .debug_line section of

+   * ELF file.

+   * Param:

+   *  dir_index - Index of the directory in the file descriptor list. If this

+   *    parameter is zero, compilation directory (DW_AT_comp_dir) for this CU

+   *    will be returned.

+   * Return:

+   *  Directory name for the given index, or NULL if index was too big.

+   *  NOTE: pointer returned from this method addressed mapped section of

+   *  ELF file.

+   */

+  virtual const char* get_stmt_dir_name(Elf_Word dir_index) = 0;

+

+ protected:

+  /* DIE abbreviation descriptors, cached for this compilation unit. */

+  DwarfAbbrDieArray   abbrs_;

+

+  /* Instance of an ELF file that contains this compilation unit. */

+  ElfFile*            elf_file_;

+

+  /* DIE object for this CU. */

+  DIEObject*          cu_die_;

+

+  /* Next compilation unit in the list (previous in the order they've been

+   * discovered during ELF file parsing).

+   */

+  DwarfCU*            prev_cu_;

+

+  /* DWARF version for this CU. */

+  Elf_Half            version_;

+

+  /* Byte size of the pointer type for this compilation unit. */

+  Elf_Byte            addr_sizeof_;

+};

+

+/* Encapsulates architecture-dependent functionality of a compilation unit.

+ * Template param:

+ *  Dwarf_CUHdr - type compilation unit header in the mapped .debug_info

+ *    section of ELF file. Must be:

+ *    - Dwarf32_CUHdr for 32-bit DWARF, or

+ *    - Dwarf64_CUHdr for 64-bit DWARF.

+ *  Dwarf_Off - type for an offset field in DWARF data format. Must be:

+ *    - Dwarf32_Off for 32-bit DWARF, or

+ *    - Dwarf64_Off for 64-bit DWARF.

+ */

+template <typename Dwarf_CUHdr, typename Dwarf_Off>

+class DwarfCUImpl : public DwarfCU {

+ public:

+  /* Constructs DwarfCU instance.

+   * Param:

+   *  elf - Instance of ElfFile containing this compilation unit.

+   *  hdr - Pointer to compilation unit header inside mapped .debug_info

+   *    section of the ELF file.

+   */

+  DwarfCUImpl(ElfFile* elf, const Dwarf_CUHdr* hdr);

+

+  /* Destructs DwarfCU instance. */

+  ~DwarfCUImpl() {

+  }

+

+  /* Parses this compilation unit in .debug_info section, collecting children

+   * DIEs of this compilation unit. This is an implementation of DwarfCU's

+   * abstract metod.

+   * See DwarfCU::parse().

+   */

+  bool parse(const DwarfParseContext* parse_context,

+             const void** next_cu_die);

+

+  /* Gets PC address information.

+   * This is an implementation of DwarfCU's abstract metod.

+   * See DwarfCU::get_pc_address_file_info().

+   */

+  bool get_pc_address_file_info(Elf_Xword address, Dwarf_AddressInfo* info);

+

+  /* Gets file descriptor in the mapped .debug_line section of ELF file for a

+   * given index in the file descriptor list.

+   * This is an implementation of DwarfCU's abstract metod.

+   * See DwarfCU::get_stmt_file_info().

+   */

+  const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index);

+

+  /* Gets directory name by an index in the mapped .debug_line section of

+   * ELF file.

+   * This is an implementation of DwarfCU's abstract metod.

+   * See DwarfCU::get_stmt_dir_name().

+   */

+  const char* get_stmt_dir_name(Elf_Word dir_index);

+

+  /* Gets a DIE object referenced by an offset from the beginning of

+   * this CU. This is an implementation of DwarfCU's abstract metod.

+   */

+  DIEObject* get_referenced_die_object(Elf_Word ref) const {

+    const Dwarf_DIE* die = get_referenced_die(ref);

+    return cu_die_->find_die_object(die);

+  }

+

+  /* Gets a reference to a DIE object (offset of the DIE from the

+   * beginning of this CU in the mapped .debug_info section.

+   * This is an implementation of DwarfCU's abstract metod.

+   */

+  Elf_Word get_die_reference(const Dwarf_DIE* die) const {

+    return static_cast<Elf_Word>(diff_ptr(cu_header_, die));

+  }

+

+ protected:

+  /* Process a child DIE (and all its children) in this compilation unit.

+   * Param:

+   *  parse_context - See DwarfCU::parse().

+   *  die - DIE descriptor of the child to process in this method.

+   *  parent_obj - Parent object of the child to process in this method.

+   *    NOTE: this parameter can be NULL only for a DIE that represents this

+   *    compilation unit itself.

+   * Return:

+   *  Pointer to the end of child's attribute list in the mapped .debug_info

+   *  section on success, or NULL on failure. Usually, pointer returned from

+   *  this method is simply discarded, since parent calculates address of the

+   *  next sibling's DIE based on DW_AT_sibling attribute of the DIE preceding

+   *  child's DIE.

+   */

+  const Elf_Byte* process_DIE(const DwarfParseContext* parse_context,

+                              const Dwarf_DIE* die,

+                              DIEObject* parent_obj);

+

+  /* Creates a DIE object for the given DIE.

+   * Param:

+   *  parse_context See DwarfCU::parse().

+   *  die - DIE to create an object for.

+   *  parent - Parent DIE object for the one that's being created in this

+   *    method.

+   *  tag - Tag of the DIE object that's being created in this method.

+   * Return:

+   *  Created DIE object. This method may returns NULL in two cases:

+   *    - We're not interested in this DIE (decided by looking at 'tag'

+   *      parameter. In this case errno should be set to zero.

+   *    - Memory allocation has failed. In this case errno should be

+   *      set to ENOMEM.

+   */

+  DIEObject* create_die_object(const DwarfParseContext* parse_context,

+                               const Dwarf_DIE* die,

+                               DIEObject* parent,

+                               Dwarf_Tag tag);

+

+  /* Initializes (caches) STMT lines header for this CU. */

+  bool init_stmtl();

+

+  /* Saves current source file information, collected in the state machine by

+   * the "Line Number Program".

+   * Param:

+   *  state - State machine collected "Line Number Program" results.

+   *  info - Upon success contains source file information, copied over from

+   *    the state machine.

+   * Return:

+   *  true on success, or false on failure.

+   */

+  bool set_source_info(const DwarfStateMachine* state,

+                       Dwarf_AddressInfo* info);

+

+  /* Gets pointer to the DIE descriptor for this CU. */

+  const Dwarf_DIE* get_DIE() const {

+    /* CU's DIE descriptor immediately follows CU header. */

+    return INC_CPTR_T(Dwarf_DIE, cu_header_, sizeof(Dwarf_CUHdr));

+  }

+

+  /* Caches STMTL header from .debug_line section to stmtl_header_.

+   * Template param:

+   *  Dwarf_STMTL_Hdr - Dwarf_STMTL_Hdr32, or Dwarf_STMTL_Hdr64, depending

+   *    on the header type.

+   * Param:

+   *  stmtl_hdr - STMTL header in the mapped .debug_line section to cache.

+   */

+  template <typename Dwarf_STMTL_Hdr>

+  void cache_stmtl(const Dwarf_STMTL_Hdr* stmtl_hdr) {

+    stmtl_header_.unit_length = elf_file()->pull_val(stmtl_hdr->unit_length.size);

+    stmtl_header_.version = elf_file()->pull_val(stmtl_hdr->version);

+    stmtl_header_.header_length = elf_file()->pull_val(stmtl_hdr->header_length);

+    stmtl_header_.min_instruction_len = stmtl_hdr->min_instruction_len;

+    stmtl_header_.default_is_stmt = stmtl_hdr->default_is_stmt;

+    stmtl_header_.line_base = stmtl_hdr->line_base;

+    stmtl_header_.line_range = stmtl_hdr->line_range;

+    stmtl_header_.opcode_base = stmtl_hdr->opcode_base;

+    stmtl_header_.standard_opcode_lengths = &stmtl_hdr->standard_opcode_lengths;

+    stmtl_header_.start = INC_CPTR_T(Elf_Byte, &stmtl_hdr->min_instruction_len,

+                                     stmtl_header_.header_length);

+    stmtl_header_.end = INC_CPTR_T(Elf_Byte, &stmtl_hdr->version,

+                                   stmtl_header_.unit_length);

+    stmtl_header_.include_directories =

+        INC_CPTR_T(char, stmtl_header_.standard_opcode_lengths,

+                   stmtl_header_.opcode_base - 1);

+    const char* dir = stmtl_header_.include_directories;

+    while (*dir != '\0') {

+      dir += strlen(dir) + 1;

+      stmtl_header_.inc_dir_num++;

+    }

+    stmtl_header_.file_infos = INC_CPTR_T(Dwarf_STMTL_FileDesc, dir, 1);

+  }

+

+  /* Gets a DIE referenced by an offset from the beginning of this CU

+   * in the mapped .debug_info section.

+   */

+  const Dwarf_DIE* get_referenced_die(Elf_Word ref) const {

+    return INC_CPTR_T(Dwarf_DIE, cu_header_, ref);

+  }

+

+  /* Checks if pointer to the DIE attribute is contained within the CU's area

+   * of the mapped .debug_info section.

+   * Param:

+   *  ptr - Pointer to the DIE attribute to check.

+   * Return:

+   *  true, if pointer to the DIE attribute is contained within the CU's area

+   *  of the mapped .debug_info section, or false if attribute pointer goes

+   *  beyond CU's area of the mapped .debug_info section.

+   */

+  bool is_attrib_ptr_valid(const void* ptr) const {

+    return diff_ptr(cu_header_, ptr) < cu_size_;

+  }

+

+ protected:

+  /* Pointer to this compilation unit header inside the mapped .debug_info

+   * section of the ELF file.

+   */

+  const Dwarf_CUHdr*          cu_header_;

+

+  /* Size of this compilation unit area in the mapped .debug_info section.

+   * This value has been cached off the CU header in order to avoid

+   * endianness conversions.

+   */

+  Dwarf_Off                   cu_size_;

+

+  /* STMT lines header, cached off mapped .debug_line section. */

+  Dwarf_STMTL_Hdr             stmtl_header_;

+};

+

+#endif  // ELFF_DWARF_CU_H_

diff --git a/elff/dwarf_defs.h b/elff/dwarf_defs.h
new file mode 100644
index 0000000..567df6a
--- /dev/null
+++ b/elff/dwarf_defs.h
@@ -0,0 +1,1000 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains declarations of types, constants and structures

+ * describing DWARF format.

+ */

+

+#ifndef ELFF_DWARF_DEFS_H_

+#define ELFF_DWARF_DEFS_H_

+

+#include "dwarf.h"

+#include "elf_defs.h"

+

+/* DWARF structures are packed to 1 byte. */

+#define ELFF_PACKED __attribute__ ((packed))

+

+/*

+ * Helper types for misc. DWARF variables.

+ */

+

+/* Type for DWARF abbreviation number. */

+typedef uint32_t  Dwarf_AbbrNum;

+

+/* Type for DWARF tag ID. */

+typedef uint16_t  Dwarf_Tag;

+

+/* Type for DWARF attribute ID. */

+typedef uint16_t  Dwarf_At;

+

+/* Type for DWARF form ID. */

+typedef uint16_t  Dwarf_Form;

+

+/* Type for offset in 32-bit DWARF. */

+typedef uint32_t  Dwarf32_Off;

+

+/* Type for offset in 64-bit DWARF. */

+typedef uint64_t  Dwarf64_Off;

+

+/* Enumerates types of values, obtained during DWARF attribute decoding. */

+typedef enum DwarfValueType {

+  /* Undefined */

+  DWARF_VALUE_UNKNOWN = 1,

+

+  /* uint8_t */

+  DWARF_VALUE_U8,

+

+  /* int8_t */

+  DWARF_VALUE_S8,

+

+  /* uint16_t */

+  DWARF_VALUE_U16,

+

+  /* int16_t */

+  DWARF_VALUE_S16,

+

+  /* uint32_t */

+  DWARF_VALUE_U32,

+

+  /* int32_t */

+  DWARF_VALUE_S32,

+

+  /* uint64_t */

+  DWARF_VALUE_U64,

+

+  /* int64_t */

+  DWARF_VALUE_S64,

+

+  /* const char* */

+  DWARF_VALUE_STR,

+

+  /* 32-bit address */

+  DWARF_VALUE_PTR32,

+

+  /* 64-bit address */

+  DWARF_VALUE_PTR64,

+

+  /* Dwarf_Block */

+  DWARF_VALUE_BLOCK,

+} DwarfValueType;

+

+/* Describes block of data, stored directly in the mapped .debug_info

+ * section. This type is used to represent an attribute encoded with

+ * DW_FORM_block# form.

+ */

+typedef struct Dwarf_Block {

+  /* Pointer to the block data inside mapped .debug_info section. */

+  const void*   block_ptr;

+

+  /* Byte size of the block data. */

+  Elf_Word      block_size;

+} Dwarf_Block;

+

+/* Describes a value, obtained from the mapped .debug_info section

+ * during DWARF attribute decoding.

+ */

+typedef struct Dwarf_Value {

+  /* Unites all possible data types for the value.

+   * See DwarfValueType for the list of types.

+   */

+  union {

+    Elf_Byte      u8;

+    Elf_Sbyte     s8;

+    Elf_Half      u16;

+    Elf_Shalf     s16;

+    Elf_Word      u32;

+    Elf_Sword     s32;

+    Elf_Xword     u64;

+    Elf_Sxword    s64;

+    Elf_Word      ptr32;

+    Elf_Xword     ptr64;

+    const char*   str;

+    Dwarf_Block   block;

+  };

+

+  /* Value type (defines which variable in the union abowe

+   * contains the value).

+   */

+  DwarfValueType  type;

+

+  /* Number of bytes that encode this value in .debug_info section

+   * of ELF file.

+   */

+  Elf_Word        encoded_size;

+} Dwarf_Value;

+

+/* DWARF's LEB128 data type. LEB128 is defined as:

+ * Variable Length Data. "Little Endian Base 128" (LEB128) numbers. LEB128 is

+ * a scheme for encoding integers densely that exploits the assumption that

+ * most integers are small in magnitude. (This encoding is equally suitable

+ * whether the target machine architecture represents data in big-endian or

+ * littleendian order. It is "little endian" only in the sense that it avoids

+ * using space to represent the "big" end of an unsigned integer, when the big

+ * end is all zeroes or sign extension bits).

+ *

+ * Unsigned LEB128 numbers are encoded as follows: start at the low order end

+ * of an unsigned integer and chop it into 7-bit chunks. Place each chunk into

+ * the low order 7 bits of a byte. Typically, several of the high order bytes

+ * will be zero; discard them. Emit the remaining bytes in a stream, starting

+ * with the low order byte; set the high order bit on each byte except the last

+ * emitted byte. The high bit of zero on the last byte indicates to the decoder

+ * that it has encountered the last byte. The integer zero is a special case,

+ * consisting of a single zero byte.

+ *

+ * The encoding for signed LEB128 numbers is similar, except that the criterion

+ * for discarding high order bytes is not whether they are zero, but whether

+ * they consist entirely of sign extension bits. Consider the 32-bit integer

+ * -2. The three high level bytes of the number are sign extension, thus LEB128

+ * would represent it as a single byte containing the low order 7 bits, with

+ * the high order bit cleared to indicate the end of the byte stream. Note that

+ * there is nothing within the LEB128 representation that indicates whether an

+ * encoded number is signed or unsigned. The decoder must know what type of

+ * number to expect.

+ *

+ * NOTE: It's assumed that LEB128 will not contain encodings for integers,

+ * larger than 64 bit.

+*/

+typedef struct ELFF_PACKED Dwarf_Leb128 {

+  /* Beginning of the LEB128 block. */

+  Elf_Byte  val;

+

+  /* Pulls actual value, encoded with this LEB128 block.

+   * Param:

+   *  value - Upon return will contain value, encoded with this LEB128 block.

+   *  sign - If true, the caller expects the LEB128 to contain a signed

+   *    integer, otherwise, caller expects an unsigned integer value to be

+   *    encoded with this LEB128 block.

+   */

+  void get_common(Dwarf_Value* value, bool sign) const {

+    value->u64 = 0;

+    /* Integer zero is a special case. */

+    if (val == 0) {

+      value->type = sign ? DWARF_VALUE_S32 : DWARF_VALUE_U32;

+      value->encoded_size = 1;

+      return;

+    }

+

+    /* We've got to reconstruct the integer. */

+    value->type = DWARF_VALUE_UNKNOWN;

+    value->encoded_size = 0;

+

+    /* Byte by byte loop though the LEB128, reconstructing the integer from

+     * 7-bits chunks. Byte with 8-th bit set to zero indicates the end

+     * of the LEB128 block. For signed integers, 7-th bit of the last LEB128

+     * byte controls the sign. If 7-th bit of the last LEB128 byte is set,

+     * the integer is negative. If 7-th bit of the last LEB128 byte is not

+     * set, the integer is positive.

+     */

+    const Elf_Byte* cur = &val;

+    Elf_Word shift = 0;

+    while ((*cur & 0x80) != 0) {

+      value->u64 |= (static_cast<Elf_Xword>(*cur) & 0x7F) << shift;

+      shift += 7;

+      value->encoded_size++;

+      cur++;

+    }

+    value->u64 |= (static_cast<Elf_Xword>(*cur) & 0x7F) << shift;

+    value->encoded_size++;

+

+    /* LEB128 format doesn't carry any info of the sizeof of the integer it

+     * represents. We well guess it, judging by the highest bit set in the

+     * reconstucted integer.

+     */

+    if ((value->u64 & 0xFFFFFFFF00000000LL) == 0) {

+      /* 32-bit integer. */

+      if (sign) {

+        value->type = DWARF_VALUE_S32;

+        if (((*cur) & 0x40) != 0) {

+          // Value is negative.

+          value->u64 |= - (1 << (shift + 7));

+        } else if ((value->u32 & 0x80000000) != 0) {

+          // Make sure we don't report negative value in this case.

+          value->type = DWARF_VALUE_S64;

+        }

+      } else {

+        value->type = DWARF_VALUE_U32;

+      }

+    } else {

+      /* 64-bit integer. */

+      if (sign) {

+        value->type = DWARF_VALUE_S64;

+        if (((*cur) & 0x40) != 0) {

+          // Value is negative.

+          value->u64 |= - (1 << (shift + 7));

+        }

+      } else {

+        value->type = DWARF_VALUE_U64;

+      }

+    }

+  }

+

+  /* Pulls actual unsigned value, encoded with this LEB128 block.

+   * See get_common() for more info.

+   * Param:

+   *  value - Upon return will contain unsigned value, encoded with

+   *  this LEB128 block.

+   */

+  void get_unsigned(Dwarf_Value* value) const {

+    get_common(value, false);

+  }

+

+  /* Pulls actual signed value, encoded with this LEB128 block.

+   * See get_common() for more info.

+   * Param:

+   *  value - Upon return will contain signed value, encoded with

+   *  this LEB128 block.

+   */

+  void get_signed(Dwarf_Value* value) const {

+    get_common(value, true);

+  }

+

+  /* Pulls LEB128 value, advancing past this LEB128 block.

+   * See get_common() for more info.

+   * Return:

+   *  Pointer to the byte past this LEB128 block.

+   */

+  const void* process(Dwarf_Value* value, bool sign) const {

+    get_common(value, sign);

+    return INC_CPTR(&val, value->encoded_size);

+  }

+

+  /* Pulls LEB128 unsigned value, advancing past this LEB128 block.

+   * See process() for more info.

+   */

+  const void* process_unsigned(Dwarf_Value* value) const {

+    return process(value, false);

+  }

+

+  /* Pulls LEB128 signed value, advancing past this LEB128 block.

+   * See process() for more info.

+   */

+  const void* process_signed(Dwarf_Value* value) const {

+    return process(value, true);

+  }

+} Dwarf_Leb128;

+

+/* DIE attribute descriptor in the .debug_abbrev section.

+ * Attribute descriptor contains two LEB128 values. First one provides

+ * attribute ID (one of DW_AT_XXX values), and the second one provides

+ * format (one of DW_FORMAT_XXX values), in which attribute value is

+ * encoded in the .debug_info section of the ELF file.

+ */

+typedef struct ELFF_PACKED Dwarf_Abbr_AT {

+  /* Attribute ID (DW_AT_XXX).

+   * Attribute format (DW_FORMAT_XXX) follows immediately.

+   */

+  Dwarf_Leb128  at;

+

+  /* Checks if this is a separator descriptor.

+   * Zero is an invalid attribute ID, indicating the end of attribute

+   * list for the current DIE.

+   */

+  bool is_separator() const {

+    return at.val == 0;

+  }

+

+  /* Pulls attribute data, advancing past this descriptor.

+   * Param:

+   *  at_value - Upon return contains attribute value of this descriptor.

+   *  form - Upon return contains form value of this descriptor.

+   * Return:

+   *  Pointer to the byte past this descriptor block (usually, next

+   *  attribute decriptor).

+   */

+  const Dwarf_Abbr_AT* process(Dwarf_At* at_value, Dwarf_Form* form) const {

+    if (is_separator()) {

+      /* Size of separator descriptor is always 2 bytes. */

+      *at_value = 0;

+      *form = 0;

+      return INC_CPTR_T(Dwarf_Abbr_AT, &at.val, 2);

+    }

+

+    Dwarf_Value val;

+

+    /* Process attribute ID. */

+    const Dwarf_Leb128* next =

+        reinterpret_cast<const Dwarf_Leb128*>(at.process_unsigned(&val));

+    *at_value = val.u16;

+

+    /* Follow with processing the form. */

+    next = reinterpret_cast<const Dwarf_Leb128*>(next->process_unsigned(&val));

+    *form = val.u16;

+    return reinterpret_cast<const Dwarf_Abbr_AT*>(next);

+  }

+} Dwarf_Abbr_AT;

+

+/* DIE abbreviation descriptor in the .debug_abbrev section.

+ * DIE abbreviation descriptor contains three parameters. The first one is a

+ * LEB128 value, that encodes 1 - based abbreviation descriptor number.

+ * Abbreviation descriptor numbers seems to be always in sequential order, and

+ * are counted on per-compilation unit basis. I.e. abbreviation number for the

+ * first DIE abbreviation descriptor of each compilation unit is always 1.

+ *

+ * Besides abbreviation number, DIE abbreviation descriptor contains two more

+ * values. The first one (after abbr_num) is a LEB128 value containing DIE's

+ * tag value, and the second one is one byte flag specifying whether or not

+ * the DIE contains any cildren.

+ *

+ * This descriptor is immediately followed by a list of attribute descriptors

+ * (see Dwarf_Abbr_AT) for the DIE represented by this abbreviation descriptor.

+ */

+typedef struct ELFF_PACKED Dwarf_Abbr_DIE {

+  /* 1 - based abbreviation number for the DIE. */

+  Dwarf_Leb128  abbr_num;

+

+  /* Gets abbreviation number for this descriptor. */

+  Dwarf_AbbrNum get_abbr_num() const {

+    Dwarf_Value val;

+    abbr_num.get_unsigned(&val);

+    return val.u16;

+  }

+

+  /* Gets DIE tag for this descriptor. */

+  Dwarf_Tag get_tag() const {

+    Dwarf_Tag tag;

+    process(NULL, &tag);

+    return tag;

+  }

+

+  /* Pulls DIE abbreviation descriptor data, advancing past this descriptor.

+   * Param:

+   *  abbr_index - Upon return contains abbreviation number for this

+   *    descriptor. This parameter can be NULL, if the caller is not interested

+   *    in this value.

+   *  tag - Upon return contains tag of the DIE for this descriptor. This

+   *    parameter can be NULL, if the caller is not interested in this value.

+   *  form - Upon return contains form of the DIE for this descriptor.

+   * Return:

+   *  Pointer to the list of attribute descriptors for the DIE.

+   */

+  const Dwarf_Abbr_AT* process(Dwarf_AbbrNum* abbr_index,

+                               Dwarf_Tag* tag) const {

+    Dwarf_Value val;

+    const Dwarf_Leb128* next =

+        reinterpret_cast<const Dwarf_Leb128*>(abbr_num.process_unsigned(&val));

+    if (abbr_index != NULL) {

+      *abbr_index = val.u32;

+    }

+

+    /* Next one is a "tag". */

+    next = reinterpret_cast<const Dwarf_Leb128*>(next->process_unsigned(&val));

+    if (tag != NULL) {

+      *tag = val.u16;

+    }

+

+    /* Next one is a "has children" one byte flag. We're not interested in it,

+     * so jump to the list of attribute descriptors that immediately follows

+     * this DIE descriptor. */

+    return INC_CPTR_T(Dwarf_Abbr_AT, next, 1);

+  }

+} Dwarf_Abbr_DIE;

+

+/* DIE descriptor in the .debug_info section.

+ * DIE descriptor contains one LEB128-encoded value, containing DIE's

+ * abbreviation descriptor number in the .debug_abbrev section.

+ *

+ * DIE descriptor is immediately followed by the list of DIE attribute values,

+ * format of wich is defined by the list of attribute descriptors in the

+ * .debug_abbrev section, that immediately follow the DIE attribute descriptor,

+ * addressed by this descriptor's abbr_num LEB128.

+ */

+typedef struct ELFF_PACKED Dwarf_DIE {

+  /* 1 - based index of DIE abbreviation descriptor (Dwarf_Abbr_DIE) for this

+   * DIE in the .debug_abbrev section.

+   *

+   * NOTE: DIE abbreviation descriptor indexes are tied to the compilation

+   * unit. In other words, each compilation unit restarts counting DIE

+   * abbreviation descriptors from 1.

+   *

+   * NOTE: Zero is invalid value for this field, indicating that this DIE is a

+   * separator (usually it ends a list of "child" DIEs)

+   */

+  Dwarf_Leb128  abbr_num;

+

+  /* Checks if this is a separator DIE. */

+  bool is_separator() const {

+    return abbr_num.val == 0;

+  }

+

+  /* Gets (1 - based) abbreviation number for this DIE. */

+  Dwarf_AbbrNum get_abbr_num() const {

+    Dwarf_Value val;

+    abbr_num.get_unsigned(&val);

+    return val.u16;

+  }

+

+  /* Pulls DIE information, advancing past this descriptor to DIE attributes.

+   * Param:

+   *  abbr_num - Upon return contains abbreviation number for this DIE. This

+   *    parameter can be NULL, if the caller is not interested in this value.

+   * Return:

+   *  Pointer to the byte past this descriptor (the list of DIE attributes).

+   */

+  const Elf_Byte* process(Dwarf_AbbrNum* abbr_number) const {

+    if (is_separator()) {

+      if (abbr_number != NULL) {

+        *abbr_number = 0;

+      }

+      // Size of a separator DIE is 1 byte.

+      return INC_CPTR_T(Elf_Byte, &abbr_num.val, 1);

+    }

+    Dwarf_Value val;

+    const void* ret = abbr_num.process_unsigned(&val);

+    if (abbr_number != NULL) {

+      *abbr_number = val.u32;

+    }

+    return reinterpret_cast<const Elf_Byte*>(ret);

+  }

+} Dwarf_DIE;

+

+/*

+ * Variable size headers.

+ * When encoding size value in DWARF, the first 32 bits of a "size" header

+ * define header type. If first 32 bits of the header contain 0xFFFFFFFF

+ * value, this is 64-bit size header with the following 64 bits encoding

+ * the size. Otherwise, if first 32 bits are not 0xFFFFFFFF, they contain

+ * 32-bit size value.

+ */

+

+/* Size header for 32-bit DWARF. */

+typedef struct ELFF_PACKED Dwarf32_SizeHdr {

+  /* Size value. */

+  Elf_Word  size;

+} Dwarf32_SizeHdr;

+

+/* Size header for 64-bit DWARF. */

+typedef struct ELFF_PACKED Dwarf64_SizeHdr {

+  /* Size selector. For 64-bit DWARF this field is set to 0xFFFFFFFF */

+  Elf_Word  size_selector;

+

+  /* Actual size value. */

+  Elf_Xword   size;

+} Dwarf64_SizeHdr;

+

+/* Compilation unit header in the .debug_info section.

+ * Template param:

+ *  Dwarf_SizeHdr - Type for the header's size field. Must be Dwarf32_SizeHdr

+ *    for 32-bit DWARF, or Dwarf64_SizeHdr for 64-bit DWARF.

+ *  Elf_Off - Type for abbrev_offset field. Must be Elf_Word for for 32-bit

+ *    DWARF, or Elf_Xword for 64-bit DWARF.

+ */

+template <typename Dwarf_SizeHdr, typename Elf_Off>

+struct ELFF_PACKED Dwarf_CUHdr {

+  /* Size of the compilation unit data in .debug_info section. */

+  Dwarf_SizeHdr   size_hdr;

+

+  /* Compilation unit's DWARF version stamp. */

+  Elf_Half        version;

+

+  /* Relative (to the beginning of .debug_abbrev section data) offset of the

+   * beginning of abbreviation sequence for this compilation unit.

+   */

+  Elf_Off         abbrev_offset;

+

+  /* Pointer size for this compilation unit (should be 4, or 8). */

+  Elf_Byte        address_size;

+};

+/* Compilation unit header in the .debug_info section for 32-bit DWARF. */

+typedef Dwarf_CUHdr<Dwarf32_SizeHdr, Elf_Word> Dwarf32_CUHdr;

+/* Compilation unit header in the .debug_info section for 64-bit DWARF. */

+typedef Dwarf_CUHdr<Dwarf64_SizeHdr, Elf_Xword> Dwarf64_CUHdr;

+

+/* CU STMTL header in the .debug_line section.

+ * Template param:

+ *  Dwarf_SizeHdr - Type for the header's size field. Must be Dwarf32_SizeHdr

+ *    for 32-bit DWARF, or Dwarf64_SizeHdr for 64-bit DWARF.

+ *  Elf_Size - Type for header_length field. Must be Elf_Word for for 32-bit

+ *    DWARF, or Elf_Xword for 64-bit DWARF.

+ */

+template <typename Dwarf_SizeHdr, typename Elf_Size>

+struct ELFF_PACKED Dwarf_STMTLHdr {

+  /* The size in bytes of the line number information for this compilation

+   * unit, not including the unit_length field itself. */

+  Dwarf_SizeHdr unit_length;

+

+  /* A version number. This number is specific to the line number information

+   * and is independent of the DWARF version number. */

+  Elf_Half      version;

+

+  /* The number of bytes following the header_length field to the beginning of

+   * the first byte of the line number program itself. In the 32-bit DWARF

+   * format, this is a 4-byte unsigned length; in the 64-bit DWARF format,

+   * this field is an 8-byte unsigned length. */

+  Elf_Size      header_length;

+

+  /* The size in bytes of the smallest target machine instruction. Line number

+   * program opcodes that alter the address register first multiply their

+   * operands by this value. */

+  Elf_Byte      min_instruction_len;

+

+  /* The initial value of the is_stmt register. */

+  Elf_Byte      default_is_stmt;

+

+  /* This parameter affects the meaning of the special opcodes. */

+  Elf_Sbyte     line_base;

+

+  /* This parameter affects the meaning of the special opcodes. */

+  Elf_Byte      line_range;

+

+  /* The number assigned to the first special opcode. */

+  Elf_Byte      opcode_base;

+

+  /* This is first opcode in an array specifying the number of LEB128 operands

+   * for each of the standard opcodes. The first element of the array

+   * corresponds to the opcode whose value is 1, and the last element

+   * corresponds to the opcode whose value is opcode_base - 1. By increasing

+   * opcode_base, and adding elements to this array, new standard opcodes can

+   * be added, while allowing consumers who do not know about these new opcodes

+   * to be able to skip them. NOTE: this array points to the mapped

+   * .debug_line section. */

+  Elf_Byte      standard_opcode_lengths;

+};

+/* CU STMTL header in the .debug_line section for 32-bit DWARF. */

+typedef Dwarf_STMTLHdr<Dwarf32_SizeHdr, Elf_Word> Dwarf32_STMTLHdr;

+/* CU STMTL header in the .debug_line section for 64-bit DWARF. */

+typedef Dwarf_STMTLHdr<Dwarf64_SizeHdr, Elf_Xword> Dwarf64_STMTLHdr;

+

+/* Source file descriptor in the .debug_line section.

+ * Descriptor begins with zero-terminated file name, followed by an ULEB128,

+ * encoding directory index in the list of included directories, followed by

+ * an ULEB12, encoding file modification time, followed by an ULEB12, encoding

+ * file size.

+ */

+typedef struct ELFF_PACKED Dwarf_STMTL_FileDesc {

+  /* Zero-terminated file name. */

+  char  file_name[1];

+

+  /* Checks of this descriptor ends the list. */

+  bool is_last_entry() const {

+    return file_name[0] == '\0';

+  }

+

+  /* Gets file name. */

+  const char* get_file_name() const {

+    return file_name;

+  }

+

+  /* Processes this descriptor, advancing to the next one.

+   * Param:

+   *  dir_index - Upon return contains index of the parent directory in the

+   *    list of included directories. Can be NULL if caller is not interested

+   *    in this value.

+   * Return:

+   *  Pointer to the next source file descriptor in the list.

+   */

+  const Dwarf_STMTL_FileDesc* process(Elf_Word* dir_index) const {

+    if (is_last_entry()) {

+      return this;

+    }

+

+    /* First parameter: include directory index. */

+    Dwarf_Value tmp;

+    const Dwarf_Leb128* leb =

+        INC_CPTR_T(Dwarf_Leb128, file_name, strlen(file_name) + 1);

+    leb = reinterpret_cast<const Dwarf_Leb128*>(leb->process_unsigned(&tmp));

+    if (dir_index != NULL) {

+      *dir_index = tmp.u32;

+    }

+    /* Process file time. */

+    leb = reinterpret_cast<const Dwarf_Leb128*>(leb->process_unsigned(&tmp));

+    /* Process file size. */

+    return reinterpret_cast<const Dwarf_STMTL_FileDesc*>(leb->process_unsigned(&tmp));

+  }

+

+  /* Gets directory index for this descriptor. */

+  Elf_Word get_dir_index() const {

+    assert(!is_last_entry());

+    if (is_last_entry()) {

+      return 0;

+    }

+    /* Get directory index. */

+    Dwarf_Value ret;

+    const Dwarf_Leb128* leb =

+      INC_CPTR_T(Dwarf_Leb128, file_name, strlen(file_name) + 1);

+    leb->process_unsigned(&ret);

+    return ret.u32;

+  }

+} Dwarf_STMTL_FileDesc;

+

+/* Encapsulates a DIE attribute, collected during ELF file parsing.

+ */

+class DIEAttrib {

+ public:

+  /* Constructs DIEAttrib intance. */

+  DIEAttrib()

+      : at_(0),

+        form_(0) {

+    value_.type = DWARF_VALUE_UNKNOWN;

+  }

+

+  /* Destructs DIEAttrib intance. */

+  ~DIEAttrib() {

+  }

+

+  /* Gets DWARF attribute ID (DW_AT_Xxx) for this property. */

+  Dwarf_At at() const {

+    return at_;

+  }

+

+  /* Gets DWARF form ID (DW_FORM_Xxx) for this property. */

+  Dwarf_Form form() const {

+    return form_;

+  }

+

+  /* Gets value of this property. */

+  const Dwarf_Value* value() const {

+    return &value_;

+  }

+

+  /* Value of this property. */

+  Dwarf_Value   value_;

+

+  /* DWARF attribute ID (DW_AT_Xxx) for this property. */

+  Dwarf_At      at_;

+

+  /* DWARF form ID (DW_FORM_Xxx) for this property. */

+  Dwarf_Form    form_;

+};

+

+/* Parse tag context.

+ * This structure is used as an ELF file parsing parameter, limiting collected

+ * DIEs by the list of tags.

+ */

+typedef struct DwarfParseContext {

+  /* Zero-terminated list of tags to collect DIEs for. If this field is NULL,

+   * DIEs for all tags will be collected during the parsing. */

+  const Dwarf_Tag*  tags;

+} DwarfParseContext;

+

+/* Checks if a DIE with the given tag should be collected during the parsing.

+ * Param:

+ *  parse_context - Parse context to check the tag against. This parameter can

+ *  be NULL, indicating that all tags should be collected.

+ *  tag - Tag to check.

+ * Return:

+ *  true if a DIE with the given tag should be collected during the parsing,

+ *  or false, if the DIE should not be collected.

+ */

+static inline bool

+collect_die(const DwarfParseContext* parse_context, Dwarf_Tag tag) {

+  if (parse_context == NULL || parse_context->tags == NULL) {

+    return true;

+  }

+  for (const Dwarf_Tag* tags = parse_context->tags; *tags != 0; tags++) {

+    if (*tags == tag) {

+      return true;

+    }

+  }

+  return false;

+}

+

+/* Encapsulates an array of Dwarf_Abbr_DIE pointers, cached for a compilation

+ * unit. Although Dwarf_Abbr_DIE descriptors in the .debug_abbrev section of

+ * the ELF file seems to be always in sequential order, DIE descriptors may

+ * reference them randomly. So, to provide better performance, we will cache

+ * all Dwarf_Abbr_DIE pointers, that were found for each DIE. Since all of the

+ * Dwarf_Abbr_DIE are sequential, an array is the best way to cache them.

+ *

+ * NOTE: Objects of this class are instantiated one per each CU, as all DIE

+ * abbreviation numberation is restarted from 1 for each new CU.

+ */

+class DwarfAbbrDieArray {

+ public:

+  /* Constructs DwarfAbbrDieArray instance.

+   * Most of the CUs don't have too many unique Dwarf_Abbr_DIEs, so, in order

+   * to decrease the amount of memory allocation calls, we will preallocate

+   * a relatively small array for them along with the instance of this class,

+   * hopping, that all Dwarf_Abbr_DIEs for the CU will fit into it.

+   */

+  DwarfAbbrDieArray()

+      : count_(0),

+        array_size_(ELFF_ARRAY_SIZE(small_array_)),

+        array_(&small_array_[0]) {

+  }

+

+  /* Destructs DwarfAbbrDieArray instance. */

+  ~DwarfAbbrDieArray() {

+    if (array_ != &small_array_[0]) {

+      delete[] array_;

+    }

+  }

+

+  /* Adds new entry to the array

+   * Param:

+   *  abbr - New entry to add.

+   *  num - Abbreviation number for the adding entry.

+   *    NOTE: before adding, this method will verify that descriptor for the

+   *    given abbreviation number has not been cached yet.

+   *    NOTE: due to the nature of this array, entries MUST be added strictly

+   *    in sequential order.

+   * Return:

+   *  true on success, false on failure.

+   */

+  bool add(const Dwarf_Abbr_DIE* abbr, Dwarf_AbbrNum num) {

+    assert(num != 0);

+    if (num == 0) {

+      // Zero is illegal DIE abbreviation number.

+      _set_errno(EINVAL);

+      return false;

+    }

+

+    if (num <= count_) {

+      // Already cached.

+      return true;

+    }

+

+    // Enforce strict sequential order.

+    assert(num == (count_ + 1));

+    if (num != (count_ + 1)) {

+      _set_errno(EINVAL);

+      return false;

+    }

+

+    if (num >= array_size_) {

+      /* Expand the array. Make it 64 entries bigger than adding entry number.

+       * NOTE: that we don't check for an overflow here, since we secured

+       * ourselves from that by enforcing strict sequential order. So, an

+       * overflow may happen iff number of entries cached in this array is

+       * close to 4G, which is a) totally unreasonable, and b) we would die

+       * long before this amount of entries is cached.

+       */

+      Dwarf_AbbrNum new_size = num + 64;

+

+      // Reallocate.

+      const Dwarf_Abbr_DIE** new_array = new const Dwarf_Abbr_DIE*[new_size];

+      assert(new_array != NULL);

+      if (new_array == NULL) {

+        _set_errno(ENOMEM);

+        return false;

+      }

+      memcpy(new_array, array_, count_ * sizeof(const Dwarf_Abbr_DIE*));

+      if (array_ != &small_array_[0]) {

+        delete[] array_;

+      }

+      array_ = new_array;

+      array_size_ = new_size;

+    }

+

+    // Abbreviation numbers are 1-based.

+    array_[num - 1] = abbr;

+    count_++;

+    return true;

+  }

+

+  /* Adds new entry to the array

+   * Param:

+   *  abbr - New entry to add.

+   * Return:

+   *  true on success, false on failure.

+   */

+  bool add(const Dwarf_Abbr_DIE* abbr) {

+    return add(abbr, abbr->get_abbr_num());

+  }

+

+  /* Gets an entry from the array

+   * Param:

+   *  num - 1-based index of an entry to get.

+   * Return:

+   *  Entry on success, or NULL if num exceeds the number of entries

+   *  contained in the array.

+   */

+  const Dwarf_Abbr_DIE* get(Dwarf_AbbrNum num) const {

+    assert(num != 0 && num <= count_);

+    if (num != 0 && num <= count_) {

+      return array_[num - 1];

+    } else {

+      _set_errno(EINVAL);

+      return NULL;

+    }

+  }

+

+  /* Caches Dwarf_Abbr_DIEs into this array up to the requested number.

+   * NOTE: This method cannot be called on an empty array. Usually, first

+   * entry is inserted into this array when CU object is initialized.

+   * Param:

+   *  num - Entry number to cache entries up to.

+   * Return:

+   *  Last cached entry (actually, an entry for the 'num' index).

+   */

+  const Dwarf_Abbr_DIE* cache_to(Dwarf_AbbrNum num) {

+    /* Last cached DIE abbreviation. We always should have cached at least one

+     * abbreviation for the CU DIE itself, added via "add" method when CU

+     * object was initialized. */

+    const Dwarf_Abbr_DIE* cur_abbr = get(count_);

+    assert(cur_abbr != NULL);

+    if (cur_abbr == NULL) {

+      return NULL;

+    }

+

+    /* Starting with the last cached DIE abbreviation, loop through the

+     * remaining DIE abbreviations in the .debug_abbrev section of the

+     * mapped ELF file, caching them until we reach the requested

+     * abbreviation descriptor number. Normally, the very next DIE

+     * abbreviation will stop the loop. */

+    while (num > count_) {

+      Dwarf_AbbrNum abbr_num;

+      Dwarf_Tag tmp2;

+      Dwarf_Form tmp3;

+      Dwarf_At tmp4;

+

+      /* Process all AT abbreviations for the current DIE entry, reaching next

+       * DIE abbreviation. */

+      const Dwarf_Abbr_AT* abbr_at = cur_abbr->process(&abbr_num, &tmp2);

+      while (!abbr_at->is_separator()) {

+        abbr_at = abbr_at->process(&tmp4, &tmp3);

+      }

+

+      // Next DIE abbreviation is right after the separator AT abbreviation.

+      cur_abbr = reinterpret_cast<const Dwarf_Abbr_DIE*>

+                                              (abbr_at->process(&tmp4, &tmp3));

+      if (!add(cur_abbr)) {

+        return NULL;

+      }

+    }

+

+    return array_[num - 1];

+  }

+

+  /* Empties array and frees allocations. */

+  void empty() {

+    if (array_ != &small_array_[0]) {

+      delete[] array_;

+      array_ = &small_array_[0];

+      array_size_ = sizeof(small_array_) / sizeof(small_array_[0]);

+    }

+    count_ = 0;

+  }

+

+ protected:

+  /* Array, preallocated in anticipation of relatively small number of

+   * DIE abbreviations in compilation unit. */

+  const Dwarf_Abbr_DIE*   small_array_[64];

+

+  /* Array of Dwarf_Abbr_DIE pointers, cached for a compilation unit. */

+  const Dwarf_Abbr_DIE**  array_;

+

+  /* Current size of the array. */

+  Dwarf_AbbrNum           array_size_;

+

+  /* Number of entries, cached in the array. */

+  Dwarf_AbbrNum           count_;

+};

+

+/* Encapsulates a state machine for the "Line Number Program", that is run

+ * on data conained in the mapped .debug_line section.

+ */

+class DwarfStateMachine {

+ public:

+  /* Constructs DwarfStateMachine instance.

+   * Param:

+   *  set_is_stmt - Matches value of default_is_stmt field in the STMTL header.

+   *    see Dwarf_STMTL_HdrXX.

+   */

+  explicit DwarfStateMachine(bool set_is_stmt)

+    : address_(0),

+      file_(1),

+      line_(1),

+      column_(0),

+      discriminator_(0),

+      is_stmt_(set_is_stmt),

+      basic_block_(false),

+      end_sequence_(false),

+      prologue_end_(false),

+      epilogue_begin_(false),

+      isa_(0),

+      set_file_info_(NULL) {

+  }

+

+  /* Destructs DwarfStateMachine instance. */

+  ~DwarfStateMachine() {

+  }

+

+  /* Resets the state to default.

+   * Param:

+   *  set_is_stmt - Matches value of default_is_stmt field in the STMTL header.

+   *    see Dwarf_STMTL_HdrXX.

+  */

+  void reset(bool set_is_stmt) {

+    address_ = 0;

+    file_ = 1;

+    line_ = 1;

+    column_ = 0;

+    discriminator_ = 0;

+    is_stmt_ = set_is_stmt;

+    basic_block_ = false;

+    end_sequence_ = false;

+    prologue_end_ = false;

+    epilogue_begin_ = false;

+    isa_ = 0;

+    set_file_info_ = NULL;

+  }

+

+  /*

+   * Machine state.

+   */

+

+  /* Current address (current PC value). */

+  Elf_Xword                   address_;

+

+  /* Current index of source file descriptor. */

+  Elf_Word                    file_;

+

+  /* Current line in the current source file. */

+  Elf_Word                    line_;

+

+  /* Current column. */

+  Elf_Word                    column_;

+

+  /* Current discriminator value. */

+  Elf_Word                    discriminator_;

+

+  /* Current STMT flag. */

+  bool                        is_stmt_;

+

+  /* Current basic block flag. */

+  bool                        basic_block_;

+

+  /* Current end of sequence flag. */

+  bool                        end_sequence_;

+

+  /* Current end of prologue flag. */

+  bool                        prologue_end_;

+

+  /* Current epilogue begin flag. */

+  bool                        epilogue_begin_;

+

+  /* Current ISA value. */

+  Elf_Word                    isa_;

+

+  /* Current value for explicitly set current source file descriptor.

+   * If not NULL, this descriptor has priority over the descriptor, addressed

+   * by the file_ member of this class. */

+  const Dwarf_STMTL_FileDesc* set_file_info_;

+};

+

+/* Checks if given tag belongs to a routine. */

+static inline bool

+dwarf_tag_is_routine(Dwarf_Tag tag) {

+  return tag == DW_TAG_inlined_subroutine ||

+         tag == DW_TAG_subprogram ||

+         tag == DW_AT_main_subprogram;

+}

+

+/* Checks if given tag belongs to a compilation unit. */

+static inline bool

+dwarf_tag_is_cu(Dwarf_Tag tag) {

+  return tag == DW_TAG_compile_unit ||

+         tag == DW_TAG_partial_unit;

+}

+

+#endif  // ELFF_DWARF_DEFS_H_

diff --git a/elff/dwarf_die.cc b/elff/dwarf_die.cc
new file mode 100644
index 0000000..2085e31
--- /dev/null
+++ b/elff/dwarf_die.cc
@@ -0,0 +1,269 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains implementations of classes defined for a variety of DWARF objects.

+ */

+

+#include "stdio.h"

+#include "dwarf_die.h"

+#include "dwarf_cu.h"

+#include "dwarf_utils.h"

+#include "elf_file.h"

+

+DIEObject::~DIEObject() {

+  /* Delete all children of this object. */

+  DIEObject* to_del = last_child();

+  while (to_del != NULL) {

+    DIEObject* next = to_del->prev_sibling();

+    delete to_del;

+    to_del = next;

+  }

+}

+

+ElfFile* DIEObject::elf_file() const {

+  return parent_cu()->elf_file();

+}

+

+Dwarf_Tag DIEObject::get_tag() const {

+  Dwarf_Tag tag;

+  return advance(NULL, &tag) != NULL ? tag : 0;

+}

+

+const char* DIEObject::get_name() const {

+  DIEAttrib die_attr;

+  /* Start with the obvious. */

+  if (get_attrib(DW_AT_name, &die_attr)) {

+    return die_attr.value()->str;

+  }

+

+  /* Lets see if there is a reference to the abstract origin, or specification,

+   * and use its name as the name for this DIE. */

+  if (get_attrib(DW_AT_abstract_origin, &die_attr) ||

+      get_attrib(DW_AT_specification, &die_attr)) {

+    DIEObject* org_die_obj =

+        parent_cu()->get_referenced_die_object(die_attr.value()->u32);

+    if (org_die_obj != NULL) {

+      return org_die_obj->get_name();

+    }

+  }

+

+  /* Lets see if there is a reference to the type DIE, and use

+   * its name as the name for this DIE. */

+  if (get_attrib(DW_AT_type, &die_attr)) {

+    DIEObject* org_die_obj =

+        parent_cu()->get_referenced_die_object(die_attr.value()->u32);

+    if (org_die_obj != NULL) {

+      return org_die_obj->get_name();

+    }

+  }

+

+  /* Can't figure the name for this DIE. */

+  return NULL;

+}

+

+bool DIEObject::get_attrib(Dwarf_At at_id, DIEAttrib* attr) const {

+  const Dwarf_Abbr_AT* at_abbr;

+

+  /* Advance to DIE attributes. */

+  const Elf_Byte* die_attr = advance(&at_abbr, NULL);

+  if (die_attr == NULL) {

+    _set_errno(EINVAL);

+    return false;

+  }

+

+  /* Loop through all DIE attributes, looking for the one that's being

+   * requested. */

+  while (!at_abbr->is_separator()) {

+    at_abbr = at_abbr->process(&attr->at_, &attr->form_);

+    die_attr = parent_cu()->process_attrib(die_attr, attr->form_, &attr->value_);

+    if (at_id == attr->at()) {

+      return true;

+    }

+  }

+

+  _set_errno(EINVAL);

+

+  return false;

+}

+

+DIEObject* DIEObject::get_leaf_for_address(Elf_Xword address) {

+  const bool contains = parent_cu()->is_CU_address_64() ?

+                            contains_address<Elf_Xword>(address) :

+                            contains_address<Elf_Word>(address);

+  if (!contains && !is_cu_die()) {

+    /* For CU DIEs address range may be zero size, even though its child DIEs

+     * occupie some address space. So, if CU DIE's address range doesn't

+     * contain the given address, we still want to go and check the children.

+     */

+    _set_errno(EINVAL);

+    return NULL;

+  }

+

+  /* This DIE contains given address (or may contain it, if this is a CU DIE).

+   * Lets iterate through child DIEs to find the leaf (last DIE) that contains

+   * this address. */

+  DIEObject* child = last_child();

+  while (child != NULL) {

+    DIEObject* leaf = child->get_leaf_for_address(address);

+    if (leaf != NULL) {

+      return leaf;

+    }

+    child = child->prev_sibling();

+  }

+  /* No child DIE contains this address. This DIE is the leaf. */

+  return contains || !is_cu_die() ? this : NULL;

+}

+

+template <typename AddrType>

+bool DIEObject::contains_address(Elf_Xword address) {

+  DIEAttrib die_ranges;

+  /* DIE can contain either list of ranges (f.i. DIEs that represent a routine

+   * that is inlined in multiple places will contain list of address ranges

+   * where that routine is inlined), or a pair "low PC, and high PC" describing

+   * contiguos address space where routine has been placed by compiler. */

+  if (get_attrib(DW_AT_ranges, &die_ranges)) {

+    /* Iterate through this DIE's ranges list, looking for the one that

+     * contains the given address. */

+    AddrType low;

+    AddrType high;

+    Elf_Word range_off = die_ranges.value()->u32;

+    while (elf_file()->get_range(range_off, &low, &high) &&

+           (low != 0 || high != 0)) {

+      if (address >= low && address < high) {

+        return true;

+      }

+      range_off += sizeof(AddrType) * 2;

+    }

+    return false;

+  } else {

+    /* This DIE doesn't have ranges. Lets see if it has low_pc and high_pc

+     * attributes. */

+    DIEAttrib low_pc;

+    DIEAttrib high_pc;

+    if (!get_attrib(DW_AT_low_pc, &low_pc) ||

+        !get_attrib(DW_AT_high_pc, &high_pc) ||

+        address < low_pc.value()->u64 ||

+        address >= high_pc.value()->u64) {

+      return false;

+    }

+    return true;

+  }

+}

+

+DIEObject* DIEObject::find_die_object(const Dwarf_DIE* die_to_find) {

+  if (die_to_find == die()) {

+    return this;

+  }

+

+  /* First we will iterate through the list of children, since chances to

+   * find requested DIE decrease as we go deeper into DIE tree. */

+  DIEObject* iter = last_child();

+  while (iter != NULL) {

+    if (iter->die() == die_to_find) {

+      return iter;

+    }

+    iter = iter->prev_sibling();

+  };

+

+  /* DIE has not been found among the children. Lets go deeper now. */

+  iter = last_child();

+  while (iter != NULL) {

+    DIEObject* ret = iter->find_die_object(die_to_find);

+    if (ret != NULL) {

+      return ret;

+    }

+    iter = iter->prev_sibling();

+  }

+

+  _set_errno(EINVAL);

+  return NULL;

+}

+

+void DIEObject::dump(bool only_this) const {

+  const Dwarf_Abbr_AT*  at_abbr;

+  Dwarf_Tag             tag;

+

+  const Elf_Byte* die_attr = advance(&at_abbr, &tag);

+  if (die_attr != NULL) {

+    printf("\n********** DIE[%p(%04X)] %s: %s **********\n",

+           die_, parent_cu()->get_die_reference(die_), dwarf_tag_name(tag),

+           get_name());

+

+    /* Dump this DIE attributes. */

+    while (!at_abbr->is_separator()) {

+      DIEAttrib attr;

+      at_abbr = at_abbr->process(&attr.at_, &attr.form_);

+      die_attr = parent_cu()->process_attrib(die_attr, attr.form(), &attr.value_);

+      dump_attrib(attr.at(), attr.form(), attr.value());

+      if (attr.at() == DW_AT_ranges) {

+        /* Dump all ranges for this DIE. */

+        Elf_Word off = attr.value()->u32;

+        if (parent_cu()->is_CU_address_64()) {

+          Elf_Xword low, high;

+          while (elf_file()->get_range<Elf_Xword>(off, &low, &high) &&

+                 (low != 0 || high != 0)) {

+            printf("                                %08I64X - %08I64X\n",

+                   low, high);

+            off += 16;

+          }

+        } else {

+          Elf_Word low, high;

+          while (elf_file()->get_range<Elf_Word>(off, &low, &high) &&

+                 (low != 0 || high != 0)) {

+            printf("                                %08X - %08X\n",

+                   low, high);

+            off += 8;

+          }

+        }

+      }

+    }

+  }

+

+  if (only_this) {

+    if (parent_die_ != NULL && !parent_die_->is_cu_die()) {

+      printf("\n-----------> CHILD OF:\n");

+      parent_die_->dump(true);

+    }

+  } else {

+    /* Dump this DIE's children. */

+    if (last_child() != NULL) {

+        last_child()->dump(false);

+    }

+

+    /* Dump this DIE's siblings. */

+    if (prev_sibling() != NULL) {

+      prev_sibling()->dump(false);

+    }

+  }

+}

+

+const Elf_Byte* DIEObject::advance(const Dwarf_Abbr_AT** at_abbr,

+                                   Dwarf_Tag* tag) const {

+  Dwarf_AbbrNum abbr_num;

+  Dwarf_Tag     die_tag;

+

+  const Elf_Byte* die_attr = die()->process(&abbr_num);

+  const Dwarf_Abbr_DIE* abbr = parent_cu()->get_die_abbr(abbr_num);

+  if (abbr == NULL) {

+    return NULL;

+  }

+

+  const Dwarf_Abbr_AT* attrib_abbr = abbr->process(NULL, &die_tag);

+  if (at_abbr != NULL) {

+    *at_abbr = attrib_abbr;

+  }

+  if (tag != NULL) {

+    *tag = die_tag;

+  }

+  return die_attr;

+}

diff --git a/elff/dwarf_die.h b/elff/dwarf_die.h
new file mode 100644
index 0000000..21dea37
--- /dev/null
+++ b/elff/dwarf_die.h
@@ -0,0 +1,202 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains declarations of classes defined for a variety of DWARF objects.

+ */

+

+#ifndef ELFF_DWARF_DIE_H_

+#define ELFF_DWARF_DIE_H_

+

+#include "dwarf_defs.h"

+#include "elf_alloc.h"

+

+class ElfFile;

+class DwarfCU;

+

+/* Encapsulates an object that wraps up a DIE, cached during

+ * ELF file parsing.

+ */

+class DIEObject : public DwarfAllocBase {

+ public:

+  /* Constructs DIEObject intance.

+   * Param:

+   *  die - DIE represented with this instance.

+   *  parent_cu - Compilation unit this DIE belongs to.

+   *  parent_die - Parent DIE object for this DIE. This parameter can be NULL

+   *    only for compilation unit DIEs.

+   */

+  DIEObject(const Dwarf_DIE* die, DwarfCU* parent_cu, DIEObject* parent_die)

+      : die_(die),

+        parent_cu_(parent_cu),

+        parent_die_(parent_die),

+        prev_sibling_(NULL),

+        last_child_(NULL) {

+  }

+

+  /* Destructs DIEObject intance. */

+  ~DIEObject();

+

+  /* Gets ELF file this DIE belongs to. */

+  ElfFile* elf_file() const;

+

+  /* Gets DWARF tag (DW_TAG_Xxx) for the DIE represented with this instance. */

+  Dwarf_Tag get_tag() const;

+

+  /* Gets the best name for this DIE.

+   * Some DIEs (such as inline routine DIEs) may have no DW_AT_name property,

+   * but may reference to another DIE that may contain DIE name. This method

+   * tries its best to get DIE name by iterating through different methods of

+   * naming the DIE.

+   * Return:

+   *  Name for this DIE, or NULL if it was not possible to find a relevant DIE

+   *  with DW_AT_name property.

+   */

+  const char* get_name() const;

+

+  /* Gets DIE's attribute by its ID.

+   * Param:

+   *  at_id - ID (DW_AT_Xxx) of the attribute to get.

+   *  attr - Upon successful return contains requested attribute information.

+   * Return:

+   *  true on success, or false if attribute for the given ID doesn't exist

+   *  in the DIE's attribute list.

+   */

+  bool get_attrib(Dwarf_At at, DIEAttrib* attr) const;

+

+  /* Gets the leaf DIE object containing given address.

+   * See DwarfCU::get_leaf_die_for_address() for method details.

+   * See DIEObject::contains_address() for implementation details.

+   */

+  DIEObject* get_leaf_for_address(Elf_Xword address);

+

+  /* Finds a DIE object for the given die in the branch starting with

+   * this DIE object.

+   */

+  DIEObject* find_die_object(const Dwarf_DIE* die_to_find);

+

+  /* Dumps this object to stdout.

+   * Param:

+   *  only_this - If true, only this object will be dumped. If this parameter

+   *    is false, all the childs and siblings of this object will be dumped

+   *    along with this object.

+   */

+  void dump(bool only_this) const;

+

+ protected:

+  /* Checks if this DIE object containing given address.

+   * Template param:

+   *  AddrType - Type of compilation unin address (4, or 8 bytes), defined by

+   *    address_size field of the CU header. Must be Elf_Xword for 8 bytes

+   *    address, or Elf_Word for 4 bytes address.

+   * Param:

+   *  address - Address ti check.

+   * Return:

+   *  True, if this DIE address ranges (including low_pc, high_pc attributes)

+   *  contain given address, or false otherwise.

+   */

+  template <typename AddrType>

+  bool contains_address(Elf_Xword address);

+

+  /* Advances to the DIE's property list.

+   * Param:

+   *  at_abbr - Upon successful return contains a pointer to the beginning of

+   *    DIE attribute abbreviation list. This parameter can be NULL, if the

+   *    caller is not interested in attribute abbreviation list for this DIE.

+   *  tag - Upon successful return contains DIE's tag. This parameter can be

+   *    NULL, if the caller is not interested in the tag value for this DIE.

+   * Return:

+   *  Pointer to the beginning of the DIE attribute list in mapped .debug_info

+   *  section on success, or NULL on failure.

+   */

+  const Elf_Byte* advance(const Dwarf_Abbr_AT** at_abbr, Dwarf_Tag* tag) const;

+

+ public:

+  /* Gets DIE represented with this instance. */

+  const Dwarf_DIE* die() const {

+    return die_;

+  }

+

+  /* Gets compilation unit this DIE belongs to. */

+  DwarfCU* parent_cu() const {

+    return parent_cu_;

+  }

+

+  /* Gets parent DIE object for this die. */

+  DIEObject* parent_die() const {

+    return parent_die_;

+  }

+

+  /* Gets last child object in the list of this DIE's childs. NOTE: for better

+   * performace the list is created in reverse order (relatively to the order,

+   * in which children DIEs have been discovered).

+   */

+  DIEObject* last_child() const {

+    return last_child_;

+  }

+

+  /* Links next child to the list of this DIE childs. */

+  void link_child(DIEObject* child) {

+    last_child_ = child;

+  }

+

+  /* Gets previous sibling of this DIE in the parent's DIE object list. */

+  DIEObject* prev_sibling() const {

+    return prev_sibling_;

+  }

+

+  /* Links next sibling to the list of this DIE siblings. */

+  void link_sibling(DIEObject* sibl) {

+    prev_sibling_ = sibl;

+  }

+

+  /* Checks if this DIE object represents a CU DIE.

+   * We relay here on the fact that only CU DIE objects have no parent

+   * DIE objects.

+   */

+  bool is_cu_die() const {

+    return parent_die_ == NULL;

+  }

+

+  /* Gets this DIE level in the branch.

+   * DIE level defines DIE's distance from the CU DIE in the branch this DIE

+   * belongs to. In other words, DIE level defines how many parent DIEs exist

+   * between this DIE, and the CU DIE. For instance, the CU DIE has level 0,

+   * a subroutine a() in this compilation unit has level 1, a soubroutine b(),

+   * that has been inlined into subroutine a() will have level 2, a try/catch

+   * block in the inlined subroutine b() will have level 3, and so on.

+   */

+  Elf_Word get_level() const {

+    return parent_die_ != NULL ? parent_die_->get_level() + 1 : 0;

+  }

+

+ protected:

+  /* DIE that is represented with this instance. */

+  const Dwarf_DIE*  die_;

+

+  /* Compilation unit this DIE belongs to. */

+  DwarfCU*          parent_cu_;

+

+  /* Parent DIE object for this die. */

+  DIEObject*        parent_die_;

+

+  /* Last child object in the list of this DIE's childs. NOTE: for better

+   * performace the list is created in reverse order (relatively to the order,

+   * in which children DIEs have been discovered).

+   */

+  DIEObject*        last_child_;

+

+  /* Previous sibling of this DIE in the parent's DIE object list. */

+  DIEObject*        prev_sibling_;

+};

+

+#endif  // ELFF_DWARF_DIE_H_

diff --git a/elff/dwarf_utils.cc b/elff/dwarf_utils.cc
new file mode 100644
index 0000000..56c05a3
--- /dev/null
+++ b/elff/dwarf_utils.cc
@@ -0,0 +1,313 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains implementation of misc. DWARF utility routines.
+ */
+
+#include "stdio.h"
+#include "dwarf_utils.h"
+
+/* "Stringifies" the parameter. */
+#define DWARF_NAMEFY(val) case val: return "" #val ""
+
+/* "Stringifies" two parameters. */
+#define DWARF_NAMEFY2(val1, val2) case val1: return "" #val1 " | " #val2 ""
+
+const char*
+dwarf_at_name(Dwarf_At at) {
+  switch (at) {
+    DWARF_NAMEFY(DW_AT_sibling);
+    DWARF_NAMEFY(DW_AT_location);
+    DWARF_NAMEFY(DW_AT_name);
+    DWARF_NAMEFY(DW_AT_ordering);
+    DWARF_NAMEFY(DW_AT_subscr_data);
+    DWARF_NAMEFY(DW_AT_byte_size);
+    DWARF_NAMEFY(DW_AT_bit_offset);
+    DWARF_NAMEFY(DW_AT_bit_size);
+    DWARF_NAMEFY(DW_AT_element_list);
+    DWARF_NAMEFY(DW_AT_stmt_list);
+    DWARF_NAMEFY(DW_AT_low_pc);
+    DWARF_NAMEFY(DW_AT_high_pc);
+    DWARF_NAMEFY(DW_AT_language);
+    DWARF_NAMEFY(DW_AT_member);
+    DWARF_NAMEFY(DW_AT_discr);
+    DWARF_NAMEFY(DW_AT_discr_value);
+    DWARF_NAMEFY(DW_AT_visibility);
+    DWARF_NAMEFY(DW_AT_import);
+    DWARF_NAMEFY(DW_AT_string_length);
+    DWARF_NAMEFY(DW_AT_common_reference);
+    DWARF_NAMEFY(DW_AT_comp_dir);
+    DWARF_NAMEFY(DW_AT_const_value);
+    DWARF_NAMEFY(DW_AT_containing_type);
+    DWARF_NAMEFY(DW_AT_default_value);
+    DWARF_NAMEFY(DW_AT_inline);
+    DWARF_NAMEFY(DW_AT_is_optional);
+    DWARF_NAMEFY(DW_AT_lower_bound);
+    DWARF_NAMEFY(DW_AT_producer);
+    DWARF_NAMEFY(DW_AT_prototyped);
+    DWARF_NAMEFY(DW_AT_return_addr);
+    DWARF_NAMEFY(DW_AT_start_scope);
+    DWARF_NAMEFY2(DW_AT_bit_stride, DW_AT_stride_size);
+    DWARF_NAMEFY(DW_AT_upper_bound);
+    DWARF_NAMEFY(DW_AT_abstract_origin);
+    DWARF_NAMEFY(DW_AT_accessibility);
+    DWARF_NAMEFY(DW_AT_address_class);
+    DWARF_NAMEFY(DW_AT_artificial);
+    DWARF_NAMEFY(DW_AT_base_types);
+    DWARF_NAMEFY(DW_AT_calling_convention);
+    DWARF_NAMEFY(DW_AT_count);
+    DWARF_NAMEFY(DW_AT_data_member_location);
+    DWARF_NAMEFY(DW_AT_decl_column);
+    DWARF_NAMEFY(DW_AT_decl_file);
+    DWARF_NAMEFY(DW_AT_decl_line);
+    DWARF_NAMEFY(DW_AT_declaration);
+    DWARF_NAMEFY(DW_AT_discr_list);
+    DWARF_NAMEFY(DW_AT_encoding);
+    DWARF_NAMEFY(DW_AT_external);
+    DWARF_NAMEFY(DW_AT_frame_base);
+    DWARF_NAMEFY(DW_AT_friend);
+    DWARF_NAMEFY(DW_AT_identifier_case);
+    DWARF_NAMEFY(DW_AT_macro_info);
+    DWARF_NAMEFY(DW_AT_namelist_item);
+    DWARF_NAMEFY(DW_AT_priority);
+    DWARF_NAMEFY(DW_AT_segment);
+    DWARF_NAMEFY(DW_AT_specification);
+    DWARF_NAMEFY(DW_AT_static_link);
+    DWARF_NAMEFY(DW_AT_type);
+    DWARF_NAMEFY(DW_AT_use_location);
+    DWARF_NAMEFY(DW_AT_variable_parameter);
+    DWARF_NAMEFY(DW_AT_virtuality);
+    DWARF_NAMEFY(DW_AT_vtable_elem_location);
+    DWARF_NAMEFY(DW_AT_allocated);
+    DWARF_NAMEFY(DW_AT_associated);
+    DWARF_NAMEFY(DW_AT_data_location);
+    DWARF_NAMEFY2(DW_AT_byte_stride, DW_AT_stride);
+    DWARF_NAMEFY(DW_AT_entry_pc);
+    DWARF_NAMEFY(DW_AT_use_UTF8);
+    DWARF_NAMEFY(DW_AT_extension);
+    DWARF_NAMEFY(DW_AT_ranges);
+    DWARF_NAMEFY(DW_AT_trampoline);
+    DWARF_NAMEFY(DW_AT_call_column);
+    DWARF_NAMEFY(DW_AT_call_file);
+    DWARF_NAMEFY(DW_AT_call_line);
+    DWARF_NAMEFY(DW_AT_description);
+    DWARF_NAMEFY(DW_AT_binary_scale);
+    DWARF_NAMEFY(DW_AT_decimal_scale);
+    DWARF_NAMEFY(DW_AT_small);
+    DWARF_NAMEFY(DW_AT_decimal_sign);
+    DWARF_NAMEFY(DW_AT_digit_count);
+    DWARF_NAMEFY(DW_AT_picture_string);
+    DWARF_NAMEFY(DW_AT_mutable);
+    DWARF_NAMEFY(DW_AT_threads_scaled);
+    DWARF_NAMEFY(DW_AT_explicit);
+    DWARF_NAMEFY(DW_AT_object_pointer);
+    DWARF_NAMEFY(DW_AT_endianity);
+    DWARF_NAMEFY(DW_AT_elemental);
+    DWARF_NAMEFY(DW_AT_pure);
+    DWARF_NAMEFY(DW_AT_recursive);
+    DWARF_NAMEFY(DW_AT_signature);
+    DWARF_NAMEFY(DW_AT_main_subprogram);
+    DWARF_NAMEFY(DW_AT_data_bit_offset);
+    DWARF_NAMEFY(DW_AT_const_expr);
+    DWARF_NAMEFY(DW_AT_enum_class);
+    DWARF_NAMEFY(DW_AT_linkage_name);
+    default:
+      return "DW_AT_Unknown";
+  }
+}
+
+const char*
+dwarf_form_name(Dwarf_Form form) {
+  switch (form) {
+    DWARF_NAMEFY(DW_FORM_addr);
+    DWARF_NAMEFY(DW_FORM_block2);
+    DWARF_NAMEFY(DW_FORM_block4);
+    DWARF_NAMEFY(DW_FORM_data2);
+    DWARF_NAMEFY(DW_FORM_data4);
+    DWARF_NAMEFY(DW_FORM_data8);
+    DWARF_NAMEFY(DW_FORM_string);
+    DWARF_NAMEFY(DW_FORM_block);
+    DWARF_NAMEFY(DW_FORM_block1);
+    DWARF_NAMEFY(DW_FORM_data1);
+    DWARF_NAMEFY(DW_FORM_flag);
+    DWARF_NAMEFY(DW_FORM_sdata);
+    DWARF_NAMEFY(DW_FORM_strp);
+    DWARF_NAMEFY(DW_FORM_udata);
+    DWARF_NAMEFY(DW_FORM_ref_addr);
+    DWARF_NAMEFY(DW_FORM_ref1);
+    DWARF_NAMEFY(DW_FORM_ref2);
+    DWARF_NAMEFY(DW_FORM_ref4);
+    DWARF_NAMEFY(DW_FORM_ref8);
+    DWARF_NAMEFY(DW_FORM_ref_udata);
+    DWARF_NAMEFY(DW_FORM_indirect);
+    DWARF_NAMEFY(DW_FORM_sec_offset);
+    DWARF_NAMEFY(DW_FORM_exprloc);
+    DWARF_NAMEFY(DW_FORM_flag_present);
+    DWARF_NAMEFY(DW_FORM_ref_sig8);
+    default:
+      return "DW_FORM_Unknown";
+  }
+}
+
+const char*
+dwarf_tag_name(Dwarf_Tag tag) {
+  switch (tag) {
+    DWARF_NAMEFY(DW_TAG_array_type);
+    DWARF_NAMEFY(DW_TAG_class_type);
+    DWARF_NAMEFY(DW_TAG_entry_point);
+    DWARF_NAMEFY(DW_TAG_enumeration_type);
+    DWARF_NAMEFY(DW_TAG_formal_parameter);
+    DWARF_NAMEFY(DW_TAG_imported_declaration);
+    DWARF_NAMEFY(DW_TAG_label);
+    DWARF_NAMEFY(DW_TAG_lexical_block);
+    DWARF_NAMEFY(DW_TAG_member);
+    DWARF_NAMEFY(DW_TAG_pointer_type);
+    DWARF_NAMEFY(DW_TAG_reference_type);
+    DWARF_NAMEFY(DW_TAG_compile_unit);
+    DWARF_NAMEFY(DW_TAG_string_type);
+    DWARF_NAMEFY(DW_TAG_structure_type);
+    DWARF_NAMEFY(DW_TAG_subroutine_type);
+    DWARF_NAMEFY(DW_TAG_typedef);
+    DWARF_NAMEFY(DW_TAG_union_type);
+    DWARF_NAMEFY(DW_TAG_unspecified_parameters);
+    DWARF_NAMEFY(DW_TAG_variant);
+    DWARF_NAMEFY(DW_TAG_common_block);
+    DWARF_NAMEFY(DW_TAG_common_inclusion);
+    DWARF_NAMEFY(DW_TAG_inheritance);
+    DWARF_NAMEFY(DW_TAG_inlined_subroutine);
+    DWARF_NAMEFY(DW_TAG_module);
+    DWARF_NAMEFY(DW_TAG_ptr_to_member_type);
+    DWARF_NAMEFY(DW_TAG_set_type);
+    DWARF_NAMEFY(DW_TAG_subrange_type);
+    DWARF_NAMEFY(DW_TAG_with_stmt);
+    DWARF_NAMEFY(DW_TAG_access_declaration);
+    DWARF_NAMEFY(DW_TAG_base_type);
+    DWARF_NAMEFY(DW_TAG_catch_block);
+    DWARF_NAMEFY(DW_TAG_const_type);
+    DWARF_NAMEFY(DW_TAG_constant);
+    DWARF_NAMEFY(DW_TAG_enumerator);
+    DWARF_NAMEFY(DW_TAG_file_type);
+    DWARF_NAMEFY(DW_TAG_friend);
+    DWARF_NAMEFY(DW_TAG_namelist);
+    DWARF_NAMEFY2(DW_TAG_namelist_item, DW_TAG_namelist_items);
+    DWARF_NAMEFY(DW_TAG_packed_type);
+    DWARF_NAMEFY(DW_TAG_subprogram);
+    DWARF_NAMEFY2(DW_TAG_template_type_parameter, DW_TAG_template_type_param);
+    DWARF_NAMEFY2(DW_TAG_template_value_parameter,
+                  DW_TAG_template_value_param);
+    DWARF_NAMEFY(DW_TAG_thrown_type);
+    DWARF_NAMEFY(DW_TAG_try_block);
+    DWARF_NAMEFY(DW_TAG_variant_part);
+    DWARF_NAMEFY(DW_TAG_variable);
+    DWARF_NAMEFY(DW_TAG_volatile_type);
+    DWARF_NAMEFY(DW_TAG_dwarf_procedure);
+    DWARF_NAMEFY(DW_TAG_restrict_type);
+    DWARF_NAMEFY(DW_TAG_interface_type);
+    DWARF_NAMEFY(DW_TAG_namespace);
+    DWARF_NAMEFY(DW_TAG_imported_module);
+    DWARF_NAMEFY(DW_TAG_unspecified_type);
+    DWARF_NAMEFY(DW_TAG_partial_unit);
+    DWARF_NAMEFY(DW_TAG_imported_unit);
+    DWARF_NAMEFY(DW_TAG_mutable_type);
+    DWARF_NAMEFY(DW_TAG_condition);
+    DWARF_NAMEFY(DW_TAG_shared_type);
+    DWARF_NAMEFY(DW_TAG_type_unit);
+    DWARF_NAMEFY(DW_TAG_rvalue_reference_type);
+    DWARF_NAMEFY(DW_TAG_template_alias);
+    default:
+      return "DW_TAG_Unknown";
+  }
+}
+
+void
+dump_attrib(Dwarf_At at, Dwarf_Form form, const Dwarf_Value* val) {
+  if (form != 0) {
+    printf("   +++ Attribute: %s [%s]\n",
+           dwarf_at_name(at), dwarf_form_name(form));
+  } else {
+    printf("   +++ Attribute: %s\n", dwarf_at_name(at));
+  }
+  dump_value(val);
+}
+
+void
+dump_value(const Dwarf_Value* attr_value) {
+  printf("       Data[%03u]: (", attr_value->encoded_size);
+  switch (attr_value->type) {
+    case DWARF_VALUE_U8:
+      printf("BYTE)   = %u (x%02X)\n", (Elf_Word)attr_value->u8,
+                                      (Elf_Word)attr_value->u8);
+      break;
+
+    case DWARF_VALUE_S8:
+      printf("SBYTE)  = %d (x%02X)\n", (Elf_Sword)attr_value->s8,
+                                      (Elf_Sword)attr_value->s8);
+      break;
+
+    case DWARF_VALUE_U16:
+      printf("WORD)   = %u (x%04X)\n", (Elf_Word)attr_value->u16,
+                                      (Elf_Word)attr_value->u16);
+      break;
+
+    case DWARF_VALUE_S16:
+      printf("SWORD)  = %d (x%04X)\n", (Elf_Sword)attr_value->s16,
+                                      (Elf_Sword)attr_value->s16);
+      break;
+
+    case DWARF_VALUE_U32:
+      printf("DWORD)  = %u (x%08X)\n", attr_value->u32,
+                                      attr_value->u32);
+      break;
+
+    case DWARF_VALUE_S32:
+      printf("SDWORD) = %d (x%08X)\n", attr_value->s32,
+                                      attr_value->s32);
+      break;
+
+    case DWARF_VALUE_U64:
+      printf("XWORD)  = %I64u (x%I64X)\n", attr_value->u64,
+                                          attr_value->u64);
+      break;
+
+    case DWARF_VALUE_S64:
+      printf("SXWORD) = %I64d (x%I64X)\n", attr_value->s64,
+                                          attr_value->s64);
+      break;
+
+    case DWARF_VALUE_STR:
+      printf("STRING) = %s\n", attr_value->str);
+      break;
+
+    case DWARF_VALUE_PTR32:
+      printf("PTR32)  = x%08X\n", attr_value->ptr32);
+      break;
+
+    case DWARF_VALUE_PTR64:
+      printf("PTR64)  = x%08I64X\n", attr_value->ptr64);
+      break;
+
+    case DWARF_VALUE_BLOCK:
+      printf("BLOCK)  = [%I64u]:", attr_value->block.block_size);
+      for (Elf_Xword i = 0; i < attr_value->block.block_size; i++) {
+        Elf_Byte prnt = *((const Elf_Byte*)attr_value->block.block_ptr + i);
+        printf(" x%02X", prnt);
+      }
+      printf("\n");
+      break;
+
+    case DWARF_VALUE_UNKNOWN:
+    default:
+      printf("UNKNOWN)");
+      break;
+  }
+}
diff --git a/elff/dwarf_utils.h b/elff/dwarf_utils.h
new file mode 100644
index 0000000..fc007d1
--- /dev/null
+++ b/elff/dwarf_utils.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains declarations of misc. DWARF utility routines.

+ */

+

+#ifndef ELFF_DWARF_UTILS_

+#define ELFF_DWARF_UTILS_

+

+#include "dwarf_defs.h"

+

+/* Gets DWARF attribute name string (DW_AT_Xxx) for a given attribute ID.

+ * Param:

+ *  at - DWARF attribute ID to get name string for.

+ * Return:

+ *  Attribute name string. Note that this routine returns "DW_AT_Unknown",

+ *  if DWARF attribute value passed to this routine has not been recognized.

+ */

+const char* dwarf_at_name(Dwarf_At at);

+

+/* Gets DWARF form name string (DW_FORM_Xxx) for a given form.

+ * Param:

+ *  form - DWARF form to get name string for.

+ * Return:

+ *  Form name string. Note that this routine returns "DW_FORM_Unknown", if

+ *  DWARF form value passed to this routine has not been recognized.

+ */

+const char* dwarf_form_name(Dwarf_Form form);

+

+/* Gets DWARF tag name string (DW_TAG_Xxx) for a given tag.

+ * Param:

+ *  tag - DWARF tag to get name string for.

+ * Return:

+ *  Tag name string. Note that this routine returns "DW_TAG_Unknown", if DWARF

+ *  tag value passed to this routine has not been recognized.

+ */

+const char* dwarf_tag_name(Dwarf_Tag tag);

+

+/* Dumps DWARF attribute to stdout.

+ * Param:

+ *  at - Attribute ID (DW_AT_Xxx)

+ *  form - Attribute form (DW_FORM_Xxx)

+ *  val - Attribute value.

+ */

+void dump_attrib(Dwarf_At at, Dwarf_Form form, const Dwarf_Value* val);

+

+/* Dumps DWARF attribute value to stdout.

+ * Param:

+ *  val - Attribute value.

+ */

+void dump_value(const Dwarf_Value* val);

+

+#endif  // ELFF_DWARF_UTILS_

diff --git a/elff/elf.h b/elff/elf.h
new file mode 100644
index 0000000..de92ba6
--- /dev/null
+++ b/elff/elf.h
@@ -0,0 +1,299 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of types, constants and structures
+ * describing ELF file format.
+ */
+
+#ifndef ELFF_ELH_H_
+#define ELFF_ELH_H_
+
+extern "C" {
+#include "qemu-common.h"
+}
+#include "elff-common.h"
+
+//=============================================================================
+// ELF file definitions
+//=============================================================================
+
+#ifdef  WIN32
+typedef HANDLE                    ELF_FILE_HANDLE;
+#define INVALID_ELF_FILE_HANDLE   INVALID_HANDLE_VALUE
+#define close_elf_file_handle     CloseHandle
+#else   // WIN32
+typedef int                       ELF_FILE_HANDLE;
+#define INVALID_ELF_FILE_HANDLE   -1
+#define close_elf_file_handle     close
+#endif  // WIN32
+
+/* Checks if ELF file handle is valid. */
+static inline bool
+elfhandle_is_valid(ELF_FILE_HANDLE handle) {
+  return handle != INVALID_ELF_FILE_HANDLE;
+}
+
+/*
+ * ELF format documentation uses Elf##_Xxx notation for data types, where
+ * ## stands for CPU architecture (32, or 64 bit), and Xxx stands for a
+ * specific type. For the sake of compliance, we will follow doc's notation
+ * when defining types used in ELF file descriptors. However, for the sake of
+ * code simplicity, we will drop CPU architecture index from the types that
+ * have equal sizes on both, 32 and 64 bit architectures.
+ */
+
+/*
+ * Architecture independent types.
+ */
+
+typedef uint8_t   Elf_Byte;
+typedef int8_t    Elf_Sbyte;
+
+typedef uint16_t  Elf_Half;
+typedef int16_t   Elf_Shalf;
+
+typedef uint32_t  Elf_Word;
+typedef int32_t   Elf_Sword;
+
+typedef uint64_t  Elf_Xword;
+typedef int64_t   Elf_Sxword;
+
+/*
+ * Architecture dependent types.
+ */
+
+/* 32-bit ELF address. */
+typedef uint32_t  Elf32_Addr;
+/* 32-bit ELF offset. */
+typedef uint32_t  Elf32_Off;
+
+/* 64-bit ELF address. */
+typedef uint64_t  Elf64_Addr;
+/* 64-bit ELF offset. */
+typedef uint64_t  Elf64_Off;
+
+//=============================================================================
+// ELF file header
+//=============================================================================
+
+/* Byte size of the fixed portion of ELF header. */
+#define EI_NIDENT	16
+
+/* Common (architecture independent portion of) ELF file header,
+ * that starts at offset 0 in ELF file.
+ */
+typedef struct Elf_CommonHdr {
+  union {
+    struct {
+      /* ei_mag0 - ei_mag3 contain ELF header signature. See ELFMAGx bellow. */
+      Elf_Byte  ei_mag0;
+      Elf_Byte  ei_mag1;
+      Elf_Byte  ei_mag2;
+      Elf_Byte  ei_mag3;
+
+      /* File class (32, or 64 bits). See ELFCLASSxxx bellow. */
+      Elf_Byte  ei_class;
+
+      /* Data encoding (endianness). See ELFDATAxxx bellow. */
+      Elf_Byte  ei_data;
+
+      /* ELF header version number. */
+      Elf_Byte  ei_version;
+    } ei_info;
+    unsigned char e_ident[EI_NIDENT];
+  };
+
+  /* File type (executable, shared object, etc.) */
+  Elf_Half      e_type;
+
+  /* Processor type. */
+  Elf_Half      e_machine;
+
+  /* File version. */
+  Elf_Word      e_version;
+} Elf_CommonHdr;
+
+
+/* ELF header signature. */
+#define ELFMAG0		0x7f
+#define ELFMAG1		'E'
+#define ELFMAG2		'L'
+#define ELFMAG3		'F'
+#define ELFMAG		"\177ELF"
+#define SELFMAG		4
+
+/*
+ * Possible ei_class values.
+ */
+
+/* Invalid. */
+#define ELFCLASSNONE  0
+/* It's 32-bit ELF file. */
+#define ELFCLASS32    1
+/* It's 64-bit ELF file. */
+#define ELFCLASS64    2
+
+/*
+ * Possible ei_data values.
+ */
+
+/* Invalid. */
+#define ELFDATANONE   0
+/* ELF data is formatted in little-endian. */
+#define ELFDATA2LSB   1
+/* ELF data is formatted in big-endian. */
+#define ELFDATA2MSB   2
+
+/* Tempated (architecture dependent) ELF file header.
+ * Template param:
+ *  Elf_Addr - Actual type for address encoding (Elf32_Addr, or Elf64_Addr).
+ *  Elf_Off - Actual type for offset encoding (Elf32_Off, or Elf64_Off).
+ */
+template <typename Elf_Addr, typename Elf_Off>
+struct Elf_FHdr {
+  /* Common header. */
+  Elf_CommonHdr common;
+
+  /* Module entry point. */
+  Elf_Addr      e_entry;
+
+  /* Programm header table offset (in bytes) from the beginning of the file.
+   * Zero if there is no programm header in this file.
+   */
+  Elf_Off       e_phoff;
+
+  /* Section header table offset (in bytes) from the beginning of the file.
+   * Zero if there is no section header in this file.
+   */
+  Elf_Off       e_shoff;
+
+  /* Processor-specific flags. */
+  Elf_Word      e_flags;
+
+  /* This header size in bytes. */
+  Elf_Half      e_ehsize;
+
+  /* Byte size of an entry in programm header table. All entries
+   * in the table are the same size.
+   */
+  Elf_Half      e_phentsize;
+
+  /* Number of entries in programm header table. */
+  Elf_Half      e_phnum;
+
+  /* Byte size of an entry in section header table. All entries
+   * in the table are the same size.
+   */
+  Elf_Half      e_shentsize;
+
+  /* Number of entries in section header table. */
+  Elf_Half      e_shnum;
+
+  /* Zero-based index of an entry for name string table section in the section
+   * header table. If no such section exists in the file this field contains
+   * SHN_UNDEF value.
+   */
+  Elf_Half      e_shstrndx;
+};
+/* 32-bit ELF header. */
+typedef Elf_FHdr<Elf32_Addr, Elf32_Off> Elf32_FHdr;
+/* 64-bit ELF header. */
+typedef Elf_FHdr<Elf64_Addr, Elf64_Off> Elf64_FHdr;
+
+//=============================================================================
+// ELF section header
+//=============================================================================
+
+/* Templated (architecture dependent) section header for ELF file.
+ * Template param:
+ *  Elf_Addr - Actual type for address encoding (Elf32_Addr, or Elf64_Addr).
+ *  Elf_Off - Actual type for offset encoding (Elf32_Off, or Elf64_Off).
+ */
+template <typename Elf_Addr, typename Elf_Off>
+struct Elf_SHdr {
+  /* Index (byte offset) of section name in the name string table section. */
+  Elf_Word    sh_name;
+
+  /* Section type and semantics. */
+  Elf_Word    sh_type;
+
+  /* Section flags and attributes. */
+  Elf_Word    sh_flags;
+
+  /* Section address in the memory image of the process. */
+  Elf_Addr    sh_addr;
+
+  /* Byte offset from the beginning of the ELF file to the first
+   * byte in the section.
+   */
+  Elf_Off     sh_offset;
+
+  /* Section size in bytes. */
+  Elf_Word    sh_size;
+
+  /* Section header table index link. Depends on section type. */
+  Elf_Word    sh_link;
+
+  /* Extra section information, depending on the section type. */
+  Elf_Word    sh_info;
+
+  /* Address alignment constrains. 0 and 1 means that section has no
+   * alignment constrains.
+   */
+  Elf_Word    sh_addralign;
+
+  /* Entry size for sections that hold some kind of a table. */
+  Elf_Word    sh_entsize;
+};
+/* 32-bit section header. */
+typedef Elf_SHdr<Elf32_Addr, Elf32_Off> Elf32_SHdr;
+/* 64-bit section header. */
+typedef Elf_SHdr<Elf64_Addr, Elf64_Off> Elf64_SHdr;
+
+/*
+ * Special section indices
+ */
+#define SHN_UNDEF       0
+#define SHN_LORESERVE   0xff00
+#define SHN_LOPROC      0xff00
+#define SHN_HIPROC      0xff1f
+#define SHN_LOOS        0xff20
+#define SHN_HIOS        0xff3f
+#define SHN_ABS         0xfff1
+#define SHN_COMMON      0xfff2
+#define SHN_XINDEX      0xffff
+#define SHN_HIRESERVE   0xffff
+
+/*
+ * Values for sh_type
+ */
+#define SHT_NULL            0
+#define SHT_PROGBITS        1
+#define SHT_SYMTAB          2
+#define SHT_STRTAB          3
+#define SHT_RELA            4
+#define SHT_HASH            5
+#define SHT_DYNAMIC         6
+#define SHT_NOTE            7
+#define SHT_NOBITS          8
+#define SHT_REL             9
+#define SHT_SHLIB           10
+#define SHT_DYNSYM          11
+#define SHT_INIT_ARRAY      14
+#define SHT_FINI_ARRAY      15
+#define SHT_PREINIT_ARRAY   16
+#define SHT_GROUP           17
+#define SHT_SYMTAB_SHNDX    18
+#define SHT_NUM             19
+
+#endif  // ELFF_ELH_H_
diff --git a/elff/elf_alloc.cc b/elff/elf_alloc.cc
new file mode 100644
index 0000000..10d740b
--- /dev/null
+++ b/elff/elf_alloc.cc
@@ -0,0 +1,62 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains implementation of class ElfAllocator, that implements memory

+ * allocations for DWARF objects.

+ */

+

+#include "elf_alloc.h"

+#include "elf_file.h"

+

+ElfAllocator::ElfAllocator()

+    : current_chunk_(NULL) {

+}

+

+ElfAllocator::~ElfAllocator() {

+  ElfAllocatorChunk* chunk_to_free = current_chunk_;

+  while (chunk_to_free != NULL) {

+    ElfAllocatorChunk* next_chunk = chunk_to_free->prev;

+    free(chunk_to_free);

+    chunk_to_free = next_chunk;

+  }

+}

+

+void* ElfAllocator::alloc(size_t size) {

+  /* Lets keep everyting properly aligned. */

+  size = (size + ELFALLOC_ALIGNMENT_MASK) & ~ELFALLOC_ALIGNMENT_MASK;

+

+  if (current_chunk_ == NULL || current_chunk_->remains < size) {

+    /* Allocate new chunk. */

+    ElfAllocatorChunk* new_chunk =

+        reinterpret_cast<ElfAllocatorChunk*>(malloc(ELF_ALLOC_CHUNK_SIZE));

+    assert(new_chunk != NULL);

+    if (new_chunk == NULL) {

+      _set_errno(ENOMEM);

+      return NULL;

+    }

+    new_chunk->size = ELF_ALLOC_CHUNK_SIZE;

+    new_chunk->avail = INC_PTR(new_chunk, sizeof(ElfAllocatorChunk));

+    new_chunk->remains = new_chunk->size - sizeof(ElfAllocatorChunk);

+    new_chunk->prev = current_chunk_;

+    current_chunk_ = new_chunk;

+  }

+

+  void* ret = current_chunk_->avail;

+  current_chunk_->remains -= size;

+  current_chunk_->avail = INC_PTR(current_chunk_->avail, size);

+  return ret;

+}

+

+void* DwarfAllocBase::operator new(size_t size, const ElfFile* elf) {

+  return elf->allocator()->alloc(size);

+}

diff --git a/elff/elf_alloc.h b/elff/elf_alloc.h
new file mode 100644
index 0000000..d76dcdb
--- /dev/null
+++ b/elff/elf_alloc.h
@@ -0,0 +1,160 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains declaration of class ElfAllocator, that implements memory

+ * allocations for DWARF objects.

+ */

+

+#ifndef ELFF_ELF_ALLOC_H_

+#define ELFF_ELF_ALLOC_H_

+

+extern "C" {

+#include "qemu-common.h"

+}

+#include "elff-common.h"

+

+class ElfFile;

+

+/* Alignment mask for blocks, allocated with this allocator. */

+#define ELFALLOC_ALIGNMENT_MASK 3

+

+/* Chunk size. Even on relatively small ELF files, there are a lot of DWARF

+ * info, which makes our parsing pretty hungry on memory. On average, memory

+ * consumption on cached DWARF objects may easily reach 640K, which makes

+ * choosing 32K as chunk size pretty reasonable.

+ */

+#define ELF_ALLOC_CHUNK_SIZE  (32 * 1024)

+

+/* Describes a chunk of memory, allocated by ElfAllocator.

+ * NOTE: this header's sizeof must be always aligned accordingly to the

+ * ELFALLOC_ALIGNMENT_MASK value, so we can produce properly aligned blocks

+ * without having to adjust alignment of the blocks, returned from alloc()

+ * method.

+ */

+typedef struct ElfAllocatorChunk {

+  /* Previous chunk in the chain of chunks allocated by ElfAllocator instance.

+   * For better allocation performance, ElfAllocator keeps its list of

+   * allocated chunks in reverse order (relatively to the chunk allocation

+   * sequence). So this field in each chunk references the chunk, allocated

+   * just prior this one. This field contains NULL for the first allocated

+   * chunk.

+   */

+  ElfAllocatorChunk*  prev;

+

+  /* Address of the next available block in this chunk. */

+  void*               avail;

+

+  /* Chunk size. */

+  size_t              size;

+

+  /* Number of bytes that remain available in this chunk. */

+  size_t              remains;

+} ElfAllocatorChunk;

+

+/* Encapsulates memory allocator for DWARF-related objects.

+ * Due to the implementation of ELF/DWARF framework in this library, data,

+ * collected during ELF/DWARF parsing stays in memory for as long, as instance

+ * of ElfFile that's being parsed is alive. To save performance on the numerous

+ * memory allocations (and then, deallocations) we will use this simple memory

+ * allocator that will grab memory from the heap in large chunks and then will

+ * provide DWARF objects with blocks of the required size inside those chunks.

+ * This will be much faster than going to the heap all the time, and since we

+ * will use overwritten operators new/delete for the DWARF objects that use

+ * this allocator, this is going to be pretty flexible and reliable solution

+ * for DWARF object allocation implementation. See DwarfAllocBase for more

+ * details.

+ *

+ * Instance (always one) of this class is created by ElfFile object when it is

+ * initializing.

+ */

+class ElfAllocator {

+ public:

+  /* Constructs ElfAllocator instance. */

+  ElfAllocator();

+

+  /* Destructs ElfAllocator instance. */

+  ~ElfAllocator();

+

+  /* Allocates requested number of bytes for a DWARF object.

+   * Param:

+   *  size - Number of bytes to allocate. Value passed in this parameter

+   *    will be rounded up accordingly to ELFALLOC_ALIGNMENT_MASK value,

+   *    simplifying alignment adjustments for the allocated blocks.

+   * Return:

+   *  Address of allocated block of the requested size on success,

+   *  or NULL on failure.

+   */

+  void* alloc(size_t size);

+

+ protected:

+  /* Current chunk to allocate memory from. NOTE: chunks are listed here

+   * in reverse order (relatively to the chunk allocation sequence).

+   */

+  ElfAllocatorChunk*  current_chunk_;

+};

+

+/* Base class for all WDARF objects that will use ElfAllocator class for

+ * instance allocations. NOTE: it's required, that all classes that use

+ * ElfAllocator are derived from this one, as it provides compilation-time

+ * protection from mistakenly using "traditional" operator 'new' for object

+ * instantiation.

+ */

+class DwarfAllocBase {

+ public:

+  /* Constructs DwarfAllocBase instance. */

+  DwarfAllocBase() {

+  }

+

+  /* Destructs DwarfAllocBase instance. */

+  virtual ~DwarfAllocBase() {

+  }

+

+  /* Main operator new.

+   * Implements allocation of objects of derived classes from elf's "chunked"

+   * allocator, instantiated in ElfFile object (see ElfAllocator class).

+   * Param:

+   *  size - Number of bytes to allocate for an instance of the derived class.

+   *  elf - ELF file instance that owns the allocating object.

+   * Return:

+   *  Pointer to the allocated memory on success, or NULL on failure.

+   */

+  void* operator new(size_t size, const ElfFile* elf);

+

+  /* Overwitten operator delete.

+   * Since deleting for chunk-allocated objects is a "no-op", we don't do

+   * anything in this operator. We, however, are obliged to implement this

+   * operator in order to compliment overwritten operator 'new'.

+   */

+  void operator delete(void* ptr) {

+  }

+

+  /* Overwitten operator delete.

+   * Since deleting for chunk-allocated objects is a "no-op", we don't do

+   * anything in this operator. We, however, are obliged to implement this

+   * operator in order to compliment overwritten operator 'new'.

+   */

+  void operator delete[](void* ptr) {

+  }

+

+ private:

+  /* Default operator new.

+   * We override it making 'private' in order to cause a compiler error on

+   * attempts to instantiate objects of derived classes using this version

+   * of operator 'new'.

+   */

+  void* operator new(size_t size) {

+    return NULL;

+  }

+};

+

+#endif  // ELFF_ELF_ALLOC_H_

diff --git a/elff/elf_defs.h b/elff/elf_defs.h
new file mode 100644
index 0000000..39fd1b1
--- /dev/null
+++ b/elff/elf_defs.h
@@ -0,0 +1,135 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains some helpful macros, and inline routines.

+ */

+

+#ifndef ELFF_ELF_DEFS_H_

+#define ELFF_ELF_DEFS_H_

+

+#include "elf.h"

+

+//=============================================================================

+// Macros.

+//=============================================================================

+

+/* Increments a pointer by n bytes.

+ * Param:

+ *  p - Pointer to increment.

+ *  n - Number of bytes to increment the pointer with.

+ */

+#define INC_PTR(p, n)   (reinterpret_cast<uint8_t*>(p) + (n))

+

+/* Increments a constant pointer by n bytes.

+ * Param:

+ *  p - Pointer to increment.

+ *  n - Number of bytes to increment the pointer with.

+ */

+#define INC_CPTR(p, n)  (reinterpret_cast<const uint8_t*>(p) + (n))

+

+/* Increments a pointer of a given type by n bytes.

+ * Param:

+ *  T - Pointer type

+ *  p - Pointer to increment.

+ *  n - Number of bytes to increment the pointer with.

+ */

+#define INC_PTR_T(T, p, n)                              \

+    reinterpret_cast<T*>                                \

+        (reinterpret_cast<uint8_t*>(p) + (n))

+

+/* Increments a constant pointer of a given type by n bytes.

+ * Param:

+ *  T - Pointer type

+ *  p - Pointer to increment.

+ *  n - Number of bytes to increment the pointer with.

+ */

+#define INC_CPTR_T(T, p, n)                                 \

+    reinterpret_cast<const T*>                              \

+        (reinterpret_cast<const uint8_t*>(p) + (n))

+

+/* Calculates number of entries in a static array.

+ * Param:

+ *  a - Array.

+ * Return:

+ *  Number of entries in the array.

+ */

+#define ELFF_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))

+

+/* Calculates offset of a field inside a structure (or a class) of the

+ * given type.

+ * Param:

+ *  T - Structure (or class) type.

+ *  f - Name of a field (member variable) for this structure (or class).

+ */

+#define ELFF_FIELD_OFFSET(T, f) ((size_t)(size_t*)&(((T *)0)->f))

+

+//=============================================================================

+// Inline routines.

+//=============================================================================

+

+/* Calculates byte interval between two pointers.

+ * Param:

+ *  s - Starting pointer of the interval. Must be less, or equal to 'e'.

+ *  e - Ending pointer of the interval. Must be greater, or equal to 's'.

+ * Return:

+ *  Byte interval between two pointers.

+ */

+static inline size_t

+diff_ptr(const void* s, const void* e) {

+  assert(s <= e);

+  return ((size_t)(reinterpret_cast<const uint8_t*>(e) -

+         reinterpret_cast<const uint8_t*>(s)));

+}

+

+/* Gets one byte from an index inside a memory block.

+ * Param:

+ *  ptr - Address of the beginning of the memory block.

+ *  bt - Index of a byte inside the block to get.

+ * Return:

+ *  A byte at the given index inside the given memory block.

+ */

+static inline uint8_t

+get_byte(const void* ptr, uint32_t bt) {

+  return *(reinterpret_cast<const uint8_t*>(ptr) + bt);

+}

+

+/* Checks if given address range is fully contained within a section.

+ * Param:

+ *  rp - Beginning of the range to check.

+ *  rsize - Size of the range to check.

+ *  ss - Beginning of the section that should contain the checking range.

+ *  ssize - Size of the section that should contain the checking range.

+ * Return:

+ *  true, if given address range is fully contained within a section, or

+ *  false, if any part of the address range is not contained in the secton.

+ */

+static inline bool

+is_in_section(const void* rp, size_t rsize, const void* ss, size_t ssize) {

+  const void* rend = INC_CPTR(rp, rsize);

+  /* We also make sure here that increment didn't overflow the pointer. */

+  return rp >= ss && ss != NULL && (diff_ptr(ss, rend) <= ssize) && rend >= rp;

+}

+

+/* Checks if this code runs on CPU with a little-endian data format.

+ * Return:

+ *  true, if this code runs on CPU with a little-endian data format,

+ *  or false, if this code runs on CPU with a big-endian data format.

+ */

+static inline bool

+is_little_endian_cpu(void) {

+  uint16_t tmp = 0x00FF;

+  /* Lets see if byte has flipped for little-endian. */

+  return get_byte(&tmp, 0) == 0xFF;

+}

+

+#endif  // ELFF_ELF_DEFS_H_

diff --git a/elff/elf_file.cc b/elff/elf_file.cc
new file mode 100644
index 0000000..70ed81c
--- /dev/null
+++ b/elff/elf_file.cc
@@ -0,0 +1,539 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains implementation of ElfFile classes that encapsulate an ELF file.

+ */

+

+#include "string.h"

+#include "elf_file.h"

+#include "elf_alloc.h"

+#include "dwarf_cu.h"

+#include "dwarf_utils.h"

+

+/* Tags to parse when collecting info about routines. */

+static const Dwarf_Tag parse_rt_tags[] = {

+  DW_TAG_compile_unit,

+  DW_TAG_partial_unit,

+  DW_TAG_inlined_subroutine,

+  DW_TAG_subprogram,

+  0

+};

+static const DwarfParseContext parse_rt_context = { parse_rt_tags };

+

+//=============================================================================

+// Base ElfFile implementation

+//=============================================================================

+

+ElfFile::ElfFile()

+    : sec_table_(NULL),

+      elf_file_path_(NULL),

+      sec_count_(0),

+      cu_count_(0),

+      last_cu_(NULL),

+      allocator_(NULL),

+      fixed_base_address_(0),

+      is_exec_(0),

+      elf_handle_(INVALID_ELF_FILE_HANDLE),

+      sec_entry_size_(0) {

+}

+

+ElfFile::~ElfFile() {

+  DwarfCU* cu_to_del = last_cu_;

+  while (cu_to_del != NULL) {

+    DwarfCU* next_cu_to_del = cu_to_del->prev_cu_;

+    delete cu_to_del;

+    cu_to_del = next_cu_to_del;

+  }

+

+  if (elfhandle_is_valid(elf_handle_)) {

+    close_elf_file_handle(elf_handle_);

+  }

+

+  if (elf_file_path_ != NULL) {

+    delete[] elf_file_path_;

+  }

+

+  if (sec_table_ != NULL) {

+    delete[] reinterpret_cast<Elf_Byte*>(sec_table_);

+  }

+

+  /* Must be deleted last! */

+  if (allocator_ != NULL) {

+    delete allocator_;

+  }

+}

+

+ElfFile* ElfFile::Create(const char* path) {

+  ElfFile* ret = NULL;

+  /* Allocate enough space on the stack to fit the largest ELF file header. */

+  Elf64_FHdr header;

+  const Elf_CommonHdr* elf_hdr = &header.common;

+

+  assert(path != NULL && *path != '\0');

+  if (path == NULL || *path == '\0') {

+    _set_errno(EINVAL);

+    return NULL;

+  }

+

+  /*

+   * Open ELF file, and read its header (the largest one possible).

+   */

+

+#ifdef WIN32

+  HANDLE file_handle = CreateFile(path, GENERIC_READ,

+                                  FILE_SHARE_READ, NULL, OPEN_EXISTING,

+                                  FILE_FLAG_RANDOM_ACCESS, NULL);

+  assert(file_handle != INVALID_HANDLE_VALUE);

+  if (file_handle == INVALID_HANDLE_VALUE) {

+    _set_errno(GetLastError());

+    return NULL;

+  }

+

+  DWORD read_bytes;

+  BOOL res = ReadFile(file_handle, &header, sizeof(header), &read_bytes, NULL);

+  CloseHandle(file_handle);

+  assert(res && read_bytes == sizeof(header));

+  if (!res || read_bytes != sizeof(header)) {

+    _set_errno(GetLastError());

+    return NULL;

+  }

+#else // WIN32

+  int file_handle = open(path, O_RDONLY | O_BINARY, 0);

+  assert(file_handle >= 0);

+  if (file_handle < 0) {

+    return NULL;

+  }

+  const ssize_t read_bytes = read(file_handle, &header, sizeof(header));

+  close(file_handle);

+  assert(read_bytes != -1 && read_bytes == sizeof(header));

+  if (read_bytes == -1 || read_bytes != sizeof(header)) {

+    if (read_bytes != -1) {

+      _set_errno(EINVAL);

+    }

+    return NULL;

+  }

+#endif  // WIN32

+

+  /* Lets see if this is an ELF file at all. */

+  if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG) != 0) {

+    /* File is not an ELF file. */

+    _set_errno(ENOEXEC);

+    return NULL;

+  }

+

+  /* Lets check ELF's "bitness". */

+  assert(elf_hdr->ei_info.ei_class == ELFCLASS32 ||

+         elf_hdr->ei_info.ei_class == ELFCLASS64);

+  if (elf_hdr->ei_info.ei_class != ELFCLASS32 &&

+      elf_hdr->ei_info.ei_class != ELFCLASS64) {

+    /* Neither 32, or 64-bit ELF file. Something wrong here. */

+    _set_errno(EBADF);

+    return NULL;

+  }

+

+  /* Lets instantiate appropriate ElfFileImpl object for this ELF. */

+  if (elf_hdr->ei_info.ei_class == ELFCLASS32) {

+    ret = new ElfFileImpl<Elf32_Addr, Elf32_Off>;

+  } else {

+    ret = new ElfFileImpl<Elf64_Addr, Elf64_Off>;

+  }

+  assert(ret != NULL);

+  if (ret != NULL) {

+    if (!ret->initialize(elf_hdr, path)) {

+      delete ret;

+      ret = NULL;

+    }

+  } else {

+    _set_errno(ENOMEM);

+  }

+

+  return ret;

+}

+

+bool ElfFile::initialize(const Elf_CommonHdr* elf_hdr, const char* path) {

+  /* Must be created first! */

+  allocator_ = new ElfAllocator();

+  assert(allocator_ != NULL);

+  if (allocator_ == NULL) {

+    _set_errno(ENOMEM);

+    return false;

+  }

+

+  /* Copy file path. */

+  size_t path_len = strlen(path) + 1;

+  elf_file_path_ = new char[path_len];

+  assert(elf_file_path_ != NULL);

+  if (elf_file_path_ == NULL) {

+    _set_errno(ENOMEM);

+    return false;

+  }

+  memcpy(elf_file_path_, path, path_len);

+

+  /* Cache some basic ELF properties. */

+  is_ELF_64_ = elf_hdr->ei_info.ei_class == ELFCLASS64;

+  is_elf_big_endian_ = elf_hdr->ei_info.ei_data == ELFDATA2MSB;

+  same_endianness_ = is_elf_little_endian() == is_little_endian_cpu();

+  is_exec_ = elf_hdr->e_type == 2;

+

+  /* Reopen file for further reads and mappings. */

+#ifdef WIN32

+  elf_handle_ = CreateFile(elf_file_path_, GENERIC_READ,

+                           FILE_SHARE_READ, NULL, OPEN_EXISTING,

+                           FILE_FLAG_RANDOM_ACCESS, NULL);

+  assert(elf_handle_ != INVALID_HANDLE_VALUE);

+  if (elf_handle_ == INVALID_HANDLE_VALUE) {

+    _set_errno(GetLastError());

+    return false;

+  }

+#else // WIN32

+  elf_handle_ = open(elf_file_path_, O_RDONLY | O_BINARY, 0);

+  assert(elf_handle_ >= 0);

+  if (elf_handle_ < 0) {

+    elf_handle_ = INVALID_ELF_FILE_HANDLE;

+    return false;

+  }

+#endif  // WIN32

+

+  return true;

+}

+

+bool ElfFile::get_pc_address_info(Elf_Xword address,

+                                  Elf_AddressInfo* address_info) {

+  assert(address_info != NULL);

+  if (address_info == NULL) {

+    _set_errno(EINVAL);

+    return false;

+  }

+

+  /* Collect routine information for all CUs in this file. */

+  if (parse_compilation_units(&parse_rt_context) == -1) {

+    return false;

+  }

+

+  /* Iterate through the collected CUs looking for the one that

+   * contains the given address. */

+  address_info->inline_stack = NULL;

+  DwarfCU* cu = last_cu();

+  while (cu != NULL) {

+    /* Find a leaf DIE object in the current CU that contains the address. */

+    Dwarf_AddressInfo info;

+    info.die_obj = cu->get_leaf_die_for_address(address);

+    if (info.die_obj != NULL) {

+      /* Convert the address to a location inside source file. */

+      if (cu->get_pc_address_file_info(address, &info)) {

+          /* Copy location information to the returning structure. */

+          address_info->file_name = info.file_name;

+          address_info->dir_name = info.dir_name;

+          address_info->line_number = info.line_number;

+      } else {

+          address_info->file_name = NULL;

+          address_info->dir_name = NULL;

+          address_info->line_number = 0;

+      }

+

+      /* Lets see if the DIE represents a routine (rather than

+       * a lexical block, for instance). */

+      Dwarf_Tag tag = info.die_obj->get_tag();

+      while (!dwarf_tag_is_routine(tag)) {

+        /* This is not a routine DIE. Lets loop trhough the parents of that

+         * DIE looking for the first routine DIE. */

+        info.die_obj = info.die_obj->parent_die();

+        if (info.die_obj == NULL) {

+          /* Reached compilation unit DIE. Can't go any further. */

+          address_info->routine_name = "<unknown>";

+          return true;

+        }

+        tag = info.die_obj->get_tag();

+      }

+

+      /* Save name of the routine that contains the address. */

+      address_info->routine_name = info.die_obj->get_name();

+      if (address_info->routine_name == NULL) {

+        /* In some cases (minimum debugging info in the file) routine

+         * name may be not avaible. We, however, are obliged by API

+         * considerations to return something in this field. */

+          address_info->routine_name = "<unknown>";

+      }

+

+      /* Lets see if address belongs to an inlined routine. */

+      if (tag != DW_TAG_inlined_subroutine) {

+        address_info->inline_stack = NULL;

+        return true;

+      }

+

+      /*

+       * Address belongs to an inlined routine. Create inline stack.

+       */

+

+      /* Allocate inline stack array big enough to fit all parent entries. */

+      address_info->inline_stack =

+        new Elf_InlineInfo[info.die_obj->get_level() + 1];

+      assert(address_info->inline_stack != NULL);

+      if (address_info->inline_stack == NULL) {

+        _set_errno(ENOMEM);

+        return false;

+      }

+      memset(address_info->inline_stack, 0,

+             sizeof(Elf_InlineInfo) * (info.die_obj->get_level() + 1));

+

+      /* Reverse DIEs filling in inline stack entries for inline

+       * routine tags. */

+      int inl_index = 0;

+      do {

+        /* Save source file information. */

+        DIEAttrib file_desc;

+        if (info.die_obj->get_attrib(DW_AT_call_file, &file_desc)) {

+          const Dwarf_STMTL_FileDesc* desc =

+              cu->get_stmt_file_info(file_desc.value()->u32);

+          if (desc != NULL) {

+            address_info->inline_stack[inl_index].inlined_in_file =

+                desc->file_name;

+            address_info->inline_stack[inl_index].inlined_in_file_dir =

+                cu->get_stmt_dir_name(desc->get_dir_index());

+          }

+        }

+        if (address_info->inline_stack[inl_index].inlined_in_file == NULL) {

+          address_info->inline_stack[inl_index].inlined_in_file = "<unknown>";

+          address_info->inline_stack[inl_index].inlined_in_file_dir = NULL;

+        }

+

+        /* Save source line information. */

+        if (info.die_obj->get_attrib(DW_AT_call_line, &file_desc)) {

+          address_info->inline_stack[inl_index].inlined_at_line = file_desc.value()->u32;

+        }

+

+        /* Advance DIE to the parent routine, and save its name. */

+        info.die_obj = info.die_obj->parent_die();

+        assert(info.die_obj != NULL);

+        if (info.die_obj != NULL) {

+          tag = info.die_obj->get_tag();

+          while (!dwarf_tag_is_routine(tag)) {

+            info.die_obj = info.die_obj->parent_die();

+            if (info.die_obj == NULL) {

+              break;

+            }

+            tag = info.die_obj->get_tag();

+          }

+          if (info.die_obj != NULL) {

+            address_info->inline_stack[inl_index].routine_name =

+                info.die_obj->get_name();

+          }

+        }

+        if (address_info->inline_stack[inl_index].routine_name == NULL) {

+          address_info->inline_stack[inl_index].routine_name = "<unknown>";

+        }

+

+        /* Continue with the parent DIE. */

+        inl_index++;

+      } while (info.die_obj != NULL && tag == DW_TAG_inlined_subroutine);

+

+      return true;

+    }

+    cu = cu->prev_cu();

+  }

+

+  return false;

+}

+

+void ElfFile::free_pc_address_info(Elf_AddressInfo* address_info) const {

+  assert(address_info != NULL);

+  if (address_info != NULL && address_info->inline_stack != NULL) {

+    delete address_info->inline_stack;

+    address_info->inline_stack = NULL;

+  }

+}

+

+//=============================================================================

+// ElfFileImpl

+//=============================================================================

+

+template <typename Elf_Addr, typename Elf_Off>

+bool ElfFileImpl<Elf_Addr, Elf_Off>::initialize(const Elf_CommonHdr* elf_hdr,

+                                                const char* path) {

+  /* Must be called first! */

+  if (!ElfFile::initialize(elf_hdr, path)) {

+    return false;

+  }

+

+  /* Cache some header data, so later we can discard the header. */

+  const Elf_FHdr<Elf_Addr, Elf_Off>* header =

+      reinterpret_cast<const Elf_FHdr<Elf_Addr, Elf_Off>*>(elf_hdr);

+  sec_count_ = pull_val(header->e_shnum);

+  sec_entry_size_ = pull_val(header->e_shentsize);

+  fixed_base_address_ = pull_val(header->e_entry) & ~0xFFF;

+

+  /* Cache section table (must have one!) */

+  const Elf_Off sec_table_off = pull_val(header->e_shoff);

+  assert(sec_table_off != 0 && sec_count_ != 0);

+  if (sec_table_off == 0 || sec_count_ == 0) {

+    _set_errno(EBADF);

+    return false;

+  }

+  const size_t sec_table_size = sec_count_ * sec_entry_size_;

+  sec_table_ = new Elf_Byte[sec_table_size];

+  assert(sec_table_ != NULL);

+  if (sec_table_ == NULL) {

+    _set_errno(ENOMEM);

+    return false;

+  }

+#ifdef  WIN32

+  LARGE_INTEGER convert;

+  convert.QuadPart = sec_table_off;

+  if ((SetFilePointer(elf_handle_, convert.LowPart,

+                      &convert.HighPart,

+                      FILE_BEGIN) == INVALID_SET_FILE_POINTER) &&

+      (GetLastError() != NO_ERROR)) {

+    _set_errno(GetLastError());

+    return false;

+  }

+  DWORD read_bytes;

+  BOOL res =

+      ReadFile(elf_handle_, sec_table_, sec_table_size, &read_bytes, NULL);

+  assert(res && read_bytes == sec_table_size);

+  if (!res || read_bytes != sec_table_size) {

+    _set_errno(GetLastError());

+    return false;

+  }

+#else   // WIN32

+  ssize_t res = lseek(elf_handle_, sec_table_off, SEEK_SET);

+  assert(res != -1);

+  if (res == -1) {

+    return false;

+  }

+  res = read(elf_handle_, sec_table_, sec_table_size);

+  assert(res != -1 && res == sec_table_size);

+  if (res == -1 || res != sec_table_size) {

+    if (res != -1) {

+      _set_errno(EINVAL);

+    }

+    return false;

+  }

+#endif  // WIN32

+

+  /* Map ELF's string section (must have one!). */

+  const Elf_Half str_sec_index = pull_val(header->e_shstrndx);

+  assert(str_sec_index != SHN_UNDEF);

+  if (str_sec_index == SHN_UNDEF) {

+    _set_errno(EBADF);

+    return false;

+  }

+  const Elf_SHdr<Elf_Addr, Elf_Off>* str_sec =

+      reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>

+          (get_section_by_index(str_sec_index));

+  assert(str_sec != NULL);

+  if (str_sec == NULL) {

+    _set_errno(EBADF);

+    return false;

+  }

+  if (!string_section_.map(elf_handle_, pull_val(str_sec->sh_offset),

+                           pull_val(str_sec->sh_size))) {

+    return false;

+  }

+

+  /* Lets determine DWARF format. According to the docs, DWARF is 64 bit, if

+   * first 4 bytes in the compilation unit header are set to 0xFFFFFFFF.

+   * .debug_info section of the ELF file begins with the first CU header. */

+  if (!map_section_by_name(".debug_info", &debug_info_)) {

+    _set_errno(EBADF);

+    return false;

+  }

+

+  /* Note that we don't care about endianness here, since 0xFFFFFFFF is an

+   * endianness-independent value, so we don't have to pull_val here. */

+  is_DWARF_64_ =

+    *reinterpret_cast<const Elf_Word*>(debug_info_.data()) == 0xFFFFFFFF;

+

+  return true;

+}

+

+template <typename Elf_Addr, typename Elf_Off>

+int ElfFileImpl<Elf_Addr, Elf_Off>::parse_compilation_units(

+    const DwarfParseContext* parse_context) {

+  /* Lets see if we already parsed the file. */

+  if (last_cu() != NULL) {

+    return cu_count_;

+  }

+

+  /* Cache sections required for this parsing. */

+  if (!map_section_by_name(".debug_abbrev", &debug_abbrev_) ||

+      !map_section_by_name(".debug_ranges", &debug_ranges_) ||

+      !map_section_by_name(".debug_line", &debug_line_) ||

+      !map_section_by_name(".debug_str", &debug_str_)) {

+    _set_errno(EBADF);

+    return false;

+  }

+

+  /* .debug_info section opens with the first CU header. */

+  const void* next_cu = debug_info_.data();

+

+  /* Iterate through CUs until we reached the end of .debug_info section, or

+   * advanced to a CU with zero size, indicating the end of CU list for this

+   * file. */

+  while (is_valid_cu(next_cu)) {

+    /* Instatiate CU, depending on DWARF "bitness". */

+    DwarfCU* cu = DwarfCU::create_instance(this, next_cu);

+    if (cu == NULL) {

+      _set_errno(ENOMEM);

+      return -1;

+    }

+

+    if (cu->parse(parse_context, &next_cu)) {

+      cu->set_prev_cu(last_cu_);

+      last_cu_ = cu;

+      cu_count_++;

+    } else {

+      delete cu;

+      return -1;

+    }

+  };

+

+  return cu_count_;

+}

+

+template <typename Elf_Addr, typename Elf_Off>

+bool ElfFileImpl<Elf_Addr, Elf_Off>::get_section_info_by_name(const char* name,

+                                                              Elf_Off* offset,

+                                                              Elf_Word* size) {

+  const Elf_SHdr<Elf_Addr, Elf_Off>* cur_section =

+      reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>(sec_table_);

+

+  for (Elf_Half sec = 0; sec < sec_count_; sec++) {

+    const char* sec_name = get_str_sec_str(pull_val(cur_section->sh_name));

+    if (sec_name != NULL && strcmp(name, sec_name) == 0) {

+      *offset = pull_val(cur_section->sh_offset);

+      *size = pull_val(cur_section->sh_size);

+      return true;

+    }

+    cur_section = reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>

+                                  (INC_CPTR(cur_section, sec_entry_size_));

+  }

+  _set_errno(EINVAL);

+  return false;

+}

+

+template <typename Elf_Addr, typename Elf_Off>

+bool ElfFileImpl<Elf_Addr, Elf_Off>::map_section_by_name(

+    const char* name,

+    ElfMappedSection* section) {

+  if (section->is_mapped()) {

+    return true;

+  }

+

+  Elf_Off offset;

+  Elf_Word size;

+  if (!get_section_info_by_name(name, &offset, &size)) {

+    return false;

+  }

+

+  return section->map(elf_handle_, offset, size);

+}

diff --git a/elff/elf_file.h b/elff/elf_file.h
new file mode 100644
index 0000000..6c57bde
--- /dev/null
+++ b/elff/elf_file.h
@@ -0,0 +1,621 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains declaration of ElfFile classes that encapsulate an ELF file.

+ */

+

+#ifndef ELFF_ELF_FILE_H_

+#define ELFF_ELF_FILE_H_

+

+#include "dwarf_die.h"

+#include "elf_mapped_section.h"

+#include "elff_api.h"

+

+/* Encapsulates architecture-independent functionality of an ELF file.

+ *

+ * This class is a base class for templated ElfFileImpl. This class implements

+ * functionality around an ELF file that is independent from particulars of the

+ * ELF's CPU architectire, while ElfFileImpl handles all particulars of CPU

+ * architecture (namely, 32 or 64-bit), for which ELF file has been built.

+ *

+ * NOTE: This class operates on ELF sections that have been mapped to memory.

+ *

+ */

+class ElfFile {

+ public:

+  /* Constructs ElfFile instance. */

+  ElfFile();

+

+  /* Destructs ElfFile instance. */

+  virtual ~ElfFile();

+

+  /* Creates ElfFileImpl instance, depending on ELF file CPU architecture.

+   * This method will collect initial information about requested ELF file,

+   * and will instantiate appropriate ElfFileImpl class object for it.

+   * Param:

+   *  path - Full path to the ELF file.

+   * Return:

+   *  Initialized ElfFileImpl instance, typecasted back to ElfFile object on

+   *  success, or NULL on failure, with errno providing extended error

+   *  information.

+   */

+  static ElfFile* Create(const char* path);

+

+  /* Checks if ELF file is a 64, or 32-bit ELF file. */

+  bool is_ELF_64() const {

+    return is_ELF_64_;

+  }

+  bool is_ELF_32() const {

+    return !is_ELF_64_;

+  }

+

+  /* Checks if ELF file data format is big, or little-endian. */

+  bool is_elf_big_endian() const {

+    return is_elf_big_endian_;

+  }

+  bool is_elf_little_endian() const {

+    return !is_elf_big_endian_;

+  }

+

+  /* Checks whether or not endianness of CPU this library is built for matches

+   * endianness of the ELF file that is represented with this instance. */

+  bool same_endianness() const {

+    return same_endianness_;

+  }

+

+  /* Checks if format of DWARF data in this file is 64, or 32-bit. */

+  bool is_DWARF_64() const {

+    return is_DWARF_64_;

+  }

+  bool is_DWARF_32() const {

+    return !is_DWARF_64_;

+  }

+

+  /* Gets DWARF objects allocator for this instance. */

+  class ElfAllocator* allocator() const {

+    return allocator_;

+  }

+

+  /* Gets head of compilation unit list, collected during parsing of this file.

+   * NOTE: list of collected compilation units returned from this method is

+   * in reverse order relatively to the order CUs have been added to the list

+   * during ELF file parsing.

+   */

+  class DwarfCU* last_cu() const {

+    return last_cu_;

+  }

+

+  /* Gets number of compilation units, collected during parsing of

+   * this ELF file with parse_compilation_units() method.

+   */

+  int cu_count() const {

+    return cu_count_;

+  }

+

+  /* Gets  executable file flag */

+  bool is_exec() const {

+      return is_exec_;

+  }

+

+ protected:

+  /* Initializes ElfFile instance. This method is called from Create method of

+   * this class after appropriate ElfFileImpl instance has been created. Note,

+   * that Create() method will validate that requested file is an ELF file,

+   * prior to instantiating of an ElfFileImpl object, and calling this method.

+   * Param:

+   *  elf_hdr - Address of the common ELF file header.

+   *  path - See Create().

+   * Return:

+   *  true on success, or false on failure, with errno containing extended

+   *  error information.

+   */

+  virtual bool initialize(const Elf_CommonHdr* elf_hdr, const char* path);

+

+/*=============================================================================

+ * Endianness helper methods.

+ * Since endianness of ELF file may differ from the endianness of the CPU this

+ * library runs on, every time a value is required from a section of the ELF

+ * file, it must be first pulled out of that section to a local variable, and

+ * then used from that local variable. While value is pulled from ELF file

+ * section, it must be converted accordingly to the endianness of the CPU and

+ * ELF file. Routines bellow provide such functionality.

+=============================================================================*/

+

+ public:

+  /* Pulls one byte value from ELF file. Note that for one byte we don't need

+   * to do any endianness conversion, and these two methods are provided purely

+   * for completness of the API.

+   * Param:

+   *  val - References value inside ELF file buffer to pull data from.

+   * Return

+   *  Pulled value with endianness appropriate for the CPU this library is

+   *  running on.

+   */

+  uint8_t pull_val(const uint8_t* val) const {

+    return *val;

+  }

+  uint8_t pull_val(const uint8_t& val) const {

+    return val;

+  }

+  int8_t pull_val(const int8_t* val) const {

+    return *val;

+  }

+  int8_t pull_val(const int8_t& val) const {

+    return val;

+  }

+

+  /* Pulls two byte value from ELF file.

+   * Param:

+   *  val - References value inside ELF file buffer to pull data from.

+   * Return

+   *  Pulled value with endianness appropriate for the CPU this library is

+   *  running on.

+   */

+  uint16_t pull_val(const uint16_t* val) const {

+    if (same_endianness()) {

+      return *val;

+    }

+    if (is_elf_big_endian()) {

+      return (uint16_t)get_byte(val, 0) << 8 | get_byte(val, 1);

+    } else {

+      return (uint16_t)get_byte(val, 1) << 8 | get_byte(val, 0);

+    }

+  }

+  uint16_t pull_val(const uint16_t& val) const {

+    return same_endianness() ? val : pull_val(&val);

+  }

+  int16_t pull_val(const int16_t* val) const {

+    return static_cast<int16_t>

+              (pull_val(reinterpret_cast<const uint16_t*>(val)));

+  }

+  int16_t pull_val(const int16_t& val) const {

+    return static_cast<int16_t>

+              (pull_val(reinterpret_cast<const uint16_t&>(val)));

+  }

+

+  /* Pulls four byte value from ELF file.

+   * Param:

+   *  val - References value inside ELF file buffer to pull data from.

+   * Return

+   *  Pulled value with endianness appropriate for the CPU this library is

+   *  running on.

+   */

+  uint32_t pull_val(const uint32_t* val) const {

+    if (same_endianness()) {

+      return *val;

+    }

+    if (is_elf_big_endian()) {

+      return (uint32_t)get_byte(val, 0) << 24 |

+             (uint32_t)get_byte(val, 1) << 16 |

+             (uint32_t)get_byte(val, 2) << 8  |

+             (uint32_t)get_byte(val, 3);

+    } else {

+      return (uint32_t)get_byte(val, 3) << 24 |

+             (uint32_t)get_byte(val, 2) << 16 |

+             (uint32_t)get_byte(val, 1) << 8  |

+             (uint32_t)get_byte(val, 0);

+    }

+  }

+  uint32_t pull_val(const uint32_t& val) const {

+    return same_endianness() ? val : pull_val(&val);

+  }

+  int32_t pull_val(const int32_t* val) const {

+    return static_cast<int32_t>

+              (pull_val(reinterpret_cast<const uint32_t*>(val)));

+  }

+  int32_t pull_val(const int32_t& val) const {

+    return static_cast<int32_t>

+              (pull_val(reinterpret_cast<const uint32_t&>(val)));

+  }

+

+  /* Pulls eight byte value from ELF file.

+   * Param:

+   *  val - References value inside ELF file buffer to pull data from.

+   * Return

+   *  Pulled value with endianness appropriate for the CPU this library is

+   *  running on.

+   */

+  uint64_t pull_val(const uint64_t* val) const {

+    if (same_endianness()) {

+      return *val;

+    }

+    if (is_elf_big_endian()) {

+      return (uint64_t)get_byte(val, 0) << 56 |

+             (uint64_t)get_byte(val, 1) << 48 |

+             (uint64_t)get_byte(val, 2) << 40 |

+             (uint64_t)get_byte(val, 3) << 32 |

+             (uint64_t)get_byte(val, 4) << 24 |

+             (uint64_t)get_byte(val, 5) << 16 |

+             (uint64_t)get_byte(val, 6) << 8  |

+             (uint64_t)get_byte(val, 7);

+    } else {

+      return (uint64_t)get_byte(val, 7) << 56 |

+             (uint64_t)get_byte(val, 6) << 48 |

+             (uint64_t)get_byte(val, 5) << 40 |

+             (uint64_t)get_byte(val, 4) << 32 |

+             (uint64_t)get_byte(val, 3) << 24 |

+             (uint64_t)get_byte(val, 2) << 16 |

+             (uint64_t)get_byte(val, 1) << 8  |

+             (uint64_t)get_byte(val, 0);

+    }

+  }

+  uint64_t pull_val(const uint64_t& val) const {

+    return same_endianness() ? val : pull_val(&val);

+  }

+  int64_t pull_val(const int64_t* val) const {

+    return static_cast<int64_t>

+              (pull_val(reinterpret_cast<const uint64_t*>(val)));

+  }

+  int64_t pull_val(const int64_t& val) const {

+    return static_cast<int64_t>

+              (pull_val(reinterpret_cast<const uint64_t&>(val)));

+  }

+

+//=============================================================================

+// ELF file section management.

+//=============================================================================

+

+ public:

+  /* Gets a string contained in ELF's string section by index.

+   * Param:

+   *  index - String index (byte offset) in the ELF's string section.

+   * Return:

+   *  Pointer to the requested string, or NULL if string index exceeds ELF's

+   *  string section size.

+   *  NOTE: pointer returned from this method points to a mapped section of

+   *  ELF file.

+   */

+  const char* get_str_sec_str(Elf_Xword index) const {

+    assert(string_section_.is_mapped() && index < string_section_.size());

+    if (string_section_.is_mapped() && index < string_section_.size()) {

+      return INC_CPTR_T(char, string_section_.data(), index);

+    } else {

+      _set_errno(EINVAL);

+      return NULL;

+    }

+  }

+

+  /* Gets a string contained in ELF's debug string section (.debug_str)

+   * by index.

+   * Param:

+   *  index - String index (byte offset) in the ELF's debug string section.

+   * Return:

+   *  Pointer to the requested string, or NULL if string index exceeds ELF's

+   *  debug string section size.

+   *  NOTE: pointer returned from this method points to a mapped section of

+   *  ELF file.

+   */

+  const char* get_debug_str(Elf_Xword index) const {

+    assert(debug_str_.is_mapped() && index < debug_str_.size());

+    if (debug_str_.is_mapped() && index < debug_str_.size()) {

+      return INC_CPTR_T(char, debug_str_.data(), index);

+    } else {

+      _set_errno(EINVAL);

+      return NULL;

+    }

+  }

+

+ protected:

+  /* Gets pointer to a section header, given section index within ELF's

+   * section table.

+   * Param:

+   *  index - Section index within ELF's section table.

+   * Return:

+   *  Pointer to a section header (ElfXX_SHdr flavor, depending on ELF's CPU

+   *  architecture) on success, or NULL if section index exceeds number of

+   *  sections for this ELF file.

+   */

+  const void* get_section_by_index(Elf_Half index) const {

+    assert(index < sec_count_);

+    if (index < sec_count_) {

+      return INC_CPTR(sec_table_, static_cast<size_t>(index) * sec_entry_size_);

+    } else {

+      _set_errno(EINVAL);

+      return NULL;

+    }

+  }

+

+//=============================================================================

+// DWARF management.

+//=============================================================================

+

+ protected:

+  /* Parses DWARF, and buids a list of compilation units for this ELF file.

+   * Compilation unit, collected with this methods are linked together in a

+   * list, head of which is available via last_cu() method of this class.

+   * NOTE: CUs in the list returned via last_cu() method are in reverse order

+   * relatively to the order in which CUs are stored in .debug_info section.

+   * This is ELF and DWARF data format - dependent method.

+   * Param:

+   *  parse_context - Parsing context that defines which tags, and which

+   *    properties for which tag should be collected during parsing. NULL

+   *    passed in this parameter indicates that all properties for all tags

+   *    should be collected.

+   * Return:

+   *  Number of compilation units, collected in this method on success,

+   *  or -1 on failure.

+   */

+  virtual int parse_compilation_units(const DwarfParseContext* parse_context) = 0;

+

+ public:

+  /* Gets PC address information.

+   * Param:

+   *  address - PC address to get information for. The address must be relative

+   *    to the beginning of ELF file represented by this class.

+   *  address_info - Upon success contains information about routine(s) that

+   *    contain the given address.

+   * Return:

+   *  true if routine(s) containing has been found and its information has been

+   *  saved into address_info, or false if no appropriate routine for that

+   *  address has been found, or there was a memory error when collecting

+   *  routine(s) information. In case of failure, errno contains extended error

+   *  information.

+   */

+  bool get_pc_address_info(Elf_Xword address, Elf_AddressInfo* address_info);

+

+  /* Frees resources aqcuired for address information in successful call to

+   * get_pc_address_info().

+   * Param:

+   *  address_info - Address information structure, initialized in successful

+   *    call to get_pc_address_info() routine.

+   */

+  void free_pc_address_info(Elf_AddressInfo* address_info) const;

+

+  /* Gets beginning of the .debug_info section data.

+   * Return:

+   *  Beginning of the .debug_info section data.

+   *  NOTE: pointer returned from this method points to a mapped section of

+   *  ELF file.

+   */

+  const void* get_debug_info_data() const {

+    return debug_info_.data();

+  }

+

+  /* Gets beginning of the .debug_abbrev section data.

+   * Return:

+   *  Beginning of the .debug_abbrev section data.

+   *  NOTE: pointer returned from this method points to a mapped section of

+   *  ELF file.

+   */

+  const void* get_debug_abbrev_data() const {

+    return debug_abbrev_.data();

+  }

+

+  /* Gets beginning of the .debug_ranges section data.

+   * Return:

+   *  Beginning of the .debug_ranges section data.

+   *  NOTE: pointer returned from this method points to a mapped section of

+   *  ELF file.

+   */

+  const void* get_debug_ranges_data() const {

+    return debug_ranges_.data();

+  }

+

+  /* Gets beginning of the .debug_line section data.

+   * Return:

+   *  Beginning of the .debug_line section data.

+   *  NOTE: pointer returned from this method points to a mapped section of

+   *  ELF file.

+   */

+  const void* get_debug_line_data() const {

+    return debug_line_.data();

+  }

+

+  /* Checks, if given address range is contained in the mapped .debug_info

+   * section of this file.

+   * Param:

+   *  ptr - Starting address of the range.

+   *  size - Range size in bytes.

+   * Return:

+   *  true if given address range is contained in the mapped .debug_info

+   *  section of this file, or false if any part of the range doesn't belong

+   *  to that section.

+   */

+  bool is_valid_die_ptr(const void* ptr, size_t size) const {

+    return debug_info_.is_contained(ptr, size);

+  }

+

+  /* Checks, if given address range is contained in the mapped .debug_abbrev

+   * section of this file.

+   * Param:

+   *  ptr - Starting address of the range.

+   *  size - Range size in bytes.

+   * Return:

+   *  true if given address range is contained in the mapped .debug_abbrev

+   *  section of this file, or false if any part of the range doesn't belong

+   *  to that section.

+   */

+  bool is_valid_abbr_ptr(const void* ptr, size_t size) const {

+    return debug_abbrev_.is_contained(ptr, size);

+  }

+

+  /* Checks if given pointer addresses a valid compilation unit header in the

+   * mapped .debug_info section of the ELF file.

+   * Param:

+   *  cu_header - Pointer to a compilation unit header to check.

+   * Return

+   *  true, if given pointer addresses a valid compilation unit header, or

+   *  false, if it's not. A valid CU header must be fully conained inside

+   *  .debug_info section of the ELF file, and its size must not be zero.

+   */

+  bool is_valid_cu(const void* cu_header) const {

+    if (is_DWARF_64()) {

+      return is_valid_die_ptr(cu_header, sizeof(Dwarf64_CUHdr)) &&

+             reinterpret_cast<const Dwarf64_CUHdr*>(cu_header)->size_hdr.size != 0;

+    } else {

+      return is_valid_die_ptr(cu_header, sizeof(Dwarf32_CUHdr)) &&

+             reinterpret_cast<const Dwarf32_CUHdr*>(cu_header)->size_hdr.size != 0;

+    }

+  }

+

+  /* Gets range's low and high pc for the given range reference in the mapped

+   * .debug_ranges section of an ELF file.

+   * Template param:

+   *  AddrType - Defines pointer type for the CU the range belongs to. CU's

+   *    pointer type can be defined independently from ELF and DWARF types,

+   *    and is encoded in address_size field of the CU header in .debug_info

+   *    section of ELF file.

+   * Param:

+   *  offset - Byte offset within .debug_ranges section of the range record.

+   *  low - Upon successful return contains value for range's low pc.

+   *  high - Upon successful return contains value for range's high pc.

+   * Return:

+   *  true on success, or false, if requested record is not fully contained

+   *  in the .debug_ranges section.

+   */

+  template<typename AddrType>

+  bool get_range(Elf_Word offset, AddrType* low, AddrType* high) {

+    const AddrType* ptr = INC_CPTR_T(AddrType, debug_ranges_.data(), offset);

+    assert(debug_ranges_.is_contained(ptr, sizeof(AddrType) * 2));

+    if (!debug_ranges_.is_contained(ptr, sizeof(AddrType) * 2)) {

+      _set_errno(EINVAL);

+      return false;

+    }

+    *low = pull_val(ptr);

+    *high = pull_val(ptr + 1);

+    return true;

+  }

+

+ protected:

+  /* Mapped ELF string section. */

+  ElfMappedSection    string_section_;

+

+  /* Mapped .debug_info section. */

+  ElfMappedSection    debug_info_;

+

+  /* Mapped .debug_abbrev section. */

+  ElfMappedSection    debug_abbrev_;

+

+  /* Mapped .debug_str section. */

+  ElfMappedSection    debug_str_;

+

+  /* Mapped .debug_line section. */

+  ElfMappedSection    debug_line_;

+

+  /* Mapped .debug_ranges section. */

+  ElfMappedSection    debug_ranges_;

+

+  /* Base address of the loaded module (if fixed), or 0 if module doesn't get

+   * loaded at fixed address. */

+  Elf_Xword           fixed_base_address_;

+

+  /* Handle to the ELF file represented with this instance. */

+  ELF_FILE_HANDLE     elf_handle_;

+

+  /* Path to the ELF file represented with this instance. */

+  char*               elf_file_path_;

+

+  /* DWARF objects allocator for this instance. */

+  class ElfAllocator* allocator_;

+

+  /* Beginning of the cached ELF's section table. */

+  void*               sec_table_;

+

+  /* Number of sections in the ELF file wrapped by this instance. */

+  Elf_Half            sec_count_;

+

+  /* Byte size of an entry in the section table. */

+  Elf_Half            sec_entry_size_;

+

+  /* Head of compilation unit list, collected during the parsing. */

+  class DwarfCU*      last_cu_;

+

+  /* Number of compilation units in last_cu_ list. */

+  int                 cu_count_;

+

+  /* Flags ELF's CPU architecture: 64 (true), or 32 bits (false). */

+  bool                is_ELF_64_;

+

+  /* Flags endianness of the processed ELF file. true indicates that ELF file

+   * data is stored in big-endian form, false indicates that ELF file data is

+   * stored in big-endian form.

+   */

+  bool                is_elf_big_endian_;

+

+  /* Flags whether or not endianness of CPU this library is built for matches

+   * endianness of the ELF file that is represented with this instance.

+   */

+  bool                same_endianness_;

+

+  /* Flags DWARF format: 64, or 32 bits. DWARF format is determined by looking

+   * at the first 4 bytes of .debug_info section (which is the beginning of the

+   * first compilation unit header). If first 4 bytes contain 0xFFFFFFFF, the

+   * DWARF is 64 bit. Otherwise, DWARF is 32 bit. */

+  bool                is_DWARF_64_;

+

+  /* Flags executable file. If this member is 1, ELF file represented with this

+   * instance is an executable. If this member is 0, file is a shared library.

+   */

+  bool                is_exec_;

+};

+

+/* Encapsulates architecture-dependent functionality of an ELF file.

+ * Template param:

+ *  Elf_Addr - type for an address field in ELF file. Must be:

+ *    - Elf32_Addr for 32-bit CPU, or

+ *    - Elf64_Addr for 64-bit CPU.

+ *  Elf_Off - type for an offset field in ELF file. Must be:

+ *    - Elf64_Off for 32-bit CPU, or

+ *    - Elf64_Off for 64-bit CPU.

+ */

+template <typename Elf_Addr, typename Elf_Off>

+class ElfFileImpl : protected ElfFile {

+/* Instance of this class must be instantiated from

+ * ElfFile::Create() method only. */

+friend class ElfFile;

+ protected:

+  /* Constructs ElfFileImpl instance. */

+  ElfFileImpl() {

+  };

+

+  /* Destructs ElfFileImpl instance. */

+  ~ElfFileImpl() {

+  }

+

+ protected:

+  /* Initializes instance. This is an override of the base class method.

+   * See ElfFile::initialize().

+   */

+  bool initialize(const Elf_CommonHdr* elf_hdr, const char* path);

+

+  /* Parses DWARF, and buids list of compilation units for this ELF file.

+   * This is an implementation of the base class' abstract method.

+   * See ElfFile::parse_compilation_units().

+   */

+  virtual int parse_compilation_units(const DwarfParseContext* parse_context);

+

+  /* Gets section information by section name.

+   * Param:

+   *  name - Name of the section to get information for.

+   *  offset - Upon success contains offset of the section data in ELF file.

+   *  size - Upon success contains size of the section data in ELF file.

+   * Return:

+   *  true on sucess, or false if section with such name doesn't exist in

+   *  this ELF file.

+   */

+  bool get_section_info_by_name(const char* name,

+                                Elf_Off* offset,

+                                Elf_Word* size);

+

+  /* Maps section by its name.

+   * Param:

+   *  name - Name of the section to map.

+   *  section - Upon success contains section's mapping information.

+   * Return:

+   *  true on sucess, or false if section with such name doesn't exist in

+   *  this ELF file, or mapping has failed.

+   */

+  bool map_section_by_name(const char* name, ElfMappedSection* section);

+};

+

+#endif  // ELFF_ELF_FILE_H_

diff --git a/elff/elf_mapped_section.cc b/elff/elf_mapped_section.cc
new file mode 100644
index 0000000..46fc6b6
--- /dev/null
+++ b/elff/elf_mapped_section.cc
@@ -0,0 +1,95 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains implementation of a class ElfMappedSection, that encapsulates

+ * a section of an ELF file, mapped to memory.

+ */

+

+#include "elf_defs.h"

+#include "elf_mapped_section.h"

+

+ElfMappedSection::ElfMappedSection()

+    : mapped_at_(NULL),

+      data_(NULL),

+      size_(0) {

+}

+

+ElfMappedSection::~ElfMappedSection() {

+  if (mapped_at_ != NULL) {

+#ifdef WIN32

+    UnmapViewOfFile(mapped_at_);

+#else   // WIN32

+    munmap(mapped_at_, diff_ptr(mapped_at_, data_) + size_);

+#endif  // WIN32

+  }

+}

+

+bool ElfMappedSection::map(ELF_FILE_HANDLE handle,

+                           Elf_Xword offset,

+                           Elf_Word size) {

+  /* Get the mask for mapping offset alignment. */

+#ifdef  WIN32

+  SYSTEM_INFO sys_info;

+  GetSystemInfo(&sys_info);

+  const Elf_Xword align_mask = sys_info.dwAllocationGranularity - 1;

+#else   // WIN32

+  const Elf_Xword align_mask = getpagesize() - 1;

+#endif  // WIN32

+

+  /* Adjust mapping offset and mapping size accordingly to

+   * the mapping alignment requirements. */

+  const Elf_Xword map_offset = offset & ~align_mask;

+  const Elf_Word map_size = static_cast<Elf_Word>(offset - map_offset + size);

+

+  /* Make sure mapping size doesn't exceed 4G: may happen on 64-bit ELFs, if

+   * section size is close to 4G, while section offset is badly misaligned. */

+  assert(map_size >= size);

+  if (map_size < size) {

+    _set_errno(EFBIG);

+    return false;

+  }

+

+  /* Map the section. */

+#ifdef  WIN32

+  LARGE_INTEGER converter;

+  converter.QuadPart = map_offset + map_size;

+  HANDLE map_handle = CreateFileMapping(handle, NULL, PAGE_READONLY,

+                                        converter.HighPart, converter.LowPart,

+                                        NULL);

+  assert(map_handle != NULL);

+  if (map_handle != NULL) {

+    converter.QuadPart = map_offset;

+    mapped_at_ = MapViewOfFile(map_handle, FILE_MAP_READ, converter.HighPart,

+                               converter.LowPart, map_size);

+    assert(mapped_at_ != NULL);

+    /* Memory mapping (if successful) will hold extra references to the

+     * mapping, so we can close it right after we mapped file view. */

+    CloseHandle(map_handle);

+  }

+  if (mapped_at_ == NULL) {

+    _set_errno(GetLastError());

+    return false;

+  }

+#else   // WIN32

+  mapped_at_ = mmap(0, map_size, PROT_READ, MAP_SHARED, handle, map_offset);

+  assert(mapped_at_ != MAP_FAILED);

+  if (mapped_at_ == MAP_FAILED) {

+    return false;

+  }

+#endif  // WIN32

+

+  data_ = INC_CPTR(mapped_at_, offset - map_offset);

+  size_ = size;

+

+  return true;

+}

diff --git a/elff/elf_mapped_section.h b/elff/elf_mapped_section.h
new file mode 100644
index 0000000..2f3ca56
--- /dev/null
+++ b/elff/elf_mapped_section.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains declaration of a class ElfMappedSection, that encapsulates

+ * a section of an ELF file, mapped to memory.

+ */

+

+#ifndef ELFF_ELF_MAPPED_SECTION_H_

+#define ELFF_ELF_MAPPED_SECTION_H_

+

+#include "elf_defs.h"

+

+/* Encapsulates a section of an ELF file, mapped to memory. */

+class ElfMappedSection {

+ public:

+  /* Constructs ElfMappedSection instance. */

+  ElfMappedSection();

+

+  /* Destructs ElfMappedSection instance. */

+  ~ElfMappedSection();

+

+  /* Maps ELF file section to memory.

+   * Param:

+   *  handle - Handle to an opened ELF file.

+   *  offset - Offset of the beginning of the section data in ELF file.

+   *    NOTE: we explicitly use 64-bit type for this parameter, since we may

+   *    still allow 32-bit library to process 64 bits ELF/DWARF formats. We

+   *    really only care about section size being small enough to fit in 32

+   *    bits value in this case (which seems to be always true for ELF files,

+   *    as section size is encoded with 32-bit value even in 64-bit ELF file).

+   *  size - Section byte size in ELF file.

+   * Return:

+   *  true on success, or false on failure, with errno providing extended

+   *  error information.

+   *  NOTE: if section has already been mapped, this method immediately

+   *  returns with success.

+   */

+  bool map(ELF_FILE_HANDLE handle, Elf_Xword offset, Elf_Word size);

+

+  /* Checks if section has been mapped. */

+  bool is_mapped() const {

+    return mapped_at_ != NULL;

+  }

+

+  /* Gets address of the beginning of the mapped section. */

+  const void* data() const {

+    assert(is_mapped());

+    return data_;

+  }

+

+  /* Gets section size. */

+  Elf_Word size() const {

+    assert(is_mapped());

+    return size_;

+  }

+

+  /* Checks if an address range is fully contained in this section. */

+  bool is_contained(const void* ptr, size_t rsize) const {

+    assert(is_mapped());

+    return is_mapped() && is_in_section(ptr, rsize, data(), size());

+  }

+

+ protected:

+  /* Beginning of the memory mapping, containing the section.

+   * NOTE: due to page alignment requirements of the mapping API, mapping

+   * address may differ from the address where the actual section data

+   * starts inside that mapping.

+   */

+  void*         mapped_at_;

+

+  /* Address of the beginning of the mapped section. */

+  const void*   data_;

+

+  /* Section size. */

+  Elf_Word      size_;

+};

+

+#endif  // ELFF_ELF_MAPPED_SECTION_H_

diff --git a/elff/elff-common.h b/elff/elff-common.h
new file mode 100644
index 0000000..922de10
--- /dev/null
+++ b/elff/elff-common.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Includes common headers for the ELFF library.

+ */

+

+#ifndef ELFF_ELFF_COMMON_H_

+#define ELFF_ELFF_COMMON_H_

+

+#include "stddef.h"

+#include "sys/types.h"

+#include "assert.h"

+#include "memory.h"

+#include "errno.h"

+#ifdef  WIN32

+#include "Windows.h"

+#else   // WIN32

+#include <sys/mman.h>

+#include <sys/stat.h>

+#include <fcntl.h>

+#endif  // WIN32

+

+static inline void _set_errno(uint32_t err) {

+    errno = err;

+}

+

+/* Main operator new. We overwrite it to redirect memory

+ * allocations to qemu_malloc, instead of malloc. */

+inline void* operator new(size_t size) {

+    return qemu_malloc(size);

+}

+

+/* Main operator delete. We overwrite it to redirect memory

+ * deallocation to qemu_free, instead of free. */

+inline void operator delete(void* p) {

+    if (p != NULL) {

+        qemu_free(p);

+    }

+}

+

+/* Main operator delete for arrays. We overwrite it to redirect

+ * memory deallocation to qemu_free, instead of free. */

+inline void operator delete[](void* p) {

+    if (p != NULL) {

+        qemu_free(p);

+    }

+}

+

+#endif  // ELFF_ELFF_COMMON_H_

diff --git a/elff/elff_api.cc b/elff/elff_api.cc
new file mode 100644
index 0000000..46b2ad1
--- /dev/null
+++ b/elff/elff_api.cc
@@ -0,0 +1,84 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains implementation of routines that encapsulte an API for parsing

+ * an ELF file containing debugging information in DWARF format.

+ */

+

+#include "elff_api.h"

+#include "elf_file.h"

+#include "dwarf_defs.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+ELFF_HANDLE

+elff_init(const char* elf_file_path)

+{

+  ElfFile* elf_file = ElfFile::Create(elf_file_path);

+  return reinterpret_cast<ELFF_HANDLE>(elf_file);

+}

+

+void

+elff_close(ELFF_HANDLE handle)

+{

+  if (handle != NULL) {

+    delete reinterpret_cast<ElfFile*>(handle);

+  }

+}

+

+int

+elff_is_exec(ELFF_HANDLE handle)

+{

+  assert(handle != NULL);

+  if (handle == NULL) {

+    _set_errno(EINVAL);

+    return -1;

+  }

+  return reinterpret_cast<ElfFile*>(handle)->is_exec();

+}

+

+int

+elff_get_pc_address_info(ELFF_HANDLE handle,

+                         uint64_t address,

+                         Elf_AddressInfo* address_info)

+{

+  assert(handle != NULL && address_info != NULL);

+  if (handle == NULL || address_info == NULL) {

+    _set_errno(EINVAL);

+    return -1;

+  }

+

+  if (reinterpret_cast<ElfFile*>(handle)->get_pc_address_info(address,

+                                                              address_info)) {

+    return 0;

+  } else {

+    return -1;

+  }

+}

+

+void

+elff_free_pc_address_info(ELFF_HANDLE handle, Elf_AddressInfo* address_info)

+{

+  assert(handle != NULL && address_info != NULL);

+  if (handle == NULL || address_info == NULL) {

+    return;

+  }

+  reinterpret_cast<ElfFile*>(handle)->free_pc_address_info(address_info);

+}

+

+#ifdef __cplusplus

+}   /* end of extern "C" */

+#endif

+

diff --git a/elff/elff_api.h b/elff/elff_api.h
new file mode 100644
index 0000000..7b02746
--- /dev/null
+++ b/elff/elff_api.h
@@ -0,0 +1,173 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project

+**

+** This software is licensed under the terms of the GNU General Public

+** License version 2, as published by the Free Software Foundation, and

+** may be copied, distributed, and modified under those terms.

+**

+** 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.

+*/

+

+/*

+ * Contains declaration of types, strctures, routines, etc. that encapsulte

+ * an API for parsing an ELF file containing debugging information in DWARF

+ * format.

+ */

+

+#ifndef ELFF_API_H_

+#define ELFF_API_H_

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#include "qemu-common.h"

+

+/* Defines type for a handle used in ELFF API. */

+typedef void* ELFF_HANDLE;

+

+/* Defines an entry for 'inline_stack' array in Elf_AddressInfo structure.

+ * Each entry in the array represents a routine, where routine represented

+ * with the previous array entry has been inlined. First element in the array

+ * (at index 0) represents information for the inlined routine, referenced by

+ * Elf_AddressInfo structure itself. If name for a routine was not available

+ * (DW_AT_name attribute was missing), routine name is set to "<unknown>".

+ * Last entry in the array has all its fields set to zero. It's sufficient

+ * just to check for routine_name field of this structure to be NULL to detect

+ * last entry in the array.

+ */

+typedef struct Elf_InlineInfo {

+  /* Name of the routine where previous routine is inlined.

+   * This field can never be NULL, except for the last array entry.

+   */

+  const char*     routine_name;

+

+  /* Source file name where routine is inlined.

+   * This field can be NULL, if it was not possible to obtain information

+   * about source file location for the routine. If this field is NULL, content

+   * of inlined_in_file_dir and inlined_at_line fields is undefined and should

+   * be ignored. */

+  const char*     inlined_in_file;

+

+  /* Source file directory where routine is inlined.

+   * If inlined_in_file field contains NULL, content of this field is undefined

+   * and should be ignored. */

+  const char*     inlined_in_file_dir;

+

+  /* Source file line number where routine is inlined.

+   * If inlined_in_file field contains NULL, content of this field is undefined

+   * and should be ignored. */

+  uint32_t        inlined_at_line;

+} Elf_InlineInfo;

+

+/* Checks if an entry is the last entry in the array.

+ * Return:

+ *  Boolean: 1 if this is last entry, or zero otherwise.

+ */

+static inline int

+elfinlineinfo_is_last_entry(const Elf_InlineInfo* info) {

+    return info->routine_name == 0;

+}

+

+/* PC address information descriptor.

+ * This descriptor contains as much information about a PC address as it was

+ * possible to collect from an ELF file. */

+typedef struct Elf_AddressInfo {

+  /* Name of the routine containing the address. If name of the routine

+   * was not available (DW_AT_name attribute was missing) this field

+   * is set to "<unknown>". */

+  const char*       routine_name;

+

+  /* Name of the source file containing the routine. If source location for the

+   * routine was not available, this field is set to NULL, and content of

+   * dir_name, and line_number fields of this structure is not defined. */

+  const char*       file_name;

+

+  /* Path to the source file directory. If file_name field of this structure is

+   * NULL, content of this field is not defined. */

+  const char*       dir_name;

+

+  /* Line number in the source file for the address. If file_name field of this

+   * structure is NULL, content of this field is not defined. */

+  uint32_t          line_number;

+

+  /* If routine that contains the given address has been inlined (or it is part

+   * of even deeper inline branch) this array lists information about that

+   * inline branch rooting to the first routine that has not been inlined. The

+   * first element in the array references a routine, where routine containing

+   * the given address has been inlined. The second entry contains information

+   * about a routine referenced by the first entry (and so on). If routine,

+   * containing the given address has not been inlined, this field is set to

+   * NULL. The array ends with an entry containing all zeroes. */

+  Elf_InlineInfo*   inline_stack;

+} Elf_AddressInfo;

+

+//=============================================================================

+// API routines

+//=============================================================================

+

+/* Initializes ELFF API for the given ELF file.

+ * Param:

+ *  elf_file_path - Path to the ELF file to initialize API for.

+ * Return:

+ *  On success, this routine returns a handle that can be used in subsequent

+ *  calls to this API dealing with the given ELF file. On failure this routine

+ *  returns NULL, with errno providing extended error information.

+ *  NOTE: handle returned from this routine must be closed using elff_close().

+ */

+ELFF_HANDLE elff_init(const char* elf_file_path);

+

+/* Closes a handle obtained after successful call to elff_init routine.

+ * Param:

+ *  handle - A handle to close. This handle must be a handle returned from

+ *  a successful call to elff_init routine.

+ */

+void elff_close(ELFF_HANDLE handle);

+

+/* Checks if ELF file represents an executable file, or a shared library.

+ *  handle - A handle obtained from successful call to elff_init().

+ * Return:

+ *  1  if ELF file represents an executable file, or

+ *  0  if ELF file represents a shared library, or

+ *  -1 if handle is invalid.

+ */

+int elff_is_exec(ELFF_HANDLE handle);

+

+/* Gets PC address information.

+ * Param:

+ *  handle - A handle obtained from successful call to elff_init().

+ *  address - PC address to get information for. Address must be relative to

+ *    the beginning of ELF file represented by the handle parameter.

+ *  address_info - Upon success contains information about routine(s) that

+ *    contain the given address.

+ * Return:

+ *  0 if routine(s) containing the given address has been found and information

+ *  has been saved into address_info, or -1 if no appropriate routine for that

+ *  address has been found, or there was a memory error when collecting

+ *  routine(s) information. In case of failure, errno provides extended

+ *  error information.

+ *  NOTE: Successful call to this routine must be complimented with a call

+ *  to free_pc_address_info, so ELFF API can release resources aquired for

+ *  address_info.

+ */

+int elff_get_pc_address_info(ELFF_HANDLE handle,

+                             uint64_t address,

+                             Elf_AddressInfo* address_info);

+

+/* Frees resources acquired for address information in successful call to

+ * get_pc_address_info().

+ * Param:

+ *  handle - A handle obtained from successful call to elff_init().

+ *  address_info - Address information structure, initialized in successful

+ *    call to get_pc_address_info() routine.

+ */

+void elff_free_pc_address_info(ELFF_HANDLE handle,

+                               Elf_AddressInfo* address_info);

+

+#ifdef __cplusplus

+}   /* end of extern "C" */

+#endif

+

+#endif  // ELFF_API_H_

diff --git a/exec-all.h b/exec-all.h
index 0a240ee..c686554 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -76,7 +76,7 @@
                            void *puc);
 void cpu_resume_from_signal(CPUState *env1, void *puc);
 void cpu_io_recompile(CPUState *env, void *retaddr);
-TranslationBlock *tb_gen_code(CPUState *env, 
+TranslationBlock *tb_gen_code(CPUState *env,
                               target_ulong pc, target_ulong cs_base, int flags,
                               int cflags);
 void cpu_exec_init(CPUState *env);
@@ -154,11 +154,23 @@
        jmp_first */
     struct TranslationBlock *jmp_next[2];
     struct TranslationBlock *jmp_first;
-
 #ifdef CONFIG_TRACE
     struct BBRec *bb_rec;
     uint64_t prev_time;
 #endif
+
+#ifdef CONFIG_MEMCHECK
+    /* Maps PCs in this translation block to corresponding PCs in guest address
+     * space. The array is arranged in such way, that every even entry contains
+     * PC in the translation block, followed by an odd entry that contains
+     * guest PC corresponding to that PC in the translation block. This
+     * arrangement is set by tcg_gen_code_common that initializes this array
+     * when performing guest code translation. */
+    target_ulong*   tpc2gpc;
+    /* Number of pairs (pc_tb, pc_guest) in tpc2gpc array. */
+    unsigned int    tpc2gpc_pairs;
+#endif  // CONFIG_MEMCHECK
+
     uint32_t icount;
 };
 
@@ -182,6 +194,60 @@
     return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
 }
 
+#ifdef CONFIG_MEMCHECK
+/* Gets translated PC for a given (translated PC, guest PC) pair.
+ * Return:
+ *  Translated PC, or NULL if pair index was too large.
+ */
+static inline target_ulong
+tb_get_tb_pc(const TranslationBlock* tb, unsigned int pair)
+{
+    return (tb->tpc2gpc != NULL && pair < tb->tpc2gpc_pairs) ?
+                                                    tb->tpc2gpc[pair * 2] : 0;
+}
+
+/* Gets guest PC for a given (translated PC, guest PC) pair.
+ * Return:
+ *  Guest PC, or NULL if pair index was too large.
+ */
+static inline target_ulong
+tb_get_guest_pc(const TranslationBlock* tb, unsigned int pair)
+{
+    return (tb->tpc2gpc != NULL && pair < tb->tpc2gpc_pairs) ?
+            tb->tpc2gpc[pair * 2 + 1] : 0;
+}
+
+/* Gets guest PC for a given translated PC.
+ * Return:
+ *  Guest PC for a given translated PC, or NULL if there was no pair, matching
+ *  translated PC in tb's tpc2gpc array.
+ */
+static inline target_ulong
+tb_search_guest_pc_from_tb_pc(const TranslationBlock* tb, target_ulong tb_pc)
+{
+    if (tb->tpc2gpc != NULL && tb->tpc2gpc_pairs != 0) {
+        unsigned int m_min = 0;
+        unsigned int m_max = (tb->tpc2gpc_pairs - 1) << 1;
+        /* Make sure that tb_pc is within TB array. */
+        if (tb_pc < tb->tpc2gpc[0]) {
+            return 0;
+        }
+        while (m_min <= m_max) {
+            const unsigned int m = ((m_min + m_max) >> 1) & ~1;
+            if (tb_pc < tb->tpc2gpc[m]) {
+                m_max = m - 2;
+            } else if (m == m_max || tb_pc < tb->tpc2gpc[m + 2]) {
+                return tb->tpc2gpc[m + 1];
+            } else {
+                m_min = m + 2;
+            }
+        }
+        return tb->tpc2gpc[m_max + 1];
+    }
+    return 0;
+}
+#endif  // CONFIG_MEMCHECK
+
 TranslationBlock *tb_alloc(target_ulong pc);
 void tb_free(TranslationBlock *tb);
 void tb_flush(CPUState *env);
@@ -368,7 +434,7 @@
 void kqemu_flush(CPUState *env, int global);
 void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr);
 void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr);
-void kqemu_set_phys_mem(uint64_t start_addr, ram_addr_t size, 
+void kqemu_set_phys_mem(uint64_t start_addr, ram_addr_t size,
                         ram_addr_t phys_offset);
 void kqemu_cpu_interrupt(CPUState *env);
 void kqemu_record_dump(void);
diff --git a/exec.c b/exec.c
index d33a3c0..ce6aeda 100644
--- a/exec.c
+++ b/exec.c
@@ -43,6 +43,9 @@
 #if defined(CONFIG_USER_ONLY)
 #include <qemu.h>
 #endif
+#ifdef CONFIG_MEMCHECK
+#include "memcheck/memcheck_api.h"
+#endif  // CONFIG_MEMCHECK
 
 //#define DEBUG_TB_INVALIDATE
 //#define DEBUG_FLUSH
@@ -216,21 +219,21 @@
     DWORD old_protect;
     VirtualProtect(addr, size,
                    PAGE_EXECUTE_READWRITE, &old_protect);
-    
+
 }
 #else
 static void map_exec(void *addr, long size)
 {
     unsigned long start, end, page_size;
-    
+
     page_size = getpagesize();
     start = (unsigned long)addr;
     start &= ~(page_size - 1);
-    
+
     end = (unsigned long)addr + size;
     end += page_size - 1;
     end &= ~(page_size - 1);
-    
+
     mprotect((void *)start, end - start,
              PROT_READ | PROT_WRITE | PROT_EXEC);
 }
@@ -280,7 +283,7 @@
                                     (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
                     page_set_flags(startaddr & TARGET_PAGE_MASK,
                                    TARGET_PAGE_ALIGN(endaddr),
-                                   PAGE_RESERVED); 
+                                   PAGE_RESERVED);
                 }
             } while (!feof(f));
             fclose(f);
@@ -321,7 +324,7 @@
             unsigned long addr = h2g(p);
             page_set_flags(addr & TARGET_PAGE_MASK,
                            TARGET_PAGE_ALIGN(addr + len),
-                           PAGE_RESERVED); 
+                           PAGE_RESERVED);
         }
 #else
         p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
@@ -429,7 +432,7 @@
         code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
     /* The code gen buffer location may have constraints depending on
        the host cpu and OS */
-#if defined(__linux__) 
+#if defined(__linux__)
     {
         int flags;
         void *start = NULL;
@@ -476,7 +479,7 @@
             code_gen_buffer_size = (800 * 1024 * 1024);
 #endif
         code_gen_buffer = mmap(addr, code_gen_buffer_size,
-                               PROT_WRITE | PROT_READ | PROT_EXEC, 
+                               PROT_WRITE | PROT_READ | PROT_EXEC,
                                flags, -1, 0);
         if (code_gen_buffer == MAP_FAILED) {
             fprintf(stderr, "Could not allocate dynamic translator buffer\n");
@@ -489,7 +492,7 @@
 #endif
 #endif /* !USE_STATIC_CODE_GEN_BUFFER */
     map_exec(code_gen_prologue, sizeof(code_gen_prologue));
-    code_gen_buffer_max_size = code_gen_buffer_size - 
+    code_gen_buffer_max_size = code_gen_buffer_size -
         code_gen_max_block_size();
     code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
     tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
@@ -630,6 +633,17 @@
     nb_tbs = 0;
 
     for(env = first_cpu; env != NULL; env = env->next_cpu) {
+#ifdef CONFIG_MEMCHECK
+        int tb_to_clean;
+        for (tb_to_clean = 0; tb_to_clean < TB_JMP_CACHE_SIZE; tb_to_clean++) {
+            if (env->tb_jmp_cache[tb_to_clean] != NULL &&
+                env->tb_jmp_cache[tb_to_clean]->tpc2gpc != NULL) {
+                qemu_free(env->tb_jmp_cache[tb_to_clean]->tpc2gpc);
+                env->tb_jmp_cache[tb_to_clean]->tpc2gpc = NULL;
+                env->tb_jmp_cache[tb_to_clean]->tpc2gpc_pairs = 0;
+            }
+        }
+#endif  // CONFIG_MEMCHECK
         memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
     }
 
@@ -820,6 +834,14 @@
     }
     tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
 
+#ifdef CONFIG_MEMCHECK
+    if (tb->tpc2gpc != NULL) {
+        qemu_free(tb->tpc2gpc);
+        tb->tpc2gpc = NULL;
+        tb->tpc2gpc_pairs = 0;
+    }
+#endif  // CONFIG_MEMCHECK
+
     tb_phys_invalidate_count++;
 }
 
@@ -1185,6 +1207,10 @@
     tb = &tbs[nb_tbs++];
     tb->pc = pc;
     tb->cflags = 0;
+#ifdef CONFIG_MEMCHECK
+    tb->tpc2gpc = NULL;
+    tb->tpc2gpc_pairs = 0;
+#endif  // CONFIG_MEMCHECK
     return tb;
 }
 
@@ -1745,11 +1771,11 @@
     /* Discard jump cache entries for any tb which might potentially
        overlap the flushed page.  */
     i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
-    memset (&env->tb_jmp_cache[i], 0, 
+    memset (&env->tb_jmp_cache[i], 0,
 	    TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
 
     i = tb_jmp_cache_hash_page(addr);
-    memset (&env->tb_jmp_cache[i], 0, 
+    memset (&env->tb_jmp_cache[i], 0,
 	    TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
 }
 
@@ -2076,6 +2102,37 @@
     } else {
         te->addr_write = -1;
     }
+
+#ifdef CONFIG_MEMCHECK
+    /*
+     * If we have memchecker running, we need to make sure that page, cached
+     * into TLB as the result of this operation will comply with our requirement
+     * to cause __ld/__stx_mmu being called for memory access on the pages
+     * containing memory blocks that require access violation checks.
+     *
+     * We need to check with memory checker if we should invalidate this page
+     * iff:
+     *  - Memchecking is enabled.
+     *  - Page that's been cached belongs to the user space.
+     *  - Request to cache this page didn't come from softmmu. We're covered
+     *    there, because after page was cached here we will invalidate it in
+     *    the __ld/__stx_mmu wrapper.
+     *  - Cached page belongs to RAM, not I/O area.
+     *  - Page is cached for read, or write access.
+     */
+    if (memcheck_instrument_mmu && mmu_idx == 1 && !is_softmmu &&
+        (pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
+        (prot & (PAGE_READ | PAGE_WRITE)) &&
+        memcheck_is_checked(vaddr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE)) {
+        if (prot & PAGE_READ) {
+            te->addr_read ^= TARGET_PAGE_MASK;
+        }
+        if (prot & PAGE_WRITE) {
+            te->addr_write ^= TARGET_PAGE_MASK;
+        }
+    }
+#endif  // CONFIG_MEMCHECK
+
     return ret;
 }
 
@@ -3651,7 +3708,7 @@
 
     tb = tb_find_pc((unsigned long)retaddr);
     if (!tb) {
-        cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p", 
+        cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
                   retaddr);
     }
     n = env->icount_decr.u16.low + tb->icount;
@@ -3729,7 +3786,7 @@
     cpu_fprintf(f, "Translation buffer state:\n");
     cpu_fprintf(f, "gen code size       %ld/%ld\n",
                 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
-    cpu_fprintf(f, "TB count            %d/%d\n", 
+    cpu_fprintf(f, "TB count            %d/%d\n",
                 nb_tbs, code_gen_max_blocks);
     cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n",
                 nb_tbs ? target_code_size / nb_tbs : 0,
diff --git a/hw/android_arm.c b/hw/android_arm.c
index 4ef4a10..d656b81 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -20,6 +20,9 @@
 #include "audio/audio.h"
 #include "arm-misc.h"
 #include "console.h"
+#ifdef CONFIG_MEMCHECK
+#include "memcheck/memcheck_api.h"
+#endif  // CONFIG_MEMCHECK
 
 #define ARM_CPU_SAVE_VERSION  1
 
@@ -63,7 +66,7 @@
 #endif
 static void android_arm_init_(ram_addr_t ram_size,
     const char *boot_device,
-    const char *kernel_filename, 
+    const char *kernel_filename,
     const char *kernel_cmdline,
     const char *initrd_filename,
     const char *cpu_model)
@@ -142,9 +145,19 @@
 #endif
 #ifdef CONFIG_TRACE
     extern const char *trace_filename;
-    if (trace_filename != NULL) {
+    /* Init trace device if either tracing, or memory checking is enabled. */
+    if (trace_filename != NULL
+#ifdef CONFIG_MEMCHECK
+        || memcheck_enabled
+#endif  // CONFIG_MEMCHECK
+       ) {
         trace_dev_init();
     }
+    if (trace_filename != NULL) {
+        dprint( "Trace file name is set to %s\n", trace_filename );
+    } else  {
+        dprint("Trace file name is not set\n");
+    }
 #endif
 
 #if TEST_SWITCH
diff --git a/hw/goldfish_trace.c b/hw/goldfish_trace.c
index c4f2f92..742ac63 100644
--- a/hw/goldfish_trace.c
+++ b/hw/goldfish_trace.c
@@ -15,12 +15,16 @@
  */
 #include "qemu_file.h"
 #include "goldfish_trace.h"
+#ifdef CONFIG_MEMCHECK
+#include "memcheck/memcheck.h"
+#endif  // CONFIG_MEMCHECK
 
 //#define DEBUG   1
 
 extern void cpu_loop_exit(void);
 
 extern int tracing;
+extern const char *trace_filename;
 
 /* for execve */
 static char path[CLIENT_PAGE_SIZE];
@@ -44,28 +48,51 @@
 
     switch (offset >> 2) {
     case TRACE_DEV_REG_SWITCH:  // context switch, switch to pid
-        trace_switch(value);
+        if (trace_filename != NULL) {
+            trace_switch(value);
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, context switch %u\n", value);
+            printf("QEMU.trace: kernel, context switch %u\n", value);
 #endif
+        }
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            memcheck_switch(value);
+        }
+#endif  // CONFIG_MEMCHECK
         break;
     case TRACE_DEV_REG_TGID:    // save the tgid for the following fork/clone
         tgid = value;
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, tgid %u\n", value);
+        if (trace_filename != NULL) {
+            printf("QEMU.trace: kernel, tgid %u\n", value);
+        }
 #endif
         break;
     case TRACE_DEV_REG_FORK:    // fork, fork new pid
-        trace_fork(tgid, value);
+        if (trace_filename != NULL) {
+            trace_fork(tgid, value);
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, fork %u\n", value);
+            printf("QEMU.trace: kernel, fork %u\n", value);
 #endif
+        }
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            memcheck_fork(tgid, value);
+        }
+#endif  // CONFIG_MEMCHECK
         break;
     case TRACE_DEV_REG_CLONE:    // fork, clone new pid (i.e. thread)
-        trace_clone(tgid, value);
+        if (trace_filename != NULL) {
+            trace_clone(tgid, value);
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, clone %u\n", value);
+            printf("QEMU.trace: kernel, clone %u\n", value);
 #endif
+        }
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            memcheck_clone(tgid, value);
+        }
+#endif  // CONFIG_MEMCHECK
         break;
     case TRACE_DEV_REG_EXECVE_VMSTART:  // execve, vstart
         vstart = value;
@@ -78,10 +105,23 @@
         break;
     case TRACE_DEV_REG_EXECVE_EXEPATH:  // init exec, path of EXE
         vstrcpy(value, path, CLIENT_PAGE_SIZE);
-        trace_init_exec(vstart, vend, eoff, path);
+        if (trace_filename != NULL) {
+            trace_init_exec(vstart, vend, eoff, path);
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
+            printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n",
+                   vstart, vend, eoff, path);
 #endif
+        }
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            if (path[0] == '\0') {
+                // vstrcpy may fail to copy path. In this case lets do it
+                // differently.
+                memcheck_get_guest_kernel_string(path, value, CLIENT_PAGE_SIZE);
+            }
+            memcheck_mmap_exepath(vstart, vend, eoff, path);
+        }
+#endif  // CONFIG_MEMCHECK
         path[0] = 0;
         break;
     case TRACE_DEV_REG_CMDLINE_LEN:     // execve, process cmdline length
@@ -89,23 +129,37 @@
         break;
     case TRACE_DEV_REG_CMDLINE:         // execve, process cmdline
         cpu_memory_rw_debug(cpu_single_env, value, arg, cmdlen, 0);
-        trace_execve(arg, cmdlen);
+        if (trace_filename != NULL) {
+            trace_execve(arg, cmdlen);
+        }
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            memcheck_set_cmd_line(arg, cmdlen);
+        }
+#endif  // CONFIG_MEMCHECK
 #ifdef DEBUG
-        {
+        if (trace_filename != NULL) {
             int i;
             for (i = 0; i < cmdlen; i ++)
                 if (i != cmdlen - 1 && arg[i] == 0)
                     arg[i] = ' ';
             printf("QEMU.trace: kernel, execve %s[%d]\n", arg, cmdlen);
+            arg[0] = 0;
         }
 #endif
-        arg[0] = 0;
         break;
     case TRACE_DEV_REG_EXIT:            // exit, exit current process with exit code
-        trace_exit(value);
+        if (trace_filename != NULL) {
+            trace_exit(value);
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, exit %x\n", value);
+            printf("QEMU.trace: kernel, exit %x\n", value);
 #endif
+        }
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            memcheck_exit(value);
+        }
+#endif  // CONFIG_MEMCHECK
         break;
     case TRACE_DEV_REG_NAME:            // record thread name
         vstrcpy(value, path, CLIENT_PAGE_SIZE);
@@ -115,28 +169,49 @@
         if (path[len - 1] == '\n') {
             path[len - 1] = 0;
         }
-        trace_name(path);
+        if (trace_filename != NULL) {
+            trace_name(path);
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, name %s\n", path);
+            printf("QEMU.trace: kernel, name %s\n", path);
 #endif
+        }
         break;
     case TRACE_DEV_REG_MMAP_EXEPATH:    // mmap, path of EXE, the others are same as execve
         vstrcpy(value, path, CLIENT_PAGE_SIZE);
-        trace_mmap(vstart, vend, eoff, path);
+        if (trace_filename != NULL) {
+            trace_mmap(vstart, vend, eoff, path);
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
+            printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
 #endif
+        }
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            if (path[0] == '\0') {
+                // vstrcpy may fail to copy path. In this case lets do it
+                // differently.
+                memcheck_get_guest_kernel_string(path, value, CLIENT_PAGE_SIZE);
+            }
+            memcheck_mmap_exepath(vstart, vend, eoff, path);
+        }
+#endif  // CONFIG_MEMCHECK
         path[0] = 0;
         break;
     case TRACE_DEV_REG_INIT_PID:        // init, name the pid that starts before device registered
         pid = value;
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            memcheck_init_pid(value);
+        }
+#endif  // CONFIG_MEMCHECK
         break;
     case TRACE_DEV_REG_INIT_NAME:       // init, the comm of the init pid
         vstrcpy(value, path, CLIENT_PAGE_SIZE);
-        trace_init_name(tgid, pid, path);
+        if (trace_filename != NULL) {
+            trace_init_name(tgid, pid, path);
 #ifdef DEBUG
-        printf("QEMU.trace: kernel, init name %u [%s]\n", pid, path);
+            printf("QEMU.trace: kernel, init name %u [%s]\n", pid, path);
 #endif
+        }
         path[0] = 0;
         break;
 
@@ -145,18 +220,21 @@
         break;
     case TRACE_DEV_REG_DYN_SYM:         // add dynamic symbol
         vstrcpy(value, arg, CLIENT_PAGE_SIZE);
-        trace_dynamic_symbol_add(dsaddr, arg);
+        if (trace_filename != NULL) {
+            trace_dynamic_symbol_add(dsaddr, arg);
 #ifdef DEBUG
-        printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, arg);
+            printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, arg);
 #endif
+        }
         arg[0] = 0;
         break;
     case TRACE_DEV_REG_REMOVE_ADDR:         // remove dynamic symbol addr
-        trace_dynamic_symbol_remove(value);
+        if (trace_filename != NULL) {
+            trace_dynamic_symbol_remove(value);
 #ifdef DEBUG
-        printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
+            printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
 #endif
-        arg[0] = 0;
+        }
         break;
 
     case TRACE_DEV_REG_PRINT_STR:       // print string
@@ -172,10 +250,11 @@
         break;
 
     case TRACE_DEV_REG_STOP_EMU:        // stop the VM execution
-        // To ensure that the number of instructions executed in this
-        // block is correct, we pretend that there was an exception.
-        trace_exception(0);
-
+        if (trace_filename != NULL) {
+            // To ensure that the number of instructions executed in this
+            // block is correct, we pretend that there was an exception.
+            trace_exception(0);
+        }
         cpu_single_env->exception_index = EXCP_HLT;
         cpu_single_env->halted = 1;
         qemu_system_shutdown_request();
@@ -183,14 +262,19 @@
         break;
 
     case TRACE_DEV_REG_ENABLE:          // tracing enable: 0 = stop, 1 = start
-        if (value == 1)
-            start_tracing();
+        if (value == 1) {
+            if (trace_filename != NULL) {
+                start_tracing();
+            }
+        }
         else if (value == 0) {
-            stop_tracing();
+            if (trace_filename != NULL) {
+                stop_tracing();
 
-            // To ensure that the number of instructions executed in this
-            // block is correct, we pretend that there was an exception.
-            trace_exception(0);
+                // To ensure that the number of instructions executed in this
+                // block is correct, we pretend that there was an exception.
+                trace_exception(0);
+            }
         }
         break;
 
@@ -198,7 +282,14 @@
         unmap_start = value;
         break;
     case TRACE_DEV_REG_UNMAP_END:
-        trace_munmap(unmap_start, value);
+        if (trace_filename != NULL) {
+            trace_munmap(unmap_start, value);
+        }
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled) {
+            memcheck_unmap(unmap_start, value);
+        }
+#endif  // CONFIG_MEMCHECK
         break;
 
     case TRACE_DEV_REG_METHOD_ENTRY:
@@ -207,12 +298,46 @@
     case TRACE_DEV_REG_NATIVE_ENTRY:
     case TRACE_DEV_REG_NATIVE_EXIT:
     case TRACE_DEV_REG_NATIVE_EXCEPTION:
-        if (tracing) {
-            int call_type = (offset - 4096) >> 2;
-            trace_interpreted_method(value, call_type);
+        if (trace_filename != NULL) {
+            if (tracing) {
+                int call_type = (offset - 4096) >> 2;
+                trace_interpreted_method(value, call_type);
+            }
         }
         break;
 
+#ifdef CONFIG_MEMCHECK
+    case TRACE_DEV_REG_MALLOC:
+        if (memcheck_enabled) {
+            memcheck_guest_alloc(value);
+        }
+        break;
+
+    case TRACE_DEV_REG_FREE_PTR:
+        if (memcheck_enabled) {
+            memcheck_guest_free(value);
+        }
+        break;
+
+    case TRACE_DEV_REG_QUERY_MALLOC:
+        if (memcheck_enabled) {
+            memcheck_guest_query_malloc(value);
+        }
+        break;
+
+    case TRACE_DEV_REG_LIBC_INIT:
+        if (memcheck_enabled) {
+            memcheck_guest_libc_initialized(value);
+        }
+        break;
+
+    case TRACE_DEV_REG_PRINT_USER_STR:
+        if (memcheck_enabled) {
+            memcheck_guest_print_str(value);
+        }
+        break;
+#endif // CONFIG_MEMCHECK
+
     default:
         if (offset < 4096) {
             cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset);
diff --git a/memcheck/memcheck.c b/memcheck/memcheck.c
new file mode 100644
index 0000000..9308c9f
--- /dev/null
+++ b/memcheck/memcheck.c
@@ -0,0 +1,648 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains implementation of memory checking framework in the emulator.
+ */
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "sys-queue.h"
+#include "qemu_file.h"
+#include "elff_api.h"
+#include "memcheck.h"
+#include "memcheck_proc_management.h"
+#include "memcheck_util.h"
+#include "memcheck_logging.h"
+
+// =============================================================================
+// Global data
+// =============================================================================
+
+/* Controls what messages from the guest should be printed to emulator's
+ * stdout. This variable holds a combinations of TRACE_LIBC_XXX flags. */
+uint32_t trace_flags = 0;
+
+/* Global flag, indicating whether or not memchecking has been enabled
+ * for the current emulator session. 1 means that memchecking has been enabled,
+ * 0 means that memchecking has not been enabled. */
+int memcheck_enabled = 0;
+
+/* Global flag, indicating whether or not __ld/__stx_mmu should be instrumented
+ * for checking for access violations. If read / write access violation check
+ * has been disabled by -memcheck flags, there is no need to instrument mmu
+ * routines and waste performance.
+ * 1 means that instrumenting is required, 0 means that instrumenting is not
+ * required. */
+int memcheck_instrument_mmu = 0;
+
+/* Global flag, indicating whether or not memchecker is collecting call stack.
+ * 1 - call stack is being collected, 0 means that stack is not being
+ * collected. */
+int memcheck_watch_call_stack = 1;
+
+// =============================================================================
+// Static routines.
+// =============================================================================
+
+/* Prints invalid pointer access violation information.
+ * Param:
+ *  proc - Process that caused access violation.
+ *  ptr - Pointer that caused access violation.
+ *  routine - If 1, access violation has occurred in 'free' routine.
+ *      If 2, access violation has occurred in 'realloc' routine.
+ */
+static void
+av_invalid_pointer(ProcDesc* proc, target_ulong ptr, int routine)
+{
+    if (trace_flags & TRACE_CHECK_INVALID_PTR_ENABLED) {
+        printf("memcheck: Access violation is detected in process %s[pid=%u]:\n"
+          "  INVALID POINTER 0x%08X is used in '%s' operation.\n"
+          "  Allocation descriptor for this pointer has not been found in the\n"
+          "  allocation map for the process. Most likely, this is an attempt\n"
+          "  to %s a pointer that has been freed.\n",
+          proc->image_path, proc->pid, ptr, routine == 1 ? "free" : "realloc",
+          routine == 1 ? "free" : "reallocate");
+    }
+}
+
+/* Prints read / write access violation information.
+ * Param:
+ *  proc - Process that caused access violation.
+ *  desc - Allocation descriptor for the violation.
+ *  addr - Address at which vilation has occurred.
+ *  data_size - Size of data accessed at the 'addr'.
+ *  val - If access violation has occurred at write operation, this parameter
+ *      contains value that's being written to 'addr'. For read violation this
+ *      parameter is not used.
+ *  retaddr - Code address (in TB) where access violation has occurred.
+ *  is_read - If 1, access violation has occurred when memory at 'addr' has been
+ *      read. If 0, access violation has occurred when memory was written.
+ */
+static void
+av_access_violation(ProcDesc* proc,
+                    MallocDescEx* desc,
+                    target_ulong addr,
+                    uint32_t data_size,
+                    uint64_t val,
+                    target_ulong retaddr,
+                    int is_read)
+{
+    target_ulong vaddr;
+    Elf_AddressInfo elff_info;
+    ELFF_HANDLE elff_handle = NULL;
+
+    desc->malloc_desc.av_count++;
+    if ((is_read && !(trace_flags & TRACE_CHECK_READ_VIOLATION_ENABLED)) ||
+        (!is_read && !(trace_flags & TRACE_CHECK_WRITE_VIOLATION_ENABLED))) {
+        return;
+    }
+
+    /* Convert host address to guest address. */
+    vaddr = memcheck_tpc_to_gpc(retaddr);
+    printf("memcheck: Access violation is detected in process %s[pid=%u]:\n",
+           proc->image_path, proc->pid);
+
+    /* Obtain routine, filename / line info for the address. */
+    const MMRangeDesc* rdesc = procdesc_get_range_desc(proc, vaddr);
+    if (rdesc != NULL) {
+        int elff_res;
+        printf("  In module %s at address 0x%08X\n", rdesc->path, vaddr);
+        elff_res =
+          memcheck_get_address_info(vaddr, rdesc, &elff_info, &elff_handle);
+        if (elff_res == 0) {
+            printf("  In routine %s in %s/%s:%u\n",
+                   elff_info.routine_name, elff_info.dir_name,
+                   elff_info.file_name, elff_info.line_number);
+            if (elff_info.inline_stack != NULL) {
+                const Elf_InlineInfo* inl = elff_info.inline_stack;
+                int index = 0;
+                for (; inl[index].routine_name != NULL; index++) {
+                    char align[64];
+                    size_t set_align = 4 + index * 2;
+                    if (set_align >= sizeof(align)) {
+                        set_align = sizeof(align) -1;
+                    }
+                    memset(align, ' ', set_align);
+                    align[set_align] = '\0';
+                    printf(align);
+                    if (inl[index].inlined_in_file == NULL) {
+                        printf("inlined to %s in unknown location\n",
+                               inl[index].routine_name);
+                    } else {
+                        printf("inlined to %s in %s/%s:%u\n",
+                               inl[index].routine_name,
+                               inl[index].inlined_in_file_dir,
+                               inl[index].inlined_in_file,
+                               inl[index].inlined_at_line);
+                    }
+                }
+            }
+            elff_free_pc_address_info(elff_handle, &elff_info);
+            elff_close(elff_handle);
+        } else if (elff_res == 1) {
+            printf("  Unable to obtain routine information. Symbols file is not found.\n");
+        } else {
+            printf("  Unable to obtain routine information.\n"
+                   "  Symbols file doesn't contain debugging information for address 0x%08X.\n",
+                    mmrangedesc_get_module_offset(rdesc, vaddr));
+        }
+    } else {
+        printf("  In unknown module at address 0x%08X\n", vaddr);
+    }
+
+    printf("  Process attempts to %s %u bytes %s address 0x%08X\n",
+           is_read ? "read" : "write", data_size,
+           is_read ? "from" : "to", addr);
+    printf("  Accessed range belongs to the %s guarding area of allocated block.\n",
+           addr < (target_ulong)mallocdesc_get_user_ptr(&desc->malloc_desc) ?
+                "prefix" : "suffix");
+    printf("  Allocation descriptor for this violation:\n");
+    memcheck_dump_malloc_desc(desc, 1, 0);
+}
+
+/* Validates access to a guest address.
+ * Param:
+ *  addr - Virtual address in the guest space where memory is accessed.
+ *  data_size - Size of the accessed data.
+ *  proc_ptr - Upon exit from this routine contains pointer to the process
+ *      descriptor for the current process, or NULL, if no such descriptor has
+ *      been found.
+ *  desc_ptr - Upon exit from this routine contains pointer to the allocation
+ *      descriptor matching given address range, or NULL, if allocation
+ *      descriptor for the validated memory range has not been found.
+ * Return:
+ *  0 if access to the given guest address range doesn't violate anything, or
+ *  1 if given guest address range doesn't match any entry in the current
+ *      process allocation descriptors map, or
+ *  -1 if a violation has been detected.
+ */
+static int
+memcheck_common_access_validation(target_ulong addr,
+                                  uint32_t data_size,
+                                  ProcDesc** proc_ptr,
+                                  MallocDescEx** desc_ptr)
+{
+    MallocDescEx* desc;
+    target_ulong validating_range_end;
+    target_ulong user_range_end;
+
+    ProcDesc* proc = get_current_process();
+    *proc_ptr = proc;
+    if (proc == NULL) {
+        *desc_ptr = NULL;
+        return 1;
+    }
+
+    desc = procdesc_find_malloc_for_range(proc, addr, data_size);
+    *desc_ptr = desc;
+    if (desc == NULL) {
+        return 1;
+    }
+
+    /* Verify that validating address range doesn't start before the address
+     * available to the user. */
+    if (addr < mallocdesc_get_user_ptr(&desc->malloc_desc)) {
+        // Stepped on the prefix guarding area.
+        return -1;
+    }
+
+    validating_range_end = addr + data_size;
+    user_range_end = mallocdesc_get_user_alloc_end(&desc->malloc_desc);
+
+    /* Verify that validating address range ends inside the user block.
+     * We may step on the suffix guarding area because of alignment issue.
+     * For example, the application code reads last byte in the allocated block
+     * with something like this:
+     *
+     *      char last_byte_value = *(char*)last_byte_address;
+     *
+     * and this code got compiled into something like this:
+     *
+     *      mov eax, [last_byte_address];
+     *      mov [last_byte_value], al;
+     *
+     * In this case we will catch a read from the suffix area, even though
+     * there were no errors in the code. So, in order to prevent such "false
+     * negative" alarms, lets "forgive" this violation.
+     * There is one bad thing about this "forgivness" though, as it may very
+     * well be, that in real life some of these "out of bound" bytes will cross
+     * page boundaries, marching into a page that has not been mapped to the
+     * process.
+     */
+    if (validating_range_end <= user_range_end) {
+        // Validating address range is fully contained inside the user block.
+        return 0;
+    }
+
+    /* Lets see if this AV is caused by an alignment issue.*/
+    if ((validating_range_end - user_range_end) < data_size) {
+        /* Could be an alignment. */
+        return 0;
+    }
+
+    return -1;
+}
+
+/* Checks if process has allocation descriptors for pages defined by a buffer.
+ * Param:
+ *  addr - Starting address of a buffer.
+ *  buf_size - Buffer size.
+ * Return:
+ *  1 if process has allocations descriptors for pages defined by a buffer, or
+ *  0 if pages containing given buffer don't have any memory allocations in
+ *  them.
+ */
+static inline int
+procdesc_contains_allocs(ProcDesc* proc, target_ulong addr, uint32_t buf_size) {
+    if (proc != NULL) {
+        // Beginning of the page containing last byte in range.
+        const target_ulong end_page = (addr + buf_size - 1) & TARGET_PAGE_MASK;
+        // Adjust beginning of the range to the beginning of the page.
+        addr &= TARGET_PAGE_MASK;
+        // Total size of range to check for descriptors.
+        buf_size = end_page - addr + TARGET_PAGE_SIZE + 1;
+        return procdesc_find_malloc_for_range(proc, addr, buf_size) ? 1 : 0;
+    } else {
+        return 0;
+    }
+}
+
+// =============================================================================
+// Memchecker API.
+// =============================================================================
+
+void
+memcheck_init(const char* tracing_flags)
+{
+    if (*tracing_flags == '0') {
+        // Memchecker is disabled.
+        return;
+    } else if (*tracing_flags == '1') {
+        // Set default tracing.
+        trace_flags = TRACE_CHECK_LEAK_ENABLED             |
+                      TRACE_CHECK_READ_VIOLATION_ENABLED   |
+                      TRACE_CHECK_INVALID_PTR_ENABLED      |
+                      TRACE_CHECK_WRITE_VIOLATION_ENABLED;
+    }
+
+    // Parse -memcheck option params, converting them into tracing flags.
+    while (*tracing_flags) {
+        switch (*tracing_flags) {
+            case 'A':
+                // Enable all emulator's tracing messages.
+                trace_flags |= TRACE_ALL_ENABLED;
+                break;
+            case 'F':
+                // Enable fork() tracing.
+                trace_flags |= TRACE_PROC_FORK_ENABLED;
+                break;
+            case 'S':
+                // Enable guest process staring tracing.
+                trace_flags |= TRACE_PROC_START_ENABLED;
+                break;
+            case 'E':
+                // Enable guest process exiting tracing.
+                trace_flags |= TRACE_PROC_EXIT_ENABLED;
+                break;
+            case 'C':
+                // Enable clone() tracing.
+                trace_flags |= TRACE_PROC_CLONE_ENABLED;
+                break;
+            case 'N':
+                // Enable new PID allocation tracing.
+                trace_flags |= TRACE_PROC_NEW_PID_ENABLED;
+                break;
+            case 'B':
+                // Enable libc.so initialization tracing.
+                trace_flags |= TRACE_PROC_LIBC_INIT_ENABLED;
+                break;
+            case 'L':
+                // Enable memory leaks tracing.
+                trace_flags |= TRACE_CHECK_LEAK_ENABLED;
+                break;
+            case 'I':
+                // Enable invalid free / realloc pointer tracing.
+                trace_flags |= TRACE_CHECK_INVALID_PTR_ENABLED;
+                break;
+            case 'R':
+                // Enable reading violations tracing.
+                trace_flags |= TRACE_CHECK_READ_VIOLATION_ENABLED;
+                break;
+            case 'W':
+                // Enable writing violations tracing.
+                trace_flags |= TRACE_CHECK_WRITE_VIOLATION_ENABLED;
+                break;
+            case 'M':
+                // Enable module mapping tracing.
+                trace_flags |= TRACE_PROC_MMAP_ENABLED;
+                break;
+            default:
+                break;
+        }
+        if (trace_flags == TRACE_ALL_ENABLED) {
+            break;
+        }
+        tracing_flags++;
+    }
+
+    /* Lets see if we need to instrument MMU, injecting memory access checking.
+     * We instrument MMU only if we monitor read, or write memory access. */
+    if (trace_flags & (TRACE_CHECK_READ_VIOLATION_ENABLED |
+                       TRACE_CHECK_WRITE_VIOLATION_ENABLED)) {
+        memcheck_instrument_mmu = 1;
+    } else {
+        memcheck_instrument_mmu = 0;
+    }
+
+    memcheck_init_proc_management();
+
+    /* Lets check env. variables needed for memory checking. */
+    if (getenv("ANDROID_PROJECT_OUT") == NULL) {
+        printf("memcheck: Missing ANDROID_PROJECT_OUT environment variable, that is used\n"
+               "to calculate path to symbol files.\n");
+    }
+
+    // Always set this flag at the very end of the initialization!
+    memcheck_enabled = 1;
+}
+
+void
+memcheck_guest_libc_initialized(uint32_t pid)
+{
+    ProcDesc* proc = get_process_from_pid(pid);
+    if (proc == NULL) {
+        ME("memcheck: Unable to obtain process for libc_init pid=%u", pid);
+        return;
+    }
+    proc->flags |= PROC_FLAG_LIBC_INITIALIZED;
+
+    /* When process initializes its own libc.so instance, it means that now
+     * it has fresh heap. So, at this point we must get rid of all entries
+     * (inherited and transition) that were collected in this process'
+     * allocation descriptors map. */
+    procdesc_empty_alloc_map(proc);
+    T(PROC_LIBC_INIT, "memcheck: libc.so has been initialized for %s[pid=%u]\n",
+      proc->image_path, proc->pid);
+}
+
+void
+memcheck_guest_alloc(target_ulong guest_address)
+{
+    MallocDescEx desc;
+    MallocDescEx replaced;
+    RBTMapResult insert_res;
+    ProcDesc* proc;
+    ThreadDesc* thread;
+    uint32_t indx;
+
+    // Copy allocation descriptor from guest to emulator.
+    memcheck_get_malloc_descriptor(&desc.malloc_desc, guest_address);
+    desc.flags = 0;
+    desc.call_stack = NULL;
+    desc.call_stack_count = 0;
+
+    proc = get_process_from_pid(desc.malloc_desc.allocator_pid);
+    if (proc == NULL) {
+        ME("memcheck: Unable to obtain process for allocation pid=%u",
+           desc.malloc_desc.allocator_pid);
+        memcheck_fail_alloc(guest_address);
+        return;
+    }
+
+    if (!procdesc_is_executing(proc)) {
+        desc.flags |= MDESC_FLAG_TRANSITION_ENTRY;
+    }
+
+    /* Copy thread's calling stack to the allocation descriptor. */
+    thread = get_current_thread();
+    desc.call_stack_count = thread->call_stack_count;
+    if (desc.call_stack_count) {
+        desc.call_stack = qemu_malloc(desc.call_stack_count * sizeof(target_ulong));
+        if (desc.call_stack == NULL) {
+            ME("memcheck: Unable to allocate %u bytes for the calling stack",
+               desc.call_stack_count * sizeof(target_ulong));
+            return;
+        }
+    }
+
+    /* Thread's calling stack is in descending order (i.e. first entry in the
+     * thread's stack is the most distant routine from the current one). On the
+     * other hand, we keep calling stack entries in allocation descriptor in
+     * assending order. */
+    for (indx = 0; indx < thread->call_stack_count; indx++) {
+        desc.call_stack[indx] =
+           thread->call_stack[thread->call_stack_count - 1 - indx].call_address;
+    }
+
+    // Save malloc descriptor in the map.
+    insert_res = procdesc_add_malloc(proc, &desc, &replaced);
+    if (insert_res == RBT_MAP_RESULT_ENTRY_INSERTED) {
+        // Invalidate TLB cache for the allocated block.
+        if (memcheck_instrument_mmu) {
+            invalidate_tlb_cache(desc.malloc_desc.ptr,
+                                mallocdesc_get_alloc_end(&desc.malloc_desc));
+        }
+    } else if (insert_res == RBT_MAP_RESULT_ENTRY_REPLACED) {
+        /* We don't expect to have another entry in the map that matches
+         * inserting entry. This is an error condition for us, indicating
+         * that we somehow lost track of memory allocations. */
+        ME("memcheck: Duplicate allocation blocks:");
+        if (VERBOSE_CHECK(memcheck)) {
+            printf("   New block:\n");
+            memcheck_dump_malloc_desc(&desc, 1, 1);
+            printf("   Replaced block:\n");
+            memcheck_dump_malloc_desc(&replaced, 1, 1);
+        }
+        if (replaced.call_stack != NULL) {
+            qemu_free(replaced.call_stack);
+        }
+    } else {
+        ME("memcheck: Unable to insert an entry to the allocation map:");
+        if (VERBOSE_CHECK(memcheck)) {
+            memcheck_dump_malloc_desc(&desc, 1, 1);
+        }
+        memcheck_fail_alloc(guest_address);
+        return;
+    }
+}
+
+void
+memcheck_guest_free(target_ulong guest_address)
+{
+    MallocFree desc;
+    MallocDescEx pulled;
+    int pull_res;
+    ProcDesc* proc;
+
+    // Copy free descriptor from guest to emulator.
+    memcheck_get_free_descriptor(&desc, guest_address);
+
+    proc = get_process_from_pid(desc.free_pid);
+    if (proc == NULL) {
+        ME("memcheck: Unable to obtain process for pid=%u on free",
+           desc.free_pid);
+        memcheck_fail_free(guest_address);
+        return;
+    }
+
+    // Pull matching entry from the map.
+    pull_res = procdesc_pull_malloc(proc, desc.ptr, &pulled);
+    if (pull_res) {
+        av_invalid_pointer(proc, desc.ptr, 1);
+        memcheck_fail_free(guest_address);
+        return;
+    }
+
+    // Make sure that ptr has expected value
+    if (desc.ptr != mallocdesc_get_user_ptr(&pulled.malloc_desc)) {
+        if (trace_flags & TRACE_CHECK_INVALID_PTR_ENABLED) {
+            printf("memcheck: Access violation is detected in process %s[pid=%u]:\n",
+                   proc->image_path, proc->pid);
+            printf("  INVALID POINTER 0x%08X is used in 'free' operation.\n"
+                   "  This pointer is unexpected for 'free' operation, as allocation\n"
+                   "  descriptor found for this pointer in the process' allocation map\n"
+                   "  suggests that 0x%08X is the pointer to be used to free this block.\n"
+                   "  Allocation descriptor matching the pointer:\n",
+                   desc.ptr,
+                   (uint32_t)mallocdesc_get_user_ptr(&pulled.malloc_desc));
+            memcheck_dump_malloc_desc(&pulled, 1, 0);
+        }
+    }
+    if (pulled.call_stack != NULL) {
+        qemu_free(pulled.call_stack);
+    }
+}
+
+void
+memcheck_guest_query_malloc(target_ulong guest_address)
+{
+    MallocDescQuery qdesc;
+    MallocDescEx* found;
+    ProcDesc* proc;
+
+    // Copy free descriptor from guest to emulator.
+    memcheck_get_query_descriptor(&qdesc, guest_address);
+
+    proc = get_process_from_pid(qdesc.query_pid);
+    if (proc == NULL) {
+        ME("memcheck: Unable to obtain process for pid=%u on query_%s",
+           qdesc.query_pid, qdesc.routine == 1 ? "free" : "realloc");
+        memcheck_fail_query(guest_address);
+        return;
+    }
+
+    // Find allocation entry for the given address.
+    found = procdesc_find_malloc(proc, qdesc.ptr);
+    if (found == NULL) {
+        av_invalid_pointer(proc, qdesc.ptr, qdesc.routine);
+        memcheck_fail_query(guest_address);
+        return;
+    }
+
+    // Copy allocation descriptor back to the guest's space.
+    memcheck_set_malloc_descriptor(qdesc.desc, &found->malloc_desc);
+}
+
+void
+memcheck_guest_print_str(target_ulong str) {
+    char str_copy[4096];
+    memcheck_get_guest_string(str_copy, str, sizeof(str_copy));
+    printf(str_copy);
+}
+
+/* Validates read operations, detected in __ldx_mmu routine.
+ * This routine is called from __ldx_mmu wrapper implemented in
+ * softmmu_template.h on condition that loading is occurring from user memory.
+ * Param:
+ *  addr - Virtual address in the guest space where memory is read.
+ *  data_size - Size of the read.
+ *  retaddr - Code address (in TB) that accesses memory.
+ * Return:
+ *  1 if TLB record for the accessed page should be invalidated in order to
+ *  ensure that subsequent attempts to access data in this page will cause
+ *  __ld/stx_mmu to be used. If memchecker is no longer interested in monitoring
+ * access to this page, this routine returns 0.
+ */
+int
+memcheck_validate_ld(target_ulong addr,
+                     uint32_t data_size,
+                     target_ulong retaddr)
+{
+    ProcDesc* proc;
+    MallocDescEx* desc;
+
+    int res = memcheck_common_access_validation(addr, data_size, &proc, &desc);
+    if (res == -1) {
+        av_access_violation(proc, desc, addr, data_size, 0, retaddr, 1);
+        return 1;
+    }
+
+    /* Even though descriptor for the given address range has not been found,
+     * we need to make sure that pages containing the given address range
+     * don't contain other descriptors. */
+    return res ? procdesc_contains_allocs(proc, addr, data_size) : 0;
+}
+
+/* Validates write operations, detected in __stx_mmu routine.
+ * This routine is called from __stx_mmu wrapper implemented in
+ * softmmu_template.h on condition that storing is occurring from user memory.
+ * Param:
+ *  addr - Virtual address in the guest space where memory is written.
+ *  data_size - Size of the write.
+ *  value - Value to be written. Note that we typecast all values to 64 bits,
+ *      since this will fit all data sizes.
+ *  retaddr - Code address (in TB) that accesses memory.
+ * Return:
+ *  1 if TLB record for the accessed page should be invalidated in order to
+ *  ensure that subsequent attempts to access data in this page will cause
+ *  __ld/stx_mmu to be used. If memchecker is no longer interested in monitoring
+ * access to this page, this routine returns 0.
+ */
+int
+memcheck_validate_st(target_ulong addr,
+                     uint32_t data_size,
+                     uint64_t value,
+                     target_ulong retaddr)
+{
+    MallocDescEx* desc;
+    ProcDesc* proc;
+
+    int res = memcheck_common_access_validation(addr, data_size, &proc, &desc);
+    if (res == -1) {
+        av_access_violation(proc, desc, addr, data_size, value, retaddr, 0);
+        return 1;
+    }
+
+    /* Even though descriptor for the given address range has not been found,
+     * we need to make sure that pages containing the given address range
+     * don't contain other descriptors. */
+    return res ? procdesc_contains_allocs(proc, addr, data_size) : 0;
+}
+
+/* Checks if given address range in the context of the current process is under
+ * surveillance.
+ * Param:
+ *  addr - Starting address of a range.
+ *  size - Range size.
+ * Return:
+ *  boolean: 1 if address range contains memory that require access violation
+ *  detection, or 0 if given address range is in no interest to the memchecker.
+ */
+int
+memcheck_is_checked(target_ulong addr, uint32_t size) {
+    return procdesc_contains_allocs(get_current_process(), addr, size) ? 1 : 0;
+}
diff --git a/memcheck/memcheck.h b/memcheck/memcheck.h
new file mode 100644
index 0000000..a9a6422
--- /dev/null
+++ b/memcheck/memcheck.h
@@ -0,0 +1,194 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of types, constants, and routines used by memory
+ * checking framework.
+ */
+
+#ifndef QEMU_MEMCHECK_MEMCHECK_H
+#define QEMU_MEMCHECK_MEMCHECK_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "memcheck_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Initializes memory access checking framework.
+ * This routine is called from emulator's main routine on condition,
+ * that emulator has been started with -memcheck option.
+ * Param:
+ *  tracing_flags - Parameters set for the -memcheck option. These parameters
+ *  contain abbreviation for memchecking tracing messages that should be enabled
+ *  for the emulator and guest systems.
+ */
+void memcheck_init(const char* tracing_flags);
+
+// =============================================================================
+// Handlers for memory allocation events, generated by the guest system.
+// =============================================================================
+
+/* Libc.so has been initialized by a process in guest's system.
+ * This routine is called in response to TRACE_DEV_REG_LIBC_INIT event that is
+ * fired up by the guest system on /dev/qemu_trace mapped page.
+ * Param:
+ *  pid - ID of the process in context of which libc.so has been initialized.
+ */
+void memcheck_guest_libc_initialized(uint32_t pid);
+
+/* Guest system has allocated memory from heap.
+ * This routine is called in response to TRACE_DEV_REG_MALLOC event that is
+ * fired up by the guest system on /dev/qemu_trace mapped page.
+ * Param:
+ *  guest_address - Virtual address of allocation descriptor (MallocDesc) that
+ *      contains information about allocated memory block. Note that this
+ *      descriptor is located in the guests's user memory. Note also that
+ *      emulator reports failure back to the guest by zeroing out libc_pid field
+ *      of the structure, addressed by this parameter.
+ */
+void memcheck_guest_alloc(target_ulong guest_address);
+
+/* Guest system is freeing memory to heap.
+ * This routine is called in response to TRACE_DEV_REG_FREE_PTR event,
+ * fired up by the guest system on /dev/qemu_trace mapped page.
+ * Param:
+ *  guest_address - Virtual address of free descriptor (MallocFree) that
+ *      contains information about memory block that's being freed. Note that
+ *      this descriptor is located in the guests's user memory.  Note also that
+ *      emulator reports failure back to the guest by zeroing out libc_pid field
+ *      of the structure, addressed by this parameter.
+ */
+void memcheck_guest_free(target_ulong guest_address);
+
+/* Guest system has queried information about an address in its virtual memory.
+ * This routine is called in response to TRACE_DEV_REG_QUERY_MALLOC event,
+ * fired up by the guest system on /dev/qemu_trace mapped page.
+ * Param:
+ *  guest_address - Virtual address in the guest's space of the MallocDescQuery
+ *      structure, that describes the query and receives the response. Note
+ *      that emulator reports failure back to the guest by zeroing out libc_pid
+ *      field of the structure, addressed by this parameter.
+ */
+void memcheck_guest_query_malloc(target_ulong guest_address);
+
+/* Prints a string to emulator's stdout.
+ * This routine is called in response to TRACE_DEV_REG_PRINT_USER_STR event,
+ * fired up by the guest system on /dev/qemu_trace mapped page.
+ * Param:
+ *  str - Virtual address in the guest's space of the string to print.
+ */
+void memcheck_guest_print_str(target_ulong str);
+
+// =============================================================================
+// Handlers for events, generated by the kernel.
+// =============================================================================
+
+/* Handles PID initialization event.
+ * This routine is called in response to TRACE_DEV_REG_INIT_PID event, which
+ * indicates that new process has been initialized (but not yet executed).
+ * Param:
+ *  pid - ID of the process that is being initialized. This value will also be
+ *      used as main thread ID for the intializing process.
+ */
+void memcheck_init_pid(uint32_t pid);
+
+/* Handles thread switch event.
+ * This routine is called in response to TRACE_DEV_REG_SWITCH event, which
+ * indicates that thread switch occurred in the guest system.
+ * Param:
+ *  tid - ID of the thread that becomes active.
+ */
+void memcheck_switch(uint32_t tid);
+
+/* Handles process forking / new process creation event.
+ * This routine is called in response to TRACE_DEV_REG_FORK event, which
+ * indicates that new process has been forked / created. It's assumed, that
+ * process that is forking new process is the current process.
+ * Param:
+ *  tgid - TODO: Clarify that!
+ *  new_pid - Process ID that's been assigned to the forked process.
+ */
+void memcheck_fork(uint32_t tgid, uint32_t new_pid);
+
+/* Handles new thread creation event.
+ * This routine is called in response to TRACE_DEV_REG_CLONE event, which
+ * indicates that new thread has been created in context of the current process.
+ * Param:
+ *  tgid - TODO: Clarify that!
+ *  new_tid - Thread ID that's been assigned to the new thread.
+ */
+void memcheck_clone(uint32_t tgid, uint32_t new_tid);
+
+/* Sets process command line.
+ * This routine is called in response to TRACE_DEV_REG_CMDLINE event, which
+ * is used to grab first command line argument, and use it is image path to
+ * the current process.
+ * Param:
+ *  cmg_arg - Command line arguments.
+ *  cmdlen - Length of the command line arguments string.
+ */
+void memcheck_set_cmd_line(const char* cmd_arg, unsigned cmdlen);
+
+/* Handles thread / process exiting event.
+ * This routine is called in response to TRACE_DEV_REG_EXIT event, which
+ * indicates that current thread is exiting. We consider that process is
+ * exiting when last thread for that process is exiting.
+ * Param:
+ *  exit_code - Thread exit code.
+ */
+void memcheck_exit(uint32_t exit_code);
+
+/* Handles memory mapping of a module in guest address space.
+ * This routine is called in response to TRACE_DEV_REG_EXECVE_VMSTART,
+ * TRACE_DEV_REG_EXECVE_VMEND, TRACE_DEV_REG_EXECVE_OFFSET, and
+ * TRACE_DEV_REG_MMAP_EXEPATH events, which indicate that a module has been
+ * loaded and mapped on the guest system.
+ * Param:
+ *  vstart - Guest address where mapping starts.
+ *  vend - Guest address where mapping ends.
+ *  exec_offset - Exec offset inside module mapping.
+ *  path - Path to the module that has been mapped.
+ */
+void memcheck_mmap_exepath(target_ulong vstart,
+                           target_ulong vend,
+                           target_ulong exec_offset,
+                           const char* path);
+
+/* Handles memory unmapping of a module in guest address space.
+ * This routine is called in response to TRACE_DEV_REG_UNMAP_START, and
+ * TRACE_DEV_REG_UNMAP_END events, which indicate that a module has been
+ * unmapped on the guest system.
+ * Param:
+ *  vstart - Guest address where unmapping starts.
+ *  vend - Guest address where unmapping ends.
+ */
+void memcheck_unmap(target_ulong vstart, target_ulong vend);
+
+/* Global flag, indicating whether or not memchecking has been enabled
+ * for the current emulator session. If set to zero, indicates that memchecking
+ * is not enabled. Value other than zero indicates that memchecking is enabled
+ * for the current emulator session.
+ */
+extern int memcheck_enabled;
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // QEMU_MEMCHECK_MEMCHECK_H
diff --git a/memcheck/memcheck_api.h b/memcheck/memcheck_api.h
new file mode 100644
index 0000000..1961465
--- /dev/null
+++ b/memcheck/memcheck_api.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of memchecker external variables and routines, used by
+ * other qemu components.
+ */
+
+#ifndef QEMU_MEMCHECK_MEMCHECK_API_H
+#define QEMU_MEMCHECK_MEMCHECK_API_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+/* Global flag, indicating whether or not memchecking has been enabled
+ * for the current emulator session. 1 means that memchecking has been
+ * enabled, 0 means that memchecking has not been enabled. The variable
+ * is declared in memchec/memcheck.c */
+extern int memcheck_enabled;
+
+/* Flags wether or not mmu instrumentation is enabled by memchecker.
+ * 1 - enabled, 0 - is not enabled. */
+extern int memcheck_instrument_mmu;
+
+/* Global flag, indicating whether or not memchecker is collecting call stack.
+ * 1 - call stack is being collected, 0 means that stack is not being
+ * collected. The variable is declared in memchec/memcheck.c */
+extern int memcheck_watch_call_stack;
+
+/* Array of (tb_pc, guest_pc) pairs, big enough for all translations. This
+ * array is used to obtain guest PC address from a translated PC address.
+ * tcg_gen_code_common will fill it up when memchecker is enabled. The array is
+ * declared in ./translate_all.c */
+extern target_ulong* gen_opc_tpc2gpc_ptr;
+
+/* Number of (tb_pc, guest_pc) pairs stored in gen_opc_tpc2gpc array.
+ * The variable is declared in ./translate_all.c */
+extern unsigned int gen_opc_tpc2gpc_pairs;
+
+/* Checks if given address range in the context of the current process is
+ * under surveillance by memchecker.
+ * Param:
+ *  addr - Starting address of a range.
+ *  size - Range size.
+ * Return:
+ *  boolean: 1 if address range contains memory that requires access
+ *  violation detection, or 0 if given address range is in no interest to
+ *  the memchecker. */
+int memcheck_is_checked(target_ulong addr, uint32_t size);
+
+/* Validates __ldx_mmu operations.
+ * Param:
+ *  addr - Virtual address in the guest space where memory is read.
+ *  data_size - Size of the read.
+ *  retaddr - Code address (in TB) that accesses memory.
+ * Return:
+ *  1 Address should be invalidated in TLB cache, in order to ensure that
+ *  subsequent attempts to read from that page will launch __ld/__stx_mmu.
+ *  If this routine returns zero, no page invalidation is requried.
+ */
+int memcheck_validate_ld(target_ulong addr,
+                         uint32_t data_size,
+                         target_ulong retaddr);
+
+/* Validates __stx_mmu operations.
+ * Param:
+ *  addr - Virtual address in the guest space where memory is written.
+ *  data_size - Size of the write.
+ *  value - Value to be written. Note that we typecast all values to 64 bits,
+ *      since this will fit all data sizes.
+ *  retaddr - Code address (in TB) that accesses memory.
+ * Return:
+ *  1 Address should be invalidated in TLB cache, in order to ensure that
+ *  subsequent attempts to read from that page will launch __ld/__stx_mmu.
+ *  If this routine returns zero, no page invalidation is requried.
+ */
+int memcheck_validate_st(target_ulong addr,
+                         uint32_t data_size,
+                         uint64_t value,
+                         target_ulong retaddr);
+
+/* Memchecker's handler for on_call callback.
+ * Param:
+ *  pc - Guest address where call has been made.
+ *  ret - Guest address where called routine will return.
+ */
+void memcheck_on_call(target_ulong pc, target_ulong ret);
+
+/* Memchecker's handler for on_ret callback.
+ * Param:
+ *  pc - Guest address where routine has returned.
+ */
+void memcheck_on_ret(target_ulong pc);
+
+#endif  // QEMU_MEMCHECK_MEMCHECK_API_H
diff --git a/memcheck/memcheck_common.h b/memcheck/memcheck_common.h
new file mode 100644
index 0000000..668b78c
--- /dev/null
+++ b/memcheck/memcheck_common.h
@@ -0,0 +1,484 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of structures, routines, etc. that are commonly used
+ * in memechecker framework.
+ */
+
+#ifndef QEMU_MEMCHECK_MEMCHECK_COMMON_H
+#define QEMU_MEMCHECK_MEMCHECK_COMMON_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "qemu-common.h"
+#include "cpu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// =============================================================================
+// Events generated by the guest system.
+// =============================================================================
+
+/* Notifies the emulator that libc has been initialized for a process.
+ * Event's value parameter is PID for the process in context of which libc has
+ * been initialized.
+ */
+#define TRACE_DEV_REG_LIBC_INIT             1536
+
+/* Notifies the emulator about new memory block being allocated.
+ * Event's value parameter points to MallocDesc instance in the guest's address
+ * space that contains allocated block information. Note that 'libc_pid' field
+ * of the descriptor is used by emulator to report failure in handling this
+ * event. In case of failure emulator will zero that filed before completing
+ * this event.
+ */
+#define TRACE_DEV_REG_MALLOC                1537
+
+/* Notifies the emulator about memory block being freed.
+ * Event's value parameter points to MallocFree descriptor instance in the
+ * guest's address space that contains information about block that's being
+ * freed. Note that 'libc_pid' field of the descriptor is used by emulator to
+ * report failure in handling this event. In case of failure emulator will zero
+ * that filed before completing this event.
+ */
+#define TRACE_DEV_REG_FREE_PTR              1538
+
+/* Queries the emulator about memory block information.
+ * Event's value parameter points to MallocDescQuery descriptor instance in the
+ * guest's address space that contains query parameters. Note that 'libc_pid'
+ * field of the descriptor is used by emulator to report failure in handling
+ * this event. In case of failure emulator will zero that filed before
+ * completing this event.
+ */
+#define TRACE_DEV_REG_QUERY_MALLOC          1539
+
+/* Queries the emulator to print a string to its stdout.
+ * Event's value parameter points to zero-terminated string to be printed. Note
+ * that this string is located in the guest's address space.
+ */
+#define TRACE_DEV_REG_PRINT_USER_STR        1540
+
+// =============================================================================
+// Communication structures
+// =============================================================================
+
+/* Describes memory block allocated from the heap. This structure is passed
+ * along with TRACE_DEV_REG_MALLOC event. This descriptor is used to inform
+ * the emulator about new memory block being allocated from the heap. The entire
+ * structure is initialized by the guest system before event is fired up. It is
+ * important to remember that same structure (an exact copy) is also declared
+ * in the libc's sources. So, every time a change is made to any of these
+ * two declaration, another one must be also updated accordingly. */
+typedef struct MallocDesc {
+    /* Poniter to the memory block actually allocated from the heap. Note that
+     * this is not the pointer that is returned to the malloc's caller. Pointer
+     * returned to the caller is calculated by adding value stored in this field
+     * to the value stored in prefix_size field of this structure.
+     */
+    target_ulong    ptr;
+
+    /* Nuber of bytes requested by the malloc's caller. */
+    uint32_t        requested_bytes;
+
+    /* Byte size of the prefix data. Actual pointer returned to the malloc's
+     * caller is calculated by adding value stored in this field to the value
+     * stored in in the ptr field of this structure.
+     */
+    uint32_t        prefix_size;
+
+    /* Byte size of the suffix data. */
+    uint32_t        suffix_size;
+
+    /* Id of the process that initialized libc instance, in which allocation
+     * has occurred. This field is used by the emulator to report errors in
+     * the course of TRACE_DEV_REG_MALLOC event handling. In case of an error,
+     * emulator sets this field to zero (invalid value for a process ID).
+     */
+    uint32_t        libc_pid;
+
+    /* Id of the process in context of which allocation has occurred.
+     * Value in this field may differ from libc_pid value, if process that
+     * is doing allocation has been forked from the process that initialized
+     * libc instance.
+     */
+    uint32_t        allocator_pid;
+
+    /* Number of access violations detected on this allocation. */
+    uint32_t        av_count;
+} MallocDesc;
+/* Helpers for addressing field in MallocDesc structure, using which emulator
+ * reports an error back to the guest.
+ */
+#define ALLOC_RES_OFFSET        ((uint32_t)&(((MallocDesc*)0)->libc_pid))
+#define ALLOC_RES_ADDRESS(p)    (p + ALLOC_RES_OFFSET)
+
+/* Describes memory block info queried from emulator. This structure is passed
+ * along with TRACE_DEV_REG_QUERY_MALLOC event. When handling free and realloc
+ * calls, it is required that we have information about memory blocks that were
+ * actually allocated in previous calls to malloc, memalign, or realloc. Since
+ * we don't keep this information directlry in the allocated block, but rather
+ * we keep it in the emulator, we need to query emulator for that information
+ * with TRACE_DEV_REG_QUERY_MALLOC query. The entire structure is initialized
+ * by the guest system before event is fired up It is important to remember that
+ * same structure (an exact copy) is also declared in the libc's sources. So,
+ * every time a change is made to any of these two declaration, another one
+ * must be also updated accordingly.
+ */
+typedef struct MallocDescQuery {
+    /* Pointer for which information is queried. Note that this pointer doesn't
+     * have to be exact pointer returned to malloc's caller, but can point
+     * anywhere inside an allocated block, including guarding areas. Emulator
+     * will respond with information about allocated block that contains this
+     * pointer.
+     */
+    target_ulong    ptr;
+
+    /* Id of the process that initialized libc instance, in which this query
+     * is called. This field is used by the emulator to report errors in
+     * the course of TRACE_DEV_REG_QUERY_MALLOC event handling. In case of an
+     * error, emulator sets this field to zero (invalid value for a process ID).
+     */
+    uint32_t        libc_pid;
+
+    /* Process ID in context of which query is made. */
+    uint32_t        query_pid;
+
+    /* Code of the allocation routine, in context of which query has been made:
+     *  1 - free
+     *  2 - realloc
+     */
+    uint32_t        routine;
+
+    /* Address in guest's virtual space of memory allocation descriptor for the
+     * queried pointer. Descriptor, addressed by this field is initialized by
+     * the emulator in response to the query.
+     */
+    target_ulong    desc;
+} MallocDescQuery;
+/* Helpers for addressing field in MallocDescQuery structure using which
+ * emulator reports an error back to the guest.
+ */
+#define QUERY_RES_OFFSET        ((uint32_t)&(((MallocDescQuery*)0)->libc_pid))
+#define QUERY_RES_ADDRESS(p)    (p + QUERY_RES_OFFSET)
+
+/* Describes memory block that is being freed back to the heap. This structure
+ * is passed along with TRACE_DEV_REG_FREE_PTR event. The entire structure is
+ * initialized by the guest system before event is fired up. It is important to
+ * remember that same structure (an exact copy) is also declared in the libc's
+ * sources. So, every time a change is made to any of these two declaration,
+ * another one must be also updated accordingly.
+ */
+typedef struct MallocFree {
+    /* Pointer to be freed. */
+    uint32_t    ptr;
+
+    /* Id of the process that initialized libc instance, in which this free
+     * is called. This field is used by the emulator to report errors in
+     * the course of TRACE_DEV_REG_FREE_PTR event handling. In case of an
+     * error, emulator sets this field to zero (invalid value for a process ID).
+     */
+    uint32_t    libc_pid;
+
+    /* Process ID in context of which memory is being freed. */
+    uint32_t    free_pid;
+} MallocFree;
+/* Helpers for addressing field in MallocFree structure, using which emulator
+ * reports an error back to the guest.
+ */
+#define FREE_RES_OFFSET         ((uint32_t)&(((MallocFree*)0)->libc_pid))
+#define FREE_RES_ADDRESS(p)     (p + FREE_RES_OFFSET)
+
+/* Extends MallocDesc structure with additional information, used by memchecker.
+ */
+typedef struct MallocDescEx {
+    /* Allocation descriptor this structure extends. */
+    MallocDesc      malloc_desc;
+
+    /* Call stack that lead to memory allocation. The array is arranged in
+     * accending order, where entry at index 0 corresponds to the routine
+     * that allocated memory. */
+    target_ulong*   call_stack;
+
+    /* Number of entries in call_stack array. */
+    uint32_t        call_stack_count;
+
+    /* Set of misc. flags. See MDESC_FLAG_XXX bellow. */
+    uint32_t        flags;
+} MallocDescEx;
+
+/* Indicates that memory has been allocated before process started execution.
+ * After a process has been forked, but before it actually starts executing,
+ * allocations can be made in context of that process PID. This flag marks such
+ * allocations in the process' allocation descriptors map.
+ */
+#define MDESC_FLAG_TRANSITION_ENTRY         0x00000001
+
+/* Indicates that memory block has been inherited from the parent process.
+ * When a process is forked from its parent process, the forked process inherits
+ * a copy of the parent process' heap. Thus, all allocations that were recorded
+ * for the parent process must be also recorded for the forked process. This
+ * flag marks entries in the forked process' allocation descriptors map that
+ * were copied over from the parent process' allocation descriptors map.
+ */
+#define MDESC_FLAG_INHERITED_ON_FORK        0x00000002
+
+/* Describes a memory mapping of an execution module in the guest system. */
+typedef struct MMRangeDesc {
+    /* Starting address of mmapping of a module in the guest's address space. */
+    target_ulong            map_start;
+
+    /* Ending address of mmapping of a module in the guest's address space. */
+    target_ulong            map_end;
+
+    /* Mmapping's execution offset. */
+    target_ulong            exec_offset;
+
+    /* Image path of the module that has been mapped with this mmapping. */
+    char*                   path;
+} MMRangeDesc;
+
+/* Enumerates returned values for insert routines implemeted for red-black
+ * tree maps.
+ */
+typedef enum {
+    /* New entry has been inserted into the map. */
+    RBT_MAP_RESULT_ENTRY_INSERTED = 0,
+
+    /* An entry, matching the new one already exists in the map. */
+    RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS,
+
+    /* An existing entry, matching the new one has been replaced
+    * with the new entry.
+    */
+    RBT_MAP_RESULT_ENTRY_REPLACED,
+
+    /* An error has occurred when inserting entry into the map. */
+    RBT_MAP_RESULT_ERROR = -1,
+} RBTMapResult;
+
+/* Encapsulates an array of guest addresses, sorted in accending order. */
+typedef struct AddrArray {
+    /* Array of addresses. */
+    target_ulong*   addr;
+
+    /* Number of elements in the array. */
+    int             num;
+} AddrArray;
+
+// =============================================================================
+// Inlines
+// =============================================================================
+
+/* Gets pointer returned to malloc caller for the given allocation decriptor.
+ * Param:
+ *  desc - Allocation descriptor.
+ * Return:
+ *  Pointer to the allocated memory returned to the malloc caller.
+ */
+static inline target_ulong
+mallocdesc_get_user_ptr(const MallocDesc* desc)
+{
+    return desc->ptr + desc->prefix_size;
+}
+
+/* Gets total size of the allocated block for the given descriptor.
+ * Param:
+ *  desc - Descriptor for the memory block, allocated in malloc handler.
+ * Return:
+ *  Total size of memory block allocated in malloc handler.
+ */
+static inline uint32_t
+mallocdesc_get_alloc_size(const MallocDesc* desc)
+{
+    return desc->prefix_size + desc->requested_bytes + desc->suffix_size;
+}
+
+/* Gets the end of the allocated block for the given descriptor.
+ * Param:
+ *  desc - Descriptor for the memory block, allocated in malloc handler.
+ * Return:
+ *  Pointer to the end of the allocated block (next byte past the block).
+ */
+static inline target_ulong
+mallocdesc_get_alloc_end(const MallocDesc* desc)
+{
+    return desc->ptr + mallocdesc_get_alloc_size(desc);
+}
+
+/* Gets the end of the allocated block available to the user for the given
+ * descriptor.
+ * Param:
+ *  desc - Descriptor for the memory block, allocated in malloc handler.
+ * Return:
+ *  Pointer to the end of the allocated block available to the user (next byte
+ *  past the block - suffix guarding area).
+ */
+static inline target_ulong
+mallocdesc_get_user_alloc_end(const MallocDesc* desc)
+{
+    return mallocdesc_get_user_ptr(desc) + desc->requested_bytes;
+}
+
+/* Checks if allocation has been made before process started execution.
+ * Param:
+ *  desc - Allocation descriptor to check.
+ * Return:
+ *  boolean: 1 if allocation has been made before process started execution,
+ *  or 0 if allocation has been made after process started execution.
+ */
+static inline int
+mallocdescex_is_transition_entry(const MallocDescEx* desc)
+{
+    return (desc->flags & MDESC_FLAG_TRANSITION_ENTRY) != 0;
+}
+
+/* Checks if allocation block has been inherited on fork.
+ * Param:
+ *  desc - Allocation descriptor to check.
+ * Return:
+ *  boolean: 1 if allocation has been inherited on fork, or 0 if allocation
+ *  has been made by this process..
+ */
+static inline int
+mallocdescex_is_inherited_on_fork(const MallocDescEx* desc)
+{
+    return (desc->flags & MDESC_FLAG_INHERITED_ON_FORK) != 0;
+}
+
+/* Gets offset for the given address inside a mapped module.
+ * Param:
+ *  address - Address to get offset for.
+ * Return:
+ *  Offset of the given address inside a mapped module, represented with the
+ *  given mmaping range descriptor.
+ */
+static inline target_ulong
+mmrangedesc_get_module_offset(const MMRangeDesc* rdesc, target_ulong address)
+{
+    return address - rdesc->map_start + rdesc->exec_offset;
+}
+
+/* Checks if given address is contained in the given address array.
+ * Return:
+ *  boolean: 1 if address is contained in the array, or zero if it's not.
+ */
+static inline int
+addrarray_check(const AddrArray* addr_array, target_ulong addr)
+{
+    if (addr_array->num != 0) {
+        int m_min = 0;
+        int m_max = addr_array->num - 1;
+
+        /* May be odd for THUMB mode. */
+        addr &= ~1;
+        /* Since array is sorted we can do binary search here. */
+        while (m_min <= m_max) {
+            const int m = (m_min + m_max) >> 1;
+            const target_ulong saved = addr_array->addr[m];
+            if (addr == saved) {
+                return 1;
+            }
+            if (addr < saved) {
+                m_max = m - 1;
+            } else {
+                m_min = m + 1;
+            }
+        }
+    }
+    return 0;
+}
+
+/* Adds an address to the address array.
+ * Return:
+ *  1  - Address has been added to the array.
+ *  -1 - Address already exists in the array.
+ *  0  - Unable to expand the array.
+ */
+static inline int
+addrarray_add(AddrArray* addr_array, target_ulong addr)
+{
+    target_ulong* new_arr;
+    int m_min;
+    int m_max;
+
+    /* May be odd for THUMB mode. */
+    addr &= ~1;
+    if (addr_array->num == 0) {
+        /* First element. */
+        addr_array->addr = qemu_malloc(sizeof(target_ulong));
+        assert(addr_array->addr != NULL);
+        if (addr_array->addr == NULL) {
+            return 0;
+        }
+        *addr_array->addr = addr;
+        addr_array->num++;
+        return 1;
+    }
+
+    /* Using binary search find the place where to insert new address. */
+    m_min = 0;
+    m_max = addr_array->num - 1;
+    while (m_min <= m_max) {
+        const int m = (m_min + m_max) >> 1;
+        const target_ulong saved = addr_array->addr[m];
+        if (addr == saved) {
+            return -1;
+        }
+        if (addr < saved) {
+            m_max = m - 1;
+        } else {
+            m_min = m + 1;
+        }
+    }
+    if (m_max < 0) {
+        m_max = 0;
+    }
+    /* Expand the array. */
+    new_arr = qemu_malloc(sizeof(target_ulong) * (addr_array->num + 1));
+    assert(new_arr != NULL);
+    if (new_arr == NULL) {
+        return 0;
+    }
+    /* Copy preceding elements to the new array. */
+    if (m_max != 0) {
+        memcpy(new_arr, addr_array->addr, m_max * sizeof(target_ulong));
+    }
+    if (addr > addr_array->addr[m_max]) {
+        new_arr[m_max] = addr_array->addr[m_max];
+        m_max++;
+    }
+    /* Insert new address. */
+    new_arr[m_max] = addr;
+    /* Copy remaining elements to the new array. */
+    if (m_max < addr_array->num) {
+        memcpy(new_arr + m_max + 1, addr_array->addr + m_max,
+               (addr_array->num - m_max) * sizeof(target_ulong));
+    }
+    /* Swap arrays. */
+    qemu_free(addr_array->addr);
+    addr_array->addr = new_arr;
+    addr_array->num++;
+    return 1;
+}
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // QEMU_MEMCHECK_MEMCHECK_COMMON_H
diff --git a/memcheck/memcheck_logging.h b/memcheck/memcheck_logging.h
new file mode 100644
index 0000000..c2ae6e9
--- /dev/null
+++ b/memcheck/memcheck_logging.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of logging macros used in memchecker framework.
+ */
+
+#ifndef QEMU_MEMCHECK_MEMCHECK_LOGGING_H
+#define QEMU_MEMCHECK_MEMCHECK_LOGGING_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "qemu-common.h"
+#include "android/utils/debug.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Prints debug message under the 'memcheck' tag. */
+#define MD(...)  VERBOSE_PRINT(memcheck, __VA_ARGS__)
+
+/* Prints an error message under the 'memcheck' tag. */
+#define ME(...)  \
+    do { if (VERBOSE_CHECK(memcheck)) derror(__VA_ARGS__); } while (0)
+
+// =============================================================================
+// Tracing flags (see trace_flags declared in memcheck.c), and macros
+// =============================================================================
+
+/* Enables fork() tracing. */
+#define TRACE_PROC_FORK_ENABLED                 0x00000001
+/* Enables clone() tracing. */
+#define TRACE_PROC_CLONE_ENABLED                0x00000002
+/* Enables new PID allocation tracing. */
+#define TRACE_PROC_NEW_PID_ENABLED              0x00000004
+/* Enables guest process starting tracing. */
+#define TRACE_PROC_START_ENABLED                0x00000008
+/* Enables guest process exiting tracing. */
+#define TRACE_PROC_EXIT_ENABLED                 0x00000010
+/* Enables libc.so initialization tracing. */
+#define TRACE_PROC_LIBC_INIT_ENABLED            0x00000020
+/* Enables leaking tracing. */
+#define TRACE_CHECK_LEAK_ENABLED                0x00000040
+/* Enables invalid pointer access tracing. */
+#define TRACE_CHECK_INVALID_PTR_ENABLED         0x00000080
+/* Enables reading violations tracing. */
+#define TRACE_CHECK_READ_VIOLATION_ENABLED      0x00000100
+/* Enables writing violations tracing. */
+#define TRACE_CHECK_WRITE_VIOLATION_ENABLED     0x00000200
+/* Enables module mapping tracing. */
+#define TRACE_PROC_MMAP_ENABLED                 0x00000400
+/* All tracing flags combined. */
+#define TRACE_ALL_ENABLED   (TRACE_PROC_FORK_ENABLED                | \
+                             TRACE_PROC_CLONE_ENABLED               | \
+                             TRACE_PROC_NEW_PID_ENABLED             | \
+                             TRACE_PROC_START_ENABLED               | \
+                             TRACE_PROC_LIBC_INIT_ENABLED           | \
+                             TRACE_PROC_EXIT_ENABLED                | \
+                             TRACE_CHECK_INVALID_PTR_ENABLED        | \
+                             TRACE_CHECK_READ_VIOLATION_ENABLED     | \
+                             TRACE_CHECK_WRITE_VIOLATION_ENABLED    | \
+                             TRACE_PROC_MMAP_ENABLED                | \
+                             TRACE_CHECK_LEAK_ENABLED)
+
+/* Prints a trace to the stdout. */
+#define T(level, ...)                                   \
+    do {                                                \
+        if (trace_flags & TRACE_##level##_ENABLED) {    \
+            printf(__VA_ARGS__);                        \
+        }                                               \
+    } while (0)
+
+/* Set of tracing flags (declared in memchek.c). */
+extern uint32_t trace_flags;
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // QEMU_MEMCHECK_MEMCHECK_LOGGING_H
diff --git a/memcheck/memcheck_malloc_map.c b/memcheck/memcheck_malloc_map.c
new file mode 100644
index 0000000..07ae889
--- /dev/null
+++ b/memcheck/memcheck_malloc_map.c
@@ -0,0 +1,289 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains implementation of routines that implement a red-black tree of
+ * memory blocks allocated by the guest system.
+ */
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "memcheck_malloc_map.h"
+#include "memcheck_util.h"
+#include "memcheck_logging.h"
+
+/* Global flag, indicating whether or not __ld/__stx_mmu should be instrumented
+ * for checking for access violations. If read / write access violation check.
+ * Defined in memcheck.c
+ */
+extern int memcheck_instrument_mmu;
+
+/* Allocation descriptor stored in the map. */
+typedef struct AllocMapEntry {
+    /* R-B tree entry. */
+    RB_ENTRY(AllocMapEntry) rb_entry;
+
+    /* Allocation descriptor for this entry. */
+    MallocDescEx            desc;
+} AllocMapEntry;
+
+// =============================================================================
+// Inlines
+// =============================================================================
+
+/* Gets address of the beginning of an allocation block for the given entry in
+ * the map.
+ * Param:
+ *  adesc - Entry in the allocation descriptors map.
+ * Return:
+ *  Address of the beginning of an allocation block for the given entry in the
+ *  map.
+ */
+static inline target_ulong
+allocmapentry_alloc_begins(const AllocMapEntry* adesc)
+{
+    return adesc->desc.malloc_desc.ptr;
+}
+
+/* Gets address of the end of an allocation block for the given entry in
+ * the map.
+ * Param:
+ *  adesc - Entry in the allocation descriptors map.
+ * Return:
+ *  Address of the end of an allocation block for the given entry in the map.
+ */
+static inline target_ulong
+allocmapentry_alloc_ends(const AllocMapEntry* adesc)
+{
+    return mallocdesc_get_alloc_end(&adesc->desc.malloc_desc);
+}
+
+// =============================================================================
+// R-B Tree implementation
+// =============================================================================
+
+/* Compare routine for the allocation descriptors map.
+ * Param:
+ *  d1 - First map entry to compare.
+ *  d2 - Second map entry to compare.
+ * Return:
+ *  0 - Descriptors are equal. Note that descriptors are considered to be
+ *      equal iff memory blocks they describe intersect in any part.
+ *  1 - d1 is greater than d2
+ *  -1 - d1 is less than d2.
+ */
+static inline int
+cmp_rb(AllocMapEntry* d1, AllocMapEntry* d2)
+{
+    const target_ulong start1 = allocmapentry_alloc_begins(d1);
+    const target_ulong start2 = allocmapentry_alloc_begins(d2);
+
+    if (start1 < start2) {
+        return (allocmapentry_alloc_ends(d1) - 1) < start2 ? -1 : 0;
+    }
+    return (allocmapentry_alloc_ends(d2) - 1) < start1 ? 1 : 0;
+}
+
+/* Expands RB macros here. */
+RB_GENERATE(AllocMap, AllocMapEntry, rb_entry, cmp_rb);
+
+// =============================================================================
+// Static routines
+// =============================================================================
+
+/* Inserts new (or replaces existing) entry into allocation descriptors map.
+ * See comments on allocmap_insert routine in the header file for details
+ * about this routine.
+ */
+static RBTMapResult
+allocmap_insert_desc(AllocMap* map,
+                     AllocMapEntry* adesc,
+                     MallocDescEx* replaced)
+{
+    AllocMapEntry* existing = AllocMap_RB_INSERT(map, adesc);
+    if (existing == NULL) {
+        return RBT_MAP_RESULT_ENTRY_INSERTED;
+    }
+
+    // Matching entry exists. Lets see if we need to replace it.
+    if (replaced == NULL) {
+        return RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS;
+    }
+
+    /* Copy existing entry to the provided buffer and replace it
+     * with the new one. */
+    memcpy(replaced, &existing->desc, sizeof(MallocDescEx));
+    AllocMap_RB_REMOVE(map, existing);
+    qemu_free(existing);
+    AllocMap_RB_INSERT(map, adesc);
+    return RBT_MAP_RESULT_ENTRY_REPLACED;
+}
+
+/* Finds an entry in the allocation descriptors map that matches the given
+ * address range.
+ * Param:
+ *  map - Allocation descriptors map where to search for an entry.
+ *  address - Virtual address in the guest's user space to find matching
+ *      entry for.
+ * Return:
+ *  Address of an allocation descriptors map entry that matches the given
+ *  address, or NULL if no such entry has been found.
+ */
+static inline AllocMapEntry*
+allocmap_find_entry(const AllocMap* map,
+                    target_ulong address,
+                    uint32_t block_size)
+{
+    AllocMapEntry adesc;
+    adesc.desc.malloc_desc.ptr = address;
+    adesc.desc.malloc_desc.requested_bytes = block_size;
+    adesc.desc.malloc_desc.prefix_size = 0;
+    adesc.desc.malloc_desc.suffix_size = 0;
+    return AllocMap_RB_FIND((AllocMap*)map, &adesc);
+}
+
+// =============================================================================
+// Map API
+// =============================================================================
+
+void
+allocmap_init(AllocMap* map)
+{
+    RB_INIT(map);
+}
+
+RBTMapResult
+allocmap_insert(AllocMap* map, const MallocDescEx* desc, MallocDescEx* replaced)
+{
+    RBTMapResult ret;
+
+    // Allocate and initialize new map entry.
+    AllocMapEntry* adesc = qemu_malloc(sizeof(AllocMapEntry));
+    if (adesc == NULL) {
+        ME("memcheck: Unable to allocate new AllocMapEntry on insert.");
+        return RBT_MAP_RESULT_ERROR;
+    }
+    memcpy(&adesc->desc, desc, sizeof(MallocDescEx));
+
+    // Insert new entry into the map.
+    ret = allocmap_insert_desc(map, adesc, replaced);
+    if (ret == RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS ||
+        ret == RBT_MAP_RESULT_ERROR) {
+        /* Another descriptor already exists for this block, or an error
+         * occurred. We have to tree new descriptor, as it wasn't inserted. */
+        qemu_free(adesc);
+    }
+    return ret;
+}
+
+MallocDescEx*
+allocmap_find(const AllocMap* map, target_ulong address, uint32_t block_size)
+{
+    AllocMapEntry* adesc = allocmap_find_entry(map, address, block_size);
+    return adesc != NULL ? &adesc->desc : NULL;
+}
+
+int
+allocmap_pull(AllocMap* map, target_ulong address, MallocDescEx* pulled)
+{
+    AllocMapEntry* adesc = allocmap_find_entry(map, address, 1);
+    if (adesc != NULL) {
+        memcpy(pulled, &adesc->desc, sizeof(MallocDescEx));
+        AllocMap_RB_REMOVE(map, adesc);
+        qemu_free(adesc);
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+int
+allocmap_pull_first(AllocMap* map, MallocDescEx* pulled)
+{
+    AllocMapEntry* first = RB_MIN(AllocMap, map);
+    if (first != NULL) {
+        memcpy(pulled, &first->desc, sizeof(MallocDescEx));
+        AllocMap_RB_REMOVE(map, first);
+        qemu_free(first);
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+int
+allocmap_copy(AllocMap* to,
+              const AllocMap* from,
+              uint32_t set_flags,
+              uint32_t clear_flags)
+{
+    AllocMapEntry* entry;
+    RB_FOREACH(entry, AllocMap, (AllocMap*)from) {
+        RBTMapResult ins_res;
+        AllocMapEntry* new_entry =
+                (AllocMapEntry*)qemu_malloc(sizeof(AllocMapEntry));
+        if (new_entry == NULL) {
+            ME("memcheck: Unable to allocate new AllocMapEntry on copy.");
+            return -1;
+        }
+        memcpy(new_entry, entry, sizeof(AllocMapEntry));
+        new_entry->desc.flags &= ~clear_flags;
+        new_entry->desc.flags |= set_flags;
+        if (entry->desc.call_stack_count) {
+            new_entry->desc.call_stack =
+               qemu_malloc(entry->desc.call_stack_count * sizeof(target_ulong));
+            memcpy(new_entry->desc.call_stack, entry->desc.call_stack,
+                   entry->desc.call_stack_count * sizeof(target_ulong));
+        } else {
+            new_entry->desc.call_stack = NULL;
+        }
+        new_entry->desc.call_stack_count = entry->desc.call_stack_count;
+        ins_res = allocmap_insert_desc(to, new_entry, NULL);
+        if (ins_res == RBT_MAP_RESULT_ENTRY_INSERTED) {
+            if (memcheck_instrument_mmu) {
+                // Invalidate TLB cache for inserted entry.
+                invalidate_tlb_cache(new_entry->desc.malloc_desc.ptr,
+                        mallocdesc_get_alloc_end(&new_entry->desc.malloc_desc));
+            }
+        } else {
+            ME("memcheck: Unable to insert new map entry on copy. Insert returned %u",
+               ins_res);
+            if (new_entry->desc.call_stack != NULL) {
+                qemu_free(new_entry->desc.call_stack);
+            }
+            qemu_free(new_entry);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int
+allocmap_empty(AllocMap* map)
+{
+    MallocDescEx pulled;
+    int removed = 0;
+
+    while (!allocmap_pull_first(map, &pulled)) {
+        removed++;
+        if (pulled.call_stack != NULL) {
+            qemu_free(pulled.call_stack);
+        }
+    }
+
+    return removed;
+}
diff --git a/memcheck/memcheck_malloc_map.h b/memcheck/memcheck_malloc_map.h
new file mode 100644
index 0000000..b356180
--- /dev/null
+++ b/memcheck/memcheck_malloc_map.h
@@ -0,0 +1,150 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of structures and routines that implement a red-black
+ * tree (a map) of memory blocks allocated by the guest system. The map is
+ * organized in such a way, that each entry in the map describes a virtual
+ * address range that belongs to a memory block allocated in the guest's space.
+ * The range includes block's suffix and prefix, as well as block returned to
+ * malloc's caller. Map considers two blocks to be equal if their address ranges
+ * intersect in any part. Allocation descriptor maps are instantiated one per
+ * each process running on the guest system.
+ */
+
+#ifndef QEMU_MEMCHECK_MEMCHECK_MALLOC_MAP_H
+#define QEMU_MEMCHECK_MEMCHECK_MALLOC_MAP_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "sys-tree.h"
+#include "memcheck_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Allocation descriptors map. */
+typedef struct AllocMap {
+    /* Head of the map. */
+    struct AllocMapEntry*   rbh_root;
+} AllocMap;
+
+// =============================================================================
+// Map API
+// =============================================================================
+
+/* Initializes allocation descriptors map.
+ * Param:
+ *  map - Allocation descriptors map to initialize.
+ */
+void allocmap_init(AllocMap* map);
+
+/* Inserts new (or replaces existing) entry in the allocation descriptors map.
+ * Insertion, or replacement is controlled by the value, passed to this routine
+ * with 'replaced' parameter. If this parameter is NULL, insertion will fail if
+ * a matching entry already exists in the map. If 'replaced' parameter is not
+ * NULL, and a matching entry exists in the map, content of the existing entry
+ * will be copied to the descriptor, addressed by 'replace' parameter, existing
+ * entry will be removed from the map, and new entry will be inserted.
+ * Param:
+ *  map - Allocation descriptors map where to insert new, or replace existing
+ *      entry.
+ *  desc - Allocation descriptor to insert to the map.
+ *  replaced - If not NULL, upon return from this routine contains descriptor
+ *      that has been replaced in the map with the new entry. Note that if this
+ *      routine returns with value other than RBT_MAP_RESULT_ENTRY_REPLACED,
+ *      content of the 'replaced' buffer is not defined, as no replacement has
+ *      actually occurred.
+ * Return
+ *  See RBTMapResult for the return codes.
+ */
+RBTMapResult allocmap_insert(AllocMap* map,
+                             const MallocDescEx* desc,
+                             MallocDescEx* replaced);
+
+/* Finds an entry in the allocation descriptors map that matches the given
+ * address.
+ * Param:
+ *  map - Allocation descriptors map where to search for an entry.
+ *  address - Virtual address in the guest's user space to find matching
+ *      entry for. Entry matches the address, if address is contained within
+ *      allocated memory range (including guarding areas), as defined by the
+ *      memory allocation descriptor for that entry.
+ *  block_size - Size of the block, beginning with 'address'.
+ * Return:
+ *  Pointer to the allocation descriptor found in a map entry, or NULL if no
+ *  matching entry has been found in the map.
+ */
+MallocDescEx* allocmap_find(const AllocMap* map,
+                            target_ulong address,
+                            uint32_t block_size);
+
+/* Pulls (finds and removes) an entry from the allocation descriptors map that
+ * matches the given address.
+ * Param:
+ *  map - Allocation descriptors map where to search for an entry.
+ *  address - Virtual address in the guest's user space to find matching
+ *      entry for. Entry matches the address, if address is contained within
+ *      allocated memory range (including guarding areas), as defined by the
+ *      memory allocation descriptor for that entry.
+ *  pulled - Upon successful return contains allocation descriptor data pulled
+ *      from the map.
+ * Return:
+ *  Zero if an allocation descriptor that matches the given address has
+ *  been pulled, or 1 if no matching entry has been found in the map.
+ */
+int allocmap_pull(AllocMap* map, target_ulong address, MallocDescEx* pulled);
+
+/* Pulls (removes) an entry from the head of the allocation descriptors map.
+ * Param:
+ *  map - Allocation descriptors map where to pull an entry from.
+ *  pulled - Upon successful return contains allocation descriptor data pulled
+ *      from the head of the map.
+ * Return:
+ *  Zero if an allocation descriptor has been pulled from the head of the map,
+ *  or 1 if map is empty.
+ */
+int allocmap_pull_first(AllocMap* map, MallocDescEx* pulled);
+
+/* Copies content of one memory allocation descriptors map to another.
+ * Param:
+ *  to - Map where to copy entries to.
+ *  from - Map where to copy entries from.
+ *  set_flags - Flags that should be set in the copied entry's 'flags' field.
+ *  celar_flags - Flags that should be cleared in the copied entry's 'flags'
+ *  field.
+ * Return:
+ *  Zero on success, or -1 on error.
+ */
+int allocmap_copy(AllocMap* to,
+                  const AllocMap* from,
+                  uint32_t set_flags,
+                  uint32_t clear_flags);
+
+/* Empties the map.
+ * Param:
+ *  map - Map to empty.
+ * Return:
+ *  Number of entries removed from the map.
+ */
+int allocmap_empty(AllocMap* map);
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // QEMU_MEMCHECK_MEMCHECK_MALLOC_MAP_H
diff --git a/memcheck/memcheck_mmrange_map.c b/memcheck/memcheck_mmrange_map.c
new file mode 100644
index 0000000..f2609df
--- /dev/null
+++ b/memcheck/memcheck_mmrange_map.c
@@ -0,0 +1,236 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains implementation of routines that implement a red-black tree of
+ * memory mappings in the guest system.
+ */
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "memcheck_mmrange_map.h"
+#include "memcheck_logging.h"
+
+/* Memory range descriptor stored in the map. */
+typedef struct MMRangeMapEntry {
+    /* R-B tree entry. */
+    RB_ENTRY(MMRangeMapEntry)   rb_entry;
+
+    /* Memory range descriptor for this entry. */
+    MMRangeDesc                 desc;
+} MMRangeMapEntry;
+
+// =============================================================================
+// R-B Tree implementation
+// =============================================================================
+
+/* Compare routine for the map.
+ * Param:
+ *  d1 - First map entry to compare.
+ *  d2 - Second map entry to compare.
+ * Return:
+ *  0 - Descriptors are equal. Note that descriptors are considered to be
+ *      equal iff memory blocks they describe intersect in any part.
+ *  1 - d1 is greater than d2
+ *  -1 - d1 is less than d2.
+ */
+static inline int
+cmp_rb(MMRangeMapEntry* d1, MMRangeMapEntry* d2)
+{
+    const target_ulong start1 = d1->desc.map_start;
+    const target_ulong start2 = d2->desc.map_start;
+
+    if (start1 < start2) {
+        return (d1->desc.map_end - 1) < start2 ? -1 : 0;
+    }
+    return (d2->desc.map_end - 1) < start1 ? 1 : 0;
+}
+
+/* Expands RB macros here. */
+RB_GENERATE(MMRangeMap, MMRangeMapEntry, rb_entry, cmp_rb);
+
+// =============================================================================
+// Static routines
+// =============================================================================
+
+/* Inserts new (or replaces existing) entry into the map.
+ * See comments on mmrangemap_insert routine in the header file for details
+ * about this routine.
+ */
+static RBTMapResult
+mmrangemap_insert_desc(MMRangeMap* map,
+                       MMRangeMapEntry* rdesc,
+                       MMRangeDesc* replaced)
+{
+    MMRangeMapEntry* existing = MMRangeMap_RB_INSERT(map, rdesc);
+    if (existing == NULL) {
+        return RBT_MAP_RESULT_ENTRY_INSERTED;
+    }
+
+    // Matching entry exists. Lets see if we need to replace it.
+    if (replaced == NULL) {
+        return RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS;
+    }
+
+    /* Copy existing entry to the provided buffer and replace it
+     * with the new one. */
+    memcpy(replaced, &existing->desc, sizeof(MMRangeDesc));
+    MMRangeMap_RB_REMOVE(map, existing);
+    qemu_free(existing);
+    MMRangeMap_RB_INSERT(map, rdesc);
+    return RBT_MAP_RESULT_ENTRY_REPLACED;
+}
+
+/* Finds an entry in the map that matches the given address range.
+ * Param:
+ *  map - Map where to search for an entry.
+ *  start - Starting address of a mapping range.
+ *  end - Ending address of a mapping range.
+ * Return:
+ *  Address of a map entry that matches the given range, or NULL if no
+ *  such entry has been found.
+ */
+static inline MMRangeMapEntry*
+mmrangemap_find_entry(const MMRangeMap* map,
+                      target_ulong start,
+                      target_ulong end)
+{
+    MMRangeMapEntry rdesc;
+    rdesc.desc.map_start = start;
+    rdesc.desc.map_end = end;
+    return MMRangeMap_RB_FIND((MMRangeMap*)map, &rdesc);
+}
+
+// =============================================================================
+// Map API
+// =============================================================================
+
+void
+mmrangemap_init(MMRangeMap* map)
+{
+    RB_INIT(map);
+}
+
+RBTMapResult
+mmrangemap_insert(MMRangeMap* map,
+                  const MMRangeDesc* desc,
+                  MMRangeDesc* replaced)
+{
+    RBTMapResult ret;
+
+    // Allocate and initialize new map entry.
+    MMRangeMapEntry* rdesc = qemu_malloc(sizeof(MMRangeMapEntry));
+    if (rdesc == NULL) {
+        ME("memcheck: Unable to allocate new MMRangeMapEntry on insert.");
+        return RBT_MAP_RESULT_ERROR;
+    }
+    memcpy(&rdesc->desc, desc, sizeof(MMRangeDesc));
+
+    // Insert new entry into the map.
+    ret = mmrangemap_insert_desc(map, rdesc, replaced);
+    if (ret == RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS ||
+        ret == RBT_MAP_RESULT_ERROR) {
+        /* Another descriptor already exists for this block, or an error
+         * occurred. We have to free new descriptor, as it wasn't inserted. */
+        qemu_free(rdesc);
+    }
+    return ret;
+}
+
+MMRangeDesc*
+mmrangemap_find(const MMRangeMap* map, target_ulong start, target_ulong end)
+{
+    MMRangeMapEntry* rdesc = mmrangemap_find_entry(map, start, end);
+    return rdesc != NULL ? &rdesc->desc : NULL;
+}
+
+int
+mmrangemap_pull(MMRangeMap* map,
+                target_ulong start,
+                target_ulong end,
+                MMRangeDesc* pulled)
+{
+    MMRangeMapEntry* rdesc = mmrangemap_find_entry(map, start, end);
+    if (rdesc != NULL) {
+        memcpy(pulled, &rdesc->desc, sizeof(MMRangeDesc));
+        MMRangeMap_RB_REMOVE(map, rdesc);
+        qemu_free(rdesc);
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+int
+mmrangemap_pull_first(MMRangeMap* map, MMRangeDesc* pulled)
+{
+    MMRangeMapEntry* first = RB_MIN(MMRangeMap, map);
+    if (first != NULL) {
+        memcpy(pulled, &first->desc, sizeof(MMRangeDesc));
+        MMRangeMap_RB_REMOVE(map, first);
+        qemu_free(first);
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+int
+mmrangemap_copy(MMRangeMap* to, const MMRangeMap* from)
+{
+    MMRangeMapEntry* entry;
+    RB_FOREACH(entry, MMRangeMap, (MMRangeMap*)from) {
+        RBTMapResult ins_res;
+        MMRangeMapEntry* new_entry =
+                (MMRangeMapEntry*)qemu_malloc(sizeof(MMRangeMapEntry));
+        if (new_entry == NULL) {
+            ME("memcheck: Unable to allocate new MMRangeMapEntry on copy.");
+            return -1;
+        }
+        memcpy(new_entry, entry, sizeof(MMRangeMapEntry));
+        new_entry->desc.path = qemu_malloc(strlen(entry->desc.path) + 1);
+        if (new_entry->desc.path == NULL) {
+            ME("memcheck: Unable to allocate new path for MMRangeMapEntry on copy.");
+            qemu_free(new_entry);
+            return -1;
+        }
+        strcpy(new_entry->desc.path, entry->desc.path);
+        ins_res = mmrangemap_insert_desc(to, new_entry, NULL);
+        if (ins_res != RBT_MAP_RESULT_ENTRY_INSERTED) {
+            ME("memcheck: Unable to insert new range map entry on copy. Insert returned %u",
+               ins_res);
+            qemu_free(new_entry->desc.path);
+            qemu_free(new_entry);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int
+mmrangemap_empty(MMRangeMap* map)
+{
+    MMRangeDesc pulled;
+    int removed = 0;
+
+    while (!mmrangemap_pull_first(map, &pulled)) {
+        qemu_free(pulled.path);
+        removed++;
+    }
+
+    return removed;
+}
diff --git a/memcheck/memcheck_mmrange_map.h b/memcheck/memcheck_mmrange_map.h
new file mode 100644
index 0000000..f2c9701
--- /dev/null
+++ b/memcheck/memcheck_mmrange_map.h
@@ -0,0 +1,127 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of structures and routines that implement a red-black
+ * tree (a map) of module memory mapping ranges in the guest system. The map is
+ * organized in such a way, that each entry in the map describes a virtual
+ * address range that belongs to a mapped execution module in the guest system.
+ * Map considers two ranges to be equal if their address ranges intersect in
+ * any part.
+ */
+
+#ifndef QEMU_MEMCHECK_MEMCHECK_MMRANGE_MAP_H
+#define QEMU_MEMCHECK_MEMCHECK_MMRANGE_MAP_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "sys-tree.h"
+#include "memcheck_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Memory mapping range map. */
+typedef struct MMRangeMap {
+    /* Head of the map. */
+    struct MMRangeMapEntry* rbh_root;
+} MMRangeMap;
+
+// =============================================================================
+// Map API
+// =============================================================================
+
+/* Initializes the map.
+ * Param:
+ *  map - Map to initialize.
+ */
+void mmrangemap_init(MMRangeMap* map);
+
+/* Inserts new (or replaces existing) entry in the map.
+ * Insertion, or replacement is controlled by the value, passed to this routine
+ * with 'replaced' parameter. If this parameter is NULL, insertion will fail if
+ * a matching entry already exists in the map. If 'replaced' parameter is not
+ * NULL, and a matching entry exists in the map, content of the existing entry
+ * will be copied to the descriptor, addressed by 'replace' parameter, existing
+ * entry will be removed from the map, and new entry will be inserted.
+ * Param:
+ *  map - Map where to insert new, or replace existing entry.
+ *  desc - Descriptor to insert to the map.
+ *  replaced - If not NULL, upon return from this routine contains descriptor
+ *      that has been replaced in the map with the new entry. Note that if this
+ *      routine returns with value other than RBT_MAP_RESULT_ENTRY_REPLACED,
+ *      content of the 'replaced' buffer is not defined, as no replacement has
+ *      actually occurred.
+ * Return
+ *  See RBTMapResult for the return codes.
+ */
+RBTMapResult mmrangemap_insert(MMRangeMap* map,
+                               const MMRangeDesc* desc,
+                               MMRangeDesc* replaced);
+
+/* Finds an entry in the map that matches the given address.
+ * Param:
+ *  map - Map where to search for an entry.
+ *  start - Starting address of a mapping range.
+ *  end - Ending address of a mapping range.
+ * Return:
+ *  Pointer to the descriptor found in a map entry, or NULL if no matching
+ * entry has been found in the map.
+ */
+MMRangeDesc* mmrangemap_find(const MMRangeMap* map,
+                             target_ulong start,
+                             target_ulong end);
+
+/* Pulls (finds and removes) an entry from the map that matches the given
+ * address.
+ * Param:
+ *  map - Map where to search for an entry.
+ *  start - Starting address of a mapping range.
+ *  end - Ending address of a mapping range.
+ *  pulled - Upon successful return contains descriptor data pulled from the
+ *      map.
+ * Return:
+ *  Zero if a descriptor that matches the given address has been pulled, or 1
+ *  if no matching entry has been found in the map.
+ */
+int mmrangemap_pull(MMRangeMap* map,
+                    target_ulong start,
+                    target_ulong end,
+                    MMRangeDesc* pulled);
+
+/* Copies content of one memory map to another.
+ * Param:
+ *  to - Map where to copy entries to.
+ *  from - Map where to copy entries from.
+ * Return:
+ *  Zero on success, or -1 on error.
+ */
+int mmrangemap_copy(MMRangeMap* to, const MMRangeMap* from);
+
+/* Empties the map.
+ * Param:
+ *  map - Map to empty.
+ * Return:
+ *  Number of entries removed from the map.
+ */
+int mmrangemap_empty(MMRangeMap* map);
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // QEMU_MEMCHECK_MEMCHECK_MMRANGE_MAP_H
diff --git a/memcheck/memcheck_proc_management.c b/memcheck/memcheck_proc_management.c
new file mode 100644
index 0000000..531ec4a
--- /dev/null
+++ b/memcheck/memcheck_proc_management.c
@@ -0,0 +1,799 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains implementation of routines related to process management in
+ * memchecker framework.
+ */
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "elff/elff_api.h"
+#include "memcheck.h"
+#include "memcheck_proc_management.h"
+#include "memcheck_logging.h"
+
+/* Current thread id.
+ * This value is updated with each call to memcheck_switch, saving here
+ * ID of the thread that becomes current. */
+static uint32_t current_tid = 0;
+
+/* Current thread descriptor.
+ * This variable is used to cache current thread descriptor. This value gets
+ * initialized on "as needed" basis, when descriptor for the current thread
+ * is requested for the first time.
+ * Note that every time memcheck_switch routine is called, this value gets
+ * NULL'ed, since another thread becomes current. */
+static ThreadDesc* current_thread = NULL;
+
+/* Current process descriptor.
+ * This variable is used to cache current process descriptor. This value gets
+ * initialized on "as needed" basis, when descriptor for the current process
+ * is requested for the first time.
+ * Note that every time memcheck_switch routine is called, this value gets
+ * NULL'ed, since new thread becomes current, thus process switch may have
+ * occurred as well. */
+static ProcDesc*    current_process = NULL;
+
+/* List of running processes. */
+static LIST_HEAD(proc_list, ProcDesc) proc_list;
+
+/* List of running threads. */
+static LIST_HEAD(thread_list, ThreadDesc) thread_list;
+
+// =============================================================================
+// Static routines
+// =============================================================================
+
+/* Creates and lists thread descriptor for a new thread.
+ * This routine will allocate and initialize new thread descriptor. After that
+ * this routine will insert the descriptor into the global list of running
+ * threads, as well as thread list in the process descriptor of the process
+ * in context of which this thread is created.
+ * Param:
+ *  proc - Process descriptor of the process, in context of which new thread
+ *      is created.
+ *  tid - Thread ID of the thread that's being created.
+ * Return:
+ *  New thread descriptor on success, or NULL on failure.
+ */
+static ThreadDesc*
+create_new_thread(ProcDesc* proc, uint32_t tid)
+{
+    ThreadDesc* new_thread = (ThreadDesc*)qemu_malloc(sizeof(ThreadDesc));
+    if (new_thread == NULL) {
+        ME("memcheck: Unable to allocate new thread descriptor.");
+        return NULL;
+    }
+    new_thread->tid = tid;
+    new_thread->process = proc;
+    new_thread->call_stack = NULL;
+    new_thread->call_stack_count = 0;
+    new_thread->call_stack_max = 0;
+    LIST_INSERT_HEAD(&thread_list, new_thread, global_entry);
+    LIST_INSERT_HEAD(&proc->threads, new_thread, proc_entry);
+    return new_thread;
+}
+
+/* Creates and lists process descriptor for a new process.
+ * This routine will allocate and initialize new process descriptor. After that
+ * this routine will create main thread descriptor for the process (with the
+ * thread ID equal to the new process ID), and then new process descriptor will
+ * be inserted into the global list of running processes.
+ * Param:
+ *  pid - Process ID of the process that's being created.
+ *  parent_pid - Process ID of the parent process.
+ * Return:
+ *  New process descriptor on success, or NULL on failure.
+ */
+static ProcDesc*
+create_new_process(uint32_t pid, uint32_t parent_pid)
+{
+    // Create and init new process descriptor.
+    ProcDesc* new_proc = (ProcDesc*)qemu_malloc(sizeof(ProcDesc));
+    if (new_proc == NULL) {
+        ME("memcheck: Unable to allocate new process descriptor");
+        return NULL;
+    }
+    LIST_INIT(&new_proc->threads);
+    allocmap_init(&new_proc->alloc_map);
+    mmrangemap_init(&new_proc->mmrange_map);
+    new_proc->pid = pid;
+    new_proc->parent_pid = parent_pid;
+    new_proc->image_path = NULL;
+    new_proc->flags = 0;
+
+    if (parent_pid != 0) {
+        /* If new process has been forked, it inherits a copy of parent's
+         * process heap, as well as parent's mmaping of loaded modules. So, on
+         * fork we're required to copy parent's allocation descriptors map, as
+         * well as parent's mmapping map to the new process. */
+        int failed;
+        ProcDesc* parent = get_process_from_pid(parent_pid);
+        if (parent == NULL) {
+            ME("memcheck: Unable to get parent process pid=%u for new process pid=%u",
+               parent_pid, pid);
+            qemu_free(new_proc);
+            return NULL;
+        }
+
+        /* Copy parent's allocation map, setting "inherited" flag, and clearing
+         * parent's "transition" flag in the copied entries. */
+        failed = allocmap_copy(&new_proc->alloc_map, &parent->alloc_map,
+                               MDESC_FLAG_INHERITED_ON_FORK,
+                               MDESC_FLAG_TRANSITION_ENTRY);
+        if (failed) {
+            ME("memcheck: Unable to copy process' %s[pid=%u] allocation map to new process pid=%u",
+               parent->image_path, parent_pid, pid);
+            allocmap_empty(&new_proc->alloc_map);
+            qemu_free(new_proc);
+            return NULL;
+        }
+
+        // Copy parent's memory mappings map.
+        failed = mmrangemap_copy(&new_proc->mmrange_map, &parent->mmrange_map);
+        if (failed) {
+            ME("memcheck: Unable to copy process' %s[pid=%u] mmrange map to new process pid=%u",
+               parent->image_path, parent_pid, pid);
+            mmrangemap_empty(&new_proc->mmrange_map);
+            allocmap_empty(&new_proc->alloc_map);
+            qemu_free(new_proc);
+            return NULL;
+        }
+    }
+
+    // Create and register main thread descriptor for new process.
+    if(create_new_thread(new_proc, pid) == NULL) {
+        mmrangemap_empty(&new_proc->mmrange_map);
+        allocmap_empty(&new_proc->alloc_map);
+        qemu_free(new_proc);
+        return NULL;
+    }
+
+    // List new process.
+    LIST_INSERT_HEAD(&proc_list, new_proc, global_entry);
+
+    return new_proc;
+}
+
+/* Finds thread descriptor for a thread id in the global list of running
+ * threads.
+ * Param:
+ *  tid - Thread ID to look up thread descriptor for.
+ * Return:
+ *  Found thread descriptor, or NULL if thread descriptor has not been found.
+ */
+static ThreadDesc*
+get_thread_from_tid(uint32_t tid)
+{
+    ThreadDesc* thread;
+
+    /* There is a pretty good chance that when this call is made, it's made
+     * to get descriptor for the current thread. Lets see if it is so, so
+     * we don't have to iterate through the entire list. */
+    if (tid == current_tid && current_thread != NULL) {
+        return current_thread;
+    }
+
+    LIST_FOREACH(thread, &thread_list, global_entry) {
+        if (tid == thread->tid) {
+            if (tid == current_tid) {
+                current_thread = thread;
+            }
+            return thread;
+        }
+    }
+    return NULL;
+}
+
+/* Gets thread descriptor for the current thread.
+ * Return:
+ *  Found thread descriptor, or NULL if thread descriptor has not been found.
+ */
+ThreadDesc*
+get_current_thread(void)
+{
+    // Lets see if current thread descriptor has been cached.
+    if (current_thread == NULL) {
+        /* Descriptor is not cached. Look it up in the list. Note that
+         * get_thread_from_tid(current_tid) is not used here in order to
+         * optimize this code for performance, as this routine is called from
+         * the performance sensitive path. */
+        ThreadDesc* thread;
+        LIST_FOREACH(thread, &thread_list, global_entry) {
+            if (current_tid == thread->tid) {
+                current_thread = thread;
+                return current_thread;
+            }
+        }
+    }
+    return current_thread;
+}
+
+/* Finds process descriptor for a thread id.
+ * Param:
+ *  tid - Thread ID to look up process descriptor for.
+ * Return:
+ *  Process descriptor for the thread, or NULL, if process descriptor
+ *  has not been found.
+ */
+static inline ProcDesc*
+get_process_from_tid(uint32_t tid)
+{
+    const ThreadDesc* thread = get_thread_from_tid(tid);
+    return (thread != NULL) ? thread->process : NULL;
+}
+
+/* Sets, or replaces process image path in process descriptor.
+ * Generally, new process' image path is unknown untill we calculate it in
+ * the handler for TRACE_DEV_REG_CMDLINE event. This routine is called from
+ * TRACE_DEV_REG_CMDLINE event handler to set, or replace process image path.
+ * Param:
+ *  proc - Descriptor of the process where to set, or replace image path.
+ *  image_path - Image path to the process, transmitted with
+ *      TRACE_DEV_REG_CMDLINE event.
+ * set_flags_on_replace - Flags to be set when current image path for the
+ *      process has been actually replaced with the new one.
+ * Return:
+ *  Zero on success, or -1 on failure.
+ */
+static int
+procdesc_set_image_path(ProcDesc* proc,
+                        const char* image_path,
+                        uint32_t set_flags_on_replace)
+{
+    if (image_path == NULL || proc == NULL) {
+        return 0;
+    }
+
+    if (proc->image_path != NULL) {
+        /* Process could have been forked, and inherited image path of the
+         * parent process. However, it seems that "fork" in terms of TRACE_XXX
+         * is not necessarly a strict "fork", but rather new process creation
+         * in general. So, if that's the case we need to override image path
+         * inherited from the parent process. */
+        if (!strcmp(proc->image_path, image_path)) {
+            // Paths are the same. Just bail out.
+            return 0;
+        }
+        qemu_free(proc->image_path);
+        proc->image_path = NULL;
+    }
+
+    // Save new image path into process' descriptor.
+    proc->image_path = qemu_malloc(strlen(image_path) + 1);
+    if (proc->image_path == NULL) {
+        ME("memcheck: Unable to allocate %u bytes for image path %s to set it for pid=%u",
+           strlen(image_path) + 1, image_path, proc->pid);
+        return -1;
+    }
+    strcpy(proc->image_path, image_path);
+    proc->flags |= set_flags_on_replace;
+    return 0;
+}
+
+/* Frees thread descriptor. */
+static void
+threaddesc_free(ThreadDesc* thread)
+{
+    uint32_t indx;
+
+    if (thread == NULL) {
+        return;
+    }
+
+    if (thread->call_stack != NULL) {
+        for (indx = 0; indx < thread->call_stack_count; indx++) {
+            if (thread->call_stack[indx].module_path != NULL) {
+                qemu_free(thread->call_stack[indx].module_path);
+            }
+        }
+        qemu_free(thread->call_stack);
+    }
+    qemu_free(thread);
+}
+
+// =============================================================================
+// Process management API
+// =============================================================================
+
+void
+memcheck_init_proc_management(void)
+{
+    LIST_INIT(&proc_list);
+    LIST_INIT(&thread_list);
+}
+
+ProcDesc*
+get_process_from_pid(uint32_t pid)
+{
+    ProcDesc* proc;
+
+    /* Chances are that pid addresses the current process. Lets check this,
+     * so we don't have to iterate through the entire project list. */
+    if (current_thread != NULL && current_thread->process->pid == pid) {
+        current_process = current_thread->process;
+        return current_process;
+    }
+
+    LIST_FOREACH(proc, &proc_list, global_entry) {
+        if (pid == proc->pid) {
+            break;
+        }
+    }
+    return proc;
+}
+
+ProcDesc*
+get_current_process(void)
+{
+    if (current_process == NULL) {
+        const ThreadDesc* cur_thread = get_current_thread();
+        if (cur_thread != NULL) {
+            current_process = cur_thread->process;
+        }
+    }
+    return current_process;
+}
+
+void
+memcheck_on_call(target_ulong from, target_ulong ret)
+{
+    const uint32_t grow_by = 32;
+    const uint32_t max_stack = grow_by;
+    ThreadDesc* thread = get_current_thread();
+    if (thread == NULL) {
+        return;
+    }
+
+    /* We're not saving call stack until process starts execution. */
+    if (!procdesc_is_executing(thread->process)) {
+        return;
+    }
+
+    const MMRangeDesc* rdesc = procdesc_get_range_desc(thread->process, from);
+    if (rdesc == NULL) {
+        ME("memcheck: Unable to find mapping for guest PC 0x%08X in process %s[pid=%u]",
+           from, thread->process->image_path, thread->process->pid);
+        return;
+    }
+
+    /* Limit calling stack size. There are cases when calling stack can be
+     * quite deep due to recursion (up to 4000 entries). */
+    if (thread->call_stack_count >= max_stack) {
+#if 0
+        /* This happens quite often. */
+        MD("memcheck: Thread stack for %s[pid=%u, tid=%u] is too big: %u",
+           thread->process->image_path, thread->process->pid, thread->tid,
+           thread->call_stack_count);
+#endif
+        return;
+    }
+
+    if (thread->call_stack_count >= thread->call_stack_max) {
+        /* Expand calling stack array buffer. */
+        thread->call_stack_max += grow_by;
+        ThreadCallStackEntry* new_array =
+            qemu_malloc(thread->call_stack_max * sizeof(ThreadCallStackEntry));
+        if (new_array == NULL) {
+            ME("memcheck: Unable to allocate %u bytes for calling stack.",
+               thread->call_stack_max * sizeof(ThreadCallStackEntry));
+            thread->call_stack_max -= grow_by;
+            return;
+        }
+        if (thread->call_stack_count != 0) {
+            memcpy(new_array, thread->call_stack,
+                   thread->call_stack_count * sizeof(ThreadCallStackEntry));
+        }
+        if (thread->call_stack != NULL) {
+            qemu_free(thread->call_stack);
+        }
+        thread->call_stack = new_array;
+    }
+    thread->call_stack[thread->call_stack_count].call_address = from;
+    thread->call_stack[thread->call_stack_count].call_address_rel =
+            mmrangedesc_get_module_offset(rdesc, from);
+    thread->call_stack[thread->call_stack_count].ret_address = ret;
+    thread->call_stack[thread->call_stack_count].ret_address_rel =
+            mmrangedesc_get_module_offset(rdesc, ret);
+    thread->call_stack[thread->call_stack_count].module_path =
+            qemu_malloc(strlen(rdesc->path) + 1);
+    if (thread->call_stack[thread->call_stack_count].module_path == NULL) {
+        ME("memcheck: Unable to allocate %u bytes for module path in the thread calling stack.",
+            strlen(rdesc->path) + 1);
+        return;
+    }
+    strcpy(thread->call_stack[thread->call_stack_count].module_path,
+           rdesc->path);
+    thread->call_stack_count++;
+}
+
+void
+memcheck_on_ret(target_ulong ret)
+{
+    ThreadDesc* thread = get_current_thread();
+    if (thread == NULL) {
+        return;
+    }
+
+    /* We're not saving call stack until process starts execution. */
+    if (!procdesc_is_executing(thread->process)) {
+        return;
+    }
+
+    if (thread->call_stack_count > 0) {
+        int indx = (int)thread->call_stack_count - 1;
+        for (; indx >= 0; indx--) {
+            if (thread->call_stack[indx].ret_address == ret) {
+                thread->call_stack_count = indx;
+                return;
+            }
+        }
+    }
+}
+
+// =============================================================================
+// Handlers for events, generated by the kernel.
+// =============================================================================
+
+void
+memcheck_init_pid(uint32_t new_pid)
+{
+    create_new_process(new_pid, 0);
+    T(PROC_NEW_PID, "memcheck: init_pid(pid=%u) in current thread tid=%u\n",
+      new_pid, current_tid);
+}
+
+void
+memcheck_switch(uint32_t tid)
+{
+    /* Since new thread became active, we have to invalidate cached
+     * descriptors for current thread and process. */
+    current_thread = NULL;
+    current_process = NULL;
+    current_tid = tid;
+}
+
+void
+memcheck_fork(uint32_t tgid, uint32_t new_pid)
+{
+    ProcDesc* parent_proc;
+    ProcDesc* new_proc;
+
+    /* tgid may match new_pid, in which case current process is the
+     * one that's being forked, otherwise tgid identifies process
+     * that's being forked. */
+    if (new_pid == tgid) {
+        parent_proc = get_current_process();
+    } else {
+        parent_proc = get_process_from_tid(tgid);
+    }
+
+    if (parent_proc == NULL) {
+        ME("memcheck: FORK(%u, %u): Unable to look up parent process. Current tid=%u",
+           tgid, new_pid, current_tid);
+        return;
+    }
+
+    if (parent_proc->pid != get_current_process()->pid) {
+        MD("memcheck: FORK(%u, %u): parent %s[pid=%u] is not the current process %s[pid=%u]",
+           tgid, new_pid, parent_proc->image_path, parent_proc->pid,
+           get_current_process()->image_path, get_current_process()->pid);
+    }
+
+    new_proc = create_new_process(new_pid, parent_proc->pid);
+    if (new_proc == NULL) {
+        return;
+    }
+
+    /* Since we're possibly forking parent process, we need to inherit
+     * parent's image path in the forked process. */
+    procdesc_set_image_path(new_proc, parent_proc->image_path, 0);
+
+    T(PROC_FORK, "memcheck: FORK(tgid=%u, new_pid=%u) by %s[pid=%u] (tid=%u)\n",
+      tgid, new_pid, parent_proc->image_path, parent_proc->pid, current_tid);
+}
+
+void
+memcheck_clone(uint32_t tgid, uint32_t new_tid)
+{
+    ProcDesc* parent_proc;
+
+    /* tgid may match new_pid, in which case current process is the
+     * one that creates thread, otherwise tgid identifies process
+     * that creates thread. */
+    if (new_tid == tgid) {
+        parent_proc = get_current_process();
+    } else {
+        parent_proc = get_process_from_tid(tgid);
+    }
+
+    if (parent_proc == NULL) {
+        ME("memcheck: CLONE(%u, %u) Unable to look up parent process. Current tid=%u",
+           tgid, new_tid, current_tid);
+        return;
+    }
+
+    if (parent_proc->pid != get_current_process()->pid) {
+        ME("memcheck: CLONE(%u, %u): parent %s[pid=%u] is not the current process %s[pid=%u]",
+           tgid, new_tid, parent_proc->image_path, parent_proc->pid,
+           get_current_process()->image_path, get_current_process()->pid);
+    }
+
+    create_new_thread(parent_proc, new_tid);
+
+    T(PROC_CLONE, "memcheck: CLONE(tgid=%u, new_tid=%u) by %s[pid=%u] (tid=%u)\n",
+      tgid, new_tid, parent_proc->image_path, parent_proc->pid, current_tid);
+}
+
+void
+memcheck_set_cmd_line(const char* cmd_arg, unsigned cmdlen)
+{
+    char parsed[4096];
+    int n;
+
+    ProcDesc* current_proc = get_current_process();
+    if (current_proc == NULL) {
+        ME("memcheck: CMDL(%s, %u): Unable to look up process for current tid=%3u",
+           cmd_arg, cmdlen, current_tid);
+        return;
+    }
+
+    /* Image path is the first agrument in cmd line. Note that due to
+     * limitations of TRACE_XXX cmdlen can never exceed CLIENT_PAGE_SIZE */
+    memcpy(parsed, cmd_arg, cmdlen);
+
+    // Cut first argument off the entire command line.
+    for (n = 0; n < cmdlen; n++) {
+        if (parsed[n] == ' ') {
+            break;
+        }
+    }
+    parsed[n] = '\0';
+
+    // Save process' image path into descriptor.
+    procdesc_set_image_path(current_proc, parsed,
+                            PROC_FLAG_IMAGE_PATH_REPLACED);
+    current_proc->flags |= PROC_FLAG_EXECUTING;
+
+    /* At this point we need to discard memory mappings inherited from
+     * the parent process, since this process has become "independent" from
+     * its parent. */
+    mmrangemap_empty(&current_proc->mmrange_map);
+    T(PROC_START, "memcheck: Executing process %s[pid=%u]\n",
+      current_proc->image_path, current_proc->pid);
+}
+
+void
+memcheck_exit(uint32_t exit_code)
+{
+    ProcDesc* proc;
+    int leaks_reported = 0;
+    MallocDescEx leaked_alloc;
+
+    // Exiting thread descriptor.
+    ThreadDesc* thread = get_current_thread();
+    if (thread == NULL) {
+        ME("memcheck: EXIT(%u): Unable to look up thread for current tid=%u",
+           exit_code, current_tid);
+        return;
+    }
+    proc = thread->process;
+
+    // Since current thread is exiting, we need to NULL its cached descriptor.
+    current_thread = NULL;
+
+    // Unlist the thread from its process as well as global lists.
+    LIST_REMOVE(thread, proc_entry);
+    LIST_REMOVE(thread, global_entry);
+    threaddesc_free(thread);
+
+    /* Lets see if this was last process thread, which would indicate
+     * process termination. */
+    if (!LIST_EMPTY(&proc->threads)) {
+        return;
+    }
+
+    // Process is terminating. Report leaks and free resources.
+    proc->flags |= PROC_FLAG_EXITING;
+
+    /* Empty allocation descriptors map for the exiting process,
+     * reporting leaking blocks in the process. */
+    while (!allocmap_pull_first(&proc->alloc_map, &leaked_alloc)) {
+        /* We should "forgive" blocks that were inherited from the
+         * parent process on fork, or were allocated while process was
+         * in "transition" state. */
+        if (!mallocdescex_is_inherited_on_fork(&leaked_alloc) &&
+            !mallocdescex_is_transition_entry(&leaked_alloc)) {
+            if (!leaks_reported) {
+                // First leak detected. Print report's header.
+                T(CHECK_LEAK, "memcheck: Process %s[pid=%u] is exiting leaking allocated blocks:\n",
+                  proc->image_path, proc->pid);
+            }
+            if (trace_flags & TRACE_CHECK_LEAK_ENABLED) {
+                // Dump leaked block information.
+                printf("   Leaked block %u:\n", leaks_reported + 1);
+                memcheck_dump_malloc_desc(&leaked_alloc, 0, 0);
+                if (leaked_alloc.call_stack != NULL) {
+                    const int max_stack = 24;
+                    if (max_stack >= leaked_alloc.call_stack_count) {
+                        printf("      Call stack:\n");
+                    } else {
+                        printf("      Call stack (first %u of %u entries):\n",
+                               max_stack, leaked_alloc.call_stack_count);
+                    }
+                    uint32_t stk;
+                    for (stk = 0;
+                         stk < leaked_alloc.call_stack_count && stk < max_stack;
+                         stk++) {
+                        const MMRangeDesc* rdesc =
+                           procdesc_find_mapentry(proc,
+                                                  leaked_alloc.call_stack[stk]);
+                        if (rdesc != NULL) {
+                            Elf_AddressInfo elff_info;
+                            ELFF_HANDLE elff_handle = NULL;
+                            uint32_t rel =
+                                mmrangedesc_get_module_offset(rdesc,
+                                                  leaked_alloc.call_stack[stk]);
+                            printf("         Frame %u: PC=0x%08X (relative 0x%08X) in module %s\n",
+                                   stk, leaked_alloc.call_stack[stk], rel,
+                                   rdesc->path);
+                            if (memcheck_get_address_info(leaked_alloc.call_stack[stk],
+                                                          rdesc, &elff_info,
+                                                          &elff_handle) == 0) {
+                                printf("            Routine %s @ %s/%s:%u\n",
+                                       elff_info.routine_name,
+                                       elff_info.dir_name,
+                                       elff_info.file_name,
+                                       elff_info.line_number);
+                                elff_free_pc_address_info(elff_handle,
+                                                          &elff_info);
+                                elff_close(elff_handle);
+                            }
+                        } else {
+                            printf("         Frame %u: PC=0x%08X in module <unknown>\n",
+                                   stk, leaked_alloc.call_stack[stk]);
+
+                        }
+                    }
+                }
+            }
+            leaks_reported++;
+        }
+    }
+
+    if (leaks_reported) {
+        T(CHECK_LEAK, "memcheck: Process %s[pid=%u] is leaking %u allocated blocks.\n",
+          proc->image_path, proc->pid, leaks_reported);
+    }
+
+    T(PROC_EXIT, "memcheck: Exiting process %s[pid=%u] in thread %u. Memory leaks detected: %u\n",
+      proc->image_path, proc->pid, current_tid, leaks_reported);
+
+    /* Since current process is exiting, we need to NULL its cached descriptor,
+     * and unlist it from the list of running processes. */
+    current_process = NULL;
+    LIST_REMOVE(proc, global_entry);
+
+    // Empty process' mmapings map.
+    mmrangemap_empty(&proc->mmrange_map);
+    if (proc->image_path != NULL) {
+        qemu_free(proc->image_path);
+    }
+    qemu_free(proc);
+}
+
+void
+memcheck_mmap_exepath(target_ulong vstart,
+                      target_ulong vend,
+                      target_ulong exec_offset,
+                      const char* path)
+{
+    MMRangeDesc desc;
+    MMRangeDesc replaced;
+    RBTMapResult ins_res;
+
+    ProcDesc* proc = get_current_process();
+    if (proc == NULL) {
+        ME("memcheck: MMAP(0x%08X, 0x%08X, 0x%08X, %s) Unable to look up current process. Current tid=%u",
+           vstart, vend, exec_offset, path, current_tid);
+        return;
+    }
+
+    /* First, unmap an overlapped section */
+    memcheck_unmap(vstart, vend);
+
+    /* Add new mapping. */
+    desc.map_start = vstart;
+    desc.map_end = vend;
+    desc.exec_offset = exec_offset;
+    desc.path = qemu_malloc(strlen(path) + 1);
+    if (desc.path == NULL) {
+        ME("memcheck: MMAP(0x%08X, 0x%08X, 0x%08X, %s) Unable to allocate path for the entry.",
+           vstart, vend, exec_offset, path);
+        return;
+    }
+    strcpy(desc.path, path);
+
+    ins_res = mmrangemap_insert(&proc->mmrange_map, &desc, &replaced);
+    if (ins_res == RBT_MAP_RESULT_ERROR) {
+        ME("memcheck: %s[pid=%u] unable to insert memory mapping entry: 0x%08X - 0x%08X",
+           proc->image_path, proc->pid, vstart, vend);
+        qemu_free(desc.path);
+        return;
+    }
+
+    if (ins_res == RBT_MAP_RESULT_ENTRY_REPLACED) {
+        MD("memcheck: %s[pid=%u] MMRANGE %s[0x%08X - 0x%08X] is replaced with %s[0x%08X - 0x%08X]",
+           proc->image_path, proc->pid, replaced.path, replaced.map_start,
+           replaced.map_end, desc.path, desc.map_start, desc.map_end);
+        qemu_free(replaced.path);
+    }
+
+    T(PROC_MMAP, "memcheck: %s[pid=%u] %s is mapped: 0x%08X - 0x%08X + 0x%08X\n",
+      proc->image_path, proc->pid, path, vstart, vend, exec_offset);
+}
+
+void
+memcheck_unmap(target_ulong vstart, target_ulong vend)
+{
+    MMRangeDesc desc;
+    ProcDesc* proc = get_current_process();
+    if (proc == NULL) {
+        ME("memcheck: UNMAP(0x%08X, 0x%08X) Unable to look up current process. Current tid=%u",
+           vstart, vend, current_tid);
+        return;
+    }
+
+    if (mmrangemap_pull(&proc->mmrange_map, vstart, vend, &desc)) {
+        return;
+    }
+
+    if (desc.map_start >= vstart && desc.map_end <= vend) {
+        /* Entire mapping has been deleted. */
+        T(PROC_MMAP, "memcheck: %s[pid=%u] %s is unmapped: [0x%08X - 0x%08X + 0x%08X]\n",
+          proc->image_path, proc->pid, desc.path, vstart, vend, desc.exec_offset);
+        qemu_free(desc.path);
+        return;
+    }
+
+    /* This can be first stage of "remap" request, when part of the existing
+     * mapping has been unmapped. If that's so, lets cut unmapped part from the
+     * block that we just pulled, and add whatever's left back to the map. */
+    T(PROC_MMAP, "memcheck: REMAP(0x%08X, 0x%08X + 0x%08X) -> (0x%08X, 0x%08X)\n",
+       desc.map_start, desc.map_end, desc.exec_offset, vstart, vend);
+    if (desc.map_start == vstart) {
+        /* We cut part from the beginning. Add the tail back. */
+        desc.exec_offset += vend - desc.map_start;
+        desc.map_start = vend;
+        mmrangemap_insert(&proc->mmrange_map, &desc, NULL);
+    } else if (desc.map_end == vend) {
+        /* We cut part from the tail. Add the beginning back. */
+        desc.map_end = vstart;
+        mmrangemap_insert(&proc->mmrange_map, &desc, NULL);
+    } else {
+        /* We cut piece in the middle. */
+        MMRangeDesc tail;
+        tail.map_start = vend;
+        tail.map_end = desc.map_end;
+        tail.exec_offset = vend - desc.map_start + desc.exec_offset;
+        tail.path = qemu_malloc(strlen(desc.path) + 1);
+        strcpy(tail.path, desc.path);
+        mmrangemap_insert(&proc->mmrange_map, &tail, NULL);
+        desc.map_end = vstart;
+        mmrangemap_insert(&proc->mmrange_map, &desc, NULL);
+    }
+}
diff --git a/memcheck/memcheck_proc_management.h b/memcheck/memcheck_proc_management.h
new file mode 100644
index 0000000..d5525b1
--- /dev/null
+++ b/memcheck/memcheck_proc_management.h
@@ -0,0 +1,327 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of structures, routines, etc. related to process
+ * management in memchecker framework.
+ */
+
+#ifndef QEMU_MEMCHECK_MEMCHECK_PROC_MANAGEMENT_H
+#define QEMU_MEMCHECK_MEMCHECK_PROC_MANAGEMENT_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "sys-queue.h"
+#include "memcheck_common.h"
+#include "memcheck_malloc_map.h"
+#include "memcheck_mmrange_map.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// =============================================================================
+// Process management structures
+// =============================================================================
+
+/* Describes a process that is monitored by memchecker framework. */
+typedef struct ProcDesc {
+    /* Map of memory blocks allocated in context of this process. */
+    AllocMap                                    alloc_map;
+
+    /* Map of memory mapped modules loaded in context of this process. */
+    MMRangeMap                                  mmrange_map;
+
+    /* Descriptor's entry in the global process list. */
+    LIST_ENTRY(ProcDesc)                        global_entry;
+
+    /* List of threads running in context of this process. */
+    LIST_HEAD(threads, ThreadDesc)              threads;
+
+    /* Path to the process' image file. */
+    char*                                       image_path;
+
+    /* Process id. */
+    uint32_t                                    pid;
+
+    /* Parent process id. */
+    uint32_t                                    parent_pid;
+
+    /* Misc. process flags. See PROC_FLAG_XXX */
+    uint32_t                                    flags;
+} ProcDesc;
+
+/* Process is executing. */
+#define PROC_FLAG_EXECUTING             0x00000001
+/* Process is exiting. */
+#define PROC_FLAG_EXITING               0x00000002
+/* ProcDesc->image_path has been replaced during process execution. */
+#define PROC_FLAG_IMAGE_PATH_REPLACED   0x00000004
+/* libc.so instance has been initialized for this process. */
+#define PROC_FLAG_LIBC_INITIALIZED      0x00000008
+
+/* Entry in the thread's calling stack array. */
+typedef struct ThreadCallStackEntry {
+    /* Guest PC where call has been made. */
+    target_ulong    call_address;
+    /* Guest PC where call has been made, relative to the beginning of the
+     * mapped module that contains call_address. */
+    target_ulong    call_address_rel;
+    /* Guest PC where call will return. */
+    target_ulong    ret_address;
+    /* Guest PC where call will return, relative to the beginning of the
+     * mapped module that contains ret_address. */
+    target_ulong    ret_address_rel;
+    /* Path to the image file of the module containing call_address. */
+    char*           module_path;
+} ThreadCallStackEntry;
+
+/* Describes a thread that is monitored by memchecker framework. */
+typedef struct ThreadDesc {
+    /* Descriptor's entry in the global thread list. */
+    LIST_ENTRY(ThreadDesc)  global_entry;
+
+    /* Descriptor's entry in the process' thread list. */
+    LIST_ENTRY(ThreadDesc)  proc_entry;
+
+    /* Descriptor of the process this thread belongs to. */
+    ProcDesc*               process;
+
+    /* Calling stack for this thread. */
+    ThreadCallStackEntry*   call_stack;
+
+    /* Number of entries in the call_stack array. */
+    uint32_t                call_stack_count;
+
+    /* Maximum number of entries that can fit into call_stack buffer. */
+    uint32_t                call_stack_max;
+
+    /* Thread id. */
+    uint32_t                tid;
+} ThreadDesc;
+
+// =============================================================================
+// Inlines
+// =============================================================================
+
+/* Checks if process has been forked, rather than created from a "fresh" PID.
+ * Param:
+ *  proc - Descriptor for the process to check.
+ * Return:
+ *  boolean: 1 if process has been forked, or 0 if it was
+ *  created from a "fresh" PID.
+ */
+static inline int
+procdesc_is_forked(const ProcDesc* proc)
+{
+    return proc->parent_pid != 0;
+}
+
+/* Checks if process is executing.
+ * Param:
+ *  proc - Descriptor for the process to check.
+ * Return:
+ *  boolean: 1 if process is executing, or 0 if it is not executing.
+ */
+static inline int
+procdesc_is_executing(const ProcDesc* proc)
+{
+    return (proc->flags & PROC_FLAG_EXECUTING) != 0;
+}
+
+/* Checks if process is exiting.
+ * Param:
+ *  proc - Descriptor for the process to check.
+ * Return:
+ *  boolean: 1 if process is exiting, or 0 if it is still alive.
+ */
+static inline int
+procdesc_is_exiting(const ProcDesc* proc)
+{
+    return (proc->flags & PROC_FLAG_EXITING) != 0;
+}
+
+/* Checks if process has initialized its libc.so instance.
+ * Param:
+ *  proc - Descriptor for the process to check.
+ * Return:
+ *  boolean: 1 if process has initialized its libc.so instance, or 0 otherwise.
+ */
+static inline int
+procdesc_is_libc_initialized(const ProcDesc* proc)
+{
+    return (proc->flags & PROC_FLAG_LIBC_INITIALIZED) != 0;
+}
+
+/* Checks if process image path has been replaced.
+ * Param:
+ *  proc - Descriptor for the process to check.
+ * Return:
+ *  boolean: 1 if process image path has been replaced,
+ *  or 0 if it was not replaced.
+ */
+static inline int
+procdesc_is_image_path_replaced(const ProcDesc* proc)
+{
+    return (proc->flags & PROC_FLAG_IMAGE_PATH_REPLACED) != 0;
+}
+
+// =============================================================================
+// Process management API
+// =============================================================================
+
+/* Gets thread descriptor for the current thread.
+ * Return:
+ *  Found thread descriptor, or NULL if thread descriptor has not been found.
+ */
+ThreadDesc* get_current_thread(void);
+
+/* Initializes process management API. */
+void memcheck_init_proc_management(void);
+
+/* Gets process descriptor for the current process.
+ * Return:
+ *  Process descriptor for the current process, or NULL, if process descriptor
+ *  has not been found.
+ */
+ProcDesc* get_current_process(void);
+
+/* Finds process descriptor for a process id.
+ * Param:
+ *  pid - Process ID to look up process descriptor for.
+ * Return:
+ *  Process descriptor for the PID, or NULL, if process descriptor
+ *  has not been found.
+ */
+ProcDesc* get_process_from_pid(uint32_t pid);
+
+/* Inserts new (or replaces existing) entry in the allocation descriptors map
+ * for the given process.
+ * See allocmap_insert for more information on this routine, its parameters
+ * and returning value.
+ * Param:
+ *  proc - Process descriptor where to add new allocation entry info.
+ */
+static inline RBTMapResult
+procdesc_add_malloc(ProcDesc* proc,
+                    const MallocDescEx* desc,
+                    MallocDescEx* replaced)
+{
+    return allocmap_insert(&proc->alloc_map, desc, replaced);
+}
+
+/* Finds an entry in the allocation descriptors map for the given process,
+ * matching given address range.
+ * See allocmap_find for more information on this routine, its parameters
+ * and returning value.
+ * Param:
+ *  proc - Process descriptor where to find an allocation entry.
+ */
+static inline MallocDescEx*
+procdesc_find_malloc_for_range(ProcDesc* proc,
+                               target_ulong address,
+                               uint32_t block_size)
+{
+    return allocmap_find(&proc->alloc_map, address, block_size);
+}
+
+/* Finds an entry in the allocation descriptors map for the given process,
+ * matching given address.
+ * See allocmap_find for more information on this routine, its parameters
+ * and returning value.
+ * Param:
+ *  proc - Process descriptor where to find an allocation entry.
+ */
+static inline MallocDescEx*
+procdesc_find_malloc(ProcDesc* proc, target_ulong address)
+{
+    return procdesc_find_malloc_for_range(proc, address, 1);
+}
+
+/* Pulls (finds and removes) an entry from the allocation descriptors map for
+ * the given process, matching given address.
+ * See allocmap_pull for more information on this routine, its parameters
+ * and returning value.
+ * Param:
+ *  proc - Process descriptor where to pull an allocation entry from.
+ */
+static inline int
+procdesc_pull_malloc(ProcDesc* proc, target_ulong address, MallocDescEx* pulled)
+{
+    return allocmap_pull(&proc->alloc_map, address, pulled);
+}
+
+/* Empties allocation descriptors map for the process.
+ * Param:
+ *  proc - Process to empty allocation map for.
+ * Return:
+ *  Number of entries deleted from the allocation map.
+ */
+static inline int
+procdesc_empty_alloc_map(ProcDesc* proc)
+{
+    return allocmap_empty(&proc->alloc_map);
+}
+
+/* Finds mmapping entry for the given address in the given process.
+ * Param:
+ *  proc - Descriptor of the process where to look for an entry.
+ *  addr - Address in the guest space for which to find an entry.
+ * Return:
+ *  Mapped entry, or NULL if no mapping for teh given address exists in the
+ *  process address space.
+ */
+static inline MMRangeDesc*
+procdesc_find_mapentry(const ProcDesc* proc, target_ulong addr)
+{
+    return mmrangemap_find(&proc->mmrange_map, addr, addr + 1);
+}
+
+/* Gets module descriptor for the given address.
+ * Param:
+ *  proc - Descriptor of the process where to look for a module.
+ *  addr - Address in the guest space for which to find a module descriptor.
+ * Return:
+ *  module descriptor for the module containing the given address, or NULL if no
+ *  such module has been found in the process' map of mmaped modules.
+ */
+static inline const MMRangeDesc*
+procdesc_get_range_desc(const ProcDesc* proc, target_ulong addr)
+{
+    return procdesc_find_mapentry(proc, addr);
+}
+
+/* Gets name of the module mmaped in context of the given process for the
+ * given address.
+ * Param:
+ *  proc - Descriptor of the process where to look for a module.
+ *  addr - Address in the guest space for which to find a module.
+ * Return:
+ *  Image path to the module containing the given address, or NULL if no such
+ *  module has been found in the process' map of mmaped modules.
+ */
+static inline const char*
+procdesc_get_module_path(const ProcDesc* proc, target_ulong addr)
+{
+    MMRangeDesc* rdesc = procdesc_find_mapentry(proc, addr);
+    return rdesc != NULL ? rdesc->path : NULL;
+}
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // QEMU_MEMCHECK_MEMCHECK_PROC_MANAGEMENT_H
diff --git a/memcheck/memcheck_util.c b/memcheck/memcheck_util.c
new file mode 100644
index 0000000..cc4182d
--- /dev/null
+++ b/memcheck/memcheck_util.c
@@ -0,0 +1,270 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains implementation of utility routines for memchecker framework.
+ */
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "stdio.h"
+#include "qemu-common.h"
+#include "android/utils/path.h"
+#include "cpu.h"
+#include "softmmu_outside_jit.h"
+#include "memcheck_proc_management.h"
+#include "memcheck_logging.h"
+#include "memcheck_util.h"
+
+/* Gets symblos file path for the given module.
+ * Param:
+ *  module_path - Path to the module to get sympath for.
+ *  sym_path - Buffer, where to save path to the symbols file path for the givem
+ *      module. NOTE: This buffer must be big enough to contain the largest
+ *      path possible.
+ *  max_char - Character size of the buffer addressed by sym_path parameter.
+ * Return:
+ *  0 on success, or -1 if symbols file has not been found, or sym_path buffer
+ *  was too small to contain entire path.
+ */
+static int
+get_sym_path(const char* module_path, char* sym_path, size_t max_char)
+{
+    const char* sym_path_root = getenv("ANDROID_PROJECT_OUT");
+    if (sym_path_root == NULL || strlen(sym_path_root) >= max_char) {
+        return -1;
+    }
+
+    strcpy(sym_path, sym_path_root);
+    max_char -= strlen(sym_path_root);
+    if (sym_path[strlen(sym_path)-1] != PATH_SEP_C) {
+        strcat(sym_path, PATH_SEP);
+        max_char--;
+    }
+    if (strlen("symbols") >= max_char) {
+        return -1;
+    }
+    strcat(sym_path, "symbols");
+    max_char -= strlen("symbols");
+    if (strlen(module_path) >= max_char) {
+        return -1;
+    }
+    strcat(sym_path, module_path);
+
+    /* Sometimes symbol file for a module is placed into a parent symbols
+     * directory. Lets iterate through all parent sym dirs, until we find
+     * sym file, or reached symbols root. */
+    while (!path_exists(sym_path)) {
+        /* Select module name. */
+        char* name = strrchr(sym_path, PATH_SEP_C);
+        assert(name != NULL);
+        *name = '\0';
+        /* Parent directory. */
+        char* parent = strrchr(sym_path, PATH_SEP_C);
+        assert(parent != NULL);
+        *parent = '\0';
+        if (strcmp(sym_path, sym_path_root) == 0) {
+            return -1;
+        }
+        *parent = PATH_SEP_C;
+        memmove(parent+1, name + 1, strlen(name + 1) + 1);
+    }
+
+    return 0;
+}
+
+// =============================================================================
+// Transfering data between guest and emulator address spaces.
+// =============================================================================
+
+void
+memcheck_get_guest_buffer(void* qemu_address,
+                          target_ulong guest_address,
+                          size_t buffer_size)
+{
+    /* Byte-by-byte copying back and forth between guest's and emulator's memory
+     * appears to be efficient enough (at least on small blocks used in
+     * memchecker), so there is no real need to optimize it by aligning guest
+     * buffer to 32 bits and use ld/stl_user instead of ld/stub_user to
+     * read / write guest's memory. */
+    while (buffer_size) {
+        *(uint8_t*)qemu_address = ldub_user(guest_address);
+        (uint32_t)qemu_address++;
+        guest_address++;
+        buffer_size--;
+    }
+}
+
+void
+memcheck_set_guest_buffer(target_ulong guest_address,
+                          const void* qemu_address,
+                          size_t buffer_size)
+{
+    while (buffer_size) {
+        stb_user(guest_address, *(uint8_t*)qemu_address);
+        guest_address++;
+        (uint32_t)qemu_address++;
+        buffer_size--;
+    }
+}
+
+size_t
+memcheck_get_guest_string(char* qemu_str,
+                          target_ulong guest_str,
+                          size_t qemu_buffer_size)
+{
+    size_t copied = 0;
+
+    if (qemu_buffer_size > 1) {
+        for (copied = 0; copied < qemu_buffer_size - 1; copied++) {
+            qemu_str[copied] = ldub_user(guest_str + copied);
+            if (qemu_str[copied] == '\0') {
+                return copied;
+            }
+        }
+    }
+    qemu_str[copied] = '\0';
+    return copied;
+}
+
+size_t
+memcheck_get_guest_kernel_string(char* qemu_str,
+                                 target_ulong guest_str,
+                                 size_t qemu_buffer_size)
+{
+    size_t copied = 0;
+
+    if (qemu_buffer_size > 1) {
+        for (copied = 0; copied < qemu_buffer_size - 1; copied++) {
+            qemu_str[copied] = ldub_kernel(guest_str + copied);
+            if (qemu_str[copied] == '\0') {
+                return copied;
+            }
+        }
+    }
+    qemu_str[copied] = '\0';
+    return copied;
+}
+
+// =============================================================================
+// Helpers for transfering memory allocation information.
+// =============================================================================
+
+void
+memcheck_fail_alloc(target_ulong guest_address)
+{
+    stl_user(ALLOC_RES_ADDRESS(guest_address), 0);
+}
+
+void
+memcheck_fail_free(target_ulong guest_address)
+{
+    stl_user(FREE_RES_ADDRESS(guest_address), 0);
+}
+
+void
+memcheck_fail_query(target_ulong guest_address)
+{
+    stl_user(QUERY_RES_ADDRESS(guest_address), 0);
+}
+
+// =============================================================================
+// Misc. utility routines.
+// =============================================================================
+
+void
+invalidate_tlb_cache(target_ulong start, target_ulong end)
+{
+    target_ulong index = (start >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    const target_ulong to = ((end - 1) >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE-1);
+    for (; index <= to; index++, start += TARGET_PAGE_SIZE) {
+        target_ulong tlb_addr = cpu_single_env->tlb_table[1][index].addr_write;
+        if ((start & TARGET_PAGE_MASK) ==
+            (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+            cpu_single_env->tlb_table[1][index].addr_write ^= TARGET_PAGE_MASK;
+        }
+        tlb_addr = cpu_single_env->tlb_table[1][index].addr_read;
+        if ((start & TARGET_PAGE_MASK) ==
+            (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+            cpu_single_env->tlb_table[1][index].addr_read ^= TARGET_PAGE_MASK;
+        }
+    }
+}
+
+void
+memcheck_dump_malloc_desc(const MallocDescEx* desc_ex,
+                          int print_flags,
+                          int print_proc_info)
+{
+    const MallocDesc* desc = &desc_ex->malloc_desc;
+    printf("            User range:             0x%08X - 0x%08X, %u bytes\n",
+           (uint32_t)mallocdesc_get_user_ptr(desc),
+            (uint32_t)mallocdesc_get_user_ptr(desc) + desc->requested_bytes,
+           desc->requested_bytes);
+    printf("            Prefix guarding area:   0x%08X - 0x%08X, %u bytes\n",
+           desc->ptr, desc->ptr + desc->prefix_size, desc->prefix_size);
+    printf("            Suffix guarding area:   0x%08X - 0x%08X, %u bytes\n",
+           mallocdesc_get_user_alloc_end(desc),
+           mallocdesc_get_user_alloc_end(desc) + desc->suffix_size,
+           desc->suffix_size);
+    if (print_proc_info) {
+        ProcDesc* proc = get_process_from_pid(desc->allocator_pid);
+        if (proc != NULL) {
+            printf("            Allocated by:           %s[pid=%u]\n",
+                   proc->image_path, proc->pid);
+        }
+    }
+    if (print_flags) {
+        printf("            Flags:                  0x%08X\n", desc_ex->flags);
+    }
+}
+
+int
+memcheck_get_address_info(target_ulong abs_pc,
+                          const MMRangeDesc* rdesc,
+                          Elf_AddressInfo* info,
+                          ELFF_HANDLE* elff_handle)
+{
+    char sym_path[MAX_PATH];
+    ELFF_HANDLE handle;
+
+    if (get_sym_path(rdesc->path, sym_path, MAX_PATH)) {
+        return 1;
+    }
+
+    handle = elff_init(sym_path);
+    if (handle == NULL) {
+        return -1;
+    }
+
+    if (!elff_is_exec(handle)) {
+        /* Debug info for shared library is created for the relative address. */
+        target_ulong rel_pc = mmrangedesc_get_module_offset(rdesc, abs_pc);
+        if (elff_get_pc_address_info(handle, rel_pc, info)) {
+            elff_close(handle);
+            return -1;
+        }
+    } else {
+        /* Debug info for executables is created for the absoulte address. */
+        if (elff_get_pc_address_info(handle, abs_pc, info)) {
+            elff_close(handle);
+            return -1;
+        }
+    }
+
+    *elff_handle = handle;
+    return 0;
+}
diff --git a/memcheck/memcheck_util.h b/memcheck/memcheck_util.h
new file mode 100644
index 0000000..d4f6c8a
--- /dev/null
+++ b/memcheck/memcheck_util.h
@@ -0,0 +1,245 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains declarations of utility routines for memchecker framework.
+ */
+
+#ifndef QEMU_MEMCHECK_MEMCHECK_UTIL_H
+#define QEMU_MEMCHECK_MEMCHECK_UTIL_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "memcheck_common.h"
+#include "elff_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// =============================================================================
+// Transfering data between guest and emulator address spaces.
+// =============================================================================
+
+/* Copies buffer residing in the guest's virtual address space to a buffer
+ * in the emulator's address space.
+ * Param:
+ *  guest_address - Address of the bufer in guest's virtual address space.
+ *  qemu_address - Address of the bufer in the emulator's address space.
+ *  buffer_size - Byte size of the guest's buffer.
+ */
+void memcheck_get_guest_buffer(void* qemu_address,
+                               target_ulong guest_address,
+                               size_t buffer_size);
+
+/* Copies buffer residing in the emulator's address space to a buffer in the
+ * guest's virtual address space.
+ * Param:
+ *  qemu_address - Address of the bufer in the emulator's address space.
+ *  guest_address - Address of the bufer in guest's virtual address space.
+ *  buffer_size - Byte size of the emualtor's buffer.
+ */
+void memcheck_set_guest_buffer(target_ulong guest_address,
+                               const void* qemu_address,
+                               size_t buffer_size);
+
+/* Copies zero-terminated string residing in the guest's virtual address space
+ * to a string buffer in emulator's address space.
+ * Param:
+ *  qemu_str - Address of the string bufer in the emulator's address space.
+ *  guest_str - Address of the string in guest's virtual address space.
+ *  qemu_buffer_size - Size of the emulator's string buffer.
+ * Return
+ *  Length of the string that has been copied.
+ */
+size_t memcheck_get_guest_string(char* qemu_str,
+                                 target_ulong guest_str,
+                                 size_t qemu_buffer_size);
+
+/* Copies zero-terminated string residing in the guest's kernel address space
+ * to a string buffer in emulator's address space.
+ * Param:
+ *  qemu_str - Address of the string bufer in the emulator's address space.
+ *  guest_str - Address of the string in guest's kernel address space.
+ *  qemu_buffer_size - Size of the emulator's string buffer.
+ * Return
+ *  Length of the string that has been copied.
+ */
+size_t memcheck_get_guest_kernel_string(char* qemu_str,
+                                        target_ulong guest_str,
+                                        size_t qemu_buffer_size);
+
+// =============================================================================
+// Helpers for transfering memory allocation information.
+// =============================================================================
+
+/* Copies memory allocation descriptor from the guest's address space to the
+ * emulator's memory.
+ * Param:
+ *  qemu_address - Descriptor address in the emulator's address space where to
+ *      copy descriptor.
+ *  guest_address - Descriptor address in the guest's address space.
+ */
+static inline void
+memcheck_get_malloc_descriptor(MallocDesc* qemu_address,
+                               target_ulong guest_address)
+{
+    memcheck_get_guest_buffer(qemu_address, guest_address, sizeof(MallocDesc));
+}
+
+/* Copies memory allocation descriptor from the emulator's memory to the guest's
+ * address space.
+ * Param:
+ *  guest_address - Descriptor address in the guest's address space.
+ *  qemu_address - Descriptor address in the emulator's address space where to
+ *  copy descriptor.
+ */
+static inline void
+memcheck_set_malloc_descriptor(target_ulong guest_address,
+                               const MallocDesc* qemu_address)
+{
+    memcheck_set_guest_buffer(guest_address, qemu_address, sizeof(MallocDesc));
+}
+
+/* Copies memory free descriptor from the guest's address space to the
+ * emulator's memory.
+ * Param:
+ *  qemu_address - Descriptor address in the emulator's address space where to
+ *      copy descriptor.
+ *  guest_address - Descriptor address in the guest's address space.
+ */
+static inline void
+memcheck_get_free_descriptor(MallocFree* qemu_address,
+                             target_ulong guest_address)
+{
+    memcheck_get_guest_buffer(qemu_address, guest_address, sizeof(MallocFree));
+}
+
+/* Copies memory allocation query descriptor from the guest's address space to
+ * the emulator's memory.
+ * Param:
+ *  guest_address - Descriptor address in the guest's address space.
+ *  qemu_address - Descriptor address in the emulator's address space where to
+ *      copy descriptor.
+ */
+static inline void
+memcheck_get_query_descriptor(MallocDescQuery* qemu_address,
+                              target_ulong guest_address)
+{
+    memcheck_get_guest_buffer(qemu_address, guest_address,
+                              sizeof(MallocDescQuery));
+}
+
+/* Fails allocation request (TRACE_DEV_REG_MALLOC event).
+ * Allocation request failure is reported by zeroing 'libc_pid' filed in the
+ * allocation descriptor in the guest's address space.
+ * Param:
+ *  guest_address - Allocation descriptor address in the guest's address space,
+ *      where to record failure.
+ */
+void memcheck_fail_alloc(target_ulong guest_address);
+
+/* Fails free request (TRACE_DEV_REG_FREE_PTR event).
+ * Free request failure is reported by zeroing 'libc_pid' filed in the free
+ * descriptor in the guest's address space.
+ * Param:
+ *  guest_address - Free descriptor address in the guest's address space, where
+ *      to record failure.
+ */
+void memcheck_fail_free(target_ulong guest_address);
+
+/* Fails memory allocation query request (TRACE_DEV_REG_QUERY_MALLOC event).
+ * Query request failure is reported by zeroing 'libc_pid' filed in the query
+ * descriptor in the guest's address space.
+ * Param:
+ *  guest_address - Query descriptor address in the guest's address space, where
+ *      to record failure.
+ */
+void memcheck_fail_query(target_ulong guest_address);
+
+// =============================================================================
+// Misc. utility routines.
+// =============================================================================
+
+/* Converts PC address in the translated block to a corresponded PC address in
+ * the guest address space.
+ * Param:
+ *  tb_pc - PC address in the translated block.
+ * Return:
+ *  Corresponded PC address in the guest address space on success, or NULL if
+ *  conversion has failed.
+ */
+static inline target_ulong
+memcheck_tpc_to_gpc(target_ulong tb_pc)
+{
+    const TranslationBlock* tb = tb_find_pc(tb_pc);
+    return tb != NULL ? tb_search_guest_pc_from_tb_pc(tb, tb_pc) : 0;
+}
+
+/* Invalidates TLB table pages that contain given memory range.
+ * This routine is called after new entry is inserted into allocation map, so
+ * every access to the allocated block will cause __ld/__stx_mmu to be called.
+ * Param:
+ *  start - Beginning of the allocated block to invalidate pages for.
+ *  end - End of (past one byte after) the allocated block to invalidate pages
+ *      for.
+ */
+void invalidate_tlb_cache(target_ulong start, target_ulong end);
+
+/* Gets routine, file path and line number information for a PC address in the
+ * given module.
+ * Param:
+ *  abs_pc - PC address.
+ *  rdesc - Mapped memory range descriptor for the module containing abs_pc.
+ *  info - Upon successful return will contain routine, file path and line
+ *      information for the given PC address in the given module.
+ *      NOTE: Pathnames, saved into this structure are contained in mapped
+ *      sections of the symbols file for the module addressed by module_path.
+ *      Thus, pathnames are accessible only while elff_handle returned from this
+ *      routine remains opened.
+ *      NOTE: each successful call to this routine requires the caller to call
+ *      elff_free_pc_address_info for Elf_AddressInfo structure.
+ *  elff_handle - Upon successful return will contain a handle to the ELFF API
+ *      that wraps symbols file for the module, addressed by module_path. The
+ *      handle must remain opened for as long as pathnames in the info structure
+ *      are accessed, and must be eventually closed via call to elff_close.
+ * Return:
+ *  0 on success, 1, if symbols file for the module has not been found, or -1 on
+ *  other failures. If a failure is returned from this routine content of info
+ *  and elff_handle parameters is undefined.
+ */
+int memcheck_get_address_info(target_ulong abs_pc,
+                              const MMRangeDesc* rdesc,
+                              Elf_AddressInfo* info,
+                              ELFF_HANDLE* elff_handle);
+
+/* Dumps content of an allocation descriptor to stdout.
+ * Param desc - Allocation descriptor to dump.
+ * print_flags - If 1, flags field of the descriptor will be dumped to stdout.
+ *      If 0, flags filed will not be dumped.
+ * print_proc_info - If 1, allocator's process information for the descriptor
+ *      will be dumped to stdout. If 0, allocator's process information will
+ *      not be dumped.
+ */
+void memcheck_dump_malloc_desc(const MallocDescEx* desc,
+                               int print_flags,
+                               int print_proc_info);
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // QEMU_MEMCHECK_MEMCHECK_UTIL_H
diff --git a/softmmu_header.h b/softmmu_header.h
index a1b3808..f96b512 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -41,8 +41,16 @@
 
 #if ACCESS_TYPE < (NB_MMU_MODES)
 
-#define CPU_MMU_INDEX ACCESS_TYPE
+#if defined(OUTSIDE_JIT)
+/* Dispatch calls to __ldx_outside_jit / __stx_outside_jit, which don't
+ * expect CPU environment. to be cached in ebp register, but rather uses
+ * cpu_single_env variable for that purpose.
+ */
+#define MMUSUFFIX _outside_jit
+#else   // OUTSIDE_JIT
 #define MMUSUFFIX _mmu
+#endif  // OUTSIDE_JIT
+#define CPU_MMU_INDEX ACCESS_TYPE
 
 #elif ACCESS_TYPE == (NB_MMU_MODES)
 
diff --git a/softmmu_outside_jit.c b/softmmu_outside_jit.c
new file mode 100644
index 0000000..048a2ea
--- /dev/null
+++ b/softmmu_outside_jit.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 2007-2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains SOFTMMU macros expansion for ldx_user and stx_user routines used
+ * outside of JIT. The issue is that regular implementation of these routines
+ * assumes that pointer to CPU environment is stored in ebp register, which
+ * is true for calls made inside JIT, but is not necessarily true for calls
+ * made outside of JIT. The way SOFTMMU macros are expanded in this header
+ * enforces ldx/stx routines to use CPU environment stored in cpu_single_env
+ * variable.
+ */
+
+#include "qemu-common.h"
+#include "cpu.h"
+
+#define OUTSIDE_JIT
+#define MMUSUFFIX       _outside_jit
+#define GETPC()         NULL
+#define env             cpu_single_env
+#define ACCESS_TYPE     1
+#define CPU_MMU_INDEX   (cpu_mmu_index(env))
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+#undef CPU_MMU_INDEX
+#undef ACCESS_TYPE
+#undef env
+#undef MMUSUFFIX
diff --git a/softmmu_outside_jit.h b/softmmu_outside_jit.h
new file mode 100644
index 0000000..07ba4c7
--- /dev/null
+++ b/softmmu_outside_jit.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 2007-2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains SOFTMMU macros expansion for ldx_user and stx_user routines used
+ * outside of JIT. The issue is that regular implementation of these routines
+ * assumes that pointer to CPU environment is stored in ebp register, which
+ * is true for calls made inside JIT, but is not necessarily true for calls
+ * made outside of JIT. The way SOFTMMU macros are expanded in this header
+ * enforces ldx/stx routines to use CPU environment stored in cpu_single_env
+ * variable.
+ */
+#ifndef QEMU_SOFTMMU_OUTSIDE_JIT_H
+#define QEMU_SOFTMMU_OUTSIDE_JIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Declares routines implemented in softmmu_outside_jit.c, that are used in
+// this macros expansion. Note that MMUSUFFIX _outside_jit is enforced in
+// softmmu_header.h by defining OUTSIDE_JIT macro.
+////////////////////////////////////////////////////////////////////////////////
+
+uint8_t REGPARM __ldb_outside_jit(target_ulong addr, int mmu_idx);
+void REGPARM __stb_outside_jit(target_ulong addr, uint8_t val, int mmu_idx);
+uint16_t REGPARM __ldw_outside_jit(target_ulong addr, int mmu_idx);
+void REGPARM __stw_outside_jit(target_ulong addr, uint16_t val, int mmu_idx);
+uint32_t REGPARM __ldl_outside_jit(target_ulong addr, int mmu_idx);
+void REGPARM __stl_outside_jit(target_ulong addr, uint32_t val, int mmu_idx);
+uint64_t REGPARM __ldq_outside_jit(target_ulong addr, int mmu_idx);
+void REGPARM __stq_outside_jit(target_ulong addr, uint64_t val, int mmu_idx);
+
+// Enforces MMUSUFFIX to be set to _outside_jit in softmmu_header.h
+#define OUTSIDE_JIT
+// Enforces use of cpu_single_env for CPU environment.
+#define env cpu_single_env
+
+// =============================================================================
+// Generate ld/stx_user
+// =============================================================================
+#define MEMSUFFIX MMU_MODE1_SUFFIX
+#define ACCESS_TYPE 1
+
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+
+#undef MEMSUFFIX
+#undef ACCESS_TYPE
+
+// =============================================================================
+// Generate ld/stx_kernel
+// =============================================================================
+#define MEMSUFFIX MMU_MODE0_SUFFIX
+#define ACCESS_TYPE 0
+
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+
+#undef MEMSUFFIX
+#undef ACCESS_TYPE
+
+#undef env
+#undef OUTSIDE_JIT
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // QEMU_SOFTMMU_OUTSIDE_JIT_H
diff --git a/softmmu_template.h b/softmmu_template.h
index 4b33aef..ad00c4d 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -47,6 +47,20 @@
 #define ADDR_READ addr_read
 #endif
 
+#if defined(CONFIG_MEMCHECK) && !defined(OUTSIDE_JIT) && !defined(SOFTMMU_CODE_ACCESS)
+/*
+ * Support for memory access checker.
+ * We need to instrument __ldx/__stx_mmu routines implemented in this file with
+ * callbacks to access validation routines implemented by the memory checker.
+ * Note that (at least for now) we don't do that instrumentation for memory
+ * addressing the code (SOFTMMU_CODE_ACCESS controls that). Also, we don't want
+ * to instrument code that is used by emulator itself (OUTSIDE_JIT controls
+ * that).
+ */
+#define CONFIG_MEMCHECK_MMU
+#include "memcheck/memcheck_api.h"
+#endif  // CONFIG_MEMCHECK && !OUTSIDE_JIT && !SOFTMMU_CODE_ACCESS
+
 static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
                                                         int mmu_idx,
                                                         void *retaddr);
@@ -91,6 +105,9 @@
     target_ulong tlb_addr;
     target_phys_addr_t addend;
     void *retaddr;
+#ifdef CONFIG_MEMCHECK_MMU
+    int invalidate_cache = 0;
+#endif  // CONFIG_MEMCHECK_MMU
 
     /* test if there is match for unaligned or IO access */
     /* XXX: could done more in memory macro in a non portable way */
@@ -106,6 +123,17 @@
             addend = env->iotlb[mmu_idx][index];
             res = glue(io_read, SUFFIX)(addend, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+            /* This is not I/O access: do access verification. */
+#ifdef CONFIG_MEMCHECK_MMU
+            /* We only validate access to the guest's user space, for which
+             * mmu_idx is set to 1. */
+            if (memcheck_instrument_mmu && mmu_idx == 1 &&
+                memcheck_validate_ld(addr, DATA_SIZE, (target_ulong)GETPC())) {
+                /* Memory read breaks page boundary. So, if required, we
+                 * must invalidate two caches in TLB. */
+                invalidate_cache = 2;
+            }
+#endif  // CONFIG_MEMCHECK_MMU
             /* slow unaligned access (it spans two pages or IO) */
         do_unaligned_access:
             retaddr = GETPC();
@@ -115,6 +143,14 @@
             res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
                                                          mmu_idx, retaddr);
         } else {
+#ifdef CONFIG_MEMCHECK_MMU
+            /* We only validate access to the guest's user space, for which
+             * mmu_idx is set to 1. */
+            if (memcheck_instrument_mmu && mmu_idx == 1) {
+                invalidate_cache = memcheck_validate_ld(addr, DATA_SIZE,
+                                                        (target_ulong)GETPC());
+            }
+#endif  // CONFIG_MEMCHECK_MMU
             /* unaligned/aligned access in the same page */
 #ifdef ALIGNED_ONLY
             if ((addr & (DATA_SIZE - 1)) != 0) {
@@ -125,6 +161,20 @@
             addend = env->tlb_table[mmu_idx][index].addend;
             res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
         }
+#ifdef CONFIG_MEMCHECK_MMU
+        if (invalidate_cache) {
+            /* Accessed memory is under memchecker control. We must invalidate
+             * containing page(s) in order to make sure that next access to them
+             * will invoke _ld/_st_mmu. */
+            env->tlb_table[mmu_idx][index].addr_read ^= TARGET_PAGE_MASK;
+            env->tlb_table[mmu_idx][index].addr_write ^= TARGET_PAGE_MASK;
+            if ((invalidate_cache == 2) && (index < CPU_TLB_SIZE)) {
+                // Read crossed page boundaris. Invalidate second cache too.
+                env->tlb_table[mmu_idx][index + 1].addr_read ^= TARGET_PAGE_MASK;
+                env->tlb_table[mmu_idx][index + 1].addr_write ^= TARGET_PAGE_MASK;
+            }
+        }
+#endif  // CONFIG_MEMCHECK_MMU
     } else {
         /* the page is not in the TLB : fill it */
         retaddr = GETPC();
@@ -234,6 +284,9 @@
     target_ulong tlb_addr;
     void *retaddr;
     int index;
+#ifdef CONFIG_MEMCHECK_MMU
+    int invalidate_cache = 0;
+#endif  // CONFIG_MEMCHECK_MMU
 
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
@@ -247,6 +300,18 @@
             addend = env->iotlb[mmu_idx][index];
             glue(io_write, SUFFIX)(addend, val, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+            /* This is not I/O access: do access verification. */
+#ifdef CONFIG_MEMCHECK_MMU
+            /* We only validate access to the guest's user space, for which
+             * mmu_idx is set to 1. */
+            if (memcheck_instrument_mmu && mmu_idx == 1 &&
+                memcheck_validate_st(addr, DATA_SIZE, (uint64_t)val,
+                                     (target_ulong)GETPC())) {
+                /* Memory write breaks page boundary. So, if required, we
+                 * must invalidate two caches in TLB. */
+                invalidate_cache = 2;
+            }
+#endif  // CONFIG_MEMCHECK_MMU
         do_unaligned_access:
             retaddr = GETPC();
 #ifdef ALIGNED_ONLY
@@ -255,6 +320,15 @@
             glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
                                                    mmu_idx, retaddr);
         } else {
+#ifdef CONFIG_MEMCHECK_MMU
+            /* We only validate access to the guest's user space, for which
+             * mmu_idx is set to 1. */
+            if (memcheck_instrument_mmu && mmu_idx == 1) {
+                invalidate_cache = memcheck_validate_st(addr, DATA_SIZE,
+                                                        (uint64_t)val,
+                                                        (target_ulong)GETPC());
+            }
+#endif  // CONFIG_MEMCHECK_MMU
             /* aligned/unaligned access in the same page */
 #ifdef ALIGNED_ONLY
             if ((addr & (DATA_SIZE - 1)) != 0) {
@@ -265,6 +339,20 @@
             addend = env->tlb_table[mmu_idx][index].addend;
             glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
         }
+#ifdef CONFIG_MEMCHECK_MMU
+        if (invalidate_cache) {
+            /* Accessed memory is under memchecker control. We must invalidate
+             * containing page(s) in order to make sure that next access to them
+             * will invoke _ld/_st_mmu. */
+            env->tlb_table[mmu_idx][index].addr_read ^= TARGET_PAGE_MASK;
+            env->tlb_table[mmu_idx][index].addr_write ^= TARGET_PAGE_MASK;
+            if ((invalidate_cache == 2) && (index < CPU_TLB_SIZE)) {
+                // Write crossed page boundaris. Invalidate second cache too.
+                env->tlb_table[mmu_idx][index + 1].addr_read ^= TARGET_PAGE_MASK;
+                env->tlb_table[mmu_idx][index + 1].addr_write ^= TARGET_PAGE_MASK;
+            }
+        }
+#endif  // CONFIG_MEMCHECK_MMU
     } else {
         /* the page is not in the TLB : fill it */
         retaddr = GETPC();
diff --git a/sys-tree.h b/sys-tree.h
new file mode 100644
index 0000000..13d049f
--- /dev/null
+++ b/sys-tree.h
@@ -0,0 +1,771 @@
+/*  $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $  */
+/*  $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $    */
+/* $FreeBSD: src/sys/sys/tree.h,v 1.9.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $ */
+
+/*-
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_TREE_H_
+#define _SYS_TREE_H_
+
+/* Ommit "struct" prefix if this code is built with C++,
+ * so it can build. */
+#ifdef __cplusplus
+#define SYS_TREE_STRUCT
+#else
+#define SYS_TREE_STRUCT  struct
+#endif
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure.  Every operation
+ * on the tree causes a splay to happen.  The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree.  On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n).  The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute.  It fulfills a set of conditions:
+ *  - every search path from the root to a leaf consists of the
+ *    same number of black nodes,
+ *  - each red node (except for the root) has a black parent,
+ *  - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type)                      \
+struct name {                               \
+    SYS_TREE_STRUCT type *sph_root; /* root of the tree */           \
+}
+
+#define SPLAY_INITIALIZER(root)                     \
+    { NULL }
+
+#define SPLAY_INIT(root) do {                       \
+    (root)->sph_root = NULL;                    \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ENTRY(type)                       \
+struct {                                \
+    SYS_TREE_STRUCT type *spe_left; /* left element */           \
+    SYS_TREE_STRUCT type *spe_right; /* right element */         \
+}
+
+#define SPLAY_LEFT(elm, field)      (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field)     (elm)->field.spe_right
+#define SPLAY_ROOT(head)        (head)->sph_root
+#define SPLAY_EMPTY(head)       (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do {           \
+    SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field);  \
+    SPLAY_RIGHT(tmp, field) = (head)->sph_root;         \
+    (head)->sph_root = tmp;                     \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do {            \
+    SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field);  \
+    SPLAY_LEFT(tmp, field) = (head)->sph_root;          \
+    (head)->sph_root = tmp;                     \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do {               \
+    SPLAY_LEFT(tmp, field) = (head)->sph_root;          \
+    tmp = (head)->sph_root;                     \
+    (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);     \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do {              \
+    SPLAY_RIGHT(tmp, field) = (head)->sph_root;         \
+    tmp = (head)->sph_root;                     \
+    (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);    \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do {     \
+    SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+    SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
+    SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+    SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp)             \
+void name##_SPLAY(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *);            \
+void name##_SPLAY_MINMAX(SYS_TREE_STRUCT name *, int);               \
+SYS_TREE_STRUCT type *name##_SPLAY_INSERT(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *);     \
+SYS_TREE_STRUCT type *name##_SPLAY_REMOVE(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *);     \
+                                    \
+/* Finds the node with the same key as elm */               \
+static __inline SYS_TREE_STRUCT type *                       \
+name##_SPLAY_FIND(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)          \
+{                                   \
+    if (SPLAY_EMPTY(head))                      \
+        return(NULL);                       \
+    name##_SPLAY(head, elm);                    \
+    if ((cmp)(elm, (head)->sph_root) == 0)              \
+        return (head->sph_root);                \
+    return (NULL);                          \
+}                                   \
+                                    \
+static __inline SYS_TREE_STRUCT type *                       \
+name##_SPLAY_NEXT(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)          \
+{                                   \
+    name##_SPLAY(head, elm);                    \
+    if (SPLAY_RIGHT(elm, field) != NULL) {              \
+        elm = SPLAY_RIGHT(elm, field);              \
+        while (SPLAY_LEFT(elm, field) != NULL) {        \
+            elm = SPLAY_LEFT(elm, field);           \
+        }                           \
+    } else                              \
+        elm = NULL;                     \
+    return (elm);                           \
+}                                   \
+                                    \
+static __inline SYS_TREE_STRUCT type *                       \
+name##_SPLAY_MIN_MAX(SYS_TREE_STRUCT name *head, int val)            \
+{                                   \
+    name##_SPLAY_MINMAX(head, val);                 \
+        return (SPLAY_ROOT(head));                  \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp)              \
+SYS_TREE_STRUCT type *                               \
+name##_SPLAY_INSERT(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)        \
+{                                   \
+    if (SPLAY_EMPTY(head)) {                        \
+        SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL;    \
+    } else {                                \
+        int __comp;                         \
+        name##_SPLAY(head, elm);                    \
+        __comp = (cmp)(elm, (head)->sph_root);          \
+        if(__comp < 0) {                        \
+            SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
+            SPLAY_RIGHT(elm, field) = (head)->sph_root;     \
+            SPLAY_LEFT((head)->sph_root, field) = NULL;     \
+        } else if (__comp > 0) {                    \
+            SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
+            SPLAY_LEFT(elm, field) = (head)->sph_root;      \
+            SPLAY_RIGHT((head)->sph_root, field) = NULL;    \
+        } else                          \
+            return ((head)->sph_root);              \
+    }                                   \
+    (head)->sph_root = (elm);                       \
+    return (NULL);                          \
+}                                   \
+                                    \
+SYS_TREE_STRUCT type *                               \
+name##_SPLAY_REMOVE(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)        \
+{                                   \
+    SYS_TREE_STRUCT type *__tmp;                     \
+    if (SPLAY_EMPTY(head))                      \
+        return (NULL);                      \
+    name##_SPLAY(head, elm);                    \
+    if ((cmp)(elm, (head)->sph_root) == 0) {            \
+        if (SPLAY_LEFT((head)->sph_root, field) == NULL) {  \
+            (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
+        } else {                        \
+            __tmp = SPLAY_RIGHT((head)->sph_root, field);   \
+            (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
+            name##_SPLAY(head, elm);            \
+            SPLAY_RIGHT((head)->sph_root, field) = __tmp;   \
+        }                           \
+        return (elm);                       \
+    }                               \
+    return (NULL);                          \
+}                                   \
+                                    \
+void                                    \
+name##_SPLAY(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)           \
+{                                   \
+    SYS_TREE_STRUCT type __node, *__left, *__right, *__tmp;          \
+    int __comp;                         \
+\
+    SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+    __left = __right = &__node;                 \
+\
+    while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) {      \
+        if (__comp < 0) {                   \
+            __tmp = SPLAY_LEFT((head)->sph_root, field);    \
+            if (__tmp == NULL)              \
+                break;                  \
+            if ((cmp)(elm, __tmp) < 0){         \
+                SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+                if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+                    break;              \
+            }                       \
+            SPLAY_LINKLEFT(head, __right, field);       \
+        } else if (__comp > 0) {                \
+            __tmp = SPLAY_RIGHT((head)->sph_root, field);   \
+            if (__tmp == NULL)              \
+                break;                  \
+            if ((cmp)(elm, __tmp) > 0){         \
+                SPLAY_ROTATE_LEFT(head, __tmp, field);  \
+                if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+                    break;              \
+            }                       \
+            SPLAY_LINKRIGHT(head, __left, field);       \
+        }                           \
+    }                               \
+    SPLAY_ASSEMBLE(head, &__node, __left, __right, field);      \
+}                                   \
+                                    \
+/* Splay with either the minimum or the maximum element         \
+ * Used to find minimum or maximum element in tree.         \
+ */                                 \
+void name##_SPLAY_MINMAX(SYS_TREE_STRUCT name *head, int __comp) \
+{                                   \
+    SYS_TREE_STRUCT type __node, *__left, *__right, *__tmp;          \
+\
+    SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+    __left = __right = &__node;                 \
+\
+    while (1) {                         \
+        if (__comp < 0) {                   \
+            __tmp = SPLAY_LEFT((head)->sph_root, field);    \
+            if (__tmp == NULL)              \
+                break;                  \
+            if (__comp < 0){                \
+                SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+                if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+                    break;              \
+            }                       \
+            SPLAY_LINKLEFT(head, __right, field);       \
+        } else if (__comp > 0) {                \
+            __tmp = SPLAY_RIGHT((head)->sph_root, field);   \
+            if (__tmp == NULL)              \
+                break;                  \
+            if (__comp > 0) {               \
+                SPLAY_ROTATE_LEFT(head, __tmp, field);  \
+                if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+                    break;              \
+            }                       \
+            SPLAY_LINKRIGHT(head, __left, field);       \
+        }                           \
+    }                               \
+    SPLAY_ASSEMBLE(head, &__node, __left, __right, field);      \
+}
+
+#define SPLAY_NEGINF    -1
+#define SPLAY_INF   1
+
+#define SPLAY_INSERT(name, x, y)    name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y)    name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y)      name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y)      name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x)      (SPLAY_EMPTY(x) ? NULL  \
+                    : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x)      (SPLAY_EMPTY(x) ? NULL  \
+                    : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head)                    \
+    for ((x) = SPLAY_MIN(name, head);               \
+         (x) != NULL;                       \
+         (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type)                     \
+struct name {                               \
+    SYS_TREE_STRUCT type *rbh_root; /* root of the tree */           \
+}
+
+#define RB_INITIALIZER(root)                        \
+    { NULL }
+
+#define RB_INIT(root) do {                      \
+    (root)->rbh_root = NULL;                    \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_BLACK    0
+#define RB_RED      1
+#define RB_ENTRY(type)                          \
+struct {                                \
+    SYS_TREE_STRUCT type *rbe_left;      /* left element */      \
+    SYS_TREE_STRUCT type *rbe_right;     /* right element */     \
+    SYS_TREE_STRUCT type *rbe_parent;    /* parent element */        \
+    int rbe_color;          /* node color */        \
+}
+
+#define RB_LEFT(elm, field)     (elm)->field.rbe_left
+#define RB_RIGHT(elm, field)        (elm)->field.rbe_right
+#define RB_PARENT(elm, field)       (elm)->field.rbe_parent
+#define RB_COLOR(elm, field)        (elm)->field.rbe_color
+#define RB_ROOT(head)           (head)->rbh_root
+#define RB_EMPTY(head)          (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do {                 \
+    RB_PARENT(elm, field) = parent;                 \
+    RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL;      \
+    RB_COLOR(elm, field) = RB_RED;                  \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_SET_BLACKRED(black, red, field) do {             \
+    RB_COLOR(black, field) = RB_BLACK;              \
+    RB_COLOR(red, field) = RB_RED;                  \
+} while (/*CONSTCOND*/ 0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x)   do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do {          \
+    (tmp) = RB_RIGHT(elm, field);                   \
+    if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
+        RB_PARENT(RB_LEFT(tmp, field), field) = (elm);      \
+    }                               \
+    RB_AUGMENT(elm);                        \
+    if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) {  \
+        if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+            RB_LEFT(RB_PARENT(elm, field), field) = (tmp);  \
+        else                            \
+            RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+    } else                              \
+        (head)->rbh_root = (tmp);               \
+    RB_LEFT(tmp, field) = (elm);                    \
+    RB_PARENT(elm, field) = (tmp);                  \
+    RB_AUGMENT(tmp);                        \
+    if ((RB_PARENT(tmp, field)))                    \
+        RB_AUGMENT(RB_PARENT(tmp, field));          \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do {         \
+    (tmp) = RB_LEFT(elm, field);                    \
+    if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
+        RB_PARENT(RB_RIGHT(tmp, field), field) = (elm);     \
+    }                               \
+    RB_AUGMENT(elm);                        \
+    if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) {  \
+        if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+            RB_LEFT(RB_PARENT(elm, field), field) = (tmp);  \
+        else                            \
+            RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+    } else                              \
+        (head)->rbh_root = (tmp);               \
+    RB_RIGHT(tmp, field) = (elm);                   \
+    RB_PARENT(elm, field) = (tmp);                  \
+    RB_AUGMENT(tmp);                        \
+    if ((RB_PARENT(tmp, field)))                    \
+        RB_AUGMENT(RB_PARENT(tmp, field));          \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp)                \
+    RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp)         \
+    RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr)     \
+attr void name##_RB_INSERT_COLOR(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *);     \
+attr void name##_RB_REMOVE_COLOR(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *, SYS_TREE_STRUCT type *);\
+attr SYS_TREE_STRUCT type *name##_RB_REMOVE(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *);   \
+attr SYS_TREE_STRUCT type *name##_RB_INSERT(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *);   \
+attr SYS_TREE_STRUCT type *name##_RB_FIND(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *);     \
+attr SYS_TREE_STRUCT type *name##_RB_NFIND(SYS_TREE_STRUCT name *, SYS_TREE_STRUCT type *);    \
+attr SYS_TREE_STRUCT type *name##_RB_NEXT(SYS_TREE_STRUCT type *);            \
+attr SYS_TREE_STRUCT type *name##_RB_PREV(SYS_TREE_STRUCT type *);            \
+attr SYS_TREE_STRUCT type *name##_RB_MINMAX(SYS_TREE_STRUCT name *, int);         \
+                                    \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp)             \
+    RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp)          \
+    RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr)      \
+attr void                               \
+name##_RB_INSERT_COLOR(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)     \
+{                                   \
+    SYS_TREE_STRUCT type *parent, *gparent, *tmp;                \
+    while ((parent = RB_PARENT(elm, field)) != NULL &&      \
+        RB_COLOR(parent, field) == RB_RED) {            \
+        gparent = RB_PARENT(parent, field);         \
+        if (parent == RB_LEFT(gparent, field)) {        \
+            tmp = RB_RIGHT(gparent, field);         \
+            if (tmp && RB_COLOR(tmp, field) == RB_RED) {    \
+                RB_COLOR(tmp, field) = RB_BLACK;    \
+                RB_SET_BLACKRED(parent, gparent, field);\
+                elm = gparent;              \
+                continue;               \
+            }                       \
+            if (RB_RIGHT(parent, field) == elm) {       \
+                RB_ROTATE_LEFT(head, parent, tmp, field);\
+                tmp = parent;               \
+                parent = elm;               \
+                elm = tmp;              \
+            }                       \
+            RB_SET_BLACKRED(parent, gparent, field);    \
+            RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+        } else {                        \
+            tmp = RB_LEFT(gparent, field);          \
+            if (tmp && RB_COLOR(tmp, field) == RB_RED) {    \
+                RB_COLOR(tmp, field) = RB_BLACK;    \
+                RB_SET_BLACKRED(parent, gparent, field);\
+                elm = gparent;              \
+                continue;               \
+            }                       \
+            if (RB_LEFT(parent, field) == elm) {        \
+                RB_ROTATE_RIGHT(head, parent, tmp, field);\
+                tmp = parent;               \
+                parent = elm;               \
+                elm = tmp;              \
+            }                       \
+            RB_SET_BLACKRED(parent, gparent, field);    \
+            RB_ROTATE_LEFT(head, gparent, tmp, field);  \
+        }                           \
+    }                               \
+    RB_COLOR(head->rbh_root, field) = RB_BLACK;         \
+}                                   \
+                                    \
+attr void                               \
+name##_RB_REMOVE_COLOR(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *parent, SYS_TREE_STRUCT type *elm) \
+{                                   \
+    SYS_TREE_STRUCT type *tmp;                       \
+    while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+        elm != RB_ROOT(head)) {                 \
+        if (RB_LEFT(parent, field) == elm) {            \
+            tmp = RB_RIGHT(parent, field);          \
+            if (RB_COLOR(tmp, field) == RB_RED) {       \
+                RB_SET_BLACKRED(tmp, parent, field);    \
+                RB_ROTATE_LEFT(head, parent, tmp, field);\
+                tmp = RB_RIGHT(parent, field);      \
+            }                       \
+            if ((RB_LEFT(tmp, field) == NULL ||     \
+                RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+                (RB_RIGHT(tmp, field) == NULL ||        \
+                RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+                RB_COLOR(tmp, field) = RB_RED;      \
+                elm = parent;               \
+                parent = RB_PARENT(elm, field);     \
+            } else {                    \
+                if (RB_RIGHT(tmp, field) == NULL || \
+                    RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
+                    SYS_TREE_STRUCT type *oleft;     \
+                    if ((oleft = RB_LEFT(tmp, field)) \
+                        != NULL)            \
+                        RB_COLOR(oleft, field) = RB_BLACK;\
+                    RB_COLOR(tmp, field) = RB_RED;  \
+                    RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+                    tmp = RB_RIGHT(parent, field);  \
+                }                   \
+                RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+                RB_COLOR(parent, field) = RB_BLACK; \
+                if (RB_RIGHT(tmp, field))       \
+                    RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
+                RB_ROTATE_LEFT(head, parent, tmp, field);\
+                elm = RB_ROOT(head);            \
+                break;                  \
+            }                       \
+        } else {                        \
+            tmp = RB_LEFT(parent, field);           \
+            if (RB_COLOR(tmp, field) == RB_RED) {       \
+                RB_SET_BLACKRED(tmp, parent, field);    \
+                RB_ROTATE_RIGHT(head, parent, tmp, field);\
+                tmp = RB_LEFT(parent, field);       \
+            }                       \
+            if ((RB_LEFT(tmp, field) == NULL ||     \
+                RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+                (RB_RIGHT(tmp, field) == NULL ||        \
+                RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+                RB_COLOR(tmp, field) = RB_RED;      \
+                elm = parent;               \
+                parent = RB_PARENT(elm, field);     \
+            } else {                    \
+                if (RB_LEFT(tmp, field) == NULL ||  \
+                    RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
+                    SYS_TREE_STRUCT type *oright;        \
+                    if ((oright = RB_RIGHT(tmp, field)) \
+                        != NULL)            \
+                        RB_COLOR(oright, field) = RB_BLACK;\
+                    RB_COLOR(tmp, field) = RB_RED;  \
+                    RB_ROTATE_LEFT(head, tmp, oright, field);\
+                    tmp = RB_LEFT(parent, field);   \
+                }                   \
+                RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+                RB_COLOR(parent, field) = RB_BLACK; \
+                if (RB_LEFT(tmp, field))        \
+                    RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
+                RB_ROTATE_RIGHT(head, parent, tmp, field);\
+                elm = RB_ROOT(head);            \
+                break;                  \
+            }                       \
+        }                           \
+    }                               \
+    if (elm)                            \
+        RB_COLOR(elm, field) = RB_BLACK;            \
+}                                   \
+                                    \
+attr SYS_TREE_STRUCT type *                          \
+name##_RB_REMOVE(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)           \
+{                                   \
+    SYS_TREE_STRUCT type *child, *parent, *old = elm;            \
+    int color;                          \
+    if (RB_LEFT(elm, field) == NULL)                \
+        child = RB_RIGHT(elm, field);               \
+    else if (RB_RIGHT(elm, field) == NULL)              \
+        child = RB_LEFT(elm, field);                \
+    else {                              \
+        SYS_TREE_STRUCT type *left;                  \
+        elm = RB_RIGHT(elm, field);             \
+        while ((left = RB_LEFT(elm, field)) != NULL)        \
+            elm = left;                 \
+        child = RB_RIGHT(elm, field);               \
+        parent = RB_PARENT(elm, field);             \
+        color = RB_COLOR(elm, field);               \
+        if (child)                      \
+            RB_PARENT(child, field) = parent;       \
+        if (parent) {                       \
+            if (RB_LEFT(parent, field) == elm)      \
+                RB_LEFT(parent, field) = child;     \
+            else                        \
+                RB_RIGHT(parent, field) = child;    \
+            RB_AUGMENT(parent);             \
+        } else                          \
+            RB_ROOT(head) = child;              \
+        if (RB_PARENT(elm, field) == old)           \
+            parent = elm;                   \
+        (elm)->field = (old)->field;                \
+        if (RB_PARENT(old, field)) {                \
+            if (RB_LEFT(RB_PARENT(old, field), field) == old)\
+                RB_LEFT(RB_PARENT(old, field), field) = elm;\
+            else                        \
+                RB_RIGHT(RB_PARENT(old, field), field) = elm;\
+            RB_AUGMENT(RB_PARENT(old, field));      \
+        } else                          \
+            RB_ROOT(head) = elm;                \
+        RB_PARENT(RB_LEFT(old, field), field) = elm;        \
+        if (RB_RIGHT(old, field))               \
+            RB_PARENT(RB_RIGHT(old, field), field) = elm;   \
+        if (parent) {                       \
+            left = parent;                  \
+            do {                        \
+                RB_AUGMENT(left);           \
+            } while ((left = RB_PARENT(left, field)) != NULL); \
+        }                           \
+        goto color;                     \
+    }                               \
+    parent = RB_PARENT(elm, field);                 \
+    color = RB_COLOR(elm, field);                   \
+    if (child)                          \
+        RB_PARENT(child, field) = parent;           \
+    if (parent) {                           \
+        if (RB_LEFT(parent, field) == elm)          \
+            RB_LEFT(parent, field) = child;         \
+        else                            \
+            RB_RIGHT(parent, field) = child;        \
+        RB_AUGMENT(parent);                 \
+    } else                              \
+        RB_ROOT(head) = child;                  \
+color:                                  \
+    if (color == RB_BLACK)                      \
+        name##_RB_REMOVE_COLOR(head, parent, child);        \
+    return (old);                           \
+}                                   \
+                                    \
+/* Inserts a node into the RB tree */                   \
+attr SYS_TREE_STRUCT type *                          \
+name##_RB_INSERT(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)           \
+{                                   \
+    SYS_TREE_STRUCT type *tmp;                       \
+    SYS_TREE_STRUCT type *parent = NULL;                 \
+    int comp = 0;                           \
+    tmp = RB_ROOT(head);                        \
+    while (tmp) {                           \
+        parent = tmp;                       \
+        comp = (cmp)(elm, parent);              \
+        if (comp < 0)                       \
+            tmp = RB_LEFT(tmp, field);          \
+        else if (comp > 0)                  \
+            tmp = RB_RIGHT(tmp, field);         \
+        else                            \
+            return (tmp);                   \
+    }                               \
+    RB_SET(elm, parent, field);                 \
+    if (parent != NULL) {                       \
+        if (comp < 0)                       \
+            RB_LEFT(parent, field) = elm;           \
+        else                            \
+            RB_RIGHT(parent, field) = elm;          \
+        RB_AUGMENT(parent);                 \
+    } else                              \
+        RB_ROOT(head) = elm;                    \
+    name##_RB_INSERT_COLOR(head, elm);              \
+    return (NULL);                          \
+}                                   \
+                                    \
+/* Finds the node with the same key as elm */               \
+attr SYS_TREE_STRUCT type *                          \
+name##_RB_FIND(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)         \
+{                                   \
+    SYS_TREE_STRUCT type *tmp = RB_ROOT(head);               \
+    int comp;                           \
+    while (tmp) {                           \
+        comp = cmp(elm, tmp);                   \
+        if (comp < 0)                       \
+            tmp = RB_LEFT(tmp, field);          \
+        else if (comp > 0)                  \
+            tmp = RB_RIGHT(tmp, field);         \
+        else                            \
+            return (tmp);                   \
+    }                               \
+    return (NULL);                          \
+}                                   \
+                                    \
+/* Finds the first node greater than or equal to the search key */  \
+attr SYS_TREE_STRUCT type *                          \
+name##_RB_NFIND(SYS_TREE_STRUCT name *head, SYS_TREE_STRUCT type *elm)            \
+{                                   \
+    SYS_TREE_STRUCT type *tmp = RB_ROOT(head);               \
+    SYS_TREE_STRUCT type *res = NULL;                    \
+    int comp;                           \
+    while (tmp) {                           \
+        comp = cmp(elm, tmp);                   \
+        if (comp < 0) {                     \
+            res = tmp;                  \
+            tmp = RB_LEFT(tmp, field);          \
+        }                           \
+        else if (comp > 0)                  \
+            tmp = RB_RIGHT(tmp, field);         \
+        else                            \
+            return (tmp);                   \
+    }                               \
+    return (res);                           \
+}                                   \
+                                    \
+/* ARGSUSED */                              \
+attr SYS_TREE_STRUCT type *                          \
+name##_RB_NEXT(SYS_TREE_STRUCT type *elm)                    \
+{                                   \
+    if (RB_RIGHT(elm, field)) {                 \
+        elm = RB_RIGHT(elm, field);             \
+        while (RB_LEFT(elm, field))             \
+            elm = RB_LEFT(elm, field);          \
+    } else {                            \
+        if (RB_PARENT(elm, field) &&                \
+            (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+            elm = RB_PARENT(elm, field);            \
+        else {                          \
+            while (RB_PARENT(elm, field) &&         \
+                (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
+                elm = RB_PARENT(elm, field);        \
+            elm = RB_PARENT(elm, field);            \
+        }                           \
+    }                               \
+    return (elm);                           \
+}                                   \
+                                    \
+/* ARGSUSED */                              \
+attr SYS_TREE_STRUCT type *                          \
+name##_RB_PREV(SYS_TREE_STRUCT type *elm)                    \
+{                                   \
+    if (RB_LEFT(elm, field)) {                  \
+        elm = RB_LEFT(elm, field);              \
+        while (RB_RIGHT(elm, field))                \
+            elm = RB_RIGHT(elm, field);         \
+    } else {                            \
+        if (RB_PARENT(elm, field) &&                \
+            (elm == RB_RIGHT(RB_PARENT(elm, field), field)))    \
+            elm = RB_PARENT(elm, field);            \
+        else {                          \
+            while (RB_PARENT(elm, field) &&         \
+                (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
+                elm = RB_PARENT(elm, field);        \
+            elm = RB_PARENT(elm, field);            \
+        }                           \
+    }                               \
+    return (elm);                           \
+}                                   \
+                                    \
+attr SYS_TREE_STRUCT type *                          \
+name##_RB_MINMAX(SYS_TREE_STRUCT name *head, int val)                \
+{                                   \
+    SYS_TREE_STRUCT type *tmp = RB_ROOT(head);               \
+    SYS_TREE_STRUCT type *parent = NULL;                 \
+    while (tmp) {                           \
+        parent = tmp;                       \
+        if (val < 0)                        \
+            tmp = RB_LEFT(tmp, field);          \
+        else                            \
+            tmp = RB_RIGHT(tmp, field);         \
+    }                               \
+    return (parent);                        \
+}
+
+#define RB_NEGINF   -1
+#define RB_INF  1
+
+#define RB_INSERT(name, x, y)   name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y)   name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y)    name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x)     name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x)     name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head)                   \
+    for ((x) = RB_MIN(name, head);                  \
+         (x) != NULL;                       \
+         (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_FROM(x, name, y)                 \
+    for ((x) = (y);                         \
+        ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL);    \
+         (x) = (y))
+
+#define RB_FOREACH_SAFE(x, name, head, y)               \
+    for ((x) = RB_MIN(name, head);                  \
+        ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL);    \
+         (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head)               \
+    for ((x) = RB_MAX(name, head);                  \
+         (x) != NULL;                       \
+         (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_FROM(x, name, y)             \
+    for ((x) = (y);                         \
+        ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL);    \
+         (x) = (y))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y)           \
+    for ((x) = RB_MAX(name, head);                  \
+        ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL);    \
+         (x) = (y))
+
+#endif  /* _SYS_TREE_H_ */
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f98655f..afc0146 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -417,6 +417,15 @@
     return (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR ? 1 : 0;
 }
 
+static inline int is_cpu_user (CPUState *env)
+{
+#ifdef CONFIG_USER_ONLY
+    return 1;
+#else
+    return (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR;
+#endif  // CONFIG_USER_ONLY
+}
+
 #if defined(CONFIG_USER_ONLY)
 static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 9ac7e25..56d9953 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -10,6 +10,9 @@
 #ifdef CONFIG_TRACE
 #include "trace.h"
 #endif
+#ifdef CONFIG_MEMCHECK
+#include "memcheck/memcheck_api.h"
+#endif  // CONFIG_MEMCHECK
 
 static uint32_t cortexa8_cp15_c0_c1[8] =
 { 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 };
@@ -2668,3 +2671,12 @@
     }
 }
 
+#ifdef CONFIG_MEMCHECK
+void HELPER(on_call)(void* pc, void* ret) {
+    memcheck_on_call((target_ulong)pc, (target_ulong)ret);
+}
+
+void HELPER(on_ret)(void* ret) {
+    memcheck_on_ret((target_ulong)ret);
+}
+#endif  // CONFIG_MEMCHECK
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index abc54d2..a42b3ae 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -466,4 +466,19 @@
 
 DEF_HELPER_2(set_teecr, void, env, i32)
 
+#ifdef CONFIG_MEMCHECK
+/* Hooks to translated BL/BLX. This callback is used to build thread's
+ * calling stack.
+ * Param:
+ *  First pointer contains guest PC where BL/BLX has been found.
+ *  Second pointer contains guest PC where BL/BLX will return.
+ */
+DEF_HELPER_2(on_call, void, ptr, ptr)
+/* Hooks to return from translated BL/BLX. This callback is used to build
+ * thread's calling stack.
+ * Param:
+ *  Pointer contains guest PC where BL/BLX will return.
+ */
+DEF_HELPER_1(on_ret, void, ptr)
+#endif  // CONFIG_MEMCHECK
 #include "def-helper.h"
diff --git a/target-arm/memcheck_arm_helpers.h b/target-arm/memcheck_arm_helpers.h
new file mode 100644
index 0000000..a05668a
--- /dev/null
+++ b/target-arm/memcheck_arm_helpers.h
@@ -0,0 +1,200 @@
+/* Copyright (C) 2007-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/*
+ * Contains implementation of memcheck helper routines used by ARM's translator.
+ */
+
+#ifndef QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H
+#define QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H
+
+/* This file should compile iff qemu is built with memory checking
+ * configuration turned on. */
+#ifndef CONFIG_MEMCHECK
+#error CONFIG_MEMCHECK is not defined.
+#endif  // CONFIG_MEMCHECK
+
+#include "helpers.h"
+#include "memcheck/memcheck_api.h"
+
+/* Array of return addresses detected in gen_intermediate_code_internal. */
+AddrArray   ret_addresses = { 0 };
+
+/* Checks if call stack collection is enabled for the given context.
+ * We collect call stack only for the user mode (both, code and CPU), and on
+ * condition that memory checking, and call collection are enabled. It also
+ * seems that collecting stack for the linker code is excessive, as it doesn't
+ * provide much useful info for the memory checker.
+ * Return:
+ *  boolean: 1 if stack collection is enabled for the given context, or 0 if
+ *  it's not enabled.
+ */
+static inline int
+watch_call_stack(DisasContext *s)
+{
+    if (!memcheck_enabled || !memcheck_watch_call_stack) {
+        return 0;
+    }
+
+#ifndef CONFIG_USER_ONLY
+    if (!s->user) {
+        /* We're not interested in kernel mode CPU stack. */
+        return 0;
+    }
+#endif  // CONFIG_USER_ONLY
+
+    /* We're not interested in kernel code stack (pc >= 0xC0000000).
+     * Android specific: We're also not interested in android linker stack
+     * (0xB0000000 - 0xB00FFFFF) */
+    if (s->pc >= 0xC0000000 || (0xB0000000 <= s->pc && s->pc <= 0xB00FFFFF)) {
+        return 0;
+    }
+    return 1;
+}
+
+/* Checks if given ARM instruction is BL, or BLX.
+ * Return:
+ *  boolean: 1 if ARM instruction is BL/BLX, or 0 if it's not.
+ */
+static inline int
+is_arm_bl_or_blx(uint32_t insn)
+{
+    /* ARM BL  (immediate): xxxx 1011 xxxx xxxx xxxx xxxx xxxx xxxx
+     * ARM BLX (immediate): 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx
+     * ARM BLX (register):  xxxx 0001 0010 xxxx xxxx xxxx 0011 xxxx
+     */
+    if ((insn & 0x0F000000) == 0x0B000000 ||    // ARM BL (imm)
+        (insn & 0xFE000000) == 0xFA000000 ||    // ARM BLX (imm)
+        (insn & 0x0FF000F0) == 0x12000030) {    // ARM BLX (reg)
+        return 1;
+    }
+    return 0;
+}
+
+/* Checks if given THUMB instruction is BL, or BLX.
+ * Param:
+ *  insn - THUMB instruction to check.
+ *  ret_off - If insn is BL, or BLX, upon return ret_off contains
+ *      instruction's byte size. If instruction is not BL, or BLX, content of
+ *      this parameter is undefined on return.
+ * Return:
+ *  boolean: 1 if THUMB instruction is BL/BLX, or 0 if it's not.
+ */
+static inline int
+is_thumb_bl_or_blx(uint16_t insn, target_ulong* ret_off)
+{
+    /* THUMB BLX(register):      0100 0111 1xxx xxxx
+     * THUMB BL(1-stimmediate):  1111 0xxx xxxx xxxx
+     * THUMB BLX(1-stimmediate): 1111 0xxx xxxx xxxx
+     */
+    if ((insn & 0xFF80) == 0x4780) {            // THUMB BLX(reg)
+        *ret_off = 2;
+        return 1;
+    } else if ((insn & 0xF800) == 0xF000) {     // THUMB BL(X)(imm)
+        *ret_off = 4;
+        return 1;
+    }
+    return 0;
+}
+
+/* Registers a return address detected in gen_intermediate_code_internal.
+ * NOTE: If return address has been registered as new in this routine, this will
+ * cause invalidation of all existing TBs that contain translated code for that
+ * address.
+ * Param:
+ *  env - CPU state environment.
+ *  addr - Return address to register.
+ * Return:
+ *  1  - Address has been registered in this routine.
+ *  -1 - Address has been already registered before.
+ *  0  - Insufficient memory.
+ */
+static int
+register_ret_address(CPUState* env, target_ulong addr)
+{
+    int ret;
+    if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) {
+        /* Address belongs to a module that always loads at this fixed address.
+         * So, we can keep this address in the global array. */
+        ret = addrarray_add(&ret_addresses, addr);
+    } else {
+        /* TODO: Figure out how to move "floating" part to the process
+         * descriptor. */
+        ret = addrarray_add(&ret_addresses, addr);
+    }
+    assert(ret != 0);
+
+    if (ret == 1) {
+        /* If this ret address has been added to the array, we need to make sure
+         * that all TBs that contain translated code for that address are
+         * invalidated. This will force retranslation of that code, which will
+         * make sure that our ret callback is set. This is also important part
+         * in keeping consistency between translated code, and intermediate code
+         * generated for guest PC calculation. If we don't invalidate TBs, and
+         * PC calculation code is generated, there will be inconsistency due to
+         * the fact that TB code doesn't contain ret callback, while PC calc
+         * code contains it. This inconsistency will lead to an immanent
+         * segmentation fault.*/
+        TranslationBlock* tb;
+        const target_ulong phys_pc = get_phys_addr_code(env, addr);
+        const target_ulong phys_page1 = phys_pc & TARGET_PAGE_MASK;
+
+        for(tb = tb_phys_hash[tb_phys_hash_func(phys_pc)]; tb != NULL;
+            tb = tb->phys_hash_next) {
+            if (tb->pc == addr && tb->page_addr[0] == phys_page1) {
+                tb_phys_invalidate(tb, -1);
+            }
+        }
+    }
+    return ret;
+}
+
+/* Checks if given address is recognized as a return address.
+ * Return:
+ *  boolean: 1 if if given address is recognized as a return address,
+ *  or 0 if it's not.
+ */
+static inline int
+is_ret_address(target_ulong addr)
+{
+    if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) {
+        return addrarray_check(&ret_addresses, addr);
+    } else {
+        return addrarray_check(&ret_addresses, addr);
+    }
+}
+
+/* Adds "on_call" callback into generated intermediate code. */
+static inline void
+set_on_call(target_ulong pc, target_ulong ret)
+{
+    TCGv_ptr tmp_pc = tcg_const_ptr(pc & ~1);
+    TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1);
+
+    gen_helper_on_call(tmp_pc, tmp_ret);
+
+    tcg_temp_free_ptr(tmp_ret);
+    tcg_temp_free_ptr(tmp_pc);
+}
+
+/* Adds "on_ret" callback into generated intermediate code. */
+static inline void
+set_on_ret(target_ulong ret)
+{
+    TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1);
+
+    gen_helper_on_ret(tmp_ret);
+
+    tcg_temp_free_ptr(tmp_ret);
+}
+
+#endif  // QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H
diff --git a/target-arm/translate.c b/target-arm/translate.c
index b6e1a34..4432c7b 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -65,6 +65,9 @@
 #if !defined(CONFIG_USER_ONLY)
     int user;
 #endif
+#ifdef CONFIG_MEMCHECK
+    int search_pc;
+#endif  // CONFIG_MEMCHECK
 } DisasContext;
 
 #if defined(CONFIG_USER_ONLY)
@@ -77,6 +80,26 @@
 #include "helpers.h"
 #endif /* CONFIG_TRACE */
 
+#ifdef CONFIG_MEMCHECK
+/*
+ * Memchecker addition in this module is intended to inject qemu callback into
+ * translated code for each BL/BLX, as well as BL/BLX returns. These callbacks
+ * are used to build calling stack of the thread in order to provide better
+ * reporting on memory access violations. Although this may seem as something
+ * that may gratly impact the performance, in reality it doesn't. Overhead that
+ * is added by setting up callbacks and by callbacks themselves is neglectable.
+ * On the other hand, maintaining calling stack can indeed add some perf.
+ * overhead (TODO: provide solid numbers here).
+ * One of the things to watch out with regards to injecting callbacks, is
+ * consistency between intermediate code generated for execution, and for guest
+ * PC address calculation. If code doesn't match, a segmentation fault is
+ * guaranteed.
+ */
+
+#include "memcheck/memcheck_proc_management.h"
+#include "memcheck_arm_helpers.h"
+#endif  // CONFIG_MEMCHECK
+
 /* These instructions trap after executing, so defer them until after the
    conditional executions state has been updated.  */
 #define DISAS_WFI 4
@@ -5783,8 +5806,22 @@
     TCGv tmp3;
     TCGv addr;
     TCGv_i64 tmp64;
-
     insn = ldl_code(s->pc);
+
+#ifdef CONFIG_MEMCHECK
+    if (watch_call_stack(s)) {
+        if (is_ret_address(s->pc)) {
+            set_on_ret(s->pc);
+        }
+        if (is_arm_bl_or_blx(insn)) {
+            set_on_call(s->pc, s->pc + 4);
+            if (!s->search_pc) {
+                register_ret_address(env, s->pc + 4);
+            }
+        }
+    }
+#endif  // CONFIG_MEMCHECK
+
 #ifdef CONFIG_TRACE
     if (tracing) {
         trace_add_insn(insn, 0);
@@ -5792,6 +5829,7 @@
         gen_traceInsn();
     }
 #endif
+
     s->pc += 4;
 
     /* M variants do not implement ARM mode.  */
@@ -6985,7 +7023,6 @@
         case 0xb:
             {
                 int32_t offset;
-
                 /* branch (and link) */
                 val = (int32_t)s->pc;
                 if (insn & (1 << 24)) {
@@ -7170,9 +7207,11 @@
         gen_traceTicks(ticks);
     }
 #endif
-    s->pc += 2;
+
     insn |= (uint32_t)insn_hw1 << 16;
 
+    s->pc += 2;
+
     if ((insn & 0xf800e800) != 0xf000e800) {
         ARCH(6T2);
     }
@@ -8149,6 +8188,22 @@
     }
 
     insn = lduw_code(s->pc);
+
+#ifdef CONFIG_MEMCHECK
+    if (watch_call_stack(s)) {
+        target_ulong ret_off;
+        if (is_ret_address(s->pc)) {
+            set_on_ret(s->pc);
+        }
+        if (is_thumb_bl_or_blx(insn, &ret_off)) {
+            set_on_call(s->pc, s->pc + ret_off);
+            if (!s->search_pc) {
+                register_ret_address(env, s->pc + ret_off);
+            }
+        }
+    }
+#endif  // CONFIG_MEMCHECK
+
 #ifdef CONFIG_TRACE
     if (tracing) {
         int  ticks = get_insn_ticks_thumb(insn);
@@ -8834,6 +8889,9 @@
         dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
     }
 #endif
+#ifdef CONFIG_MEMCHECK
+    dc->search_pc = search_pc;
+#endif  // CONFIG_MEMCHECK
     cpu_F0s = tcg_temp_new_i32();
     cpu_F1s = tcg_temp_new_i32();
     cpu_F0d = tcg_temp_new_i64();
@@ -8892,7 +8950,15 @@
                 }
             }
         }
+
+#ifdef CONFIG_MEMCHECK
+        /* When memchecker is enabled, we need to keep a match between
+         * translated PC and guest PCs, so memchecker can quickly covert
+         * one to another. Note that we do that only for user mode. */
+        if (search_pc || (memcheck_enabled && dc->user)) {
+#else   // CONFIG_MEMCHECK
         if (search_pc) {
+#endif  // CONFIG_MEMCHECK
             j = gen_opc_ptr - gen_opc_buf;
             if (lj < j) {
                 lj++;
@@ -9039,6 +9105,14 @@
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
     } else {
+#ifdef CONFIG_MEMCHECK
+        if (memcheck_enabled && dc->user) {
+            j = gen_opc_ptr - gen_opc_buf;
+            lj++;
+            while (lj <= j)
+                gen_opc_instr_start[lj++] = 0;
+        }
+#endif  // CONFIG_MEMCHECK
         tb->size = dc->pc - pc_start;
         tb->icount = num_insns;
     }
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 5d18842..c63168b 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -57,7 +57,7 @@
 #include "tcg-op.h"
 #include "elf.h"
 
-static void patch_reloc(uint8_t *code_ptr, int type, 
+static void patch_reloc(uint8_t *code_ptr, int type,
                         tcg_target_long value, tcg_target_long addend);
 
 static TCGOpDef tcg_op_defs[] = {
@@ -75,6 +75,16 @@
 uint16_t *gen_opc_ptr;
 TCGArg *gen_opparam_ptr;
 
+#ifdef CONFIG_MEMCHECK
+/*
+ * Memchecker addition in this module is intended to build a map that matches
+ * translated PC to a guest PC. Map is built in tcg_gen_code_common routine,
+ * and is saved into temporary gen_opc_tpc2gpc_ptr array, that later will be
+ * copied into the TranslationBlock that represents the translated code.
+ */
+#include "memcheck/memcheck_api.h"
+#endif  // CONFIG_MEMCHECK
+
 static inline void tcg_out8(TCGContext *s, uint8_t v)
 {
     *s->code_ptr++ = v;
@@ -94,7 +104,7 @@
 
 /* label relocation processing */
 
-void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, 
+void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
                    int label_index, long addend)
 {
     TCGLabel *l;
@@ -103,7 +113,7 @@
     l = &s->labels[label_index];
     if (l->has_value) {
         /* FIXME: This may break relocations on RISC targets that
-           modify instruction fields in place.  The caller may not have 
+           modify instruction fields in place.  The caller may not have
            written the initial value.  */
         patch_reloc(code_ptr, type, l->u.value, addend);
     } else {
@@ -117,7 +127,7 @@
     }
 }
 
-static void tcg_out_label(TCGContext *s, int label_index, 
+static void tcg_out_label(TCGContext *s, int label_index,
                           tcg_target_long value)
 {
     TCGLabel *l;
@@ -157,7 +167,7 @@
 {
     TCGPool *p;
     int pool_size;
-    
+
     if (size > TCG_POOL_CHUNK_SIZE) {
         /* big malloc: insert a new pool (XXX: could optimize) */
         p = qemu_malloc(sizeof(TCGPool) + size);
@@ -180,7 +190,7 @@
                 p = qemu_malloc(sizeof(TCGPool) + pool_size);
                 p->size = pool_size;
                 p->next = NULL;
-                if (s->pool_current) 
+                if (s->pool_current)
                     s->pool_current->next = p;
                 else
                     s->pool_first = p;
@@ -211,7 +221,7 @@
     memset(s, 0, sizeof(*s));
     s->temps = s->static_temps;
     s->nb_globals = 0;
-    
+
     /* Count total number of arguments and allocate the corresponding
        space */
     total_args = 0;
@@ -232,14 +242,14 @@
         sorted_args += n;
         args_ct += n;
     }
-    
+
     tcg_target_init(s);
 
     /* init global prologue and epilogue */
     s->code_buf = code_gen_prologue;
     s->code_ptr = s->code_buf;
     tcg_target_qemu_prologue(s);
-    flush_icache_range((unsigned long)s->code_buf, 
+    flush_icache_range((unsigned long)s->code_buf,
                        (unsigned long)s->code_ptr);
 }
 
@@ -697,7 +707,7 @@
     if (idx < s->nb_globals) {
         pstrcpy(buf, buf_size, ts->name);
     } else {
-        if (ts->temp_local) 
+        if (ts->temp_local)
             snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
         else
             snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
@@ -735,7 +745,7 @@
     tcg_target_ulong v;
 
     if (unlikely(!s->helpers_sorted)) {
-        qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), 
+        qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
               helper_cmp);
         s->helpers_sorted = 1;
     }
@@ -794,7 +804,7 @@
 #else
             pc = args[0];
 #endif
-            if (!first_insn) 
+            if (!first_insn)
                 fprintf(outfile, "\n");
             fprintf(outfile, " ---- 0x%" PRIx64, pc);
             first_insn = 0;
@@ -834,7 +844,7 @@
                             tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
                 }
             }
-        } else if (c == INDEX_op_movi_i32 
+        } else if (c == INDEX_op_movi_i32
 #if TCG_TARGET_REG_BITS == 64
                    || c == INDEX_op_movi_i64
 #endif
@@ -845,7 +855,7 @@
             nb_oargs = def->nb_oargs;
             nb_iargs = def->nb_iargs;
             nb_cargs = def->nb_cargs;
-            fprintf(outfile, " %s %s,$", def->name, 
+            fprintf(outfile, " %s %s,$", def->name,
                     tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
             val = args[1];
             th = tcg_find_helper(s, val);
@@ -869,7 +879,7 @@
                 nb_iargs = def->nb_iargs;
                 nb_cargs = def->nb_cargs;
             }
-            
+
             k = 0;
             for(i = 0; i < nb_oargs; i++) {
                 if (k != 0)
@@ -1026,7 +1036,7 @@
 #ifdef USE_LIVENESS_ANALYSIS
 
 /* set a nop for an operation using 'nb_args' */
-static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, 
+static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
                                TCGArg *args, int nb_args)
 {
     if (nb_args == 0) {
@@ -1090,7 +1100,7 @@
 
     /* XXX: make it really dynamic */
     s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t));
-    
+
     dead_temps = tcg_malloc(s->nb_temps);
     memset(dead_temps, 1, s->nb_temps);
 
@@ -1119,7 +1129,7 @@
                         if (!dead_temps[arg])
                             goto do_not_remove_call;
                     }
-                    tcg_set_nop(s, gen_opc_buf + op_index, 
+                    tcg_set_nop(s, gen_opc_buf + op_index,
                                 args - 1, nb_args);
                 } else {
                 do_not_remove_call:
@@ -1129,7 +1139,7 @@
                         arg = args[i];
                         dead_temps[arg] = 1;
                     }
-                    
+
                     if (!(call_flags & TCG_CALL_CONST)) {
                         /* globals are live (they may be used by the call) */
                         memset(dead_temps, 0, s->nb_globals);
@@ -1269,8 +1279,8 @@
 
     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
         if (s->reg_to_temp[i] >= 0) {
-            printf("%s: %s\n", 
-                   tcg_target_reg_names[i], 
+            printf("%s: %s\n",
+                   tcg_target_reg_names[i],
                    tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
         }
     }
@@ -1288,7 +1298,7 @@
             ts = &s->temps[k];
             if (ts->val_type != TEMP_VAL_REG ||
                 ts->reg != reg) {
-                printf("Inconsistency for register %s:\n", 
+                printf("Inconsistency for register %s:\n",
                        tcg_target_reg_names[reg]);
                 goto fail;
             }
@@ -1299,7 +1309,7 @@
         if (ts->val_type == TEMP_VAL_REG &&
             !ts->fixed_reg &&
             s->reg_to_temp[ts->reg] != k) {
-                printf("Inconsistency for temp %s:\n", 
+                printf("Inconsistency for temp %s:\n",
                        tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
         fail:
                 printf("reg state:\n");
@@ -1334,7 +1344,7 @@
         ts = &s->temps[temp];
         assert(ts->val_type == TEMP_VAL_REG);
         if (!ts->mem_coherent) {
-            if (!ts->mem_allocated) 
+            if (!ts->mem_allocated)
                 temp_allocate_frame(s, temp);
             tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
         }
@@ -1387,9 +1397,9 @@
             ts->val_type = TEMP_VAL_MEM;
             break;
         case TEMP_VAL_CONST:
-            reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
+            reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
                                 allocated_regs);
-            if (!ts->mem_allocated) 
+            if (!ts->mem_allocated)
                 temp_allocate_frame(s, temp);
             tcg_out_movi(s, ts->type, reg, ts->val);
             tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
@@ -1519,7 +1529,7 @@
     ots->mem_coherent = 0;
 }
 
-static void tcg_reg_alloc_op(TCGContext *s, 
+static void tcg_reg_alloc_op(TCGContext *s,
                              const TCGOpDef *def, int opc,
                              const TCGArg *args,
                              unsigned int dead_iargs)
@@ -1536,11 +1546,11 @@
     nb_iargs = def->nb_iargs;
 
     /* copy constants */
-    memcpy(new_args + nb_oargs + nb_iargs, 
-           args + nb_oargs + nb_iargs, 
+    memcpy(new_args + nb_oargs + nb_iargs,
+           args + nb_oargs + nb_iargs,
            sizeof(TCGArg) * def->nb_cargs);
 
-    /* satisfy input constraints */ 
+    /* satisfy input constraints */
     tcg_regset_set(allocated_regs, s->reserved_regs);
     for(k = 0; k < nb_iargs; k++) {
         i = def->sorted_args[nb_oargs + k];
@@ -1581,7 +1591,7 @@
                 /* if the input is aliased to an output and if it is
                    not dead after the instruction, we must allocate
                    a new register and move it */
-                if (!IS_DEAD_IARG(i - nb_oargs)) 
+                if (!IS_DEAD_IARG(i - nb_oargs))
                     goto allocate_in_reg;
             }
         }
@@ -1590,7 +1600,7 @@
             /* nothing to do : the constraint is satisfied */
         } else {
         allocate_in_reg:
-            /* allocate a new register matching the constraint 
+            /* allocate a new register matching the constraint
                and move the temporary register into it */
             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
             tcg_out_mov(s, reg, ts->reg);
@@ -1600,7 +1610,7 @@
         tcg_regset_set_reg(allocated_regs, reg);
     iarg_end: ;
     }
-    
+
     if (def->flags & TCG_OPF_BB_END) {
         tcg_reg_alloc_bb_end(s, allocated_regs);
     } else {
@@ -1616,9 +1626,9 @@
                 }
             }
         }
-        
+
         if (def->flags & TCG_OPF_CALL_CLOBBER) {
-            /* XXX: permit generic clobber register list ? */ 
+            /* XXX: permit generic clobber register list ? */
             for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
                     tcg_reg_free(s, reg);
@@ -1626,12 +1636,12 @@
             }
             /* XXX: for load/store we could do that only for the slow path
                (i.e. when a memory callback is called) */
-            
+
             /* store globals and free associated registers (we assume the insn
                can modify any global. */
             save_globals(s, allocated_regs);
         }
-        
+
         /* satisfy the output constraints */
         tcg_regset_set(allocated_regs, s->reserved_regs);
         for(k = 0; k < nb_oargs; k++) {
@@ -1659,7 +1669,7 @@
                 ts->reg = reg;
                 /* temp value is modified, so the value kept in memory is
                    potentially not the same */
-                ts->mem_coherent = 0; 
+                ts->mem_coherent = 0;
                 s->reg_to_temp[reg] = arg;
             }
         oarg_end:
@@ -1669,7 +1679,7 @@
 
     /* emit instruction */
     tcg_out_op(s, opc, new_args, const_args);
-    
+
     /* move the outputs in the correct register if needed */
     for(i = 0; i < nb_oargs; i++) {
         ts = &s->temps[args[i]];
@@ -1713,7 +1723,7 @@
     /* assign stack slots first */
     /* XXX: preallocate call stack */
     call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
-    call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 
+    call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
         ~(TCG_TARGET_STACK_ALIGN - 1);
     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
     if (allocate_args) {
@@ -1731,13 +1741,13 @@
             if (ts->val_type == TEMP_VAL_REG) {
                 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
             } else if (ts->val_type == TEMP_VAL_MEM) {
-                reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
+                reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
                                     s->reserved_regs);
                 /* XXX: not correct if reading values from the stack */
                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
             } else if (ts->val_type == TEMP_VAL_CONST) {
-                reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
+                reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
                                     s->reserved_regs);
                 /* XXX: sign extend may be needed on some targets */
                 tcg_out_movi(s, ts->type, reg, ts->val);
@@ -1750,7 +1760,7 @@
         stack_offset += sizeof(tcg_target_long);
 #endif
     }
-    
+
     /* assign input registers */
     tcg_regset_set(allocated_regs, s->reserved_regs);
     for(i = 0; i < nb_regs; i++) {
@@ -1774,7 +1784,7 @@
             tcg_regset_set_reg(allocated_regs, reg);
         }
     }
-    
+
     /* assign function address */
     func_arg = args[nb_oargs + nb_iargs - 1];
     arg_ct = &def->args_ct[0];
@@ -1807,8 +1817,8 @@
     } else {
         tcg_abort();
     }
-        
-    
+
+
     /* mark dead temporaries and free the associated registers */
     for(i = 0; i < nb_iargs; i++) {
         arg = args[nb_oargs + i];
@@ -1821,14 +1831,14 @@
             }
         }
     }
-    
+
     /* clobber call registers */
     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
             tcg_reg_free(s, reg);
         }
     }
-    
+
     /* store globals and free associated registers (we assume the call
        can modify any global. */
     if (!(flags & TCG_CALL_CONST)) {
@@ -1836,7 +1846,7 @@
     }
 
     tcg_out_op(s, opc, &func_arg, &const_func_arg);
-    
+
     if (allocate_args) {
         tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
     }
@@ -1856,11 +1866,11 @@
                 s->reg_to_temp[ts->reg] = -1;
             ts->val_type = TEMP_VAL_REG;
             ts->reg = reg;
-            ts->mem_coherent = 0; 
+            ts->mem_coherent = 0;
             s->reg_to_temp[reg] = arg;
         }
     }
-    
+
     return nb_iargs + nb_oargs + def->nb_cargs + 1;
 }
 
@@ -1888,6 +1898,9 @@
     const TCGOpDef *def;
     unsigned int dead_iargs;
     const TCGArg *args;
+#ifdef CONFIG_MEMCHECK
+    unsigned int tpc2gpc_index = 0;
+#endif  // CONFIG_MEMCHECK
 
 #ifdef DEBUG_DISAS
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
@@ -1921,7 +1934,27 @@
     args = gen_opparam_buf;
     op_index = 0;
 
+#ifdef CONFIG_MEMCHECK
+    gen_opc_tpc2gpc_pairs = 0;
+#endif  // CONFIG_MEMCHECK
+
     for(;;) {
+#ifdef CONFIG_MEMCHECK
+        /* On condition that memcheck is enabled, and operation index reached
+         * new operation in the guest code, save (pc_tb, pc_guest) pair into
+         * gen_opc_tpc2gpc array. Note that we do that only on condition that
+         * search_pc is < 0. This way we make sure that this is "normal"
+         * translation, called from tcg_gen_code, and not from
+         * tcg_gen_code_search_pc. */
+        if (memcheck_enabled && search_pc < 0 &&
+            gen_opc_instr_start[op_index]) {
+            gen_opc_tpc2gpc_ptr[tpc2gpc_index] = (target_ulong)s->code_ptr;
+            tpc2gpc_index++;
+            gen_opc_tpc2gpc_ptr[tpc2gpc_index] = gen_opc_pc[op_index];
+            tpc2gpc_index++;
+            gen_opc_tpc2gpc_pairs++;
+        }
+#endif  // CONFIG_MEMCHECK
         opc = gen_opc_buf[op_index];
 #ifdef CONFIG_PROFILER
         tcg_table_op_count[opc]++;
@@ -2027,7 +2060,7 @@
     tcg_gen_code_common(s, gen_code_buf, -1);
 
     /* flush instruction cache */
-    flush_icache_range((unsigned long)gen_code_buf, 
+    flush_icache_range((unsigned long)gen_code_buf,
                        (unsigned long)s->code_ptr);
     return s->code_ptr -  gen_code_buf;
 }
@@ -2051,33 +2084,33 @@
     tot = s->interm_time + s->code_time;
     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
                 tot, tot / 2.4e9);
-    cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 
-                s->tb_count, 
+    cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
+                s->tb_count,
                 s->tb_count1 - s->tb_count,
                 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
-    cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n", 
+    cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n",
                 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
-                s->tb_count ? 
+                s->tb_count ?
                 (double)s->del_op_count / s->tb_count : 0);
     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
-                s->tb_count ? 
+                s->tb_count ?
                 (double)s->temp_count / s->tb_count : 0,
                 s->temp_count_max);
-    
-    cpu_fprintf(f, "cycles/op           %0.1f\n", 
+
+    cpu_fprintf(f, "cycles/op           %0.1f\n",
                 s->op_count ? (double)tot / s->op_count : 0);
-    cpu_fprintf(f, "cycles/in byte      %0.1f\n", 
+    cpu_fprintf(f, "cycles/in byte      %0.1f\n",
                 s->code_in_len ? (double)tot / s->code_in_len : 0);
-    cpu_fprintf(f, "cycles/out byte     %0.1f\n", 
+    cpu_fprintf(f, "cycles/out byte     %0.1f\n",
                 s->code_out_len ? (double)tot / s->code_out_len : 0);
     if (tot == 0)
         tot = 1;
-    cpu_fprintf(f, "  gen_interm time   %0.1f%%\n", 
+    cpu_fprintf(f, "  gen_interm time   %0.1f%%\n",
                 (double)s->interm_time / tot * 100.0);
-    cpu_fprintf(f, "  gen_code time     %0.1f%%\n", 
+    cpu_fprintf(f, "  gen_code time     %0.1f%%\n",
                 (double)s->code_time / tot * 100.0);
-    cpu_fprintf(f, "liveness/code time  %0.1f%%\n", 
+    cpu_fprintf(f, "liveness/code time  %0.1f%%\n",
                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
                 s->restore_count);
diff --git a/translate-all.c b/translate-all.c
index 4bdf2c9..8964758 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -49,6 +49,22 @@
 uint32_t gen_opc_hflags[OPC_BUF_SIZE];
 #endif
 
+#ifdef CONFIG_MEMCHECK
+/*
+ * Memchecker code in this module copies TB PC <-> Guest PC map to the TB
+ * descriptor after guest code has been translated in cpu_gen_init routine.
+ */
+#include "memcheck/memcheck_api.h"
+
+/* Array of (tb_pc, guest_pc) pairs, big enough for all translations. This
+ * array is used to obtain guest PC address from a translated PC address.
+ * tcg_gen_code_common will fill it up when memchecker is enabled. */
+static target_ulong gen_opc_tpc2gpc[OPC_BUF_SIZE * 2];
+target_ulong* gen_opc_tpc2gpc_ptr = &gen_opc_tpc2gpc[0];
+/* Number of (tb_pc, guest_pc) pairs stored in gen_opc_tpc2gpc array. */
+unsigned int gen_opc_tpc2gpc_pairs;
+#endif  // CONFIG_MEMCHECK
+
 /* XXX: suppress that */
 unsigned long code_gen_max_block_size(void)
 {
@@ -67,7 +83,7 @@
 
 void cpu_gen_init(void)
 {
-    tcg_context_init(&tcg_ctx); 
+    tcg_context_init(&tcg_ctx);
     tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf),
                   CPU_TEMP_BUF_NLONGS * sizeof(long));
 }
@@ -126,6 +142,19 @@
     s->code_out_len += gen_code_size;
 #endif
 
+#ifdef CONFIG_MEMCHECK
+    /* Save translated PC -> guest PC map into TB. */
+    if (memcheck_enabled && gen_opc_tpc2gpc_pairs && is_cpu_user(env)) {
+        tb->tpc2gpc =
+                qemu_malloc(gen_opc_tpc2gpc_pairs * 2 * sizeof(target_ulong));
+        if (tb->tpc2gpc != NULL) {
+            memcpy(tb->tpc2gpc, gen_opc_tpc2gpc_ptr,
+                   gen_opc_tpc2gpc_pairs * 2 * sizeof(target_ulong));
+            tb->tpc2gpc_pairs = gen_opc_tpc2gpc_pairs;
+        }
+    }
+#endif  // CONFIG_MEMCHECK
+
 #ifdef DEBUG_DISAS
     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
         qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr);