Merge "Add props files for each partition"
diff --git a/libc/bionic/__libc_current_sigrtmin.cpp b/libc/bionic/__libc_current_sigrtmin.cpp
index 16b037d..7c93267 100644
--- a/libc/bionic/__libc_current_sigrtmin.cpp
+++ b/libc/bionic/__libc_current_sigrtmin.cpp
@@ -31,7 +31,8 @@
 // POSIX timers use __SIGRTMIN + 0.
 // libbacktrace uses __SIGRTMIN + 1.
 // libcore uses __SIGRTMIN + 2.
+// __SIGRTMIN + 3 is reserved for triggering native stack dumps.
 
 int __libc_current_sigrtmin(void) {
-  return __SIGRTMIN + 3;
+  return __SIGRTMIN + 4;
 }
diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h
index 9aa4a1f..b8f3cec 100644
--- a/libc/include/dlfcn.h
+++ b/libc/include/dlfcn.h
@@ -29,6 +29,7 @@
 #ifndef __DLFCN_H__
 #define __DLFCN_H__
 
+#include <stdint.h>
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
diff --git a/libc/private/CFIShadow.h b/libc/private/CFIShadow.h
new file mode 100644
index 0000000..26351db
--- /dev/null
+++ b/libc/private/CFIShadow.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CFI_SHADOW_H
+#define CFI_SHADOW_H
+
+#include <stdint.h>
+
+#include "private/bionic_page.h"
+#include "private/bionic_macros.h"
+
+constexpr unsigned kLibraryAlignmentBits = 18;
+constexpr size_t kLibraryAlignment = 1UL << kLibraryAlignmentBits;
+
+// This class defines format of the shadow region for Control Flow Integrity support.
+// See documentation in http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html#shared-library-support.
+//
+// CFI shadow is effectively a very fast and specialized implementation of dladdr: given an address that
+// belongs to a shared library or an executable, it can find the address of a specific export in that
+// library (a function called "__cfi_check"). This is only guaranteed to work for
+// addresses of possible CFI targets inside a library: indirectly called functions and virtual
+// tables. A random address inside a library may not work in the future (but it does in the current
+// implementation).
+//
+// Implementation is a sparse array of uint16_t where each element describes the location of
+// __cfi_check for a 2**kShadowGranularity range of memory. Array elements (called "shadow values"
+// below) are interpreted as follows.
+//
+// For an address P and corresponding shadow value V, the address of __cfi_check is calculated as
+//   align_up(P, 2**kShadowGranularity) - (V - 2) * (2 ** kCfiCheckGranularity)
+//
+// Special shadow values:
+//        0 = kInvalidShadow, this memory range has no valid CFI targets.
+//        1 = kUncheckedShadow, any address is this memory range is a valid CFI target
+//
+// Loader requirement: each aligned 2**kShadowGranularity region of address space may contain at
+// most one DSO.
+// Compiler requirement: __cfi_check is aligned at kCfiCheckGranularity.
+// Compiler requirement: __cfi_check for a given DSO is located below any CFI target for that DSO.
+class CFIShadow {
+ public:
+  static constexpr uintptr_t kShadowGranularity = kLibraryAlignmentBits;
+  static constexpr uintptr_t kCfiCheckGranularity = 12;
+
+  // Each uint16_t element of the shadow corresponds to this much application memory.
+  static constexpr uintptr_t kShadowAlign = 1UL << kShadowGranularity;
+
+  // Alignment of __cfi_check.
+  static constexpr uintptr_t kCfiCheckAlign = 1UL << kCfiCheckGranularity;  // 4K
+
+#if defined(__aarch64__)
+  static constexpr uintptr_t kMaxTargetAddr = 0x7fffffffff;
+#elif defined (__LP64__)
+  static constexpr uintptr_t kMaxTargetAddr = 0x7fffffffffff;
+#else
+  static constexpr uintptr_t kMaxTargetAddr = 0xffffffff;
+#endif
+
+  // Shadow is 2 -> 2**kShadowGranularity.
+  static constexpr uintptr_t kShadowSize =
+      align_up((kMaxTargetAddr >> (kShadowGranularity - 1)), PAGE_SIZE);
+
+  // Returns offset inside the shadow region for an address.
+  static constexpr uintptr_t MemToShadowOffset(uintptr_t x) {
+    return (x >> kShadowGranularity) << 1;
+  }
+
+  typedef int (*CFICheckFn)(uint64_t, void *, void *);
+
+ public:
+  enum ShadowValues : uint16_t {
+    kInvalidShadow = 0,    // Not a valid CFI target.
+    kUncheckedShadow = 1,  // Unchecked, valid CFI target.
+    kRegularShadowMin = 2  // This and all higher values encode a negative offset to __cfi_check in
+                           // the units of kCfiCheckGranularity, starting with 0 at
+                           // kRegularShadowMin.
+  };
+};
+
+#endif  // CFI_SHADOW_H
diff --git a/libc/private/bionic_macros.h b/libc/private/bionic_macros.h
index d5c5b9c..303218e 100644
--- a/libc/private/bionic_macros.h
+++ b/libc/private/bionic_macros.h
@@ -48,11 +48,11 @@
     ? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
     : (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
 
-static inline uintptr_t align_down(uintptr_t p, size_t align) {
+static constexpr uintptr_t align_down(uintptr_t p, size_t align) {
   return p & ~(align - 1);
 }
 
-static inline uintptr_t align_up(uintptr_t p, size_t align) {
+static constexpr uintptr_t align_up(uintptr_t p, size_t align) {
   return (p + align - 1) & ~(align - 1);
 }
 
diff --git a/libc/seccomp/Android.mk b/libc/seccomp/Android.mk
new file mode 100644
index 0000000..af1311c
--- /dev/null
+++ b/libc/seccomp/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_MODULE := libseccomp_policy
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := arm_policy.c arm64_policy.c
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/libc/seccomp/arm64_policy.c b/libc/seccomp/arm64_policy.c
new file mode 100644
index 0000000..d5a87d6
--- /dev/null
+++ b/libc/seccomp/arm64_policy.c
@@ -0,0 +1,48 @@
+// Autogenerated file - edit at your peril!!
+
+#include <linux/filter.h>
+#include <errno.h>
+
+#include "seccomp_policy.h"
+const struct sock_filter arm64_filter[] = {
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5, 0, 35),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 17, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 32, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 18, 29, 30), //setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|getcwd
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 30, 28, 29), //eventfd2|epoll_create1|epoll_ctl|epoll_pwait|dup|dup3|fcntl|inotify_init1|inotify_add_watch|inotify_rm_watch|ioctl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 27, 28), //flock|mknodat|mkdirat|unlinkat|symlinkat|linkat|renameat|umount2|mount
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 59, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 25, 26), //statfs|fstatfs|truncate|ftruncate|fallocate|faccessat|chdir|fchdir|chroot|fchmod|fchmodat|fchownat|fchown|openat|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 24, 25), //pipe2|quotactl|getdents64|lseek|read|write|readv|writev|pread64|pwrite64|preadv|pwritev|sendfile|pselect6|ppoll|signalfd4|vmsplice|splice|tee|readlinkat|newfstatat|fstat|sync|fsync|fdatasync|sync_file_range|timerfd_create|timerfd_settime|timerfd_gettime|utimensat|acct|capget|capset|personality|exit|exit_group|waitid|set_tid_address|unshare
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 129, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 105, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 21, 22), //nanosleep|getitimer|setitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 128, 20, 21), //init_module|delete_module|timer_create|timer_gettime|timer_getoverrun|timer_settime|timer_delete|clock_settime|clock_gettime|clock_getres|clock_nanosleep|syslog|ptrace|sched_setparam|sched_setscheduler|sched_getscheduler|sched_getparam|sched_setaffinity|sched_getaffinity|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 130, 18, 19), //kill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 139, 17, 18), //tgkill|sigaltstack|rt_sigsuspend|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 242, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 179, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 178, 12, 13), //setpriority|getpriority|reboot|setregid|setgid|setreuid|setuid|setresuid|getresuid|setresgid|getresgid|setfsuid|setfsgid|times|setpgid|getpgid|getsid|setsid|getgroups|setgroups|uname|sethostname|setdomainname|getrlimit|setrlimit|getrusage|umask|prctl|getcpu|gettimeofday|settimeofday|adjtimex|getpid|getppid|getuid|geteuid|getgid|getegid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 11, 12), //sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 202, 10, 11), //socket|socketpair|bind|listen
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 221, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 8, 9), //connect|getsockname|getpeername|sendto|recvfrom|setsockopt|getsockopt|shutdown|sendmsg|recvmsg|readahead|brk|munmap|mremap
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 234, 7, 8), //execve|mmap|fadvise64|swapon|swapoff|mprotect|msync|mlock|munlock|mlockall|munlockall|mincore|madvise
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 266, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 260, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 4, 5), //accept4|recvmmsg
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 3, 4), //wait4|prlimit64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 268, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 267, 1, 2), //clock_adjtime
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 272, 0, 1), //setns|sendmmsg|process_vm_readv|process_vm_writev
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+};
+
+const size_t arm64_filter_size = sizeof(arm64_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/arm_policy.c b/libc/seccomp/arm_policy.c
new file mode 100644
index 0000000..44e734e
--- /dev/null
+++ b/libc/seccomp/arm_policy.c
@@ -0,0 +1,146 @@
+// Autogenerated file - edit at your peril!!
+
+#include <linux/filter.h>
+#include <errno.h>
+
+#include "seccomp_policy.h"
+const struct sock_filter arm_filter[] = {
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 133),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 174, 67, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 33, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 17, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 11, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 6, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 125, 126), //exit
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5, 124, 125), //read|write
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 123, 124), //close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 121, 122), //execve|chdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 22, 120, 121), //lseek|getpid|mount
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 117, 118), //ptrace
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 116, 117), //sync|kill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 42, 114, 115), //dup
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 113, 114), //times
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 54, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 109, 110), //brk
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 53, 108, 109), //acct|umount2
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 55, 106, 107), //ioctl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 105, 106), //setpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 62, 102, 103), //umask|chroot
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 101, 102), //getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 74, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 99, 100), //setsid|sigaction
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 98, 99), //sethostname|setrlimit
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 124, 17, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 87, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 80, 92, 93), //getrusage|gettimeofday|settimeofday
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 91, 92), //swapon|reboot
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 90, 91), //munmap|truncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 88, 89), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 87, 88), //getpriority|setpriority
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 106, 84, 85), //syslog|setitimer|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 83, 84), //wait4|swapoff|sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 121, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 119, 81, 82), //fsync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 80, 81), //setdomainname|uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 138, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 128, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 76, 77), //adjtimex|mprotect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 130, 75, 76), //init_module|delete_module
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 73, 74), //quotactl|getpgid|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 72, 73), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 143, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 141, 69, 70), //setfsuid|setfsgid|_llseek
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 68, 69), //flock|msync|readv|writev|getsid|fdatasync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 66, 67), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 173, 65, 66), //prctl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 290, 33, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 239, 17, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 213, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 197, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 191, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 58, 59), //rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 57, 58), //getcwd|capget|capset|sigaltstack|sendfile
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 195, 56, 57), //ugetrlimit|mmap2|truncate64|ftruncate64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 54, 55), //fstat64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 53, 54), //getuid32|getgid32|geteuid32|getegid32|setreuid32|setregid32|getgroups32|setgroups32|fchown32|setresuid32|getresuid32|setresgid32|getresgid32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 219, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 215, 50, 51), //setuid32|setgid32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 49, 50), //getdents64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 225, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 47, 48), //mincore|madvise|fcntl64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 238, 46, 47), //readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 248, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 241, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 240, 42, 43), //sendfile64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 243, 41, 42), //sched_setaffinity|sched_getaffinity
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 251, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 249, 39, 40), //exit_group
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 252, 38, 39), //epoll_ctl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 280, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 270, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 269, 35, 36), //set_tid_address|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete|clock_settime|clock_gettime|clock_getres|clock_nanosleep|statfs64|fstatfs64|tgkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 271, 34, 35), //arm_fadvise64_64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 286, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 32, 33), //waitid|socket|bind|connect|listen
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 289, 31, 32), //getsockname|getpeername|socketpair
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 350, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 327, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 317, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 292, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 291, 26, 27), //sendto
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 298, 25, 26), //recvfrom|shutdown|setsockopt|getsockopt|sendmsg|recvmsg
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 319, 23, 24), //inotify_add_watch|inotify_rm_watch
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 326, 22, 23), //openat|mkdirat|mknodat|fchownat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 345, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 340, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 338, 19, 20), //fstatat64|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 344, 18, 19), //splice|sync_file_range2|tee|vmsplice
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 348, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 347, 16, 17), //getcpu|epoll_pwait
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 349, 15, 16), //utimensat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 372, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 365, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 352, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 351, 11, 12), //timerfd_create
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 363, 10, 11), //fallocate|timerfd_settime|timerfd_gettime|signalfd4|eventfd2|epoll_create1|dup3|pipe2|inotify_init1|preadv|pwritev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 369, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 367, 8, 9), //recvmmsg|accept4
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 370, 7, 8), //prlimit64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983042, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 374, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 373, 4, 5), //clock_adjtime
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 378, 3, 4), //sendmmsg|setns|process_vm_readv|process_vm_writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983045, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983043, 1, 2), //__ARM_NR_cacheflush
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983046, 0, 1), //__ARM_NR_set_tls
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+};
+
+const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/seccomp_policy.h b/libc/seccomp/seccomp_policy.h
new file mode 100644
index 0000000..e0282bd
--- /dev/null
+++ b/libc/seccomp/seccomp_policy.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SECCOMP_POLICY_H
+#define SECCOMP_POLICY_H
+
+#include <stddef.h>
+#include <linux/seccomp.h>
+
+extern const struct sock_filter arm_filter[];
+extern const size_t arm_filter_size;
+extern const struct sock_filter arm64_filter[];
+extern const size_t arm64_filter_size;
+
+#endif
diff --git a/libc/tools/genseccomp.py b/libc/tools/genseccomp.py
new file mode 100755
index 0000000..b82bb12
--- /dev/null
+++ b/libc/tools/genseccomp.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+import os
+from subprocess import Popen, PIPE
+import textwrap
+from gensyscalls import SysCallsTxtParser
+
+
+syscall_file = "SYSCALLS.TXT"
+
+
+class SyscallRange(object):
+  def __init__(self, name, value):
+    self.names = [name]
+    self.begin = value
+    self.end = self.begin + 1
+
+  def add(self, name, value):
+    if value != self.end:
+      raise ValueError
+    self.end += 1
+    self.names.append(name)
+
+
+def generate_bpf_jge(value, ge_target, less_target):
+  return "BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, {0}, {1}, {2})".format(value, ge_target, less_target)
+
+
+# Converts the sorted ranges of allowed syscalls to a binary tree bpf
+# For a single range, output a simple jump to {fail} or {allow}. We can't set
+# the jump ranges yet, since we don't know the size of the filter, so use a
+# placeholder
+# For multiple ranges, split into two, convert the two halves and output a jump
+# to the correct half
+def convert_to_bpf(ranges):
+  if len(ranges) == 1:
+    # We will replace {fail} and {allow} with appropriate range jumps later
+    return [generate_bpf_jge(ranges[0].end, "{fail}", "{allow}") +
+            ", //" + "|".join(ranges[0].names)]
+  else:
+    half = (len(ranges) + 1) / 2
+    first = convert_to_bpf(ranges[:half])
+    second = convert_to_bpf(ranges[half:])
+    return [generate_bpf_jge(ranges[half].begin, len(first), 0) + ","] + first + second
+
+
+def construct_bpf(architecture, header_dir, output_path):
+  parser = SysCallsTxtParser()
+  parser.parse_file(syscall_file)
+  syscalls = parser.syscalls
+
+  # Select only elements matching required architecture
+  syscalls = [x for x in syscalls if architecture in x and x[architecture]]
+
+  # We only want the name
+  names = [x["name"] for x in syscalls]
+
+  # Run preprocessor over the __NR_syscall symbols, including unistd.h,
+  # to get the actual numbers
+  prefix = "__SECCOMP_"  # prefix to ensure no name collisions
+  cpp = Popen(["../../prebuilts/clang/host/linux-x86/clang-stable/bin/clang",
+               "-E", "-nostdinc", "-I" + header_dir, "-Ikernel/uapi/", "-"],
+              stdin=PIPE, stdout=PIPE)
+  cpp.stdin.write("#include <asm/unistd.h>\n")
+  for name in names:
+    # In SYSCALLS.TXT, there are two arm-specific syscalls whose names start
+    # with __ARM__NR_. These we must simply write out as is.
+    if not name.startswith("__ARM_NR_"):
+      cpp.stdin.write(prefix + name + ", __NR_" + name + "\n")
+    else:
+      cpp.stdin.write(prefix + name + ", " + name + "\n")
+  content = cpp.communicate()[0].split("\n")
+
+  # The input is now the preprocessed source file. This will contain a lot
+  # of junk from the preprocessor, but our lines will be in the format:
+  #
+  #     __SECCOMP_${NAME}, (0 + value)
+
+  syscalls = []
+  for line in content:
+    if not line.startswith(prefix):
+      continue
+
+    # We might pick up extra whitespace during preprocessing, so best to strip.
+    name, value = [w.strip() for w in line.split(",")]
+    name = name[len(prefix):]
+
+    # Note that some of the numbers were expressed as base + offset, so we
+    # need to eval, not just int
+    value = eval(value)
+    syscalls.append((name, value))
+
+  # Sort the values so we convert to ranges and binary chop
+  syscalls = sorted(syscalls, lambda x, y: cmp(x[1], y[1]))
+
+  # Turn into a list of ranges. Keep the names for the comments
+  ranges = []
+  for name, value in syscalls:
+    if not ranges:
+      ranges.append(SyscallRange(name, value))
+      continue
+
+    last_range = ranges[-1]
+    if last_range.end == value:
+      last_range.add(name, value)
+    else:
+      ranges.append(SyscallRange(name, value))
+
+  bpf = convert_to_bpf(ranges)
+
+  # Now we know the size of the tree, we can substitute the {fail} and {allow}
+  # placeholders
+  for i, statement in enumerate(bpf):
+    # Replace placeholder with
+    # "distance to jump to fail, distance to jump to allow"
+    # We will add a kill statement and an allow statement after the tree
+    # With bpfs jmp 0 means the next statement, so the distance to the end is
+    # len(bpf) - i - 1, which is where we will put the kill statement, and
+    # then the statement after that is the allow statement
+    if "{fail}" in statement and "{allow}" in statement:
+      bpf[i] = statement.format(fail=str(len(bpf) - i - 1),
+                                allow=str(len(bpf) - i))
+
+  # Add check that we aren't off the bottom of the syscalls
+  bpf.insert(0,
+             "BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, " + str(ranges[0].begin) +
+             ", 0, " + str(len(bpf)) + "),")
+
+  # Add the error and allow calls at the end
+  bpf.append("BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),")
+  bpf.append("BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),")
+
+  # And output policy
+  header = textwrap.dedent("""\
+    // Autogenerated file - edit at your peril!!
+
+    #include <linux/filter.h>
+    #include <errno.h>
+
+    #include "seccomp_policy.h"
+    const struct sock_filter {architecture}_filter[] = {{
+    """).format(architecture=architecture)
+
+  footer = textwrap.dedent("""\
+
+    }};
+
+    const size_t {architecture}_filter_size = sizeof({architecture}_filter) / sizeof(struct sock_filter);
+    """).format(architecture=architecture)
+  output = header + "\n".join(bpf) + footer
+
+  existing = ""
+  if os.path.isfile(output_path):
+    existing = open(output_path).read()
+  if output == existing:
+    print "File " + output_path + " not changed."
+  else:
+    with open(output_path, "w") as output_file:
+      output_file.write(output)
+
+    print "Generated file " + output_path
+
+
+def main():
+  # Set working directory for predictable results
+  os.chdir(os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc"))
+  construct_bpf("arm", "kernel/uapi/asm-arm", "seccomp/arm_policy.c")
+  construct_bpf("arm64", "kernel/uapi/asm-arm64", "seccomp/arm64_policy.c")
+
+
+if __name__ == "__main__":
+  main()
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index b4aa06c..329184f 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -674,6 +674,7 @@
 
 logging.basicConfig(level=logging.INFO)
 
-state = State()
-state.process_file(os.path.join(bionic_libc_root, "SYSCALLS.TXT"))
-state.regenerate()
+if __name__ == "__main__":
+    state = State()
+    state.process_file(os.path.join(bionic_libc_root, "SYSCALLS.TXT"))
+    state.regenerate()
diff --git a/libdl/Android.bp b/libdl/Android.bp
index a0aeeff..013554a 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -44,7 +44,7 @@
             version_script: "libdl.x86_64.map",
         },
     },
-    srcs: ["libdl.c"],
+    srcs: ["libdl.c", "libdl_cfi.cpp"],
     cflags: [
         "-Wall",
         "-Wextra",
@@ -61,6 +61,9 @@
     allow_undefined_symbols: true,
     system_shared_libs: [],
 
+    // For private/CFIShadow.h.
+    include_dirs: ["bionic/libc"],
+
     // This is placeholder library the actual implementation is (currently)
     // provided by the linker.
     shared_libs: [ "ld-android" ],
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 1fdc1a7..f452641 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -36,6 +36,9 @@
 
 LIBC_PLATFORM {
   global:
+    __cfi_init;
+    __cfi_slowpath;
+    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -35,6 +35,9 @@
 
 LIBC_PLATFORM {
   global:
+    __cfi_init;
+    __cfi_slowpath;
+    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 0a82a2e..cc044fe 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -35,6 +35,9 @@
 
 LIBC_PLATFORM {
   global:
+    __cfi_init;
+    __cfi_slowpath;
+    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -35,6 +35,9 @@
 
 LIBC_PLATFORM {
   global:
+    __cfi_init;
+    __cfi_slowpath;
+    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -35,6 +35,9 @@
 
 LIBC_PLATFORM {
   global:
+    __cfi_init;
+    __cfi_slowpath;
+    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -35,6 +35,9 @@
 
 LIBC_PLATFORM {
   global:
+    __cfi_init;
+    __cfi_slowpath;
+    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -35,6 +35,9 @@
 
 LIBC_PLATFORM {
   global:
+    __cfi_init;
+    __cfi_slowpath;
+    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
diff --git a/libdl/libdl_cfi.cpp b/libdl/libdl_cfi.cpp
new file mode 100644
index 0000000..362b093
--- /dev/null
+++ b/libdl/libdl_cfi.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/mman.h>
+
+#include "private/CFIShadow.h"
+
+__attribute__((__weak__, visibility("default"))) extern "C" void __loader_cfi_fail(
+    uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void* CallerPc);
+
+// Base address of the CFI shadow. Passed down from the linker in __cfi_init()
+// and does not change after that. The contents of the shadow change in
+// dlopen/dlclose.
+static struct {
+  uintptr_t v;
+  char padding[PAGE_SIZE - sizeof(v)];
+} shadow_base_storage alignas(PAGE_SIZE);
+
+extern "C" uintptr_t* __cfi_init(uintptr_t shadow_base) {
+  shadow_base_storage.v = shadow_base;
+  static_assert(sizeof(shadow_base_storage) == PAGE_SIZE, "");
+  mprotect(&shadow_base_storage, PAGE_SIZE, PROT_READ);
+  return &shadow_base_storage.v;
+}
+
+static uint16_t shadow_load(void* p) {
+  uintptr_t addr = reinterpret_cast<uintptr_t>(p);
+  uintptr_t ofs = CFIShadow::MemToShadowOffset(addr);
+  if (ofs > CFIShadow::kShadowSize) return CFIShadow::kInvalidShadow;
+  return *reinterpret_cast<uint16_t*>(shadow_base_storage.v + ofs);
+}
+
+static uintptr_t cfi_check_addr(uint16_t v, void* Ptr) {
+  uintptr_t addr = reinterpret_cast<uintptr_t>(Ptr);
+  uintptr_t aligned_addr = align_up(addr, CFIShadow::kShadowAlign);
+  uintptr_t p = aligned_addr - (static_cast<uintptr_t>(v - CFIShadow::kRegularShadowMin)
+                                << CFIShadow::kCfiCheckGranularity);
+#ifdef __arm__
+  // Assume Thumb encoding. FIXME: force thumb at compile time?
+  p++;
+#endif
+  return p;
+}
+
+static inline void cfi_slowpath_common(uint64_t CallSiteTypeId, void* Ptr, void* DiagData) {
+  uint16_t v = shadow_load(Ptr);
+  switch (v) {
+    case CFIShadow::kInvalidShadow:
+      __loader_cfi_fail(CallSiteTypeId, Ptr, DiagData, __builtin_return_address(0));
+      break;
+    case CFIShadow::kUncheckedShadow:
+      break;
+    default:
+      reinterpret_cast<CFIShadow::CFICheckFn>(cfi_check_addr(v, Ptr))(CallSiteTypeId, Ptr, DiagData);
+  }
+}
+
+extern "C" void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr) {
+  cfi_slowpath_common(CallSiteTypeId, Ptr, nullptr);
+}
+
+extern "C" void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void* Ptr, void* DiagData) {
+  cfi_slowpath_common(CallSiteTypeId, Ptr, DiagData);
+}
diff --git a/linker/Android.bp b/linker/Android.bp
index a3b9cb2..6d93571 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -18,6 +18,7 @@
         "linker.cpp",
         "linker_block_allocator.cpp",
         "linker_dlwarning.cpp",
+        "linker_cfi.cpp",
         "linker_gdb_support.cpp",
         "linker_globals.cpp",
         "linker_libc_support.c",
@@ -116,6 +117,7 @@
         "libz",
         "liblog",
         "libc++_static",
+        "libdebuggerd_handler",
 
         // Important: The liblinker_malloc should be the last library in the list
         // to overwrite any other malloc implementations by other static libraries.
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index bb7b1ca..0092179 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "linker.h"
+#include "linker_cfi.h"
 #include "linker_globals.h"
 #include "linker_dlwarning.h"
 
@@ -189,6 +190,10 @@
   return result;
 }
 
+void __cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *CallerPc) {
+  CFIShadowWriter::CfiFail(CallSiteTypeId, Ptr, DiagData, CallerPc);
+}
+
 // name_offset: starting index of the name in libdl_info.strtab
 #define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
     { name_offset, \
@@ -225,11 +230,11 @@
   // 012345678901234 567890123456789012345678901234567 8901234567890123456789012345678901 2345678901234567 89
     "et_sdk_version\0__loader_android_init_namespaces\0__loader_android_create_namespace\0__loader_dlvsym\0__"
   // 4*
-  // 0000000000111111111122222 2222233333333334444444 4445555555555666666666677777777778 8888888889999999 999
-  // 0123456789012345678901234 5678901234567890123456 7890123456789012345678901234567890 1234567890123456 789
-    "loader_android_dlwarning\0"
+  // 0000000000111111111122222 222223333333333444 4444444555555555566666666667777 77777788888888889999999999
+  // 0123456789012345678901234 567890123456789012 3456789012345678901234567890123 45678901234567890123456789
+    "loader_android_dlwarning\0__loader_cfi_fail\0"
 #if defined(__arm__)
-  // 425
+  // 443
     "__loader_dl_unwind_find_exidx\0"
 #endif
     ;
@@ -255,8 +260,9 @@
   ELFW(SYM_INITIALIZER)(348, &__android_create_namespace, 1),
   ELFW(SYM_INITIALIZER)(382, &__dlvsym, 1),
   ELFW(SYM_INITIALIZER)(398, &__android_dlwarning, 1),
+  ELFW(SYM_INITIALIZER)(425, &__cfi_fail, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(425, &__dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(443, &__dl_unwind_find_exidx, 1),
 #endif
 };
 
@@ -273,9 +279,9 @@
 // Note that adding any new symbols here requires stubbing them out in libdl.
 static unsigned g_libdl_buckets[1] = { 1 };
 #if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0 };
 #else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
 #endif
 
 static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
diff --git a/linker/linker.cpp b/linker/linker.cpp
index fc8d1ef..83bd9f3 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -48,6 +48,7 @@
 
 #include "linker.h"
 #include "linker_block_allocator.h"
+#include "linker_cfi.h"
 #include "linker_gdb_support.h"
 #include "linker_globals.h"
 #include "linker_debug.h"
@@ -105,6 +106,12 @@
 // Is ASAN enabled?
 static bool g_is_asan = false;
 
+static CFIShadowWriter g_cfi_shadow;
+
+CFIShadowWriter* get_cfi_shadow() {
+  return &g_cfi_shadow;
+}
+
 static bool is_system_library(const std::string& realpath) {
   for (const auto& dir : g_default_namespace.get_default_library_paths()) {
     if (file_is_in_dir(realpath, dir)) {
@@ -1226,7 +1233,7 @@
 //    target_sdk_version (*candidate != nullptr)
 // 2. The library was not found by soname (*candidate is nullptr)
 static bool find_loaded_library_by_soname(android_namespace_t* ns,
-                                          const char* name, soinfo** candidate) {
+                                         const char* name, soinfo** candidate) {
   *candidate = nullptr;
 
   // Ignore filename with path.
@@ -1504,7 +1511,8 @@
 
   bool linked = local_group.visit([&](soinfo* si) {
     if (!si->is_linked()) {
-      if (!si->link_image(global_group, local_group, extinfo)) {
+      if (!si->link_image(global_group, local_group, extinfo) ||
+          !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
         return false;
       }
     }
@@ -1656,6 +1664,7 @@
 
   while ((si = local_unload_list.pop_front()) != nullptr) {
     notify_gdb_of_unload(si);
+    get_cfi_shadow()->BeforeUnload(si);
     soinfo_free(si);
   }
 
diff --git a/linker/linker.h b/linker/linker.h
index c65d503..7746982 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -103,6 +103,8 @@
 
 soinfo* get_libdl_info(const char* linker_path);
 
+soinfo* find_containing_library(const void* p);
+
 void do_android_get_LD_LIBRARY_PATH(char*, size_t);
 void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
 void* do_dlopen(const char* name,
@@ -125,6 +127,10 @@
 
 int do_dladdr(const void* addr, Dl_info* info);
 
+// void ___cfi_slowpath(uint64_t CallSiteTypeId, void *Ptr, void *Ret);
+// void ___cfi_slowpath_diag(uint64_t CallSiteTypeId, void *Ptr, void *DiagData, void *Ret);
+void ___cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *Ret);
+
 void set_application_target_sdk_version(uint32_t target);
 uint32_t get_application_target_sdk_version();
 
@@ -163,7 +169,4 @@
                                       const char* permitted_when_isolated_path,
                                       android_namespace_t* parent_namespace);
 
-constexpr unsigned kLibraryAlignmentBits = 18;
-constexpr size_t kLibraryAlignment = 1UL << kLibraryAlignmentBits;
-
 #endif
diff --git a/linker/linker_cfi.cpp b/linker/linker_cfi.cpp
new file mode 100644
index 0000000..f788c16
--- /dev/null
+++ b/linker/linker_cfi.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "linker_cfi.h"
+
+#include "linker_debug.h"
+#include "linker_globals.h"
+#include "private/bionic_page.h"
+#include "private/bionic_prctl.h"
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <cstdint>
+
+// Update shadow without making it writable by preparing the data on the side and mremap-ing it in
+// place.
+class ShadowWrite {
+  char* shadow_start;
+  char* shadow_end;
+  char* aligned_start;
+  char* aligned_end;
+  char* tmp_start;
+
+ public:
+  ShadowWrite(uint16_t* s, uint16_t* e) {
+    shadow_start = reinterpret_cast<char*>(s);
+    shadow_end = reinterpret_cast<char*>(e);
+    aligned_start = reinterpret_cast<char*>(PAGE_START(reinterpret_cast<uintptr_t>(shadow_start)));
+    aligned_end = reinterpret_cast<char*>(PAGE_END(reinterpret_cast<uintptr_t>(shadow_end)));
+    tmp_start =
+        reinterpret_cast<char*>(mmap(nullptr, aligned_end - aligned_start, PROT_READ | PROT_WRITE,
+                                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+    CHECK(tmp_start != MAP_FAILED);
+    memcpy(tmp_start, aligned_start, shadow_start - aligned_start);
+    memcpy(tmp_start + (shadow_end - aligned_start), shadow_end, aligned_end - shadow_end);
+  }
+
+  uint16_t* begin() {
+    return reinterpret_cast<uint16_t*>(tmp_start + (shadow_start - aligned_start));
+  }
+
+  uint16_t* end() {
+    return reinterpret_cast<uint16_t*>(tmp_start + (shadow_end - aligned_start));
+  }
+
+  ~ShadowWrite() {
+    size_t size = aligned_end - aligned_start;
+    mprotect(tmp_start, size, PROT_READ);
+    void* res = mremap(tmp_start, size, size, MREMAP_MAYMOVE | MREMAP_FIXED,
+                       reinterpret_cast<void*>(aligned_start));
+    CHECK(res != MAP_FAILED);
+  }
+};
+
+void CFIShadowWriter::FixupVmaName() {
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *shadow_start, kShadowSize, "cfi shadow");
+}
+
+void CFIShadowWriter::AddConstant(uintptr_t begin, uintptr_t end, uint16_t v) {
+  uint16_t* shadow_begin = MemToShadow(begin);
+  uint16_t* shadow_end = MemToShadow(end - 1) + 1;
+
+  ShadowWrite sw(shadow_begin, shadow_end);
+  std::fill(sw.begin(), sw.end(), v);
+}
+
+void CFIShadowWriter::AddUnchecked(uintptr_t begin, uintptr_t end) {
+  AddConstant(begin, end, kUncheckedShadow);
+}
+
+void CFIShadowWriter::AddInvalid(uintptr_t begin, uintptr_t end) {
+  AddConstant(begin, end, kInvalidShadow);
+}
+
+void CFIShadowWriter::Add(uintptr_t begin, uintptr_t end, uintptr_t cfi_check) {
+  CHECK((cfi_check & (kCfiCheckAlign - 1)) == 0);
+
+  // Don't fill anything below cfi_check. We can not represent those addresses
+  // in the shadow, and must make sure at codegen to place all valid call
+  // targets above cfi_check.
+  begin = std::max(begin, cfi_check) & ~(kShadowAlign - 1);
+  uint16_t* shadow_begin = MemToShadow(begin);
+  uint16_t* shadow_end = MemToShadow(end - 1) + 1;
+
+  ShadowWrite sw(shadow_begin, shadow_end);
+  uint16_t sv = ((begin + kShadowAlign - cfi_check) >> kCfiCheckGranularity) + kRegularShadowMin;
+
+  // With each step of the loop below, __cfi_check address computation base is increased by
+  // 2**ShadowGranularity.
+  // To compensate for that, each next shadow value must be increased by 2**ShadowGranularity /
+  // 2**CfiCheckGranularity.
+  uint16_t sv_step = 1 << (kShadowGranularity - kCfiCheckGranularity);
+  for (uint16_t& s : sw) {
+    // If there is something there already, fall back to unchecked. This may happen in rare cases
+    // with MAP_FIXED libraries. FIXME: consider using a (slow) resolution function instead.
+    s = (s == kInvalidShadow) ? sv : kUncheckedShadow;
+    sv += sv_step;
+  }
+}
+
+static soinfo* find_libdl(soinfo* solist) {
+  for (soinfo* si = solist; si != nullptr; si = si->next) {
+    const char* soname = si->get_soname();
+    if (soname && strcmp(soname, "libdl.so") == 0) {
+      return si;
+    }
+  }
+  return nullptr;
+}
+
+static uintptr_t soinfo_find_symbol(soinfo* si, const char* s) {
+  SymbolName name(s);
+  const ElfW(Sym) * sym;
+  if (si->find_symbol_by_name(name, nullptr, &sym) && sym) {
+    return si->resolve_symbol_address(sym);
+  }
+  return 0;
+}
+
+uintptr_t soinfo_find_cfi_check(soinfo* si) {
+  return soinfo_find_symbol(si, "__cfi_check");
+}
+
+uintptr_t CFIShadowWriter::MapShadow() {
+  void* p =
+      mmap(nullptr, kShadowSize, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
+  CHECK(p != MAP_FAILED);
+  return reinterpret_cast<uintptr_t>(p);
+}
+
+bool CFIShadowWriter::AddLibrary(soinfo* si) {
+  CHECK(shadow_start != nullptr);
+  if (si->base == 0 || si->size == 0) {
+    return true;
+  }
+  uintptr_t cfi_check = soinfo_find_cfi_check(si);
+  if (cfi_check == 0) {
+    INFO("[ CFI add 0x%zx + 0x%zx %s ]", static_cast<uintptr_t>(si->base),
+         static_cast<uintptr_t>(si->size), si->get_soname());
+    AddUnchecked(si->base, si->base + si->size);
+    return true;
+  }
+
+  INFO("[ CFI add 0x%zx + 0x%zx %s: 0x%zx ]", static_cast<uintptr_t>(si->base),
+       static_cast<uintptr_t>(si->size), si->get_soname(), cfi_check);
+#ifdef __arm__
+  // Require Thumb encoding.
+  if ((cfi_check & 1UL) != 1UL) {
+    DL_ERR("__cfi_check in not a Thumb function in the library \"%s\"", si->get_soname());
+    return false;
+  }
+  cfi_check &= ~1UL;
+#endif
+  if ((cfi_check & (kCfiCheckAlign - 1)) != 0) {
+    DL_ERR("unaligned __cfi_check in the library \"%s\"", si->get_soname());
+    return false;
+  }
+  Add(si->base, si->base + si->size, cfi_check);
+  return true;
+}
+
+// Pass the shadow mapping address to libdl.so. In return, we get an pointer to the location
+// libdl.so uses to store the address.
+bool CFIShadowWriter::NotifyLibDl(soinfo* solist, uintptr_t p) {
+  soinfo* libdl = find_libdl(solist);
+  if (libdl == nullptr) {
+    DL_ERR("CFI could not find libdl");
+    return false;
+  }
+
+  uintptr_t cfi_init = soinfo_find_symbol(libdl, "__cfi_init");
+  CHECK(cfi_init != 0);
+  shadow_start = reinterpret_cast<uintptr_t* (*)(uintptr_t)>(cfi_init)(p);
+  CHECK(shadow_start != nullptr);
+  CHECK(*shadow_start == p);
+  return true;
+}
+
+bool CFIShadowWriter::MaybeInit(soinfo* new_si, soinfo* solist) {
+  CHECK(initial_link_done);
+  // Check if CFI shadow must be initialized at this time.
+  bool found = false;
+  if (new_si == nullptr) {
+    // This is the case when we've just completed the initial link. There may have been earlier
+    // calls to MaybeInit that were skipped. Look though the entire solist.
+    for (soinfo* si = solist; si != nullptr; si = si->next) {
+      if (soinfo_find_cfi_check(si)) {
+        found = true;
+        break;
+      }
+    }
+  } else {
+    // See if the new library uses CFI.
+    found = soinfo_find_cfi_check(new_si);
+  }
+
+  // Nothing found.
+  if (!found) {
+    return true;
+  }
+
+  // Init shadow and add all currently loaded libraries (not just the new ones).
+  if (!NotifyLibDl(solist, MapShadow()))
+    return false;
+  for (soinfo* si = solist; si != nullptr; si = si->next) {
+    if (!AddLibrary(si))
+      return false;
+  }
+  FixupVmaName();
+  return true;
+}
+
+bool CFIShadowWriter::AfterLoad(soinfo* si, soinfo* solist) {
+  if (!initial_link_done) {
+    // Too early.
+    return true;
+  }
+
+  if (shadow_start == nullptr) {
+    return MaybeInit(si, solist);
+  }
+
+  // Add the new library to the CFI shadow.
+  if (!AddLibrary(si))
+    return false;
+  FixupVmaName();
+  return true;
+}
+
+void CFIShadowWriter::BeforeUnload(soinfo* si) {
+  if (shadow_start == nullptr) return;
+  if (si->base == 0 || si->size == 0) return;
+  INFO("[ CFI remove 0x%zx + 0x%zx: %s ]", static_cast<uintptr_t>(si->base),
+       static_cast<uintptr_t>(si->size), si->get_soname());
+  AddInvalid(si->base, si->base + si->size);
+  FixupVmaName();
+}
+
+bool CFIShadowWriter::InitialLinkDone(soinfo* solist) {
+  CHECK(!initial_link_done)
+  initial_link_done = true;
+  return MaybeInit(nullptr, solist);
+}
+
+// Find __cfi_check in the caller and let it handle the problem. Since caller_pc is likely not a
+// valid CFI target, we can not use CFI shadow for lookup. This does not need to be fast, do the
+// regular symbol lookup.
+void CFIShadowWriter::CfiFail(uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void* CallerPc) {
+  soinfo* si = find_containing_library(CallerPc);
+  if (!si) {
+    __builtin_trap();
+  }
+
+  uintptr_t cfi_check = soinfo_find_cfi_check(si);
+  if (!cfi_check) {
+    __builtin_trap();
+  }
+
+  reinterpret_cast<CFICheckFn>(cfi_check)(CallSiteTypeId, Ptr, DiagData);
+}
diff --git a/linker/linker_cfi.h b/linker/linker_cfi.h
new file mode 100644
index 0000000..df76421
--- /dev/null
+++ b/linker/linker_cfi.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LINKER_CFI_H_
+#define _LINKER_CFI_H_
+
+#include "linker.h"
+#include "linker_debug.h"
+
+#include <algorithm>
+
+#include "private/CFIShadow.h"
+
+// This class keeps the contents of CFI shadow up-to-date with the current set of loaded libraries.
+// See the comment in CFIShadow.h for more context.
+// See documentation in http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html#shared-library-support.
+//
+// Shadow is mapped and initialized lazily as soon as the first CFI-enabled DSO is loaded.
+// It is updated after a set of libraries is loaded (but before any constructors are ran), and
+// before any library is unloaded.
+class CFIShadowWriter : private CFIShadow {
+  // Returns pointer to the shadow element for an address.
+  uint16_t* MemToShadow(uintptr_t x) {
+    return reinterpret_cast<uint16_t*>(*shadow_start + MemToShadowOffset(x));
+  }
+
+  // Update shadow for the address range to the given constant value.
+  void AddConstant(uintptr_t begin, uintptr_t end, uint16_t v);
+
+  // Update shadow for the address range to kUncheckedShadow.
+  void AddUnchecked(uintptr_t begin, uintptr_t end);
+
+  // Update shadow for the address range to kInvalidShadow.
+  void AddInvalid(uintptr_t begin, uintptr_t end);
+
+  // Update shadow for the address range to the given __cfi_check value.
+  void Add(uintptr_t begin, uintptr_t end, uintptr_t cfi_check);
+
+  // Add a DSO to CFI shadow.
+  bool AddLibrary(soinfo* si);
+
+  // Map CFI shadow.
+  uintptr_t MapShadow();
+
+  // Initialize CFI shadow and update its contents for everything in solist if any loaded library is
+  // CFI-enabled. If soinfos != nullptr, do an incremental check by looking only at the libraries in
+  // soinfos[]; otherwise look at the entire solist.
+  //
+  // Returns false if the shadow is already initialized. It is the caller's responsibility to update
+  // the shadow for the new libraries in that case.
+  // Otherwise, returns true and leaves the shadow either up-to-date or uninitialized.
+  bool MaybeInit(soinfo *new_si, soinfo *solist);
+
+  // Set a human readable name for the entire shadow region.
+  void FixupVmaName();
+
+  bool NotifyLibDl(soinfo *solist, uintptr_t p);
+
+  // Pointer to the shadow start address.
+  uintptr_t *shadow_start;
+
+  bool initial_link_done;
+
+ public:
+  // Update shadow after loading a set of DSOs.
+  // This function will initialize the shadow if it sees a CFI-enabled DSO for the first time.
+  // In that case it will retroactively update shadow for all previously loaded DSOs. "solist" is a
+  // pointer to the global list.
+  // This function must be called before any user code has observed the newly loaded DSO.
+  bool AfterLoad(soinfo* si, soinfo *solist);
+
+  // Update shadow before unloading a DSO.
+  void BeforeUnload(soinfo* si);
+
+  bool InitialLinkDone(soinfo *solist);
+
+  // Handle failure to locate __cfi_check for a target address.
+  static void CfiFail(uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void *caller_pc);
+};
+
+CFIShadowWriter* get_cfi_shadow();
+
+#endif // _LINKER_CFI_H_
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index dad7409..9ed7505 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -29,6 +29,7 @@
 #include "linker_main.h"
 
 #include "linker_debug.h"
+#include "linker_cfi.h"
 #include "linker_gdb_support.h"
 #include "linker_globals.h"
 #include "linker_phdr.h"
@@ -41,7 +42,7 @@
 #include "android-base/strings.h"
 #include "android-base/stringprintf.h"
 #ifdef __ANDROID__
-#include "debuggerd/client.h"
+#include "debuggerd/handler.h"
 #endif
 
 #include <vector>
@@ -368,6 +369,10 @@
 
   add_vdso(args);
 
+  if (!get_cfi_shadow()->InitialLinkDone(solist)) {
+    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+  }
+
   {
     ProtectedDataGuard guard;
 
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index a453bef..72549cc 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -42,6 +42,7 @@
 #include "linker_utils.h"
 
 #include "private/bionic_prctl.h"
+#include "private/CFIShadow.h" // For kLibraryAlignment
 
 static int GetTargetElfMachine() {
 #if defined(__arm__)
diff --git a/tests/Android.bp b/tests/Android.bp
index fe34b9f..85ae26e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -295,6 +295,7 @@
     target: {
         android: {
             srcs: [
+                "cfi_test.cpp",
                 "dlext_test.cpp",
                 "libdl_test.cpp",
             ],
@@ -442,7 +443,7 @@
         "libtinyxml2",
         "liblog",
         "libbase",
-        "libdebuggerd_client",
+        "libdebuggerd_handler",
     ],
 
     static_executable: true,
diff --git a/tests/cfi_test.cpp b/tests/cfi_test.cpp
new file mode 100644
index 0000000..0f93edb
--- /dev/null
+++ b/tests/cfi_test.cpp
@@ -0,0 +1,94 @@
+#include <gtest/gtest.h>
+#include <dlfcn.h>
+
+#include "BionicDeathTest.h"
+
+// Private libdl interface.
+extern "C" {
+void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr);
+void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void* Ptr, void* DiagData);
+}
+
+static void f() {}
+
+TEST(cfi_test, basic) {
+  void* handle;
+  handle = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+#define SYM(type, name) auto name = reinterpret_cast<type>(dlsym(handle, #name))
+  SYM(int (*)(), get_count);
+  SYM(uint64_t(*)(), get_last_type_id);
+  SYM(void* (*)(), get_last_address);
+  SYM(void* (*)(), get_last_diag);
+  SYM(void* (*)(), get_global_address);
+  SYM(void (*)(uint64_t, void*, void*), __cfi_check);
+#undef SYM
+
+  int c = get_count();
+
+  // CFI check for code inside the DSO. Can't use just any function address - this is only
+  // guaranteed to work for code addresses above __cfi_check.
+  void* code_ptr = reinterpret_cast<char*>(__cfi_check) + 1234;
+  void* diag_ptr = reinterpret_cast<void*>(5678);
+  __cfi_slowpath_diag(42, code_ptr, diag_ptr);
+  EXPECT_EQ(42U, get_last_type_id());
+  EXPECT_EQ(code_ptr, get_last_address());
+  EXPECT_EQ(diag_ptr, get_last_diag());
+  EXPECT_EQ(++c, get_count());
+
+  // __cfi_slowpath passes nullptr for the Diag argument.
+  __cfi_slowpath(42, code_ptr);
+  EXPECT_EQ(42U, get_last_type_id());
+  EXPECT_EQ(code_ptr, get_last_address());
+  EXPECT_EQ(nullptr, get_last_diag());
+  EXPECT_EQ(++c, get_count());
+
+  // CFI check for a data address inside the DSO.
+  __cfi_slowpath(43, get_global_address());
+  EXPECT_EQ(43U, get_last_type_id());
+  EXPECT_EQ(get_global_address(), get_last_address());
+  EXPECT_EQ(++c, get_count());
+
+  // CFI check for a function inside _this_ DSO. It either goes to this DSO's __cfi_check,
+  // or (if missing) is simply ignored. Any way, it does not affect the test lib's counters.
+  __cfi_slowpath(44, reinterpret_cast<void*>(&f));
+  EXPECT_EQ(43U, get_last_type_id());
+  EXPECT_EQ(get_global_address(), get_last_address());
+  EXPECT_EQ(c, get_count());
+
+  // CFI check for a stack address. This is always invalid and gets the process killed.
+  EXPECT_DEATH(__cfi_slowpath(45, reinterpret_cast<void*>(&c)), "");
+
+  // CFI check for a heap address. This is always invalid and gets the process killed.
+  void* p = malloc(4096);
+  EXPECT_DEATH(__cfi_slowpath(46, p), "");
+  free(p);
+
+  // Load the same library again.
+  void* handle2 = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(handle2 != nullptr) << dlerror();
+  EXPECT_EQ(handle2, handle);
+
+  // Check that it is still there.
+  __cfi_slowpath(43, get_global_address());
+  EXPECT_EQ(43U, get_last_type_id());
+  EXPECT_EQ(get_global_address(), get_last_address());
+  EXPECT_EQ(++c, get_count());
+
+  dlclose(handle);
+  dlclose(handle2);
+
+  // CFI check for a function inside the unloaded DSO. This is always invalid and gets the process
+  // killed.
+  EXPECT_DEATH(__cfi_slowpath(45, reinterpret_cast<void*>(code_ptr)), "");
+}
+
+TEST(cfi_test, invalid) {
+  void* handle;
+  handle = dlopen("libcfi-test-bad.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_FALSE(handle != nullptr) << dlerror();
+
+  handle = dlopen("libcfi-test-bad.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_FALSE(handle != nullptr) << dlerror();
+}
diff --git a/tests/gtest_preinit_debuggerd.cpp b/tests/gtest_preinit_debuggerd.cpp
index aac2e3f..88ca63b 100644
--- a/tests/gtest_preinit_debuggerd.cpp
+++ b/tests/gtest_preinit_debuggerd.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "debuggerd/client.h"
+#include "debuggerd/handler.h"
 
 void __gtest_preinit() {
   debuggerd_init(nullptr);
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 004f668..b5855af 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -24,7 +24,8 @@
     relative_install_path: "bionic-loader-test-libs",
     gtest: false,
     sanitize: {
-        never: true,
+        address: false,
+        coverage: false,
     },
     stl: "libc++_static",
     target: {
@@ -475,3 +476,21 @@
         "libutils",
     ],
 }
+
+cc_test_library {
+    name: "libcfi-test",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["cfi_test_lib.cpp"],
+    sanitize: {
+        cfi: false,
+    },
+}
+
+cc_test_library {
+    name: "libcfi-test-bad",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["cfi_test_bad_lib.cpp"],
+    sanitize: {
+        cfi: false,
+    },
+}
diff --git a/tests/libs/cfi_test_bad_lib.cpp b/tests/libs/cfi_test_bad_lib.cpp
new file mode 100644
index 0000000..429c843
--- /dev/null
+++ b/tests/libs/cfi_test_bad_lib.cpp
@@ -0,0 +1,4 @@
+// Mock an invalid CFI-enabled library.
+__attribute__((aligned(4096))) extern "C" char dummy[16] = {};
+__asm__(".globl __cfi_check");
+__asm__("__cfi_check = dummy + 3"); // Not aligned to anything.
diff --git a/tests/libs/cfi_test_lib.cpp b/tests/libs/cfi_test_lib.cpp
new file mode 100644
index 0000000..b0e2f42
--- /dev/null
+++ b/tests/libs/cfi_test_lib.cpp
@@ -0,0 +1,68 @@
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+// This library is built for all targets, including host tests, so __cfi_slowpath may not be
+// present. But it is only used in the bionic loader tests.
+extern "C" __attribute__((weak)) void __cfi_slowpath(uint64_t, void*);
+
+static int g_count;
+static uint64_t g_last_type_id;
+static void* g_last_address;
+static void* g_last_diag;
+
+extern "C" {
+
+// Mock a CFI-enabled library without relying on the compiler.
+__attribute__((aligned(4096))) void __cfi_check(uint64_t CallSiteTypeId, void* TargetAddr,
+                                                void* Diag) {
+  ++g_count;
+  g_last_type_id = CallSiteTypeId;
+  g_last_address = TargetAddr;
+  g_last_diag = Diag;
+}
+
+int get_count() {
+  return g_count;
+}
+
+uint64_t get_last_type_id() {
+  return g_last_type_id;
+}
+
+void* get_last_address() {
+  return g_last_address;
+}
+
+void* get_last_diag() {
+  return g_last_diag;
+}
+
+void* get_global_address() {
+  return &g_count;
+}
+}
+
+// Check that CFI is set up in module constructors and destructors.
+struct A {
+  void check_cfi_self() {
+    g_last_type_id = 0;
+    assert(&__cfi_slowpath);
+    // CFI check for an invalid address. Normally, this would kill the process by routing the call
+    // back to the calling module's __cfi_check, which does the right thing based on
+    // -fsanitize-recover / -fsanitize-trap. But this module has custom __cfi_check that does not do
+    // any of that, so the result looks like a passing check.
+    int zz;
+    __cfi_slowpath(13, static_cast<void*>(&zz));
+    assert(g_last_type_id == 13);
+    // CFI check for a libc function. This never goes into this module's __cfi_check, and must pass.
+    __cfi_slowpath(14, reinterpret_cast<void*>(&exit));
+    assert(g_last_type_id == 13);
+  }
+  A() {
+    check_cfi_self();
+  }
+  ~A() {
+    check_cfi_self();
+  }
+} a;