diff mbox series

EfficiencySanitizer implementation.

Message ID 20181006201856eucas1p19811bf53e6a8bee0c9110c9d8e650f5a~bHmmZwGNW0166601666eucas1p1l@eucas1p1.samsung.com
State New
Headers show
Series EfficiencySanitizer implementation. | expand

Commit Message

Denis Khalikov Oct. 6, 2018, 8:17 p.m. UTC
Hello everyone,
this is a patch which implements EfficiencySanitizer aka ESan
into GCC. The EfficiencySanitizer tool is available in the llvm.
So, the main idea was to port the runtime library into GCC and
implement GCC compiler pass on GIMPLE IR with the same semantics
as llvm does on llvm IR.
The main difference that this patch also enables ESan under 32 bit
ARM CPU with some changes to runtime library.
Link to the RFC on the llvm-dev:
https://lists.llvm.org/pipermail/llvm-dev/2016-April/098355.html

I know this patch is not acceptable into GCC trunk, so, I send
this patch in the weekend to don't bother anyone, but may be
someone will be interested. Also, I'll be very appreciated for
any feedback.
GCC should be build with --enable-checking=release.

This patch includes:

1. GCC pass for the CacheFragmentation tool on the GIMPLE IR.
Special compiler pass instruments every memory access into the struct
field with gimple internal call ESAN_RECORD_ACCESS and expands
it in sanopt pass.
Creates fields counter array, each cell of that array
counts memory accesses to the special field. Creates array of
the structs, where the every instance of the struct represents meta
info of the real struct.

a. Source example:

struct node {
   int a;
   int b;
   int c;
};

int main () {
   struct node c;
   for (int i = 0; i < 100; ++i) {
     c.a = i + 1;
     c.b = i + 1;
     c.c = i + 1;
   }
   return 0;
}

b. Instrumented GIMPLE:
   <bb 4> :
   _1 = i_4 + 1;
   .ESAN_RECORD_ACCESS (0B, 0);
   c.a = _1;
   _2 = i_4 + 1;
   .ESAN_RECORD_ACCESS (0B, 1);
   c.b = _2;
   _3 = i_4 + 1;
   .ESAN_RECORD_ACCESS (0B, 2);
   c.c = _3;
   i_11 = i_4 + 1;

c. Assembler:

# The fields counter array.
# Every cell 8 bytes long and represents the amount
# of the field accesses.

     .weak    struct.node$1$1$1
     .bss
     .align 8
     .type    struct.node$1$1$1, @object
     .size    struct.node$1$1$1, 24
struct.node$1$1$1:
     .zero    24

# Increment the specific cell by the field index.
# Actually __esan_increment, could be inlined.
    movl    $struct.node$1$1$1, %eax
    movq    %rax, %rdi
    call    __esan_increment
    movl    %ebx, -32(%rbp)
    movl    -20(%rbp), %eax
    leal    1(%rax), %ebx
    movl    $struct.node$1$1$1+8, %eax
    movq    %rax, %rdi
    call    __esan_increment
    movl    %ebx, -28(%rbp)
    movl    -20(%rbp), %eax
    leal    1(%rax), %ebx
    movl    $struct.node$1$1$1+16, %eax
    movq    %rax, %rdi
    call    __esan_increment

# The array of the structs with
# meta info like size of the special struct,
# number of the fields and pointer to the
# fields counter array.

.Lesan_info0:
     .quad    .LC0
     .long    12
     .long    3
     .quad    0
     .quad    0
     .quad    0
     .quad    struct.node$1$1$1
     .quad    0

__esan_init is inserted to the static constructor.
__esan_exit is inserted to the static destructor.

d. Output:

==28719==  struct node
==28719==   size = 12, count = 300, ratio = 2
==28719==   # 0: count = 100
==28719==   # 1: count = 100
==28719==   # 2: count = 100
==28719==EfficiencySanitizer: total struct field access count = 300

2. GCC pass for the WorkingSet tool.
Special compiler pass instruments every memory access in the program.
Memory accesses are simply prepended with a function call like
__esan_aligned_load(addr), __esan_aligned_store(addr).
Also, __esan_init is inserted to the static constructor and
__esan_exit is inserted to the static destructor.

a. Assembler:

   movq    -32(%rbp), %rax
   movq    %rax, %rdi
   call    __esan_aligned_store1

The runtime library simply manages shadow memory and computes statistic
of the program efficiency. The tool maps one cache line (64 bytes) of
the program to the one byte of the shadow memory.
The runtime library measures the data working set size of an application 
at each snapshot during execution.

b. Output:

==28742== EfficiencySanitizer: the total working set size: 32 MB (524291 
cache lines)

HOW TO USE:

WorkingSet tool.
To measure the working set size, you should build your binary or
shared library with compile time flag
-fsanitize=efficiency-working-set and set runtime options 
ESAN_OPTIONS=process_range_access=1:record_snapshots=1

CacheFragmentation tool.
To enable CacheFragmentation tool you should compile your binary or
shared library with compile time flag -fsanitize=efficiency-cache-frag
and set runtime options ESAN_OPTIONS=build_mode=0:verbosity=1

Comments

Richard Biener Oct. 7, 2018, 8:03 a.m. UTC | #1
On October 6, 2018 10:17:48 PM GMT+02:00, Denis Khalikov <d.khalikov@partner.samsung.com> wrote:
>Hello everyone,
>this is a patch which implements EfficiencySanitizer aka ESan
>into GCC. The EfficiencySanitizer tool is available in the llvm.
>So, the main idea was to port the runtime library into GCC and
>implement GCC compiler pass on GIMPLE IR with the same semantics
>as llvm does on llvm IR.
>The main difference that this patch also enables ESan under 32 bit
>ARM CPU with some changes to runtime library.
>Link to the RFC on the llvm-dev:
>https://lists.llvm.org/pipermail/llvm-dev/2016-April/098355.html
>
>I know this patch is not acceptable into GCC trunk, so, I send
>this patch in the weekend to don't bother anyone, but may be
>someone will be interested. Also, I'll be very appreciated for
>any feedback.
>GCC should be build with --enable-checking=release.
>
>This patch includes:
>
>1. GCC pass for the CacheFragmentation tool on the GIMPLE IR.
>Special compiler pass instruments every memory access into the struct
>field with gimple internal call ESAN_RECORD_ACCESS and expands
>it in sanopt pass.
>Creates fields counter array, each cell of that array
>counts memory accesses to the special field. Creates array of
>the structs, where the every instance of the struct represents meta
>info of the real struct.
>
>a. Source example:
>
>struct node {
>   int a;
>   int b;
>   int c;
>};
>
>int main () {
>   struct node c;
>   for (int i = 0; i < 100; ++i) {
>     c.a = i + 1;
>     c.b = i + 1;
>     c.c = i + 1;
>   }
>   return 0;
>}
>
>b. Instrumented GIMPLE:
>   <bb 4> :
>   _1 = i_4 + 1;
>   .ESAN_RECORD_ACCESS (0B, 0);
>   c.a = _1;
>   _2 = i_4 + 1;
>   .ESAN_RECORD_ACCESS (0B, 1);
>   c.b = _2;
>   _3 = i_4 + 1;
>   .ESAN_RECORD_ACCESS (0B, 2);
>   c.c = _3;
>   i_11 = i_4 + 1;
>
>c. Assembler:
>
># The fields counter array.
># Every cell 8 bytes long and represents the amount
># of the field accesses.
>
>     .weak    struct.node$1$1$1
>     .bss
>     .align 8
>     .type    struct.node$1$1$1, @object
>     .size    struct.node$1$1$1, 24
>struct.node$1$1$1:
>     .zero    24
>
># Increment the specific cell by the field index.
># Actually __esan_increment, could be inlined.
>    movl    $struct.node$1$1$1, %eax
>    movq    %rax, %rdi
>    call    __esan_increment
>    movl    %ebx, -32(%rbp)
>    movl    -20(%rbp), %eax
>    leal    1(%rax), %ebx
>    movl    $struct.node$1$1$1+8, %eax
>    movq    %rax, %rdi
>    call    __esan_increment
>    movl    %ebx, -28(%rbp)
>    movl    -20(%rbp), %eax
>    leal    1(%rax), %ebx
>    movl    $struct.node$1$1$1+16, %eax
>    movq    %rax, %rdi
>    call    __esan_increment
>
># The array of the structs with
># meta info like size of the special struct,
># number of the fields and pointer to the
># fields counter array.
>
>.Lesan_info0:
>     .quad    .LC0
>     .long    12
>     .long    3
>     .quad    0
>     .quad    0
>     .quad    0
>     .quad    struct.node$1$1$1
>     .quad    0
>
>__esan_init is inserted to the static constructor.
>__esan_exit is inserted to the static destructor.
>
>d. Output:
>
>==28719==  struct node
>==28719==   size = 12, count = 300, ratio = 2
>==28719==   # 0: count = 100
>==28719==   # 1: count = 100
>==28719==   # 2: count = 100
>==28719==EfficiencySanitizer: total struct field access count = 300
>
>2. GCC pass for the WorkingSet tool.
>Special compiler pass instruments every memory access in the program.
>Memory accesses are simply prepended with a function call like
>__esan_aligned_load(addr), __esan_aligned_store(addr).
>Also, __esan_init is inserted to the static constructor and
>__esan_exit is inserted to the static destructor.
>
>a. Assembler:
>
>   movq    -32(%rbp), %rax
>   movq    %rax, %rdi
>   call    __esan_aligned_store1
>
>The runtime library simply manages shadow memory and computes statistic
>of the program efficiency. The tool maps one cache line (64 bytes) of
>the program to the one byte of the shadow memory.
>The runtime library measures the data working set size of an
>application 
>at each snapshot during execution.
>
>b. Output:
>
>==28742== EfficiencySanitizer: the total working set size: 32 MB
>(524291 
>cache lines)
>
>HOW TO USE:
>
>WorkingSet tool.
>To measure the working set size, you should build your binary or
>shared library with compile time flag
>-fsanitize=efficiency-working-set and set runtime options 
>ESAN_OPTIONS=process_range_access=1:record_snapshots=1
>
>CacheFragmentation tool.
>To enable CacheFragmentation tool you should compile your binary or
>shared library with compile time flag -fsanitize=efficiency-cache-frag
>and set runtime options ESAN_OPTIONS=build_mode=0:verbosity=1

I wonder how this is more efficient or precise than tools like valgrind with a suitable CPU model? (with valgrind possibly using a JIT) 

Richard.
Denis Khalikov Oct. 8, 2018, 9:36 a.m. UTC | #2
I assume that the compiler based instrumentation,
should be more efficient than binary instrumentation.
But, I was just interested in the process of implementation
for that tool.
Sorry for the noise.

On 10/07/2018 11:03 AM, Richard Biener wrote:
> On October 6, 2018 10:17:48 PM GMT+02:00, Denis Khalikov <d.khalikov@partner.samsung.com> wrote:
>> Hello everyone,
>> this is a patch which implements EfficiencySanitizer aka ESan
>> into GCC. The EfficiencySanitizer tool is available in the llvm.
>> So, the main idea was to port the runtime library into GCC and
>> implement GCC compiler pass on GIMPLE IR with the same semantics
>> as llvm does on llvm IR.
>> The main difference that this patch also enables ESan under 32 bit
>> ARM CPU with some changes to runtime library.
>> Link to the RFC on the llvm-dev:
>> https://lists.llvm.org/pipermail/llvm-dev/2016-April/098355.html
>>
>> I know this patch is not acceptable into GCC trunk, so, I send
>> this patch in the weekend to don't bother anyone, but may be
>> someone will be interested. Also, I'll be very appreciated for
>> any feedback.
>> GCC should be build with --enable-checking=release.
>>
>> This patch includes:
>>
>> 1. GCC pass for the CacheFragmentation tool on the GIMPLE IR.
>> Special compiler pass instruments every memory access into the struct
>> field with gimple internal call ESAN_RECORD_ACCESS and expands
>> it in sanopt pass.
>> Creates fields counter array, each cell of that array
>> counts memory accesses to the special field. Creates array of
>> the structs, where the every instance of the struct represents meta
>> info of the real struct.
>>
>> a. Source example:
>>
>> struct node {
>>   int a;
>>   int b;
>>   int c;
>> };
>>
>> int main () {
>>   struct node c;
>>   for (int i = 0; i < 100; ++i) {
>>     c.a = i + 1;
>>     c.b = i + 1;
>>     c.c = i + 1;
>>   }
>>   return 0;
>> }
>>
>> b. Instrumented GIMPLE:
>>   <bb 4> :
>>   _1 = i_4 + 1;
>>   .ESAN_RECORD_ACCESS (0B, 0);
>>   c.a = _1;
>>   _2 = i_4 + 1;
>>   .ESAN_RECORD_ACCESS (0B, 1);
>>   c.b = _2;
>>   _3 = i_4 + 1;
>>   .ESAN_RECORD_ACCESS (0B, 2);
>>   c.c = _3;
>>   i_11 = i_4 + 1;
>>
>> c. Assembler:
>>
>> # The fields counter array.
>> # Every cell 8 bytes long and represents the amount
>> # of the field accesses.
>>
>>     .weak    struct.node$1$1$1
>>     .bss
>>     .align 8
>>     .type    struct.node$1$1$1, @object
>>     .size    struct.node$1$1$1, 24
>> struct.node$1$1$1:
>>     .zero    24
>>
>> # Increment the specific cell by the field index.
>> # Actually __esan_increment, could be inlined.
>>    movl    $struct.node$1$1$1, %eax
>>    movq    %rax, %rdi
>>    call    __esan_increment
>>    movl    %ebx, -32(%rbp)
>>    movl    -20(%rbp), %eax
>>    leal    1(%rax), %ebx
>>    movl    $struct.node$1$1$1+8, %eax
>>    movq    %rax, %rdi
>>    call    __esan_increment
>>    movl    %ebx, -28(%rbp)
>>    movl    -20(%rbp), %eax
>>    leal    1(%rax), %ebx
>>    movl    $struct.node$1$1$1+16, %eax
>>    movq    %rax, %rdi
>>    call    __esan_increment
>>
>> # The array of the structs with
>> # meta info like size of the special struct,
>> # number of the fields and pointer to the
>> # fields counter array.
>>
>> .Lesan_info0:
>>     .quad    .LC0
>>     .long    12
>>     .long    3
>>     .quad    0
>>     .quad    0
>>     .quad    0
>>     .quad    struct.node$1$1$1
>>     .quad    0
>>
>> __esan_init is inserted to the static constructor.
>> __esan_exit is inserted to the static destructor.
>>
>> d. Output:
>>
>> ==28719==  struct node
>> ==28719==   size = 12, count = 300, ratio = 2
>> ==28719==   # 0: count = 100
>> ==28719==   # 1: count = 100
>> ==28719==   # 2: count = 100
>> ==28719==EfficiencySanitizer: total struct field access count = 300
>>
>> 2. GCC pass for the WorkingSet tool.
>> Special compiler pass instruments every memory access in the program.
>> Memory accesses are simply prepended with a function call like
>> __esan_aligned_load(addr), __esan_aligned_store(addr).
>> Also, __esan_init is inserted to the static constructor and
>> __esan_exit is inserted to the static destructor.
>>
>> a. Assembler:
>>
>>   movq    -32(%rbp), %rax
>>   movq    %rax, %rdi
>>   call    __esan_aligned_store1
>>
>> The runtime library simply manages shadow memory and computes statistic
>> of the program efficiency. The tool maps one cache line (64 bytes) of
>> the program to the one byte of the shadow memory.
>> The runtime library measures the data working set size of an
>> application
>> at each snapshot during execution.
>>
>> b. Output:
>>
>> ==28742== EfficiencySanitizer: the total working set size: 32 MB
>> (524291
>> cache lines)
>>
>> HOW TO USE:
>>
>> WorkingSet tool.
>> To measure the working set size, you should build your binary or
>> shared library with compile time flag
>> -fsanitize=efficiency-working-set and set runtime options
>> ESAN_OPTIONS=process_range_access=1:record_snapshots=1
>>
>> CacheFragmentation tool.
>> To enable CacheFragmentation tool you should compile your binary or
>> shared library with compile time flag -fsanitize=efficiency-cache-frag
>> and set runtime options ESAN_OPTIONS=build_mode=0:verbosity=1
>
> I wonder how this is more efficient or precise than tools like valgrind with a suitable CPU model? (with valgrind possibly using a JIT)
>
> Richard.
>
>
>
diff mbox series

Patch

From bb1ed949a5c5dd13f9f35612bdd9514ce564f34a Mon Sep 17 00:00:00 2001
From: Denis Khalikov <d.khalikov@partner.samsung.com>
Date: Fri, 5 Oct 2018 20:42:42 +0300
Subject: [PATCH] EfficiencySanitizer implementation.

---
 gcc/Makefile.in                                 |    2 +
 gcc/builtins.def                                |    4 +-
 gcc/esan.c                                      | 1180 +++++++++++++++++++++++
 gcc/esan.h                                      |   27 +
 gcc/flag-types.h                                |    2 +
 gcc/gcc.c                                       |   19 +
 gcc/internal-fn.c                               |    8 +
 gcc/internal-fn.def                             |    1 +
 gcc/opts.c                                      |    2 +
 gcc/passes.def                                  |    3 +
 gcc/sanitizer.def                               |   49 +
 gcc/sanopt.c                                    |    3 +
 gcc/testsuite/g++.dg/esan/cache-fragmentation.C |   96 ++
 gcc/testsuite/g++.dg/esan/esan.exp              |   34 +
 gcc/testsuite/g++.dg/esan/unaligned.C           |   18 +
 gcc/testsuite/g++.dg/esan/workingset-simple.C   |   29 +
 gcc/testsuite/lib/esan-dg.exp                   |  156 +++
 gcc/toplev.c                                    |    5 +
 gcc/tree-pass.h                                 |    2 +
 gcc/tree-ssa-alias.c                            |    1 +
 gcc/tree-ssa-operands.c                         |    1 +
 libsanitizer/Makefile.am                        |    5 +
 libsanitizer/Makefile.in                        |   11 +-
 libsanitizer/asan/Makefile.in                   |    1 +
 libsanitizer/configure                          |   48 +-
 libsanitizer/configure.ac                       |   20 +
 libsanitizer/configure.tgt                      |    3 +
 libsanitizer/esan/Makefile.am                   |   78 ++
 libsanitizer/esan/Makefile.in                   |  646 +++++++++++++
 libsanitizer/esan/cache_frag.cpp                |  216 +++++
 libsanitizer/esan/cache_frag.h                  |   29 +
 libsanitizer/esan/esan.cpp                      |  312 ++++++
 libsanitizer/esan/esan.h                        |   62 ++
 libsanitizer/esan/esan.syms.extra               |    4 +
 libsanitizer/esan/esan_circular_buffer.h        |   96 ++
 libsanitizer/esan/esan_flags.cpp                |   60 ++
 libsanitizer/esan/esan_flags.h                  |   41 +
 libsanitizer/esan/esan_flags.inc                |   59 ++
 libsanitizer/esan/esan_hashtable.h              |  381 ++++++++
 libsanitizer/esan/esan_interceptors.cpp         |  556 +++++++++++
 libsanitizer/esan/esan_interface.cpp            |  122 +++
 libsanitizer/esan/esan_interface_internal.h     |   84 ++
 libsanitizer/esan/esan_linux.cpp                |   83 ++
 libsanitizer/esan/esan_shadow.h                 |  318 ++++++
 libsanitizer/esan/esan_sideline.h               |   61 ++
 libsanitizer/esan/esan_sideline_linux.cpp       |  177 ++++
 libsanitizer/esan/libtool-version               |    6 +
 libsanitizer/esan/working_set.cpp               |  282 ++++++
 libsanitizer/esan/working_set.h                 |   40 +
 libsanitizer/esan/working_set_posix.cpp         |  133 +++
 libsanitizer/include/esan_interface.h           |   50 +
 libsanitizer/interception/Makefile.in           |    1 +
 libsanitizer/libbacktrace/Makefile.in           |    1 +
 libsanitizer/libsanitizer.spec.in               |    1 +
 libsanitizer/lsan/Makefile.in                   |    1 +
 libsanitizer/sanitizer_common/Makefile.in       |    1 +
 libsanitizer/tsan/Makefile.in                   |    1 +
 libsanitizer/ubsan/Makefile.in                  |    1 +
 58 files changed, 5623 insertions(+), 10 deletions(-)
 create mode 100644 gcc/esan.c
 create mode 100644 gcc/esan.h
 create mode 100644 gcc/testsuite/g++.dg/esan/cache-fragmentation.C
 create mode 100644 gcc/testsuite/g++.dg/esan/esan.exp
 create mode 100644 gcc/testsuite/g++.dg/esan/unaligned.C
 create mode 100644 gcc/testsuite/g++.dg/esan/workingset-simple.C
 create mode 100644 gcc/testsuite/lib/esan-dg.exp
 create mode 100644 libsanitizer/esan/Makefile.am
 create mode 100644 libsanitizer/esan/Makefile.in
 create mode 100644 libsanitizer/esan/cache_frag.cpp
 create mode 100644 libsanitizer/esan/cache_frag.h
 create mode 100644 libsanitizer/esan/esan.cpp
 create mode 100644 libsanitizer/esan/esan.h
 create mode 100644 libsanitizer/esan/esan.syms.extra
 create mode 100644 libsanitizer/esan/esan_circular_buffer.h
 create mode 100644 libsanitizer/esan/esan_flags.cpp
 create mode 100644 libsanitizer/esan/esan_flags.h
 create mode 100644 libsanitizer/esan/esan_flags.inc
 create mode 100644 libsanitizer/esan/esan_hashtable.h
 create mode 100644 libsanitizer/esan/esan_interceptors.cpp
 create mode 100644 libsanitizer/esan/esan_interface.cpp
 create mode 100644 libsanitizer/esan/esan_interface_internal.h
 create mode 100644 libsanitizer/esan/esan_linux.cpp
 create mode 100644 libsanitizer/esan/esan_shadow.h
 create mode 100644 libsanitizer/esan/esan_sideline.h
 create mode 100644 libsanitizer/esan/esan_sideline_linux.cpp
 create mode 100644 libsanitizer/esan/libtool-version
 create mode 100644 libsanitizer/esan/working_set.cpp
 create mode 100644 libsanitizer/esan/working_set.h
 create mode 100644 libsanitizer/esan/working_set_posix.cpp
 create mode 100644 libsanitizer/include/esan_interface.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 4b7cec8..02ca3e4 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1497,6 +1497,7 @@  OBJS = \
 	asan.o \
 	tsan.o \
 	ubsan.o \
+	esan.o \
 	sanopt.o \
 	sancov.o \
 	tree-call-cdce.o \
@@ -2583,6 +2584,7 @@  GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/asan.c \
   $(srcdir)/ubsan.c \
   $(srcdir)/tsan.c \
+  $(srcdir)/esan.c \
   $(srcdir)/sanopt.c \
   $(srcdir)/sancov.c \
   $(srcdir)/ipa-devirt.c \
diff --git a/gcc/builtins.def b/gcc/builtins.def
index ef89729..db7b886 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -238,7 +238,9 @@  along with GCC; see the file COPYING3.  If not see
 	       true, true, true, ATTRS, true, \
 	      (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
 				| SANITIZE_UNDEFINED \
-				| SANITIZE_UNDEFINED_NONDEFAULT) \
+				| SANITIZE_UNDEFINED_NONDEFAULT \
+                                | SANITIZE_EFFICIENCY_WORKING_SET \
+                                | SANITIZE_EFFICIENCY_CACHE_FRAG) \
 	       || flag_sanitize_coverage))
 
 /* Define an attribute list for math functions that are normally
diff --git a/gcc/esan.c b/gcc/esan.c
new file mode 100644
index 0000000..b0a5c14
--- /dev/null
+++ b/gcc/esan.c
@@ -0,0 +1,1180 @@ 
+/* EfficiencySanitizer.
+   Copyright (C) 2011-2018 Free Software Foundation, Inc.
+   Contributed by Denis Khalikov.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "memmodel.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "tree-cfg.h"
+#include "tree-iterator.h"
+#include "esan.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "builtins.h"
+#include "asan.h"
+#include "output.h"
+#include "stor-layout.h"
+#include "ssa.h"
+#include "gimple-fold.h"
+
+/* The size taken from llvm part.  */
+static const unsigned max_struct_field_counter_name_size = 512;
+static char field_counter_name[max_struct_field_counter_name_size];
+static char counter_prefix[] = "struct.";
+
+/* Struct represents internal information about processed
+   record types.  */
+struct esan_type
+{
+  esan_type ()
+    : type (NULL_TREE), array_type (NULL_TREE), field_counter_name (NULL),
+      fields_count (0)
+  {
+  }
+
+  esan_type (tree t, tree a)
+    : type (t), array_type (a), field_counter_name (NULL), fields_count (0)
+  {
+  }
+
+  esan_type (const int value)
+  {
+    if (!value)
+      type = array_type = NULL_TREE;
+  }
+
+  tree type;
+  tree array_type;
+  char *field_counter_name;
+  size_t fields_count;
+};
+
+/* Represents the type, field and index related to them.
+   Why do we need this type at all ?
+
+   Assume we have following classes A, B, C as A <- B <- C,
+   and field access load %reg, &C->A_field, so we should
+   go recurively and find actual type A and field index
+   inside the A class.
+   This struct hepls to solve that problem.
+*/
+struct esan_field_index
+{
+  esan_field_index () : type (NULL_TREE), field (NULL_TREE), index (0) {}
+
+  esan_field_index (tree base_type, tree base_field, size_t base_index)
+    : type (base_type), field (base_field), index (base_index)
+  {
+  }
+
+  esan_field_index (const esan_field_index &other)
+  {
+    type = other.type;
+    field = other.field;
+    index = other.index;
+  }
+
+  esan_field_index &
+  operator= (const esan_field_index &other)
+  {
+    if (this == &other)
+      return *this;
+
+    type = other.type;
+    field = other.field;
+    index = other.index;
+    return *this;
+  }
+
+  tree type;
+  tree field;
+  size_t index;
+};
+
+/* FIXME: use hash_set<K, K_Traits> instead vec<T>
+   to improve search from O(n) to O(1).  */
+static vec<esan_type> vec_esan_type;
+
+static tree
+get_memory_access_decl (bool is_store, unsigned size)
+{
+  /*  Choose an appropriate builtin.  */
+  enum built_in_function fcode;
+  if (size <= 1)
+    fcode
+      = is_store ? BUILT_IN_ESAN_ALIGNED_STORE1 : BUILT_IN_ESAN_ALIGNED_LOAD1;
+  else if (size <= 3)
+    fcode
+      = is_store ? BUILT_IN_ESAN_ALIGNED_STORE2 : BUILT_IN_ESAN_ALIGNED_LOAD2;
+  else if (size <= 7)
+    fcode
+      = is_store ? BUILT_IN_ESAN_ALIGNED_STORE4 : BUILT_IN_ESAN_ALIGNED_LOAD4;
+  else if (size <= 15)
+    fcode
+      = is_store ? BUILT_IN_ESAN_ALIGNED_STORE8 : BUILT_IN_ESAN_ALIGNED_LOAD8;
+  else
+    fcode
+      = is_store ? BUILT_IN_ESAN_ALIGNED_STORE16 : BUILT_IN_ESAN_ALIGNED_LOAD16;
+  return builtin_decl_implicit (fcode);
+}
+
+static void
+instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_store)
+{
+  tree base, expr_ptr;
+  basic_block bb;
+  HOST_WIDE_INT size;
+  gimple *stmt, *g;
+  gimple_seq seq;
+  location_t loc;
+  unsigned int align;
+
+  size = int_size_in_bytes (TREE_TYPE (expr));
+  /*  Can't instrument memory accesses in case of size <= 0.  */
+  if (size <= 0)
+    return;
+
+  poly_int64 unused_bitsize, unused_bitpos;
+  tree offset;
+  machine_mode mode;
+  int unsignedp, reversep, volatilep = 0;
+
+  base = get_inner_reference (expr, &unused_bitsize, &unused_bitpos, &offset,
+			      &mode, &unsignedp, &reversep, &volatilep);
+
+  if (TREE_READONLY (base) || (VAR_P (base) && DECL_HARD_REGISTER (base)))
+    return;
+
+  stmt = gsi_stmt (gsi);
+  loc = gimple_location (stmt);
+  align = get_object_alignment (expr);
+  /*  In this case we can't instrument memmory access.  */
+  if (align < BITS_PER_UNIT)
+    return;
+
+  /*  In this case we need folded ptr to expression.  */
+  expr_ptr = build_fold_addr_expr (unshare_expr (expr));
+
+  expr_ptr = force_gimple_operand (expr_ptr, &seq, true, NULL_TREE);
+  /* Build the esan's builtin.  */
+  g = gimple_build_call (get_memory_access_decl (is_store, size), 1, expr_ptr);
+  /* Set location.  */
+  gimple_set_location (g, loc);
+  gimple_seq_add_stmt_without_update (&seq, g);
+
+  if (is_gimple_call (stmt) && is_store)
+    {
+      /*  Could be a fallthrough edge.  */
+      if (is_ctrl_altering_stmt (stmt))
+	{
+	  edge e;
+
+	  bb = gsi_bb (gsi);
+	  e = find_fallthru_edge (bb->succs);
+	  if (e)
+	    gsi_insert_seq_on_edge_immediate (e, seq);
+	}
+      else
+	/*  Insert after the call on store.  */
+	gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT);
+    }
+  else
+    /*  Insert before.  */
+    gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
+}
+
+static void
+maybe_instrument_working_set_gimple (gimple_stmt_iterator *gsi)
+{
+  gimple *stmt;
+  tree rhs, lhs;
+
+  stmt = gsi_stmt (*gsi);
+
+  if (is_gimple_call (stmt))
+    return;
+
+  if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
+    {
+      if (gimple_store_p (stmt))
+	{
+	  lhs = gimple_assign_lhs (stmt);
+	  instrument_expr (*gsi, lhs, true);
+	}
+      if (gimple_assign_load_p (stmt))
+	{
+	  rhs = gimple_assign_rhs1 (stmt);
+	  instrument_expr (*gsi, rhs, false);
+	}
+    }
+}
+
+static size_t type_count;
+static size_t default_count;
+
+/* Function generates unique id.  */
+static size_t
+gen_unique_id (char *buff, size_t *t_count)
+{
+  size_t size = 1;
+  size_t count = *t_count;
+  while (count)
+    {
+      *buff++ = '0' + count % 10;
+      count /= 10;
+      ++size;
+    }
+  *t_count += 1;
+  return size;
+}
+
+static int
+convert_to_type_id (char *buff, tree field_type)
+{
+  switch (TREE_CODE (field_type))
+    {
+    case INTEGER_TYPE:
+      *buff = '1';
+      return 1;
+    case REAL_TYPE:
+      *buff = '2';
+      return 1;
+    case COMPLEX_TYPE:
+      *buff = '3';
+      return 1;
+    case VECTOR_TYPE:
+      *buff = '4';
+      return 1;
+    case ENUMERAL_TYPE:
+      *buff = '5';
+      return 1;
+    case BOOLEAN_TYPE:
+      *buff = '6';
+      return 1;
+    case POINTER_TYPE:
+      {
+	*buff++ = '8';
+	return gen_unique_id (buff, &type_count);
+      }
+    default:
+      {
+	*buff++ = '9';
+	return gen_unique_id (buff, &default_count);
+      }
+    }
+}
+
+static void
+reverse (char *buff, size_t len)
+{
+  if (!len)
+    return;
+
+  size_t start, end;
+
+  for (start = 0, end = len - 1; start < end; ++start, --end)
+    {
+      char temp = buff[end];
+      buff[end] = buff[start];
+      buff[start] = temp;
+    }
+}
+
+static size_t
+unique_id_size (size_t t_count)
+{
+  size_t size = 1;
+  while (t_count)
+    {
+      t_count /= 10;
+      ++size;
+    }
+  return size;
+}
+
+static size_t
+field_type_size (tree field)
+{
+  if (TREE_CODE (field) == FIELD_DECL)
+    {
+      switch (TREE_CODE (TREE_TYPE (field)))
+	{
+	case INTEGER_TYPE:
+	case REAL_TYPE:
+	case COMPLEX_TYPE:
+	case VECTOR_TYPE:
+	case ENUMERAL_TYPE:
+	case BOOLEAN_TYPE:
+	  return 1;
+	case POINTER_TYPE:
+	  {
+	    return unique_id_size (type_count);
+	  }
+	default:
+	  {
+	    return unique_id_size (default_count);
+	  }
+	}
+    }
+  /* Skip nested types.  */
+  return 0;
+}
+
+/* Functions creates struct field counter name consistent with
+   llvm part, because runtime relies on it.  */
+static ssize_t
+create_struct_field_counter_name (tree type, size_t *count)
+{
+  tree field;
+  size_t offset, start;
+  const char *type_name;
+
+  /* Could be NULL type identifier.  */
+  if (!TYPE_IDENTIFIER (type))
+    return -1;
+
+  type_name = IDENTIFIER_POINTER (TYPE_IDENTIFIER (type));
+  *count = offset = start = 0;
+
+  memset (field_counter_name, 0, max_struct_field_counter_name_size);
+
+  size_t counter_prefix_len = strlen (counter_prefix);
+  memcpy (field_counter_name, counter_prefix, counter_prefix_len);
+  offset += counter_prefix_len;
+
+  size_t type_name_len = strlen (type_name);
+
+  if (type_name_len + counter_prefix_len >= max_struct_field_counter_name_size)
+    return -1;
+
+  memcpy (field_counter_name + offset, type_name, type_name_len);
+  offset += type_name_len;
+
+  start = offset;
+
+  for (field = TYPE_FIELDS (type); field
+				   /* offset + sizeof (field) + sizeof ($).  */
+				   && (offset + field_type_size (field) + 1)
+					< max_struct_field_counter_name_size;
+       field = DECL_CHAIN (field))
+    {
+      if (TREE_CODE (field) == FIELD_DECL)
+	{
+	  offset += convert_to_type_id (field_counter_name + offset,
+					TREE_TYPE (field));
+	  field_counter_name[offset++] = '$';
+	  /* Don't count nested types as a field.  */
+	  if (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE)
+	    ++*count;
+	}
+    }
+
+  /* This is strangely, but llvm part writes fields id in reverse order.  */
+  reverse (field_counter_name + start, offset - start);
+  return offset;
+}
+
+/* This should be kept consistent with LLVM's EfficiencySanitizer StructInfo.
+   struct StructInfo {
+     const char *StructName;
+     u32 Size;
+     u32 NumFields;
+     u32 *FieldOffset;           // auxiliary struct field info.
+     u32 *FieldSize;             // auxiliary struct field info.
+     const char **FieldTypeName; // auxiliary struct field info.
+     u64 *FieldCounters;
+     u64 *ArrayCounter;
+   };  */
+
+/* Cached strcut_info_type tree.  */
+static tree esan_struct_info_type;
+
+/* Returns struct_info_type tree.  */
+static tree
+esan_get_struct_info_type (void)
+{
+  /* Decription taken from llvm.  */
+  static const unsigned int count = 8;
+  static const char *field_names[count]
+    = {"StructName", "Size",	  "NumFields",     "FieldOffset",
+       "FieldSize",  "FieldTypeName", "FieldCounters", "ArrayCounters"};
+  tree fields[count], ret;
+
+  if (esan_struct_info_type)
+    return esan_struct_info_type;
+
+  tree range_type = build_range_type (sizetype, size_zero_node, NULL_TREE);
+  /* StructName is a ptr to char with flex size.  */
+  tree flex_char_arr_type = build_array_type (char_type_node, range_type);
+  /* FieldOffset and FieldSize ptrs.  */
+  tree flex_uint_arr_type = build_array_type (unsigned_type_node, range_type);
+  /* FieldCounter and ArrayCounter.  */
+  tree flex_luint_arr_type
+    = build_array_type (long_long_unsigned_type_node, range_type);
+
+  ret = make_node (RECORD_TYPE);
+  for (unsigned int i = 0; i < count; ++i)
+    {
+      switch (i)
+	{
+	case 0:
+	case 5:
+	  fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+				  get_identifier (field_names[i]),
+				  build_pointer_type (flex_char_arr_type));
+	  break;
+	case 1:
+	case 2:
+	  fields[i]
+	    = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+			  get_identifier (field_names[i]), unsigned_type_node);
+	  break;
+	case 3:
+	case 4:
+	  fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+				  get_identifier (field_names[i]),
+				  build_pointer_type (flex_uint_arr_type));
+	  break;
+	case 6:
+	case 7:
+	  fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+				  get_identifier (field_names[i]),
+				  build_pointer_type (flex_luint_arr_type));
+	  break;
+	default:
+	  break;
+	}
+
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+
+  tree type_decl = build_decl (input_location, TYPE_DECL,
+			       get_identifier ("__esan_strcut_type_info"), ret);
+
+  DECL_IGNORED_P (type_decl) = 1;
+  DECL_ARTIFICIAL (type_decl) = 1;
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = type_decl;
+  TYPE_STUB_DECL (ret) = type_decl;
+  layout_type (ret);
+  esan_struct_info_type = ret;
+  return ret;
+}
+
+/* This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo.
+   The tool-specific information per compilation unit (module).
+   struct CacheFragInfo {
+     const char *UnitName;
+     u32 NumStructs;
+     StructInfo *Structs;
+   };  */
+
+static tree esan_cache_frag_info_type;
+
+static tree
+esan_get_cache_frag_info_type (void)
+{
+  static const unsigned int count = 3;
+  static const char *field_names[count] = {"UnitName", "NumStructs", "Structs"};
+  tree fields[count], ret;
+
+  if (esan_cache_frag_info_type)
+    return esan_cache_frag_info_type;
+
+  tree esan_struct_type_info = esan_get_struct_info_type ();
+
+  tree range_type = build_range_type (sizetype, size_zero_node, NULL_TREE);
+  /* StructInfo Array Type.  */
+  tree struct_info_arr_type
+    = build_array_type (esan_struct_type_info, range_type);
+
+  /* Unit Name.  */
+  tree flex_char_arr_type = build_array_type (char_type_node, range_type);
+
+  ret = make_node (RECORD_TYPE);
+
+  for (unsigned int i = 0; i < count; ++i)
+    {
+      switch (i)
+	{
+	case 0:
+	  fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+				  get_identifier (field_names[i]),
+				  build_pointer_type (flex_char_arr_type));
+	  break;
+	case 1:
+	  fields[i]
+	    = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+			  get_identifier (field_names[i]), unsigned_type_node);
+	  break;
+	case 2:
+	  fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+				  get_identifier (field_names[i]),
+				  build_pointer_type (struct_info_arr_type));
+	  break;
+	default:
+	  break;
+	}
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+
+  tree type_decl
+    = build_decl (input_location, TYPE_DECL,
+		  get_identifier ("__esan_cache_frag_info_type"), ret);
+
+  DECL_IGNORED_P (type_decl) = 1;
+  DECL_ARTIFICIAL (type_decl) = 1;
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = type_decl;
+  TYPE_STUB_DECL (ret) = type_decl;
+  layout_type (ret);
+  esan_cache_frag_info_type = ret;
+  return ret;
+}
+
+static unsigned int esan_ids[2];
+static tree esan_array_counter_type;
+
+static tree
+esan_get_array_counter_type (void)
+{
+  tree ret;
+
+  if (esan_array_counter_type)
+    return esan_array_counter_type;
+
+  tree range_type = build_range_type (sizetype, size_zero_node, NULL_TREE);
+  ret = build_array_type (long_long_unsigned_type_node, range_type);
+
+  esan_array_counter_type = ret;
+  return ret;
+}
+
+static void
+esan_add_struct (tree array_addr, vec<constructor_elt, va_gc> *v,
+		 size_t fields_count, char *field_counter_name_type,
+		 size_t struct_size)
+{
+  /* Create StructName.  */
+  const char *struct_name = field_counter_name_type;
+  size_t struct_name_len = strlen (struct_name) + 1;
+  tree struct_name_tree = build_string (struct_name_len, struct_name);
+  TREE_TYPE (struct_name_tree)
+    = build_array_type_nelts (char_type_node, struct_name_len);
+  TREE_READONLY (struct_name_tree) = 1;
+  TREE_STATIC (struct_name_tree) = 1;
+
+  /* Create StructInfo type.  */
+  tree dtype = esan_get_struct_info_type ();
+
+  /* Create an instance of StructInfo.  */
+  char tmp_name[32];
+  ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lesan_type", esan_ids[0]++);
+  tree decl
+    = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name), dtype);
+  TREE_STATIC (decl) = 1;
+  TREE_PUBLIC (decl) = 0;
+  TREE_READONLY (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  DECL_EXTERNAL (decl) = 0;
+
+  /* Initialize created struct.  */
+  tree ctor = build_constructor_va (
+    dtype, 8, NULL_TREE, build_fold_addr_expr (struct_name_tree), NULL_TREE,
+    build_int_cst (unsigned_type_node, struct_size), NULL_TREE,
+    build_int_cst (unsigned_type_node, fields_count), NULL_TREE,
+    build_zero_cst (long_long_unsigned_type_node), NULL_TREE,
+    build_zero_cst (long_long_unsigned_type_node), NULL_TREE,
+    build_zero_cst (long_long_unsigned_type_node), NULL_TREE, array_addr,
+    NULL_TREE, build_zero_cst (long_long_unsigned_type_node));
+
+  TREE_CONSTANT (ctor) = 1;
+  TREE_STATIC (ctor) = 1;
+  DECL_INITIAL (decl) = ctor;
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ctor);
+}
+
+static ssize_t
+esan_vec_contains_type (tree type)
+{
+  ssize_t index = 0;
+
+  if (type == NULL_TREE)
+    return -1;
+
+  esan_type esan_type_instance;
+  /* This is O(n) cost, but I think we can improve it to ~ O(1)
+     by using a hash_set.  */
+  while (vec_esan_type.iterate (index, &esan_type_instance))
+    {
+      if ((TYPE_IDENTIFIER (type)) == TYPE_IDENTIFIER (esan_type_instance.type))
+	return index;
+      ++index;
+    }
+  return -1;
+}
+
+bool
+esan_expand_record_access_ifn (gimple_stmt_iterator *gsip)
+{
+  tree field_int, base_int;
+  size_t fields_count, field_index;
+  tree base_type;
+  gimple_stmt_iterator gsi, gsi_origin;
+  gimple *stmt;
+  location_t loc;
+  ssize_t index;
+
+  /* Expand internal ESAN_ACCESS.  */
+  gsi_origin = gsi = *gsip;
+  stmt = gsi_stmt (gsi);
+  loc = gimple_location (stmt);
+  base_int = gimple_call_arg (stmt, 0);
+  field_int = gimple_call_arg (stmt, 1);
+  esan_type esan_type_instance;
+
+  tree array = NULL_TREE;
+  tree ptr = NULL_TREE;
+  base_type = TREE_TYPE (TREE_TYPE (base_int));
+
+  if (!base_type)
+    {
+      unlink_stmt_vdef (stmt);
+      return gsi_remove (&gsi_origin, true);
+    }
+
+  field_index = tree_to_uhwi (field_int);
+  index = esan_vec_contains_type (base_type);
+
+  /* In case we have not found type in the pool of types
+     and field has valid index, we should
+     create fields counter array and add type to the pool of types.  */
+  if (index == -1)
+    {
+      fields_count = 0;
+      ssize_t field_counter_name_len
+	= create_struct_field_counter_name (base_type, &fields_count);
+
+      if (field_counter_name_len == -1)
+	goto finish;
+
+      char *field_counter_name_type
+	= (char *) xmalloc (field_counter_name_len + 1);
+      memset (field_counter_name_type, 0, field_counter_name_len + 1);
+      memcpy (field_counter_name_type, field_counter_name,
+	      field_counter_name_len + 1);
+
+      tree atype = esan_get_array_counter_type ();
+      array = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			  get_identifier (field_counter_name), atype);
+
+      TREE_STATIC (array) = 1;
+      TREE_PUBLIC (array) = 1;
+      DECL_ARTIFICIAL (array) = 1;
+      DECL_IGNORED_P (array) = 1;
+      DECL_WEAK (array) = 1;
+      DECL_SIZE (array) = build_int_cst (
+	integer_type_node,
+	fields_count * tree_to_uhwi (TYPE_SIZE (long_long_unsigned_type_node)));
+
+      DECL_SIZE_UNIT (array)
+	= build_int_cst (integer_type_node,
+			 fields_count
+			   * tree_to_uhwi (
+			       TYPE_SIZE_UNIT (long_long_unsigned_type_node)));
+      DECL_EXTERNAL (array) = 0;
+
+      tree counter_ctor
+	= build_constructor_va (atype, 1, NULL_TREE, build_zero_cst (atype));
+      TREE_CONSTANT (counter_ctor) = 1;
+      TREE_STATIC (counter_ctor) = 1;
+      DECL_INITIAL (array) = counter_ctor;
+      varpool_node::finalize_decl (array);
+
+      ptr = build_fold_addr_expr (array);
+      esan_type_instance.type = base_type;
+      esan_type_instance.array_type = array;
+      esan_type_instance.field_counter_name = field_counter_name_type;
+      esan_type_instance.fields_count = fields_count;
+      vec_esan_type.safe_push (esan_type_instance);
+    }
+  /* We have already added the type into the pool, so fields counter
+     array was created.  */
+  else if (index >= 0)
+    {
+      if (vec_esan_type.iterate (index, &esan_type_instance))
+	ptr = build_fold_addr_expr (esan_type_instance.array_type);
+      else
+	goto finish;
+    }
+  {
+    gimple *g;
+    /* Field number + sizeof (long int).  */
+    tree offset = build_int_cst (unsigned_type_node,
+				 field_index
+				   * tree_to_uhwi (TYPE_SIZE_UNIT (
+				       long_long_unsigned_type_node)));
+    /* array + offset.  */
+    g = gimple_build_assign (make_ssa_name (pointer_sized_int_node), PLUS_EXPR,
+			     ptr, offset);
+    gimple_set_location (g, loc);
+    gsi_insert_before (gsip, g, GSI_SAME_STMT);
+    ptr = gimple_assign_lhs (g);
+
+    tree call_decl = builtin_decl_implicit (BUILT_IN_ESAN_INCREMENT);
+
+    g = gimple_build_call (call_decl, 1, ptr);
+    gimple_set_location (g, loc);
+    gsi_insert_before (gsip, g, GSI_SAME_STMT);
+    /* FIXME Inline __esan_increment for the better performance.  */
+  }
+finish:
+  unlink_stmt_vdef (stmt);
+  return gsi_remove (&gsi_origin, true);
+}
+
+/* Go recursively and find the actual class type and field index inside it.  */
+static esan_field_index
+esan_get_field_index_internal (tree base_type, tree field, bool *found)
+{
+  tree field_it = TYPE_FIELDS (base_type);
+  esan_field_index field_index (base_type, field, 0);
+
+  for (; field_it && !*found; field_it = DECL_CHAIN (field_it))
+    {
+      if (TREE_CODE (field_it) == FIELD_DECL)
+	{
+	  if (TREE_CODE (TREE_TYPE (field_it)) == RECORD_TYPE)
+	    {
+	      esan_field_index nested_field_index
+		= esan_get_field_index_internal (TREE_TYPE (field_it), field,
+						 found);
+	      if (*found)
+		return nested_field_index;
+	    }
+	  else if (field_it == field)
+	    *found = true;
+	  else
+	    ++field_index.index;
+	}
+    }
+  return *found ? field_index : esan_field_index (NULL_TREE, NULL_TREE, 0);
+}
+
+static bool
+esan_get_field_index (tree base_type, tree field, esan_field_index *field_index)
+{
+  bool found = false;
+  /* At this momet we don't really know the record type where field is defined,
+     so can't cash the previous search.  */
+  *field_index = esan_get_field_index_internal (base_type, field, &found);
+  return found;
+}
+
+static void
+instrument_record_field_access (tree base, gimple_stmt_iterator *iter,
+				tree field, const enum tree_code code)
+{
+  tree t = NULL_TREE, base_type = NULL_TREE;
+  gcall *g;
+  esan_field_index field_index_internal;
+  HOST_WIDE_INT field_index;
+
+  if (code == MEM_REF)
+    {
+      t = TREE_OPERAND (base, 0);
+      if (!POINTER_TYPE_P (TREE_TYPE (t)))
+	return;
+    }
+
+  /* Don't instrument unions.  */
+  if (TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE)
+    return;
+
+  /* Get the actual field index inside the record.  */
+  if (!esan_get_field_index (TREE_TYPE (base), field, &field_index_internal))
+    return;
+
+  field_index = field_index_internal.index;
+  base_type = TYPE_MAIN_VARIANT (field_index_internal.type);
+
+  /* Pack the pointer to integer, so other pass will keep it the same. */
+  g = gimple_build_call_internal (IFN_ESAN_RECORD_ACCESS, 2,
+				  build_int_cst (build_pointer_type (base_type),
+						 0),
+				  build_int_cst (unsigned_type_node,
+						 field_index));
+
+  gimple_set_location (g, gimple_location (gsi_stmt (*iter)));
+  gsi_insert_before (iter, g, GSI_SAME_STMT);
+}
+
+static void
+instrument_record_access (gimple_stmt_iterator *gsi, tree expr, bool is_store)
+{
+  tree field, t, base;
+  poly_int64 unused_bitsize, unused_bitpos;
+  tree offset;
+  machine_mode mode;
+  int unsignedp, reversep, volatilep = 0;
+
+  gimple *stmt = gsi_stmt (*gsi);
+
+  HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (expr));
+
+  if (size <= 0)
+    return;
+
+  tree base_tree
+    = get_inner_reference (expr, &unused_bitsize, &unused_bitpos, &offset,
+			   &mode, &unsignedp, &reversep, &volatilep);
+
+  if (TREE_READONLY (base_tree)
+      || (VAR_P (base_tree) && DECL_HARD_REGISTER (base_tree)))
+    return;
+
+  if (get_object_alignment (expr) < BITS_PER_UNIT)
+    return;
+
+  t = is_store ? gimple_get_lhs (stmt) : gimple_assign_rhs1 (stmt);
+  base = get_base_address (t);
+  field = NULL_TREE;
+
+  /* Get the field.  */
+  if (TREE_CODE (t) == COMPONENT_REF)
+    field = TREE_OPERAND (t, 1);
+
+  if (!field || field == base)
+    return;
+
+  const enum tree_code code = TREE_CODE (base);
+
+  if ((code == MEM_REF && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
+      || code == VAR_DECL)
+    instrument_record_field_access (base, gsi, field, code);
+}
+
+static void
+maybe_instrument_cache_frag_gimple (gimple_stmt_iterator *gsi)
+{
+  gimple *stmt;
+  tree lhs, rhs;
+  stmt = gsi_stmt (*gsi);
+
+  if (is_gimple_call (stmt))
+    return;
+
+  if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
+    {
+      if (gimple_store_p (stmt))
+	{
+	  lhs = gimple_assign_lhs (stmt);
+	  instrument_record_access (gsi, lhs, true);
+	}
+      else if (gimple_assign_load_p (stmt))
+	{
+	  rhs = gimple_assign_rhs1 (stmt);
+	  instrument_record_access (gsi, rhs, false);
+	}
+    }
+}
+
+static void
+instrument_memory_accesses (void)
+{
+  basic_block bb;
+  gimple_stmt_iterator gsi;
+
+  /*  So, walk through all basic blocks
+      and try to instrument memory accesses.  */
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+	  if (flag_sanitize & SANITIZE_EFFICIENCY_WORKING_SET)
+	    maybe_instrument_working_set_gimple (&gsi);
+	  else if (flag_sanitize & SANITIZE_EFFICIENCY_CACHE_FRAG)
+	    maybe_instrument_cache_frag_gimple (&gsi);
+	}
+    }
+}
+
+/* EfficiencySanitizer instrumentation pass.  */
+
+static unsigned
+esan_pass (void)
+{
+  initialize_sanitizer_builtins ();
+  instrument_memory_accesses ();
+  return 0;
+}
+
+/* Creates an arrray of StructInfo structs and CacheInfo struct.
+   Inserts __esan_init () into the list of CTORs and
+   __esan_exit() into the listof DCTORs. */
+
+void
+esan_finish_file (void)
+{
+  tree ctor_statements = NULL_TREE;
+  tree dctor_statements = NULL_TREE;
+  initialize_sanitizer_builtins ();
+  tree tool_id = NULL_TREE;
+
+  tree init_decl = builtin_decl_implicit (BUILT_IN_ESAN_INIT);
+  tree exit_decl = builtin_decl_implicit (BUILT_IN_ESAN_EXIT);
+
+  if (flag_sanitize & SANITIZE_EFFICIENCY_CACHE_FRAG)
+    {
+      esan_type esan_type_instance;
+      size_t index = 0;
+      size_t num_types = vec_esan_type.length ();
+      vec<constructor_elt, va_gc> *v;
+      vec_alloc (v, num_types);
+
+      /* Create StructInfo struct for the every struct we have instrumented.  */
+      while (vec_esan_type.iterate (index, &esan_type_instance))
+	{
+	  tree ptr = build_fold_addr_expr (esan_type_instance.array_type);
+	  esan_add_struct (ptr, v, esan_type_instance.fields_count,
+			   esan_type_instance.field_counter_name,
+			   int_size_in_bytes (esan_type_instance.type));
+
+	  /* Was allocated by xmalloc, so free the memory.  */
+	  free (esan_type_instance.field_counter_name);
+	  ++index;
+	}
+
+      /* Create module name string.  */
+      size_t module_name_len = strlen (main_input_filename) + 1;
+      tree module_name_str
+	= build_string (module_name_len, main_input_filename);
+      TREE_TYPE (module_name_str)
+	= build_array_type_nelts (char_type_node, module_name_len);
+      TREE_READONLY (module_name_str) = 1;
+      TREE_STATIC (module_name_str) = 1;
+
+      tool_id = build_int_cst (unsigned_type_node, 1);
+      /* First, create the array of struct info type.  */
+      tree stype = esan_get_struct_info_type ();
+
+      stype = build_array_type_nelts (stype, num_types);
+
+      char tmp_info_name[32];
+      ASM_GENERATE_INTERNAL_LABEL (tmp_info_name, "Lesan_info", 0);
+
+      tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			     get_identifier (tmp_info_name), stype);
+
+      TREE_STATIC (var) = 1;
+      TREE_PUBLIC (var) = 0;
+      TREE_READONLY (var) = 1;
+      DECL_ARTIFICIAL (var) = 1;
+      DECL_IGNORED_P (var) = 1;
+      DECL_EXTERNAL (var) = 0;
+
+      tree ctor = build_constructor (stype, v);
+
+      TREE_CONSTANT (ctor) = 1;
+      TREE_STATIC (ctor) = 1;
+      DECL_INITIAL (var) = ctor;
+
+      varpool_node::finalize_decl (var);
+
+      tree ctype = esan_get_cache_frag_info_type ();
+      char tmp_cache_name[32];
+      ASM_GENERATE_INTERNAL_LABEL (tmp_cache_name, "Lesan_cache", 0);
+
+      tree c_var = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			       get_identifier (tmp_cache_name), ctype);
+      TREE_STATIC (c_var) = 1;
+      TREE_PUBLIC (c_var) = 0;
+      DECL_ARTIFICIAL (c_var) = 1;
+      DECL_IGNORED_P (c_var) = 1;
+      DECL_EXTERNAL (c_var) = 0;
+
+      tree c_ctor
+	= build_constructor_va (ctype, 3, NULL_TREE,
+				build_fold_addr_expr (module_name_str),
+				NULL_TREE,
+				build_int_cst (unsigned_type_node, num_types),
+				NULL_TREE, build_fold_addr_expr (var));
+
+      TREE_CONSTANT (c_ctor) = 1;
+      TREE_STATIC (c_ctor) = 1;
+      DECL_INITIAL (c_var) = c_ctor;
+      varpool_node::finalize_decl (c_var);
+
+      append_to_statement_list (
+	build_call_expr (init_decl, 2, build_int_cst (unsigned_type_node, 1),
+			 build_fold_addr_expr (c_var)),
+	&ctor_statements);
+      cgraph_build_static_cdtor ('I', ctor_statements,
+				 MAX_RESERVED_INIT_PRIORITY - 1);
+
+      append_to_statement_list (build_call_expr (exit_decl, 1,
+						 build_fold_addr_expr (c_var)),
+				&dctor_statements);
+      cgraph_build_static_cdtor ('D', dctor_statements,
+				 MAX_RESERVED_INIT_PRIORITY - 1);
+    }
+  else if (flag_sanitize & SANITIZE_EFFICIENCY_WORKING_SET)
+    {
+      tool_id = build_int_cst (unsigned_type_node, 2);
+      append_to_statement_list (
+	build_call_expr (init_decl, 2, build_int_cst (unsigned_type_node, 2),
+			 build_zero_cst (long_unsigned_type_node)),
+	&ctor_statements);
+      cgraph_build_static_cdtor ('I', ctor_statements,
+				 MAX_RESERVED_INIT_PRIORITY - 1);
+      append_to_statement_list (build_call_expr (exit_decl, 0),
+				&dctor_statements);
+      cgraph_build_static_cdtor ('D', dctor_statements,
+				 MAX_RESERVED_INIT_PRIORITY - 1);
+    }
+
+  tree tool_id_type = build_array_type_nelts (unsigned_type_node, 1);
+
+  /* Runtime part relies on __esan_which_tool global, which
+     informs the runtime about what part of runtime library should run.  */
+  tree tool_id_decl
+    = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		  get_identifier ("__esan_which_tool"), tool_id_type);
+  TREE_STATIC (tool_id_decl) = 1;
+  TREE_PUBLIC (tool_id_decl) = 1;
+  DECL_WEAK (tool_id_decl) = 1;
+  DECL_ARTIFICIAL (tool_id_decl) = 1;
+  DECL_IGNORED_P (tool_id_decl) = 1;
+  DECL_EXTERNAL (tool_id_decl) = 0;
+
+  tree tool_id_ctor
+    = build_constructor_va (TREE_TYPE (tool_id_decl), 1, NULL_TREE, tool_id);
+  TREE_CONSTANT (tool_id_ctor) = 1;
+  TREE_STATIC (tool_id_ctor) = 1;
+  DECL_INITIAL (tool_id_decl) = tool_id_ctor;
+  varpool_node::finalize_decl (tool_id_decl);
+}
+
+/* The pass descriptor.  */
+
+namespace {
+
+const pass_data pass_data_esan = {
+  GIMPLE_PASS,		 /* type */
+  "esan",		 /* name */
+  OPTGROUP_NONE,	 /* optinfo_flags */
+  TV_NONE,		 /* tv_id */
+  (PROP_ssa | PROP_cfg), /* properties_required */
+  0,			 /* properties_provided */
+  0,			 /* properties_destroyed */
+  0,			 /* todo_flags_start */
+  TODO_update_ssa,       /* todo_flags_finish */
+};
+
+class pass_esan : public gimple_opt_pass
+{
+public:
+  pass_esan (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_esan, ctxt) {}
+
+  /* opt_pass methods: */
+  opt_pass *
+  clone () { return new pass_esan (m_ctxt); }
+
+  virtual bool
+  gate (function *)
+  {
+    return (
+      (flag_sanitize
+       & (SANITIZE_EFFICIENCY_WORKING_SET | SANITIZE_EFFICIENCY_CACHE_FRAG))
+      != 0);
+  }
+
+  virtual unsigned int
+  execute (function *) { return esan_pass (); }
+
+}; // class pass_esan
+
+} // namespace
+
+gimple_opt_pass *
+make_pass_esan (gcc::context *ctxt)
+{
+  return new pass_esan (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_esan_O0 = {
+  GIMPLE_PASS,		 /* type */
+  "esan0",		 /* name */
+  OPTGROUP_NONE,	 /* optinfo_flags */
+  TV_NONE,		 /* tv_id */
+  (PROP_ssa | PROP_cfg), /* properties_required */
+  0,			 /* properties_provided */
+  0,			 /* properties_destroyed */
+  0,			 /* todo_flags_start */
+  TODO_update_ssa,       /* todo_flags_finish */
+};
+
+class pass_esan_O0 : public gimple_opt_pass
+{
+public:
+  pass_esan_O0 (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_esan_O0, ctxt) {}
+
+  /* opt_pass methods: */
+  virtual bool
+  gate (function *)
+  {
+    return (
+      (flag_sanitize
+       & (SANITIZE_EFFICIENCY_WORKING_SET | SANITIZE_EFFICIENCY_CACHE_FRAG))
+	!= 0
+      && !optimize);
+  }
+
+  virtual unsigned int
+  execute (function *) { return esan_pass (); }
+
+}; // class pass_esan_O0
+
+} // namespace
+
+gimple_opt_pass *
+make_pass_esan_O0 (gcc::context *ctxt)
+{
+  return new pass_esan_O0 (ctxt);
+}
diff --git a/gcc/esan.h b/gcc/esan.h
new file mode 100644
index 0000000..f483086
--- /dev/null
+++ b/gcc/esan.h
@@ -0,0 +1,27 @@ 
+/* EfficiencySanitizer.
+   Copyright (C) 2011-2018 Free Software Foundation, Inc.
+   Contributed by Denis Khalikov.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef TREE_ESAN
+#define TREE_ESAN
+
+extern void esan_finish_file (void);
+extern bool esan_expand_record_access_ifn (gimple_stmt_iterator *gsip);
+
+#endif /* TREE_ESAN */
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 500f663..503066e 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -248,6 +248,8 @@  enum sanitize_code {
   SANITIZE_BUILTIN = 1UL << 25,
   SANITIZE_POINTER_COMPARE = 1UL << 26,
   SANITIZE_POINTER_SUBTRACT = 1UL << 27,
+  SANITIZE_EFFICIENCY_WORKING_SET = 1UL << 28,
+  SANITIZE_EFFICIENCY_CACHE_FRAG = 1UL << 29,
   SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
 		       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 264204d..7969688 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -755,6 +755,19 @@  proper position among the other output files.  */
 #endif
 #endif
 
+#ifndef LIBESAN_SPEC
+#define STATIC_LIBESAN_LIBS \
+  " %{static-libesan:%:include(libsanitizer.spec)%(link_libesan)}"
+#ifdef HAVE_LD_STATIC_DYNAMIC
+#define LIBESAN_SPEC "%{static-libesan:" LD_STATIC_OPTION \
+		     "} -lesan %{static-libesan:" LD_DYNAMIC_OPTION "}" \
+		     STATIC_LIBESAN_LIBS
+#else
+#define LIBESAN_SPEC "-lesan" STATIC_LIBESAN_LIBS
+#endif
+#endif
+
+
 /* Linker options for compressed debug sections.  */
 #if HAVE_LD_COMPRESS_DEBUG == 0
 /* No linker support.  */
@@ -993,6 +1006,8 @@  proper position among the other output files.  */
     %{%:sanitize(thread):" LIBTSAN_SPEC "\
     %{static:%ecannot specify -static with -fsanitize=thread}}\
     %{%:sanitize(undefined):" LIBUBSAN_SPEC "}\
+    %{%:sanitize(efficiency-working-set):" LIBESAN_SPEC "}\
+    %{%:sanitize(efficiency-cache-frag):" LIBESAN_SPEC "}\
     %{%:sanitize(leak):" LIBLSAN_SPEC "}}}}"
 #endif
 
@@ -9350,6 +9365,10 @@  sanitize_spec_function (int argc, const char **argv)
     return ((flag_sanitize
 	     & (SANITIZE_ADDRESS | SANITIZE_LEAK | SANITIZE_THREAD))
 	    == SANITIZE_LEAK) ? "" : NULL;
+  if (strcmp (argv[0], "efficiency-working-set") == 0)
+    return (flag_sanitize & SANITIZE_EFFICIENCY_WORKING_SET) ? "" : NULL;
+  if (strcmp (argv[0], "efficiency-cache-frag") == 0)
+    return (flag_sanitize & SANITIZE_EFFICIENCY_CACHE_FRAG) ? "" : NULL;
   return NULL;
 }
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 34d4f9e..85566f4 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -456,6 +456,14 @@  expand_UBSAN_OBJECT_SIZE (internal_fn, gcall *)
 /* This should get expanded in the sanopt pass.  */
 
 static void
+expand_ESAN_RECORD_ACCESS (internal_fn, gcall *)
+{
+  gcc_unreachable ();
+}
+
+/* This should get expanded in the sanopt pass.  */
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index cda314e..1706a7e 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -289,6 +289,7 @@  DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (TSAN_FUNC_EXIT, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (VA_ARG, ECF_NOTHROW | ECF_LEAF, NULL)
+DEF_INTERNAL_FN (ESAN_RECORD_ACCESS, ECF_LEAF | ECF_NOTHROW, NULL)
 
 /* An unduplicable, uncombinable function.  Generally used to preserve
    a CFG property in the face of jump threading, tail merging or
diff --git a/gcc/opts.c b/gcc/opts.c
index dc12c2e..e52f3e3 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1583,6 +1583,8 @@  const struct sanitizer_opts_s sanitizer_opts[] =
   SANITIZER_OPT (vptr, SANITIZE_VPTR, true),
   SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true),
   SANITIZER_OPT (builtin, SANITIZE_BUILTIN, true),
+  SANITIZER_OPT (efficiency-working-set, SANITIZE_EFFICIENCY_WORKING_SET, true),
+  SANITIZER_OPT (efficiency-cache-frag, SANITIZE_EFFICIENCY_CACHE_FRAG, true),
   SANITIZER_OPT (all, ~0U, true),
 #undef SANITIZER_OPT
   { NULL, 0U, 0UL, false }
diff --git a/gcc/passes.def b/gcc/passes.def
index 7f4b347..257f6a4 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -252,6 +252,7 @@  along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_asan);
       NEXT_PASS (pass_tsan);
       NEXT_PASS (pass_dce);
+      NEXT_PASS (pass_esan);
       /* Pass group that runs when 1) enabled, 2) there are loops
 	 in the function.  Make sure to run pass_fix_loops before
 	 to discover/remove loops before running the gate function
@@ -367,6 +368,7 @@  along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
       NEXT_PASS (pass_tsan);
+      NEXT_PASS (pass_esan);
       /* ???  We do want some kind of loop invariant motion, but we possibly
          need to adjust LIM to be more friendly towards preserving accurate
 	 debug information here.  */
@@ -392,6 +394,7 @@  along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_lower_switch_O0);
   NEXT_PASS (pass_asan_O0);
   NEXT_PASS (pass_tsan_O0);
+  NEXT_PASS (pass_esan_O0);
   NEXT_PASS (pass_sanopt);
   NEXT_PASS (pass_cleanup_eh);
   NEXT_PASS (pass_lower_resx);
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index a043c4e..82e898f 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -180,6 +180,55 @@  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_COMPARE, "__sanitizer_ptr_cmp",
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_SUBTRACT, "__sanitizer_ptr_sub",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
 
+/* Efficiency Sanitizer */
+DEF_SANITIZER_BUILTIN(BUILT_IN_ESAN_INIT, "__esan_init",
+		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ESAN_EXIT, "__esan_exit",
+		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE1, "__esan_aligned_store1",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD1, "__esan_aligned_load1",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE2, "__esan_aligned_store2",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD2, "__esan_aligned_load2",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE4, "__esan_aligned_store4",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD4, "__esan_aligned_load4",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE8, "__esan_aligned_store8",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD8, "__esan_aligned_load8",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE16, "__esan_aligned_store16",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD16, "__esan_aligned_load16",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE1, "__esan_unaligned_store1",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD1, "__esan_unaligned_load1",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE2, "__esan_unaligned_store2",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD2, "__esan_unaligned_load2",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE4, "__esan_unaligned_store4",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD4, "__esan_unaligned_load4",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE8, "__esan_unaligned_store8",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD8, "__esan_unaligned_load8",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE16, "__esan_unaligned_store16",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD16, "__esan_unaligned_load16",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_INCREMENT, "__esan_increment",
+		       BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
+
+
 /* Thread Sanitizer */
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", 
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index 082f936..1717c40 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -34,6 +34,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
+#include "esan.h"
 #include "params.h"
 #include "tree-hash-traits.h"
 #include "gimple-ssa.h"
@@ -1338,6 +1339,8 @@  pass_sanopt::execute (function *fun)
 						    &need_commit_edge_insert,
 						    shadow_vars_mapping);
 		  break;
+		case IFN_ESAN_RECORD_ACCESS:
+		  no_next = esan_expand_record_access_ifn (&gsi);
 		default:
 		  break;
 		}
diff --git a/gcc/testsuite/g++.dg/esan/cache-fragmentation.C b/gcc/testsuite/g++.dg/esan/cache-fragmentation.C
new file mode 100644
index 0000000..e95c564
--- /dev/null
+++ b/gcc/testsuite/g++.dg/esan/cache-fragmentation.C
@@ -0,0 +1,96 @@ 
+// { dg-do run { target { x86_64-*-linux* } } }
+// { dg-options "-fsanitize=efficiency-cache-frag" }
+
+struct A
+{
+  int a;
+  char b;
+  float c;
+  double d;
+  unsigned e;
+  unsigned long f;
+  unsigned long long j;
+};
+
+struct B : A
+{
+  int f1;
+  int f2;
+  int f3;
+};
+
+struct C : B
+{
+  int f4;
+  int f5;
+  int f6;
+};
+
+struct E
+{
+  int f7;
+  int f8;
+};
+
+struct D : B, E
+{
+  int f9;
+};
+
+static int count = 10;
+
+static void
+foo ()
+{
+  A a;
+  for (int i = 0; i < count; ++i)
+    {
+      a.a = i;
+      a.b = a.a;
+      a.c = i;
+      a.d = i;
+      a.e = i;
+      a.f = i;
+      a.j = i;
+    }
+
+  A b;
+  A *ptr = &b;
+  for (int i = 0; i < count; ++i)
+    {
+      ptr->a = i;
+      ptr->b = ptr->a;
+      ptr->c = i;
+      ptr->d = i;
+      ptr->e = i;
+      ptr->f = i;
+      ptr->j = i;
+    }
+}
+
+void
+bar ()
+{
+  C c;
+  for (int i = 0; i < count; ++i)
+    {
+      c.a = i;
+      c.f1 = i;
+      c.f4 = i;
+    }
+
+  D d;
+  for (int i = 0; i < count; ++i)
+    {
+      d.f9 = i;
+      d.f7 = i;
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  foo ();
+  bar ();
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/esan/esan.exp b/gcc/testsuite/g++.dg/esan/esan.exp
new file mode 100644
index 0000000..9052347
--- /dev/null
+++ b/gcc/testsuite/g++.dg/esan/esan.exp
@@ -0,0 +1,34 @@ 
+# Copyright (C) 2012-2016 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Load support procs.
+load_lib g++-dg.exp
+load_lib esan-dg.exp
+
+# Initialize `dg'.
+dg-init
+esan_init
+
+# Main loop.
+if [check_effective_target_fsanitize_esan] {
+  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" ""
+}
+
+# All done.
+esan_finish
+dg-finish
diff --git a/gcc/testsuite/g++.dg/esan/unaligned.C b/gcc/testsuite/g++.dg/esan/unaligned.C
new file mode 100644
index 0000000..cc15683
--- /dev/null
+++ b/gcc/testsuite/g++.dg/esan/unaligned.C
@@ -0,0 +1,18 @@ 
+// { dg-do run { target { x86_64-*-linux* } } }
+// { dg-options "-fsanitize=efficiency-working-set" }
+
+class A {
+public:
+  bool : 1;
+  bool IsExpandedByDefault : 1;
+};
+
+void fn1() {
+  A a;
+  a.IsExpandedByDefault = 0;
+}
+
+int main (int argc, char **argv) {
+  fn1 ();
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/esan/workingset-simple.C b/gcc/testsuite/g++.dg/esan/workingset-simple.C
new file mode 100644
index 0000000..f38134e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/esan/workingset-simple.C
@@ -0,0 +1,29 @@ 
+// { dg-do run { target { x86_64-*-linux* } } }
+// { dg-options "-fsanitize=efficiency-working-set" }
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <assert.h>
+
+const int size = 0x1 << 25; // 520k cache lines
+const int line_size = 64;
+
+int main(int argc, char **argv) {
+  char *bufA = (char *)malloc(sizeof(char) * line_size);
+  char bufB[64];
+  char *bufC = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
+                            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  bufA[0] = 0;
+  // This additional access to the same line should not increase the line
+  // count: but it's difficult to make a non-flaky test that measures the
+  // lines down to the ones digit so right now we're not really testing that.
+  // If we add a heap-only mode we may be able to be more precise.
+  bufA[1] = 0;
+  bufB[33] = 1;
+  for (int i = 0; i < size; i += line_size)
+    bufC[i] = 0;
+  free(bufA);
+  munmap(bufC, 0x4000);
+  return 0;
+}
diff --git a/gcc/testsuite/lib/esan-dg.exp b/gcc/testsuite/lib/esan-dg.exp
new file mode 100644
index 0000000..e3b933d
--- /dev/null
+++ b/gcc/testsuite/lib/esan-dg.exp
@@ -0,0 +1,156 @@ 
+# Copyright (C) 2013-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Return 1 if compilation with -fsanitize=efficiency-working-set is error-free for trivial
+# code, 0 otherwise.  Also set what to do by default here, depending on the
+# result of a runtime test.
+
+proc check_effective_target_fsanitize_esan {} {
+    global individual_timeout
+    global dg-do-what-default
+
+    if ![check_no_compiler_messages fsanitize_esan executable {
+	int main (void) { return 0; }
+    }] {
+        return 0
+    }
+
+    # Lower timeout value in case test does not terminate properly.
+    set individual_timeout 20
+    if [check_runtime_nocache esan_works {
+	int main () { return 0; }
+    }] {
+	set dg-do-what-default run
+    } else {
+	set dg-do-what-default link
+    }
+    unset individual_timeout
+
+    return 1
+}
+
+#
+# esan_link_flags -- compute library path and flags to find libesan.
+# (originally from g++.exp)
+#
+
+proc esan_link_flags { paths } {
+    global srcdir
+    global ld_library_path
+    global shlib_ext
+    global esan_saved_library_path
+
+    set gccpath ${paths}
+    set flags ""
+
+    set shlib_ext [get_shlib_extension]
+    set esan_saved_library_path $ld_library_path
+
+    if { $gccpath != "" } {
+      if { [file exists "${gccpath}/libsanitizer/esan/.libs/libesan.a"]
+	   || [file exists "${gccpath}/libsanitizer/esan/.libs/libesan.${shlib_ext}"] } {
+	  append flags " -B${gccpath}/libsanitizer/esan/ "
+	  append flags " -L${gccpath}/libsanitizer/esan/.libs "
+	  append ld_library_path ":${gccpath}/libsanitizer/esan/.libs"
+      }
+    } else {
+      global tool_root_dir
+
+      set libesan [lookfor_file ${tool_root_dir} libesan]
+      if { $libesan != "" } {
+	  append flags "-L${libesan} "
+	  append ld_library_path ":${libesan}"
+      }
+    }
+
+    set_ld_library_path_env_vars
+
+    return "$flags"
+}
+
+#
+# esan_init -- called at the start of each subdir of tests
+#
+
+proc esan_init { args } {
+    global TEST_ALWAYS_FLAGS
+    global ALWAYS_CXXFLAGS
+    global TOOL_OPTIONS
+    global esan_saved_TEST_ALWAYS_FLAGS
+    global esan_saved_ALWAYS_CXXFLAGS
+    global dg-do-what-default
+    global esan_saved_dg-do-what-default
+
+    set link_flags ""
+    if ![is_remote host] {
+	if [info exists TOOL_OPTIONS] {
+	    set link_flags "[esan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
+	} else {
+	    set link_flags "[esan_link_flags [get_multilibs]]"
+	}
+    }
+
+    if [info exists dg-do-what-default] {
+	set esan_saved_dg-do-what-default ${dg-do-what-default}
+    }
+    if [info exists TEST_ALWAYS_FLAGS] {
+	set esan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
+    }
+    if [info exists ALWAYS_CXXFLAGS] {
+	set esan_saved_ALWAYS_CXXFLAGS $ALWAYS_CXXFLAGS
+	set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
+	set ALWAYS_CXXFLAGS [concat "{additional_flags=-fsanitize=efficiency-working-set -g}" $ALWAYS_CXXFLAGS]
+    } else {
+	if [info exists TEST_ALWAYS_FLAGS] {
+	    set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=efficiency-working-set -g $TEST_ALWAYS_FLAGS"
+	} else {
+	    set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=efficiency-working-set -g"
+	}
+    }
+}
+
+#
+# esan_finish -- called at the end of each subdir of tests
+#
+
+proc esan_finish { args } {
+    global TEST_ALWAYS_FLAGS
+    global esan_saved_TEST_ALWAYS_FLAGS
+    global esan_saved_ALWAYS_CXXFLAGS
+    global dg-do-what-default
+    global esan_saved_dg-do-what-default
+    global esan_saved_library_path
+    global ld_library_path
+
+    if [info exists esan_saved_ALWAYS_CXXFLAGS ] {
+	set ALWAYS_CXXFLAGS $esan_saved_ALWAYS_CXXFLAGS
+    } else {
+	if [info exists esan_saved_TEST_ALWAYS_FLAGS] {
+	    set TEST_ALWAYS_FLAGS $esan_saved_TEST_ALWAYS_FLAGS
+        } else {
+	    unset TEST_ALWAYS_FLAGS
+        }
+    }
+
+    if [info exists esan_saved_dg-do-what-default] {
+	set dg-do-what-default ${esan_saved_dg-do-what-default}
+    } else {
+	unset dg-do-what-default
+    }
+    set ld_library_path $esan_saved_library_path
+    set_ld_library_path_env_vars
+    clear_effective_target_cache
+}
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 9fb83d4..c8e6ef0 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -67,6 +67,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "asan.h"
 #include "tsan.h"
+#include "esan.h"
 #include "plugin.h"
 #include "context.h"
 #include "pass_manager.h"
@@ -507,6 +508,10 @@  compile_file (void)
       if (flag_sanitize & SANITIZE_THREAD)
 	tsan_finish_file ();
 
+      if (flag_sanitize &
+          (SANITIZE_EFFICIENCY_WORKING_SET | SANITIZE_EFFICIENCY_CACHE_FRAG))
+        esan_finish_file ();
+
       omp_finish_file ();
 
       hsa_output_brig ();
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index af15adc..5e395aa 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -343,6 +343,8 @@  extern gimple_opt_pass *make_pass_asan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_asan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan_O0 (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_esan (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_esan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_sancov (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_sancov_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_lower_cf (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 032e79b..ac46fd8 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -1972,6 +1972,7 @@  call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref)
       case IFN_UBSAN_OBJECT_SIZE:
       case IFN_UBSAN_PTR:
       case IFN_ASAN_CHECK:
+      case IFN_ESAN_RECORD_ACCESS:
 	return false;
       default:
 	break;
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index 7bff676..588b202 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -861,6 +861,7 @@  get_expr_operands (struct function *fn, gimple *stmt, tree *expr_p, int flags)
     case LABEL_DECL:
     case CONST_DECL:
     case CASE_LABEL_EXPR:
+    case FIELD_DECL:
       /* Expressions that make no memory references.  */
       return;
 
diff --git a/libsanitizer/Makefile.am b/libsanitizer/Makefile.am
index 018f0b0..b50ff10 100644
--- a/libsanitizer/Makefile.am
+++ b/libsanitizer/Makefile.am
@@ -22,6 +22,11 @@  nodist_saninclude_HEADERS += \
 if TSAN_SUPPORTED
 SUBDIRS += tsan
 endif
+if ESAN_SUPPORTED
+SUBDIRS += esan
+nodist_saninclude_HEADERS += \
+  include/sanitizer/esan_interface.h
+endif
 endif
 
 ## May be used by toolexeclibdir.
diff --git a/libsanitizer/Makefile.in b/libsanitizer/Makefile.in
index a9fea21e..aae9957 100644
--- a/libsanitizer/Makefile.in
+++ b/libsanitizer/Makefile.in
@@ -59,6 +59,10 @@  target_triplet = @target@
 @SANITIZER_SUPPORTED_TRUE@@USING_MAC_INTERPOSE_FALSE@am__append_2 = interception
 @LIBBACKTRACE_SUPPORTED_TRUE@@SANITIZER_SUPPORTED_TRUE@am__append_3 = libbacktrace
 @SANITIZER_SUPPORTED_TRUE@@TSAN_SUPPORTED_TRUE@am__append_4 = tsan
+@ESAN_SUPPORTED_TRUE@@SANITIZER_SUPPORTED_TRUE@am__append_5 = esan
+@ESAN_SUPPORTED_TRUE@@SANITIZER_SUPPORTED_TRUE@am__append_6 = \
+@ESAN_SUPPORTED_TRUE@@SANITIZER_SUPPORTED_TRUE@  include/sanitizer/esan_interface.h
+
 subdir = .
 DIST_COMMON = ChangeLog $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/configure $(am__configure_deps) \
@@ -141,7 +145,7 @@  AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = sanitizer_common interception libbacktrace lsan asan \
-	ubsan tsan
+	ubsan tsan esan
 ACLOCAL = @ACLOCAL@
 ALLOC_FILE = @ALLOC_FILE@
 AMTAR = @AMTAR@
@@ -262,6 +266,7 @@  install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libesan = @link_libesan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -292,10 +297,10 @@  top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 sanincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include/sanitizer
-nodist_saninclude_HEADERS = $(am__append_1)
+nodist_saninclude_HEADERS = $(am__append_1) $(am__append_6)
 @SANITIZER_SUPPORTED_TRUE@SUBDIRS = sanitizer_common $(am__append_2) \
 @SANITIZER_SUPPORTED_TRUE@	$(am__append_3) lsan asan ubsan \
-@SANITIZER_SUPPORTED_TRUE@	$(am__append_4)
+@SANITIZER_SUPPORTED_TRUE@	$(am__append_4) $(am__append_5)
 gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in
index 4cf27e7..6d2900a 100644
--- a/libsanitizer/asan/Makefile.in
+++ b/libsanitizer/asan/Makefile.in
@@ -272,6 +272,7 @@  install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libesan = @link_libesan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
diff --git a/libsanitizer/configure b/libsanitizer/configure
index 5836450..805ca3c 100755
--- a/libsanitizer/configure
+++ b/libsanitizer/configure
@@ -623,10 +623,13 @@  SANITIZER_SUPPORTED_FALSE
 SANITIZER_SUPPORTED_TRUE
 USING_MAC_INTERPOSE_FALSE
 USING_MAC_INTERPOSE_TRUE
+link_libesan
 link_liblsan
 link_libubsan
 link_libtsan
 link_libasan
+ESAN_SUPPORTED_FALSE
+ESAN_SUPPORTED_TRUE
 LSAN_SUPPORTED_FALSE
 LSAN_SUPPORTED_TRUE
 TSAN_SUPPORTED_FALSE
@@ -12037,7 +12040,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12040 "configure"
+#line 12043 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12143,7 +12146,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12146 "configure"
+#line 12149 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13308,20 +13311,20 @@  if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 	      prelink_cmds_CXX='tpldir=Template.dir~
 		rm -rf $tpldir~
 		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
-		compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
 	      old_archive_cmds_CXX='tpldir=Template.dir~
 		rm -rf $tpldir~
 		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
-		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
 		$RANLIB $oldlib'
 	      archive_cmds_CXX='tpldir=Template.dir~
 		rm -rf $tpldir~
 		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
 	      archive_expsym_cmds_CXX='tpldir=Template.dir~
 		rm -rf $tpldir~
 		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
 	      ;;
 	    *) # Version 6 and above use weak symbols
 	      archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
@@ -15490,6 +15493,7 @@  fi
 # Get target configury.
 unset TSAN_SUPPORTED
 unset LSAN_SUPPORTED
+unset ESAN_SUPPORTED
 . ${srcdir}/configure.tgt
  if test "x$TSAN_SUPPORTED" = "xyes"; then
   TSAN_SUPPORTED_TRUE=
@@ -15507,6 +15511,14 @@  else
   LSAN_SUPPORTED_FALSE=
 fi
 
+ if test "x$ESAN_SUPPORTED" = "xyes"; then
+  ESAN_SUPPORTED_TRUE=
+  ESAN_SUPPORTED_FALSE='#'
+else
+  ESAN_SUPPORTED_TRUE='#'
+  ESAN_SUPPORTED_FALSE=
+fi
+
 
 # Check for functions needed.
 for ac_func in clock_getres clock_gettime clock_settime lstat readlink
@@ -15628,6 +15640,9 @@  link_libubsan=$link_sanitizer_common
 link_liblsan=$link_sanitizer_common
 
 
+# Set up the set of additional libraries that we need to link against for libesan.
+link_libesan=$link_sanitizer_common
+
 
 # At least for glibc, clock_gettime is in librt.  But don't pull that
 # in if it still doesn't give us the function we want.  This
@@ -16506,6 +16521,11 @@  if test "x$TSAN_SUPPORTED" = "xyes"; then
 
 fi
 
+if test "x$ESAN_SUPPORTED" = "xyes"; then
+  ac_config_files="$ac_config_files esan/Makefile"
+
+fi
+
 
 
 
@@ -16746,6 +16766,10 @@  if test -z "${LSAN_SUPPORTED_TRUE}" && test -z "${LSAN_SUPPORTED_FALSE}"; then
   as_fn_error "conditional \"LSAN_SUPPORTED\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${ESAN_SUPPORTED_TRUE}" && test -z "${ESAN_SUPPORTED_FALSE}"; then
+  as_fn_error "conditional \"ESAN_SUPPORTED\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${USING_MAC_INTERPOSE_TRUE}" && test -z "${USING_MAC_INTERPOSE_FALSE}"; then
   as_fn_error "conditional \"USING_MAC_INTERPOSE\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -17757,6 +17781,7 @@  do
     "asan/Makefile") CONFIG_FILES="$CONFIG_FILES asan/Makefile" ;;
     "ubsan/Makefile") CONFIG_FILES="$CONFIG_FILES ubsan/Makefile" ;;
     "tsan/Makefile") CONFIG_FILES="$CONFIG_FILES tsan/Makefile" ;;
+    "esan/Makefile") CONFIG_FILES="$CONFIG_FILES esan/Makefile" ;;
 
   *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
@@ -19703,6 +19728,17 @@  _EOF
     . ${multi_basedir}/config-ml.in
     { ml_norecursion=; unset ml_norecursion;}
  ;;
+    "esan/Makefile":F) cat > vpsed$$ << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+    sed -f vpsed$$ $ac_file > tmp$$
+    mv tmp$$ $ac_file
+    rm vpsed$$
+    echo 'MULTISUBDIR =' >> $ac_file
+    ml_norecursion=yes
+    . ${multi_basedir}/config-ml.in
+    { ml_norecursion=; unset ml_norecursion;}
+ ;;
 
   esac
 done # for ac_tag
diff --git a/libsanitizer/configure.ac b/libsanitizer/configure.ac
index 34ba09f..0f1e756 100644
--- a/libsanitizer/configure.ac
+++ b/libsanitizer/configure.ac
@@ -88,9 +88,11 @@  fi
 # Get target configury.
 unset TSAN_SUPPORTED
 unset LSAN_SUPPORTED
+unset ESAN_SUPPORTED
 . ${srcdir}/configure.tgt
 AM_CONDITIONAL(TSAN_SUPPORTED, [test "x$TSAN_SUPPORTED" = "xyes"])
 AM_CONDITIONAL(LSAN_SUPPORTED, [test "x$LSAN_SUPPORTED" = "xyes"])
+AM_CONDITIONAL(ESAN_SUPPORTED, [test "x$ESAN_SUPPORTED" = "xyes"])
 
 # Check for functions needed.
 AC_CHECK_FUNCS(clock_getres clock_gettime clock_settime lstat readlink)
@@ -124,6 +126,9 @@  AC_SUBST(link_libubsan)
 link_liblsan=$link_sanitizer_common
 AC_SUBST(link_liblsan)
 
+# Set up the set of additional libraries that we need to link against for libesan.
+link_libesan=$link_sanitizer_common
+AC_SUBST(link_libesan)
 
 # At least for glibc, clock_gettime is in librt.  But don't pull that
 # in if it still doesn't give us the function we want.  This
@@ -374,6 +379,21 @@  _EOF
 ])
 fi
 
+if test "x$ESAN_SUPPORTED" = "xyes"; then
+  AC_CONFIG_FILES(AC_FOREACH([DIR], [esan], [DIR/Makefile ]),
+    [cat > vpsed$$ << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+    sed -f vpsed$$ $ac_file > tmp$$
+    mv tmp$$ $ac_file
+    rm vpsed$$
+    echo 'MULTISUBDIR =' >> $ac_file
+    ml_norecursion=yes
+    . ${multi_basedir}/config-ml.in
+    AS_UNSET([ml_norecursion])
+])
+fi
+
 AC_SUBST([TSAN_TARGET_DEPENDENT_OBJECTS])
 AC_SUBST([SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS])
 
diff --git a/libsanitizer/configure.tgt b/libsanitizer/configure.tgt
index 1dce1e6..cd2a896 100644
--- a/libsanitizer/configure.tgt
+++ b/libsanitizer/configure.tgt
@@ -26,6 +26,7 @@  case "${target}" in
 	if test x$ac_cv_sizeof_void_p = x8; then
 		TSAN_SUPPORTED=yes
 		LSAN_SUPPORTED=yes
+                ESAN_SUPPORTED=yes
 		TSAN_TARGET_DEPENDENT_OBJECTS=tsan_rtl_amd64.lo
 	fi
 	if echo "int x = __x86_64__;" | $CC -c -x c -o /dev/null - > /dev/null 2>&1; then
@@ -44,6 +45,7 @@  case "${target}" in
   s390*-*-linux*)
 	;;
   arm*-*-linux*)
+        ESAN_SUPPORTED=yes
 	;;
   mips*64*-*-linux*)
 	# This clause is only here to not match the supported mips*-*-linux*.
@@ -60,6 +62,7 @@  case "${target}" in
 	;;
   x86_64-*-darwin[1]* | i?86-*-darwin[1]*)
 	TSAN_SUPPORTED=no
+        ESAN_SUPPORTED=no
 	;;
   *)
 	UNSUPPORTED=1
diff --git a/libsanitizer/esan/Makefile.am b/libsanitizer/esan/Makefile.am
new file mode 100644
index 0000000..9264b9b
--- /dev/null
+++ b/libsanitizer/esan/Makefile.am
@@ -0,0 +1,78 @@ 
+AM_CPPFLAGS = -I $(top_srcdir) -I $(top_srcdir)/include
+
+# May be used by toolexeclibdir.
+gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DPIC
+AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
+AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+AM_CXXFLAGS += -std=gnu++11
+AM_CXXFLAGS += $(EXTRA_CXXFLAGS)
+ACLOCAL_AMFLAGS = -I m4
+
+toolexeclib_LTLIBRARIES = libesan.la
+
+esan_files = \
+	esan.cpp \
+	esan_flags.cpp \
+	esan_interface.cpp \
+	esan_interceptors.cpp \
+	esan_linux.cpp \
+	esan_sideline_linux.cpp \
+	cache_frag.cpp \
+	working_set.cpp \
+	working_set_posix.cpp
+
+libesan_la_SOURCES = $(esan_files)
+libesan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la
+if !USING_MAC_INTERPOSE
+libesan_la_LIBADD += $(top_builddir)/interception/libinterception.la
+endif
+if LIBBACKTRACE_SUPPORTED
+libesan_la_LIBADD += $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la
+endif
+libesan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS)
+libesan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libesan)
+
+# Work around what appears to be a GNU make bug handling MAKEFLAGS
+# values defined in terms of make variables, as is the case for CC and
+# friends when we are called from the top level Makefile.
+AM_MAKEFLAGS = \
+	"AR_FLAGS=$(AR_FLAGS)" \
+	"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
+	"CFLAGS=$(CFLAGS)" \
+	"CXXFLAGS=$(CXXFLAGS)" \
+	"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+	"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+	"INSTALL=$(INSTALL)" \
+	"INSTALL_DATA=$(INSTALL_DATA)" \
+	"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+	"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+	"JC1FLAGS=$(JC1FLAGS)" \
+	"LDFLAGS=$(LDFLAGS)" \
+	"LIBCFLAGS=$(LIBCFLAGS)" \
+	"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+	"MAKE=$(MAKE)" \
+	"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+	"PICFLAG=$(PICFLAG)" \
+	"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+	"SHELL=$(SHELL)" \
+	"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+	"exec_prefix=$(exec_prefix)" \
+	"infodir=$(infodir)" \
+	"libdir=$(libdir)" \
+	"prefix=$(prefix)" \
+	"includedir=$(includedir)" \
+	"AR=$(AR)" \
+	"AS=$(AS)" \
+	"LD=$(LD)" \
+	"LIBCFLAGS=$(LIBCFLAGS)" \
+	"NM=$(NM)" \
+	"PICFLAG=$(PICFLAG)" \
+	"RANLIB=$(RANLIB)" \
+	"DESTDIR=$(DESTDIR)"
+
+MAKEOVERRIDES=
+
+## ################################################################
+
diff --git a/libsanitizer/esan/Makefile.in b/libsanitizer/esan/Makefile.in
new file mode 100644
index 0000000..f71c0a8
--- /dev/null
+++ b/libsanitizer/esan/Makefile.in
@@ -0,0 +1,646 @@ 
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@USING_MAC_INTERPOSE_FALSE@am__append_1 = $(top_builddir)/interception/libinterception.la
+@LIBBACKTRACE_SUPPORTED_TRUE@am__append_2 = $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la
+subdir = esan
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/libstdc++-raw-cxx.m4 \
+	$(top_srcdir)/../config/multi.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/stdint.m4 \
+	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/enable.m4 \
+	$(top_srcdir)/../config/cet.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
+LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libesan_la_DEPENDENCIES =  \
+	$(top_builddir)/sanitizer_common/libsanitizer_common.la \
+	$(am__append_1) $(am__append_2) $(am__DEPENDENCIES_1)
+am__objects_1 = esan.lo esan_flags.lo esan_interface.lo \
+	esan_interceptors.lo esan_linux.lo esan_sideline_linux.lo \
+	cache_frag.lo working_set.lo working_set_posix.lo
+am_libesan_la_OBJECTS = $(am__objects_1)
+libesan_la_OBJECTS = $(am_libesan_la_OBJECTS)
+libesan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libesan_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(libesan_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+ETAGS = etags
+CTAGS = ctags
+ACLOCAL = @ACLOCAL@
+ALLOC_FILE = @ALLOC_FILE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BACKTRACE_SUPPORTED = @BACKTRACE_SUPPORTED@
+BACKTRACE_SUPPORTS_THREADS = @BACKTRACE_SUPPORTS_THREADS@
+BACKTRACE_USES_MALLOC = @BACKTRACE_USES_MALLOC@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DPIC
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXTRA_ASFLAGS = @EXTRA_ASFLAGS@
+EXTRA_CFLAGS = @EXTRA_CFLAGS@
+EXTRA_CXXFLAGS = @EXTRA_CXXFLAGS@
+FGREP = @FGREP@
+FORMAT_FILE = @FORMAT_FILE@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSTDCXX_RAW_CXX_CXXFLAGS = @LIBSTDCXX_RAW_CXX_CXXFLAGS@
+LIBSTDCXX_RAW_CXX_LDFLAGS = @LIBSTDCXX_RAW_CXX_LDFLAGS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TSAN_TARGET_DEPENDENT_OBJECTS = @TSAN_TARGET_DEPENDENT_OBJECTS@
+VERSION = @VERSION@
+VIEW_FILE = @VIEW_FILE@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+link_libasan = @link_libasan@
+link_libesan = @link_libesan@
+link_liblsan = @link_liblsan@
+link_libtsan = @link_libtsan@
+link_libubsan = @link_libubsan@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+multi_basedir = @multi_basedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_noncanonical = @target_noncanonical@
+target_os = @target_os@
+target_vendor = @target_vendor@
+toolexecdir = @toolexecdir@
+toolexeclibdir = @toolexeclibdir@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I $(top_srcdir) -I $(top_srcdir)/include
+
+# May be used by toolexeclibdir.
+gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
+	-Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \
+	-fomit-frame-pointer -funwind-tables -fvisibility=hidden \
+	-Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) \
+	-std=gnu++11 $(EXTRA_CXXFLAGS)
+ACLOCAL_AMFLAGS = -I m4
+toolexeclib_LTLIBRARIES = libesan.la
+esan_files = \
+	esan.cpp \
+	esan_flags.cpp \
+	esan_interface.cpp \
+	esan_interceptors.cpp \
+	esan_linux.cpp \
+	esan_sideline_linux.cpp \
+	cache_frag.cpp \
+	working_set.cpp \
+	working_set_posix.cpp
+
+libesan_la_SOURCES = $(esan_files)
+libesan_la_LIBADD =  \
+	$(top_builddir)/sanitizer_common/libsanitizer_common.la \
+	$(am__append_1) $(am__append_2) $(LIBSTDCXX_RAW_CXX_LDFLAGS)
+libesan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libesan)
+
+# Work around what appears to be a GNU make bug handling MAKEFLAGS
+# values defined in terms of make variables, as is the case for CC and
+# friends when we are called from the top level Makefile.
+AM_MAKEFLAGS = \
+	"AR_FLAGS=$(AR_FLAGS)" \
+	"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
+	"CFLAGS=$(CFLAGS)" \
+	"CXXFLAGS=$(CXXFLAGS)" \
+	"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+	"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+	"INSTALL=$(INSTALL)" \
+	"INSTALL_DATA=$(INSTALL_DATA)" \
+	"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+	"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+	"JC1FLAGS=$(JC1FLAGS)" \
+	"LDFLAGS=$(LDFLAGS)" \
+	"LIBCFLAGS=$(LIBCFLAGS)" \
+	"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+	"MAKE=$(MAKE)" \
+	"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+	"PICFLAG=$(PICFLAG)" \
+	"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+	"SHELL=$(SHELL)" \
+	"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+	"exec_prefix=$(exec_prefix)" \
+	"infodir=$(infodir)" \
+	"libdir=$(libdir)" \
+	"prefix=$(prefix)" \
+	"includedir=$(includedir)" \
+	"AR=$(AR)" \
+	"AS=$(AS)" \
+	"LD=$(LD)" \
+	"LIBCFLAGS=$(LIBCFLAGS)" \
+	"NM=$(NM)" \
+	"PICFLAG=$(PICFLAG)" \
+	"RANLIB=$(RANLIB)" \
+	"DESTDIR=$(DESTDIR)"
+
+MAKEOVERRIDES = 
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign esan/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign esan/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(toolexeclibdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(toolexeclibdir)"; \
+	}
+
+uninstall-toolexeclibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(toolexeclibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(toolexeclibdir)/$$f"; \
+	done
+
+clean-toolexeclibLTLIBRARIES:
+	-test -z "$(toolexeclib_LTLIBRARIES)" || rm -f $(toolexeclib_LTLIBRARIES)
+	@list='$(toolexeclib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libesan.la: $(libesan_la_OBJECTS) $(libesan_la_DEPENDENCIES) $(EXTRA_libesan_la_DEPENDENCIES) 
+	$(libesan_la_LINK) -rpath $(toolexeclibdir) $(libesan_la_OBJECTS) $(libesan_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache_frag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esan_flags.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esan_interceptors.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esan_interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esan_linux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esan_sideline_linux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/working_set.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/working_set_posix.Plo@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(toolexeclibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-toolexeclibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-toolexeclibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-toolexeclibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-toolexeclibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags dvi dvi-am html html-am info info-am install \
+	install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip install-toolexeclibLTLIBRARIES installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-toolexeclibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libsanitizer/esan/cache_frag.cpp b/libsanitizer/esan/cache_frag.cpp
new file mode 100644
index 0000000..47fb638
--- /dev/null
+++ b/libsanitizer/esan/cache_frag.cpp
@@ -0,0 +1,216 @@ 
+//===-- cache_frag.cpp ----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// This file contains cache fragmentation-specific code.
+//===----------------------------------------------------------------------===//
+
+#include "esan.h"
+#include "esan_flags.h"
+#include "sanitizer_common/sanitizer_addrhashmap.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include <string.h>
+
+namespace __esan {
+
+//===-- Struct field access counter runtime -------------------------------===//
+
+// This should be kept consistent with LLVM's EfficiencySanitizer StructInfo.
+struct StructInfo {
+  const char *StructName;
+  u32 Size;
+  u32 NumFields;
+  u32 *FieldOffset;           // auxiliary struct field info.
+  u32 *FieldSize;             // auxiliary struct field info.
+  const char **FieldTypeName; // auxiliary struct field info.
+  u64 *FieldCounters;
+  u64 *ArrayCounter;
+  bool hasAuxFieldInfo() { return FieldOffset != nullptr; }
+};
+
+// This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo.
+// The tool-specific information per compilation unit (module).
+struct CacheFragInfo {
+  const char *UnitName;
+  u32 NumStructs;
+  StructInfo *Structs;
+};
+
+struct StructCounter {
+  StructInfo *Struct;
+  u64 Count; // The total access count of the struct.
+  u64 Ratio; // Difference ratio for the struct layout access.
+};
+
+// We use StructHashMap to keep track of an unique copy of StructCounter.
+typedef AddrHashMap<StructCounter, 31051> StructHashMap;
+struct Context {
+  StructHashMap StructMap;
+  u32 NumStructs;
+  u64 TotalCount; // The total access count of all structs.
+};
+static Context *Ctx;
+
+static void reportStructSummary() {
+  // FIXME: provide a better struct field access summary report.
+  Report("%s: total struct field access count = %llu\n", SanitizerToolName,
+         Ctx->TotalCount);
+}
+
+// FIXME: we are still exploring proper ways to evaluate the difference between
+// struct field counts.  Currently, we use a simple formula to calculate the
+// difference ratio: V1/V2.
+static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) {
+  if (Val2 > Val1) {
+    Swap(Val1, Val2);
+  }
+  if (Val2 == 0)
+    Val2 = 1;
+  return (Val1 / Val2);
+}
+
+static void reportStructCounter(StructHashMap::Handle &Handle) {
+  const u32 TypePrintLimit = 512;
+  const char *type, *start, *end;
+  StructInfo *Struct = Handle->Struct;
+  // Union field address calculation is done via bitcast instead of GEP,
+  // so the count for union is always 0.
+  // We skip the union report to avoid confusion.
+  if (strncmp(Struct->StructName, "union.", 6) == 0)
+    return;
+  // Remove the '.' after class/struct during print.
+  if (strncmp(Struct->StructName, "class.", 6) == 0) {
+    type = "class";
+    start = &Struct->StructName[6];
+  } else {
+    type = "struct";
+    start = &Struct->StructName[7];
+  }
+  // Remove the suffixes with '$' during print.
+  end = strchr(start, '$');
+  if (end == nullptr)
+    return;
+
+  Report("  %s %.*s\n", type, end - start, start);
+  Report("   size = %u, count = %llu, ratio = %llu\n", Struct->Size,
+         Handle->Count, Handle->Ratio);
+  if (Struct->hasAuxFieldInfo()) {
+    for (u32 i = 0; i < Struct->NumFields; ++i) {
+      Report("   #%2u: offset = %u,\t size = %u,"
+             "\t count = %llu,\t type = %.*s\n",
+             i, Struct->FieldOffset[i], Struct->FieldSize[i],
+             Struct->FieldCounters[i], TypePrintLimit, Struct->FieldTypeName[i]);
+    }
+  } else {
+    for (u32 i = 0; i < Struct->NumFields; ++i) {
+      Report("   #%2u: count = %llu\n", i, Struct->FieldCounters[i]);
+    }
+  }
+}
+
+static void computeStructRatio(StructHashMap::Handle &Handle) {
+  Handle->Ratio = 0;
+  Handle->Count = Handle->Struct->FieldCounters[0];
+  for (u32 i = 1; i < Handle->Struct->NumFields; ++i) {
+    Handle->Count += Handle->Struct->FieldCounters[i];
+    Handle->Ratio += computeDifferenceRatio(
+        Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]);
+  }
+  Ctx->TotalCount += Handle->Count;
+  if (Handle->Ratio >= (u64)getFlags()->report_threshold ||
+      (Verbosity() >= 1 && Handle->Count > 0))
+    reportStructCounter(Handle);
+}
+
+static void registerStructInfo(CacheFragInfo *CacheFrag) {
+  for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
+    StructInfo *Struct = &CacheFrag->Structs[i];
+    StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters);
+    if (H.created()) {
+      VPrintf(2, " Register %s: %u fields\n", Struct->StructName,
+              Struct->NumFields);
+      H->Struct = Struct;
+      ++Ctx->NumStructs;
+    } else {
+      VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
+              Struct->NumFields);
+    }
+  }
+}
+
+static void unregisterStructInfo(CacheFragInfo *CacheFrag) {
+  // FIXME: if the library is unloaded before finalizeCacheFrag, we should
+  // collect the result for later report.
+  for (u32 i = 0; i < CacheFrag->NumStructs; ++i) {
+    StructInfo *Struct = &CacheFrag->Structs[i];
+    StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true);
+    if (H.exists()) {
+      VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName,
+              Struct->NumFields);
+      // FIXME: we should move this call to finalizeCacheFrag once we can
+      // iterate over the hash map there.
+      computeStructRatio(H);
+      --Ctx->NumStructs;
+    } else {
+      VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName,
+              Struct->NumFields);
+    }
+  }
+  static bool Reported = false;
+  if (Ctx->NumStructs == 0 && !Reported) {
+    Reported = true;
+    reportStructSummary();
+  }
+}
+
+//===-- Init/exit functions -----------------------------------------------===//
+
+void processCacheFragCompilationUnitInit(void *Ptr) {
+  if (!getFlags()->build_mode) {
+    CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
+    VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
+            CacheFrag->UnitName, CacheFrag->NumStructs);
+    registerStructInfo(CacheFrag);
+  }
+}
+
+void processCacheFragCompilationUnitExit(void *Ptr) {
+  if (!getFlags()->build_mode) {
+    CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr;
+    VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__,
+            CacheFrag->UnitName, CacheFrag->NumStructs);
+    unregisterStructInfo(CacheFrag);
+  }
+}
+
+void initializeCacheFrag() {
+  if (!getFlags()->build_mode) {
+    VPrintf(2, "in esan::%s\n", __FUNCTION__);
+    // We use placement new to initialize Ctx before C++ static initializaion.
+    // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap.
+    static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1];
+    Ctx = new (CtxMem) Context();
+    Ctx->NumStructs = 0;
+  }
+}
+
+int finalizeCacheFrag() {
+  VPrintf(2, "in esan::%s\n", __FUNCTION__);
+  return 0;
+}
+
+void reportCacheFrag() {
+  VPrintf(2, "in esan::%s\n", __FUNCTION__);
+  // FIXME: Not yet implemented.  We need to iterate over all of the
+  // compilation unit data.
+}
+
+} // namespace __esan
diff --git a/libsanitizer/esan/cache_frag.h b/libsanitizer/esan/cache_frag.h
new file mode 100644
index 0000000..646d3f8
--- /dev/null
+++ b/libsanitizer/esan/cache_frag.h
@@ -0,0 +1,29 @@ 
+//===-- cache_frag.h --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Header for cache-fragmentation-specific code.
+//===----------------------------------------------------------------------===//
+
+#ifndef CACHE_FRAG_H
+#define CACHE_FRAG_H
+
+namespace __esan {
+
+void processCacheFragCompilationUnitInit(void *Ptr);
+void processCacheFragCompilationUnitExit(void *Ptr);
+
+void initializeCacheFrag();
+int finalizeCacheFrag();
+void reportCacheFrag();
+
+} // namespace __esan
+
+#endif  // CACHE_FRAG_H
diff --git a/libsanitizer/esan/esan.cpp b/libsanitizer/esan/esan.cpp
new file mode 100644
index 0000000..1f0c302
--- /dev/null
+++ b/libsanitizer/esan/esan.cpp
@@ -0,0 +1,312 @@ 
+//===-- esan.cpp ----------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Main file (entry points) for the Esan run-time.
+//===----------------------------------------------------------------------===//
+
+#include "esan.h"
+#include "esan_flags.h"
+#include "esan_interface_internal.h"
+#include "esan_shadow.h"
+#include "cache_frag.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "working_set.h"
+
+// See comment below.
+extern "C" {
+extern void __cxa_atexit(void (*function)(void));
+}
+
+// Delete this, after supporting Cache fragmentation tool.
+//ToolType __esan_which_tool = ESAN_WorkingSet;
+namespace __esan {
+
+bool EsanIsInitialized;
+bool EsanDuringInit;
+ShadowMapping Mapping;
+
+// Different tools use different scales within the same shadow mapping scheme.
+// The scale used here must match that used by the compiler instrumentation.
+// This array is indexed by the ToolType enum.
+static const uptr ShadowScale[] = {
+  0, // ESAN_None.
+  2, // ESAN_CacheFrag: 4B:1B, so 4 to 1 == >>2.
+  6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6.
+};
+
+// We are combining multiple performance tuning tools under the umbrella of
+// one EfficiencySanitizer super-tool.  Most of our tools have very similar
+// memory access instrumentation, shadow memory mapping, libc interception,
+// etc., and there is typically more shared code than distinct code.
+//
+// We are not willing to dispatch on tool dynamically in our fastpath
+// instrumentation: thus, which tool to use is a static option selected
+// at compile time and passed to __esan_init().
+//
+// We are willing to pay the overhead of tool dispatch in the slowpath to more
+// easily share code.  We expect to only come here rarely.
+// If this becomes a performance hit, we can add separate interface
+// routines for each subtool (e.g., __esan_cache_frag_aligned_load_4).
+// But for libc interceptors, we'll have to do one of the following:
+// A) Add multiple-include support to sanitizer_common_interceptors.inc,
+//    instantiate it separately for each tool, and call the selected
+//    tool's intercept setup code.
+// B) Build separate static runtime libraries, one for each tool.
+// C) Completely split the tools into separate sanitizers.
+
+void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite) {
+  // Could be a shadow fault while building the package on the OBS worker.
+  // So, just disable this by default.
+  if (getFlags()->process_range_access) {
+    VPrintf(3, "in esan::%s %p: %c %p %d\n", __FUNCTION__, PC,
+            IsWrite ? 'w' : 'r', Addr, Size);
+    if (__esan_which_tool == ESAN_CacheFrag) {
+      // TODO(bruening): add shadow mapping and update shadow bits here.
+      // We'll move this to cache_frag.cpp once we have something.
+    } else if (__esan_which_tool == ESAN_WorkingSet) {
+      processRangeAccessWorkingSet(PC, Addr, Size, IsWrite);
+    }
+  }
+}
+
+void incrementFieldCounter(void *Addr) {
+  if (!getFlags()->build_mode) {
+    ++(*(unsigned long int *)Addr);
+  }
+}
+
+bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int)) {
+  if (__esan_which_tool == ESAN_WorkingSet)
+    return processWorkingSetSignal(SigNum, Handler, Result);
+  return true;
+}
+
+bool processSigaction(int SigNum, const void *Act, void *OldAct) {
+  if (__esan_which_tool == ESAN_WorkingSet)
+    return processWorkingSetSigaction(SigNum, Act, OldAct);
+  return true;
+}
+
+bool processSigprocmask(int How, void *Set, void *OldSet) {
+  if (__esan_which_tool == ESAN_WorkingSet)
+    return processWorkingSetSigprocmask(How, Set, OldSet);
+  return true;
+}
+
+#if SANITIZER_DEBUG
+static bool verifyShadowScheme() {
+  // Sanity checks for our shadow mapping scheme.
+  uptr AppStart, AppEnd;
+  if (Verbosity() >= 3) {
+    for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) {
+      VPrintf(3, "App #%d: [%zx-%zx) (%zuGB)\n", i, AppStart, AppEnd,
+              (AppEnd - AppStart) >> 30);
+    }
+  }
+  for (int Scale = 0; Scale < 8; ++Scale) {
+    Mapping.initialize(Scale);
+    if (Verbosity() >= 3) {
+      VPrintf(3, "\nChecking scale %d\n", Scale);
+      uptr ShadowStart, ShadowEnd;
+      for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) {
+        VPrintf(3, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart,
+                ShadowEnd, (ShadowEnd - ShadowStart) >> 30);
+      }
+      for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) {
+        VPrintf(3, "Shadow(Shadow) #%d: [%zx-%zx)\n", i,
+                appToShadow(ShadowStart), appToShadow(ShadowEnd - 1)+1);
+      }
+    }
+    for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) {
+      DCHECK(isAppMem(AppStart));
+      DCHECK(!isAppMem(AppStart - 1));
+      DCHECK(isAppMem(AppEnd - 1));
+      DCHECK(!isAppMem(AppEnd));
+      DCHECK(!isShadowMem(AppStart));
+      DCHECK(!isShadowMem(AppEnd - 1));
+      DCHECK(isShadowMem(appToShadow(AppStart)));
+      DCHECK(isShadowMem(appToShadow(AppEnd - 1)));
+      // Double-shadow checks.
+      DCHECK(!isShadowMem(appToShadow(appToShadow(AppStart))));
+      DCHECK(!isShadowMem(appToShadow(appToShadow(AppEnd - 1))));
+    }
+    // Ensure no shadow regions overlap each other.
+    uptr ShadowAStart, ShadowBStart, ShadowAEnd, ShadowBEnd;
+    for (int i = 0; getShadowRegion(i, &ShadowAStart, &ShadowAEnd); ++i) {
+      for (int j = 0; getShadowRegion(j, &ShadowBStart, &ShadowBEnd); ++j) {
+        DCHECK(i == j || ShadowAStart >= ShadowBEnd ||
+               ShadowAEnd <= ShadowBStart);
+      }
+    }
+  }
+  return true;
+}
+#endif
+
+uptr VmaSize;
+
+static void initializeShadow() {
+  verifyAddressSpace();
+
+  // This is based on the assumption that the intial stack is always allocated
+  // in the topmost segment of the user address space and the assumption
+  // holds true on all the platforms currently supported.
+  VmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+
+  DCHECK(verifyShadowScheme());
+
+  Mapping.initialize(ShadowScale[__esan_which_tool]);
+
+  VPrintf(1, "Shadow scale=%d offset=%p\n", Mapping.Scale, Mapping.Offset);
+
+  uptr ShadowStart, ShadowEnd;
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+  for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) {
+    VPrintf(1, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, ShadowEnd,
+            (ShadowEnd - ShadowStart) >> 30);
+
+    uptr Map;
+    if (__esan_which_tool == ESAN_WorkingSet) {
+      // We want to identify all shadow pages that are touched so we start
+      // out inaccessible.
+      Map = (uptr)MmapFixedNoAccess(ShadowStart, ShadowEnd - ShadowStart,
+                                    "shadow");
+    } else {
+      Map = (uptr)MmapFixedNoReserve(ShadowStart, ShadowEnd - ShadowStart,
+                                     "shadow");
+    }
+    if (Map != ShadowStart) {
+      Printf("FATAL: EfficiencySanitizer failed to map its shadow memory.\n");
+      Die();
+    }
+
+    if (common_flags()->no_huge_pages_for_shadow)
+      NoHugePagesInRegion(ShadowStart, ShadowEnd - ShadowStart);
+    if (common_flags()->use_madv_dontdump)
+      DontDumpShadowMemory(ShadowStart, ShadowEnd - ShadowStart);
+
+    // TODO: Call MmapNoAccess() on in-between regions.
+  }
+#else
+  // ARMVL
+  ShadowStart = 0x20000000;
+  ShadowEnd = 0x3fffffff;
+  uptr Map =
+      (uptr)MmapFixedNoReserve(ShadowStart, ShadowEnd - ShadowStart, "shadow");
+
+  if (Map != ShadowStart) {
+    Printf("FATAL : EfficiencySanitizer failed to map its shadow memory \n");
+    Die();
+  }
+  VPrintf(1, "Shadow [%zx-%zx) (%zuGB)\n", ShadowStart, ShadowEnd,
+          (ShadowEnd - ShadowStart) >> 20);
+
+#endif
+}
+
+void initializeLibrary(ToolType Tool) {
+  // We assume there is only one thread during init, but we need to
+  // guard against double-init when we're (re-)called from an
+  // early interceptor.
+  if (EsanIsInitialized || EsanDuringInit)
+    return;
+  EsanDuringInit = true;
+  CHECK(Tool == __esan_which_tool);
+  SanitizerToolName = "EfficiencySanitizer";
+  CacheBinaryName();
+  initializeFlags();
+
+  // Intercepting libc _exit or exit via COMMON_INTERCEPTOR_ON_EXIT only
+  // finalizes on an explicit exit call by the app.  To handle a normal
+  // exit we register an atexit handler.
+
+  // In case we run sanitized DSO but did not sanitize binary,
+  // we will get an segfault. Also can't set libesan to preload because
+  //__esan__which_tool comes from static DSO constructor, so if we
+  // do not have it, we will get a segfault.
+  if (Tool == ESAN_WorkingSet)
+    ::__cxa_atexit((void (*)())finalizeLibrary);
+
+  VPrintf(1, "in esan::%s\n", __FUNCTION__);
+  if (__esan_which_tool <= ESAN_None || __esan_which_tool >= ESAN_Max) {
+    Printf("ERROR: unknown tool %d requested\n", __esan_which_tool);
+    Die();
+  }
+
+  if (__esan_which_tool == ESAN_WorkingSet) {
+    initializeShadow();
+    initializeShadowWorkingSet();
+  }
+
+  initializeInterceptors();
+
+  if (__esan_which_tool == ESAN_CacheFrag) {
+    initializeCacheFrag();
+  } else if (__esan_which_tool == ESAN_WorkingSet) {
+    initializeWorkingSet();
+  }
+
+  EsanIsInitialized = true;
+  EsanDuringInit = false;
+}
+
+int finalizeLibrary() {
+  VPrintf(1, "in esan::%s\n", __FUNCTION__);
+  if (__esan_which_tool == ESAN_CacheFrag) {
+    return finalizeCacheFrag();
+  } else if (__esan_which_tool == ESAN_WorkingSet) {
+    return finalizeWorkingSet();
+  }
+  return 0;
+}
+
+void reportResults() {
+  VPrintf(1, "in esan::%s\n", __FUNCTION__);
+  if (__esan_which_tool == ESAN_CacheFrag) {
+    return reportCacheFrag();
+  } else if (__esan_which_tool == ESAN_WorkingSet) {
+    return reportWorkingSet();
+  }
+}
+
+void processCompilationUnitInit(void *Ptr) {
+  VPrintf(2, "in esan::%s\n", __FUNCTION__);
+  if (__esan_which_tool == ESAN_CacheFrag) {
+    DCHECK(Ptr != nullptr);
+    processCacheFragCompilationUnitInit(Ptr);
+  } else {
+    DCHECK(Ptr == nullptr);
+  }
+}
+
+// This is called when the containing module is unloaded.
+// For the main executable module, this is called after finalizeLibrary.
+void processCompilationUnitExit(void *Ptr) {
+  VPrintf(2, "in esan::%s\n", __FUNCTION__);
+  if (__esan_which_tool == ESAN_CacheFrag) {
+    DCHECK(Ptr != nullptr);
+    processCacheFragCompilationUnitExit(Ptr);
+  } else {
+    DCHECK(Ptr == nullptr);
+  }
+}
+
+unsigned int getSampleCount() {
+  VPrintf(1, "in esan::%s\n", __FUNCTION__);
+  if (__esan_which_tool == ESAN_WorkingSet) {
+    return getSampleCountWorkingSet();
+  }
+  return 0;
+}
+
+} // namespace __esan
diff --git a/libsanitizer/esan/esan.h b/libsanitizer/esan/esan.h
new file mode 100644
index 0000000..bb5ea9a
--- /dev/null
+++ b/libsanitizer/esan/esan.h
@@ -0,0 +1,62 @@ 
+//===-- esan.h --------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Main internal esan header file.
+//
+// Ground rules:
+//   - C++ run-time should not be used (static CTORs, RTTI, exceptions, static
+//     function-scope locals)
+//   - All functions/classes/etc reside in namespace __esan, except for those
+//     declared in esan_interface_internal.h.
+//   - Platform-specific files should be used instead of ifdefs (*).
+//   - No system headers included in header files (*).
+//   - Platform specific headers included only into platform-specific files (*).
+//
+//  (*) Except when inlining is critical for performance.
+//===----------------------------------------------------------------------===//
+
+#ifndef ESAN_H
+#define ESAN_H
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "esan_interface_internal.h"
+
+namespace __esan {
+
+extern bool EsanIsInitialized;
+extern bool EsanDuringInit;
+extern uptr VmaSize;
+
+void initializeLibrary(ToolType Tool);
+int finalizeLibrary();
+void reportResults();
+unsigned int getSampleCount();
+// Esan creates the variable per tool per compilation unit at compile time
+// and passes its pointer Ptr to the runtime library.
+void processCompilationUnitInit(void *Ptr);
+void processCompilationUnitExit(void *Ptr);
+void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite);
+void initializeInterceptors();
+void incrementFieldCounter(void *Addr);
+
+// Platform-dependent routines.
+void verifyAddressSpace();
+bool fixMmapAddr(void **Addr, SIZE_T Size, int Flags);
+uptr checkMmapResult(uptr Addr, SIZE_T Size);
+// The return value indicates whether to call the real version or not.
+bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int));
+bool processSigaction(int SigNum, const void *Act, void *OldAct);
+bool processSigprocmask(int How, void *Set, void *OldSet);
+
+} // namespace __esan
+
+#endif // ESAN_H
diff --git a/libsanitizer/esan/esan.syms.extra b/libsanitizer/esan/esan.syms.extra
new file mode 100644
index 0000000..d6397d4
--- /dev/null
+++ b/libsanitizer/esan/esan.syms.extra
@@ -0,0 +1,4 @@ 
+__esan_init
+__esan_exit
+__esan_aligned*
+__esan_unaligned*
diff --git a/libsanitizer/esan/esan_circular_buffer.h b/libsanitizer/esan/esan_circular_buffer.h
new file mode 100644
index 0000000..9ce102d
--- /dev/null
+++ b/libsanitizer/esan/esan_circular_buffer.h
@@ -0,0 +1,96 @@ 
+//===-- esan_circular_buffer.h ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Circular buffer data structure.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __esan {
+
+// A circular buffer for POD data whose memory is allocated using mmap.
+// There are two usage models: one is to use initialize/free (for global
+// instances) and the other is to use placement new with the
+// constructor and to call the destructor or free (they are equivalent).
+template<typename T>
+class CircularBuffer {
+ public:
+  // To support global instances we cannot initialize any field in the
+  // default constructor.
+  explicit CircularBuffer() {}
+  CircularBuffer(uptr BufferCapacity) {
+    initialize(BufferCapacity);
+    WasConstructed = true;
+  }
+  ~CircularBuffer() {
+    if (WasConstructed) // Else caller will call free() explicitly.
+      free();
+  }
+  void initialize(uptr BufferCapacity) {
+    Capacity = BufferCapacity;
+    // MmapOrDie rounds up to the page size for us.
+    Data = (T *)MmapOrDie(Capacity * sizeof(T), "CircularBuffer");
+    StartIdx = 0;
+    Count = 0;
+    WasConstructed = false;
+  }
+  void free() {
+    UnmapOrDie(Data, Capacity * sizeof(T));
+  }
+  T &operator[](uptr Idx) {
+    CHECK_LT(Idx, Count);
+    uptr ArrayIdx = (StartIdx + Idx) % Capacity;
+    return Data[ArrayIdx];
+  }
+  const T &operator[](uptr Idx) const {
+    CHECK_LT(Idx, Count);
+    uptr ArrayIdx = (StartIdx + Idx) % Capacity;
+    return Data[ArrayIdx];
+  }
+  void push_back(const T &Item) {
+    CHECK_GT(Capacity, 0);
+    uptr ArrayIdx = (StartIdx + Count) % Capacity;
+    Data[ArrayIdx] = Item;
+    if (Count < Capacity)
+      ++Count;
+    else
+      StartIdx = (StartIdx + 1) % Capacity;
+  }
+  T &back() {
+    CHECK_GT(Count, 0);
+    uptr ArrayIdx = (StartIdx + Count - 1) % Capacity;
+    return Data[ArrayIdx];
+  }
+  void pop_back() {
+    CHECK_GT(Count, 0);
+    --Count;
+  }
+  uptr size() const {
+    return Count;
+  }
+  void clear() {
+    StartIdx = 0;
+    Count = 0;
+  }
+  bool empty() const { return size() == 0; }
+
+ private:
+  CircularBuffer(const CircularBuffer&);
+  void operator=(const CircularBuffer&);
+
+  bool WasConstructed;
+  T *Data;
+  uptr Capacity;
+  uptr StartIdx;
+  uptr Count;
+};
+
+} // namespace __esan
diff --git a/libsanitizer/esan/esan_flags.cpp b/libsanitizer/esan/esan_flags.cpp
new file mode 100644
index 0000000..c90bf24
--- /dev/null
+++ b/libsanitizer/esan/esan_flags.cpp
@@ -0,0 +1,60 @@ 
+//===-- esan_flags.cc -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Esan flag parsing logic.
+//===----------------------------------------------------------------------===//
+
+#include "esan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+using namespace __sanitizer;
+
+namespace __esan {
+
+static const char EsanOptsEnv[] = "ESAN_OPTIONS";
+
+Flags EsanFlagsDontUseDirectly;
+
+void Flags::setDefaults() {
+#define ESAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "esan_flags.inc"
+#undef ESAN_FLAG
+}
+
+static void registerEsanFlags(FlagParser *Parser, Flags *F) {
+#define ESAN_FLAG(Type, Name, DefaultValue, Description) \
+  RegisterFlag(Parser, #Name, Description, &F->Name);
+#include "esan_flags.inc"
+#undef ESAN_FLAG
+}
+
+void initializeFlags() {
+  SetCommonFlagsDefaults();
+  Flags *F = getFlags();
+  F->setDefaults();
+
+  FlagParser Parser;
+  registerEsanFlags(&Parser, F);
+  RegisterCommonFlags(&Parser);
+  Parser.ParseString(GetEnv(EsanOptsEnv));
+
+  InitializeCommonFlags();
+  if (Verbosity())
+    ReportUnrecognizedFlags();
+  if (common_flags()->help)
+    Parser.PrintFlagDescriptions();
+
+  __sanitizer_set_report_path(common_flags()->log_path);
+}
+
+} // namespace __esan
diff --git a/libsanitizer/esan/esan_flags.h b/libsanitizer/esan/esan_flags.h
new file mode 100644
index 0000000..c8f4ef5
--- /dev/null
+++ b/libsanitizer/esan/esan_flags.h
@@ -0,0 +1,41 @@ 
+//===-- esan_flags.h --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Esan runtime flags.
+//===----------------------------------------------------------------------===//
+
+#ifndef ESAN_FLAGS_H
+#define ESAN_FLAGS_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+
+namespace __esan {
+
+class Flags {
+public:
+#define ESAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "esan_flags.inc"
+#undef ESAN_FLAG
+
+  void setDefaults();
+};
+
+extern Flags EsanFlagsDontUseDirectly;
+inline Flags *getFlags() {
+  return &EsanFlagsDontUseDirectly;
+}
+
+void initializeFlags();
+
+} // namespace __esan
+
+#endif // ESAN_FLAGS_H
diff --git a/libsanitizer/esan/esan_flags.inc b/libsanitizer/esan/esan_flags.inc
new file mode 100644
index 0000000..231abd4
--- /dev/null
+++ b/libsanitizer/esan/esan_flags.inc
@@ -0,0 +1,59 @@ 
+//===-- esan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Esan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ESAN_FLAG
+# error "Define ESAN_FLAG prior to including this file!"
+#endif
+
+// ESAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
+
+//===----------------------------------------------------------------------===//
+// Cross-tool options
+//===----------------------------------------------------------------------===//
+
+ESAN_FLAG(int, cache_line_size, 64,
+          "The number of bytes in a cache line.  For the working-set tool, this "
+          "cannot be changed without also changing the compiler "
+          "instrumentation.")
+
+ESAN_FLAG(bool, process_range_access, true,
+          "Process range access.")
+
+//===----------------------------------------------------------------------===//
+// Working set tool options
+//===----------------------------------------------------------------------===//
+
+ESAN_FLAG(bool, record_snapshots, true,
+          "Working set tool: whether to sample snapshots during a run.")
+
+// Typical profiling uses a 10ms timer.  Our snapshots take some work
+// to scan memory so we reduce to 20ms.
+// To disable samples, turn off record_snapshots.
+ESAN_FLAG(int, sample_freq, 20,
+          "Working set tool: sampling frequency in milliseconds.")
+
+// This controls the difference in frequency between each successive series
+// of snapshots.  There are 8 in total, with number 0 using sample_freq.
+// Number N samples number N-1 every (1 << snapshot_step) instance of N-1.
+ESAN_FLAG(int, snapshot_step, 2, "Working set tool: the log of the sampling "
+          "performed for the next-higher-frequency snapshot series.")
+
+//===----------------------------------------------------------------------===//
+// Cache Fragmentation tool options
+//===----------------------------------------------------------------------===//
+ESAN_FLAG(bool, build_mode, false, "Don't output any info under the build\n")
+// The difference information of a struct is reported if the struct's difference
+// score is greater than the report_threshold.
+ESAN_FLAG(int, report_threshold, 1<<10, "Cache-frag tool: the struct difference"
+          " score threshold for reporting.")
diff --git a/libsanitizer/esan/esan_hashtable.h b/libsanitizer/esan/esan_hashtable.h
new file mode 100644
index 0000000..7bd8297
--- /dev/null
+++ b/libsanitizer/esan/esan_hashtable.h
@@ -0,0 +1,381 @@ 
+//===-- esan_hashtable.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Generic resizing hashtable.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include <stddef.h>
+
+namespace __esan {
+
+//===----------------------------------------------------------------------===//
+// Default hash and comparison functions
+//===----------------------------------------------------------------------===//
+
+template <typename T> struct DefaultHash {
+  size_t operator()(const T &Key) const {
+    return (size_t)Key;
+  }
+};
+
+template <typename T> struct DefaultEqual {
+  bool operator()(const T &Key1, const T &Key2) const {
+    return Key1 == Key2;
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// HashTable declaration
+//===----------------------------------------------------------------------===//
+
+// A simple resizing and mutex-locked hashtable.
+//
+// If the default hash functor is used, KeyTy must have an operator size_t().
+// If the default comparison functor is used, KeyTy must have an operator ==.
+//
+// By default all operations are internally-synchronized with a mutex, with no
+// synchronization for payloads once hashtable functions return.  If
+// ExternalLock is set to true, the caller should call the lock() and unlock()
+// routines around all hashtable operations and subsequent manipulation of
+// payloads.
+template <typename KeyTy, typename DataTy, bool ExternalLock = false,
+          typename HashFuncTy = DefaultHash<KeyTy>,
+          typename EqualFuncTy = DefaultEqual<KeyTy> >
+class HashTable {
+public:
+  // InitialCapacity must be a power of 2.
+  // ResizeFactor must be between 1 and 99 and indicates the
+  // maximum percentage full that the table should ever be.
+  HashTable(u32 InitialCapacity = 2048, u32 ResizeFactor = 70);
+  ~HashTable();
+  bool lookup(const KeyTy &Key, DataTy &Payload); // Const except for Mutex.
+  bool add(const KeyTy &Key, const DataTy &Payload);
+  bool remove(const KeyTy &Key);
+  u32 size(); // Const except for Mutex.
+  // If the table is internally-synchronized, this lock must not be held
+  // while a hashtable function is called as it will deadlock: the lock
+  // is not recursive.  This is meant for use with externally-synchronized
+  // tables or with an iterator.
+  void lock();
+  void unlock();
+
+private:
+  struct HashEntry {
+    KeyTy Key;
+    DataTy Payload;
+    HashEntry *Next;
+  };
+
+public:
+  struct HashPair {
+    HashPair(KeyTy Key, DataTy Data) : Key(Key), Data(Data) {}
+    KeyTy Key;
+    DataTy Data;
+  };
+
+  // This iterator does not perform any synchronization.
+  // It expects the caller to lock the table across the whole iteration.
+  // Calling HashTable functions while using the iterator is not supported.
+  // The iterator returns copies of the keys and data.
+  class iterator {
+  public:
+    iterator(
+        HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy> *Table);
+    iterator(const iterator &Src) = default;
+    iterator &operator=(const iterator &Src) = default;
+    HashPair operator*();
+    iterator &operator++();
+    iterator &operator++(int);
+    bool operator==(const iterator &Cmp) const;
+    bool operator!=(const iterator &Cmp) const;
+
+  private:
+    iterator(
+        HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy> *Table,
+        int Idx);
+    friend HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>;
+    HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy> *Table;
+    int Idx;
+    HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::HashEntry
+        *Entry;
+  };
+
+  // No erase or insert iterator supported
+  iterator begin();
+  iterator end();
+
+private:
+  void resize();
+
+  HashEntry **Table;
+  u32 Capacity;
+  u32 Entries;
+  const u32 ResizeFactor;
+  BlockingMutex Mutex;
+  const HashFuncTy HashFunc;
+  const EqualFuncTy EqualFunc;
+};
+
+//===----------------------------------------------------------------------===//
+// Hashtable implementation
+//===----------------------------------------------------------------------===//
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::HashTable(
+    u32 InitialCapacity, u32 ResizeFactor)
+    : Capacity(InitialCapacity), Entries(0), ResizeFactor(ResizeFactor),
+      HashFunc(HashFuncTy()), EqualFunc(EqualFuncTy()) {
+  CHECK(IsPowerOfTwo(Capacity));
+  CHECK(ResizeFactor >= 1 && ResizeFactor <= 99);
+  Table = (HashEntry **)InternalAlloc(Capacity * sizeof(HashEntry *));
+  internal_memset(Table, 0, Capacity * sizeof(HashEntry *));
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::~HashTable() {
+  for (u32 i = 0; i < Capacity; ++i) {
+    HashEntry *Entry = Table[i];
+    while (Entry != nullptr) {
+      HashEntry *Next = Entry->Next;
+      Entry->Payload.~DataTy();
+      InternalFree(Entry);
+      Entry = Next;
+    }
+  }
+  InternalFree(Table);
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+u32 HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::size() {
+  u32 Res;
+  if (!ExternalLock)
+    Mutex.Lock();
+  Res = Entries;
+  if (!ExternalLock)
+    Mutex.Unlock();
+  return Res;
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+bool HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::lookup(
+    const KeyTy &Key, DataTy &Payload) {
+  if (!ExternalLock)
+    Mutex.Lock();
+  bool Found = false;
+  size_t Hash = HashFunc(Key) % Capacity;
+  HashEntry *Entry = Table[Hash];
+  for (; Entry != nullptr; Entry = Entry->Next) {
+    if (EqualFunc(Entry->Key, Key)) {
+      Payload = Entry->Payload;
+      Found = true;
+      break;
+    }
+  }
+  if (!ExternalLock)
+    Mutex.Unlock();
+  return Found;
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+void HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::resize() {
+  if (!ExternalLock)
+    Mutex.CheckLocked();
+  size_t OldCapacity = Capacity;
+  HashEntry **OldTable = Table;
+  Capacity *= 2;
+  Table = (HashEntry **)InternalAlloc(Capacity * sizeof(HashEntry *));
+  internal_memset(Table, 0, Capacity * sizeof(HashEntry *));
+  // Re-hash
+  for (u32 i = 0; i < OldCapacity; ++i) {
+    HashEntry *OldEntry = OldTable[i];
+    while (OldEntry != nullptr) {
+      HashEntry *Next = OldEntry->Next;
+      size_t Hash = HashFunc(OldEntry->Key) % Capacity;
+      OldEntry->Next = Table[Hash];
+      Table[Hash] = OldEntry;
+      OldEntry = Next;
+    }
+  }
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+bool HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::add(
+    const KeyTy &Key, const DataTy &Payload) {
+  if (!ExternalLock)
+    Mutex.Lock();
+  bool Exists = false;
+  size_t Hash = HashFunc(Key) % Capacity;
+  HashEntry *Entry = Table[Hash];
+  for (; Entry != nullptr; Entry = Entry->Next) {
+    if (EqualFunc(Entry->Key, Key)) {
+      Exists = true;
+      break;
+    }
+  }
+  if (!Exists) {
+    Entries++;
+    if (Entries * 100 >= Capacity * ResizeFactor) {
+      resize();
+      Hash = HashFunc(Key) % Capacity;
+    }
+    HashEntry *Add = (HashEntry *)InternalAlloc(sizeof(*Add));
+    Add->Key = Key;
+    Add->Payload = Payload;
+    Add->Next = Table[Hash];
+    Table[Hash] = Add;
+  }
+  if (!ExternalLock)
+    Mutex.Unlock();
+  return !Exists;
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+bool HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::remove(
+    const KeyTy &Key) {
+  if (!ExternalLock)
+    Mutex.Lock();
+  bool Found = false;
+  size_t Hash = HashFunc(Key) % Capacity;
+  HashEntry *Entry = Table[Hash];
+  HashEntry *Prev = nullptr;
+  for (; Entry != nullptr; Prev = Entry, Entry = Entry->Next) {
+    if (EqualFunc(Entry->Key, Key)) {
+      Found = true;
+      Entries--;
+      if (Prev == nullptr)
+        Table[Hash] = Entry->Next;
+      else
+        Prev->Next = Entry->Next;
+      Entry->Payload.~DataTy();
+      InternalFree(Entry);
+      break;
+    }
+  }
+  if (!ExternalLock)
+    Mutex.Unlock();
+  return Found;
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+void HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::lock() {
+  Mutex.Lock();
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+void HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::unlock() {
+  Mutex.Unlock();
+}
+
+//===----------------------------------------------------------------------===//
+// Iterator implementation
+//===----------------------------------------------------------------------===//
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::iterator::
+    iterator(
+        HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy> *Table)
+    : Table(Table), Idx(-1), Entry(nullptr) {
+  operator++();
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::iterator::
+    iterator(
+        HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy> *Table,
+        int Idx)
+    : Table(Table), Idx(Idx), Entry(nullptr) {
+  CHECK(Idx >= (int)Table->Capacity); // Only used to create end().
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+typename HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy,
+                   EqualFuncTy>::HashPair
+    HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::iterator::
+    operator*() {
+  CHECK(Idx >= 0 && Idx < (int)Table->Capacity);
+  CHECK(Entry != nullptr);
+  return HashPair(Entry->Key, Entry->Payload);
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+typename HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy,
+                   EqualFuncTy>::iterator &
+    HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::iterator::
+    operator++() {
+  if (Entry != nullptr)
+    Entry = Entry->Next;
+  while (Entry == nullptr) {
+    ++Idx;
+    if (Idx >= (int)Table->Capacity)
+      break; // At end().
+    Entry = Table->Table[Idx];
+  }
+  return *this;
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+typename HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy,
+                   EqualFuncTy>::iterator &
+    HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::iterator::
+    operator++(int) {
+  iterator Temp(*this);
+  operator++();
+  return Temp;
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+bool HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::iterator::
+operator==(const iterator &Cmp) const {
+  return Cmp.Table == Table && Cmp.Idx == Idx && Cmp.Entry == Entry;
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+bool HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::iterator::
+operator!=(const iterator &Cmp) const {
+  return Cmp.Table != Table || Cmp.Idx != Idx || Cmp.Entry != Entry;
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+typename HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy,
+                   EqualFuncTy>::iterator
+HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::begin() {
+  return iterator(this);
+}
+
+template <typename KeyTy, typename DataTy, bool ExternalLock,
+          typename HashFuncTy, typename EqualFuncTy>
+typename HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy,
+                   EqualFuncTy>::iterator
+HashTable<KeyTy, DataTy, ExternalLock, HashFuncTy, EqualFuncTy>::end() {
+  return iterator(this, Capacity);
+}
+
+} // namespace __esan
diff --git a/libsanitizer/esan/esan_interceptors.cpp b/libsanitizer/esan/esan_interceptors.cpp
new file mode 100644
index 0000000..e3ff80f
--- /dev/null
+++ b/libsanitizer/esan/esan_interceptors.cpp
@@ -0,0 +1,556 @@ 
+//===-- esan_interceptors.cpp ---------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Interception routines for the esan run-time.
+//===----------------------------------------------------------------------===//
+
+#include "esan.h"
+#include "esan_shadow.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+using namespace __esan; // NOLINT
+
+#define CUR_PC() (StackTrace::GetCurrentPc())
+
+//===----------------------------------------------------------------------===//
+// Interception via sanitizer common interceptors
+//===----------------------------------------------------------------------===//
+
+// Get the per-platform defines for what is possible to intercept
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+
+DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
+
+// TODO(bruening): tsan disables several interceptors (getpwent, etc.) claiming
+// that interception is a perf hit: should we do the same?
+
+// We don't need to intercept this.
+#undef SANITIZER_INTERCEPT_TLS_GET_ADDR
+#undef SANITIZER_INTERCEPT_FORTIFY_SOURCE
+
+// TODO(bruening): the common realpath interceptor assumes malloc is
+// intercepted!  We should try to parametrize that, though we'll
+// intercept malloc soon ourselves and can then remove this undef.
+#undef SANITIZER_INTERCEPT_REALPATH
+
+// We provide our own version:
+#undef SANITIZER_INTERCEPT_SIGPROCMASK
+
+// Could cause a segfault see: https://github.com/google/sanitizers/issues/321.
+#undef SANITIZER_INTERCEPT_CLOCK_GETTIME
+
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!EsanIsInitialized)
+
+#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
+#define COMMON_INTERCEPT_FUNCTION_VER(name, ver)                          \
+  INTERCEPT_FUNCTION_VER(name, ver)
+
+// We must initialize during early interceptors, to support tcmalloc.
+// This means that for some apps we fully initialize prior to
+// __esan_init() being called.
+// We currently do not use ctx.
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)                               \
+  do {                                                                         \
+    if (UNLIKELY(COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)) {                 \
+      if (!UNLIKELY(EsanDuringInit))                                           \
+        initializeLibrary(__esan_which_tool);                                  \
+      return REAL(func)(__VA_ARGS__);                                          \
+    }                                                                          \
+    ctx = nullptr;                                                             \
+    (void)ctx;                                                                 \
+  } while (false)
+
+#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...)                      \
+  COMMON_INTERCEPTOR_ENTER(ctx, func, __VA_ARGS__)
+
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size)                         \
+  processRangeAccess(CUR_PC(), (uptr)ptr, size, true)
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size)                          \
+  processRangeAccess(CUR_PC(), (uptr)ptr, size, false)
+
+// This is only called if the app explicitly calls exit(), not on
+// a normal exit.
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) finalizeLibrary()
+
+#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path)                          \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(file);                                                              \
+    (void)(path);                                                              \
+  } while (false)
+#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file)                               \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(file);                                                              \
+  } while (false)
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)                    \
+  do {                                                                         \
+    (void)(filename);                                                          \
+    (void)(handle);                                                            \
+  } while (false)
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()                                  \
+  do {                                                                         \
+  } while (false)
+#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u)                                     \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(u);                                                                 \
+  } while (false)
+#define COMMON_INTERCEPTOR_RELEASE(ctx, u)                                     \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(u);                                                                 \
+  } while (false)
+#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path)                              \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(path);                                                              \
+  } while (false)
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd)                                 \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(fd);                                                                \
+  } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd)                                 \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(fd);                                                                \
+  } while (false)
+#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd)                                  \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(fd);                                                                \
+  } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd)                    \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(fd);                                                                \
+    (void)(newfd);                                                             \
+  } while (false)
+#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name)                          \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(name);                                                              \
+  } while (false)
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name)                 \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(thread);                                                            \
+    (void)(name);                                                              \
+  } while (false)
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m)                                  \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(m);                                                                 \
+  } while (false)
+#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m)                                \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(m);                                                                 \
+  } while (false)
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m)                                \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(m);                                                                 \
+  } while (false)
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg)                            \
+  do {                                                                         \
+    (void)(ctx);                                                               \
+    (void)(msg);                                                               \
+  } while (false)
+#define COMMON_INTERCEPTOR_USER_CALLBACK_START()                               \
+  do {                                                                         \
+  } while (false)
+#define COMMON_INTERCEPTOR_USER_CALLBACK_END()                                 \
+  do {                                                                         \
+  } while (false)
+
+#include "sanitizer_common/sanitizer_common_interceptors.inc"
+
+//===----------------------------------------------------------------------===//
+// Syscall interception
+//===----------------------------------------------------------------------===//
+
+// We want the caller's PC b/c unlike the other function interceptors these
+// are separate pre and post functions called around the app's syscall().
+
+#define COMMON_SYSCALL_PRE_READ_RANGE(ptr, size)                               \
+  processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, false)
+
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(ptr, size)                              \
+  do {                                                                         \
+    (void)(ptr);                                                               \
+    (void)(size);                                                              \
+  } while (false)
+
+#define COMMON_SYSCALL_POST_READ_RANGE(ptr, size)                              \
+  do {                                                                         \
+    (void)(ptr);                                                               \
+    (void)(size);                                                              \
+  } while (false)
+
+// The actual amount written is in post, not pre.
+#define COMMON_SYSCALL_POST_WRITE_RANGE(ptr, size)                             \
+  processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, true)
+
+#define COMMON_SYSCALL_ACQUIRE(addr)                                           \
+  do {                                                                         \
+    (void)(addr);                                                              \
+  } while (false)
+#define COMMON_SYSCALL_RELEASE(addr)                                           \
+  do {                                                                         \
+    (void)(addr);                                                              \
+  } while (false)
+#define COMMON_SYSCALL_FD_CLOSE(fd)                                            \
+  do {                                                                         \
+    (void)(fd);                                                                \
+  } while (false)
+#define COMMON_SYSCALL_FD_ACQUIRE(fd)                                          \
+  do {                                                                         \
+    (void)(fd);                                                                \
+  } while (false)
+#define COMMON_SYSCALL_FD_RELEASE(fd)                                          \
+  do {                                                                         \
+    (void)(fd);                                                                \
+  } while (false)
+#define COMMON_SYSCALL_PRE_FORK()                                              \
+  do {                                                                         \
+  } while (false)
+#define COMMON_SYSCALL_POST_FORK(res)                                          \
+  do {                                                                         \
+    (void)(res);                                                               \
+  } while (false)
+
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
+//===----------------------------------------------------------------------===//
+// Custom interceptors
+//===----------------------------------------------------------------------===//
+
+// TODO(bruening): move more of these to the common interception pool as they
+// are shared with tsan and asan.
+// While our other files match LLVM style, here we match sanitizer style as we
+// expect to move these to the common pool.
+
+INTERCEPTOR(char *, strcpy, char *dst, const char *src) { // NOLINT
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strcpy, dst, src);
+  uptr srclen = internal_strlen(src);
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, srclen + 1);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, src, srclen + 1);
+  return REAL(strcpy)(dst, src); // NOLINT
+}
+
+INTERCEPTOR(char *, strncpy, char *dst, char *src, uptr n) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strncpy, dst, src, n);
+  uptr srclen = internal_strnlen(src, n);
+  uptr copied_size = srclen + 1 > n ? n : srclen + 1;
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, copied_size);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, src, copied_size);
+  return REAL(strncpy)(dst, src, n);
+}
+
+INTERCEPTOR(int, open, const char *name, int flags, int mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, open, name, flags, mode);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0);
+  return REAL(open)(name, flags, mode);
+}
+
+#if SANITIZER_LINUX
+INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, open64, name, flags, mode);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0);
+  return REAL(open64)(name, flags, mode);
+}
+#define ESAN_MAYBE_INTERCEPT_OPEN64 INTERCEPT_FUNCTION(open64)
+#else
+#define ESAN_MAYBE_INTERCEPT_OPEN64
+#endif
+
+INTERCEPTOR(int, creat, const char *name, int mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, creat, name, mode);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0);
+  return REAL(creat)(name, mode);
+}
+
+#if SANITIZER_LINUX
+INTERCEPTOR(int, creat64, const char *name, int mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, creat64, name, mode);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0);
+  return REAL(creat64)(name, mode);
+}
+#define ESAN_MAYBE_INTERCEPT_CREAT64 INTERCEPT_FUNCTION(creat64)
+#else
+#define ESAN_MAYBE_INTERCEPT_CREAT64
+#endif
+
+INTERCEPTOR(int, unlink, char *path) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, unlink, path);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0);
+  return REAL(unlink)(path);
+}
+
+INTERCEPTOR(int, puts, const char *s) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, puts, s);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s));
+  return REAL(puts)(s);
+}
+
+INTERCEPTOR(int, rmdir, char *path) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, rmdir, path);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0);
+  return REAL(rmdir)(path);
+}
+
+//===----------------------------------------------------------------------===//
+// Shadow-related interceptors
+//===----------------------------------------------------------------------===//
+
+// These are candidates for sharing with all sanitizers if shadow memory
+// support is also standardized.
+
+INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags,
+                 int fd, OFF_T off) {
+  if (UNLIKELY(REAL(mmap) == nullptr)) {
+    // With esan init during interceptor init and a static libc preventing
+    // our early-calloc from triggering, we can end up here before our
+    // REAL pointer is set up.
+    return (void *)internal_mmap(addr, sz, prot, flags, fd, off);
+  }
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off);
+  if (!fixMmapAddr(&addr, sz, flags))
+    return (void *)-1;
+  void *result = REAL(mmap)(addr, sz, prot, flags, fd, off);
+  return (void *)checkMmapResult((uptr)result, sz);
+}
+
+#if SANITIZER_LINUX
+INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags,
+                 int fd, OFF64_T off) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off);
+  if (!fixMmapAddr(&addr, sz, flags))
+    return (void *)-1;
+  void *result = REAL(mmap64)(addr, sz, prot, flags, fd, off);
+  return (void *)checkMmapResult((uptr)result, sz);
+}
+#define ESAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64)
+#else
+#define ESAN_MAYBE_INTERCEPT_MMAP64
+#endif
+
+//===----------------------------------------------------------------------===//
+// Signal-related interceptors
+//===----------------------------------------------------------------------===//
+
+#if SANITIZER_LINUX
+typedef void (*signal_handler_t)(int);
+INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, signal, signum, handler);
+  signal_handler_t result;
+  if (!processSignal(signum, handler, &result))
+    return result;
+  else
+    return REAL(signal)(signum, handler);
+}
+#define ESAN_MAYBE_INTERCEPT_SIGNAL INTERCEPT_FUNCTION(signal)
+#else
+#error Platform not supported
+#define ESAN_MAYBE_INTERCEPT_SIGNAL
+#endif
+
+#if SANITIZER_LINUX
+DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
+             struct sigaction *oldact)
+INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
+            struct sigaction *oldact) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sigaction, signum, act, oldact);
+  if (!processSigaction(signum, act, oldact))
+    return 0;
+  else
+    return REAL(sigaction)(signum, act, oldact);
+}
+
+// This is required to properly use internal_sigaction.
+namespace __sanitizer {
+#if (defined(__x86_64__) || SANITIZER_MIPS64) && !SANITIZER_GO
+int real_sigaction(int signum, const void *act, void *oldact) {
+  if (REAL(sigaction) == nullptr) {
+    // With an instrumented allocator, this is called during interceptor init
+    // and we need a raw syscall solution.
+    return internal_sigaction_syscall(signum, act, oldact);
+  }
+  return REAL(sigaction)(signum, (const struct sigaction *)act,
+                         (struct sigaction *)oldact);
+}
+#endif
+} // namespace __sanitizer
+
+#define ESAN_MAYBE_INTERCEPT_SIGACTION INTERCEPT_FUNCTION(sigaction)
+#else
+#error Platform not supported
+#define ESAN_MAYBE_INTERCEPT_SIGACTION
+#endif
+
+#if SANITIZER_LINUX
+INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
+            __sanitizer_sigset_t *oldset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset);
+  int res = 0;
+  if (processSigprocmask(how, set, oldset))
+    res = REAL(sigprocmask)(how, set, oldset);
+  if (!res && oldset)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
+  return res;
+}
+#define ESAN_MAYBE_INTERCEPT_SIGPROCMASK INTERCEPT_FUNCTION(sigprocmask)
+#else
+#define ESAN_MAYBE_INTERCEPT_SIGPROCMASK
+#endif
+
+//This interceptor causes to crash coreclr
+#if !SANITIZER_WINDOWS && !SANITIZER_LINUX
+INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set,
+            __sanitizer_sigset_t *oldset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pthread_sigmask, how, set, oldset);
+  int res = 0;
+  if (processSigprocmask(how, set, oldset))
+    res = REAL(sigprocmask)(how, set, oldset);
+  if (!res && oldset)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
+  return res;
+}
+#define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK INTERCEPT_FUNCTION(pthread_sigmask)
+#else
+#define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK
+#endif
+
+//===----------------------------------------------------------------------===//
+// Malloc interceptors
+//===----------------------------------------------------------------------===//
+
+static const uptr early_alloc_buf_size = 4096;
+static uptr allocated_bytes;
+static char early_alloc_buf[early_alloc_buf_size];
+
+static bool isInEarlyAllocBuf(const void *ptr) {
+  return ((uptr)ptr >= (uptr)early_alloc_buf &&
+          ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf));
+}
+
+static void *handleEarlyAlloc(uptr size) {
+  // If esan is initialized during an interceptor (which happens with some
+  // tcmalloc implementations that call pthread_mutex_lock), the call from
+  // dlsym to calloc will deadlock.
+  // dlsym may also call malloc before REAL(malloc) is retrieved from dlsym.
+  // We work around it by using a static buffer for the early malloc/calloc
+  // requests.
+  // This solution will also allow us to deliberately intercept malloc & family
+  // in the future (to perform tool actions on each allocation, without
+  // replacing the allocator), as it also solves the problem of intercepting
+  // calloc when it will itself be called before its REAL pointer is
+  // initialized.
+  // We do not handle multiple threads here.  This only happens at process init
+  // time, and while it's possible for a shared library to create early threads
+  // that race here, we consider that to be a corner case extreme enough that
+  // it's not worth the effort to handle.
+  void *mem = (void *)&early_alloc_buf[allocated_bytes];
+  allocated_bytes += size;
+  CHECK_LT(allocated_bytes, early_alloc_buf_size);
+  return mem;
+}
+
+INTERCEPTOR(void*, calloc, uptr size, uptr n) {
+  if (EsanDuringInit && REAL(calloc) == nullptr)
+    return handleEarlyAlloc(size * n);
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, calloc, size, n);
+  void *res = REAL(calloc)(size, n);
+  // The memory is zeroed and thus is all written.
+  COMMON_INTERCEPTOR_WRITE_RANGE(nullptr, (uptr)res, size * n);
+  return res;
+}
+
+INTERCEPTOR(void*, malloc, uptr size) {
+  if (EsanDuringInit && REAL(malloc) == nullptr)
+    return handleEarlyAlloc(size);
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, malloc, size);
+  return REAL(malloc)(size);
+}
+
+INTERCEPTOR(void, free, void *p) {
+  void *ctx;
+  // There are only a few early allocation requests, so we simply skip the free.
+  if (isInEarlyAllocBuf(p))
+    return;
+  COMMON_INTERCEPTOR_ENTER(ctx, free, p);
+  REAL(free)(p);
+}
+
+namespace __esan {
+
+void initializeInterceptors() {
+  InitializeCommonInterceptors();
+
+  INTERCEPT_FUNCTION(strcpy); // NOLINT
+  INTERCEPT_FUNCTION(strncpy);
+
+  INTERCEPT_FUNCTION(open);
+  ESAN_MAYBE_INTERCEPT_OPEN64;
+  INTERCEPT_FUNCTION(creat);
+  ESAN_MAYBE_INTERCEPT_CREAT64;
+  INTERCEPT_FUNCTION(unlink);
+  INTERCEPT_FUNCTION(fread);
+  INTERCEPT_FUNCTION(fwrite);
+  INTERCEPT_FUNCTION(puts);
+  INTERCEPT_FUNCTION(rmdir);
+
+  INTERCEPT_FUNCTION(mmap);
+  ESAN_MAYBE_INTERCEPT_MMAP64;
+
+  ESAN_MAYBE_INTERCEPT_SIGNAL;
+  ESAN_MAYBE_INTERCEPT_SIGACTION;
+  ESAN_MAYBE_INTERCEPT_SIGPROCMASK;
+  ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK;
+
+  INTERCEPT_FUNCTION(calloc);
+  INTERCEPT_FUNCTION(malloc);
+  INTERCEPT_FUNCTION(free);
+
+  // TODO(bruening): intercept routines that other sanitizers intercept that
+  // are not in the common pool or here yet, ideally by adding to the common
+  // pool.  Examples include wcslen and bcopy.
+
+  // TODO(bruening): there are many more libc routines that read or write data
+  // structures that no sanitizer is intercepting: sigaction, strtol, etc.
+}
+
+} // namespace __esan
diff --git a/libsanitizer/esan/esan_interface.cpp b/libsanitizer/esan/esan_interface.cpp
new file mode 100644
index 0000000..0ca0da8
--- /dev/null
+++ b/libsanitizer/esan/esan_interface.cpp
@@ -0,0 +1,122 @@ 
+//===-- esan_interface.cpp ------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+//===----------------------------------------------------------------------===//
+
+#include "esan_interface_internal.h"
+#include "esan.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+using namespace __esan; // NOLINT
+
+void __esan_init(ToolType Tool, void *Ptr) {
+  if (Tool != __esan_which_tool) {
+    Printf("ERROR: tool mismatch: %d vs %d\n", Tool, __esan_which_tool);
+    Die();
+  }
+  initializeLibrary(Tool);
+  processCompilationUnitInit(Ptr);
+}
+
+void __esan_exit(void *Ptr) {
+  processCompilationUnitExit(Ptr);
+}
+
+void __esan_aligned_load1(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, false);
+}
+
+void __esan_aligned_load2(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false);
+}
+
+void __esan_aligned_load4(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false);
+}
+
+void __esan_aligned_load8(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false);
+}
+
+void __esan_aligned_load16(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false);
+}
+
+void __esan_aligned_store1(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, true);
+}
+
+void __esan_aligned_store2(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true);
+}
+
+void __esan_aligned_store4(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true);
+}
+
+void __esan_aligned_store8(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true);
+}
+
+void __esan_aligned_store16(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true);
+}
+
+void __esan_unaligned_load2(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false);
+}
+
+void __esan_unaligned_load4(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false);
+}
+
+void __esan_unaligned_load8(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false);
+}
+
+void __esan_unaligned_load16(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false);
+}
+
+void __esan_unaligned_store2(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true);
+}
+
+void __esan_unaligned_store4(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true);
+}
+
+void __esan_unaligned_store8(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true);
+}
+
+void __esan_unaligned_store16(void *Addr) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true);
+}
+
+void __esan_unaligned_loadN(void *Addr, uptr Size) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, false);
+}
+
+void __esan_unaligned_storeN(void *Addr, uptr Size) {
+  processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, true);
+}
+
+void __esan_increment(void *Addr) { incrementFieldCounter(Addr); }
+
+// Public interface:
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_report() { reportResults(); }
+
+SANITIZER_INTERFACE_ATTRIBUTE unsigned int __esan_get_sample_count() {
+  return getSampleCount();
+}
+} // extern "C"
diff --git a/libsanitizer/esan/esan_interface_internal.h b/libsanitizer/esan/esan_interface_internal.h
new file mode 100644
index 0000000..82311a6
--- /dev/null
+++ b/libsanitizer/esan/esan_interface_internal.h
@@ -0,0 +1,84 @@ 
+//===-- esan_interface_internal.h -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Calls to the functions declared in this header will be inserted by
+// the instrumentation module.
+//===----------------------------------------------------------------------===//
+
+#ifndef ESAN_INTERFACE_INTERNAL_H
+#define ESAN_INTERFACE_INTERNAL_H
+
+#include <sanitizer_common/sanitizer_internal_defs.h>
+
+// This header should NOT include any other headers.
+// All functions in this header are extern "C" and start with __esan_.
+
+using __sanitizer::uptr;
+using __sanitizer::u32;
+
+extern "C" {
+
+// This should be kept consistent with LLVM's EfficiencySanitizerOptions.
+// The value is passed as a 32-bit integer by the compiler.
+typedef enum Type : u32 {
+  ESAN_None = 0,
+  ESAN_CacheFrag,
+  ESAN_WorkingSet,
+  ESAN_Max,
+} ToolType;
+
+// To handle interceptors that invoke instrumented code prior to
+// __esan_init() being called, the instrumentation module creates this
+// global variable specifying the tool.
+extern ToolType __esan_which_tool __attribute__((weak));
+
+// This function should be called at the very beginning of the process,
+// before any instrumented code is executed and before any call to malloc.
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_init(ToolType Tool, void *Ptr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_exit(void *Ptr);
+
+// The instrumentation module will insert a call to one of these routines prior
+// to each load and store instruction for which we do not have "fastpath"
+// inlined instrumentation.  These calls constitute the "slowpath" for our
+// tools.  We have separate routines for each type of memory access to enable
+// targeted optimization.
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load1(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load2(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load4(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load8(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load16(void *Addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store1(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store2(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store4(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store8(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store16(void *Addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load2(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load4(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load8(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load16(void *Addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store2(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store4(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store8(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store16(void *Addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __esan_increment(void *Addr);
+
+// These cover unusually-sized accesses.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __esan_unaligned_loadN(void *Addr, uptr Size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __esan_unaligned_storeN(void *Addr, uptr Size);
+
+} // extern "C"
+
+#endif // ESAN_INTERFACE_INTERNAL_H
diff --git a/libsanitizer/esan/esan_linux.cpp b/libsanitizer/esan/esan_linux.cpp
new file mode 100644
index 0000000..014205c
--- /dev/null
+++ b/libsanitizer/esan/esan_linux.cpp
@@ -0,0 +1,83 @@ 
+//===-- esan.cpp ----------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Linux-specific code for the Esan run-time.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+
+#include "esan.h"
+#include "esan_shadow.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include <sys/mman.h>
+#include <errno.h>
+
+namespace __esan {
+
+void verifyAddressSpace() {
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+  // The kernel determines its mmap base from the stack size limit.
+  // Our Linux 64-bit shadow mapping assumes the stack limit is less than a
+  // terabyte, which keeps the mmap region above 0x7e00'.
+  uptr StackLimit = GetStackSizeLimitInBytes();
+  if (StackSizeIsUnlimited() || StackLimit > MaxStackSize) {
+    VReport(1, "The stack size limit is beyond the maximum supported.\n"
+            "Re-execing with a stack size below 1TB.\n");
+    SetStackSizeLimitInBytes(MaxStackSize);
+    ReExec();
+  }
+#endif
+}
+
+static bool liesWithinSingleAppRegion(uptr Start, SIZE_T Size) {
+  uptr AppStart, AppEnd;
+  for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) {
+    if (Start >= AppStart && Start + Size - 1 <= AppEnd) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool fixMmapAddr(void **Addr, SIZE_T Size, int Flags) {
+  if (*Addr) {
+    if (!liesWithinSingleAppRegion((uptr)*Addr, Size)) {
+      VPrintf(1, "mmap conflict: [%p-%p) is not in an app region\n",
+              *Addr, (uptr)*Addr + Size);
+      if (Flags & MAP_FIXED) {
+        errno = EINVAL;
+        return false;
+      } else {
+        *Addr = 0;
+      }
+    }
+  }
+  return true;
+}
+
+uptr checkMmapResult(uptr Addr, SIZE_T Size) {
+  if ((void *)Addr == MAP_FAILED)
+    return Addr;
+  if (!liesWithinSingleAppRegion(Addr, Size)) {
+    // FIXME: attempt to dynamically add this as an app region if it
+    // fits our shadow criteria.
+    // We could also try to remap somewhere else.
+    Printf("ERROR: unsupported mapping at [%p-%p)\n", Addr, Addr+Size);
+    Die();
+  }
+  return Addr;
+}
+
+} // namespace __esan
+
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/libsanitizer/esan/esan_shadow.h b/libsanitizer/esan/esan_shadow.h
new file mode 100644
index 0000000..c4b0bde
--- /dev/null
+++ b/libsanitizer/esan/esan_shadow.h
@@ -0,0 +1,318 @@ 
+//===-- esan_shadow.h -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Shadow memory mappings for the esan run-time.
+//===----------------------------------------------------------------------===//
+
+#ifndef ESAN_SHADOW_H
+#define ESAN_SHADOW_H
+
+#include "esan.h"
+#include <sanitizer_common/sanitizer_platform.h>
+
+namespace __esan {
+
+struct ApplicationRegion {
+  uptr Start;
+  uptr End;
+  bool ShadowMergedWithPrev;
+};
+
+#if SANITIZER_LINUX && defined(__x86_64__)
+// Linux x86_64
+//
+// Application memory falls into these 5 regions (ignoring the corner case
+// of PIE with a non-zero PT_LOAD base):
+//
+// [0x00000000'00000000, 0x00000100'00000000) non-PIE + heap
+// [0x00005500'00000000, 0x00005700'00000000) PIE
+// [0x00007e00'00000000, 0x00007fff'ff600000) libraries + stack, part 1
+// [0x00007fff'ff601000, 0x00008000'00000000) libraries + stack, part 2
+// [0xffffffff'ff600000, 0xffffffff'ff601000) vsyscall
+//
+// Although we can ignore the vsyscall for the most part as there are few data
+// references there (other sanitizers ignore it), we enforce a gap inside the
+// library region to distinguish the vsyscall's shadow, considering this gap to
+// be an invalid app region.
+// We disallow application memory outside of those 5 regions.
+// Our regions assume that the stack rlimit is less than a terabyte (otherwise
+// the Linux kernel's default mmap region drops below 0x7e00'), which we enforce
+// at init time (we can support larger and unlimited sizes for shadow
+// scaledowns, but it is difficult for 1:1 mappings).
+//
+// Our shadow memory is scaled from a 1:1 mapping and supports a scale
+// specified at library initialization time that can be any power-of-2
+// scaledown (1x, 2x, 4x, 8x, 16x, etc.).
+//
+// We model our shadow memory after Umbra, a library used by the Dr. Memory
+// tool: https://github.com/DynamoRIO/drmemory/blob/master/umbra/umbra_x64.c.
+// We use Umbra's scheme as it was designed to support different
+// offsets, it supports two different shadow mappings (which we may want to
+// use for future tools), and it ensures that the shadow of a shadow will
+// not overlap either shadow memory or application memory.
+//
+// This formula translates from application memory to shadow memory:
+//
+//   shadow(app) = ((app & 0x00000fff'ffffffff) + offset) >> scale
+//
+// Where the offset for 1:1 is 0x00001300'00000000.  For other scales, the
+// offset is shifted left by the scale, except for scales of 1 and 2 where
+// it must be tweaked in order to pass the double-shadow test
+// (see the "shadow(shadow)" comments below):
+//   scale == 0: 0x00001300'000000000
+//   scale == 1: 0x00002200'000000000
+//   scale == 2: 0x00004400'000000000
+//   scale >= 3: (0x00001300'000000000 << scale)
+//
+// Do not pass in the open-ended end value to the formula as it will fail.
+//
+// The resulting shadow memory regions for a 0 scaling are:
+//
+// [0x00001300'00000000, 0x00001400'00000000)
+// [0x00001800'00000000, 0x00001a00'00000000)
+// [0x00002100'00000000, 0x000022ff'ff600000)
+// [0x000022ff'ff601000, 0x00002300'00000000)
+// [0x000022ff'ff600000, 0x000022ff'ff601000]
+//
+// We also want to ensure that a wild access by the application into the shadow
+// regions will not corrupt our own shadow memory.  shadow(shadow) ends up
+// disjoint from shadow(app):
+//
+// [0x00001600'00000000, 0x00001700'00000000)
+// [0x00001b00'00000000, 0x00001d00'00000000)
+// [0x00001400'00000000, 0x000015ff'ff600000]
+// [0x000015ff'ff601000, 0x00001600'00000000]
+// [0x000015ff'ff600000, 0x000015ff'ff601000]
+
+static const struct ApplicationRegion AppRegions[] = {
+  {0x0000000000000000ull, 0x0000010000000000u, false},
+  {0x0000550000000000u,   0x0000570000000000u, false},
+  // We make one shadow mapping to hold the shadow regions for all 3 of these
+  // app regions, as the mappings interleave, and the gap between the 3rd and
+  // 4th scales down below a page.
+  {0x00007e0000000000u,   0x00007fffff600000u, false},
+  {0x00007fffff601000u,   0x0000800000000000u, true},
+  {0xffffffffff600000u,   0xffffffffff601000u, true},
+};
+
+#elif SANITIZER_LINUX && SANITIZER_MIPS64
+
+// Application memory falls into these 3 regions
+//
+// [0x00000001'00000000, 0x00000002'00000000) non-PIE + heap
+// [0x000000aa'00000000, 0x000000ab'00000000) PIE
+// [0x000000ff'00000000, 0x000000ff'ffffffff) libraries + stack
+//
+// This formula translates from application memory to shadow memory:
+//
+//   shadow(app) = ((app & 0x00000f'ffffffff) + offset) >> scale
+//
+// Where the offset for 1:1 is 0x000013'00000000.  For other scales, the
+// offset is shifted left by the scale, except for scales of 1 and 2 where
+// it must be tweaked in order to pass the double-shadow test
+// (see the "shadow(shadow)" comments below):
+//   scale == 0: 0x000013'00000000
+//   scale == 1: 0x000022'00000000
+//   scale == 2: 0x000044'00000000
+//   scale >= 3: (0x000013'00000000 << scale)
+//
+// The resulting shadow memory regions for a 0 scaling are:
+//
+// [0x00000014'00000000, 0x00000015'00000000)
+// [0x0000001d'00000000, 0x0000001e'00000000)
+// [0x00000022'00000000, 0x00000022'ffffffff)
+//
+// We also want to ensure that a wild access by the application into the shadow
+// regions will not corrupt our own shadow memory. shadow(shadow) ends up
+// disjoint from shadow(app):
+//
+// [0x00000017'00000000, 0x00000018'00000000)
+// [0x00000020'00000000, 0x00000021'00000000)
+// [0x00000015'00000000, 0x00000015'ffffffff]
+
+static const struct ApplicationRegion AppRegions[] = {
+    {0x0100000000u, 0x0200000000u, false},
+    {0xaa00000000u, 0xab00000000u, false},
+    {0xff00000000u, 0xffffffffffu, false},
+};
+
+#else
+static const struct ApplicationRegion AppRegions[] = {
+    {0x00000000u, 0x1fffffffu, false},
+    {0x40000000u, 0xffffffffu, false},
+};
+#endif
+
+static const u32 NumAppRegions = sizeof(AppRegions) / sizeof(AppRegions[0]);
+
+// See the comment above: we do not currently support a stack size rlimit
+// equal to or larger than 1TB.
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+static const uptr MaxStackSize = (1ULL << 40) - 4096;
+#else
+static const uptr MaxStackSize = (1ULL << 32) - 4096;
+#endif
+
+class ShadowMapping {
+public:
+  // The scale and offset vary by tool.
+  uptr Scale;
+  uptr Offset;
+
+  // TODO(sagar.thakur): Try to hardcode the mask as done in the compiler
+  // instrumentation to reduce the runtime cost of appToShadow.
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+  struct ShadowMemoryMask40 {
+    static const uptr Mask = 0x0000000fffffffffu;
+  };
+  struct ShadowMemoryMask47 {
+    static const uptr Mask = 0x00000fffffffffffu;
+  };
+#else
+  struct ShadowMemoryMask32 {
+    static const uptr Mask = 0x000fffffu;
+  };
+#endif
+
+  void initialize(uptr ShadowScale) {
+
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+    const uptr OffsetArray40[3] = {
+        0x0000001300000000u,
+        0x0000002200000000u,
+        0x0000004400000000u,
+    };
+    const uptr OffsetArray47[3] = {
+        0x0000130000000000u,
+        0x0000220000000000u,
+        0x0000440000000000u,
+    };
+#endif
+
+    Scale = ShadowScale;
+    switch (VmaSize) {
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+    case 40: {
+      if (Scale <= 2)
+        Offset = OffsetArray40[Scale];
+      else
+        Offset = OffsetArray40[0] << Scale;
+    } break;
+    case 47: {
+      if (Scale <= 2)
+        Offset = OffsetArray47[Scale];
+      else
+        Offset = OffsetArray47[0] << Scale;
+    } break;
+#else
+    case 32: {
+      Offset = 0x20000000; // Low Shadow Address.
+    } break;
+#endif
+    default: {
+      Printf("ERROR: %d-bit virtual memory address size not supported\n",
+             VmaSize);
+      Die();
+    }
+    }
+  }
+};
+
+extern ShadowMapping Mapping;
+
+static inline bool getAppRegion(u32 i, uptr *Start, uptr *End) {
+  if (i >= NumAppRegions)
+    return false;
+  *Start = AppRegions[i].Start;
+  *End = AppRegions[i].End;
+  return true;
+}
+
+ALWAYS_INLINE
+bool isAppMem(uptr Mem) {
+  for (u32 i = 0; i < NumAppRegions; ++i) {
+    if (Mem >= AppRegions[i].Start && Mem < AppRegions[i].End)
+      return true;
+  }
+  return false;
+}
+
+template<typename Params>
+uptr appToShadowImpl(uptr App) {
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+  return (((App & Params::Mask) + Mapping.Offset) >> Mapping.Scale);
+#else
+  return ((App >> Mapping.Scale) + Mapping.Offset);
+#endif
+}
+
+ALWAYS_INLINE
+uptr appToShadow(uptr App) {
+  switch (VmaSize) {
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+  case 40:
+    return appToShadowImpl<ShadowMapping::ShadowMemoryMask40>(App);
+  case 47:
+    return appToShadowImpl<ShadowMapping::ShadowMemoryMask47>(App);
+#else
+  case 32:
+    return appToShadowImpl<ShadowMapping::ShadowMemoryMask32>(App);
+#endif
+  default: {
+    Printf("ERROR: %d-bit virtual memory address size not supported\n",
+           VmaSize);
+    Die();
+  }
+ }
+}
+
+static inline bool getShadowRegion(u32 i, uptr *Start, uptr *End) {
+  if (i >= NumAppRegions)
+    return false;
+  u32 UnmergedShadowCount = 0;
+  u32 AppIdx;
+  for (AppIdx = 0; AppIdx < NumAppRegions; ++AppIdx) {
+    if (!AppRegions[AppIdx].ShadowMergedWithPrev) {
+      if (UnmergedShadowCount == i)
+        break;
+      UnmergedShadowCount++;
+    }
+  }
+  if (AppIdx >= NumAppRegions || UnmergedShadowCount != i)
+    return false;
+  *Start = appToShadow(AppRegions[AppIdx].Start);
+  // The formula fails for the end itself.
+  *End = appToShadow(AppRegions[AppIdx].End - 1) + 1;
+  // Merge with adjacent shadow regions:
+  for (++AppIdx; AppIdx < NumAppRegions; ++AppIdx) {
+    if (!AppRegions[AppIdx].ShadowMergedWithPrev)
+      break;
+    *Start = Min(*Start, appToShadow(AppRegions[AppIdx].Start));
+    *End = Max(*End, appToShadow(AppRegions[AppIdx].End - 1) + 1);
+  }
+  return true;
+}
+
+ALWAYS_INLINE
+bool isShadowMem(uptr Mem) {
+  // We assume this is not used on any critical performance path and so there's
+  // no need to hardcode the mapping results.
+  for (uptr i = 0; i < NumAppRegions; ++i) {
+    if (Mem >= appToShadow(AppRegions[i].Start) &&
+        Mem < appToShadow(AppRegions[i].End - 1) + 1)
+      return true;
+  }
+  return false;
+}
+
+} // namespace __esan
+
+#endif /* ESAN_SHADOW_H */
diff --git a/libsanitizer/esan/esan_sideline.h b/libsanitizer/esan/esan_sideline.h
new file mode 100644
index 0000000..aa3fae1
--- /dev/null
+++ b/libsanitizer/esan/esan_sideline.h
@@ -0,0 +1,61 @@ 
+//===-- esan_sideline.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Esan sideline thread support.
+//===----------------------------------------------------------------------===//
+
+#ifndef ESAN_SIDELINE_H
+#define ESAN_SIDELINE_H
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __esan {
+
+typedef void (*SidelineFunc)(void *Arg);
+
+// Currently only one sideline thread is supported.
+// It calls the SidelineFunc passed to launchThread once on each sample at the
+// given frequency in real time (i.e., wall clock time).
+class SidelineThread {
+public:
+  // We cannot initialize any fields in the constructor as it will be called
+  // *after* launchThread for a static instance, as esan.module_ctor is called
+  // before static initializers.
+  SidelineThread() {}
+  ~SidelineThread() {}
+
+  // To simplify declaration in sanitizer code where we want to avoid
+  // heap allocations, the constructor and destructor do nothing and
+  // launchThread and joinThread do the real work.
+  // They should each be called just once.
+  bool launchThread(SidelineFunc takeSample, void *Arg, u32 FreqMilliSec);
+  bool joinThread();
+
+  // Must be called from the sideline thread itself.
+  bool adjustTimer(u32 FreqMilliSec);
+
+private:
+  static int runSideline(void *Arg);
+  static void registerSignal(int SigNum);
+  static void handleSidelineSignal(int SigNum, void *SigInfo, void *Ctx);
+
+  char *Stack;
+  SidelineFunc sampleFunc;
+  void *FuncArg;
+  u32 Freq;
+  uptr SidelineId;
+  atomic_uintptr_t SidelineExit;
+};
+
+} // namespace __esan
+
+#endif  // ESAN_SIDELINE_H
diff --git a/libsanitizer/esan/esan_sideline_linux.cpp b/libsanitizer/esan/esan_sideline_linux.cpp
new file mode 100644
index 0000000..d04f590
--- /dev/null
+++ b/libsanitizer/esan/esan_sideline_linux.cpp
@@ -0,0 +1,177 @@ 
+//===-- esan_sideline_linux.cpp ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Support for a separate or "sideline" tool thread on Linux.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "esan_sideline.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include <errno.h>
+#include <sched.h>
+#include <sys/prctl.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+namespace __esan {
+
+static const int SigAltStackSize = 4*1024;
+static const int SidelineStackSize = 4*1024;
+static const uptr SidelineIdUninitialized = 1;
+
+// FIXME: we'll need some kind of TLS (can we trust that a pthread key will
+// work in our non-POSIX thread?) to access our data in our signal handler
+// with multiple sideline threads.  For now we assume there is only one
+// sideline thread and we use a dirty solution of a global var.
+static SidelineThread *TheThread;
+
+// We aren't passing SA_NODEFER so the same signal is blocked while here.
+void SidelineThread::handleSidelineSignal(int SigNum, void *SigInfo,
+                                          void *Ctx) {
+  VPrintf(3, "Sideline signal %d\n", SigNum);
+  CHECK_EQ(SigNum, SIGALRM);
+  // See above about needing TLS to avoid this global var.
+  SidelineThread *Thread = TheThread;
+  if (atomic_load(&Thread->SidelineExit, memory_order_relaxed) != 0)
+    return;
+  Thread->sampleFunc(Thread->FuncArg);
+}
+
+void SidelineThread::registerSignal(int SigNum) {
+  __sanitizer_sigaction SigAct;
+  internal_memset(&SigAct, 0, sizeof(SigAct));
+  SigAct.sigaction = handleSidelineSignal;
+  // We do not pass SA_NODEFER as we want to block the same signal.
+  SigAct.sa_flags = SA_ONSTACK | SA_SIGINFO;
+  int Res = internal_sigaction(SigNum, &SigAct, nullptr);
+  CHECK_EQ(Res, 0);
+}
+
+int SidelineThread::runSideline(void *Arg) {
+  VPrintf(1, "Sideline thread starting\n");
+  SidelineThread *Thread = static_cast<SidelineThread*>(Arg);
+
+  // If the parent dies, we want to exit also.
+  internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+
+  // Set up a signal handler on an alternate stack for safety.
+  InternalScopedBuffer<char> StackMap(SigAltStackSize);
+  struct sigaltstack SigAltStack;
+  SigAltStack.ss_sp = StackMap.data();
+  SigAltStack.ss_size = SigAltStackSize;
+  SigAltStack.ss_flags = 0;
+  internal_sigaltstack(&SigAltStack, nullptr);
+
+  // We inherit the signal mask from the app thread.  In case
+  // we weren't created at init time, we ensure the mask is empty.
+  __sanitizer_sigset_t SigSet;
+  internal_sigfillset(&SigSet);
+  int Res = internal_sigprocmask(SIG_UNBLOCK, &SigSet, nullptr);
+  CHECK_EQ(Res, 0);
+
+  registerSignal(SIGALRM);
+
+  bool TimerSuccess = Thread->adjustTimer(Thread->Freq);
+  CHECK(TimerSuccess);
+
+  // We loop, doing nothing but handling itimer signals.
+  while (atomic_load(&TheThread->SidelineExit, memory_order_relaxed) == 0)
+    sched_yield();
+
+  if (!Thread->adjustTimer(0))
+    VPrintf(1, "Failed to disable timer\n");
+
+  VPrintf(1, "Sideline thread exiting\n");
+  return 0;
+}
+
+bool SidelineThread::launchThread(SidelineFunc takeSample, void *Arg,
+                                  u32 FreqMilliSec) {
+  // This can only be called once.  However, we can't clear a field in
+  // the constructor and check for that here as the constructor for
+  // a static instance is called *after* our module_ctor and thus after
+  // this routine!  Thus we rely on the TheThread check below.
+  CHECK(TheThread == nullptr); // Only one sideline thread is supported.
+  TheThread = this;
+  sampleFunc = takeSample;
+  FuncArg = Arg;
+  Freq = FreqMilliSec;
+  atomic_store(&SidelineExit, 0, memory_order_relaxed);
+
+  // We do without a guard page.
+  Stack = static_cast<char*>(MmapOrDie(SidelineStackSize, "SidelineStack"));
+  // We need to handle the return value from internal_clone() not having been
+  // assigned yet (for our CHECK in adjustTimer()) so we ensure this has a
+  // sentinel value.
+  SidelineId = SidelineIdUninitialized;
+  // By omitting CLONE_THREAD, the child is in its own thread group and will not
+  // receive any of the application's signals.
+  SidelineId = internal_clone(
+      runSideline, Stack + SidelineStackSize,
+      CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
+      this, nullptr /* parent_tidptr */,
+      nullptr /* newtls */, nullptr /* child_tidptr */);
+  int ErrCode;
+  if (internal_iserror(SidelineId, &ErrCode)) {
+    Printf("FATAL: EfficiencySanitizer failed to spawn a thread (code %d).\n",
+           ErrCode);
+    Die();
+    return false; // Not reached.
+  }
+  return true;
+}
+
+bool SidelineThread::joinThread() {
+  VPrintf(1, "Joining sideline thread\n");
+  bool Res = true;
+  atomic_store(&SidelineExit, 1, memory_order_relaxed);
+  while (true) {
+    uptr Status = internal_waitpid(SidelineId, nullptr, __WALL);
+    int ErrCode;
+    if (!internal_iserror(Status, &ErrCode))
+      break;
+    if (ErrCode == EINTR)
+      continue;
+    VPrintf(1, "Failed to join sideline thread (errno %d)\n", ErrCode);
+    Res = false;
+    break;
+  }
+  UnmapOrDie(Stack, SidelineStackSize);
+  return Res;
+}
+
+// Must be called from the sideline thread itself.
+bool SidelineThread::adjustTimer(u32 FreqMilliSec) {
+  // The return value of internal_clone() may not have been assigned yet:
+  CHECK(internal_getpid() == SidelineId ||
+        SidelineId == SidelineIdUninitialized);
+  Freq = FreqMilliSec;
+  struct itimerval TimerVal;
+  TimerVal.it_interval.tv_sec = (time_t) Freq / 1000;
+  TimerVal.it_interval.tv_usec = (time_t) (Freq % 1000) * 1000;
+  TimerVal.it_value.tv_sec = (time_t) Freq / 1000;
+  TimerVal.it_value.tv_usec = (time_t) (Freq % 1000) * 1000;
+  // As we're in a different thread group, we cannot use either
+  // ITIMER_PROF or ITIMER_VIRTUAL without taking up scheduled
+  // time ourselves: thus we must use real time.
+  int Res = setitimer(ITIMER_REAL, &TimerVal, nullptr);
+  return (Res == 0);
+}
+
+} // namespace __esan
+
+#endif // SANITIZER_LINUX
diff --git a/libsanitizer/esan/libtool-version b/libsanitizer/esan/libtool-version
new file mode 100644
index 0000000..9a16cf5
--- /dev/null
+++ b/libsanitizer/esan/libtool-version
@@ -0,0 +1,6 @@ 
+# This file is used to maintain libtool version info for libasan.  See
+# the libtool manual to understand the meaning of the fields.  This is
+# a separate file so that version updates don't involve re-running
+# automake.
+# CURRENT:REVISION:AGE
+1:0:0
diff --git a/libsanitizer/esan/working_set.cpp b/libsanitizer/esan/working_set.cpp
new file mode 100644
index 0000000..b323703
--- /dev/null
+++ b/libsanitizer/esan/working_set.cpp
@@ -0,0 +1,282 @@ 
+//===-- working_set.cpp ---------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// This file contains working-set-specific code.
+//===----------------------------------------------------------------------===//
+
+#include "working_set.h"
+#include "esan.h"
+#include "esan_circular_buffer.h"
+#include "esan_flags.h"
+#include "esan_shadow.h"
+#include "esan_sideline.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+// We shadow every cache line of app memory with one shadow byte.
+// - The highest bit of each shadow byte indicates whether the corresponding
+//   cache line has ever been accessed.
+// - The lowest bit of each shadow byte indicates whether the corresponding
+//   cache line was accessed since the last sample.
+// - The other bits are used for working set snapshots at successively
+//   lower frequencies, each bit to the left from the lowest bit stepping
+//   down the frequency by 2 to the power of getFlags()->snapshot_step.
+// Thus we have something like this:
+//   Bit 0: Since last sample
+//   Bit 1: Since last 2^2 samples
+//   Bit 2: Since last 2^4 samples
+//   Bit 3: ...
+//   Bit 7: Ever accessed.
+// We live with races in accessing each shadow byte.
+typedef unsigned char byte;
+
+namespace __esan {
+
+// Our shadow memory assumes that the line size is 64.
+static const u32 CacheLineSize = 64;
+
+// See the shadow byte layout description above.
+static const u32 TotalWorkingSetBitIdx = 7;
+// We accumulate to the left until we hit this bit.
+// We don't need to accumulate to the final bit as it's set on each ref
+// by the compiler instrumentation.
+static const u32 MaxAccumBitIdx = 6;
+static const u32 CurWorkingSetBitIdx = 0;
+static const byte ShadowAccessedVal =
+  (1 << TotalWorkingSetBitIdx) | (1 << CurWorkingSetBitIdx);
+
+static SidelineThread Thread;
+// If we use real-time-based timer samples this won't overflow in any realistic
+// scenario, but if we switch to some other unit (such as memory accesses) we
+// may want to consider a 64-bit int.
+static u32 SnapshotNum;
+
+// We store the wset size for each of 8 different sampling frequencies.
+static const u32 NumFreq = 8; // One for each bit of our shadow bytes.
+// We cannot use static objects as the global destructor is called
+// prior to our finalize routine.
+// These are each circular buffers, sized up front.
+CircularBuffer<u32> SizePerFreq[NumFreq];
+// We cannot rely on static initializers (they may run too late) but
+// we record the size here for clarity:
+u32 CircularBufferSizes[NumFreq] = {
+  // These are each mmap-ed so our minimum is one page.
+  32*1024,
+  16*1024,
+  8*1024,
+  4*1024,
+  4*1024,
+  4*1024,
+  4*1024,
+  4*1024,
+};
+
+void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size,
+                                  bool IsWrite) {
+  if (Size == 0)
+    return;
+  SIZE_T I = 0;
+  uptr LineSize = getFlags()->cache_line_size;
+  // As Addr+Size could overflow at the top of a 32-bit address space,
+  // we avoid the simpler formula that rounds the start and end.
+  SIZE_T NumLines = Size / LineSize +
+    // Add any extra at the start or end adding on an extra line:
+    (LineSize - 1 + Addr % LineSize + Size % LineSize) / LineSize;
+  byte *Shadow = (byte *)appToShadow(Addr);
+  // Write shadow bytes until we're word-aligned.
+  while (I < NumLines && (uptr)Shadow % 4 != 0) {
+    if ((*Shadow & ShadowAccessedVal) != ShadowAccessedVal)
+      *Shadow |= ShadowAccessedVal;
+    ++Shadow;
+    ++I;
+  }
+  // Write whole shadow words at a time.
+  // Using a word-stride loop improves the runtime of a microbenchmark of
+  // memset calls by 10%.
+  u32 WordValue = ShadowAccessedVal | ShadowAccessedVal << 8 |
+    ShadowAccessedVal << 16 | ShadowAccessedVal << 24;
+  while (I + 4 <= NumLines) {
+    if ((*(u32*)Shadow & WordValue) != WordValue)
+      *(u32*)Shadow |= WordValue;
+    Shadow += 4;
+    I += 4;
+  }
+  // Write any trailing shadow bytes.
+  while (I < NumLines) {
+    if ((*Shadow & ShadowAccessedVal) != ShadowAccessedVal)
+      *Shadow |= ShadowAccessedVal;
+    ++Shadow;
+    ++I;
+  }
+}
+
+// This routine will word-align ShadowStart and ShadowEnd prior to scanning.
+// It does *not* clear for BitIdx==TotalWorkingSetBitIdx, as that top bit
+// measures the access during the entire execution and should never be cleared.
+static u32 countAndClearShadowValues(u32 BitIdx, uptr ShadowStart,
+                                     uptr ShadowEnd) {
+  u32 WorkingSetSize = 0;
+  u32 ByteValue = 0x1 << BitIdx;
+  u32 WordValue = ByteValue | ByteValue << 8 | ByteValue << 16 |
+    ByteValue << 24;
+  // Get word aligned start.
+  ShadowStart = RoundDownTo(ShadowStart, sizeof(u32));
+  bool Accum = getFlags()->record_snapshots && BitIdx < MaxAccumBitIdx;
+  // Do not clear the bit that measures access during the entire execution.
+  bool Clear = BitIdx < TotalWorkingSetBitIdx;
+  for (u32 *Ptr = (u32 *)ShadowStart; Ptr < (u32 *)ShadowEnd; ++Ptr) {
+    if ((*Ptr & WordValue) != 0) {
+      byte *BytePtr = (byte *)Ptr;
+      for (u32 j = 0; j < sizeof(u32); ++j) {
+        if (BytePtr[j] & ByteValue) {
+          ++WorkingSetSize;
+          if (Accum) {
+            // Accumulate to the lower-frequency bit to the left.
+            BytePtr[j] |= (ByteValue << 1);
+          }
+        }
+      }
+      if (Clear) {
+        // Clear this bit from every shadow byte.
+        *Ptr &= ~WordValue;
+      }
+    }
+  }
+  return WorkingSetSize;
+}
+
+// Scan shadow memory to calculate the number of cache lines being accessed,
+// i.e., the number of non-zero bits indexed by BitIdx in each shadow byte.
+// We also clear the lowest bits (most recent working set snapshot).
+// We do *not* clear for BitIdx==TotalWorkingSetBitIdx, as that top bit
+// measures the access during the entire execution and should never be cleared.
+static u32 computeWorkingSizeAndReset(u32 BitIdx) {
+  u32 WorkingSetSize = 0;
+  MemoryMappingLayout MemIter(true/*cache*/);
+  MemoryMappedSegment Segment;
+  while (MemIter.Next(&Segment)) {
+    VPrintf(4, "%s: considering %p-%p app=%d shadow=%d prot=%u\n", __FUNCTION__,
+            Segment.start, Segment.end, Segment.protection,
+            isAppMem(Segment.start), isShadowMem(Segment.start));
+    if (isShadowMem(Segment.start) && Segment.IsWritable()) {
+      VPrintf(3, "%s: walking %p-%p\n", __FUNCTION__, Segment.start,
+              Segment.end);
+      WorkingSetSize +=
+          countAndClearShadowValues(BitIdx, Segment.start, Segment.end);
+    }
+  }
+  return WorkingSetSize;
+}
+
+// This is invoked from a signal handler but in a sideline thread doing nothing
+// else so it is a little less fragile than a typical signal handler.
+static void takeSample(void *Arg) {
+  u32 BitIdx = CurWorkingSetBitIdx;
+  u32 Freq = 1;
+  ++SnapshotNum; // Simpler to skip 0 whose mod matches everything.
+  while (BitIdx <= MaxAccumBitIdx && (SnapshotNum % Freq) == 0) {
+    u32 NumLines = computeWorkingSizeAndReset(BitIdx);
+    VReport(1, "%s: snapshot #%5d bit %d freq %4d: %8u\n", SanitizerToolName,
+            SnapshotNum, BitIdx, Freq, NumLines);
+    SizePerFreq[BitIdx].push_back(NumLines);
+    Freq = Freq << getFlags()->snapshot_step;
+    BitIdx++;
+  }
+}
+
+unsigned int getSampleCountWorkingSet()
+{
+  return SnapshotNum;
+}
+
+// Initialization that must be done before any instrumented code is executed.
+void initializeShadowWorkingSet() {
+  CHECK(getFlags()->cache_line_size == CacheLineSize);
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
+  registerMemoryFaultHandler();
+#endif
+}
+
+void initializeWorkingSet() {
+  if (getFlags()->record_snapshots) {
+    for (u32 i = 0; i < NumFreq; ++i)
+      SizePerFreq[i].initialize(CircularBufferSizes[i]);
+    Thread.launchThread(takeSample, nullptr, getFlags()->sample_freq);
+  }
+}
+
+static u32 getPeriodForPrinting(u32 MilliSec, const char *&Unit) {
+  if (MilliSec > 600000) {
+    Unit = "min";
+    return MilliSec / 60000;
+  } else if (MilliSec > 10000) {
+    Unit = "sec";
+    return MilliSec / 1000;
+  } else {
+    Unit = "ms";
+    return MilliSec;
+  }
+}
+
+static u32 getSizeForPrinting(u32 NumOfCachelines, const char *&Unit) {
+  // We need a constant to avoid software divide support:
+  static const u32 KilobyteCachelines = (0x1 << 10) / CacheLineSize;
+  static const u32 MegabyteCachelines = KilobyteCachelines << 10;
+
+  if (NumOfCachelines > 10 * MegabyteCachelines) {
+    Unit = "MB";
+    return NumOfCachelines / MegabyteCachelines;
+  } else if (NumOfCachelines > 10 * KilobyteCachelines) {
+    Unit = "KB";
+    return NumOfCachelines / KilobyteCachelines;
+  } else {
+    Unit = "Bytes";
+    return NumOfCachelines * CacheLineSize;
+  }
+}
+
+void reportWorkingSet() {
+  const char *Unit;
+  if (getFlags()->record_snapshots) {
+    u32 Freq = 1;
+    Report(" Total number of samples: %u\n", SnapshotNum);
+    for (u32 i = 0; i < NumFreq; ++i) {
+      u32 Time = getPeriodForPrinting(getFlags()->sample_freq*Freq, Unit);
+      Report(" Samples array #%d at period %u %s\n", i, Time, Unit);
+      // FIXME: report whether we wrapped around and thus whether we
+      // have data on the whole run or just the last N samples.
+      for (u32 j = 0; j < SizePerFreq[i].size(); ++j) {
+        u32 Size = getSizeForPrinting(SizePerFreq[i][j], Unit);
+        Report("#%4d: %8u %s (%9u cache lines)\n", j, Size, Unit,
+               SizePerFreq[i][j]);
+      }
+      Freq = Freq << getFlags()->snapshot_step;
+    }
+  }
+
+  // Get the working set size for the entire execution.
+  u32 NumOfCachelines = computeWorkingSizeAndReset(TotalWorkingSetBitIdx);
+  u32 Size = getSizeForPrinting(NumOfCachelines, Unit);
+  Report(" %s: the total working set size: %u %s (%u cache lines)\n",
+         SanitizerToolName, Size, Unit, NumOfCachelines);
+}
+
+int finalizeWorkingSet() {
+  if (getFlags()->record_snapshots)
+    Thread.joinThread();
+  reportWorkingSet();
+  if (getFlags()->record_snapshots) {
+    for (u32 i = 0; i < NumFreq; ++i)
+      SizePerFreq[i].free();
+  }
+  return 0;
+}
+
+} // namespace __esan
diff --git a/libsanitizer/esan/working_set.h b/libsanitizer/esan/working_set.h
new file mode 100644
index 0000000..6a976c3
--- /dev/null
+++ b/libsanitizer/esan/working_set.h
@@ -0,0 +1,40 @@ 
+//===-- working_set.h -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Header for working-set-specific code.
+//===----------------------------------------------------------------------===//
+
+#ifndef WORKING_SET_H
+#define WORKING_SET_H
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __esan {
+
+void initializeWorkingSet();
+void initializeShadowWorkingSet();
+int finalizeWorkingSet();
+void reportWorkingSet();
+unsigned int getSampleCountWorkingSet();
+void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size,
+                                  bool IsWrite);
+
+// Platform-dependent.
+void registerMemoryFaultHandler();
+bool processWorkingSetSignal(int SigNum, void (*Handler)(int),
+                             void (**Result)(int));
+bool processWorkingSetSigaction(int SigNum, const void *Act, void *OldAct);
+bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet);
+
+} // namespace __esan
+
+#endif // WORKING_SET_H
diff --git a/libsanitizer/esan/working_set_posix.cpp b/libsanitizer/esan/working_set_posix.cpp
new file mode 100644
index 0000000..fcfa871
--- /dev/null
+++ b/libsanitizer/esan/working_set_posix.cpp
@@ -0,0 +1,133 @@ 
+//===-- working_set_posix.cpp -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// POSIX-specific working set tool code.
+//===----------------------------------------------------------------------===//
+
+#include "working_set.h"
+#include "esan_flags.h"
+#include "esan_shadow.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include <signal.h>
+#include <sys/mman.h>
+
+namespace __esan {
+
+// We only support regular POSIX threads with a single signal handler
+// for the whole process == thread group.
+// Thus we only need to store one app signal handler.
+// FIXME: Store and use any alternate stack and signal flags set by
+// the app.  For now we just call the app handler from our handler.
+static __sanitizer_sigaction AppSigAct;
+
+bool processWorkingSetSignal(int SigNum, void (*Handler)(int),
+                             void (**Result)(int)) {
+  VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum);
+  if (SigNum == SIGSEGV) {
+    *Result = AppSigAct.handler;
+    AppSigAct.sigaction = (void (*)(int, void*, void*))Handler;
+    return false; // Skip real call.
+  }
+  return true;
+}
+
+bool processWorkingSetSigaction(int SigNum, const void *ActVoid,
+                                void *OldActVoid) {
+  VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum);
+  if (SigNum == SIGSEGV) {
+    const struct sigaction *Act = (const struct sigaction *) ActVoid;
+    struct sigaction *OldAct = (struct sigaction *) OldActVoid;
+    if (OldAct)
+      internal_memcpy(OldAct, &AppSigAct, sizeof(OldAct));
+    if (Act)
+      internal_memcpy(&AppSigAct, Act, sizeof(AppSigAct));
+    return false; // Skip real call.
+  }
+  return true;
+}
+
+bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet) {
+  VPrintf(2, "%s\n", __FUNCTION__);
+  // All we need to do is ensure that SIGSEGV is not blocked.
+  // FIXME: we are not fully transparent as we do not pretend that
+  // SIGSEGV is still blocked on app queries: that would require
+  // per-thread mask tracking.
+  if (Set && (How == SIG_BLOCK || How == SIG_SETMASK)) {
+    if (internal_sigismember((__sanitizer_sigset_t *)Set, SIGSEGV)) {
+      VPrintf(1, "%s: removing SIGSEGV from the blocked set\n", __FUNCTION__);
+      internal_sigdelset((__sanitizer_sigset_t *)Set, SIGSEGV);
+    }
+  }
+  return true;
+}
+
+static void reinstateDefaultHandler(int SigNum) {
+  __sanitizer_sigaction SigAct;
+  internal_memset(&SigAct, 0, sizeof(SigAct));
+  SigAct.sigaction = (void (*)(int, void*, void*)) SIG_DFL;
+  int Res = internal_sigaction(SigNum, &SigAct, nullptr);
+  CHECK(Res == 0);
+  VPrintf(1, "Unregistered for %d handler\n", SigNum);
+}
+
+// If this is a shadow fault, we handle it here; otherwise, we pass it to the
+// app to handle it just as the app would do without our tool in place.
+static void handleMemoryFault(int SigNum, void *Info, void *Ctx) {
+  if (SigNum == SIGSEGV) {
+    // We rely on si_addr being filled in (thus we do not support old kernels).
+    siginfo_t *SigInfo = (siginfo_t *)Info;
+    uptr Addr = (uptr)SigInfo->si_addr;
+    if (isShadowMem(Addr)) {
+      VPrintf(3, "Shadow fault @%p\n", Addr);
+      uptr PageSize = GetPageSizeCached();
+      int Res = internal_mprotect((void *)RoundDownTo(Addr, PageSize),
+                                  PageSize, PROT_READ|PROT_WRITE);
+      CHECK(Res == 0);
+    } else if (AppSigAct.sigaction) {
+      // FIXME: For simplicity we ignore app options including its signal stack
+      // (we just use ours) and all the delivery flags.
+      AppSigAct.sigaction(SigNum, Info, Ctx);
+    } else {
+      // Crash instead of spinning with infinite faults.
+      reinstateDefaultHandler(SigNum);
+    }
+  } else
+    UNREACHABLE("signal not registered");
+}
+
+void registerMemoryFaultHandler() {
+  // We do not use an alternate signal stack, as doing so would require
+  // setting it up for each app thread.
+  // FIXME: This could result in problems with emulating the app's signal
+  // handling if the app relies on an alternate stack for SIGSEGV.
+
+  // We require that SIGSEGV is not blocked.  We use a sigprocmask
+  // interceptor to ensure that in the future.  Here we ensure it for
+  // the current thread.  We assume there are no other threads at this
+  // point during initialization, or that at least they do not block
+  // SIGSEGV.
+  __sanitizer_sigset_t SigSet;
+  internal_sigemptyset(&SigSet);
+  internal_sigprocmask(SIG_BLOCK, &SigSet, nullptr);
+
+  __sanitizer_sigaction SigAct;
+  internal_memset(&SigAct, 0, sizeof(SigAct));
+  SigAct.sigaction = handleMemoryFault;
+  // We want to handle nested signals b/c we need to handle a
+  // shadow fault in an app signal handler.
+  SigAct.sa_flags = SA_SIGINFO | SA_NODEFER;
+  int Res = internal_sigaction(SIGSEGV, &SigAct, &AppSigAct);
+  CHECK(Res == 0);
+  VPrintf(1, "Registered for SIGSEGV handler\n");
+}
+
+} // namespace __esan
diff --git a/libsanitizer/include/esan_interface.h b/libsanitizer/include/esan_interface.h
new file mode 100644
index 0000000..c755ed3
--- /dev/null
+++ b/libsanitizer/include/esan_interface.h
@@ -0,0 +1,50 @@ 
+//===-- sanitizer/esan_interface.h ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ESAN_INTERFACE_H
+#define SANITIZER_ESAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+// We declare our interface routines as weak to allow the user to avoid
+// ifdefs and instead use this pattern to allow building the same sources
+// with and without our runtime library:
+//     if (__esan_report)
+//       __esan_report();
+#ifdef _MSC_VER
+/* selectany is as close to weak as we'll get. */
+#define COMPILER_RT_WEAK __declspec(selectany)
+#elif __GNUC__
+#define COMPILER_RT_WEAK __attribute__((weak))
+#else
+#define COMPILER_RT_WEAK
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// This function can be called mid-run (or at the end of a run for
+// a server process that doesn't shut down normally) to request that
+// data for that point in the run be reported from the tool.
+void COMPILER_RT_WEAK __esan_report(void);
+
+// This function returns the number of samples that the esan tool has collected
+// to this point.  This is useful for testing.
+unsigned int COMPILER_RT_WEAK __esan_get_sample_count(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_ESAN_INTERFACE_H
diff --git a/libsanitizer/interception/Makefile.in b/libsanitizer/interception/Makefile.in
index 4eb6456..67ac7df 100644
--- a/libsanitizer/interception/Makefile.in
+++ b/libsanitizer/interception/Makefile.in
@@ -220,6 +220,7 @@  install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libesan = @link_libesan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
diff --git a/libsanitizer/libbacktrace/Makefile.in b/libsanitizer/libbacktrace/Makefile.in
index e23aa84..f6558c3 100644
--- a/libsanitizer/libbacktrace/Makefile.in
+++ b/libsanitizer/libbacktrace/Makefile.in
@@ -262,6 +262,7 @@  install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libesan = @link_libesan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
diff --git a/libsanitizer/libsanitizer.spec.in b/libsanitizer/libsanitizer.spec.in
index a4fa87d..b747c0c 100644
--- a/libsanitizer/libsanitizer.spec.in
+++ b/libsanitizer/libsanitizer.spec.in
@@ -9,3 +9,4 @@ 
 
 *link_liblsan: @link_liblsan@
 
+*link_libesan: @link_libesan@
diff --git a/libsanitizer/lsan/Makefile.in b/libsanitizer/lsan/Makefile.in
index a88d1f8..176232b 100644
--- a/libsanitizer/lsan/Makefile.in
+++ b/libsanitizer/lsan/Makefile.in
@@ -265,6 +265,7 @@  install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libesan = @link_libesan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in
index b0f5ac2..fba3009 100644
--- a/libsanitizer/sanitizer_common/Makefile.in
+++ b/libsanitizer/sanitizer_common/Makefile.in
@@ -265,6 +265,7 @@  install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libesan = @link_libesan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in
index 629056b..989908e 100644
--- a/libsanitizer/tsan/Makefile.in
+++ b/libsanitizer/tsan/Makefile.in
@@ -281,6 +281,7 @@  install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libesan = @link_libesan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
diff --git a/libsanitizer/ubsan/Makefile.in b/libsanitizer/ubsan/Makefile.in
index d75260f..6e53066 100644
--- a/libsanitizer/ubsan/Makefile.in
+++ b/libsanitizer/ubsan/Makefile.in
@@ -259,6 +259,7 @@  install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libesan = @link_libesan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
-- 
1.9.1