Merge "Fix dns search domain use in gethostbyname."
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
new file mode 100644
index 0000000..83e490f
--- /dev/null
+++ b/benchmarks/Android.mk
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2013 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.
+#
+
+ifneq ($(BUILD_TINY_ANDROID), true)
+
+LOCAL_PATH := $(call my-dir)
+
+# -----------------------------------------------------------------------------
+# Benchmarks.
+# -----------------------------------------------------------------------------
+
+benchmark_c_flags = \
+    -O2 \
+    -Wall -Wextra \
+    -Werror \
+    -fno-builtin \
+
+benchmark_src_files = \
+    benchmark_main.cpp \
+    math_benchmark.cpp \
+    property_benchmark.cpp \
+    string_benchmark.cpp \
+    time_benchmark.cpp \
+
+# Build benchmarks for the device (with bionic's .so). Run with:
+#   adb shell bionic-benchmarks
+include $(CLEAR_VARS)
+LOCAL_MODULE := bionic-benchmarks
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += $(benchmark_c_flags)
+LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
+LOCAL_SHARED_LIBRARIES += libstlport
+LOCAL_SRC_FILES := $(benchmark_src_files)
+include $(BUILD_EXECUTABLE)
+
+endif # !BUILD_TINY_ANDROID
diff --git a/tests/benchmark.h b/benchmarks/benchmark.h
similarity index 100%
rename from tests/benchmark.h
rename to benchmarks/benchmark.h
diff --git a/tests/benchmark_main.cpp b/benchmarks/benchmark_main.cpp
similarity index 100%
rename from tests/benchmark_main.cpp
rename to benchmarks/benchmark_main.cpp
diff --git a/tests/math_benchmark.cpp b/benchmarks/math_benchmark.cpp
similarity index 100%
rename from tests/math_benchmark.cpp
rename to benchmarks/math_benchmark.cpp
diff --git a/tests/property_benchmark.cpp b/benchmarks/property_benchmark.cpp
similarity index 100%
rename from tests/property_benchmark.cpp
rename to benchmarks/property_benchmark.cpp
diff --git a/tests/string_benchmark.cpp b/benchmarks/string_benchmark.cpp
similarity index 100%
rename from tests/string_benchmark.cpp
rename to benchmarks/string_benchmark.cpp
diff --git a/tests/time_benchmark.cpp b/benchmarks/time_benchmark.cpp
similarity index 100%
rename from tests/time_benchmark.cpp
rename to benchmarks/time_benchmark.cpp
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index c5dc402..1277b1a 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -57,10 +57,9 @@
 int     setresgid:setresgid32(gid_t, gid_t, gid_t)   arm,x86
 int     setresgid:setresgid(gid_t, gid_t, gid_t)     aarch64,mips,x86_64
 void*   __brk:brk(void*)           all
-# See comments in kill.S to understand why we don't generate ARM stubs for kill/tkill/tgkill.
-int     kill(pid_t, int)           aarch64,mips,x86,x86_64
-int     tkill(pid_t tid, int sig)  aarch64,mips,x86,x86_64
-int     tgkill(pid_t tgid, pid_t tid, int sig)  aarch64,mips,x86,x86_64
+int     kill(pid_t, int)           all
+int     tkill(pid_t tid, int sig)  all
+int     tgkill(pid_t tgid, pid_t tid, int sig)  all
 int     __ptrace:ptrace(int request, int pid, void* addr, void* data)  all
 int     __set_thread_area:set_thread_area(void*  user_desc)  mips,x86
 int     __getpriority:getpriority(int, int)  all
diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
index 0717306..95c3b61 100644
--- a/libc/arch-arm/arm.mk
+++ b/libc/arch-arm/arm.mk
@@ -6,7 +6,6 @@
     arch-arm/bionic/_exit_with_stack_teardown.S \
     arch-arm/bionic/futex_arm.S \
     arch-arm/bionic/__get_sp.S \
-    arch-arm/bionic/kill.S \
     arch-arm/bionic/libgcc_compat.c \
     arch-arm/bionic/memcmp16.S \
     arch-arm/bionic/memcmp.S \
@@ -14,8 +13,6 @@
     arch-arm/bionic/setjmp.S \
     arch-arm/bionic/sigsetjmp.S \
     arch-arm/bionic/syscall.S \
-    arch-arm/bionic/tgkill.S \
-    arch-arm/bionic/tkill.S \
 
 # These are used by the static and dynamic versions of the libc
 # respectively.
diff --git a/libc/arch-arm/bionic/__bionic_clone.S b/libc/arch-arm/bionic/__bionic_clone.S
index 0782abe..7b76f5e 100644
--- a/libc/arch-arm/bionic/__bionic_clone.S
+++ b/libc/arch-arm/bionic/__bionic_clone.S
@@ -31,10 +31,13 @@
 // pid_t __bionic_clone(int flags, void* child_stack, pid_t* parent_tid, void* tls, pid_t* child_tid, int (*fn)(void*), void* arg);
 ENTRY(__bionic_clone)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
-
     # save registers to parent stack
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
 
     # load extra parameters
     ldmfd   ip, {r4, r5, r6}
@@ -51,12 +54,19 @@
 
     # In the parent, reload saved registers then either return or set errno.
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
     b       __set_errno
 
 1:  # The child.
+    # Re-add the unwind directives that were reset from above.
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldr    r0, [sp, #-4]
     ldr    r1, [sp, #-8]
     b      __bionic_clone_entry
diff --git a/libc/arch-arm/bionic/abort_arm.S b/libc/arch-arm/bionic/abort_arm.S
index e1ab86b..1aaf21a 100644
--- a/libc/arch-arm/bionic/abort_arm.S
+++ b/libc/arch-arm/bionic/abort_arm.S
@@ -36,7 +36,9 @@
  * sequence when the crash happens.
  */
 ENTRY(abort)
-    .save   {r3, r14}
     stmfd   sp!, {r3, r14}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r3, 0
+    .cfi_rel_offset r14, 4
     bl      PIC_SYM(_C_LABEL(__libc_android_abort), PLT)
 END(abort)
diff --git a/libc/arch-arm/bionic/kill.S b/libc/arch-arm/bionic/kill.S
deleted file mode 100644
index 0d24a3f..0000000
--- a/libc/arch-arm/bionic/kill.S
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <private/bionic_asm.h>
-
-/* unlike our auto-generated syscall stubs, this code saves lr
-   on the stack, as well as a few other registers. this makes
-   our stack unwinder happy, when we generate debug stack
-   traces after the C library or other parts of the system
-   abort due to a fatal runtime error (e.g. detection
-   of a corrupted malloc heap).
-*/
-
-ENTRY(kill)
-    stmfd   sp!, {r4-r7, ip, lr}
-    ldr     r7, =__NR_kill
-    swi     #0
-    ldmfd   sp!, {r4-r7, ip, lr}
-    cmn     r0, #(MAX_ERRNO + 1)
-    bxls    lr
-    neg     r0, r0
-    b       __set_errno
-END(kill)
diff --git a/libc/arch-arm/bionic/memcmp.S b/libc/arch-arm/bionic/memcmp.S
index 7fb4283..0dc3af0 100644
--- a/libc/arch-arm/bionic/memcmp.S
+++ b/libc/arch-arm/bionic/memcmp.S
@@ -107,9 +107,11 @@
         bmi        10f
 #endif
 
-        .save {r4, lr}
         /* save registers */
         stmfd       sp!, {r4, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r4, 0
+        .cfi_rel_offset lr, 4
 
         /* since r0 hold the result, move the first source
          * pointer somewhere else
diff --git a/libc/arch-arm/bionic/memcmp16.S b/libc/arch-arm/bionic/memcmp16.S
index 99c9b88..825c94f 100644
--- a/libc/arch-arm/bionic/memcmp16.S
+++ b/libc/arch-arm/bionic/memcmp16.S
@@ -74,9 +74,11 @@
         bx          lr
 
 
-        .save {r4, lr}
         /* save registers */
 0:      stmfd       sp!, {r4, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r4, 0
+        .cfi_rel_offset lr, 4
         
         /* align first pointer to word boundary */
         tst         r3, #2
diff --git a/libc/arch-arm/bionic/setjmp.S b/libc/arch-arm/bionic/setjmp.S
index 996e55e..65b93fd 100644
--- a/libc/arch-arm/bionic/setjmp.S
+++ b/libc/arch-arm/bionic/setjmp.S
@@ -51,12 +51,16 @@
 ENTRY(setjmp)
 	/* Block all signals and retrieve the old signal mask */
 	stmfd	sp!, {r0, r14}
+	.cfi_def_cfa_offset 8
+	.cfi_rel_offset r0, 0
+	.cfi_rel_offset r14, 4
 	mov	r0, #0x00000000
 
 	bl	PIC_SYM(_C_LABEL(sigblock), PLT)
 	mov	r1, r0
 
 	ldmfd	sp!, {r0, r14}
+	.cfi_def_cfa_offset 0
 
 	/* Store signal mask */
 	str	r1, [r0, #(_JB_SIGMASK * 4)]
@@ -96,13 +100,20 @@
 
 	/* Set signal mask */
 	stmfd	sp!, {r0, r1, r14}
+	.cfi_def_cfa_offset 12
+	.cfi_rel_offset r0, 0
+	.cfi_rel_offset r1, 4
+	.cfi_rel_offset r14, 8
 	sub	sp, sp, #4	/* align the stack */
+	.cfi_adjust_cfa_offset 4
 
 	mov	r0, r2
 	bl	PIC_SYM(_C_LABEL(sigsetmask), PLT)
 
 	add	sp, sp, #4	/* unalign the stack */
+	.cfi_adjust_cfa_offset -4
 	ldmfd	sp!, {r0, r1, r14} 
+	.cfi_def_cfa_offset 0
 
 #ifdef __ARM_HAVE_VFP
 	/* Restore floating-point registers */
diff --git a/libc/arch-arm/bionic/syscall.S b/libc/arch-arm/bionic/syscall.S
index a622b58..8647718 100644
--- a/libc/arch-arm/bionic/syscall.S
+++ b/libc/arch-arm/bionic/syscall.S
@@ -31,6 +31,11 @@
 ENTRY(syscall)
     mov     ip, sp
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     mov     r7, r0
     mov     r0, r1
     mov     r1, r2
@@ -38,6 +43,7 @@
     ldmfd   ip, {r3, r4, r5, r6}
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/bionic/tgkill.S b/libc/arch-arm/bionic/tgkill.S
deleted file mode 100644
index 4ef2abc..0000000
--- a/libc/arch-arm/bionic/tgkill.S
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <private/bionic_asm.h>
-
-/* unlike our auto-generated syscall stubs, this code saves lr
-   on the stack, as well as a few other registers. this makes
-   our stack unwinder happy, when we generate debug stack
-   traces after the C library or other parts of the system
-   abort due to a fatal runtime error (e.g. detection
-   of a corrupted malloc heap).
-*/
-
-ENTRY(tgkill)
-    .save   {r4-r7, ip, lr}
-    stmfd   sp!, {r4-r7, ip, lr}
-    ldr     r7, =__NR_tgkill
-    swi     #0
-    ldmfd   sp!, {r4-r7, ip, lr}
-    cmn     r0, #(MAX_ERRNO + 1)
-    bxls    lr
-    neg     r0, r0
-    b       __set_errno
-END(tgkill)
diff --git a/libc/arch-arm/bionic/tkill.S b/libc/arch-arm/bionic/tkill.S
deleted file mode 100644
index 0a067d6..0000000
--- a/libc/arch-arm/bionic/tkill.S
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <private/bionic_asm.h>
-
-/* unlike our auto-generated syscall stubs, this code saves lr
-   on the stack, as well as a few other registers. this makes
-   our stack unwinder happy, when we generate debug stack
-   traces after the C library or other parts of the system
-   abort due to a fatal runtime error (e.g. detection
-   of a corrupted malloc heap).
-*/
-
-ENTRY(tkill)
-    stmfd   sp!, {r4-r7, ip, lr}
-    ldr     r7, =__NR_tkill
-    swi     #0
-    ldmfd   sp!, {r4-r7, ip, lr}
-    cmn     r0, #(MAX_ERRNO + 1)
-    bxls    lr
-    neg     r0, r0
-    b       __set_errno
-END(tkill)
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index c0438b4..a1d4689 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -100,6 +100,7 @@
 syscall_src += arch-arm/syscalls/inotify_rm_watch.S
 syscall_src += arch-arm/syscalls/ioprio_get.S
 syscall_src += arch-arm/syscalls/ioprio_set.S
+syscall_src += arch-arm/syscalls/kill.S
 syscall_src += arch-arm/syscalls/klogctl.S
 syscall_src += arch-arm/syscalls/lgetxattr.S
 syscall_src += arch-arm/syscalls/linkat.S
@@ -175,10 +176,12 @@
 syscall_src += arch-arm/syscalls/symlinkat.S
 syscall_src += arch-arm/syscalls/sync.S
 syscall_src += arch-arm/syscalls/sysinfo.S
+syscall_src += arch-arm/syscalls/tgkill.S
 syscall_src += arch-arm/syscalls/timerfd_create.S
 syscall_src += arch-arm/syscalls/timerfd_gettime.S
 syscall_src += arch-arm/syscalls/timerfd_settime.S
 syscall_src += arch-arm/syscalls/times.S
+syscall_src += arch-arm/syscalls/tkill.S
 syscall_src += arch-arm/syscalls/truncate.S
 syscall_src += arch-arm/syscalls/truncate64.S
 syscall_src += arch-arm/syscalls/umask.S
diff --git a/libc/arch-arm/syscalls/__epoll_pwait.S b/libc/arch-arm/syscalls/__epoll_pwait.S
index f0b1444..b2d8d48 100644
--- a/libc/arch-arm/syscalls/__epoll_pwait.S
+++ b/libc/arch-arm/syscalls/__epoll_pwait.S
@@ -4,12 +4,17 @@
 
 ENTRY(__epoll_pwait)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_epoll_pwait
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/__llseek.S b/libc/arch-arm/syscalls/__llseek.S
index 5d215a4..ec307d2 100644
--- a/libc/arch-arm/syscalls/__llseek.S
+++ b/libc/arch-arm/syscalls/__llseek.S
@@ -4,12 +4,17 @@
 
 ENTRY(__llseek)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR__llseek
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/__mmap2.S b/libc/arch-arm/syscalls/__mmap2.S
index c8dec86..8a17997 100644
--- a/libc/arch-arm/syscalls/__mmap2.S
+++ b/libc/arch-arm/syscalls/__mmap2.S
@@ -4,12 +4,17 @@
 
 ENTRY(__mmap2)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_mmap2
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/__ppoll.S b/libc/arch-arm/syscalls/__ppoll.S
index 5992178..d9fb3d9 100644
--- a/libc/arch-arm/syscalls/__ppoll.S
+++ b/libc/arch-arm/syscalls/__ppoll.S
@@ -4,12 +4,17 @@
 
 ENTRY(__ppoll)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_ppoll
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/__pselect6.S b/libc/arch-arm/syscalls/__pselect6.S
index d44e7ed..05fea54 100644
--- a/libc/arch-arm/syscalls/__pselect6.S
+++ b/libc/arch-arm/syscalls/__pselect6.S
@@ -4,12 +4,17 @@
 
 ENTRY(__pselect6)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_pselect6
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/__waitid.S b/libc/arch-arm/syscalls/__waitid.S
index 51b6487..e5e1f54 100644
--- a/libc/arch-arm/syscalls/__waitid.S
+++ b/libc/arch-arm/syscalls/__waitid.S
@@ -4,12 +4,17 @@
 
 ENTRY(__waitid)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_waitid
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/fchownat.S b/libc/arch-arm/syscalls/fchownat.S
index 12a7710..ea8193f 100644
--- a/libc/arch-arm/syscalls/fchownat.S
+++ b/libc/arch-arm/syscalls/fchownat.S
@@ -4,12 +4,17 @@
 
 ENTRY(fchownat)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_fchownat
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/fsetxattr.S b/libc/arch-arm/syscalls/fsetxattr.S
index 7f95720..64b8d03 100644
--- a/libc/arch-arm/syscalls/fsetxattr.S
+++ b/libc/arch-arm/syscalls/fsetxattr.S
@@ -4,12 +4,17 @@
 
 ENTRY(fsetxattr)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_fsetxattr
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/futex.S b/libc/arch-arm/syscalls/futex.S
index a553b7e..1646ca2 100644
--- a/libc/arch-arm/syscalls/futex.S
+++ b/libc/arch-arm/syscalls/futex.S
@@ -4,12 +4,17 @@
 
 ENTRY(futex)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_futex
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/getsockopt.S b/libc/arch-arm/syscalls/getsockopt.S
index e5cac30..2ded34f 100644
--- a/libc/arch-arm/syscalls/getsockopt.S
+++ b/libc/arch-arm/syscalls/getsockopt.S
@@ -4,12 +4,17 @@
 
 ENTRY(getsockopt)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_getsockopt
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/kill.S b/libc/arch-arm/syscalls/kill.S
new file mode 100644
index 0000000..9a44208
--- /dev/null
+++ b/libc/arch-arm/syscalls/kill.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(kill)
+    mov     ip, r7
+    ldr     r7, =__NR_kill
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(kill)
diff --git a/libc/arch-arm/syscalls/linkat.S b/libc/arch-arm/syscalls/linkat.S
index 5e4d541..27f1e00 100644
--- a/libc/arch-arm/syscalls/linkat.S
+++ b/libc/arch-arm/syscalls/linkat.S
@@ -4,12 +4,17 @@
 
 ENTRY(linkat)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_linkat
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/lsetxattr.S b/libc/arch-arm/syscalls/lsetxattr.S
index c1a26b4..fb3f75f 100644
--- a/libc/arch-arm/syscalls/lsetxattr.S
+++ b/libc/arch-arm/syscalls/lsetxattr.S
@@ -4,12 +4,17 @@
 
 ENTRY(lsetxattr)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_lsetxattr
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/mount.S b/libc/arch-arm/syscalls/mount.S
index dae9f3c..d56682c 100644
--- a/libc/arch-arm/syscalls/mount.S
+++ b/libc/arch-arm/syscalls/mount.S
@@ -4,12 +4,17 @@
 
 ENTRY(mount)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_mount
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/perf_event_open.S b/libc/arch-arm/syscalls/perf_event_open.S
index 4cd624e..2821ac5 100644
--- a/libc/arch-arm/syscalls/perf_event_open.S
+++ b/libc/arch-arm/syscalls/perf_event_open.S
@@ -4,12 +4,17 @@
 
 ENTRY(perf_event_open)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_perf_event_open
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/prctl.S b/libc/arch-arm/syscalls/prctl.S
index 51b3c97..615a2fa 100644
--- a/libc/arch-arm/syscalls/prctl.S
+++ b/libc/arch-arm/syscalls/prctl.S
@@ -4,12 +4,17 @@
 
 ENTRY(prctl)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_prctl
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/pread64.S b/libc/arch-arm/syscalls/pread64.S
index 59bd154..0bfb6d0 100644
--- a/libc/arch-arm/syscalls/pread64.S
+++ b/libc/arch-arm/syscalls/pread64.S
@@ -4,12 +4,17 @@
 
 ENTRY(pread64)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_pread64
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/pwrite64.S b/libc/arch-arm/syscalls/pwrite64.S
index 18477f4..03247b1 100644
--- a/libc/arch-arm/syscalls/pwrite64.S
+++ b/libc/arch-arm/syscalls/pwrite64.S
@@ -4,12 +4,17 @@
 
 ENTRY(pwrite64)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_pwrite64
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/readahead.S b/libc/arch-arm/syscalls/readahead.S
index acd35bd..83d8442 100644
--- a/libc/arch-arm/syscalls/readahead.S
+++ b/libc/arch-arm/syscalls/readahead.S
@@ -4,12 +4,17 @@
 
 ENTRY(readahead)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_readahead
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/recvfrom.S b/libc/arch-arm/syscalls/recvfrom.S
index 54c7855..cb89f72 100644
--- a/libc/arch-arm/syscalls/recvfrom.S
+++ b/libc/arch-arm/syscalls/recvfrom.S
@@ -4,12 +4,17 @@
 
 ENTRY(recvfrom)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_recvfrom
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/sendto.S b/libc/arch-arm/syscalls/sendto.S
index b430e06..bd0ec1d 100644
--- a/libc/arch-arm/syscalls/sendto.S
+++ b/libc/arch-arm/syscalls/sendto.S
@@ -4,12 +4,17 @@
 
 ENTRY(sendto)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_sendto
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/setsockopt.S b/libc/arch-arm/syscalls/setsockopt.S
index 9dc7b1e..b2d7597 100644
--- a/libc/arch-arm/syscalls/setsockopt.S
+++ b/libc/arch-arm/syscalls/setsockopt.S
@@ -4,12 +4,17 @@
 
 ENTRY(setsockopt)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_setsockopt
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/setxattr.S b/libc/arch-arm/syscalls/setxattr.S
index 536630b..022195d 100644
--- a/libc/arch-arm/syscalls/setxattr.S
+++ b/libc/arch-arm/syscalls/setxattr.S
@@ -4,12 +4,17 @@
 
 ENTRY(setxattr)
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =__NR_setxattr
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
diff --git a/libc/arch-arm/syscalls/tgkill.S b/libc/arch-arm/syscalls/tgkill.S
new file mode 100644
index 0000000..4ea04f5
--- /dev/null
+++ b/libc/arch-arm/syscalls/tgkill.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(tgkill)
+    mov     ip, r7
+    ldr     r7, =__NR_tgkill
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(tgkill)
diff --git a/libc/arch-arm/syscalls/tkill.S b/libc/arch-arm/syscalls/tkill.S
new file mode 100644
index 0000000..2626ae7
--- /dev/null
+++ b/libc/arch-arm/syscalls/tkill.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(tkill)
+    mov     ip, r7
+    ldr     r7, =__NR_tkill
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(tkill)
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index 22c2c3c..c1140de 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -36,6 +36,7 @@
 
 extern "C" void _exit_with_stack_teardown(void*, size_t, int);
 extern "C" void __exit(int);
+extern "C" int __set_tid_address(int*);
 
 /* CAVEAT: our implementation of pthread_cleanup_push/pop doesn't support C++ exceptions
  *         and thread cancelation
@@ -94,6 +95,9 @@
   pthread_mutex_lock(&gThreadListLock);
   if ((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) != 0) {
     // The thread is detached, so we can destroy the pthread_internal_t.
+    // First make sure that the thread does not try to clear the tid since
+    // it points into memory that will be freed.
+    __set_tid_address(NULL);
     _pthread_internal_remove_locked(thread);
   } else {
     // Make sure that the pthread_internal_t doesn't have stale pointers to a stack that
diff --git a/libc/include/sys/glibc-syscalls.h b/libc/include/sys/glibc-syscalls.h
index 3683533..0deb73a 100644
--- a/libc/include/sys/glibc-syscalls.h
+++ b/libc/include/sys/glibc-syscalls.h
@@ -721,6 +721,7 @@
 #define SYS_fcntl64 __NR_fcntl64
 #define SYS_fdatasync __NR_fdatasync
 #define SYS_fgetxattr __NR_fgetxattr
+#define SYS_finit_module __NR_finit_module
 #define SYS_flistxattr __NR_flistxattr
 #define SYS_flock __NR_flock
 #define SYS_fork __NR_fork
@@ -785,6 +786,7 @@
 #define SYS_ioprio_get __NR_ioprio_get
 #define SYS_ioprio_set __NR_ioprio_set
 #define SYS_ipc __NR_ipc
+#define SYS_kcmp __NR_kcmp
 #define SYS_kexec_load __NR_kexec_load
 #define SYS_keyctl __NR_keyctl
 #define SYS_kill __NR_kill
@@ -1077,6 +1079,7 @@
 #define SYS_fcntl64 __NR_fcntl64
 #define SYS_fdatasync __NR_fdatasync
 #define SYS_fgetxattr __NR_fgetxattr
+#define SYS_finit_module __NR_finit_module
 #define SYS_flistxattr __NR_flistxattr
 #define SYS_flock __NR_flock
 #define SYS_fork __NR_fork
@@ -1146,6 +1149,7 @@
 #define SYS_ioprio_get __NR_ioprio_get
 #define SYS_ioprio_set __NR_ioprio_set
 #define SYS_ipc __NR_ipc
+#define SYS_kcmp __NR_kcmp
 #define SYS_kexec_load __NR_kexec_load
 #define SYS_keyctl __NR_keyctl
 #define SYS_kill __NR_kill
@@ -1164,7 +1168,6 @@
 #define SYS_lstat __NR_lstat
 #define SYS_lstat64 __NR_lstat64
 #define SYS_madvise __NR_madvise
-#define SYS_madvise1 __NR_madvise1
 #define SYS_mbind __NR_mbind
 #define SYS_migrate_pages __NR_migrate_pages
 #define SYS_mincore __NR_mincore
@@ -1216,6 +1219,8 @@
 #define SYS_pread64 __NR_pread64
 #define SYS_preadv __NR_preadv
 #define SYS_prlimit64 __NR_prlimit64
+#define SYS_process_vm_readv __NR_process_vm_readv
+#define SYS_process_vm_writev __NR_process_vm_writev
 #define SYS_prof __NR_prof
 #define SYS_profil __NR_profil
 #define SYS_pselect6 __NR_pselect6
@@ -1420,6 +1425,7 @@
 #define SYS_fcntl __NR_fcntl
 #define SYS_fdatasync __NR_fdatasync
 #define SYS_fgetxattr __NR_fgetxattr
+#define SYS_finit_module __NR_finit_module
 #define SYS_flistxattr __NR_flistxattr
 #define SYS_flock __NR_flock
 #define SYS_fork __NR_fork
@@ -1477,6 +1483,7 @@
 #define SYS_iopl __NR_iopl
 #define SYS_ioprio_get __NR_ioprio_get
 #define SYS_ioprio_set __NR_ioprio_set
+#define SYS_kcmp __NR_kcmp
 #define SYS_kexec_load __NR_kexec_load
 #define SYS_keyctl __NR_keyctl
 #define SYS_kill __NR_kill
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index d0a8f27..ef201c3 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -94,12 +94,17 @@
 
 arm_eabi_call_long = syscall_stub_header + """\
     mov     ip, sp
-    .save   {r4, r5, r6, r7}
     stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
     ldr     r7, =%(__NR_name)s
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
@@ -413,11 +418,11 @@
         glibc_fp.write("#elif defined(__arm__)\n")
         self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/arch-arm/asm/unistd.h")
         glibc_fp.write("#elif defined(__mips__)\n")
-        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/arch-mips/asm/unistd.h")
+        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-mips/asm/unistd.h")
         glibc_fp.write("#elif defined(__i386__)\n")
-        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/arch-x86/asm/unistd_32.h")
+        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-x86/asm/unistd_32.h")
         glibc_fp.write("#elif defined(__x86_64__)\n")
-        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/arch-x86/asm/unistd_64.h")
+        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-x86/asm/unistd_64.h")
         glibc_fp.write("#endif\n")
 
         glibc_fp.write("#endif /* _BIONIC_GLIBC_SYSCALLS_H_ */\n")
diff --git a/tests/Android.mk b/tests/Android.mk
index 19b5447..b5398f1 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -19,34 +19,6 @@
 LOCAL_PATH := $(call my-dir)
 
 # -----------------------------------------------------------------------------
-# Benchmarks.
-# -----------------------------------------------------------------------------
-
-benchmark_c_flags = \
-    -O2 \
-    -Wall -Wextra \
-    -Werror \
-    -fno-builtin \
-
-benchmark_src_files = \
-    benchmark_main.cpp \
-    math_benchmark.cpp \
-    property_benchmark.cpp \
-    string_benchmark.cpp \
-    time_benchmark.cpp \
-
-# Build benchmarks for the device (with bionic's .so). Run with:
-#   adb shell bionic-benchmarks
-include $(CLEAR_VARS)
-LOCAL_MODULE := bionic-benchmarks
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_CFLAGS += $(benchmark_c_flags)
-LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
-LOCAL_SHARED_LIBRARIES += libstlport
-LOCAL_SRC_FILES := $(benchmark_src_files)
-include $(BUILD_EXECUTABLE)
-
-# -----------------------------------------------------------------------------
 # Unit tests.
 # -----------------------------------------------------------------------------
 
diff --git a/tests/buffer_tests.cpp b/tests/buffer_tests.cpp
index 9e6318b..4967382 100644
--- a/tests/buffer_tests.cpp
+++ b/tests/buffer_tests.cpp
@@ -21,6 +21,10 @@
 #include <gtest/gtest.h>
 #include "buffer_tests.h"
 
+// For the comparison buffer tests, the maximum length to test for the
+// miscompare checks.
+#define MISCMP_MAX_LENGTH 512
+
 #define FENCEPOST_LENGTH 8
 
 static int g_single_aligns[][2] = {
@@ -248,9 +252,7 @@
 
       test_func(buf_align, len);
 
-      if (buf_align != buf) {
-        VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
-      }
+      VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
       VerifyFencepost(&buf_align[len]);
     }
   }
@@ -286,9 +288,7 @@
 
       test_func(src_align, dst_align, len);
 
-      if (dst_align != dst) {
-        VerifyFencepost(&dst_align[-FENCEPOST_LENGTH]);
-      }
+      VerifyFencepost(&dst_align[-FENCEPOST_LENGTH]);
       VerifyFencepost(&dst_align[len]);
     }
   }
@@ -296,6 +296,58 @@
   delete dst;
 }
 
+void RunCmpBufferAlignTest(
+    size_t max_test_size, void (*test_cmp_func)(uint8_t*, uint8_t*, size_t),
+    void (*test_miscmp_func)(uint8_t*, uint8_t*, size_t, size_t),
+    size_t (*set_incr)(size_t)) {
+  if (!set_incr) {
+    set_incr = SetIncrement;
+  }
+
+  // Allocate two large buffers for all of the testing.
+  uint8_t* buf1 = new uint8_t[3*max_test_size];
+  uint8_t* buf2 = new uint8_t[3*max_test_size];
+
+  uint8_t* buf1_align;
+  uint8_t* buf2_align;
+  for (size_t i = 0; i < g_double_aligns_len; i++) {
+    size_t incr = 1;
+    for (size_t len = 0; len <= max_test_size; len += incr) {
+      incr = set_incr(len);
+
+      buf1_align =
+          reinterpret_cast<uint8_t*>(GetAlignedPtr(
+              buf1, g_double_aligns[i][0], g_double_aligns[i][1]));
+      buf2_align =
+          reinterpret_cast<uint8_t*>(GetAlignedPtr(
+              buf2, g_double_aligns[i][2], g_double_aligns[i][3]));
+
+      // Check by putting all zeroes after both buffers.
+      memset(buf1_align+len, 0, 32);
+      memset(buf2_align+len, 0, 32);
+      test_cmp_func(buf1_align, buf2_align, len);
+
+      // Check by putting different values after both buffers.
+      for (size_t j = 0; j < 32; j++) {
+        buf1_align[len+j] = j;
+        buf2_align[len+j] = j+1;
+      }
+      test_cmp_func(buf1_align, buf2_align, len);
+
+      if (len > 0) {
+        // Change the lengths of the buffers and verify that there are
+        // miscompares.
+        for (size_t len2 = len+1; len2 < len+32; len2++) {
+          test_miscmp_func(buf1_align, buf2_align, len, len2);
+          test_miscmp_func(buf1_align, buf2_align, len2, len);
+        }
+      }
+    }
+  }
+  delete buf1;
+  delete buf2;
+}
+
 void RunSingleBufferOverreadTest(void (*test_func)(uint8_t*, size_t)) {
   // In order to verify that functions are not reading past the end of the
   // src, create data that ends exactly at an unreadable memory boundary.
@@ -339,3 +391,58 @@
   free(memory);
   delete dst;
 }
+
+void RunCmpBufferOverreadTest(
+    void (*test_cmp_func)(uint8_t*, uint8_t*, size_t),
+    void (*test_miscmp_func)(uint8_t*, uint8_t*, size_t, size_t)) {
+  // In order to verify that functions are not reading past the end of either
+  // of the bufs, create both buffers that end exactly at an unreadable memory
+  // boundary.
+  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
+  uint8_t* memory1;
+  ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory1), pagesize,
+                             2*pagesize) == 0);
+  memset(memory1, 0x23, 2*pagesize);
+
+  // Make the second page unreadable and unwritable.
+  ASSERT_TRUE(mprotect(&memory1[pagesize], pagesize, PROT_NONE) == 0);
+
+  uint8_t* memory2;
+  ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory2), pagesize,
+                             2*pagesize) == 0);
+  memset(memory2, 0x23, 2*pagesize);
+
+  // Make the second page unreadable and unwritable.
+  ASSERT_TRUE(mprotect(&memory2[pagesize], pagesize, PROT_NONE) == 0);
+
+  for (size_t i = 0; i < pagesize; i++) {
+    uint8_t* buf1 = &memory1[pagesize-i];
+    uint8_t* buf2 = &memory2[pagesize-i];
+
+    test_cmp_func(buf1, buf2, i);
+  }
+
+  // Don't cycle through pagesize, MISCMP_MAX_LENGTH bytes should be good.
+  size_t miscmp_len;
+  if (pagesize > MISCMP_MAX_LENGTH) {
+    miscmp_len = MISCMP_MAX_LENGTH;
+  } else {
+    miscmp_len = pagesize;
+  }
+  for (size_t i = 1; i < miscmp_len; i++) {
+    uint8_t* buf1 = &memory1[pagesize-i];
+    for (size_t j = 1; j < miscmp_len; j++) {
+      if (j == i)
+        continue;
+
+      uint8_t* buf2 = &memory2[pagesize-j];
+
+      test_miscmp_func(buf1, buf2, i, j);
+    }
+  }
+
+  ASSERT_TRUE(mprotect(&memory1[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+  ASSERT_TRUE(mprotect(&memory2[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+  free(memory1);
+  free(memory2);
+}
diff --git a/tests/buffer_tests.h b/tests/buffer_tests.h
index f8685a2..315083b 100644
--- a/tests/buffer_tests.h
+++ b/tests/buffer_tests.h
@@ -28,8 +28,17 @@
     size_t max_test_size, void (*test_func)(uint8_t*, uint8_t*, size_t),
     size_t (*set_incr)(size_t) = NULL);
 
+void RunCmpBufferAlignTest(
+    size_t max_test_size, void (*test_cmp_func)(uint8_t*, uint8_t*, size_t),
+    void (*test_miscmp_func)(uint8_t*, uint8_t*, size_t, size_t),
+    size_t (*set_incr)(size_t) = NULL);
+
 void RunSingleBufferOverreadTest(void (*test_func)(uint8_t*, size_t));
 
 void RunSrcDstBufferOverreadTest(void (*test_func)(uint8_t*, uint8_t*, size_t));
 
+void RunCmpBufferOverreadTest(
+    void (*test_cmp_func)(uint8_t*, uint8_t*, size_t),
+    void (*test_miscmp_func)(uint8_t*, uint8_t*, size_t, size_t));
+
 #endif // _BIONIC_TESTS_BUFFER_TESTS_H
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index be46dc9..1a7e27d 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -956,7 +956,7 @@
 }
 
 // Use our own incrementer to cut down on the total number of calls.
-static size_t StrcatSetIncrement(size_t len) {
+static size_t LargeSetIncrement(size_t len) {
   if (len >= 4096) {
     return 4096;
   } else if (len >= 1024) {
@@ -1001,9 +1001,94 @@
 }
 
 TEST(string, strcat_align) {
-  RunSrcDstBufferAlignTest(MEDIUM, DoStrcatTest, StrcatSetIncrement);
+  RunSrcDstBufferAlignTest(MEDIUM, DoStrcatTest, LargeSetIncrement);
 }
 
 TEST(string, strcat_overread) {
   RunSrcDstBufferOverreadTest(DoStrcatTest);
 }
+
+static void DoStrcmpTest(uint8_t* buf1, uint8_t* buf2, size_t len) {
+  if (len >= 1) {
+    memset(buf1, (32 + (len % 96)), len - 1);
+    buf1[len-1] = '\0';
+    memset(buf2, (32 + (len % 96)), len - 1);
+    buf2[len-1] = '\0';
+    ASSERT_EQ(0, strcmp(reinterpret_cast<char*>(buf1),
+                        reinterpret_cast<char*>(buf2)));
+  }
+}
+
+static void DoStrcmpFailTest(uint8_t* buf1, uint8_t* buf2, size_t len1, size_t len2) {
+  // Do string length differences.
+  int c = (32 + (len1 % 96));
+  memset(buf1, c, len1 - 1);
+  buf1[len1-1] = '\0';
+  memset(buf2, c, len2 - 1);
+  buf2[len2-1] = '\0';
+  ASSERT_NE(0, strcmp(reinterpret_cast<char*>(buf1),
+                      reinterpret_cast<char*>(buf2)));
+
+  // Do single character differences.
+  size_t len;
+  if (len1 > len2) {
+    len = len2;
+  } else {
+    len = len1;
+  }
+  // Need at least a two character buffer to do this test.
+  if (len > 1) {
+    buf1[len-1] = '\0';
+    buf2[len-1] = '\0';
+    int diff_c = (c + 1) % 96;
+
+    buf1[len-2] = diff_c;
+    ASSERT_NE(0, strcmp(reinterpret_cast<char*>(buf1),
+                        reinterpret_cast<char*>(buf2)));
+
+    buf1[len-2] = c;
+    buf2[len-2] = diff_c;
+    ASSERT_NE(0, strcmp(reinterpret_cast<char*>(buf1),
+                        reinterpret_cast<char*>(buf2)));
+  }
+}
+
+TEST(string, strcmp_align) {
+  RunCmpBufferAlignTest(MEDIUM, DoStrcmpTest, DoStrcmpFailTest, LargeSetIncrement);
+}
+
+TEST(string, strcmp_overread) {
+  RunCmpBufferOverreadTest(DoStrcmpTest, DoStrcmpFailTest);
+}
+
+static void DoMemcmpTest(uint8_t* buf1, uint8_t* buf2, size_t len) {
+  memset(buf1, len+1, len);
+  memset(buf2, len+1, len);
+  ASSERT_EQ(0, memcmp(buf1, buf2, len));
+}
+
+static void DoMemcmpFailTest(uint8_t* buf1, uint8_t* buf2, size_t len1, size_t len2) {
+  size_t len;
+  if (len1 > len2) {
+    len = len2;
+  } else {
+    len = len1;
+  }
+
+  memset(buf1, len2+1, len);
+  buf1[len-1] = len2;
+  memset(buf2, len2+1, len);
+  ASSERT_NE(0, memcmp(buf1, buf2, len));
+
+  buf1[len-1] = len2+1;
+  buf2[len-1] = len2;
+  ASSERT_NE(0, memcmp(buf1, buf2, len));
+}
+
+TEST(string, memcmp_align) {
+  RunCmpBufferAlignTest(MEDIUM, DoMemcmpTest, DoMemcmpFailTest, LargeSetIncrement);
+}
+
+TEST(string, memcmp_overread) {
+  RunCmpBufferOverreadTest(DoMemcmpTest, DoMemcmpFailTest);
+}