Merge "better gtest runner for bionic"
diff --git a/benchmarks/pthread_benchmark.cpp b/benchmarks/pthread_benchmark.cpp
index 92e5998..42023e0 100644
--- a/benchmarks/pthread_benchmark.cpp
+++ b/benchmarks/pthread_benchmark.cpp
@@ -47,6 +47,21 @@
 }
 BENCHMARK(BM_pthread_getspecific);
 
+static void BM_pthread_setspecific(int iters) {
+  StopBenchmarkTiming();
+  pthread_key_t key;
+  pthread_key_create(&key, NULL);
+  StartBenchmarkTiming();
+
+  for (int i = 0; i < iters; ++i) {
+    pthread_setspecific(key, NULL);
+  }
+
+  StopBenchmarkTiming();
+  pthread_key_delete(key);
+}
+BENCHMARK(BM_pthread_setspecific);
+
 static void DummyPthreadOnceInitFunction() {
 }
 
@@ -137,3 +152,80 @@
   pthread_rwlock_destroy(&lock);
 }
 BENCHMARK(BM_pthread_rw_lock_write);
+
+static void* IdleThread(void*) {
+  return NULL;
+}
+
+static void BM_pthread_create(int iters) {
+  StopBenchmarkTiming();
+  pthread_t thread;
+
+  for (int i = 0; i < iters; ++i) {
+    StartBenchmarkTiming();
+    pthread_create(&thread, NULL, IdleThread, NULL);
+    StopBenchmarkTiming();
+    pthread_join(thread, NULL);
+  }
+}
+BENCHMARK(BM_pthread_create);
+
+static void* RunThread(void*) {
+  StopBenchmarkTiming();
+  return NULL;
+}
+
+static void BM_pthread_create_and_run(int iters) {
+  StopBenchmarkTiming();
+  pthread_t thread;
+
+  for (int i = 0; i < iters; ++i) {
+    StartBenchmarkTiming();
+    pthread_create(&thread, NULL, RunThread, NULL);
+    pthread_join(thread, NULL);
+  }
+}
+BENCHMARK(BM_pthread_create_and_run);
+
+static void* ExitThread(void*) {
+  StartBenchmarkTiming();
+  pthread_exit(NULL);
+}
+
+static void BM_pthread_exit_and_join(int iters) {
+  StopBenchmarkTiming();
+  pthread_t thread;
+
+  for (int i = 0; i < iters; ++i) {
+    pthread_create(&thread, NULL, ExitThread, NULL);
+    pthread_join(thread, NULL);
+    StopBenchmarkTiming();
+  }
+}
+BENCHMARK(BM_pthread_exit_and_join);
+
+static void BM_pthread_key_create(int iters) {
+  StopBenchmarkTiming();
+  pthread_key_t key;
+
+  for (int i = 0; i < iters; ++i) {
+    StartBenchmarkTiming();
+    pthread_key_create(&key, NULL);
+    StopBenchmarkTiming();
+    pthread_key_delete(key);
+  }
+}
+BENCHMARK(BM_pthread_key_create);
+
+static void BM_pthread_key_delete(int iters) {
+  StopBenchmarkTiming();
+  pthread_key_t key;
+
+  for (int i = 0; i < iters; ++i) {
+    pthread_key_create(&key, NULL);
+    StartBenchmarkTiming();
+    pthread_key_delete(key);
+    StopBenchmarkTiming();
+  }
+}
+BENCHMARK(BM_pthread_key_delete);
diff --git a/libc/NOTICE b/libc/NOTICE
index 697b8fc..1fa31c2 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -1679,35 +1679,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 1990 Regents of the University of California.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
-
--------------------------------------------------------------------
-
 Copyright (c) 1990 The Regents of the University of California.
 All rights reserved.
 
@@ -2539,33 +2510,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 1993 Christopher G. Demetriou
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
 Copyright (c) 1993 Martin Birgmeier
 All rights reserved.
 
@@ -2685,63 +2629,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 1996-2004 Per Fogelstrom, Opsycon AB
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
-OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1997 Mark Brinicombe
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
-   must display the following acknowledgement:
-   This product includes software developed by Mark Brinicombe
-4. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
 Copyright (c) 1997 Mark Brinicombe
 Copyright (c) 2010 Android Open Source Project.
 All rights reserved.
@@ -3365,34 +3252,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2002 Opsycon AB  (www.opsycon.se / www.opsycon.com)
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of Opsycon AB nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
-OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
 Copyright (c) 2002 The NetBSD Foundation, Inc.
 All rights reserved.
 
@@ -4025,6 +3884,22 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
 Copyright (c) 2008 Todd C. Miller <millert@openbsd.org>
 
 Permission to use, copy, modify, and distribute this software for any
@@ -4611,35 +4486,32 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2013, Linaro Limited
-   All rights reserved.
+Copyright (c) 2013 The NetBSD Foundation, Inc.
+All rights reserved.
 
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions
-   are met:
+This code is derived from software contributed to The NetBSD Foundation
+by Christos Zoulas.
 
-      * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
 
-      * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-
-      * Neither the name of Linaro Limited nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY 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
-   HOLDER 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.
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 
 -------------------------------------------------------------------
 
diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
index a4da9a6..5f0b1b3 100644
--- a/libc/arch-arm/arm.mk
+++ b/libc/arch-arm/arm.mk
@@ -58,7 +58,6 @@
     arch-arm/bionic/__bionic_clone.S \
     arch-arm/bionic/_exit_with_stack_teardown.S \
     arch-arm/bionic/libgcc_compat.c \
-    arch-arm/bionic/memcmp.S \
     arch-arm/bionic/__restore.S \
     arch-arm/bionic/setjmp.S \
     arch-arm/bionic/syscall.S \
diff --git a/libc/arch-arm/bionic/memcpy.S b/libc/arch-arm/bionic/memcpy.S
deleted file mode 100644
index 2c9b10c..0000000
--- a/libc/arch-arm/bionic/memcpy.S
+++ /dev/null
@@ -1,686 +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 <machine/cpu-features.h>
-#include <private/bionic_asm.h>
-
-#if defined(__ARM_NEON__) && !defined(ARCH_ARM_USE_NON_NEON_MEMCPY)
-
-        .text
-        .fpu    neon
-
-#ifdef HAVE_32_BYTE_CACHE_LINE
-/* a prefetch distance of 2 cache-lines */
-#define CACHE_LINE_SIZE     32
-#else
-/* a prefetch distance of 4 cache-lines works best experimentally */
-#define CACHE_LINE_SIZE     64
-#endif
-
-ENTRY(memcpy)
-        .save       {r0, lr}
-        /* start preloading as early as possible */
-        pld         [r1, #(CACHE_LINE_SIZE * 0)]
-        stmfd       sp!, {r0, lr}
-        pld         [r1, #(CACHE_LINE_SIZE * 1)]
-
-/* If Neon supports unaligned access then remove the align code,
- * unless a size limit has been specified.
- */
-#ifndef NEON_UNALIGNED_ACCESS
-        /* do we have at least 16-bytes to copy (needed for alignment below) */
-        cmp         r2, #16
-        blo         5f
-
-        /* check if buffers are aligned. If so, run arm-only version */
-        eor         r3, r0, r1
-        ands        r3, r3, #0x3
-        beq         11f
-
-        /* align destination to cache-line for the write-buffer */
-        rsb         r3, r0, #0
-        ands        r3, r3, #0xF
-        beq         2f
-
-        /* copy up to 15-bytes (count in r3) */
-        sub         r2, r2, r3
-        movs        ip, r3, lsl #31
-        ldrmib      lr, [r1], #1
-        strmib      lr, [r0], #1
-        ldrcsb      ip, [r1], #1
-        ldrcsb      lr, [r1], #1
-        strcsb      ip, [r0], #1
-        strcsb      lr, [r0], #1
-        movs        ip, r3, lsl #29
-        bge         1f
-        // copies 4 bytes, destination 32-bits aligned
-        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
-        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
-1:      bcc         2f
-        // copies 8 bytes, destination 64-bits aligned
-        vld1.8      {d0}, [r1]!
-        vst1.8      {d0}, [r0, :64]!
-2:
-        /* preload immediately the next cache line, which we may need */
-        pld         [r1, #(CACHE_LINE_SIZE * 0)]
-        pld         [r1, #(CACHE_LINE_SIZE * 1)]
-
-#ifdef HAVE_32_BYTE_CACHE_LINE
-        /* make sure we have at least 32 bytes to copy */
-        subs        r2, r2, #32
-        blo         4f
-
-        /* preload all the cache lines we need.
-         * NOTE: the number of pld below depends on PREFETCH_DISTANCE,
-         * ideally would would increase the distance in the main loop to
-         * avoid the goofy code below. In practice this doesn't seem to make
-         * a big difference.
-         */
-        pld         [r1, #(PREFETCH_DISTANCE)]
-
-1:      /* The main loop copies 32 bytes at a time */
-        vld1.8      {d0  - d3},   [r1]!
-        pld         [r1, #(PREFETCH_DISTANCE)]
-        subs        r2, r2, #32
-        vst1.8      {d0  - d3},   [r0, :128]!
-        bhs         1b
-#else
-        /* make sure we have at least 64 bytes to copy */
-        subs        r2, r2, #64
-        blo         2f
-
-        /* preload all the cache lines we need. */
-        pld         [r1, #(CACHE_LINE_SIZE * 2)]
-        pld         [r1, #(CACHE_LINE_SIZE * 3)]
-
-1:      /* The main loop copies 64 bytes at a time */
-        vld1.8      {d0 - d3}, [r1]!
-        vld1.8      {d4 - d7}, [r1]!
-#ifdef  HAVE_32_BYTE_CACHE_LINE
-        pld         [r1, #(CACHE_LINE_SIZE * 2)]
-        pld         [r1, #(CACHE_LINE_SIZE * 3)]
-#else
-        pld         [r1, #(CACHE_LINE_SIZE * 3)]
-#endif
-        subs        r2, r2, #64
-        vst1.8      {d0 - d3}, [r0, :128]!
-        vst1.8      {d4 - d7}, [r0, :128]!
-        bhs         1b
-
-2:      /* fix-up the remaining count and make sure we have >= 32 bytes left */
-        add         r2, r2, #64
-        subs        r2, r2, #32
-        blo         4f
-
-3:      /* 32 bytes at a time. These cache lines were already preloaded */
-        vld1.8      {d0 - d3}, [r1]!
-        subs        r2, r2, #32
-        vst1.8      {d0 - d3}, [r0, :128]!
-        bhs         3b
-#endif
-4:      /* less than 32 left */
-        add         r2, r2, #32
-        tst         r2, #0x10
-        beq         5f
-        // copies 16 bytes, 128-bits aligned
-        vld1.8      {d0, d1}, [r1]!
-        vst1.8      {d0, d1}, [r0, :128]!
-5:      /* copy up to 15-bytes (count in r2) */
-        movs        ip, r2, lsl #29
-        bcc         1f
-        vld1.8      {d0}, [r1]!
-        vst1.8      {d0}, [r0]!
-1:      bge         2f
-        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
-        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0]!
-2:      movs        ip, r2, lsl #31
-        ldrmib      r3, [r1], #1
-        ldrcsb      ip, [r1], #1
-        ldrcsb      lr, [r1], #1
-        strmib      r3, [r0], #1
-        strcsb      ip, [r0], #1
-        strcsb      lr, [r0], #1
-
-        ldmfd       sp!, {r0, lr}
-        bx          lr
-
-#else   /* NEON_UNALIGNED_ACCESS */
-
-        // Check so divider is at least 16 bytes, needed for alignment code.
-        cmp         r2, #16
-        blo         5f
-
-#ifdef NEON_MEMCPY_ALIGNMENT_DIVIDER
-        /* Check the upper size limit for Neon unaligned memory access in memcpy */
-#if NEON_MEMCPY_ALIGNMENT_DIVIDER >= 16
-        cmp         r2, #NEON_MEMCPY_ALIGNMENT_DIVIDER
-        blo         3f
-#endif
-        /* check if buffers are aligned. If so, run arm-only version */
-        eor         r3, r0, r1
-        ands        r3, r3, #0x3
-        beq         11f
-
-        /* align destination to 16 bytes for the write-buffer */
-        rsb         r3, r0, #0
-        ands        r3, r3, #0xF
-        beq         3f
-
-        /* copy up to 15-bytes (count in r3) */
-        sub         r2, r2, r3
-        movs        ip, r3, lsl #31
-        ldrmib      lr, [r1], #1
-        strmib      lr, [r0], #1
-        ldrcsb      ip, [r1], #1
-        ldrcsb      lr, [r1], #1
-        strcsb      ip, [r0], #1
-        strcsb      lr, [r0], #1
-        movs        ip, r3, lsl #29
-        bge         1f
-        // copies 4 bytes, destination 32-bits aligned
-        vld1.32     {d0[0]}, [r1]!
-        vst1.32     {d0[0]}, [r0, :32]!
-1:      bcc         2f
-        // copies 8 bytes, destination 64-bits aligned
-        vld1.8      {d0}, [r1]!
-        vst1.8      {d0}, [r0, :64]!
-2:
-        /* preload immediately the next cache line, which we may need */
-        pld         [r1, #(CACHE_LINE_SIZE * 0)]
-        pld         [r1, #(CACHE_LINE_SIZE * 1)]
-3:
-#endif
-        /* make sure we have at least 64 bytes to copy */
-        subs        r2, r2, #64
-        blo         2f
-
-        /* preload all the cache lines we need */
-        pld         [r1, #(CACHE_LINE_SIZE * 2)]
-        pld         [r1, #(CACHE_LINE_SIZE * 3)]
-
-1:      /* The main loop copies 64 bytes at a time */
-        vld1.8      {d0 - d3}, [r1]!
-        vld1.8      {d4 - d7}, [r1]!
-#ifdef  HAVE_32_BYTE_CACHE_LINE
-        pld         [r1, #(CACHE_LINE_SIZE * 2)]
-        pld         [r1, #(CACHE_LINE_SIZE * 3)]
-#else
-        pld         [r1, #(CACHE_LINE_SIZE * 3)]
-#endif
-        subs        r2, r2, #64
-        vst1.8      {d0 - d3}, [r0]!
-        vst1.8      {d4 - d7}, [r0]!
-        bhs         1b
-
-2:      /* fix-up the remaining count and make sure we have >= 32 bytes left */
-        add         r2, r2, #64
-        subs        r2, r2, #32
-        blo         4f
-
-3:      /* 32 bytes at a time. These cache lines were already preloaded */
-        vld1.8      {d0 - d3}, [r1]!
-        subs        r2, r2, #32
-        vst1.8      {d0 - d3}, [r0]!
-        bhs         3b
-
-4:      /* less than 32 left */
-        add         r2, r2, #32
-        tst         r2, #0x10
-        beq         5f
-        // copies 16 bytes, 128-bits aligned
-        vld1.8      {d0, d1}, [r1]!
-        vst1.8      {d0, d1}, [r0]!
-5:      /* copy up to 15-bytes (count in r2) */
-        movs        ip, r2, lsl #29
-        bcc         1f
-        vld1.8      {d0}, [r1]!
-        vst1.8      {d0}, [r0]!
-1:      bge         2f
-        vld1.32     {d0[0]}, [r1]!
-        vst1.32     {d0[0]}, [r0]!
-2:      movs        ip, r2, lsl #31
-        ldrmib      r3, [r1], #1
-        ldrcsb      ip, [r1], #1
-        ldrcsb      lr, [r1], #1
-        strmib      r3, [r0], #1
-        strcsb      ip, [r0], #1
-        strcsb      lr, [r0], #1
-
-        ldmfd       sp!, {r0, lr}
-        bx          lr
-#endif  /* NEON_UNALIGNED_ACCESS */
-11:
-        /* Simple arm-only copy loop to handle aligned copy operations */
-        stmfd       sp!, {r4, r5, r6, r7, r8}
-        pld         [r1, #(CACHE_LINE_SIZE * 2)]
-
-        /* Check alignment */
-        rsb         r3, r1, #0
-        ands        r3, #3
-        beq         2f
-
-        /* align source to 32 bits. We need to insert 2 instructions between
-         * a ldr[b|h] and str[b|h] because byte and half-word instructions
-         * stall 2 cycles.
-         */
-        movs        r12, r3, lsl #31
-        sub         r2, r2, r3      /* we know that r3 <= r2 because r2 >= 4 */
-        ldrmib      r3, [r1], #1
-        ldrcsb      r4, [r1], #1
-        ldrcsb      r5, [r1], #1
-        strmib      r3, [r0], #1
-        strcsb      r4, [r0], #1
-        strcsb      r5, [r0], #1
-2:
-        subs        r2, #32
-        blt         5f
-        pld         [r1, #(CACHE_LINE_SIZE * 3)]
-3:      /* Main copy loop, copying 32 bytes at a time */
-        pld         [r1, #(CACHE_LINE_SIZE * 4)]
-        ldmia       r1!, {r3, r4, r5, r6, r7, r8, r12, lr}
-        subs        r2, r2, #32
-        stmia       r0!, {r3, r4, r5, r6, r7, r8, r12, lr}
-        bge         3b
-5:      /* Handle any remaining bytes */
-        adds        r2, #32
-        beq         6f
-
-        movs        r12, r2, lsl #28
-        ldmcsia     r1!, {r3, r4, r5, r6}   /* 16 bytes */
-        ldmmiia     r1!, {r7, r8}           /*  8 bytes */
-        stmcsia     r0!, {r3, r4, r5, r6}
-        stmmiia     r0!, {r7, r8}
-        movs        r12, r2, lsl #30
-        ldrcs       r3, [r1], #4            /*  4 bytes */
-        ldrmih      r4, [r1], #2            /*  2 bytes */
-        strcs       r3, [r0], #4
-        strmih      r4, [r0], #2
-        tst         r2, #0x1
-        ldrneb      r3, [r1]                /*  last byte  */
-        strneb      r3, [r0]
-6:
-        ldmfd       sp!, {r4, r5, r6, r7, r8}
-        ldmfd       sp!, {r0, pc}
-END(memcpy)
-
-
-#else   /* __ARM_ARCH__ < 7 */
-
-
-		/*
-		 * Optimized memcpy() for ARM.
-         *
-		 * note that memcpy() always returns the destination pointer,
-		 * so we have to preserve R0.
-		 */
-
-ENTRY(memcpy)
-		/* The stack must always be 64-bits aligned to be compliant with the
-		 * ARM ABI. Since we have to save R0, we might as well save R4
-		 * which we can use for better pipelining of the reads below
-		 */
-        .save       {r0, r4, lr}
-        stmfd       sp!, {r0, r4, lr}
-        /* Making room for r5-r11 which will be spilled later */
-        .pad        #28
-        sub         sp, sp, #28
-
-        // preload the destination because we'll align it to a cache line
-        // with small writes. Also start the source "pump".
-        pld         [r0, #0]
-        pld         [r1, #0]
-        pld         [r1, #32]
-
-		/* it simplifies things to take care of len<4 early */
-		cmp			r2, #4
-		blo			copy_last_3_and_return
-
-		/* compute the offset to align the source
-		 * offset = (4-(src&3))&3 = -src & 3
-		 */
-		rsb			r3, r1, #0
-		ands		r3, r3, #3
-		beq			src_aligned
-
-		/* align source to 32 bits. We need to insert 2 instructions between
-		 * a ldr[b|h] and str[b|h] because byte and half-word instructions
-		 * stall 2 cycles.
-		 */
-		movs		r12, r3, lsl #31
-		sub			r2, r2, r3		/* we know that r3 <= r2 because r2 >= 4 */
-		ldrmib		r3, [r1], #1
-		ldrcsb		r4, [r1], #1
-		ldrcsb		r12,[r1], #1
-        strmib		r3, [r0], #1
-		strcsb		r4, [r0], #1
-		strcsb		r12,[r0], #1
-
-src_aligned:
-
-		/* see if src and dst are aligned together (congruent) */
-		eor			r12, r0, r1
-		tst			r12, #3
-		bne			non_congruent
-
-        /* Use post-incriment mode for stm to spill r5-r11 to reserved stack
-         * frame. Don't update sp.
-         */
-        stmea		sp, {r5-r11}
-
-		/* align the destination to a cache-line */
-		rsb         r3, r0, #0
-		ands		r3, r3, #0x1C
-		beq         congruent_aligned32
-		cmp         r3, r2
-		andhi		r3, r2, #0x1C
-
-		/* conditionnaly copies 0 to 7 words (length in r3) */
-		movs		r12, r3, lsl #28
-		ldmcsia		r1!, {r4, r5, r6, r7}	/* 16 bytes */
-		ldmmiia		r1!, {r8, r9}			/*  8 bytes */
-		stmcsia		r0!, {r4, r5, r6, r7}
-		stmmiia		r0!, {r8, r9}
-		tst         r3, #0x4
-		ldrne		r10,[r1], #4			/*  4 bytes */
-		strne		r10,[r0], #4
-		sub         r2, r2, r3
-
-congruent_aligned32:
-		/*
-		 * here source is aligned to 32 bytes.
-		 */
-
-cached_aligned32:
-        subs        r2, r2, #32
-        blo         less_than_32_left
-
-        /*
-         * We preload a cache-line up to 64 bytes ahead. On the 926, this will
-         * stall only until the requested world is fetched, but the linefill
-         * continues in the the background.
-         * While the linefill is going, we write our previous cache-line
-         * into the write-buffer (which should have some free space).
-         * When the linefill is done, the writebuffer will
-         * start dumping its content into memory
-         *
-         * While all this is going, we then load a full cache line into
-         * 8 registers, this cache line should be in the cache by now
-         * (or partly in the cache).
-         *
-         * This code should work well regardless of the source/dest alignment.
-         *
-         */
-
-        // Align the preload register to a cache-line because the cpu does
-        // "critical word first" (the first word requested is loaded first).
-        bic         r12, r1, #0x1F
-        add         r12, r12, #64
-
-1:      ldmia       r1!, { r4-r11 }
-        pld         [r12, #64]
-        subs        r2, r2, #32
-
-        // NOTE: if r12 is more than 64 ahead of r1, the following ldrhi
-        // for ARM9 preload will not be safely guarded by the preceding subs.
-        // When it is safely guarded the only possibility to have SIGSEGV here
-        // is because the caller overstates the length.
-        ldrhi       r3, [r12], #32      /* cheap ARM9 preload */
-        stmia       r0!, { r4-r11 }
-		bhs         1b
-
-        add         r2, r2, #32
-
-
-
-
-less_than_32_left:
-		/*
-		 * less than 32 bytes left at this point (length in r2)
-		 */
-
-		/* skip all this if there is nothing to do, which should
-		 * be a common case (if not executed the code below takes
-		 * about 16 cycles)
-		 */
-		tst			r2, #0x1F
-		beq			1f
-
-		/* conditionnaly copies 0 to 31 bytes */
-		movs		r12, r2, lsl #28
-		ldmcsia		r1!, {r4, r5, r6, r7}	/* 16 bytes */
-		ldmmiia		r1!, {r8, r9}			/*  8 bytes */
-		stmcsia		r0!, {r4, r5, r6, r7}
-		stmmiia		r0!, {r8, r9}
-		movs		r12, r2, lsl #30
-		ldrcs		r3, [r1], #4			/*  4 bytes */
-		ldrmih		r4, [r1], #2			/*  2 bytes */
-		strcs		r3, [r0], #4
-		strmih		r4, [r0], #2
-		tst         r2, #0x1
-		ldrneb		r3, [r1]				/*  last byte  */
-		strneb		r3, [r0]
-
-		/* we're done! restore everything and return */
-1:		ldmfd		sp!, {r5-r11}
-		ldmfd		sp!, {r0, r4, lr}
-		bx			lr
-
-		/********************************************************************/
-
-non_congruent:
-		/*
-		 * here source is aligned to 4 bytes
-		 * but destination is not.
-		 *
-		 * in the code below r2 is the number of bytes read
-		 * (the number of bytes written is always smaller, because we have
-		 * partial words in the shift queue)
-		 */
-		cmp			r2, #4
-		blo			copy_last_3_and_return
-
-        /* Use post-incriment mode for stm to spill r5-r11 to reserved stack
-         * frame. Don't update sp.
-         */
-        stmea		sp, {r5-r11}
-
-		/* compute shifts needed to align src to dest */
-		rsb			r5, r0, #0
-		and			r5, r5, #3			/* r5 = # bytes in partial words */
-		mov			r12, r5, lsl #3		/* r12 = right */
-		rsb			lr, r12, #32		/* lr = left  */
-
-		/* read the first word */
-		ldr			r3, [r1], #4
-		sub			r2, r2, #4
-
-		/* write a partial word (0 to 3 bytes), such that destination
-		 * becomes aligned to 32 bits (r5 = nb of words to copy for alignment)
-		 */
-		movs		r5, r5, lsl #31
-		strmib		r3, [r0], #1
-		movmi		r3, r3, lsr #8
-		strcsb		r3, [r0], #1
-		movcs		r3, r3, lsr #8
-		strcsb		r3, [r0], #1
-		movcs		r3, r3, lsr #8
-
-		cmp			r2, #4
-		blo			partial_word_tail
-
-		/* Align destination to 32 bytes (cache line boundary) */
-1:		tst			r0, #0x1c
-		beq			2f
-		ldr			r5, [r1], #4
-		sub         r2, r2, #4
-		orr			r4, r3, r5,		lsl lr
-		mov			r3, r5,			lsr r12
-		str			r4, [r0], #4
-        cmp         r2, #4
-		bhs			1b
-		blo			partial_word_tail
-
-		/* copy 32 bytes at a time */
-2:		subs		r2, r2, #32
-		blo			less_than_thirtytwo
-
-		/* Use immediate mode for the shifts, because there is an extra cycle
-		 * for register shifts, which could account for up to 50% of
-		 * performance hit.
-		 */
-
-        cmp			r12, #24
-		beq			loop24
-		cmp			r12, #8
-		beq			loop8
-
-loop16:
-        ldr         r12, [r1], #4
-1:      mov         r4, r12
-		ldmia		r1!, {   r5,r6,r7,  r8,r9,r10,r11}
-        pld         [r1, #64]
-        subs        r2, r2, #32
-        ldrhs       r12, [r1], #4
-		orr			r3, r3, r4,		lsl #16
-		mov			r4, r4,			lsr #16
-		orr			r4, r4, r5,		lsl #16
-		mov			r5, r5,			lsr #16
-		orr			r5, r5, r6,		lsl #16
-		mov			r6, r6,			lsr #16
-		orr			r6, r6, r7,		lsl #16
-		mov			r7, r7,			lsr #16
-		orr			r7, r7, r8,		lsl #16
-		mov			r8, r8,			lsr #16
-		orr			r8, r8, r9,		lsl #16
-		mov			r9, r9,			lsr #16
-		orr			r9, r9, r10,	lsl #16
-		mov			r10, r10,		lsr #16
-		orr			r10, r10, r11,	lsl #16
-		stmia		r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
-		mov			r3, r11,		lsr #16
-		bhs			1b
-		b			less_than_thirtytwo
-
-loop8:
-        ldr         r12, [r1], #4
-1:      mov         r4, r12
-		ldmia		r1!, {   r5,r6,r7,  r8,r9,r10,r11}
-        pld         [r1, #64]
-		subs		r2, r2, #32
-        ldrhs       r12, [r1], #4
-		orr			r3, r3, r4,		lsl #24
-		mov			r4, r4,			lsr #8
-		orr			r4, r4, r5,		lsl #24
-		mov			r5, r5,			lsr #8
-		orr			r5, r5, r6,		lsl #24
-		mov			r6, r6,			lsr #8
-		orr			r6, r6, r7,		lsl #24
-		mov			r7, r7,			lsr #8
-		orr			r7, r7, r8,		lsl #24
-		mov			r8, r8,			lsr #8
-		orr			r8, r8, r9,		lsl #24
-		mov			r9, r9,			lsr #8
-		orr			r9, r9, r10,	lsl #24
-		mov			r10, r10,		lsr #8
-		orr			r10, r10, r11,	lsl #24
-		stmia		r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
-		mov			r3, r11,		lsr #8
-		bhs			1b
-		b			less_than_thirtytwo
-
-loop24:
-        ldr         r12, [r1], #4
-1:      mov         r4, r12
-		ldmia		r1!, {   r5,r6,r7,  r8,r9,r10,r11}
-        pld         [r1, #64]
-		subs		r2, r2, #32
-        ldrhs       r12, [r1], #4
-		orr			r3, r3, r4,		lsl #8
-		mov			r4, r4,			lsr #24
-		orr			r4, r4, r5,		lsl #8
-		mov			r5, r5,			lsr #24
-		orr			r5, r5, r6,		lsl #8
-		mov			r6, r6,			lsr #24
-		orr			r6, r6, r7,		lsl #8
-		mov			r7, r7,			lsr #24
-		orr			r7, r7, r8,		lsl #8
-		mov			r8, r8,			lsr #24
-		orr			r8, r8, r9,		lsl #8
-		mov			r9, r9,			lsr #24
-		orr			r9, r9, r10,	lsl #8
-		mov			r10, r10,		lsr #24
-		orr			r10, r10, r11,	lsl #8
-		stmia		r0!, {r3,r4,r5,r6, r7,r8,r9,r10}
-		mov			r3, r11,		lsr #24
-		bhs			1b
-
-
-less_than_thirtytwo:
-		/* copy the last 0 to 31 bytes of the source */
-		rsb			r12, lr, #32		/* we corrupted r12, recompute it  */
-		add			r2, r2, #32
-		cmp			r2, #4
-		blo			partial_word_tail
-
-1:		ldr			r5, [r1], #4
-		sub         r2, r2, #4
-		orr			r4, r3, r5,		lsl lr
-		mov			r3,	r5,			lsr r12
-		str			r4, [r0], #4
-        cmp         r2, #4
-		bhs			1b
-
-partial_word_tail:
-		/* we have a partial word in the input buffer */
-		movs		r5, lr, lsl #(31-3)
-		strmib		r3, [r0], #1
-		movmi		r3, r3, lsr #8
-		strcsb		r3, [r0], #1
-		movcs		r3, r3, lsr #8
-		strcsb		r3, [r0], #1
-
-		/* Refill spilled registers from the stack. Don't update sp. */
-		ldmfd		sp, {r5-r11}
-
-copy_last_3_and_return:
-		movs		r2, r2, lsl #31	/* copy remaining 0, 1, 2 or 3 bytes */
-		ldrmib		r2, [r1], #1
-		ldrcsb		r3, [r1], #1
-		ldrcsb		r12,[r1]
-		strmib		r2, [r0], #1
-		strcsb		r3, [r0], #1
-		strcsb		r12,[r0]
-
-        /* we're done! restore sp and spilled registers and return */
-        add         sp,  sp, #28
-		ldmfd		sp!, {r0, r4, lr}
-		bx			lr
-END(memcpy)
-
-
-#endif    /* __ARM_ARCH__ < 7 */
diff --git a/libc/arch-arm/bionic/memcpy.a9.S b/libc/arch-arm/bionic/memcpy.a9.S
deleted file mode 100644
index 259701d..0000000
--- a/libc/arch-arm/bionic/memcpy.a9.S
+++ /dev/null
@@ -1,614 +0,0 @@
-/* Copyright (c) 2013, Linaro Limited
-   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.
-
-      * Neither the name of Linaro Limited nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY 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
-   HOLDER 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.
-
- */
-
-/*
-   This memcpy routine is optimised for Cortex-A15 cores and takes advantage
-   of VFP or NEON when built with the appropriate flags.
-
-   Assumptions:
-
-    ARMv6 (ARMv7-a if using Neon)
-    ARM state
-    Unaligned accesses
-    LDRD/STRD support unaligned word accesses
-
- */
-
-#include <machine/cpu-features.h>
-#include <private/bionic_asm.h>
-
-	.syntax unified
-	/* This implementation requires ARM state.  */
-	.arm
-
-#ifdef __ARM_NEON__
-
-	.fpu	neon
-	.arch	armv7-a
-# define FRAME_SIZE	4
-# define USE_VFP
-# define USE_NEON
-
-#elif !defined (__SOFTFP__)
-
-	.arch	armv6
-	.fpu	vfpv2
-# define FRAME_SIZE	32
-# define USE_VFP
-
-#else
-	.arch	armv6
-# define FRAME_SIZE    32
-
-#endif
-
-/* Old versions of GAS incorrectly implement the NEON align semantics.  */
-#ifdef BROKEN_ASM_NEON_ALIGN
-#define ALIGN(addr, align) addr,:align
-#else
-#define ALIGN(addr, align) addr:align
-#endif
-
-#define PC_OFFSET	8	/* PC pipeline compensation.  */
-#define INSN_SIZE	4
-
-/* Call parameters.  */
-#define dstin	r0
-#define src	r1
-#define count	r2
-
-/* Locals.  */
-#define tmp1	r3
-#define dst	ip
-#define tmp2	r10
-
-#ifndef USE_NEON
-/* For bulk copies using GP registers.  */
-#define	A_l	r2		/* Call-clobbered.  */
-#define	A_h	r3		/* Call-clobbered.  */
-#define	B_l	r4
-#define	B_h	r5
-#define	C_l	r6
-#define	C_h	r7
-#define	D_l	r8
-#define	D_h	r9
-#endif
-
-/* Number of lines ahead to pre-fetch data.  If you change this the code
-   below will need adjustment to compensate.  */
-
-#define prefetch_lines	5
-
-#ifdef USE_VFP
-	.macro	cpy_line_vfp vreg, base
-	vstr	\vreg, [dst, #\base]
-	vldr	\vreg, [src, #\base]
-	vstr	d0, [dst, #\base + 8]
-	vldr	d0, [src, #\base + 8]
-	vstr	d1, [dst, #\base + 16]
-	vldr	d1, [src, #\base + 16]
-	vstr	d2, [dst, #\base + 24]
-	vldr	d2, [src, #\base + 24]
-	vstr	\vreg, [dst, #\base + 32]
-	vldr	\vreg, [src, #\base + prefetch_lines * 64 - 32]
-	vstr	d0, [dst, #\base + 40]
-	vldr	d0, [src, #\base + 40]
-	vstr	d1, [dst, #\base + 48]
-	vldr	d1, [src, #\base + 48]
-	vstr	d2, [dst, #\base + 56]
-	vldr	d2, [src, #\base + 56]
-	.endm
-
-	.macro	cpy_tail_vfp vreg, base
-	vstr	\vreg, [dst, #\base]
-	vldr	\vreg, [src, #\base]
-	vstr	d0, [dst, #\base + 8]
-	vldr	d0, [src, #\base + 8]
-	vstr	d1, [dst, #\base + 16]
-	vldr	d1, [src, #\base + 16]
-	vstr	d2, [dst, #\base + 24]
-	vldr	d2, [src, #\base + 24]
-	vstr	\vreg, [dst, #\base + 32]
-	vstr	d0, [dst, #\base + 40]
-	vldr	d0, [src, #\base + 40]
-	vstr	d1, [dst, #\base + 48]
-	vldr	d1, [src, #\base + 48]
-	vstr	d2, [dst, #\base + 56]
-	vldr	d2, [src, #\base + 56]
-	.endm
-#endif
-
-	.p2align 6
-ENTRY(memcpy)
-
-	mov	dst, dstin	/* Preserve dstin, we need to return it.  */
-	cmp	count, #64
-	bge	.Lcpy_not_short
-	/* Deal with small copies quickly by dropping straight into the
-	   exit block.  */
-
-.Ltail63unaligned:
-#ifdef USE_NEON
-	and	tmp1, count, #0x38
-	rsb	tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
-	add	pc, pc, tmp1
-	vld1.8	{d0}, [src]!	/* 14 words to go.  */
-	vst1.8	{d0}, [dst]!
-	vld1.8	{d0}, [src]!	/* 12 words to go.  */
-	vst1.8	{d0}, [dst]!
-	vld1.8	{d0}, [src]!	/* 10 words to go.  */
-	vst1.8	{d0}, [dst]!
-	vld1.8	{d0}, [src]!	/* 8 words to go.  */
-	vst1.8	{d0}, [dst]!
-	vld1.8	{d0}, [src]!	/* 6 words to go.  */
-	vst1.8	{d0}, [dst]!
-	vld1.8	{d0}, [src]!	/* 4 words to go.  */
-	vst1.8	{d0}, [dst]!
-	vld1.8	{d0}, [src]!	/* 2 words to go.  */
-	vst1.8	{d0}, [dst]!
-
-	tst	count, #4
-	ldrne	tmp1, [src], #4
-	strne	tmp1, [dst], #4
-#else
-	/* Copy up to 15 full words of data.  May not be aligned.  */
-	/* Cannot use VFP for unaligned data.  */
-	and	tmp1, count, #0x3c
-	add	dst, dst, tmp1
-	add	src, src, tmp1
-	rsb	tmp1, tmp1, #(60 - PC_OFFSET/2 + INSN_SIZE/2)
-	/* Jump directly into the sequence below at the correct offset.  */
-	add	pc, pc, tmp1, lsl #1
-
-	ldr	tmp1, [src, #-60]	/* 15 words to go.  */
-	str	tmp1, [dst, #-60]
-
-	ldr	tmp1, [src, #-56]	/* 14 words to go.  */
-	str	tmp1, [dst, #-56]
-	ldr	tmp1, [src, #-52]
-	str	tmp1, [dst, #-52]
-
-	ldr	tmp1, [src, #-48]	/* 12 words to go.  */
-	str	tmp1, [dst, #-48]
-	ldr	tmp1, [src, #-44]
-	str	tmp1, [dst, #-44]
-
-	ldr	tmp1, [src, #-40]	/* 10 words to go.  */
-	str	tmp1, [dst, #-40]
-	ldr	tmp1, [src, #-36]
-	str	tmp1, [dst, #-36]
-
-	ldr	tmp1, [src, #-32]	/* 8 words to go.  */
-	str	tmp1, [dst, #-32]
-	ldr	tmp1, [src, #-28]
-	str	tmp1, [dst, #-28]
-
-	ldr	tmp1, [src, #-24]	/* 6 words to go.  */
-	str	tmp1, [dst, #-24]
-	ldr	tmp1, [src, #-20]
-	str	tmp1, [dst, #-20]
-
-	ldr	tmp1, [src, #-16]	/* 4 words to go.  */
-	str	tmp1, [dst, #-16]
-	ldr	tmp1, [src, #-12]
-	str	tmp1, [dst, #-12]
-
-	ldr	tmp1, [src, #-8]	/* 2 words to go.  */
-	str	tmp1, [dst, #-8]
-	ldr	tmp1, [src, #-4]
-	str	tmp1, [dst, #-4]
-#endif
-
-	lsls	count, count, #31
-	ldrhcs	tmp1, [src], #2
-	ldrbne	src, [src]		/* Src is dead, use as a scratch.  */
-	strhcs	tmp1, [dst], #2
-	strbne	src, [dst]
-	bx	lr
-
-.Lcpy_not_short:
-	/* At least 64 bytes to copy, but don't know the alignment yet.  */
-	str	tmp2, [sp, #-FRAME_SIZE]!
-	and	tmp2, src, #7
-	and	tmp1, dst, #7
-	cmp	tmp1, tmp2
-	bne	.Lcpy_notaligned
-
-#ifdef USE_VFP
-	/* Magic dust alert!  Force VFP on Cortex-A9.  Experiments show
-	   that the FP pipeline is much better at streaming loads and
-	   stores.  This is outside the critical loop.  */
-	vmov.f32	s0, s0
-#endif
-
-	/* SRC and DST have the same mutual 32-bit alignment, but we may
-	   still need to pre-copy some bytes to get to natural alignment.
-	   We bring DST into full 64-bit alignment.  */
-	lsls	tmp2, dst, #29
-	beq	1f
-	rsbs	tmp2, tmp2, #0
-	sub	count, count, tmp2, lsr #29
-	ldrmi	tmp1, [src], #4
-	strmi	tmp1, [dst], #4
-	lsls	tmp2, tmp2, #2
-	ldrhcs	tmp1, [src], #2
-	ldrbne	tmp2, [src], #1
-	strhcs	tmp1, [dst], #2
-	strbne	tmp2, [dst], #1
-
-1:
-	subs	tmp2, count, #64	/* Use tmp2 for count.  */
-	blt	.Ltail63aligned
-
-	cmp	tmp2, #512
-	bge	.Lcpy_body_long
-
-.Lcpy_body_medium:			/* Count in tmp2.  */
-#ifdef USE_VFP
-1:
-	vldr	d0, [src, #0]
-	subs	tmp2, tmp2, #64
-	vldr	d1, [src, #8]
-	vstr	d0, [dst, #0]
-	vldr	d0, [src, #16]
-	vstr	d1, [dst, #8]
-	vldr	d1, [src, #24]
-	vstr	d0, [dst, #16]
-	vldr	d0, [src, #32]
-	vstr	d1, [dst, #24]
-	vldr	d1, [src, #40]
-	vstr	d0, [dst, #32]
-	vldr	d0, [src, #48]
-	vstr	d1, [dst, #40]
-	vldr	d1, [src, #56]
-	vstr	d0, [dst, #48]
-	add	src, src, #64
-	vstr	d1, [dst, #56]
-	add	dst, dst, #64
-	bge	1b
-	tst	tmp2, #0x3f
-	beq	.Ldone
-
-.Ltail63aligned:			/* Count in tmp2.  */
-	and	tmp1, tmp2, #0x38
-	add	dst, dst, tmp1
-	add	src, src, tmp1
-	rsb	tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
-	add	pc, pc, tmp1
-
-	vldr	d0, [src, #-56]	/* 14 words to go.  */
-	vstr	d0, [dst, #-56]
-	vldr	d0, [src, #-48]	/* 12 words to go.  */
-	vstr	d0, [dst, #-48]
-	vldr	d0, [src, #-40]	/* 10 words to go.  */
-	vstr	d0, [dst, #-40]
-	vldr	d0, [src, #-32]	/* 8 words to go.  */
-	vstr	d0, [dst, #-32]
-	vldr	d0, [src, #-24]	/* 6 words to go.  */
-	vstr	d0, [dst, #-24]
-	vldr	d0, [src, #-16]	/* 4 words to go.  */
-	vstr	d0, [dst, #-16]
-	vldr	d0, [src, #-8]	/* 2 words to go.  */
-	vstr	d0, [dst, #-8]
-#else
-	sub	src, src, #8
-	sub	dst, dst, #8
-1:
-	ldrd	A_l, A_h, [src, #8]
-	strd	A_l, A_h, [dst, #8]
-	ldrd	A_l, A_h, [src, #16]
-	strd	A_l, A_h, [dst, #16]
-	ldrd	A_l, A_h, [src, #24]
-	strd	A_l, A_h, [dst, #24]
-	ldrd	A_l, A_h, [src, #32]
-	strd	A_l, A_h, [dst, #32]
-	ldrd	A_l, A_h, [src, #40]
-	strd	A_l, A_h, [dst, #40]
-	ldrd	A_l, A_h, [src, #48]
-	strd	A_l, A_h, [dst, #48]
-	ldrd	A_l, A_h, [src, #56]
-	strd	A_l, A_h, [dst, #56]
-	ldrd	A_l, A_h, [src, #64]!
-	strd	A_l, A_h, [dst, #64]!
-	subs	tmp2, tmp2, #64
-	bge	1b
-	tst	tmp2, #0x3f
-	bne	1f
-	ldr	tmp2,[sp], #FRAME_SIZE
-	bx	lr
-1:
-	add	src, src, #8
-	add	dst, dst, #8
-
-.Ltail63aligned:			/* Count in tmp2.  */
-	/* Copy up to 7 d-words of data.  Similar to Ltail63unaligned, but
-	   we know that the src and dest are 32-bit aligned so we can use
-	   LDRD/STRD to improve efficiency.  */
-	/* TMP2 is now negative, but we don't care about that.  The bottom
-	   six bits still tell us how many bytes are left to copy.  */
-
-	and	tmp1, tmp2, #0x38
-	add	dst, dst, tmp1
-	add	src, src, tmp1
-	rsb	tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
-	add	pc, pc, tmp1
-	ldrd	A_l, A_h, [src, #-56]	/* 14 words to go.  */
-	strd	A_l, A_h, [dst, #-56]
-	ldrd	A_l, A_h, [src, #-48]	/* 12 words to go.  */
-	strd	A_l, A_h, [dst, #-48]
-	ldrd	A_l, A_h, [src, #-40]	/* 10 words to go.  */
-	strd	A_l, A_h, [dst, #-40]
-	ldrd	A_l, A_h, [src, #-32]	/* 8 words to go.  */
-	strd	A_l, A_h, [dst, #-32]
-	ldrd	A_l, A_h, [src, #-24]	/* 6 words to go.  */
-	strd	A_l, A_h, [dst, #-24]
-	ldrd	A_l, A_h, [src, #-16]	/* 4 words to go.  */
-	strd	A_l, A_h, [dst, #-16]
-	ldrd	A_l, A_h, [src, #-8]	/* 2 words to go.  */
-	strd	A_l, A_h, [dst, #-8]
-
-#endif
-	tst	tmp2, #4
-	ldrne	tmp1, [src], #4
-	strne	tmp1, [dst], #4
-	lsls	tmp2, tmp2, #31		/* Count (tmp2) now dead. */
-	ldrhcs	tmp1, [src], #2
-	ldrbne	tmp2, [src]
-	strhcs	tmp1, [dst], #2
-	strbne	tmp2, [dst]
-
-.Ldone:
-	ldr	tmp2, [sp], #FRAME_SIZE
-	bx	lr
-
-.Lcpy_body_long:			/* Count in tmp2.  */
-
-	/* Long copy.  We know that there's at least (prefetch_lines * 64)
-	   bytes to go.  */
-#ifdef USE_VFP
-	/* Don't use PLD.  Instead, read some data in advance of the current
-	   copy position into a register.  This should act like a PLD
-	   operation but we won't have to repeat the transfer.  */
-
-	vldr	d3, [src, #0]
-	vldr	d4, [src, #64]
-	vldr	d5, [src, #128]
-	vldr	d6, [src, #192]
-	vldr	d7, [src, #256]
-
-	vldr	d0, [src, #8]
-	vldr	d1, [src, #16]
-	vldr	d2, [src, #24]
-	add	src, src, #32
-
-	subs	tmp2, tmp2, #prefetch_lines * 64 * 2
-	blt	2f
-1:
-	cpy_line_vfp	d3, 0
-	cpy_line_vfp	d4, 64
-	cpy_line_vfp	d5, 128
-	add	dst, dst, #3 * 64
-	add	src, src, #3 * 64
-	cpy_line_vfp	d6, 0
-	cpy_line_vfp	d7, 64
-	add	dst, dst, #2 * 64
-	add	src, src, #2 * 64
-	subs	tmp2, tmp2, #prefetch_lines * 64
-	bge	1b
-
-2:
-	cpy_tail_vfp	d3, 0
-	cpy_tail_vfp	d4, 64
-	cpy_tail_vfp	d5, 128
-	add	src, src, #3 * 64
-	add	dst, dst, #3 * 64
-	cpy_tail_vfp	d6, 0
-	vstr	d7, [dst, #64]
-	vldr	d7, [src, #64]
-	vstr	d0, [dst, #64 + 8]
-	vldr	d0, [src, #64 + 8]
-	vstr	d1, [dst, #64 + 16]
-	vldr	d1, [src, #64 + 16]
-	vstr	d2, [dst, #64 + 24]
-	vldr	d2, [src, #64 + 24]
-	vstr	d7, [dst, #64 + 32]
-	add	src, src, #96
-	vstr	d0, [dst, #64 + 40]
-	vstr	d1, [dst, #64 + 48]
-	vstr	d2, [dst, #64 + 56]
-	add	dst, dst, #128
-	add	tmp2, tmp2, #prefetch_lines * 64
-	b	.Lcpy_body_medium
-#else
-	/* Long copy.  Use an SMS style loop to maximize the I/O
-	   bandwidth of the core.  We don't have enough spare registers
-	   to synthesise prefetching, so use PLD operations.  */
-	/* Pre-bias src and dst.  */
-	sub	src, src, #8
-	sub	dst, dst, #8
-	pld	[src, #8]
-	pld	[src, #72]
-	subs	tmp2, tmp2, #64
-	pld	[src, #136]
-	ldrd	A_l, A_h, [src, #8]
-	strd	B_l, B_h, [sp, #8]
-	ldrd	B_l, B_h, [src, #16]
-	strd	C_l, C_h, [sp, #16]
-	ldrd	C_l, C_h, [src, #24]
-	strd	D_l, D_h, [sp, #24]
-	pld	[src, #200]
-	ldrd	D_l, D_h, [src, #32]!
-	b	1f
-	.p2align	6
-2:
-	pld	[src, #232]
-	strd	A_l, A_h, [dst, #40]
-	ldrd	A_l, A_h, [src, #40]
-	strd	B_l, B_h, [dst, #48]
-	ldrd	B_l, B_h, [src, #48]
-	strd	C_l, C_h, [dst, #56]
-	ldrd	C_l, C_h, [src, #56]
-	strd	D_l, D_h, [dst, #64]!
-	ldrd	D_l, D_h, [src, #64]!
-	subs	tmp2, tmp2, #64
-1:
-	strd	A_l, A_h, [dst, #8]
-	ldrd	A_l, A_h, [src, #8]
-	strd	B_l, B_h, [dst, #16]
-	ldrd	B_l, B_h, [src, #16]
-	strd	C_l, C_h, [dst, #24]
-	ldrd	C_l, C_h, [src, #24]
-	strd	D_l, D_h, [dst, #32]
-	ldrd	D_l, D_h, [src, #32]
-	bcs	2b
-	/* Save the remaining bytes and restore the callee-saved regs.  */
-	strd	A_l, A_h, [dst, #40]
-	add	src, src, #40
-	strd	B_l, B_h, [dst, #48]
-	ldrd	B_l, B_h, [sp, #8]
-	strd	C_l, C_h, [dst, #56]
-	ldrd	C_l, C_h, [sp, #16]
-	strd	D_l, D_h, [dst, #64]
-	ldrd	D_l, D_h, [sp, #24]
-	add	dst, dst, #72
-	tst	tmp2, #0x3f
-	bne	.Ltail63aligned
-	ldr	tmp2, [sp], #FRAME_SIZE
-	bx	lr
-#endif
-
-.Lcpy_notaligned:
-	pld	[src]
-	pld	[src, #64]
-	/* There's at least 64 bytes to copy, but there is no mutual
-	   alignment.  */
-	/* Bring DST to 64-bit alignment.  */
-	lsls	tmp2, dst, #29
-	pld	[src, #(2 * 64)]
-	beq	1f
-	rsbs	tmp2, tmp2, #0
-	sub	count, count, tmp2, lsr #29
-	ldrmi	tmp1, [src], #4
-	strmi	tmp1, [dst], #4
-	lsls	tmp2, tmp2, #2
-	ldrbne	tmp1, [src], #1
-	ldrhcs	tmp2, [src], #2
-	strbne	tmp1, [dst], #1
-	strhcs	tmp2, [dst], #2
-1:
-	pld	[src, #(3 * 64)]
-	subs	count, count, #64
-	ldrmi	tmp2, [sp], #FRAME_SIZE
-	bmi	.Ltail63unaligned
-	pld	[src, #(4 * 64)]
-
-#ifdef USE_NEON
-	vld1.8	{d0-d3}, [src]!
-	vld1.8	{d4-d7}, [src]!
-	subs	count, count, #64
-	bmi	2f
-1:
-	pld	[src, #(4 * 64)]
-	vst1.8	{d0-d3}, [ALIGN (dst, 64)]!
-	vld1.8	{d0-d3}, [src]!
-	vst1.8	{d4-d7}, [ALIGN (dst, 64)]!
-	vld1.8	{d4-d7}, [src]!
-	subs	count, count, #64
-	bpl	1b
-2:
-	vst1.8	{d0-d3}, [ALIGN (dst, 64)]!
-	vst1.8	{d4-d7}, [ALIGN (dst, 64)]!
-	ands	count, count, #0x3f
-#else
-	/* Use an SMS style loop to maximize the I/O bandwidth.  */
-	sub	src, src, #4
-	sub	dst, dst, #8
-	subs	tmp2, count, #64	/* Use tmp2 for count.  */
-	ldr	A_l, [src, #4]
-	ldr	A_h, [src, #8]
-	strd	B_l, B_h, [sp, #8]
-	ldr	B_l, [src, #12]
-	ldr	B_h, [src, #16]
-	strd	C_l, C_h, [sp, #16]
-	ldr	C_l, [src, #20]
-	ldr	C_h, [src, #24]
-	strd	D_l, D_h, [sp, #24]
-	ldr	D_l, [src, #28]
-	ldr	D_h, [src, #32]!
-	b	1f
-	.p2align	6
-2:
-	pld	[src, #(5 * 64) - (32 - 4)]
-	strd	A_l, A_h, [dst, #40]
-	ldr	A_l, [src, #36]
-	ldr	A_h, [src, #40]
-	strd	B_l, B_h, [dst, #48]
-	ldr	B_l, [src, #44]
-	ldr	B_h, [src, #48]
-	strd	C_l, C_h, [dst, #56]
-	ldr	C_l, [src, #52]
-	ldr	C_h, [src, #56]
-	strd	D_l, D_h, [dst, #64]!
-	ldr	D_l, [src, #60]
-	ldr	D_h, [src, #64]!
-	subs	tmp2, tmp2, #64
-1:
-	strd	A_l, A_h, [dst, #8]
-	ldr	A_l, [src, #4]
-	ldr	A_h, [src, #8]
-	strd	B_l, B_h, [dst, #16]
-	ldr	B_l, [src, #12]
-	ldr	B_h, [src, #16]
-	strd	C_l, C_h, [dst, #24]
-	ldr	C_l, [src, #20]
-	ldr	C_h, [src, #24]
-	strd	D_l, D_h, [dst, #32]
-	ldr	D_l, [src, #28]
-	ldr	D_h, [src, #32]
-	bcs	2b
-
-	/* Save the remaining bytes and restore the callee-saved regs.  */
-	strd	A_l, A_h, [dst, #40]
-	add	src, src, #36
-	strd	B_l, B_h, [dst, #48]
-	ldrd	B_l, B_h, [sp, #8]
-	strd	C_l, C_h, [dst, #56]
-	ldrd	C_l, C_h, [sp, #16]
-	strd	D_l, D_h, [dst, #64]
-	ldrd	D_l, D_h, [sp, #24]
-	add	dst, dst, #72
-	ands	count, tmp2, #0x3f
-#endif
-	ldr	tmp2, [sp], #FRAME_SIZE
-	bne	.Ltail63unaligned
-	bx	lr
-END(memcpy)
diff --git a/libc/arch-arm/bionic/strcmp.S b/libc/arch-arm/bionic/strcmp.S
deleted file mode 100644
index 6dba942..0000000
--- a/libc/arch-arm/bionic/strcmp.S
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (c) 2011 The Android Open Source Project
- * Copyright (c) 2008 ARM Ltd
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the company may not be used to endorse or promote
- *    products derived from this software without specific prior written
- *    permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 <machine/cpu-features.h>
-#include <private/bionic_asm.h>
-
-	.text
-
-#ifdef __ARMEB__
-#define SHFT2LSB lsl
-#define SHFT2LSBEQ lsleq
-#define SHFT2MSB lsr
-#define SHFT2MSBEQ lsreq
-#define MSB 0x000000ff
-#define LSB 0xff000000
-#else
-#define SHFT2LSB lsr
-#define SHFT2LSBEQ lsreq
-#define SHFT2MSB lsl
-#define SHFT2MSBEQ lsleq
-#define MSB 0xff000000
-#define LSB 0x000000ff
-#endif
-
-#define magic1(REG) REG
-#define magic2(REG) REG, lsl #7
-
-ENTRY(strcmp)
-	pld	[r0, #0]
-	pld	[r1, #0]
-	eor	r2, r0, r1
-	tst	r2, #3
-
-	/* Strings not at same byte offset from a word boundary.  */
-	bne	.Lstrcmp_unaligned
-	ands	r2, r0, #3
-	bic	r0, r0, #3
-	bic	r1, r1, #3
-	ldr	ip, [r0], #4
-	it	eq
-	ldreq	r3, [r1], #4
-	beq	1f
-
-	/* Although s1 and s2 have identical initial alignment, they are
-	 * not currently word aligned.  Rather than comparing bytes,
-	 * make sure that any bytes fetched from before the addressed
-	 * bytes are forced to 0xff.  Then they will always compare
-	 * equal.
-	 */
-	eor	r2, r2, #3
-	lsl	r2, r2, #3
-	mvn	r3, #MSB
-	SHFT2LSB	r2, r3, r2
-	ldr	r3, [r1], #4
-	orr	ip, ip, r2
-	orr	r3, r3, r2
-1:
-	/* Load the 'magic' constant 0x01010101. */
-	str	r4, [sp, #-4]!
-	mov	r4, #1
-	orr	r4, r4, r4, lsl #8
-	orr	r4, r4, r4, lsl #16
-	.p2align	2
-4:
-	pld	[r0, #8]
-	pld	[r1, #8]
-	sub	r2, ip, magic1(r4)
-	cmp	ip, r3
-	itttt	eq
-
-	/* check for any zero bytes in first word */
-	biceq	r2, r2, ip
-	tsteq	r2, magic2(r4)
-	ldreq	ip, [r0], #4
-	ldreq	r3, [r1], #4
-	beq	4b
-2:
-	/* There's a zero or a different byte in the word */
-	SHFT2MSB	r0, ip, #24
-	SHFT2LSB	ip, ip, #8
-	cmp	r0, #1
-	it	cs
-	cmpcs	r0, r3, SHFT2MSB #24
-	it	eq
-	SHFT2LSBEQ r3, r3, #8
-	beq	2b
-	/* On a big-endian machine, r0 contains the desired byte in bits
-	 * 0-7; on a little-endian machine they are in bits 24-31.  In
-	 * both cases the other bits in r0 are all zero.  For r3 the
-	 * interesting byte is at the other end of the word, but the
-	 * other bits are not necessarily zero.  We need a signed result
-	 * representing the differnece in the unsigned bytes, so for the
-	 * little-endian case we can't just shift the interesting bits up.
-	 */
-#ifdef __ARMEB__
-	sub	r0, r0, r3, lsr #24
-#else
-	and	r3, r3, #255
-	/* No RSB instruction in Thumb2 */
-#ifdef __thumb2__
-	lsr	r0, r0, #24
-	sub	r0, r0, r3
-#else
-	rsb	r0, r3, r0, lsr #24
-#endif
-#endif
-	ldr	r4, [sp], #4
-	bx	lr
-
-.Lstrcmp_unaligned:
-	wp1 .req r0
-	wp2 .req r1
-	b1  .req r2
-	w1  .req r4
-	w2  .req r5
-	t1  .req ip
-	@ r3 is scratch
-
-	/* First of all, compare bytes until wp1(sp1) is word-aligned. */
-1:
-	tst	wp1, #3
-	beq	2f
-	ldrb	r2, [wp1], #1
-	ldrb	r3, [wp2], #1
-	cmp	r2, #1
-	it	cs
-	cmpcs	r2, r3
-	beq	1b
-	sub	r0, r2, r3
-	bx	lr
-
-2:
-	str	r5, [sp, #-4]!
-	str	r4, [sp, #-4]!
-	mov	b1, #1
-	orr	b1, b1, b1, lsl #8
-	orr	b1, b1, b1, lsl #16
-
-	and	t1, wp2, #3
-	bic	wp2, wp2, #3
-	ldr	w1, [wp1], #4
-	ldr	w2, [wp2], #4
-	cmp	t1, #2
-	beq	2f
-	bhi	3f
-
-	/* Critical inner Loop: Block with 3 bytes initial overlap */
-	.p2align	2
-1:
-	bic	t1, w1, #MSB
-	cmp	t1, w2, SHFT2LSB #8
-	sub	r3, w1, b1
-	bic	r3, r3, w1
-	bne	4f
-	ands	r3, r3, b1, lsl #7
-	it	eq
-	ldreq	w2, [wp2], #4
-	bne	5f
-	eor	t1, t1, w1
-	cmp	t1, w2, SHFT2MSB #24
-	bne	6f
-	ldr	w1, [wp1], #4
-	b	1b
-4:
-	SHFT2LSB	w2, w2, #8
-	b	8f
-
-5:
-#ifdef __ARMEB__
-	/* The syndrome value may contain false ones if the string ends
-	 * with the bytes 0x01 0x00
-	 */
-	tst	w1, #0xff000000
-	itt	ne
-	tstne	w1, #0x00ff0000
-	tstne	w1, #0x0000ff00
-	beq	7f
-#else
-	bics	r3, r3, #0xff000000
-	bne	7f
-#endif
-	ldrb	w2, [wp2]
-	SHFT2LSB	t1, w1, #24
-#ifdef __ARMEB__
-	lsl	w2, w2, #24
-#endif
-	b	8f
-
-6:
-	SHFT2LSB	t1, w1, #24
-	and	w2, w2, #LSB
-	b	8f
-
-	/* Critical inner Loop: Block with 2 bytes initial overlap */
-	.p2align	2
-2:
-	SHFT2MSB	t1, w1, #16
-	sub	r3, w1, b1
-	SHFT2LSB	t1, t1, #16
-	bic	r3, r3, w1
-	cmp	t1, w2, SHFT2LSB #16
-	bne	4f
-	ands	r3, r3, b1, lsl #7
-	it	eq
-	ldreq	w2, [wp2], #4
-	bne	5f
-	eor	t1, t1, w1
-	cmp	t1, w2, SHFT2MSB #16
-	bne	6f
-	ldr	w1, [wp1], #4
-	b	2b
-
-5:
-#ifdef __ARMEB__
-	/* The syndrome value may contain false ones if the string ends
-	 * with the bytes 0x01 0x00
-	 */
-	tst	w1, #0xff000000
-	it	ne
-	tstne	w1, #0x00ff0000
-	beq	7f
-#else
-	lsls	r3, r3, #16
-	bne	7f
-#endif
-	ldrh	w2, [wp2]
-	SHFT2LSB	t1, w1, #16
-#ifdef __ARMEB__
-	lsl	w2, w2, #16
-#endif
-	b	8f
-
-6:
-	SHFT2MSB	w2, w2, #16
-	SHFT2LSB	t1, w1, #16
-4:
-	SHFT2LSB	w2, w2, #16
-	b	8f
-
-	/* Critical inner Loop: Block with 1 byte initial overlap */
-	.p2align	2
-3:
-	and	t1, w1, #LSB
-	cmp	t1, w2, SHFT2LSB #24
-	sub	r3, w1, b1
-	bic	r3, r3, w1
-	bne	4f
-	ands	r3, r3, b1, lsl #7
-	it	eq
-	ldreq	w2, [wp2], #4
-	bne	5f
-	eor	t1, t1, w1
-	cmp	t1, w2, SHFT2MSB #8
-	bne	6f
-	ldr	w1, [wp1], #4
-	b	3b
-4:
-	SHFT2LSB	w2, w2, #24
-	b	8f
-5:
-	/* The syndrome value may contain false ones if the string ends
-	 * with the bytes 0x01 0x00
-	 */
-	tst	w1, #LSB
-	beq	7f
-	ldr	w2, [wp2], #4
-6:
-	SHFT2LSB	t1, w1, #8
-	bic	w2, w2, #MSB
-	b	8f
-7:
-	mov	r0, #0
-	ldr	r4, [sp], #4
-	ldr	r5, [sp], #4
-	bx	lr
-
-8:
-	and	r2, t1, #LSB
-	and	r0, w2, #LSB
-	cmp	r0, #1
-	it	cs
-	cmpcs	r0, r2
-	itt	eq
-	SHFT2LSBEQ	t1, t1, #8
-	SHFT2LSBEQ	w2, w2, #8
-	beq	8b
-	sub	r0, r2, r0
-	ldr	r4, [sp], #4
-	ldr	r5, [sp], #4
-	bx	lr
-END(strcmp)
diff --git a/libc/arch-arm/cortex-a15/cortex-a15.mk b/libc/arch-arm/cortex-a15/cortex-a15.mk
index f1abe32..ec423c5 100644
--- a/libc/arch-arm/cortex-a15/cortex-a15.mk
+++ b/libc/arch-arm/cortex-a15/cortex-a15.mk
@@ -1,4 +1,5 @@
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memcmp.S \
     arch-arm/cortex-a15/bionic/memcpy.S \
     arch-arm/cortex-a15/bionic/memset.S \
     arch-arm/cortex-a15/bionic/stpcpy.S \
diff --git a/libc/arch-arm/cortex-a9/cortex-a9.mk b/libc/arch-arm/cortex-a9/cortex-a9.mk
index c82db3b..e38c40a 100644
--- a/libc/arch-arm/cortex-a9/cortex-a9.mk
+++ b/libc/arch-arm/cortex-a9/cortex-a9.mk
@@ -1,4 +1,5 @@
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memcmp.S \
     arch-arm/cortex-a9/bionic/memcpy.S \
     arch-arm/cortex-a9/bionic/memset.S \
     arch-arm/cortex-a9/bionic/stpcpy.S \
diff --git a/libc/arch-arm/denver/denver.mk b/libc/arch-arm/denver/denver.mk
index 0bc52a2..5fddf95 100644
--- a/libc/arch-arm/denver/denver.mk
+++ b/libc/arch-arm/denver/denver.mk
@@ -1,4 +1,5 @@
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memcmp.S \
     arch-arm/denver/bionic/memcpy.S \
     arch-arm/denver/bionic/memmove.S \
     arch-arm/denver/bionic/memset.S \
diff --git a/libc/arch-arm/bionic/memcmp.S b/libc/arch-arm/generic/bionic/memcmp.S
similarity index 100%
rename from libc/arch-arm/bionic/memcmp.S
rename to libc/arch-arm/generic/bionic/memcmp.S
diff --git a/libc/arch-arm/generic/generic.mk b/libc/arch-arm/generic/generic.mk
index 95be867..96ed949 100644
--- a/libc/arch-arm/generic/generic.mk
+++ b/libc/arch-arm/generic/generic.mk
@@ -1,4 +1,5 @@
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memcmp.S \
     arch-arm/generic/bionic/memcpy.S \
     arch-arm/generic/bionic/memset.S \
     arch-arm/generic/bionic/strcmp.S \
diff --git a/libc/arch-arm/krait/krait.mk b/libc/arch-arm/krait/krait.mk
index 1bb7b0a..450f472 100644
--- a/libc/arch-arm/krait/krait.mk
+++ b/libc/arch-arm/krait/krait.mk
@@ -1,4 +1,5 @@
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memcmp.S \
     arch-arm/krait/bionic/memcpy.S \
     arch-arm/krait/bionic/memset.S \
     arch-arm/krait/bionic/strcmp.S \
diff --git a/libc/arch-mips/include/machine/elf_machdep.h b/libc/arch-mips/include/machine/elf_machdep.h
index d27d431..0aacedf 100644
--- a/libc/arch-mips/include/machine/elf_machdep.h
+++ b/libc/arch-mips/include/machine/elf_machdep.h
@@ -121,6 +121,7 @@
 #define	DT_MIPS_GOTSYM		0x70000013	/* first dynamic sym in got */
 #define DT_MIPS_HIPAGENO	0x70000014
 #define	DT_MIPS_RLD_MAP		0x70000016	/* address of loader map */
+#define DT_MIPS_RLD_MAP2	0x70000035	/* offset of loader map, used for PIE */
 
 /*
  * ELF Flags
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index f5be415..c74a52c 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <cutils/trace.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/libc/bionic/chown.cpp b/libc/bionic/chown.cpp
index bc2e605..dce1673 100644
--- a/libc/bionic/chown.cpp
+++ b/libc/bionic/chown.cpp
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 int chown(const char* path, uid_t uid, gid_t gid) {
   return fchownat(AT_FDCWD, path, uid, gid, 0);
diff --git a/libc/bionic/lchown.cpp b/libc/bionic/lchown.cpp
index 95251db..24611a5 100644
--- a/libc/bionic/lchown.cpp
+++ b/libc/bionic/lchown.cpp
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 int lchown(const char* path, uid_t uid, gid_t gid) {
   return fchownat(AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW);
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 2a6a03b..15b3fd5 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -74,9 +74,7 @@
 void __libc_init_tls(KernelArgumentBlock& args) {
   __libc_auxv = args.auxv;
 
-  static void* tls[BIONIC_TLS_SLOTS];
   static pthread_internal_t main_thread;
-  main_thread.tls = tls;
 
   // Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
   // As a side-effect, this tells us our pid (which is the same as the main thread's tid).
@@ -96,7 +94,7 @@
   __init_thread(&main_thread, false);
   __init_tls(&main_thread);
   __set_tls(main_thread.tls);
-  tls[TLS_SLOT_BIONIC_PREINIT] = &args;
+  main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
 
   __init_alternate_signal_stack(&main_thread);
 }
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index ebb318d..d267229 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <sys/poll.h>
 #include <sys/select.h>
 
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index c99e69c..9b45161 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -35,6 +35,7 @@
 #include "pthread_internal.h"
 
 #include "private/bionic_macros.h"
+#include "private/bionic_prctl.h"
 #include "private/bionic_ssp.h"
 #include "private/bionic_tls.h"
 #include "private/libc_logging.h"
@@ -72,6 +73,10 @@
     ss.ss_flags = 0;
     sigaltstack(&ss, NULL);
     thread->alternate_signal_stack = ss.ss_sp;
+
+    // We can only use const static allocated string for mapped region name, as Android kernel
+    // uses the string pointer directly when dumping /proc/pid/maps.
+    prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ss.ss_sp, ss.ss_size, "thread signal stack");
   }
 }
 
@@ -101,31 +106,70 @@
   return error;
 }
 
-static void* __create_thread_stack(pthread_internal_t* thread) {
+static void* __create_thread_stack(size_t stack_size, size_t guard_size) {
   // Create a new private anonymous map.
   int prot = PROT_READ | PROT_WRITE;
   int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
-  void* stack = mmap(NULL, thread->attr.stack_size, prot, flags, -1, 0);
+  void* stack = mmap(NULL, stack_size, prot, flags, -1, 0);
   if (stack == MAP_FAILED) {
     __libc_format_log(ANDROID_LOG_WARN,
                       "libc",
                       "pthread_create failed: couldn't allocate %zd-byte stack: %s",
-                      thread->attr.stack_size, strerror(errno));
+                      stack_size, strerror(errno));
     return NULL;
   }
 
   // Set the guard region at the end of the stack to PROT_NONE.
-  if (mprotect(stack, thread->attr.guard_size, PROT_NONE) == -1) {
+  if (mprotect(stack, guard_size, PROT_NONE) == -1) {
     __libc_format_log(ANDROID_LOG_WARN, "libc",
                       "pthread_create failed: couldn't mprotect PROT_NONE %zd-byte stack guard region: %s",
-                      thread->attr.guard_size, strerror(errno));
-    munmap(stack, thread->attr.stack_size);
+                      guard_size, strerror(errno));
+    munmap(stack, stack_size);
     return NULL;
   }
 
   return stack;
 }
 
+static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp, void** child_stack) {
+  size_t allocate_stack_size;
+  uint8_t* stack_top;
+
+  if (attr->stack_base == NULL) {
+    // The caller didn't provide a stack, so allocate one.
+    // Make sure the stack size and guard size are multiples of PAGE_SIZE.
+    allocate_stack_size = BIONIC_ALIGN(attr->stack_size + sizeof(pthread_internal_t), PAGE_SIZE);
+    attr->guard_size = BIONIC_ALIGN(attr->guard_size, PAGE_SIZE);
+    attr->stack_base = __create_thread_stack(allocate_stack_size, attr->guard_size);
+    if (attr->stack_base == NULL) {
+      return EAGAIN;
+    }
+    stack_top = reinterpret_cast<uint8_t*>(attr->stack_base) + allocate_stack_size;
+  } else {
+    // The caller did provide a stack, so remember we're not supposed to free it.
+    attr->flags |= PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK;
+    allocate_stack_size = 0;
+    stack_top = reinterpret_cast<uint8_t*>(attr->stack_base) + attr->stack_size;
+  }
+
+  // Thread stack is used for two sections:
+  //   pthread_internal_t.
+  //   regular stack, from top to down.
+  stack_top -= sizeof(pthread_internal_t);
+  pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top);
+
+  // No need to check stack_top alignment. The size of pthread_internal_t is 16-bytes aligned,
+  // and user allocated stack is guaranteed by pthread_attr_setstack.
+
+  thread->allocated_stack_size = allocate_stack_size;
+  thread->attr = *attr;
+  __init_tls(thread);
+
+  *threadp = thread;
+  *child_stack = stack_top;
+  return 0;
+}
+
 static int __pthread_start(void* arg) {
   pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
 
@@ -158,43 +202,21 @@
   // Inform the rest of the C library that at least one thread was created.
   __isthreaded = 1;
 
-  pthread_internal_t* thread = __create_thread_struct();
-  if (thread == NULL) {
-    return EAGAIN;
-  }
-
+  pthread_attr_t thread_attr;
   if (attr == NULL) {
-    pthread_attr_init(&thread->attr);
+    pthread_attr_init(&thread_attr);
   } else {
-    thread->attr = *attr;
+    thread_attr = *attr;
     attr = NULL; // Prevent misuse below.
   }
 
-  // Make sure the stack size and guard size are multiples of PAGE_SIZE.
-  thread->attr.stack_size = BIONIC_ALIGN(thread->attr.stack_size, PAGE_SIZE);
-  thread->attr.guard_size = BIONIC_ALIGN(thread->attr.guard_size, PAGE_SIZE);
-
-  if (thread->attr.stack_base == NULL) {
-    // The caller didn't provide a stack, so allocate one.
-    thread->attr.stack_base = __create_thread_stack(thread);
-    if (thread->attr.stack_base == NULL) {
-      __free_thread_struct(thread);
-      return EAGAIN;
-    }
-  } else {
-    // The caller did provide a stack, so remember we're not supposed to free it.
-    thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK;
+  pthread_internal_t* thread = NULL;
+  void* child_stack = NULL;
+  int result = __allocate_thread(&thread_attr, &thread, &child_stack);
+  if (result != 0) {
+    return result;
   }
 
-  // Make room for the TLS area.
-  // The child stack is the same address, just growing in the opposite direction.
-  // At offsets >= 0, we have the TLS slots.
-  // At offsets < 0, we have the child stack.
-  thread->tls = reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(thread->attr.stack_base) +
-                  thread->attr.stack_size - BIONIC_ALIGN(BIONIC_TLS_SLOTS * sizeof(void*), 16));
-  void* child_stack = thread->tls;
-  __init_tls(thread);
-
   // Create a mutex for the thread in TLS to wait on once it starts so we can keep
   // it from doing anything until after we notify the debugger about it
   //
@@ -211,7 +233,7 @@
 
   int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM |
       CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
-  void* tls = thread->tls;
+  void* tls = reinterpret_cast<void*>(thread->tls);
 #if defined(__i386__)
   // On x86 (but not x86-64), CLONE_SETTLS takes a pointer to a struct user_desc rather than
   // a pointer to the TLS itself.
@@ -227,9 +249,8 @@
     // reminder that you can't rewrite this function to use a ScopedPthreadMutexLocker.
     pthread_mutex_unlock(&thread->startup_handshake_mutex);
     if (!thread->user_allocated_stack()) {
-      munmap(thread->attr.stack_base, thread->attr.stack_size);
+      munmap(thread->attr.stack_base, thread->allocated_stack_size);
     }
-    __free_thread_struct(thread);
     __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno));
     return clone_errno;
   }
diff --git a/libc/bionic/pthread_detach.cpp b/libc/bionic/pthread_detach.cpp
index a8608e3..715acf1 100644
--- a/libc/bionic/pthread_detach.cpp
+++ b/libc/bionic/pthread_detach.cpp
@@ -46,7 +46,7 @@
 
   if (thread->tid == 0) {
     // Already exited; clean up.
-    _pthread_internal_remove_locked(thread.get());
+    _pthread_internal_remove_locked(thread.get(), true);
     return 0;
   }
 
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index a6bb363..ee76e2b 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -89,8 +89,8 @@
 
   // Keep track of what we need to know about the stack before we lose the pthread_internal_t.
   void* stack_base = thread->attr.stack_base;
-  size_t stack_size = thread->attr.stack_size;
-  bool user_allocated_stack = thread->user_allocated_stack();
+  size_t stack_size = thread->allocated_stack_size;
+  bool free_stack = false;
 
   pthread_mutex_lock(&g_thread_list_lock);
   if ((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) != 0) {
@@ -98,24 +98,18 @@
     // First make sure that the kernel does not try to clear the tid field
     // because we'll have freed the memory before the thread actually exits.
     __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
-    // will be unmapped after the exit call below.
-    if (!user_allocated_stack) {
-      thread->attr.stack_base = NULL;
-      thread->attr.stack_size = 0;
-      thread->tls = NULL;
+
+    // pthread_internal_t is freed below with stack, not here.
+    _pthread_internal_remove_locked(thread, false);
+    if (!thread->user_allocated_stack()) {
+      free_stack = true;
     }
-    // pthread_join is responsible for destroying the pthread_internal_t for non-detached threads.
-    // The kernel will futex_wake on the pthread_internal_t::tid field to wake pthread_join.
   }
   pthread_mutex_unlock(&g_thread_list_lock);
 
-  if (user_allocated_stack) {
-    // Cleaning up this thread's stack is the creator's responsibility, not ours.
-    __exit(0);
-  } else {
+  // Detached threads exit with stack teardown, and everything deallocated here.
+  // Threads that can be joined exit but leave their stacks for the pthread_join caller to clean up.
+  if (free_stack) {
     // We need to munmap the stack we're running on before calling exit.
     // That's not something we can do in C.
 
@@ -126,5 +120,7 @@
     sigprocmask(SIG_SETMASK, &mask, NULL);
 
     _exit_with_stack_teardown(stack_base, stack_size);
+  } else {
+    __exit(0);
   }
 }
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index c5136c9..62ec543 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -30,6 +30,8 @@
 
 #include <pthread.h>
 
+#include "private/bionic_tls.h"
+
 /* Has the thread been detached by a pthread_join or pthread_detach call? */
 #define PTHREAD_ATTR_FLAG_DETACHED 0x00000001
 
@@ -72,8 +74,6 @@
     return (attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK) != 0;
   }
 
-  void** tls;
-
   pthread_attr_t attr;
 
   __pthread_cleanup_t* cleanup_stack;
@@ -86,16 +86,19 @@
 
   pthread_mutex_t startup_handshake_mutex;
 
+  /* Store real allocated stack size, including thread stack and pthread_internal_t. */
+  int allocated_stack_size;
+
+  void* tls[BIONIC_TLS_SLOTS];
+
   /*
    * The dynamic linker implements dlerror(3), which makes it hard for us to implement this
    * per-thread buffer by simply using malloc(3) and free(3).
    */
 #define __BIONIC_DLERROR_BUFFER_SIZE 512
   char dlerror_buffer[__BIONIC_DLERROR_BUFFER_SIZE];
-};
+} __attribute__((aligned(16))); // Align it as thread stack top below it should be aligned.
 
-__LIBC_HIDDEN__ pthread_internal_t* __create_thread_struct();
-__LIBC_HIDDEN__ void __free_thread_struct(pthread_internal_t*);
 __LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread, bool add_to_thread_list);
 __LIBC_HIDDEN__ void __init_tls(pthread_internal_t* thread);
 __LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*);
@@ -105,7 +108,7 @@
 extern "C" __LIBC64_HIDDEN__ pthread_internal_t* __get_thread(void);
 
 __LIBC_HIDDEN__ void pthread_key_clean_all(void);
-__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread);
+__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread, bool free_thread);
 
 /*
  * Traditionally we gave threads a 1MiB stack. When we started
diff --git a/libc/bionic/pthread_internals.cpp b/libc/bionic/pthread_internals.cpp
index 33cddd7..a0a8df0 100644
--- a/libc/bionic/pthread_internals.cpp
+++ b/libc/bionic/pthread_internals.cpp
@@ -41,26 +41,7 @@
 pthread_internal_t* g_thread_list = NULL;
 pthread_mutex_t g_thread_list_lock = PTHREAD_MUTEX_INITIALIZER;
 
-pthread_internal_t* __create_thread_struct() {
-  void* result = mmap(NULL, sizeof(pthread_internal_t), PROT_READ | PROT_WRITE,
-                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
-  if (result == MAP_FAILED) {
-    __libc_format_log(ANDROID_LOG_WARN, "libc",
-                      "__create_thread_struct() failed: %s", strerror(errno));
-    return NULL;
-  }
-  return reinterpret_cast<pthread_internal_t*>(result);
-}
-
-void __free_thread_struct(pthread_internal_t* thread) {
-  int result = munmap(thread, sizeof(pthread_internal_t));
-  if (result != 0) {
-    __libc_format_log(ANDROID_LOG_WARN, "libc",
-                      "__free_thread_struct() failed: %s", strerror(errno));
-  }
-}
-
-void _pthread_internal_remove_locked(pthread_internal_t* thread) {
+void _pthread_internal_remove_locked(pthread_internal_t* thread, bool free_thread) {
   if (thread->next != NULL) {
     thread->next->prev = thread->prev;
   }
@@ -70,10 +51,11 @@
     g_thread_list = thread->next;
   }
 
-  // The main thread is not heap-allocated. See __libc_init_tls for the declaration,
-  // and __libc_init_common for the point where it's added to the thread list.
-  if ((thread->attr.flags & PTHREAD_ATTR_FLAG_MAIN_THREAD) == 0) {
-    __free_thread_struct(thread);
+  // For threads using user allocated stack (including the main thread), the pthread_internal_t
+  // can't be freed since it is on the stack.
+  if (free_thread && !thread->user_allocated_stack()) {
+    // Use one munmap to free allocated stack size, including thread stack and pthread_internal_t.
+    munmap(thread->attr.stack_base, thread->allocated_stack_size);
   }
 }
 
diff --git a/libc/bionic/pthread_join.cpp b/libc/bionic/pthread_join.cpp
index 0cbed62..e3350ef 100644
--- a/libc/bionic/pthread_join.cpp
+++ b/libc/bionic/pthread_join.cpp
@@ -74,6 +74,6 @@
     *return_value = thread->return_value;
   }
 
-  _pthread_internal_remove_locked(thread.get());
+  _pthread_internal_remove_locked(thread.get(), true);
   return 0;
 }
diff --git a/libc/bionic/pthread_key.cpp b/libc/bionic/pthread_key.cpp
index b47ef22..49b72e9 100644
--- a/libc/bionic/pthread_key.cpp
+++ b/libc/bionic/pthread_key.cpp
@@ -213,16 +213,6 @@
   // Clear value in all threads.
   pthread_mutex_lock(&g_thread_list_lock);
   for (pthread_internal_t*  t = g_thread_list; t != NULL; t = t->next) {
-    // Skip zombie threads. They don't have a valid TLS area any more.
-    // Similarly, it is possible to have t->tls == NULL for threads that
-    // were just recently created through pthread_create() but whose
-    // startup trampoline (__pthread_start) hasn't been run yet by the
-    // scheduler. t->tls will also be NULL after a thread's stack has been
-    // unmapped but before the ongoing pthread_join() is finished.
-    if (t->tid == 0 || t->tls == NULL) {
-      continue;
-    }
-
     t->tls[key] = NULL;
   }
   tls_map.DeleteKey(key);
diff --git a/libc/bionic/raise.cpp b/libc/bionic/raise.cpp
index 0dd0ad7..b134b5a 100644
--- a/libc/bionic/raise.cpp
+++ b/libc/bionic/raise.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <pthread.h>
 #include <signal.h>
 
diff --git a/libc/bionic/readlink.cpp b/libc/bionic/readlink.cpp
index a2c5e91..3bb7bc1 100644
--- a/libc/bionic/readlink.cpp
+++ b/libc/bionic/readlink.cpp
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 ssize_t readlink(const char* path, char* buf, size_t size) {
   return readlinkat(AT_FDCWD, path, buf, size);
diff --git a/libc/bionic/sigaddset.cpp b/libc/bionic/sigaddset.cpp
index 33ec6f8..6ade3b1 100644
--- a/libc/bionic/sigaddset.cpp
+++ b/libc/bionic/sigaddset.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <signal.h>
 
 int sigaddset(sigset_t* set, int signum) {
diff --git a/libc/bionic/sigdelset.cpp b/libc/bionic/sigdelset.cpp
index 9eea250..3582f0d 100644
--- a/libc/bionic/sigdelset.cpp
+++ b/libc/bionic/sigdelset.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <signal.h>
 
 int sigdelset(sigset_t* set, int signum) {
diff --git a/libc/bionic/sigemptyset.cpp b/libc/bionic/sigemptyset.cpp
index 2993169..8d8033f 100644
--- a/libc/bionic/sigemptyset.cpp
+++ b/libc/bionic/sigemptyset.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <signal.h>
 
 int sigemptyset(sigset_t* set) {
diff --git a/libc/bionic/sigfillset.cpp b/libc/bionic/sigfillset.cpp
index 7b7cbb8..37792e5 100644
--- a/libc/bionic/sigfillset.cpp
+++ b/libc/bionic/sigfillset.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <signal.h>
 
 int sigfillset(sigset_t* set) {
diff --git a/libc/bionic/sigismember.cpp b/libc/bionic/sigismember.cpp
index 0dc73ac..16acd09 100644
--- a/libc/bionic/sigismember.cpp
+++ b/libc/bionic/sigismember.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <signal.h>
 
 int sigismember(const sigset_t* set, int signum) {
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 88e5ac5..ab67935 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -42,18 +42,44 @@
 #include "private/libc_logging.h"
 #include "private/ThreadLocalBuffer.h"
 
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(stubs);
+// POSIX seems to envisage an implementation where the <pwd.h> functions are
+// implemented by brute-force searching with getpwent(3), and the <grp.h>
+// functions are implemented similarly with getgrent(3). This means that it's
+// okay for all the <grp.h> functions to share state, and all the <passwd.h>
+// functions to share state, but <grp.h> functions can't clobber <passwd.h>
+// functions' state and vice versa.
 
-struct stubs_state_t {
-  passwd passwd_;
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(group);
+
+struct group_state_t {
   group group_;
   char* group_members_[2];
-  char app_name_buffer_[32];
   char group_name_buffer_[32];
+};
+
+static group_state_t* __group_state() {
+  LOCAL_INIT_THREAD_LOCAL_BUFFER(group_state_t*, group, sizeof(group_state_t));
+  if (group_tls_buffer != NULL) {
+    memset(group_tls_buffer, 0, sizeof(group_state_t));
+    group_tls_buffer->group_.gr_mem = group_tls_buffer->group_members_;
+  }
+  return group_tls_buffer;
+}
+
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(passwd);
+
+struct passwd_state_t {
+  passwd passwd_;
+  char app_name_buffer_[32];
   char dir_buffer_[32];
   char sh_buffer_[32];
 };
 
+static passwd_state_t* __passwd_state() {
+  LOCAL_INIT_THREAD_LOCAL_BUFFER(passwd_state_t*, passwd, sizeof(passwd_state_t));
+  return passwd_tls_buffer;
+}
+
 static int do_getpw_r(int by_name, const char* name, uid_t uid,
                       passwd* dst, char* buf, size_t byte_count,
                       passwd** result) {
@@ -91,7 +117,7 @@
 
   // pw_passwd and pw_gecos are non-POSIX and unused (always NULL) in bionic.
   dst->pw_passwd = NULL;
-#ifdef __LP64__
+#if defined(__LP64__)
   dst->pw_gecos = NULL;
 #endif
 
@@ -113,17 +139,7 @@
   return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result);
 }
 
-static stubs_state_t* __stubs_state() {
-  LOCAL_INIT_THREAD_LOCAL_BUFFER(stubs_state_t*, stubs, sizeof(stubs_state_t));
-
-  if (stubs_tls_buffer != NULL) {
-    memset(stubs_tls_buffer, 0, sizeof(stubs_state_t));
-    stubs_tls_buffer->group_.gr_mem = stubs_tls_buffer->group_members_;
-  }
-  return stubs_tls_buffer;
-}
-
-static passwd* android_iinfo_to_passwd(stubs_state_t* state,
+static passwd* android_iinfo_to_passwd(passwd_state_t* state,
                                        const android_id_info* iinfo) {
   snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
   snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
@@ -145,7 +161,7 @@
   return gr;
 }
 
-static passwd* android_id_to_passwd(stubs_state_t* state, unsigned id) {
+static passwd* android_id_to_passwd(passwd_state_t* state, unsigned id) {
   for (size_t n = 0; n < android_id_count; ++n) {
     if (android_ids[n].aid == id) {
       return android_iinfo_to_passwd(state, android_ids + n);
@@ -154,7 +170,7 @@
   return NULL;
 }
 
-static passwd* android_name_to_passwd(stubs_state_t* state, const char* name) {
+static passwd* android_name_to_passwd(passwd_state_t* state, const char* name) {
   for (size_t n = 0; n < android_id_count; ++n) {
     if (!strcmp(android_ids[n].name, name)) {
       return android_iinfo_to_passwd(state, android_ids + n);
@@ -297,9 +313,7 @@
 // AID_ISOLATED_START to AID_USER-1 -> u0_i1234
 // AID_USER+                        -> u1_radio, u1_a1234, u2_i1234, etc.
 // returns a passwd structure (sets errno to ENOENT on failure).
-static passwd* app_id_to_passwd(uid_t uid, stubs_state_t* state) {
-  passwd* pw = &state->passwd_;
-
+static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {
   if (uid < AID_APP) {
     errno = ENOENT;
     return NULL;
@@ -316,18 +330,18 @@
 
   snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
 
+  passwd* pw = &state->passwd_;
   pw->pw_name  = state->app_name_buffer_;
   pw->pw_dir   = state->dir_buffer_;
   pw->pw_shell = state->sh_buffer_;
   pw->pw_uid   = uid;
   pw->pw_gid   = uid;
-
   return pw;
 }
 
 // Translate a gid into the corresponding app_<gid>
 // group structure (sets errno to ENOENT on failure).
-static group* app_id_to_group(gid_t gid, stubs_state_t* state) {
+static group* app_id_to_group(gid_t gid, group_state_t* state) {
   if (gid < AID_APP) {
     errno = ENOENT;
     return NULL;
@@ -339,13 +353,11 @@
   gr->gr_name   = state->group_name_buffer_;
   gr->gr_gid    = gid;
   gr->gr_mem[0] = gr->gr_name;
-
   return gr;
 }
 
-
 passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
-  stubs_state_t* state = __stubs_state();
+  passwd_state_t* state = __passwd_state();
   if (state == NULL) {
     return NULL;
   }
@@ -358,7 +370,7 @@
 }
 
 passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
-  stubs_state_t* state = __stubs_state();
+  passwd_state_t* state = __passwd_state();
   if (state == NULL) {
     return NULL;
   }
@@ -372,12 +384,12 @@
 
 // All users are in just one group, the one passed in.
 int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) {
-    if (*ngroups < 1) {
-        *ngroups = 1;
-        return -1;
-    }
-    groups[0] = group;
-    return (*ngroups = 1);
+  if (*ngroups < 1) {
+    *ngroups = 1;
+    return -1;
+  }
+  groups[0] = group;
+  return (*ngroups = 1);
 }
 
 char* getlogin() { // NOLINT: implementing bad function.
@@ -386,7 +398,7 @@
 }
 
 group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
-  stubs_state_t* state = __stubs_state();
+  group_state_t* state = __group_state();
   if (state == NULL) {
     return NULL;
   }
@@ -399,7 +411,7 @@
 }
 
 group* getgrnam(const char* name) { // NOLINT: implementing bad function.
-  stubs_state_t* state = __stubs_state();
+  group_state_t* state = __group_state();
   if (state == NULL) {
     return NULL;
   }
diff --git a/libc/bionic/termios.cpp b/libc/bionic/termios.cpp
index 082dcdc..44ae643 100644
--- a/libc/bionic/termios.cpp
+++ b/libc/bionic/termios.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <termios.h>
 #include <unistd.h>
 
diff --git a/libc/bionic/utimes.cpp b/libc/bionic/utimes.cpp
index 65f2d0b..0b66e6c 100644
--- a/libc/bionic/utimes.cpp
+++ b/libc/bionic/utimes.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/time.h>
diff --git a/libc/dns/gethnamaddr.c b/libc/dns/gethnamaddr.c
deleted file mode 100644
index 736858f..0000000
--- a/libc/dns/gethnamaddr.c
+++ /dev/null
@@ -1,1405 +0,0 @@
-/*	$NetBSD: gethnamaddr.c,v 1.70 2006/03/22 00:03:51 christos Exp $	*/
-
-/*
- * ++Copyright++ 1985, 1988, 1993
- * -
- * Copyright (c) 1985, 1988, 1993
- *    The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- * -
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- * -
- * --Copyright--
- */
-
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include "NetdClientDispatch.h"
-#include "resolv_netid.h"
-#include "resolv_private.h"
-#include "resolv_cache.h"
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <strings.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#define ALIGNBYTES (sizeof(uintptr_t) - 1)
-#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
-
-#ifndef LOG_AUTH
-# define LOG_AUTH 0
-#endif
-
-#define MULTI_PTRS_ARE_ALIASES 1	/* XXX - experimental */
-
-#include "nsswitch.h"
-#include <stdlib.h>
-#include <string.h>
-
-// This should be synchronized to ResponseCode.h
-static const int DnsProxyQueryResult = 222;
-
-static const char AskedForGot[] =
-			  "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
-
-#define	MAXPACKET	(64*1024)
-
-typedef union {
-    HEADER hdr;
-    u_char buf[MAXPACKET];
-} querybuf;
-
-typedef union {
-    int32_t al;
-    char ac;
-} align;
-
-#ifdef DEBUG
-static void dprintf(const char *, res_state, ...)
-	__attribute__((__format__(__printf__, 1, 3)));
-#endif
-static struct hostent *getanswer(const querybuf *, int, const char *, int,
-    res_state);
-static void map_v4v6_address(const char *, char *);
-static void map_v4v6_hostent(struct hostent *, char **, char *);
-static void addrsort(char **, int, res_state);
-
-static void _sethtent(int);
-static void _endhtent(void);
-static struct hostent *_gethtent(void);
-void ht_sethostent(int);
-void ht_endhostent(void);
-struct hostent *ht_gethostbyname(char *);
-struct hostent *ht_gethostbyaddr(const char *, int, int);
-void dns_service(void);
-#undef dn_skipname
-int dn_skipname(const u_char *, const u_char *);
-static int _gethtbyaddr(void *, void *, va_list);
-static int _gethtbyname(void *, void *, va_list);
-static struct hostent *_gethtbyname2(const char *, int);
-static int _dns_gethtbyaddr(void *, void *, va_list);
-static int _dns_gethtbyname(void *, void *, va_list);
-
-static struct hostent *gethostbyname_internal(const char *, int, res_state, unsigned, unsigned);
-
-static const ns_src default_dns_files[] = {
-	{ NSSRC_FILES, 	NS_SUCCESS },
-	{ NSSRC_DNS, 	NS_SUCCESS },
-	{ 0, 0 }
-};
-
-
-#ifdef DEBUG
-static void
-dprintf(const char *msg, res_state res, ...)
-{
-	assert(msg != NULL);
-
-	if (res->options & RES_DEBUG) {
-		int save = errno;
-		va_list ap;
-
-		va_start (ap, res);
-		vprintf(msg, ap);
-		va_end (ap);
-
-		errno = save;
-	}
-}
-#else
-# define dprintf(msg, res, num) ((void)0) /*nada*/
-#endif
-
-#define BOUNDED_INCR(x) \
-	do { \
-		cp += (x); \
-		if (cp > eom) { \
-			h_errno = NO_RECOVERY; \
-			return NULL; \
-		} \
-	} while (/*CONSTCOND*/0)
-
-#define BOUNDS_CHECK(ptr, count) \
-	do { \
-		if ((ptr) + (count) > eom) { \
-			h_errno = NO_RECOVERY; \
-			return NULL; \
-		} \
-	} while (/*CONSTCOND*/0)
-
-static struct hostent *
-getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
-    res_state res)
-{
-	const HEADER *hp;
-	const u_char *cp;
-	int n;
-	const u_char *eom, *erdata;
-	char *bp, **ap, **hap, *ep;
-	int type, class, ancount, qdcount;
-	int haveanswer, had_error;
-	int toobig = 0;
-	char tbuf[MAXDNAME];
-	const char *tname;
-	int (*name_ok)(const char *);
-	res_static  rs = __res_get_static();
-
-	assert(answer != NULL);
-	assert(qname != NULL);
-
-	tname = qname;
-	rs->host.h_name = NULL;
-	eom = answer->buf + anslen;
-	switch (qtype) {
-	case T_A:
-	case T_AAAA:
-		name_ok = res_hnok;
-		break;
-	case T_PTR:
-		name_ok = res_dnok;
-		break;
-	default:
-		return NULL;	/* XXX should be abort(); */
-	}
-	/*
-	 * find first satisfactory answer
-	 */
-	hp = &answer->hdr;
-	ancount = ntohs(hp->ancount);
-	qdcount = ntohs(hp->qdcount);
-	bp = rs->hostbuf;
-	ep = rs->hostbuf + sizeof rs->hostbuf;
-	cp = answer->buf;
-	BOUNDED_INCR(HFIXEDSZ);
-	if (qdcount != 1) {
-		h_errno = NO_RECOVERY;
-		return NULL;
-	}
-	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-	if ((n < 0) || !(*name_ok)(bp)) {
-		h_errno = NO_RECOVERY;
-		return NULL;
-	}
-	BOUNDED_INCR(n + QFIXEDSZ);
-	if (qtype == T_A || qtype == T_AAAA) {
-		/* res_send() has already verified that the query name is the
-		 * same as the one we sent; this just gets the expanded name
-		 * (i.e., with the succeeding search-domain tacked on).
-		 */
-		n = strlen(bp) + 1;		/* for the \0 */
-		if (n >= MAXHOSTNAMELEN) {
-			h_errno = NO_RECOVERY;
-			return NULL;
-		}
-		rs->host.h_name = bp;
-		bp += n;
-		/* The qname can be abbreviated, but h_name is now absolute. */
-		qname = rs->host.h_name;
-	}
-	ap = rs->host_aliases;
-	*ap = NULL;
-	rs->host.h_aliases = rs->host_aliases;
-	hap = rs->h_addr_ptrs;
-	*hap = NULL;
-	rs->host.h_addr_list = rs->h_addr_ptrs;
-	haveanswer = 0;
-	had_error = 0;
-	while (ancount-- > 0 && cp < eom && !had_error) {
-		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-		if ((n < 0) || !(*name_ok)(bp)) {
-			had_error++;
-			continue;
-		}
-		cp += n;			/* name */
-		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
-		type = _getshort(cp);
- 		cp += INT16SZ;			/* type */
-		class = _getshort(cp);
- 		cp += INT16SZ + INT32SZ;	/* class, TTL */
-		n = _getshort(cp);
-		cp += INT16SZ;			/* len */
-		BOUNDS_CHECK(cp, n);
-		erdata = cp + n;
-		if (class != C_IN) {
-			/* XXX - debug? syslog? */
-			cp += n;
-			continue;		/* XXX - had_error++ ? */
-		}
-		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
-			if (ap >= &rs->host_aliases[MAXALIASES-1])
-				continue;
-			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
-			if ((n < 0) || !(*name_ok)(tbuf)) {
-				had_error++;
-				continue;
-			}
-			cp += n;
-			if (cp != erdata) {
-				h_errno = NO_RECOVERY;
-				return NULL;
-			}
-			/* Store alias. */
-			*ap++ = bp;
-			n = strlen(bp) + 1;	/* for the \0 */
-			if (n >= MAXHOSTNAMELEN) {
-				had_error++;
-				continue;
-			}
-			bp += n;
-			/* Get canonical name. */
-			n = strlen(tbuf) + 1;	/* for the \0 */
-			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
-				had_error++;
-				continue;
-			}
-			strlcpy(bp, tbuf, (size_t)(ep - bp));
-			rs->host.h_name = bp;
-			bp += n;
-			continue;
-		}
-		if (qtype == T_PTR && type == T_CNAME) {
-			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
-			if (n < 0 || !res_dnok(tbuf)) {
-				had_error++;
-				continue;
-			}
-			cp += n;
-			if (cp != erdata) {
-				h_errno = NO_RECOVERY;
-				return NULL;
-			}
-			/* Get canonical name. */
-			n = strlen(tbuf) + 1;	/* for the \0 */
-			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
-				had_error++;
-				continue;
-			}
-			strlcpy(bp, tbuf, (size_t)(ep - bp));
-			tname = bp;
-			bp += n;
-			continue;
-		}
-		if (type != qtype) {
-			if (type != T_KEY && type != T_SIG)
-				syslog(LOG_NOTICE|LOG_AUTH,
-	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
-				       qname, p_class(C_IN), p_type(qtype),
-				       p_type(type));
-			cp += n;
-			continue;		/* XXX - had_error++ ? */
-		}
-		switch (type) {
-		case T_PTR:
-			if (strcasecmp(tname, bp) != 0) {
-				syslog(LOG_NOTICE|LOG_AUTH,
-				       AskedForGot, qname, bp);
-				cp += n;
-				continue;	/* XXX - had_error++ ? */
-			}
-			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-			if ((n < 0) || !res_hnok(bp)) {
-				had_error++;
-				break;
-			}
-#if MULTI_PTRS_ARE_ALIASES
-			cp += n;
-			if (cp != erdata) {
-				h_errno = NO_RECOVERY;
-				return NULL;
-			}
-			if (!haveanswer)
-				rs->host.h_name = bp;
-			else if (ap < &rs->host_aliases[MAXALIASES-1])
-				*ap++ = bp;
-			else
-				n = -1;
-			if (n != -1) {
-				n = strlen(bp) + 1;	/* for the \0 */
-				if (n >= MAXHOSTNAMELEN) {
-					had_error++;
-					break;
-				}
-				bp += n;
-			}
-			break;
-#else
-			rs->host.h_name = bp;
-			if (res->options & RES_USE_INET6) {
-				n = strlen(bp) + 1;	/* for the \0 */
-				if (n >= MAXHOSTNAMELEN) {
-					had_error++;
-					break;
-				}
-				bp += n;
-				map_v4v6_hostent(&rs->host, &bp, ep);
-			}
-			h_errno = NETDB_SUCCESS;
-			return &rs->host;
-#endif
-		case T_A:
-		case T_AAAA:
-			if (strcasecmp(rs->host.h_name, bp) != 0) {
-				syslog(LOG_NOTICE|LOG_AUTH,
-				       AskedForGot, rs->host.h_name, bp);
-				cp += n;
-				continue;	/* XXX - had_error++ ? */
-			}
-			if (n != rs->host.h_length) {
-				cp += n;
-				continue;
-			}
-			if (type == T_AAAA) {
-				struct in6_addr in6;
-				memcpy(&in6, cp, IN6ADDRSZ);
-				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
-					cp += n;
-					continue;
-				}
-			}
-			if (!haveanswer) {
-				int nn;
-
-				rs->host.h_name = bp;
-				nn = strlen(bp) + 1;	/* for the \0 */
-				bp += nn;
-			}
-
-			bp += sizeof(align) -
-			    (size_t)((u_long)bp % sizeof(align));
-
-			if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) {
-				dprintf("size (%d) too big\n", res, n);
-				had_error++;
-				continue;
-			}
-			if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) {
-				if (!toobig++)
-					dprintf("Too many addresses (%d)\n",
-						res, MAXADDRS);
-				cp += n;
-				continue;
-			}
-			(void)memcpy(*hap++ = bp, cp, (size_t)n);
-			bp += n;
-			cp += n;
-			if (cp != erdata) {
-				h_errno = NO_RECOVERY;
-				return NULL;
-			}
-			break;
-		default:
-			abort();
-		}
-		if (!had_error)
-			haveanswer++;
-	}
-	if (haveanswer) {
-		*ap = NULL;
-		*hap = NULL;
-		/*
-		 * Note: we sort even if host can take only one address
-		 * in its return structures - should give it the "best"
-		 * address in that case, not some random one
-		 */
-		if (res->nsort && haveanswer > 1 && qtype == T_A)
-			addrsort(rs->h_addr_ptrs, haveanswer, res);
-		if (!rs->host.h_name) {
-			n = strlen(qname) + 1;	/* for the \0 */
-			if (n > ep - bp || n >= MAXHOSTNAMELEN)
-				goto no_recovery;
-			strlcpy(bp, qname, (size_t)(ep - bp));
-			rs->host.h_name = bp;
-			bp += n;
-		}
-		if (res->options & RES_USE_INET6)
-			map_v4v6_hostent(&rs->host, &bp, ep);
-		h_errno = NETDB_SUCCESS;
-		return &rs->host;
-	}
- no_recovery:
-	h_errno = NO_RECOVERY;
-	return NULL;
-}
-
-int
-gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
-    struct hostent**result, int *errorp)
-{
-        struct hostent *res;
-
-        res = gethostbyname(name);
-        *errorp = h_errno;
-        if (res == NULL) {
-                *result = NULL;
-                return -1;
-        }
-        memcpy(hp, res, sizeof *hp);
-        *result = hp;
-        return 0;
-}
-
-struct hostent *
-gethostbyname(const char *name)
-{
-	struct hostent *hp;
-	res_state res = __res_get_state();
-
-	if (res == NULL)
-		return NULL;
-
-	assert(name != NULL);
-
-	/* try IPv6 first - if that fails do IPv4 */
-	if (res->options & RES_USE_INET6) {
-		hp = gethostbyname_internal(name, AF_INET6, res, NETID_UNSET, MARK_UNSET);
-		if (hp) {
-			__res_put_state(res);
-			return hp;
-		}
-	}
-	hp = gethostbyname_internal(name, AF_INET, res, NETID_UNSET, MARK_UNSET);
-	__res_put_state(res);
-	return hp;
-}
-
-struct hostent *
-gethostbyname2(const char *name, int af)
-{
-	return android_gethostbynamefornet(name, af, NETID_UNSET, MARK_UNSET);
-}
-
-struct hostent *
-android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
-{
-	struct hostent *hp;
-	res_state res = __res_get_state();
-
-	if (res == NULL)
-		return NULL;
-	hp = gethostbyname_internal(name, af, res, netid, mark);
-	__res_put_state(res);
-	return hp;
-}
-
-__LIBC_HIDDEN__ FILE* android_open_proxy() {
-	const char* cache_mode = getenv("ANDROID_DNS_MODE");
-	bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
-	if (!use_proxy) {
-		return NULL;
-	}
-
-	int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
-	if (s == -1) {
-		return NULL;
-	}
-
-	const int one = 1;
-	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-
-	struct sockaddr_un proxy_addr;
-	memset(&proxy_addr, 0, sizeof(proxy_addr));
-	proxy_addr.sun_family = AF_UNIX;
-	strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
-
-	if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
-		close(s);
-		return NULL;
-	}
-
-	return fdopen(s, "r+");
-}
-
-static struct hostent *
-android_read_hostent(FILE* proxy)
-{
-	uint32_t size;
-	char buf[4];
-	if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
-
-	// This is reading serialized data from system/netd/server/DnsProxyListener.cpp
-	// and changes here need to be matched there.
-	int result_code = strtol(buf, NULL, 10);
-	if (result_code != DnsProxyQueryResult) {
-		fread(&size, 1, sizeof(size), proxy);
-		return NULL;
-	}
-
-	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
-	size = ntohl(size);
-	res_static rs = __res_get_static();
-	memset(&rs->host, 0, sizeof(rs->host));
-	char *ptr = rs->hostbuf;
-
-	if (fread(ptr, 1, size, proxy) != size) return NULL;
-	ptr += size;
-	rs->host.h_name = rs->hostbuf;
-
-	char **aliases = rs->host_aliases;
-	rs->host.h_aliases = rs->host_aliases;
-	while (1) {
-		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
-		size = ntohl(size);
-
-		if (size == 0) {
-			*aliases = NULL;
-			break;
-		}
-		if (fread(ptr, 1, size, proxy) != size) return NULL;
-		*aliases++ = ptr;
-		ptr += size;
-	}
-
-	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
-	rs->host.h_addrtype = ntohl(size);
-
-	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
-	rs->host.h_length = ntohl(size);
-
-	char **addrs = rs->h_addr_ptrs;
-	rs->host.h_addr_list = rs->h_addr_ptrs;
-	while (1) {
-		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
-		size = ntohl(size);
-		if (size == 0) {
-			*addrs = NULL;
-			break;
-		}
-		if (fread(ptr, 1, size, proxy) != size) return NULL;
-		*addrs++ = ptr;
-		ptr += size;
-	}
-
-	return &rs->host;
-}
-
-
-static struct hostent *
-gethostbyname_internal_real(const char *name, int af, res_state res)
-{
-	const char *cp;
-	char *bp, *ep;
-	int size;
-	struct hostent *hp;
-	res_static rs = __res_get_static();
-
-	static const ns_dtab dtab[] = {
-		NS_FILES_CB(_gethtbyname, NULL)
-		{ NSSRC_DNS, _dns_gethtbyname, NULL },	/* force -DHESIOD */
-		{ 0, 0, 0 }
-	};
-
-	assert(name != NULL);
-
-	switch (af) {
-	case AF_INET:
-		size = INADDRSZ;
-		break;
-	case AF_INET6:
-		size = IN6ADDRSZ;
-		break;
-	default:
-		h_errno = NETDB_INTERNAL;
-		errno = EAFNOSUPPORT;
-		return NULL;
-	}
-
-	rs->host.h_addrtype = af;
-	rs->host.h_length = size;
-
-	/*
-	 * if there aren't any dots, it could be a user-level alias.
-	 * this is also done in res_nquery() since we are not the only
-	 * function that looks up host names.
-	 */
-	if (!strchr(name, '.') && (cp = __hostalias(name)))
-		name = cp;
-
-	/*
-	 * disallow names consisting only of digits/dots, unless
-	 * they end in a dot.
-	 */
-	if (isdigit((u_char) name[0]))
-		for (cp = name;; ++cp) {
-			if (!*cp) {
-				if (*--cp == '.')
-					break;
-				/*
-				 * All-numeric, no dot at the end.
-				 * Fake up a hostent as if we'd actually
-				 * done a lookup.
-				 */
-				if (inet_pton(af, name,
-				    (char *)(void *)rs->host_addr) <= 0) {
-					h_errno = HOST_NOT_FOUND;
-					return NULL;
-				}
-				strncpy(rs->hostbuf, name, MAXDNAME);
-				rs->hostbuf[MAXDNAME] = '\0';
-				bp = rs->hostbuf + MAXDNAME;
-				ep = rs->hostbuf + sizeof rs->hostbuf;
-				rs->host.h_name = rs->hostbuf;
-				rs->host.h_aliases = rs->host_aliases;
-				rs->host_aliases[0] = NULL;
-				rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
-				rs->h_addr_ptrs[1] = NULL;
-				rs->host.h_addr_list = rs->h_addr_ptrs;
-				if (res->options & RES_USE_INET6)
-					map_v4v6_hostent(&rs->host, &bp, ep);
-				h_errno = NETDB_SUCCESS;
-				return &rs->host;
-			}
-			if (!isdigit((u_char) *cp) && *cp != '.')
-				break;
-		}
-	if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
-	    name[0] == ':')
-		for (cp = name;; ++cp) {
-			if (!*cp) {
-				if (*--cp == '.')
-					break;
-				/*
-				 * All-IPv6-legal, no dot at the end.
-				 * Fake up a hostent as if we'd actually
-				 * done a lookup.
-				 */
-				if (inet_pton(af, name,
-				    (char *)(void *)rs->host_addr) <= 0) {
-					h_errno = HOST_NOT_FOUND;
-					return NULL;
-				}
-				strncpy(rs->hostbuf, name, MAXDNAME);
-				rs->hostbuf[MAXDNAME] = '\0';
-				bp = rs->hostbuf + MAXDNAME;
-				ep = rs->hostbuf + sizeof rs->hostbuf;
-				rs->host.h_name = rs->hostbuf;
-				rs->host.h_aliases = rs->host_aliases;
-				rs->host_aliases[0] = NULL;
-				rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
-				rs->h_addr_ptrs[1] = NULL;
-				rs->host.h_addr_list = rs->h_addr_ptrs;
-				h_errno = NETDB_SUCCESS;
-				return &rs->host;
-			}
-			if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
-				break;
-		}
-
-	hp = NULL;
-	h_errno = NETDB_INTERNAL;
-	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
-	    default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
-		return NULL;
-	}
-	h_errno = NETDB_SUCCESS;
-	return hp;
-}
-
-
-// very similar in proxy-ness to android_getaddrinfo_proxy
-static struct hostent *
-gethostbyname_internal(const char *name, int af, res_state res, unsigned netid, unsigned mark)
-{
-	FILE* proxy = android_open_proxy();
-	if (proxy == NULL) {
-		// Either we're not supposed to be using the proxy or the proxy is unavailable.
-		res_setnetid(res, netid);
-		res_setmark(res, mark);
-		return gethostbyname_internal_real(name, af, res);
-	}
-
-	netid = __netdClientDispatch.netIdForResolv(netid);
-
-	// This is writing to system/netd/server/DnsProxyListener.cpp and changes
-	// here need to be matched there.
-	if (fprintf(proxy, "gethostbyname %u %s %d",
-			netid,
-			name == NULL ? "^" : name,
-			af) < 0) {
-		fclose(proxy);
-		return NULL;
-	}
-
-	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
-		fclose(proxy);
-		return NULL;
-	}
-
-	struct hostent* result = android_read_hostent(proxy);
-	fclose(proxy);
-	return result;
-}
-
-
-static struct hostent *
-android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark) {
-	const u_char *uaddr = (const u_char *)addr;
-	socklen_t size;
-	struct hostent *hp;
-	static const ns_dtab dtab[] = {
-		NS_FILES_CB(_gethtbyaddr, NULL)
-		{ NSSRC_DNS, _dns_gethtbyaddr, NULL },	/* force -DHESIOD */
-		{ 0, 0, 0 }
-	};
-
-	assert(addr != NULL);
-
-	if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
-	    (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
-	     IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
-		h_errno = HOST_NOT_FOUND;
-		return NULL;
-	}
-	if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
-	    (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) ||
-	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) {
-		/* Unmap. */
-		uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
-		addr = uaddr;
-		af = AF_INET;
-		len = NS_INADDRSZ;
-	}
-	switch (af) {
-	case AF_INET:
-		size = NS_INADDRSZ;
-		break;
-	case AF_INET6:
-		size = NS_IN6ADDRSZ;
-		break;
-	default:
-		errno = EAFNOSUPPORT;
-		h_errno = NETDB_INTERNAL;
-		return NULL;
-	}
-	if (size != len) {
-		errno = EINVAL;
-		h_errno = NETDB_INTERNAL;
-		return NULL;
-	}
-	hp = NULL;
-	h_errno = NETDB_INTERNAL;
-	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
-		default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
-		return NULL;
-	h_errno = NETDB_SUCCESS;
-	return hp;
-}
-
-__LIBC_HIDDEN__ struct hostent*
-android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af, unsigned netid, unsigned mark) {
-	FILE* proxy = android_open_proxy();
-	if (proxy == NULL) {
-		// Either we're not supposed to be using the proxy or the proxy is unavailable.
-		return android_gethostbyaddrfornet_real(addr,len, af, netid, mark);
-	}
-
-	char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
-	const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
-	if (addrStr == NULL) {
-		fclose(proxy);
-		return NULL;
-	}
-
-	netid = __netdClientDispatch.netIdForResolv(netid);
-
-	if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
-			addrStr, len, af, netid) < 0) {
-		fclose(proxy);
-		return NULL;
-	}
-
-	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
-		fclose(proxy);
-		return NULL;
-	}
-
-	struct hostent *result = android_read_hostent(proxy);
-	fclose(proxy);
-	return result;
-}
-
-struct hostent *
-android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
-{
-	return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
-}
-
-struct hostent *
-gethostbyaddr(const void *addr, socklen_t len, int af)
-{
-	return android_gethostbyaddrfornet(addr, len, af, NETID_UNSET, MARK_UNSET);
-}
-
-
-static void
-_sethtent(int f)
-{
-    res_static  rs = __res_get_static();
-    if (rs == NULL) return;
-	if (!rs->hostf)
-		rs->hostf = fopen(_PATH_HOSTS, "re" );
-	else
-		rewind(rs->hostf);
-	rs->stayopen = f;
-}
-
-static void
-_endhtent(void)
-{
-    res_static  rs = __res_get_static();
-    if (rs == NULL) return;
-
-	if (rs->hostf && !rs->stayopen) {
-		(void) fclose(rs->hostf);
-		rs->hostf = NULL;
-	}
-}
-
-static struct hostent *
-_gethtent(void)
-{
-	char *p;
-	char *cp, **q;
-	int af, len;
-	res_static  rs = __res_get_static();
-
-	if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "re" ))) {
-		h_errno = NETDB_INTERNAL;
-		return NULL;
-	}
- again:
-	if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) {
-		h_errno = HOST_NOT_FOUND;
-		return NULL;
-	}
-	if (*p == '#')
-		goto again;
-	if (!(cp = strpbrk(p, "#\n")))
-		goto again;
-	*cp = '\0';
-	if (!(cp = strpbrk(p, " \t")))
-		goto again;
-	*cp++ = '\0';
-	if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) {
-		af = AF_INET6;
-		len = IN6ADDRSZ;
-	} else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) {
-		res_state res = __res_get_state();
-		if (res == NULL)
-			return NULL;
-		if (res->options & RES_USE_INET6) {
-			map_v4v6_address((char *)(void *)rs->host_addr,
-			    (char *)(void *)rs->host_addr);
-			af = AF_INET6;
-			len = IN6ADDRSZ;
-		} else {
-			af = AF_INET;
-			len = INADDRSZ;
-		}
-		__res_put_state(res);
-	} else {
-		goto again;
-	}
-	/* if this is not something we're looking for, skip it. */
-	if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af)
-		goto again;
-	if (rs->host.h_length != 0 && rs->host.h_length != len)
-		goto again;
-	rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
-	rs->h_addr_ptrs[1] = NULL;
-	rs->host.h_addr_list = rs->h_addr_ptrs;
-	rs->host.h_length = len;
-	rs->host.h_addrtype = af;
-	while (*cp == ' ' || *cp == '\t')
-		cp++;
-	rs->host.h_name = cp;
-	q = rs->host.h_aliases = rs->host_aliases;
-	if ((cp = strpbrk(cp, " \t")) != NULL)
-		*cp++ = '\0';
-	while (cp && *cp) {
-		if (*cp == ' ' || *cp == '\t') {
-			cp++;
-			continue;
-		}
-		if (q < &rs->host_aliases[MAXALIASES - 1])
-			*q++ = cp;
-		if ((cp = strpbrk(cp, " \t")) != NULL)
-			*cp++ = '\0';
-	}
-	*q = NULL;
-	h_errno = NETDB_SUCCESS;
-	return &rs->host;
-}
-
-/*ARGSUSED*/
-int
-_gethtbyname(void *rv, void *cb_data, va_list ap)
-{
-	struct hostent *hp;
-	const char *name;
-	int af;
-
-	assert(rv != NULL);
-
-	name = va_arg(ap, char *);
-	/* NOSTRICT skip len */(void)va_arg(ap, int);
-	af = va_arg(ap, int);
-
-	hp = NULL;
-#if 0
-	{
-		res_state res = __res_get_state();
-		if (res == NULL)
-			return NS_NOTFOUND;
-		if (res->options & RES_USE_INET6)
-			hp = _gethtbyname2(name, AF_INET6);
-		if (hp==NULL)
-			hp = _gethtbyname2(name, AF_INET);
-		__res_put_state(res);
-	}
-#else
-	hp = _gethtbyname2(name, af);
-#endif
-	*((struct hostent **)rv) = hp;
-	if (hp == NULL) {
-		h_errno = HOST_NOT_FOUND;
-		return NS_NOTFOUND;
-	}
-	return NS_SUCCESS;
-}
-
-static struct hostent *
-_gethtbyname2(const char *name, int af)
-{
-	struct hostent *p;
-	char *tmpbuf, *ptr, **cp;
-	int num;
-	size_t len;
-	res_static rs = __res_get_static();
-
-	assert(name != NULL);
-
-	_sethtent(rs->stayopen);
-	ptr = tmpbuf = NULL;
-	num = 0;
-	while ((p = _gethtent()) != NULL && num < MAXADDRS) {
-		if (p->h_addrtype != af)
-			continue;
-		if (strcasecmp(p->h_name, name) != 0) {
-			for (cp = p->h_aliases; *cp != NULL; cp++)
-				if (strcasecmp(*cp, name) == 0)
-					break;
-			if (*cp == NULL) continue;
-		}
-
-		if (num == 0) {
-			size_t bufsize;
-			char *src;
-
-			bufsize = strlen(p->h_name) + 2 +
-				  MAXADDRS * p->h_length +
-				  ALIGNBYTES;
-			for (cp = p->h_aliases; *cp != NULL; cp++)
-				bufsize += strlen(*cp) + 1;
-
-			if ((tmpbuf = malloc(bufsize)) == NULL) {
-				h_errno = NETDB_INTERNAL;
-				return NULL;
-			}
-
-			ptr = tmpbuf;
-			src = p->h_name;
-			while ((*ptr++ = *src++) != '\0');
-			for (cp = p->h_aliases; *cp != NULL; cp++) {
-				src = *cp;
-				while ((*ptr++ = *src++) != '\0');
-			}
-			*ptr++ = '\0';
-
-			ptr = (char *)(void *)ALIGN(ptr);
-		}
-
-		(void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
-		ptr += p->h_length;
-		num++;
-	}
-	_endhtent();
-	if (num == 0) return NULL;
-
-	len = ptr - tmpbuf;
-	if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) {
-		free(tmpbuf);
-		errno = ENOSPC;
-		h_errno = NETDB_INTERNAL;
-		return NULL;
-	}
-	ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len);
-	free(tmpbuf);
-
-	rs->host.h_name = ptr;
-	while (*ptr++);
-
-	cp = rs->host_aliases;
-	while (*ptr) {
-		*cp++ = ptr;
-		while (*ptr++);
-	}
-	ptr++;
-	*cp = NULL;
-
-	ptr = (char *)(void *)ALIGN(ptr);
-	cp = rs->h_addr_ptrs;
-	while (num--) {
-		*cp++ = ptr;
-		ptr += rs->host.h_length;
-	}
-	*cp = NULL;
-
-	return &rs->host;
-}
-
-/*ARGSUSED*/
-static int
-_gethtbyaddr(void *rv, void *cb_data, va_list ap)
-{
-	struct hostent *p;
-	const unsigned char *addr;
-	int len, af;
-	res_static  rs = __res_get_static();
-
-	assert(rv != NULL);
-
-	addr = va_arg(ap, unsigned char *);
-	len = va_arg(ap, int);
-	af = va_arg(ap, int);
-
-	rs->host.h_length = len;
-	rs->host.h_addrtype = af;
-
-	_sethtent(rs->stayopen);
-	while ((p = _gethtent()) != NULL)
-		if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
-		    (size_t)len))
-			break;
-	_endhtent();
-	*((struct hostent **)rv) = p;
-	if (p==NULL) {
-		h_errno = HOST_NOT_FOUND;
-		return NS_NOTFOUND;
-	}
-	return NS_SUCCESS;
-}
-
-static void
-map_v4v6_address(const char *src, char *dst)
-{
-	u_char *p = (u_char *)dst;
-	char tmp[INADDRSZ];
-	int i;
-
-	assert(src != NULL);
-	assert(dst != NULL);
-
-	/* Stash a temporary copy so our caller can update in place. */
-	(void)memcpy(tmp, src, INADDRSZ);
-	/* Mark this ipv6 addr as a mapped ipv4. */
-	for (i = 0; i < 10; i++)
-		*p++ = 0x00;
-	*p++ = 0xff;
-	*p++ = 0xff;
-	/* Retrieve the saved copy and we're done. */
-	(void)memcpy((void *)p, tmp, INADDRSZ);
-}
-
-static void
-map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
-{
-	char **ap;
-
-	assert(hp != NULL);
-	assert(bpp != NULL);
-	assert(ep != NULL);
-
-	if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
-		return;
-	hp->h_addrtype = AF_INET6;
-	hp->h_length = IN6ADDRSZ;
-	for (ap = hp->h_addr_list; *ap; ap++) {
-		int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
-
-		if (ep - *bpp < (i + IN6ADDRSZ)) {
-			/* Out of memory.  Truncate address list here.  XXX */
-			*ap = NULL;
-			return;
-		}
-		*bpp += i;
-		map_v4v6_address(*ap, *bpp);
-		*ap = *bpp;
-		*bpp += IN6ADDRSZ;
-	}
-}
-
-static void
-addrsort(char **ap, int num, res_state res)
-{
-	int i, j;
-	char **p;
-	short aval[MAXADDRS];
-	int needsort = 0;
-
-	assert(ap != NULL);
-
-	p = ap;
-	for (i = 0; i < num; i++, p++) {
-	    for (j = 0 ; (unsigned)j < res->nsort; j++)
-		if (res->sort_list[j].addr.s_addr ==
-		    (((struct in_addr *)(void *)(*p))->s_addr &
-		    res->sort_list[j].mask))
-			break;
-	    aval[i] = j;
-	    if (needsort == 0 && i > 0 && j < aval[i-1])
-		needsort = i;
-	}
-	if (!needsort)
-	    return;
-
-	while (needsort < num) {
-	    for (j = needsort - 1; j >= 0; j--) {
-		if (aval[j] > aval[j+1]) {
-		    char *hp;
-
-		    i = aval[j];
-		    aval[j] = aval[j+1];
-		    aval[j+1] = i;
-
-		    hp = ap[j];
-		    ap[j] = ap[j+1];
-		    ap[j+1] = hp;
-		} else
-		    break;
-	    }
-	    needsort++;
-	}
-}
-
-struct hostent *
-gethostent(void)
-{
-    res_static  rs = __res_get_static();
-	rs->host.h_addrtype = 0;
-	rs->host.h_length = 0;
-	return _gethtent();
-}
-
-/*ARGSUSED*/
-static int
-_dns_gethtbyname(void *rv, void *cb_data, va_list ap)
-{
-	querybuf *buf;
-	int n, type;
-	struct hostent *hp;
-	const char *name;
-	int af;
-	res_state res;
-
-	assert(rv != NULL);
-
-	name = va_arg(ap, char *);
-	/* NOSTRICT skip len */(void)va_arg(ap, int);
-	af = va_arg(ap, int);
-
-	switch (af) {
-	case AF_INET:
-		type = T_A;
-		break;
-	case AF_INET6:
-		type = T_AAAA;
-		break;
-	default:
-		return NS_UNAVAIL;
-	}
-	buf = malloc(sizeof(*buf));
-	if (buf == NULL) {
-		h_errno = NETDB_INTERNAL;
-		return NS_NOTFOUND;
-	}
-	res = __res_get_state();
-	if (res == NULL) {
-		free(buf);
-		return NS_NOTFOUND;
-	}
-	n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf));
-	if (n < 0) {
-		free(buf);
-		dprintf("res_nsearch failed (%d)\n", res, n);
-		__res_put_state(res);
-		return NS_NOTFOUND;
-	}
-	hp = getanswer(buf, n, name, type, res);
-	free(buf);
-	__res_put_state(res);
-	if (hp == NULL)
-		switch (h_errno) {
-		case HOST_NOT_FOUND:
-			return NS_NOTFOUND;
-		case TRY_AGAIN:
-			return NS_TRYAGAIN;
-		default:
-			return NS_UNAVAIL;
-		}
-	*((struct hostent **)rv) = hp;
-	return NS_SUCCESS;
-}
-
-/*ARGSUSED*/
-static int
-_dns_gethtbyaddr(void *rv, void	*cb_data, va_list ap)
-{
-	char qbuf[MAXDNAME + 1], *qp, *ep;
-	int n;
-	querybuf *buf;
-	struct hostent *hp;
-	const unsigned char *uaddr;
-	int len, af, advance;
-	res_state res;
-	unsigned netid, mark;
-	res_static rs = __res_get_static();
-
-	assert(rv != NULL);
-
-	uaddr = va_arg(ap, unsigned char *);
-	len = va_arg(ap, int);
-	af = va_arg(ap, int);
-	netid = va_arg(ap, unsigned);
-	mark = va_arg(ap, unsigned);
-
-	switch (af) {
-	case AF_INET:
-		(void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
-		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
-		    (uaddr[1] & 0xff), (uaddr[0] & 0xff));
-		break;
-
-	case AF_INET6:
-		qp = qbuf;
-		ep = qbuf + sizeof(qbuf) - 1;
-		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
-			advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
-			    uaddr[n] & 0xf,
-			    ((unsigned int)uaddr[n] >> 4) & 0xf);
-			if (advance > 0 && qp + advance < ep)
-				qp += advance;
-			else {
-				h_errno = NETDB_INTERNAL;
-				return NS_NOTFOUND;
-			}
-		}
-		if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
-			h_errno = NETDB_INTERNAL;
-			return NS_NOTFOUND;
-		}
-		break;
-	default:
-		abort();
-	}
-
-	buf = malloc(sizeof(*buf));
-	if (buf == NULL) {
-		h_errno = NETDB_INTERNAL;
-		return NS_NOTFOUND;
-	}
-	res = __res_get_state();
-	if (res == NULL) {
-		free(buf);
-		return NS_NOTFOUND;
-	}
-	res_setnetid(res, netid);
-	res_setmark(res, mark);
-	n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
-	if (n < 0) {
-		free(buf);
-		dprintf("res_nquery failed (%d)\n", res, n);
-		__res_put_state(res);
-		return NS_NOTFOUND;
-	}
-	hp = getanswer(buf, n, qbuf, T_PTR, res);
-	free(buf);
-	if (hp == NULL) {
-		__res_put_state(res);
-		switch (h_errno) {
-		case HOST_NOT_FOUND:
-			return NS_NOTFOUND;
-		case TRY_AGAIN:
-			return NS_TRYAGAIN;
-		default:
-			return NS_UNAVAIL;
-		}
-	}
-	hp->h_addrtype = af;
-	hp->h_length = len;
-	(void)memcpy(rs->host_addr, uaddr, (size_t)len);
-	rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
-	rs->h_addr_ptrs[1] = NULL;
-	if (af == AF_INET && (res->options & RES_USE_INET6)) {
-		map_v4v6_address((char *)(void *)rs->host_addr,
-		    (char *)(void *)rs->host_addr);
-		hp->h_addrtype = AF_INET6;
-		hp->h_length = IN6ADDRSZ;
-	}
-
-	__res_put_state(res);
-	*((struct hostent **)rv) = hp;
-	h_errno = NETDB_SUCCESS;
-	return NS_SUCCESS;
-}
diff --git a/libc/dns/include/hostent.h b/libc/dns/include/hostent.h
new file mode 100644
index 0000000..8b9a637
--- /dev/null
+++ b/libc/dns/include/hostent.h
@@ -0,0 +1,93 @@
+/*	$NetBSD: hostent.h,v 1.2 2013/08/27 09:56:12 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+#ifndef _DNS_NET_HOSTENT_H
+#define _DNS_NET_HOSTENT_H
+
+#include <stdio.h>
+#include <netdb.h>
+#include <stdarg.h>
+
+/*
+ * These are not being advertised because the interfaces are non-standard.
+ * There are versions by linux, aix, qnx, sun, etc. Our versions are used
+ * internally to provide thread safety; they mostly resemble qnx.
+ */
+void sethostent_r(FILE **);
+struct hostent	*netbsd_gethostent_r(FILE *, struct hostent *, char *, size_t, int *);
+void endhostent_r(FILE **);
+
+/*
+ * The following are internal API's and are used only for testing.
+ */
+struct getnamaddr {
+	struct hostent *hp;
+	char *buf;
+	size_t buflen;
+	int *he;
+};
+
+/* /etc/hosts lookup */
+int _hf_gethtbyaddr(void *, void *, va_list);
+int _hf_gethtbyname(void *, void *, va_list);
+
+#ifdef YP
+/* NIS lookup */
+int _yp_gethtbyaddr(void *, void *, va_list);
+int _yp_gethtbyname(void *, void *, va_list);
+#endif
+
+#define HENT_ARRAY(dst, anum, ptr, len) \
+	do { \
+		size_t _len = (anum + 1) * sizeof(*dst); \
+		if (_len > len) \
+			goto nospc; \
+		dst = (void *)ptr; \
+		ptr += _len; \
+		len -= _len; \
+	} while (/*CONSTCOND*/0)
+
+#define HENT_COPY(dst, src, slen, ptr, len) \
+	do { \
+		if ((size_t)slen > len) \
+			goto nospc; \
+		memcpy(ptr, src, (size_t)slen); \
+		dst = ptr; \
+		ptr += slen; \
+		len -= slen; \
+	} while (/* CONSTCOND */0)
+
+#define HENT_SCOPY(dst, src, ptr, len) \
+	do { \
+		size_t _len = strlen(src) + 1; \
+		HENT_COPY(dst, src, _len, ptr, len); \
+	} while (/* CONSTCOND */0)
+
+#endif /* _DNS_NET_HOSTENT_H */
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
new file mode 100644
index 0000000..8f5800a
--- /dev/null
+++ b/libc/dns/net/gethnamaddr.c
@@ -0,0 +1,1631 @@
+/*	$NetBSD: gethnamaddr.c,v 1.91 2014/06/19 15:08:18 christos Exp $	*/
+
+/*
+ * ++Copyright++ 1985, 1988, 1993
+ * -
+ * Copyright (c) 1985, 1988, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include "NetdClientDispatch.h"
+#include "resolv_netid.h"
+#include "resolv_private.h"
+#include "resolv_cache.h"
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <strings.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+
+#ifndef LOG_AUTH
+# define LOG_AUTH 0
+#endif
+
+#define MULTI_PTRS_ARE_ALIASES 1	/* XXX - experimental */
+
+#include "nsswitch.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "hostent.h"
+
+#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
+                               (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
+#define addalias(d, s, arr, siz) do {			\
+	if (d >= &arr[siz]) {				\
+		char **xptr = realloc(arr, (siz + 10) * sizeof(*arr)); \
+		if (xptr == NULL)			\
+			goto nospc;			\
+		d = xptr + (d - arr);			\
+		arr = xptr;				\
+		siz += 10;				\
+	}						\
+	*d++ = s;					\
+} while (/*CONSTCOND*/0)
+
+#define setup(arr, siz) do {				\
+	arr = malloc((siz = 10) * sizeof(*arr)); 	\
+	if (arr == NULL)				\
+		goto nospc;				\
+} while (/*CONSTCOND*/0)
+
+// This should be synchronized to ResponseCode.h
+static const int DnsProxyQueryResult = 222;
+
+static const char AskedForGot[] =
+			  "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+
+#define	MAXPACKET	(64*1024)
+
+typedef union {
+    HEADER hdr;
+    u_char buf[MAXPACKET];
+} querybuf;
+
+typedef union {
+    int32_t al;
+    char ac;
+} align;
+
+#ifdef DEBUG
+static void debugprintf(const char *, res_state, ...)
+	__attribute__((__format__(__printf__, 1, 3)));
+#endif
+static struct hostent *getanswer(const querybuf *, int, const char *, int,
+    res_state, struct hostent *, char *, size_t, int *);
+static void map_v4v6_address(const char *, char *);
+static void map_v4v6_hostent(struct hostent *, char **, char *);
+static void addrsort(char **, int, res_state);
+
+void ht_sethostent(int);
+void ht_endhostent(void);
+struct hostent *ht_gethostbyname(char *);
+struct hostent *ht_gethostbyaddr(const char *, int, int);
+void dns_service(void);
+#undef dn_skipname
+int dn_skipname(const u_char *, const u_char *);
+static int _dns_gethtbyaddr(void *, void *, va_list);
+static int _dns_gethtbyname(void *, void *, va_list);
+
+static struct hostent *gethostbyname_internal(const char *, int, res_state,
+    struct hostent *, char *, size_t, int *, unsigned, unsigned);
+static struct hostent* android_gethostbyaddrfornet_proxy_internal(const void*, socklen_t,
+    int, struct hostent *, char *, size_t, int *, unsigned, unsigned);
+
+static const ns_src default_dns_files[] = {
+	{ NSSRC_FILES, 	NS_SUCCESS },
+	{ NSSRC_DNS, 	NS_SUCCESS },
+	{ 0, 0 }
+};
+
+
+#ifdef DEBUG
+static void
+debugprintf(const char *msg, res_state res, ...)
+{
+	_DIAGASSERT(msg != NULL);
+
+	if (res->options & RES_DEBUG) {
+		int save = errno;
+		va_list ap;
+
+		va_start (ap, res);
+		vprintf(msg, ap);
+		va_end (ap);
+
+		errno = save;
+	}
+}
+#else
+# define debugprintf(msg, res, num) /*nada*/
+#endif
+
+#define BOUNDED_INCR(x) \
+	do { \
+		cp += (x); \
+		if (cp > eom) \
+			goto no_recovery; \
+	} while (/*CONSTCOND*/0)
+
+#define BOUNDS_CHECK(ptr, count) \
+	do { \
+		if ((ptr) + (count) > eom) \
+			goto no_recovery; \
+	} while (/*CONSTCOND*/0)
+
+static struct hostent *
+getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
+    res_state res, struct hostent *hent, char *buf, size_t buflen, int *he)
+{
+	const HEADER *hp;
+	const u_char *cp;
+	int n;
+	size_t qlen;
+	const u_char *eom, *erdata;
+	char *bp, **ap, **hap, *ep;
+	int type, class, ancount, qdcount;
+	int haveanswer, had_error;
+	int toobig = 0;
+	char tbuf[MAXDNAME];
+	char **aliases;
+	size_t maxaliases;
+	char *addr_ptrs[MAXADDRS];
+	const char *tname;
+	int (*name_ok)(const char *);
+
+	_DIAGASSERT(answer != NULL);
+	_DIAGASSERT(qname != NULL);
+
+	tname = qname;
+	hent->h_name = NULL;
+	eom = answer->buf + anslen;
+	switch (qtype) {
+	case T_A:
+	case T_AAAA:
+		name_ok = res_hnok;
+		break;
+	case T_PTR:
+		name_ok = res_dnok;
+		break;
+	default:
+	  *he = NO_RECOVERY;
+		return NULL;	/* XXX should be abort(); */
+	}
+
+	setup(aliases, maxaliases);
+	/*
+	 * find first satisfactory answer
+	 */
+	hp = &answer->hdr;
+	ancount = ntohs(hp->ancount);
+	qdcount = ntohs(hp->qdcount);
+	bp = buf;
+	ep = buf + buflen;
+	cp = answer->buf;
+	BOUNDED_INCR(HFIXEDSZ);
+	if (qdcount != 1)
+		goto no_recovery;
+
+	n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+	if ((n < 0) || !maybe_ok(res, bp, name_ok))
+		goto no_recovery;
+
+	BOUNDED_INCR(n + QFIXEDSZ);
+	if (qtype == T_A || qtype == T_AAAA) {
+		/* res_send() has already verified that the query name is the
+		 * same as the one we sent; this just gets the expanded name
+		 * (i.e., with the succeeding search-domain tacked on).
+		 */
+		n = (int)strlen(bp) + 1;		/* for the \0 */
+		if (n >= MAXHOSTNAMELEN)
+			goto no_recovery;
+		hent->h_name = bp;
+		bp += n;
+		/* The qname can be abbreviated, but h_name is now absolute. */
+		qname = hent->h_name;
+	}
+	hent->h_aliases = ap = aliases;
+	hent->h_addr_list = hap = addr_ptrs;
+	*ap = NULL;
+	*hap = NULL;
+	haveanswer = 0;
+	had_error = 0;
+	while (ancount-- > 0 && cp < eom && !had_error) {
+		n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+		if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
+			had_error++;
+			continue;
+		}
+		cp += n;			/* name */
+		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+		type = _getshort(cp);
+ 		cp += INT16SZ;			/* type */
+		class = _getshort(cp);
+ 		cp += INT16SZ + INT32SZ;	/* class, TTL */
+		n = _getshort(cp);
+		cp += INT16SZ;			/* len */
+		BOUNDS_CHECK(cp, n);
+		erdata = cp + n;
+		if (class != C_IN) {
+			/* XXX - debug? syslog? */
+			cp += n;
+			continue;		/* XXX - had_error++ ? */
+		}
+		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
+			n = dn_expand(answer->buf, eom, cp, tbuf,
+			    (int)sizeof tbuf);
+			if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) {
+				had_error++;
+				continue;
+			}
+			cp += n;
+			if (cp != erdata)
+				goto no_recovery;
+			/* Store alias. */
+			addalias(ap, bp, aliases, maxaliases);
+			n = (int)strlen(bp) + 1;	/* for the \0 */
+			if (n >= MAXHOSTNAMELEN) {
+				had_error++;
+				continue;
+			}
+			bp += n;
+			/* Get canonical name. */
+			n = (int)strlen(tbuf) + 1;	/* for the \0 */
+			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
+				had_error++;
+				continue;
+			}
+			strlcpy(bp, tbuf, (size_t)(ep - bp));
+			hent->h_name = bp;
+			bp += n;
+			continue;
+		}
+		if (qtype == T_PTR && type == T_CNAME) {
+			n = dn_expand(answer->buf, eom, cp, tbuf,
+			    (int)sizeof tbuf);
+			if (n < 0 || !maybe_dnok(res, tbuf)) {
+				had_error++;
+				continue;
+			}
+			cp += n;
+			if (cp != erdata)
+				goto no_recovery;
+			/* Get canonical name. */
+			n = (int)strlen(tbuf) + 1;	/* for the \0 */
+			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
+				had_error++;
+				continue;
+			}
+			strlcpy(bp, tbuf, (size_t)(ep - bp));
+			tname = bp;
+			bp += n;
+			continue;
+		}
+		if (type != qtype) {
+			if (type != T_KEY && type != T_SIG)
+				syslog(LOG_NOTICE|LOG_AUTH,
+	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+				       qname, p_class(C_IN), p_type(qtype),
+				       p_type(type));
+			cp += n;
+			continue;		/* XXX - had_error++ ? */
+		}
+		switch (type) {
+		case T_PTR:
+			if (strcasecmp(tname, bp) != 0) {
+				syslog(LOG_NOTICE|LOG_AUTH,
+				       AskedForGot, qname, bp);
+				cp += n;
+				continue;	/* XXX - had_error++ ? */
+			}
+			n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+			if ((n < 0) || !maybe_hnok(res, bp)) {
+				had_error++;
+				break;
+			}
+#if MULTI_PTRS_ARE_ALIASES
+			cp += n;
+			if (cp != erdata)
+				goto no_recovery;
+			if (!haveanswer)
+				hent->h_name = bp;
+			else
+				addalias(ap, bp, aliases, maxaliases);
+			if (n != -1) {
+				n = (int)strlen(bp) + 1;	/* for the \0 */
+				if (n >= MAXHOSTNAMELEN) {
+					had_error++;
+					break;
+				}
+				bp += n;
+			}
+			break;
+#else
+			hent->h_name = bp;
+			if (res->options & RES_USE_INET6) {
+				n = strlen(bp) + 1;	/* for the \0 */
+				if (n >= MAXHOSTNAMELEN) {
+					had_error++;
+					break;
+				}
+				bp += n;
+				map_v4v6_hostent(hent, &bp, ep);
+			}
+			goto success;
+#endif
+		case T_A:
+		case T_AAAA:
+			if (strcasecmp(hent->h_name, bp) != 0) {
+				syslog(LOG_NOTICE|LOG_AUTH,
+				       AskedForGot, hent->h_name, bp);
+				cp += n;
+				continue;	/* XXX - had_error++ ? */
+			}
+			if (n != hent->h_length) {
+				cp += n;
+				continue;
+			}
+			if (type == T_AAAA) {
+				struct in6_addr in6;
+				memcpy(&in6, cp, NS_IN6ADDRSZ);
+				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
+					cp += n;
+					continue;
+				}
+			}
+			if (!haveanswer) {
+				int nn;
+
+				hent->h_name = bp;
+				nn = (int)strlen(bp) + 1;	/* for the \0 */
+				bp += nn;
+			}
+
+			bp += sizeof(align) -
+			    (size_t)((u_long)bp % sizeof(align));
+
+			if (bp + n >= ep) {
+				debugprintf("size (%d) too big\n", res, n);
+				had_error++;
+				continue;
+			}
+			if (hap >= &addr_ptrs[MAXADDRS - 1]) {
+				if (!toobig++) {
+					debugprintf("Too many addresses (%d)\n",
+						res, MAXADDRS);
+				}
+				cp += n;
+				continue;
+			}
+			(void)memcpy(*hap++ = bp, cp, (size_t)n);
+			bp += n;
+			cp += n;
+			if (cp != erdata)
+				goto no_recovery;
+			break;
+		default:
+			abort();
+		}
+		if (!had_error)
+			haveanswer++;
+	}
+	if (haveanswer) {
+		*ap = NULL;
+		*hap = NULL;
+		/*
+		 * Note: we sort even if host can take only one address
+		 * in its return structures - should give it the "best"
+		 * address in that case, not some random one
+		 */
+		if (res->nsort && haveanswer > 1 && qtype == T_A)
+			addrsort(addr_ptrs, haveanswer, res);
+		if (!hent->h_name) {
+			n = (int)strlen(qname) + 1;	/* for the \0 */
+			if (n > ep - bp || n >= MAXHOSTNAMELEN)
+				goto no_recovery;
+			strlcpy(bp, qname, (size_t)(ep - bp));
+			hent->h_name = bp;
+			bp += n;
+		}
+		if (res->options & RES_USE_INET6)
+			map_v4v6_hostent(hent, &bp, ep);
+	  goto success;
+	}
+no_recovery:
+	free(aliases);
+	*he = NO_RECOVERY;
+	return NULL;
+success:
+	bp = (char *)ALIGN(bp);
+	n = (int)(ap - aliases);
+	qlen = (n + 1) * sizeof(*hent->h_aliases);
+	if ((size_t)(ep - bp) < qlen)
+		goto nospc;
+	hent->h_aliases = (void *)bp;
+	memcpy(bp, aliases, qlen);
+	free(aliases);
+	aliases = NULL;
+
+	bp += qlen;
+	n = (int)(hap - addr_ptrs);
+	qlen = (n + 1) * sizeof(*hent->h_addr_list);
+	if ((size_t)(ep - bp) < qlen)
+		goto nospc;
+	hent->h_addr_list = (void *)bp;
+	memcpy(bp, addr_ptrs, qlen);
+	*he = NETDB_SUCCESS;
+	return hent;
+nospc:
+	free(aliases);
+	errno = ENOSPC;
+	*he = NETDB_INTERNAL;
+	return NULL;
+}
+
+/* The prototype of gethostbyname_r is from glibc, not that in netbsd. */
+int
+gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
+    struct hostent **result, int *errorp)
+{
+	res_state res = __res_get_state();
+
+	if (res == NULL) {
+	  *result = NULL;
+		*errorp = NETDB_INTERNAL;
+		return -1;
+	}
+
+	_DIAGASSERT(name != NULL);
+
+	if (res->options & RES_USE_INET6) {
+		*result = gethostbyname_internal(name, AF_INET6, res, hp, buf, buflen, errorp, NETID_UNSET,
+		                                 MARK_UNSET);
+		if (*result) {
+			__res_put_state(res);
+			return 0;
+		}
+	}
+	*result = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, errorp, NETID_UNSET,
+	                                 MARK_UNSET);
+	__res_put_state(res);
+	if (!*result && errno == ENOSPC) {
+	  errno = ERANGE;
+	  return ERANGE; /* Return error as in linux manual page. */
+	}
+	return (*result) ? 0 : -1;
+}
+
+/* The prototype of gethostbyname2_r is from glibc, not that in netbsd. */
+int
+gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf,
+    size_t buflen, struct hostent **result, int *errorp)
+{
+	res_state res = __res_get_state();
+
+	if (res == NULL) {
+		*result = NULL;
+		*errorp = NETDB_INTERNAL;
+		return -1;
+	}
+	*result = gethostbyname_internal(name, af, res, hp, buf, buflen, errorp, NETID_UNSET,
+	                                 MARK_UNSET);
+	__res_put_state(res);
+	if (!*result && errno == ENOSPC) {
+		errno = ERANGE;
+		return ERANGE;
+	}
+	return (*result) ? 0 : -1;
+}
+
+__LIBC_HIDDEN__ FILE* android_open_proxy() {
+	const char* cache_mode = getenv("ANDROID_DNS_MODE");
+	bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
+	if (!use_proxy) {
+		return NULL;
+	}
+
+	int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+	if (s == -1) {
+		return NULL;
+	}
+
+	const int one = 1;
+	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+
+	struct sockaddr_un proxy_addr;
+	memset(&proxy_addr, 0, sizeof(proxy_addr));
+	proxy_addr.sun_family = AF_UNIX;
+	strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
+
+	if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
+		close(s);
+		return NULL;
+	}
+
+	return fdopen(s, "r+");
+}
+
+static struct hostent *
+android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he)
+{
+	uint32_t size;
+	char buf[4];
+	if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
+
+	// This is reading serialized data from system/netd/server/DnsProxyListener.cpp
+	// and changes here need to be matched there.
+	int result_code = strtol(buf, NULL, 10);
+	if (result_code != DnsProxyQueryResult) {
+		fread(&size, 1, sizeof(size), proxy);
+		*he = HOST_NOT_FOUND;
+		return NULL;
+	}
+
+	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+	size = ntohl(size);
+
+	memset(hp, 0, sizeof(*hp));
+	char *ptr = hbuf;
+	char *hbuf_end = hbuf + hbuflen;
+
+	if (ptr + size > hbuf_end) {
+		goto nospc;
+	}
+	if (fread(ptr, 1, size, proxy) != size) return NULL;
+	hp->h_name = ptr;
+	ptr += size;
+
+	char *aliases_ptrs[MAXALIASES];
+	char **aliases = &aliases_ptrs[0];
+
+	while (1) {
+		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+		size = ntohl(size);
+
+		if (size == 0) {
+			*aliases = NULL;
+			break;
+		}
+		if (ptr + size > hbuf_end) {
+		  goto nospc;
+		}
+		if (fread(ptr, 1, size, proxy) != size) return NULL;
+		if (aliases < &aliases_ptrs[MAXALIASES - 1]) {
+		  *aliases++ = ptr;
+		}
+		ptr += size;
+	}
+
+	int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
+	if (ptr + aliases_len > hbuf_end) {
+		goto nospc;
+	}
+	hp->h_aliases = (void*)ptr;
+	memcpy(ptr, aliases_ptrs, aliases_len);
+	ptr += aliases_len;
+
+	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+	hp->h_addrtype = ntohl(size);
+
+	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+	hp->h_length = ntohl(size);
+
+	char *addr_ptrs[MAXADDRS];
+	char **addr_p = &addr_ptrs[0];
+
+	while (1) {
+		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+		size = ntohl(size);
+		if (size == 0) {
+			*addr_p = NULL;
+			break;
+		}
+		if (ptr + size > hbuf_end) {
+		  goto nospc;
+		}
+		if (fread(ptr, 1, size, proxy) != size) return NULL;
+		if (addr_p < &addr_ptrs[MAXADDRS - 1]) {
+		  *addr_p++ = ptr;
+		}
+		ptr += size;
+	}
+
+	int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
+	if (ptr + addrs_len > hbuf_end) {
+		goto nospc;
+	}
+	hp->h_addr_list = (void*)ptr;
+	memcpy(ptr, addr_ptrs, addrs_len);
+	*he = NETDB_SUCCESS;
+	return hp;
+
+nospc:
+	*he = NETDB_INTERNAL;
+	errno = ENOSPC;
+	return NULL;
+}
+
+static struct hostent *
+gethostbyname_internal_real(const char *name, int af, res_state res, struct hostent *hp, char *buf,
+                            size_t buflen, int *he)
+{
+	const char *cp;
+	struct getnamaddr info;
+	char hbuf[MAXHOSTNAMELEN];
+	size_t size;
+	static const ns_dtab dtab[] = {
+		NS_FILES_CB(_hf_gethtbyname, NULL)
+		{ NSSRC_DNS, _dns_gethtbyname, NULL },	/* force -DHESIOD */
+		NS_NIS_CB(_yp_gethtbyname, NULL)
+		NS_NULL_CB
+	};
+
+	_DIAGASSERT(name != NULL);
+
+	switch (af) {
+	case AF_INET:
+		size = NS_INADDRSZ;
+		break;
+	case AF_INET6:
+		size = NS_IN6ADDRSZ;
+		break;
+	default:
+		*he = NETDB_INTERNAL;
+		errno = EAFNOSUPPORT;
+		return NULL;
+	}
+	if (buflen < size)
+		goto nospc;
+
+	hp->h_addrtype = af;
+	hp->h_length = (int)size;
+
+	/*
+	 * if there aren't any dots, it could be a user-level alias.
+	 * this is also done in res_nquery() since we are not the only
+	 * function that looks up host names.
+	 */
+	if (!strchr(name, '.') && (cp = res_hostalias(res, name,
+	    hbuf, sizeof(hbuf))))
+		name = cp;
+
+	/*
+	 * disallow names consisting only of digits/dots, unless
+	 * they end in a dot.
+	 */
+	if (isdigit((u_char) name[0]))
+		for (cp = name;; ++cp) {
+			if (!*cp) {
+				if (*--cp == '.')
+					break;
+				/*
+				 * All-numeric, no dot at the end.
+				 * Fake up a hostent as if we'd actually
+				 * done a lookup.
+				 */
+				goto fake;
+			}
+			if (!isdigit((u_char) *cp) && *cp != '.')
+				break;
+		}
+	if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
+	    name[0] == ':')
+		for (cp = name;; ++cp) {
+			if (!*cp) {
+				if (*--cp == '.')
+					break;
+				/*
+				 * All-IPv6-legal, no dot at the end.
+				 * Fake up a hostent as if we'd actually
+				 * done a lookup.
+				 */
+				goto fake;
+			}
+			if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
+				break;
+		}
+
+	*he = NETDB_INTERNAL;
+	info.hp = hp;
+	info.buf = buf;
+	info.buflen = buflen;
+	info.he = he;
+	if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname",
+	    default_dns_files, name, strlen(name), af) != NS_SUCCESS)
+		return NULL;
+	*he = NETDB_SUCCESS;
+	return hp;
+nospc:
+	*he = NETDB_INTERNAL;
+	errno = ENOSPC;
+	return NULL;
+fake:
+	HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
+	HENT_ARRAY(hp->h_aliases, 0, buf, buflen);
+
+	hp->h_aliases[0] = NULL;
+	if (size > buflen)
+		goto nospc;
+
+	if (inet_pton(af, name, buf) <= 0) {
+		*he = HOST_NOT_FOUND;
+		return NULL;
+	}
+	hp->h_addr_list[0] = buf;
+	hp->h_addr_list[1] = NULL;
+	buf += size;
+	buflen -= size;
+	HENT_SCOPY(hp->h_name, name, buf, buflen);
+	if (res->options & RES_USE_INET6)
+		map_v4v6_hostent(hp, &buf, buf + buflen);
+	*he = NETDB_SUCCESS;
+	return hp;
+}
+
+// very similar in proxy-ness to android_getaddrinfo_proxy
+static struct hostent *
+gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf,
+                       size_t hbuflen, int *errorp, unsigned netid, unsigned mark)
+{
+	FILE* proxy = android_open_proxy();
+	if (proxy == NULL) {
+		// Either we're not supposed to be using the proxy or the proxy is unavailable.
+		res_setnetid(res, netid);
+		res_setmark(res, mark);
+		return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
+	}
+
+	netid = __netdClientDispatch.netIdForResolv(netid);
+
+	// This is writing to system/netd/server/DnsProxyListener.cpp and changes
+	// here need to be matched there.
+	if (fprintf(proxy, "gethostbyname %u %s %d",
+			netid,
+			name == NULL ? "^" : name,
+			af) < 0) {
+		fclose(proxy);
+		return NULL;
+	}
+
+	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
+		fclose(proxy);
+		return NULL;
+	}
+
+	struct hostent* result = android_read_hostent(proxy, hp, hbuf, hbuflen, errorp);
+	fclose(proxy);
+	return result;
+}
+
+/* The prototype of gethostbyaddr_r is from glibc, not that in netbsd. */
+int gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, char *buf,
+                    size_t buflen, struct hostent **result, int *h_errnop)
+{
+	*result = android_gethostbyaddrfornet_proxy_internal(addr, len, af, hp, buf, buflen, h_errnop,
+                                                       NETID_UNSET, MARK_UNSET);
+	if (!*result && errno == ENOSPC) {
+		errno = ERANGE;
+		return ERANGE;
+	}
+	return (*result) ? 0 : -1;
+}
+
+static struct hostent *
+android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, struct hostent *hp,
+                                 char *buf, size_t buflen, int *he, unsigned netid, unsigned mark)
+{
+	const u_char *uaddr = (const u_char *)addr;
+	socklen_t size;
+	struct getnamaddr info;
+	static const ns_dtab dtab[] = {
+		NS_FILES_CB(_hf_gethtbyaddr, NULL)
+		{ NSSRC_DNS, _dns_gethtbyaddr, NULL },	/* force -DHESIOD */
+		NS_NIS_CB(_yp_gethtbyaddr, NULL)
+		NS_NULL_CB
+	};
+
+	_DIAGASSERT(addr != NULL);
+
+	if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
+	    (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
+	     IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
+		*he = HOST_NOT_FOUND;
+		return NULL;
+	}
+	if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
+	    (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) ||
+	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) {
+		/* Unmap. */
+		uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
+		addr = uaddr;
+		af = AF_INET;
+		len = NS_INADDRSZ;
+	}
+	switch (af) {
+	case AF_INET:
+		size = NS_INADDRSZ;
+		break;
+	case AF_INET6:
+		size = NS_IN6ADDRSZ;
+		break;
+	default:
+		errno = EAFNOSUPPORT;
+		*he = NETDB_INTERNAL;
+		return NULL;
+	}
+	if (size != len) {
+		errno = EINVAL;
+		*he = NETDB_INTERNAL;
+		return NULL;
+	}
+	info.hp = hp;
+	info.buf = buf;
+	info.buflen = buflen;
+	info.he = he;
+	*he = NETDB_INTERNAL;
+	if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr",
+	    default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
+		return NULL;
+	*he = NETDB_SUCCESS;
+	return hp;
+}
+
+static struct hostent*
+android_gethostbyaddrfornet_proxy_internal(const void* addr, socklen_t len, int af,
+                             struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
+                             unsigned netid, unsigned mark)
+{
+	FILE* proxy = android_open_proxy();
+	if (proxy == NULL) {
+		// Either we're not supposed to be using the proxy or the proxy is unavailable.
+		return android_gethostbyaddrfornet_real(addr,len, af, hp, hbuf, hbuflen, he, netid, mark);
+	}
+
+	char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
+	const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
+	if (addrStr == NULL) {
+		fclose(proxy);
+		return NULL;
+	}
+
+	netid = __netdClientDispatch.netIdForResolv(netid);
+
+	if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
+			addrStr, len, af, netid) < 0) {
+		fclose(proxy);
+		return NULL;
+	}
+
+	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
+		fclose(proxy);
+		return NULL;
+	}
+
+	struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he);
+	fclose(proxy);
+	return result;
+}
+
+struct hostent*
+netbsd_gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he)
+{
+	char *p, *name;
+	char *cp, **q;
+	int af, len;
+	size_t anum;
+	char **aliases;
+	size_t maxaliases;
+	struct in6_addr host_addr;
+
+	if (hf == NULL) {
+		*he = NETDB_INTERNAL;
+		errno = EINVAL;
+		return NULL;
+	}
+	p = NULL;
+	setup(aliases, maxaliases);
+
+	/* Allocate a new space to read file lines like upstream does.
+	 * To keep reentrancy we cannot use __res_get_static()->hostbuf here,
+	 * as the buffer may be used to store content for a previous hostent
+	 * returned by non-reentrant functions like gethostbyname().
+	 */
+	const size_t line_buf_size = sizeof(__res_get_static()->hostbuf);
+	if ((p = malloc(line_buf_size)) == NULL) {
+	  goto nospc;
+	}
+	for (;;) {
+		if (!fgets(p, line_buf_size, hf)) {
+			free(p);
+			free(aliases);
+			*he = HOST_NOT_FOUND;
+			return NULL;
+    		}
+		if (*p == '#') {
+			continue;
+		}
+		if (!(cp = strpbrk(p, "#\n"))) {
+			continue;
+		}
+		*cp = '\0';
+		if (!(cp = strpbrk(p, " \t")))
+			continue;
+		*cp++ = '\0';
+		if (inet_pton(AF_INET6, p, &host_addr) > 0) {
+			af = AF_INET6;
+			len = NS_IN6ADDRSZ;
+		} else {
+			if (inet_pton(AF_INET, p, &host_addr) <= 0)
+				continue;
+
+			res_state res = __res_get_state();
+			if (res == NULL)
+				goto nospc;
+			if (res->options & RES_USE_INET6) {
+				map_v4v6_address(buf, buf);
+				af = AF_INET6;
+				len = NS_IN6ADDRSZ;
+			} else {
+				af = AF_INET;
+				len = NS_INADDRSZ;
+			}
+			__res_put_state(res);
+		}
+
+		/* if this is not something we're looking for, skip it. */
+		if (hent->h_addrtype != 0 && hent->h_addrtype != af)
+			continue;
+		if (hent->h_length != 0 && hent->h_length != len)
+			continue;
+
+		while (*cp == ' ' || *cp == '\t')
+			cp++;
+		if ((cp = strpbrk(name = cp, " \t")) != NULL)
+			*cp++ = '\0';
+		q = aliases;
+		while (cp && *cp) {
+			if (*cp == ' ' || *cp == '\t') {
+				cp++;
+				continue;
+			}
+			addalias(q, cp, aliases, maxaliases);
+			if ((cp = strpbrk(cp, " \t")) != NULL)
+				*cp++ = '\0';
+		}
+		break;
+	}
+	hent->h_length = len;
+	hent->h_addrtype = af;
+	HENT_ARRAY(hent->h_addr_list, 1, buf, buflen);
+	anum = (size_t)(q - aliases);
+	HENT_ARRAY(hent->h_aliases, anum, buf, buflen);
+	HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf,
+	    buflen);
+	hent->h_addr_list[1] = NULL;
+
+	HENT_SCOPY(hent->h_name, name, buf, buflen);
+	for (size_t i = 0; i < anum; i++)
+		HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen);
+	hent->h_aliases[anum] = NULL;
+
+	*he = NETDB_SUCCESS;
+	free(p);
+	free(aliases);
+	return hent;
+nospc:
+	free(p);
+	free(aliases);
+	errno = ENOSPC;
+	*he = NETDB_INTERNAL;
+	return NULL;
+}
+
+static void
+map_v4v6_address(const char *src, char *dst)
+{
+	u_char *p = (u_char *)dst;
+	char tmp[NS_INADDRSZ];
+	int i;
+
+	_DIAGASSERT(src != NULL);
+	_DIAGASSERT(dst != NULL);
+
+	/* Stash a temporary copy so our caller can update in place. */
+	(void)memcpy(tmp, src, NS_INADDRSZ);
+	/* Mark this ipv6 addr as a mapped ipv4. */
+	for (i = 0; i < 10; i++)
+		*p++ = 0x00;
+	*p++ = 0xff;
+	*p++ = 0xff;
+	/* Retrieve the saved copy and we're done. */
+	(void)memcpy(p, tmp, NS_INADDRSZ);
+}
+
+static void
+map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
+{
+	char **ap;
+
+	_DIAGASSERT(hp != NULL);
+	_DIAGASSERT(bpp != NULL);
+	_DIAGASSERT(ep != NULL);
+
+	if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ)
+		return;
+	hp->h_addrtype = AF_INET6;
+	hp->h_length = NS_IN6ADDRSZ;
+	for (ap = hp->h_addr_list; *ap; ap++) {
+		int i = (int)(sizeof(align) -
+		    (size_t)((u_long)*bpp % sizeof(align)));
+
+		if (ep - *bpp < (i + NS_IN6ADDRSZ)) {
+			/* Out of memory.  Truncate address list here.  XXX */
+			*ap = NULL;
+			return;
+		}
+		*bpp += i;
+		map_v4v6_address(*ap, *bpp);
+		*ap = *bpp;
+		*bpp += NS_IN6ADDRSZ;
+	}
+}
+
+static void
+addrsort(char **ap, int num, res_state res)
+{
+	int i, j;
+	char **p;
+	short aval[MAXADDRS];
+	int needsort = 0;
+
+	_DIAGASSERT(ap != NULL);
+
+	p = ap;
+	for (i = 0; i < num; i++, p++) {
+	    for (j = 0 ; (unsigned)j < res->nsort; j++)
+		if (res->sort_list[j].addr.s_addr ==
+		    (((struct in_addr *)(void *)(*p))->s_addr &
+		    res->sort_list[j].mask))
+			break;
+	    aval[i] = j;
+	    if (needsort == 0 && i > 0 && j < aval[i-1])
+		needsort = i;
+	}
+	if (!needsort)
+	    return;
+
+	while (needsort < num) {
+	    for (j = needsort - 1; j >= 0; j--) {
+		if (aval[j] > aval[j+1]) {
+		    char *hp;
+
+		    i = aval[j];
+		    aval[j] = aval[j+1];
+		    aval[j+1] = i;
+
+		    hp = ap[j];
+		    ap[j] = ap[j+1];
+		    ap[j+1] = hp;
+		} else
+		    break;
+	    }
+	    needsort++;
+	}
+}
+
+/*ARGSUSED*/
+static int
+_dns_gethtbyname(void *rv, void *cb_data, va_list ap)
+{
+	querybuf *buf;
+	int n, type;
+	struct hostent *hp;
+	const char *name;
+	res_state res;
+	struct getnamaddr *info = rv;
+
+	_DIAGASSERT(rv != NULL);
+
+	name = va_arg(ap, char *);
+	/* NOSTRICT skip string len */(void)va_arg(ap, int);
+	info->hp->h_addrtype = va_arg(ap, int);
+
+	switch (info->hp->h_addrtype) {
+	case AF_INET:
+		info->hp->h_length = NS_INADDRSZ;
+		type = T_A;
+		break;
+	case AF_INET6:
+		info->hp->h_length = NS_IN6ADDRSZ;
+		type = T_AAAA;
+		break;
+	default:
+		return NS_UNAVAIL;
+	}
+	buf = malloc(sizeof(*buf));
+	if (buf == NULL) {
+		*info->he = NETDB_INTERNAL;
+		return NS_NOTFOUND;
+	}
+	res = __res_get_state();
+	if (res == NULL) {
+		free(buf);
+		return NS_NOTFOUND;
+	}
+	n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf));
+	if (n < 0) {
+		free(buf);
+		debugprintf("res_nsearch failed (%d)\n", res, n);
+		__res_put_state(res);
+		return NS_NOTFOUND;
+	}
+	hp = getanswer(buf, n, name, type, res, info->hp, info->buf,
+	    info->buflen, info->he);
+	free(buf);
+	__res_put_state(res);
+	if (hp == NULL)
+		switch (*info->he) {
+		case HOST_NOT_FOUND:
+			return NS_NOTFOUND;
+		case TRY_AGAIN:
+			return NS_TRYAGAIN;
+		default:
+			return NS_UNAVAIL;
+		}
+	return NS_SUCCESS;
+}
+
+/*ARGSUSED*/
+static int
+_dns_gethtbyaddr(void *rv, void	*cb_data, va_list ap)
+{
+	char qbuf[MAXDNAME + 1], *qp, *ep;
+	int n;
+	querybuf *buf;
+	struct hostent *hp;
+	const unsigned char *uaddr;
+	int advance;
+	res_state res;
+	char *bf;
+	size_t blen;
+	struct getnamaddr *info = rv;
+	unsigned netid, mark;
+
+	_DIAGASSERT(rv != NULL);
+
+	uaddr = va_arg(ap, unsigned char *);
+	info->hp->h_length = va_arg(ap, int);
+	info->hp->h_addrtype = va_arg(ap, int);
+	netid = va_arg(ap, unsigned);
+	mark = va_arg(ap, unsigned);
+
+	switch (info->hp->h_addrtype) {
+	case AF_INET:
+		(void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
+		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
+		    (uaddr[1] & 0xff), (uaddr[0] & 0xff));
+		break;
+
+	case AF_INET6:
+		qp = qbuf;
+		ep = qbuf + sizeof(qbuf) - 1;
+		for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) {
+			advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
+			    uaddr[n] & 0xf,
+			    ((unsigned int)uaddr[n] >> 4) & 0xf);
+			if (advance > 0 && qp + advance < ep)
+				qp += advance;
+			else {
+				*info->he = NETDB_INTERNAL;
+				return NS_NOTFOUND;
+			}
+		}
+		if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
+			*info->he = NETDB_INTERNAL;
+			return NS_NOTFOUND;
+		}
+		break;
+	default:
+		return NS_UNAVAIL;
+	}
+
+	buf = malloc(sizeof(*buf));
+	if (buf == NULL) {
+		*info->he = NETDB_INTERNAL;
+		return NS_NOTFOUND;
+	}
+	res = __res_get_state();
+	if (res == NULL) {
+		free(buf);
+		return NS_NOTFOUND;
+	}
+	res_setnetid(res, netid);
+	res_setmark(res, mark);
+	n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf));
+	if (n < 0) {
+		free(buf);
+		debugprintf("res_nquery failed (%d)\n", res, n);
+		__res_put_state(res);
+		return NS_NOTFOUND;
+	}
+	hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf,
+	    info->buflen, info->he);
+	free(buf);
+	if (hp == NULL) {
+		__res_put_state(res);
+		switch (*info->he) {
+		case HOST_NOT_FOUND:
+			return NS_NOTFOUND;
+		case TRY_AGAIN:
+			return NS_TRYAGAIN;
+		default:
+			return NS_UNAVAIL;
+		}
+	}
+
+	bf = (void *)(hp->h_addr_list + 2);
+	blen = (size_t)(bf - info->buf);
+	if (blen + info->hp->h_length > info->buflen)
+		goto nospc;
+	hp->h_addr_list[0] = bf;
+	hp->h_addr_list[1] = NULL;
+	(void)memcpy(bf, uaddr, (size_t)info->hp->h_length);
+	if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) {
+		if (blen + NS_IN6ADDRSZ > info->buflen)
+			goto nospc;
+		map_v4v6_address(bf, bf);
+		hp->h_addrtype = AF_INET6;
+		hp->h_length = NS_IN6ADDRSZ;
+	}
+
+	__res_put_state(res);
+	*info->he = NETDB_SUCCESS;
+	return NS_SUCCESS;
+nospc:
+	errno = ENOSPC;
+	*info->he = NETDB_INTERNAL;
+	return NS_UNAVAIL;
+}
+
+#ifdef YP
+/*ARGSUSED*/
+static struct hostent *
+_yp_hostent(char *line, int af, struct getnamaddr *info)
+{
+	struct in6_addr host_addrs[MAXADDRS];
+	char **aliases;
+	size_t maxaliases;
+	char *p = line;
+	char *cp, **q, *ptr;
+	size_t len, anum, i;
+	int addrok;
+	int more;
+	size_t naddrs;
+	struct hostent *hp = info->hp;
+
+	_DIAGASSERT(line != NULL);
+
+	hp->h_name = NULL;
+	hp->h_addrtype = af;
+	switch (af) {
+	case AF_INET:
+		hp->h_length = NS_INADDRSZ;
+		break;
+	case AF_INET6:
+		hp->h_length = NS_IN6ADDRSZ;
+		break;
+	default:
+		return NULL;
+	}
+	setup(aliases, maxaliases);
+	naddrs = 0;
+	q = aliases;
+
+nextline:
+	/* check for host_addrs overflow */
+	if (naddrs >= __arraycount(host_addrs))
+		goto done;
+
+	more = 0;
+	cp = strpbrk(p, " \t");
+	if (cp == NULL)
+		goto done;
+	*cp++ = '\0';
+
+	/* p has should have an address */
+	addrok = inet_pton(af, p, &host_addrs[naddrs]);
+	if (addrok != 1) {
+		/* skip to the next line */
+		while (cp && *cp) {
+			if (*cp == '\n') {
+				cp++;
+				goto nextline;
+			}
+			cp++;
+		}
+		goto done;
+	}
+	naddrs++;
+
+	while (*cp == ' ' || *cp == '\t')
+		cp++;
+	p = cp;
+	cp = strpbrk(p, " \t\n");
+	if (cp != NULL) {
+		if (*cp == '\n')
+			more = 1;
+		*cp++ = '\0';
+	}
+	if (!hp->h_name)
+		hp->h_name = p;
+	else if (strcmp(hp->h_name, p) == 0)
+		;
+	else
+		addalias(q, p, aliases, maxaliases);
+	p = cp;
+	if (more)
+		goto nextline;
+
+	while (cp && *cp) {
+		if (*cp == ' ' || *cp == '\t') {
+			cp++;
+			continue;
+		}
+		if (*cp == '\n') {
+			cp++;
+			goto nextline;
+		}
+		addalias(q, cp, aliases, maxaliases);
+		cp = strpbrk(cp, " \t");
+		if (cp != NULL)
+			*cp++ = '\0';
+	}
+
+done:
+	if (hp->h_name == NULL) {
+		free(aliases);
+		return NULL;
+	}
+
+	ptr = info->buf;
+	len = info->buflen;
+
+	anum = (size_t)(q - aliases);
+	HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len);
+	HENT_ARRAY(hp->h_aliases, anum, ptr, len);
+
+	for (i = 0; i < naddrs; i++)
+		HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length,
+		    ptr, len);
+	hp->h_addr_list[naddrs] = NULL;
+
+	HENT_SCOPY(hp->h_name, hp->h_name, ptr, len);
+
+	for (i = 0; i < anum; i++)
+		HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
+	hp->h_aliases[anum] = NULL;
+	free(aliases);
+
+	return hp;
+nospc:
+	free(aliases);
+	*info->he = NETDB_INTERNAL;
+	errno = ENOSPC;
+	return NULL;
+}
+
+/*ARGSUSED*/
+int
+_yp_gethtbyaddr(void *rv, void *cb_data, va_list ap)
+{
+	struct hostent *hp = NULL;
+	char *ypcurrent;
+	int ypcurrentlen, r;
+	char name[INET6_ADDRSTRLEN];	/* XXX enough? */
+	const unsigned char *uaddr;
+	int af;
+	const char *map;
+	struct getnamaddr *info = rv;
+
+	_DIAGASSERT(rv != NULL);
+
+	uaddr = va_arg(ap, unsigned char *);
+	/* NOSTRICT skip len */(void)va_arg(ap, int);
+	af = va_arg(ap, int);
+
+	if (!__ypdomain) {
+		if (_yp_check(&__ypdomain) == 0)
+			return NS_UNAVAIL;
+	}
+	/*
+	 * XXX unfortunately, we cannot support IPv6 extended scoped address
+	 * notation here.  gethostbyaddr() is not scope-aware.  too bad.
+	 */
+	if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL)
+		return NS_UNAVAIL;
+	switch (af) {
+	case AF_INET:
+		map = "hosts.byaddr";
+		break;
+	default:
+		map = "ipnodes.byaddr";
+		break;
+	}
+	ypcurrent = NULL;
+	r = yp_match(__ypdomain, map, name,
+		(int)strlen(name), &ypcurrent, &ypcurrentlen);
+	if (r == 0)
+		hp = _yp_hostent(ypcurrent, af, info);
+	else
+		hp = NULL;
+	free(ypcurrent);
+	if (hp == NULL) {
+		*info->he = HOST_NOT_FOUND;
+		return NS_NOTFOUND;
+	}
+	return NS_SUCCESS;
+}
+
+/*ARGSUSED*/
+int
+_yp_gethtbyname(void *rv, void *cb_data, va_list ap)
+{
+	struct hostent *hp;
+	char *ypcurrent;
+	int ypcurrentlen, r;
+	const char *name;
+	int af;
+	const char *map;
+	struct getnamaddr *info = rv;
+
+	_DIAGASSERT(rv != NULL);
+
+	name = va_arg(ap, char *);
+	/* NOSTRICT skip string len */(void)va_arg(ap, int);
+	af = va_arg(ap, int);
+
+	if (!__ypdomain) {
+		if (_yp_check(&__ypdomain) == 0)
+			return NS_UNAVAIL;
+	}
+	switch (af) {
+	case AF_INET:
+		map = "hosts.byname";
+		break;
+	default:
+		map = "ipnodes.byname";
+		break;
+	}
+	ypcurrent = NULL;
+	r = yp_match(__ypdomain, map, name,
+		(int)strlen(name), &ypcurrent, &ypcurrentlen);
+	if (r == 0)
+		hp = _yp_hostent(ypcurrent, af, info);
+	else
+		hp = NULL;
+	free(ypcurrent);
+	if (hp == NULL) {
+		*info->he = HOST_NOT_FOUND;
+		return NS_NOTFOUND;
+	}
+	return NS_SUCCESS;
+}
+#endif
+
+/*
+ * Non-reentrant versions.
+ */
+
+struct hostent *
+gethostbyname(const char *name)
+{
+	struct hostent *result = NULL;
+	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+
+	gethostbyname_r(name, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
+	return result;
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af)
+{
+	struct hostent *result = NULL;
+	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+
+	gethostbyname2_r(name, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
+	return result;
+}
+
+struct hostent *
+android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
+{
+	struct hostent *hp;
+	res_state res = __res_get_state();
+	if (res == NULL)
+		return NULL;
+	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+	hp = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf),
+	                            &h_errno, netid, mark);
+	__res_put_state(res);
+	return hp;
+}
+
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+	return android_gethostbyaddrfornet_proxy(addr, len, af, NETID_UNSET, MARK_UNSET);
+}
+
+struct hostent *
+android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
+{
+	return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
+}
+
+__LIBC_HIDDEN__ struct hostent*
+android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af,
+                                  unsigned netid, unsigned mark)
+{
+	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+	return android_gethostbyaddrfornet_proxy_internal(addr, len, af, &rs->host, rs->hostbuf,
+                                                    sizeof(rs->hostbuf), &h_errno, netid, mark);
+}
+
+struct hostent *
+gethostent(void)
+{
+  res_static  rs = __res_get_static();
+	if (!rs->hostf) {
+	  sethostent_r(&rs->hostf);
+	  if (!rs->hostf) {
+	    h_errno = NETDB_INTERNAL;
+	    return NULL;
+	  }
+	}
+	memset(&rs->host, 0, sizeof(rs->host));
+	return netbsd_gethostent_r(rs->hostf, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno);
+}
diff --git a/libc/dns/net/nsdispatch.c b/libc/dns/net/nsdispatch.c
index fb6d8f6..d025592 100644
--- a/libc/dns/net/nsdispatch.c
+++ b/libc/dns/net/nsdispatch.c
@@ -71,6 +71,7 @@
 #include <sys/cdefs.h>
 
 #include <assert.h>
+#include <errno.h>
 #include <nsswitch.h>
 #include <stdarg.h>
 #include <strings.h>
@@ -133,6 +134,10 @@
 				continue;
 			if (result & srclist[i].flags)
 				break;
+			/* Stop trying next resolver when there is a memory space fatal error. */
+			if ((result & NS_UNAVAIL) != 0 && errno == ENOSPC) {
+			  break;
+			}
 		}
 	}
 	result &= NS_STATUSMASK;	/* clear private flags in result */
diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
new file mode 100644
index 0000000..916421e
--- /dev/null
+++ b/libc/dns/net/sethostent.c
@@ -0,0 +1,275 @@
+/*	$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $	*/
+
+/*
+ * Copyright (c) 1985, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)sethostent.c	8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "Id: sethostent.c,v 8.5 1996/09/28 06:51:07 vixie Exp ";
+#else
+__RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <string.h>
+#include <nsswitch.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "hostent.h"
+#include "resolv_private.h"
+
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+
+#ifndef _REENTRANT
+void	res_close(void);
+#endif
+
+static struct hostent *_hf_gethtbyname2(const char *, int, struct getnamaddr *);
+
+static const char *_h_hosts = _PATH_HOSTS;
+
+void
+sethostent_r(FILE **hf)
+{
+	if (!*hf)
+		*hf = fopen(_h_hosts, "re");
+	else
+		rewind(*hf);
+}
+
+void
+endhostent_r(FILE **hf)
+{
+	if (*hf) {
+		(void)fclose(*hf);
+		*hf = NULL;
+	}
+}
+
+/*ARGSUSED*/
+int
+_hf_gethtbyname(void *rv, void *cb_data, va_list ap)
+{
+	struct hostent *hp;
+	const char *name;
+	int af;
+	struct getnamaddr *info = rv;
+
+	_DIAGASSERT(rv != NULL);
+
+	name = va_arg(ap, char *);
+	/* NOSTRICT skip string len */(void)va_arg(ap, int);
+	af = va_arg(ap, int);
+
+#if 0
+	{
+		res_state res = __res_get_state();
+		if (res == NULL)
+			return NS_NOTFOUND;
+		if (res->options & RES_USE_INET6)
+			hp = _hf_gethtbyname2(name, AF_INET6, info);
+		else
+			hp = NULL;
+		if (hp == NULL)
+			hp = _hf_gethtbyname2(name, AF_INET, info);
+		__res_put_state(res);
+	}
+#else
+	hp = _hf_gethtbyname2(name, af, info);
+#endif
+	if (hp == NULL) {
+		if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+			return NS_UNAVAIL;
+		}
+		return NS_NOTFOUND;
+	}
+	return NS_SUCCESS;
+}
+
+static struct hostent *
+_hf_gethtbyname2(const char *name, int af, struct getnamaddr *info)
+{
+	struct hostent *hp, hent;
+	char *buf, *ptr;
+	size_t len, anum, num, i;
+	FILE *hf;
+	char *aliases[MAXALIASES];
+	char *addr_ptrs[MAXADDRS];
+
+	_DIAGASSERT(name != NULL);
+
+	hf = NULL;
+	sethostent_r(&hf);
+	if (hf == NULL) {
+		errno = EINVAL;
+		*info->he = NETDB_INTERNAL;
+		return NULL;
+	}
+
+	if ((ptr = buf = malloc(len = info->buflen)) == NULL) {
+		endhostent_r(&hf);
+		*info->he = NETDB_INTERNAL;
+		return NULL;
+	}
+
+	anum = 0;		/* XXX: gcc */
+	hent.h_name = NULL;	/* XXX: gcc */
+	hent.h_addrtype = 0;	/* XXX: gcc */
+	hent.h_length = 0;	/* XXX: gcc */
+
+	for (num = 0; num < MAXADDRS;) {
+		info->hp->h_addrtype = af;
+		info->hp->h_length = 0;
+
+		hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
+		    info->he);
+		if (hp == NULL) {
+			if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+				goto nospc;
+			}
+			break;
+		}
+
+		if (strcasecmp(hp->h_name, name) != 0) {
+			char **cp;
+			for (cp = hp->h_aliases; *cp != NULL; cp++)
+				if (strcasecmp(*cp, name) == 0)
+					break;
+			if (*cp == NULL) continue;
+		}
+
+		if (num == 0) {
+			hent.h_addrtype = af = hp->h_addrtype;
+			hent.h_length = hp->h_length;
+
+			HENT_SCOPY(hent.h_name, hp->h_name, ptr, len);
+			for (anum = 0; hp->h_aliases[anum]; anum++) {
+				if (anum >= MAXALIASES)
+					goto nospc;
+				HENT_SCOPY(aliases[anum], hp->h_aliases[anum],
+				    ptr, len);
+			}
+			ptr = (void *)ALIGN(ptr);
+			if ((size_t)(ptr - buf) >= info->buflen)
+				goto nospc;
+		}
+
+		if (num >= MAXADDRS)
+			goto nospc;
+		HENT_COPY(addr_ptrs[num], hp->h_addr_list[0], hp->h_length, ptr,
+		    len);
+		num++;
+	}
+	endhostent_r(&hf);
+
+	if (num == 0) {
+		*info->he = HOST_NOT_FOUND;
+		free(buf);
+		return NULL;
+	}
+
+	hp = info->hp;
+	ptr = info->buf;
+	len = info->buflen;
+
+	hp->h_addrtype = hent.h_addrtype;
+	hp->h_length = hent.h_length;
+
+	HENT_ARRAY(hp->h_aliases, anum, ptr, len);
+	HENT_ARRAY(hp->h_addr_list, num, ptr, len);
+
+	for (i = 0; i < num; i++)
+		HENT_COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr,
+		    len);
+	hp->h_addr_list[num] = NULL;
+
+	HENT_SCOPY(hp->h_name, hent.h_name, ptr, len);
+
+	for (i = 0; i < anum; i++)
+		HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
+	hp->h_aliases[anum] = NULL;
+
+	free(buf);
+	return hp;
+nospc:
+	endhostent_r(&hf);
+	*info->he = NETDB_INTERNAL;
+	free(buf);
+	errno = ENOSPC;
+	return NULL;
+}
+
+/*ARGSUSED*/
+int
+_hf_gethtbyaddr(void *rv, void *cb_data, va_list ap)
+{
+	struct hostent *hp;
+	const unsigned char *addr;
+	struct getnamaddr *info = rv;
+	FILE *hf;
+
+	_DIAGASSERT(rv != NULL);
+
+	addr = va_arg(ap, unsigned char *);
+	info->hp->h_length = va_arg(ap, int);
+	info->hp->h_addrtype = va_arg(ap, int);
+
+	hf = NULL;
+	sethostent_r(&hf);
+	if (hf == NULL) {
+		*info->he = NETDB_INTERNAL;
+		return NS_UNAVAIL;
+	}
+	while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
+	    info->he)) != NULL)
+		if (!memcmp(hp->h_addr_list[0], addr, (size_t)hp->h_length))
+			break;
+	endhostent_r(&hf);
+
+	if (hp == NULL) {
+		if (errno == ENOSPC) {
+			return NS_UNAVAIL;
+		}
+		*info->he = HOST_NOT_FOUND;
+		return NS_NOTFOUND;
+	}
+	return NS_SUCCESS;
+}
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 1089788..4c4cfbd 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -33,8 +33,8 @@
 #include <sys/types.h>
 #include <linux/fadvise.h>
 #include <linux/fcntl.h>
+#include <linux/stat.h>
 #include <linux/uio.h>
-#include <unistd.h>  /* this is not required, but makes client code much happier */
 
 __BEGIN_DECLS
 
diff --git a/libc/include/net/ethernet.h b/libc/include/net/ethernet.h
index b1b88dd..47858b3 100644
--- a/libc/include/net/ethernet.h
+++ b/libc/include/net/ethernet.h
@@ -25,8 +25,11 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _NET_ETHERNET_H_
-#define _NET_IF_ETHERNET_H_
+#define _NET_ETHERNET_H_
+
 #include <linux/if_ether.h>
 #include <net/if_ether.h>
-#endif /* !_NET_ETHERNET_H_ */
+
+#endif
diff --git a/libc/include/net/if.h b/libc/include/net/if.h
index f36f37e..0efbf7f 100644
--- a/libc/include/net/if.h
+++ b/libc/include/net/if.h
@@ -26,9 +26,13 @@
  * SUCH DAMAGE.
  */
 
+#ifndef _NET_IF_H_
+#define _NET_IF_H_
+
 #include <sys/socket.h>
 #include <linux/if.h>
 #include <sys/cdefs.h>
+
 #ifndef IF_NAMESIZE
 #define IF_NAMESIZE IFNAMSIZ
 #endif
@@ -42,3 +46,5 @@
 extern char*        if_indextoname(unsigned ifindex, char *ifname);
 
 __END_DECLS
+
+#endif
diff --git a/libc/include/net/route.h b/libc/include/net/route.h
index d26bfc9..326fbe7 100644
--- a/libc/include/net/route.h
+++ b/libc/include/net/route.h
@@ -1,2 +1,37 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef _NET_ROUTE_H_
+#define _NET_ROUTE_H_
+
+#include <sys/socket.h>
 #include <linux/route.h>
+#include <linux/in6.h>
 #include <linux/ipv6_route.h>
+
+#endif
diff --git a/libc/include/netdb.h b/libc/include/netdb.h
index 527d5c1..e165376 100644
--- a/libc/include/netdb.h
+++ b/libc/include/netdb.h
@@ -209,7 +209,7 @@
 void endservent(void);
 void freehostent(struct hostent *);
 struct hostent	*gethostbyaddr(const void *, socklen_t, int);
-int gethostbyaddr_r(const void *, int, int, struct hostent *, char *, size_t, struct hostent **, int *);
+int gethostbyaddr_r(const void *, socklen_t, int, struct hostent *, char *, size_t, struct hostent **, int *);
 struct hostent	*gethostbyname(const char *);
 int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *);
 struct hostent	*gethostbyname2(const char *, int);
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 9519f6d..8988888 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -30,7 +30,6 @@
 #define _SIGNAL_H_
 
 #include <asm/sigcontext.h>
-#include <errno.h>
 #include <limits.h>
 #include <machine/pthread_types.h>
 #include <machine/timespec.h>
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 6f238a9..21d59fa 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -77,7 +77,9 @@
 #define	__GNUC_PREREQ(x, y)	0
 #endif
 
-#include <sys/cdefs_elf.h>
+#define __strong_alias(alias, sym) \
+    __asm__(".global " #alias "\n" \
+            #alias " = " #sym);
 
 #if defined(__cplusplus)
 #define	__BEGIN_DECLS		extern "C" {
@@ -263,13 +265,6 @@
 #endif
 #endif /* !(__STDC_VERSION__ >= 199901L) */
 
-#if defined(_KERNEL)
-#if defined(NO_KERNEL_RCSIDS)
-#undef __KERNEL_RCSID
-#define	__KERNEL_RCSID(_n, _s)		/* nothing */
-#endif /* NO_KERNEL_RCSIDS */
-#endif /* _KERNEL */
-
 /*
  * A barrier to stop the optimizer from moving code or assume live
  * register values. This is gcc specific, the version is more or less
diff --git a/libc/include/sys/cdefs_elf.h b/libc/include/sys/cdefs_elf.h
deleted file mode 100644
index a40a867..0000000
--- a/libc/include/sys/cdefs_elf.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*	$NetBSD: cdefs_elf.h,v 1.22 2005/02/26 22:25:34 perry Exp $	*/
-
-/*
- * Copyright (c) 1995, 1996 Carnegie-Mellon University.
- * All rights reserved.
- *
- * Author: Chris G. Demetriou
- *
- * Permission to use, copy, modify and distribute this software and
- * its documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
- * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
- *  School of Computer Science
- *  Carnegie Mellon University
- *  Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie the
- * rights to redistribute these changes.
- */
-
-#ifndef _SYS_CDEFS_ELF_H_
-#define	_SYS_CDEFS_ELF_H_
-
-#define __strong_alias(alias, sym) \
-    __asm__(".global " #alias "\n" \
-            #alias " = " #sym);
-
-/* We use __warnattr instead of __warn_references.
- * TODO: remove this and put an empty definition in one of the upstream-* compatibility headers.
- */
-#define	__warn_references(sym,msg)					\
-    /*__asm__(".section .gnu.warning." #sym "\n\t.ascii \"" msg "\"\n\t.text");*/
-
-#endif /* !_SYS_CDEFS_ELF_H_ */
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index e3f41a9..7017865 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -29,7 +29,6 @@
 #ifndef _SYS_STAT_H_
 #define _SYS_STAT_H_
 
-#include <endian.h>
 #include <linux/stat.h>
 #include <machine/timespec.h>
 #include <sys/cdefs.h>
@@ -39,15 +38,15 @@
 
 #if defined(__aarch64__)
 #define __STAT64_BODY \
-  unsigned long st_dev; \
-  unsigned long st_ino; \
-  unsigned int st_mode; \
-  unsigned int st_nlink; \
+  dev_t st_dev; \
+  ino_t st_ino; \
+  mode_t st_mode; \
+  nlink_t st_nlink; \
   uid_t st_uid; \
   gid_t st_gid; \
-  unsigned long st_rdev; \
+  dev_t st_rdev; \
   unsigned long __pad1; \
-  long st_size; \
+  off_t st_size; \
   int st_blksize; \
   int __pad2; \
   long st_blocks; \
@@ -57,13 +56,13 @@
   unsigned int __unused4; \
   unsigned int __unused5; \
 
-#elif defined(__mips__)
+#elif defined(__mips__) /* and mips64 */
 #define __STAT64_BODY \
   unsigned int st_dev; \
   unsigned int __pad0[3]; \
   unsigned long long st_ino; \
-  unsigned int st_mode; \
-  unsigned int st_nlink; \
+  mode_t st_mode; \
+  nlink_t st_nlink; \
   uid_t st_uid; \
   gid_t st_gid; \
   unsigned int st_rdev; \
@@ -78,15 +77,15 @@
 
 #elif defined(__x86_64__)
 #define __STAT64_BODY \
-  unsigned long st_dev; \
-  unsigned long st_ino; \
+  dev_t st_dev; \
+  ino_t st_ino; \
   unsigned long st_nlink; \
-  unsigned int st_mode; \
+  mode_t st_mode; \
   uid_t st_uid; \
   gid_t st_gid; \
   unsigned int __pad0; \
-  unsigned long st_rdev; \
-  long st_size; \
+  dev_t st_rdev; \
+  off_t st_size; \
   long st_blksize; \
   long st_blocks; \
   struct timespec st_atim; \
@@ -94,13 +93,13 @@
   struct timespec st_ctim; \
   long __pad3[3]; \
 
-#else
+#else /* __arm__ || __i386__ */
 #define __STAT64_BODY \
   unsigned long long st_dev; \
   unsigned char __pad0[4]; \
   unsigned long __st_ino; \
   unsigned int st_mode; \
-  unsigned int st_nlink; \
+  nlink_t st_nlink; \
   uid_t st_uid; \
   gid_t st_gid; \
   unsigned long long st_rdev; \
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 4a35166..944f957 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -85,7 +85,8 @@
  *  ttyname                libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
  *  strerror               libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
  *  strsignal              libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- *  stubs                  libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
+ *  passwd                 libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
+ *  group                  libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
  *  _res_key               libc
  * je_thread_allocated_tsd jemalloc
  * je_arenas_tsd           jemalloc
@@ -95,7 +96,7 @@
  *
  */
 
-#define LIBC_TLS_RESERVED_SLOTS 11
+#define LIBC_TLS_RESERVED_SLOTS 12
 
 #if defined(USE_JEMALLOC)
 /* jemalloc uses 5 keys for itself. */
diff --git a/libc/tools/generate-NOTICE.py b/libc/tools/generate-NOTICE.py
index 3edc299..79b4ea9 100755
--- a/libc/tools/generate-NOTICE.py
+++ b/libc/tools/generate-NOTICE.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 # Run with directory arguments from any directory, with no special setup required.
 # Or:
-# for i in libc libdl libm linker libstdc++ libthread_db ; do ./libc/tools/generate-NOTICE.py $i > $i/NOTICE ; done
+# for i in libc libdl libm linker libstdc++ ; do ./libc/tools/generate-NOTICE.py $i > $i/NOTICE ; done
 
 import ftplib
 import hashlib
diff --git a/libc/upstream-netbsd/android/include/fd_setsize.h b/libc/upstream-netbsd/android/include/fd_setsize.h
index e69de29..41bfcb7 100644
--- a/libc/upstream-netbsd/android/include/fd_setsize.h
+++ b/libc/upstream-netbsd/android/include/fd_setsize.h
@@ -0,0 +1 @@
+#include <sys/select.h>
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index 8386ba5..8783467 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -35,6 +35,9 @@
 /* Ignore all __weak_alias in OpenBSD. */
 #define __weak_alias(alias,sym)
 
+/* Ignore all __warn_references in OpenBSD. */
+#define __warn_references(sym,msg)
+
 /* OpenBSD's <ctype.h> uses these names, which conflicted with stlport.
  * Additionally, we changed the numeric/digit type from N to D for libcxx.
  */
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vfprintf.c b/libc/upstream-openbsd/lib/libc/stdio/vfprintf.c
index 7f8ff31..5f4fb7f 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vfprintf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/vfprintf.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: vfprintf.c,v 1.66 2014/05/03 12:36:45 deraadt Exp $	*/
+/*	$OpenBSD: vfprintf.c,v 1.67 2014/12/21 00:23:30 daniel Exp $	*/
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -753,10 +753,9 @@
 			if (signflag)
 				sign = '-';
 			if (expt == INT_MAX) {	/* inf or nan */
-				if (*cp == 'N') {
+				if (*cp == 'N')
 					cp = (ch >= 'a') ? "nan" : "NAN";
-					sign = '\0';
-				} else
+				else
 					cp = (ch >= 'a') ? "inf" : "INF";
  				size = 3;
 				flags &= ~ZEROPAD;
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vfwprintf.c b/libc/upstream-openbsd/lib/libc/stdio/vfwprintf.c
index ef0ca43..a6f4123 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vfwprintf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/vfwprintf.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: vfwprintf.c,v 1.11 2014/06/04 07:45:25 stsp Exp $ */
+/*	$OpenBSD: vfwprintf.c,v 1.12 2014/12/21 00:23:30 daniel Exp $ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -731,10 +731,9 @@
 			if (signflag)
 				sign = '-';
 			if (expt == INT_MAX) {	/* inf or nan */
-				if (*cp == 'N') {
+				if (*cp == 'N')
 					cp = (ch >= 'a') ? L"nan" : L"NAN";
-					sign = '\0';
-				} else
+				else
 					cp = (ch >= 'a') ? L"inf" : L"INF";
  				size = 3;
 				flags &= ~ZEROPAD;
diff --git a/libdl/Android.mk b/libdl/Android.mk
index c9fca0e..2a0724a 100644
--- a/libdl/Android.mk
+++ b/libdl/Android.mk
@@ -36,6 +36,7 @@
 LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
+LOCAL_ADDRESS_SANITIZER := false
 include $(BUILD_SHARED_LIBRARY)
 
 # A dummy libdl.a. Need for static executables using the LLVM unwinder. Most
@@ -48,4 +49,5 @@
 
 LOCAL_MODULE := libdl
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDRESS_SANITIZER := false
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libm/Android.mk b/libm/Android.mk
index d4cd7c3..cc2b8be 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -285,6 +285,7 @@
 LOCAL_SYSTEM_SHARED_LIBRARIES := libc
 
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
+LOCAL_ADDRESS_SANITIZER := false
 
 # arch-specific settings
 LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/arm
@@ -321,6 +322,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := libm
 
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
+LOCAL_ADDRESS_SANITIZER := false
 
 LOCAL_CXX_STL := none
 
diff --git a/libm/NOTICE b/libm/NOTICE
index 5be60db..70f2f46 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -549,32 +549,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2004-2011 David Schultz <das@FreeBSD.ORG>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
 Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
 All rights reserved.
 
@@ -976,6 +950,32 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2012 Stephen Montgomery-Smith <stephen@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
 Copyright (c) 2013 David Chisnall
 All rights reserved.
 
diff --git a/libm/freebsd-compat.h b/libm/freebsd-compat.h
index 1481cc2..a4dd6c2 100644
--- a/libm/freebsd-compat.h
+++ b/libm/freebsd-compat.h
@@ -26,6 +26,8 @@
 #define __strong_reference(sym,aliassym) \
     extern __typeof (sym) aliassym __attribute__ ((__alias__ (#sym)))
 
+#define __warn_references(sym,msg) /* ignored */
+
 /* digittoint is in BSD's <ctype.h>. */
 int digittoint(char ch);
 
diff --git a/linker/Android.mk b/linker/Android.mk
index d6e0095..0383e7b 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -19,6 +19,13 @@
 LOCAL_SRC_FILES_mips    := arch/mips/begin.S
 LOCAL_SRC_FILES_mips64  := arch/mips64/begin.S
 
+# GNU assembler aborted with clang's output for linker.cpp:
+# Assertion failure in get_line_subseg at
+#   /s/ndk-toolchain/src/build/../binutils/binutils-2.24/gas/dwarf2dbg.c line 271.
+ifeq ($(TARGET_ARCH),mips)
+    LOCAL_CLANG_CFLAGS += -integrated-as
+endif
+
 LOCAL_LDFLAGS := \
     -shared \
     -Wl,-Bsymbolic \
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 3409931..babefeb 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2402,6 +2402,13 @@
           *dp = &_r_debug;
         }
         break;
+      case DT_MIPS_RLD_MAP2:
+        // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
+        {
+          r_debug** dp = reinterpret_cast<r_debug**>(reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
+          *dp = &_r_debug;
+        }
+        break;
 
       case DT_MIPS_RLD_VERSION:
       case DT_MIPS_FLAGS:
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index c988d29..6fdfdc7 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -819,7 +819,7 @@
 
 TEST(dlfcn, dlsym_weak_func) {
   dlerror();
-  void* handle = dlopen("libtest_dlsym_weak_func.so",RTLD_NOW);
+  void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
   ASSERT_TRUE(handle != NULL);
 
   int (*weak_func)();
@@ -829,6 +829,18 @@
   dlclose(handle);
 }
 
+TEST(dlfcn, dlopen_undefined_weak_func) {
+  test_isolated([] {
+    void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
+    ASSERT_TRUE(handle != nullptr) << dlerror();
+    int (*weak_func)();
+    weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
+    ASSERT_TRUE(weak_func != nullptr) << dlerror();
+    EXPECT_EQ(6551, weak_func());
+    dlclose(handle);
+  });
+}
+
 TEST(dlfcn, dlopen_symlink) {
   void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
   void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index e4620f5..50d96b2 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -358,3 +358,12 @@
 
 module := libtest_dlsym_weak_func
 include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# -----------------------------------------------------------------------------
+# Library with weak undefined function
+# -----------------------------------------------------------------------------
+libtest_dlopen_weak_undefined_func_src_files := \
+    dlopen_weak_undefined.cpp
+
+module := libtest_dlopen_weak_undefined_func
+include $(LOCAL_PATH)/Android.build.testlib.mk
diff --git a/tests/libs/dlopen_weak_undefined.cpp b/tests/libs/dlopen_weak_undefined.cpp
new file mode 100644
index 0000000..599a52e
--- /dev/null
+++ b/tests/libs/dlopen_weak_undefined.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+extern "C" int __attribute__((weak)) weak_undefined_func();
+
+extern "C" int use_weak_undefined_func() {
+  if (weak_undefined_func) {
+    return weak_undefined_func();
+  } else {
+    return 6551;
+  }
+}
diff --git a/tests/netdb_test.cpp b/tests/netdb_test.cpp
index 0cebe4e..ab5b487 100644
--- a/tests/netdb_test.cpp
+++ b/tests/netdb_test.cpp
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
+#include <netdb.h>
+
 #include <gtest/gtest.h>
 
+#include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <netdb.h>
 #include <netinet/in.h>
 
 TEST(netdb, getaddrinfo_NULL_host) {
@@ -114,8 +116,7 @@
   ASSERT_EQ(EAI_FAMILY, getnameinfo(sa, too_little, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST));
 }
 
-TEST(netdb, gethostbyname) {
-  hostent* hent = gethostbyname("localhost");
+void VerifyLocalhost(hostent *hent) {
   ASSERT_TRUE(hent != NULL);
   ASSERT_EQ(hent->h_addrtype, AF_INET);
   ASSERT_EQ(hent->h_addr[0], 127);
@@ -124,6 +125,125 @@
   ASSERT_EQ(hent->h_addr[3], 1);
 }
 
+TEST(netdb, gethostbyname) {
+  hostent* hp = gethostbyname("localhost");
+  VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyname2) {
+  hostent* hp = gethostbyname2("localhost", AF_INET);
+  VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyname_r) {
+  hostent hent;
+  hostent *hp;
+  char buf[512];
+  int err;
+  int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp);
+
+  // Change hp->h_addr to test reentrancy.
+  hp->h_addr[0] = 0;
+
+  hostent hent2;
+  hostent *hp2;
+  char buf2[512];
+  result = gethostbyname_r("localhost", &hent2, buf2, sizeof(buf2), &hp2, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp2);
+
+  ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyname2_r) {
+  hostent hent;
+  hostent *hp;
+  char buf[512];
+  int err;
+  int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp);
+
+  // Change hp->h_addr to test reentrancy.
+  hp->h_addr[0] = 0;
+
+  hostent hent2;
+  hostent *hp2;
+  char buf2[512];
+  result = gethostbyname2_r("localhost", AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp2);
+
+  ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyaddr) {
+  char addr[4];
+  ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+  hostent *hp = gethostbyaddr(addr, sizeof(addr), AF_INET);
+  VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyaddr_r) {
+  char addr[4];
+  ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+
+  hostent hent;
+  hostent *hp;
+  char buf[512];
+  int err;
+  int result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp);
+
+  // Change hp->h_addr to test reentrancy.
+  hp->h_addr[0] = 0;
+
+  hostent hent2;
+  hostent *hp2;
+  char buf2[512];
+  result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp2);
+
+  ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyname_r_ERANGE) {
+  hostent hent;
+  hostent *hp;
+  char buf[4]; // Use too small buffer.
+  int err;
+  int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(ERANGE, result);
+  ASSERT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyname2_r_ERANGE) {
+  hostent hent;
+  hostent *hp;
+  char buf[4]; // Use too small buffer.
+  int err;
+  int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(ERANGE, result);
+  ASSERT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyaddr_r_ERANGE) {
+  char addr[4];
+  ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+
+  hostent hent;
+  hostent *hp;
+  char buf[4]; // Use too small buffer.
+  int err;
+  int result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(ERANGE, result);
+  ASSERT_EQ(NULL, hp);
+}
+
 TEST(netdb, getservbyname) {
   // smtp is TCP-only, so we know we'll get 25/tcp back.
   servent* s = getservbyname("smtp", NULL);
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 4fc5bed..1418c76 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -644,8 +644,7 @@
   ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size));
   ASSERT_EQ(32*1024U + 1, stack_size);
 #if defined(__BIONIC__)
-  // Bionic rounds up, which is what POSIX allows.
-  ASSERT_EQ(GetActualStackSize(attributes), (32 + 4)*1024U);
+  ASSERT_EQ(GetActualStackSize(attributes), 32*1024U + 1);
 #else // __BIONIC__
   // glibc rounds down, in violation of POSIX. They document this in their BUGS section.
   ASSERT_EQ(GetActualStackSize(attributes), 32*1024U);
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 854fc7b..de5eea3 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -364,22 +364,52 @@
   EXPECT_STREQ("print_me_twice print_me_twice", buf);
 }
 
-TEST(stdio, snprintf_f_special) {
-  char buf[BUFSIZ];
-  snprintf(buf, sizeof(buf), "%f", nanf(""));
-  EXPECT_STRCASEEQ("NaN", buf);
+template <typename T>
+void CheckInfNan(int snprintf_fn(T*, size_t, const T*, ...),
+                 const T* fmt, const T* fmt_plus,
+                 const T* minus_inf, const T* inf_, const T* plus_inf,
+                 const T* minus_nan, const T* nan_, const T* plus_nan) {
+  T buf[BUFSIZ];
 
-  snprintf(buf, sizeof(buf), "%f", HUGE_VALF);
-  EXPECT_STRCASEEQ("Inf", buf);
+  snprintf_fn(buf, sizeof(buf), fmt, nan(""));
+  EXPECT_STREQ(nan_, buf) << fmt;
+  snprintf_fn(buf, sizeof(buf), fmt, -nan(""));
+  EXPECT_STREQ(minus_nan, buf) << fmt;
+  snprintf_fn(buf, sizeof(buf), fmt_plus, nan(""));
+  EXPECT_STREQ(plus_nan, buf) << fmt_plus;
+  snprintf_fn(buf, sizeof(buf), fmt_plus, -nan(""));
+  EXPECT_STREQ(minus_nan, buf) << fmt_plus;
+
+  snprintf_fn(buf, sizeof(buf), fmt, HUGE_VAL);
+  EXPECT_STREQ(inf_, buf) << fmt;
+  snprintf_fn(buf, sizeof(buf), fmt, -HUGE_VAL);
+  EXPECT_STREQ(minus_inf, buf) << fmt;
+  snprintf_fn(buf, sizeof(buf), fmt_plus, HUGE_VAL);
+  EXPECT_STREQ(plus_inf, buf) << fmt_plus;
+  snprintf_fn(buf, sizeof(buf), fmt_plus, -HUGE_VAL);
+  EXPECT_STREQ(minus_inf, buf) << fmt_plus;
 }
 
-TEST(stdio, snprintf_g_special) {
-  char buf[BUFSIZ];
-  snprintf(buf, sizeof(buf), "%g", nan(""));
-  EXPECT_STRCASEEQ("NaN", buf);
+TEST(stdio, snprintf_inf_nan) {
+  CheckInfNan(snprintf, "%a", "%+a", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
+  CheckInfNan(snprintf, "%A", "%+A", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+  CheckInfNan(snprintf, "%e", "%+e", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
+  CheckInfNan(snprintf, "%E", "%+E", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+  CheckInfNan(snprintf, "%f", "%+f", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
+  CheckInfNan(snprintf, "%F", "%+F", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+  CheckInfNan(snprintf, "%g", "%+g", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
+  CheckInfNan(snprintf, "%G", "%+G", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+}
 
-  snprintf(buf, sizeof(buf), "%g", HUGE_VAL);
-  EXPECT_STRCASEEQ("Inf", buf);
+TEST(stdio, wsprintf_inf_nan) {
+  CheckInfNan(swprintf, L"%a", L"%+a", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
+  CheckInfNan(swprintf, L"%A", L"%+A", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
+  CheckInfNan(swprintf, L"%e", L"%+e", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
+  CheckInfNan(swprintf, L"%E", L"%+E", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
+  CheckInfNan(swprintf, L"%f", L"%+f", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
+  CheckInfNan(swprintf, L"%F", L"%+F", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
+  CheckInfNan(swprintf, L"%g", L"%+g", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
+  CheckInfNan(swprintf, L"%G", L"%+G", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
 }
 
 TEST(stdio, snprintf_d_INT_MAX) {
@@ -439,8 +469,22 @@
 TEST(stdio, snprintf_negative_zero_5084292) {
   char buf[BUFSIZ];
 
+  snprintf(buf, sizeof(buf), "%e", -0.0);
+  EXPECT_STREQ("-0.000000e+00", buf);
+  snprintf(buf, sizeof(buf), "%E", -0.0);
+  EXPECT_STREQ("-0.000000E+00", buf);
   snprintf(buf, sizeof(buf), "%f", -0.0);
   EXPECT_STREQ("-0.000000", buf);
+  snprintf(buf, sizeof(buf), "%F", -0.0);
+  EXPECT_STREQ("-0.000000", buf);
+  snprintf(buf, sizeof(buf), "%g", -0.0);
+  EXPECT_STREQ("-0", buf);
+  snprintf(buf, sizeof(buf), "%G", -0.0);
+  EXPECT_STREQ("-0", buf);
+  snprintf(buf, sizeof(buf), "%a", -0.0);
+  EXPECT_STREQ("-0x0p+0", buf);
+  snprintf(buf, sizeof(buf), "%A", -0.0);
+  EXPECT_STREQ("-0X0P+0", buf);
 }
 
 TEST(stdio, snprintf_utf8_15439554) {