Merge "make mmap fail on requests larger than PTRDIFF_MAX"
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/README.md b/README.md
index 72b7124..37d3f62 100644
--- a/README.md
+++ b/README.md
@@ -257,6 +257,17 @@
 The coverage report is now available at `covreport/index.html`.
 
 
+Attaching GDB to the tests
+--------------------------
+
+Bionic's test runner will run each test in its own process by default to prevent
+tests failures from impacting other tests. This also has the added benefit of
+running them in parallel, so they are much faster.
+
+However, this also makes it difficult to run the tests under GDB. To prevent
+each test from being forked, run the tests with the flag `--no-isolate`.
+
+
 LP32 ABI bugs
 -------------
 
diff --git a/libc/Android.bp b/libc/Android.bp
new file mode 100644
index 0000000..2429634
--- /dev/null
+++ b/libc/Android.bp
@@ -0,0 +1,2307 @@
+bionic_coverage = false
+
+// Define the common source files for all the libc instances
+// =========================================================
+libc_common_src_files = [
+    "bionic/bindresvport.c",
+    "bionic/ether_aton.c",
+    "bionic/ether_ntoa.c",
+    "bionic/fts.c",
+    "bionic/getpriority.c",
+    "bionic/if_indextoname.c",
+    "bionic/if_nametoindex.c",
+    "bionic/initgroups.c",
+    "bionic/ioctl.c",
+    "bionic/isatty.c",
+    "bionic/memmem.c",
+    "bionic/pututline.c",
+    "bionic/sched_cpualloc.c",
+    "bionic/sched_cpucount.c",
+    "bionic/sigblock.c",
+    "bionic/siginterrupt.c",
+    "bionic/sigsetmask.c",
+    "bionic/system_properties_compat.c",
+    "stdio/findfp.c",
+    "stdio/fread.c",
+    "stdio/snprintf.c",
+    "stdio/sprintf.c",
+    "stdio/stdio.c",
+    "stdio/stdio_ext.cpp",
+    "stdlib/atexit.c",
+    "stdlib/exit.c",
+
+    // Fortify implementations of libc functions.
+    "bionic/__FD_chk.cpp",
+    "bionic/__fgets_chk.cpp",
+    "bionic/__fread_chk.cpp",
+    "bionic/__fwrite_chk.cpp",
+    "bionic/__getcwd_chk.cpp",
+    "bionic/__memchr_chk.cpp",
+    "bionic/__memmove_chk.cpp",
+    "bionic/__memrchr_chk.cpp",
+    "bionic/__poll_chk.cpp",
+    "bionic/__pread64_chk.cpp",
+    "bionic/__pread_chk.cpp",
+    "bionic/__pwrite64_chk.cpp",
+    "bionic/__pwrite_chk.cpp",
+    "bionic/__read_chk.cpp",
+    "bionic/__readlink_chk.cpp",
+    "bionic/__readlinkat_chk.cpp",
+    "bionic/__recvfrom_chk.cpp",
+    "bionic/__stpcpy_chk.cpp",
+    "bionic/__stpncpy_chk.cpp",
+    "bionic/__strchr_chk.cpp",
+    "bionic/__strlcat_chk.cpp",
+    "bionic/__strlcpy_chk.cpp",
+    "bionic/__strlen_chk.cpp",
+    "bionic/__strncat_chk.cpp",
+    "bionic/__strncpy_chk.cpp",
+    "bionic/__strrchr_chk.cpp",
+    "bionic/__umask_chk.cpp",
+    "bionic/__vsnprintf_chk.cpp",
+    "bionic/__vsprintf_chk.cpp",
+    "bionic/__write_chk.cpp",
+]
+
+// Various kinds of cruft.
+// ========================================================
+libc_common_src_files += [
+    "bionic/ndk_cruft.cpp",
+]
+
+libc_common_src_files_32 = [
+    "bionic/legacy_32_bit_support.cpp",
+    "bionic/time64.c",
+]
+
+// Define some common cflags
+// ========================================================
+libc_common_cflags = [
+    "-D_LIBC=1",
+    "-Wall",
+    "-Wextra",
+    "-Wunused",
+
+// Try to catch typical 32-bit assumptions that break with 64-bit pointers.
+    "-Werror=pointer-to-int-cast",
+    "-Werror=int-to-pointer-cast",
+    "-Werror=type-limits",
+    "-Werror",
+]
+
+libc_common_product_variables = {
+    device_uses_jemalloc: {
+        cflags: ["-DUSE_JEMALLOC"],
+        include_dirs: ["external/jemalloc/include"],
+    },
+    device_uses_dlmalloc: {
+        cflags: ["-DUSE_DLMALLOC"],
+    },
+    // To customize dlmalloc's alignment, set BOARD_MALLOC_ALIGNMENT in
+    // the appropriate BoardConfig.mk file.
+    dlmalloc_alignment: {
+        cflags: ["-DMALLOC_ALIGNMENT=%d"],
+    },
+}
+
+// Clang/llvm has incompatible long double (fp128) for x86_64.
+// https://llvm.org/bugs/show_bug.cgi?id=23897
+use_clang_x86_64 = false
+
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// ifeq ($(strip $(DEBUG_BIONIC_LIBC)),true)
+//libc_common_cflags += ["-DDEBUG"]
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// endif
+
+//
+// Define some common conlyflags
+libc_common_conlyflags = ["-std=gnu99"]
+
+// Define some common cppflags
+libc_common_cppflags = []
+
+// ========================================================
+// libc_stack_protector.a - stack protector code
+// ========================================================
+//
+// The stack protector code needs to be compiled
+// with -fno-stack-protector, since it modifies the
+// stack canary.
+
+cc_library_static {
+
+    srcs: ["bionic/__stack_chk_fail.cpp"],
+    cflags: libc_common_cflags + ["-fno-stack-protector"],
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    name: "libc_stack_protector",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+
+}
+
+// ========================================================
+// libc_tzcode.a - upstream 'tzcode' code
+// ========================================================
+
+cc_library_static {
+
+    srcs: [
+        "tzcode/asctime.c",
+        "tzcode/difftime.c",
+        "tzcode/localtime.c",
+        "tzcode/strftime.c",
+        "tzcode/strptime.c",
+        "upstream-openbsd/lib/libc/time/wcsftime.c", // tzcode doesn't include wcsftime, so we use the OpenBSD one.
+    ],
+
+    cflags: libc_common_cflags + [
+        "-fvisibility=hidden",
+        // Don't use ridiculous amounts of stack.
+        "-DALL_STATE",
+        // Include tzsetwall, timelocal, timegm, time2posix, and posix2time.
+        "-DSTD_INSPIRED",
+        // The name of the tm_gmtoff field in our struct tm.
+        "-DTM_GMTOFF=tm_gmtoff",
+        // Where we store our tzdata.
+        "-DTZDIR=\\\"/system/usr/share/zoneinfo\\\"",
+        // Include timezone and daylight globals.
+        "-DUSG_COMPAT=1",
+        "-DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU",
+        "-Dlint",
+    ],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    local_include_dirs: ["tzcode/"],
+    name: "libc_tzcode",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+}
+
+// ========================================================
+// libc_dns.a - modified NetBSD DNS code
+// ========================================================
+
+cc_library_static {
+
+    srcs: [
+        "dns/net/gethnamaddr.c",
+        "dns/net/getservbyname.c",
+        "dns/net/getservbyport.c",
+        "dns/net/getaddrinfo.c",
+        "dns/net/getnameinfo.c",
+        "dns/net/sethostent.c",
+        "dns/net/getservent.c",
+        "dns/net/nsdispatch.c",
+        "dns/net/base64.c",
+        "dns/resolv/res_state.c",
+        "dns/resolv/res_init.c",
+        "dns/resolv/res_mkquery.c",
+        "dns/resolv/res_data.c",
+        "dns/resolv/res_debug.c",
+        "dns/resolv/herror.c",
+        "dns/resolv/res_cache.c",
+        "dns/resolv/res_query.c",
+        "dns/resolv/res_comp.c",
+        "dns/resolv/res_send.c",
+        "dns/nameser/ns_name.c",
+        "dns/nameser/ns_print.c",
+        "dns/nameser/ns_parse.c",
+        "dns/nameser/ns_ttl.c",
+        "dns/nameser/ns_netint.c",
+        "dns/nameser/ns_samedomain.c",
+
+        "upstream-netbsd/lib/libc/isc/ev_streams.c",
+        "upstream-netbsd/lib/libc/isc/ev_timers.c",
+        "upstream-netbsd/lib/libc/resolv/mtctxres.c",
+        // We use the OpenBSD res_random.
+        "upstream-openbsd/lib/libc/net/res_random.c",
+    ],
+
+    cflags: ["-Dres_randomid=__res_randomid"] +
+    libc_common_cflags + [
+        "-DANDROID_CHANGES",
+        "-DINET6",
+        "-fvisibility=hidden",
+        "-Wno-unused-parameter",
+        "-include netbsd-compat.h",
+    ],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    local_include_dirs: [
+        "dns/include",
+        "private",
+        "upstream-netbsd/lib/libc/include",
+        "upstream-netbsd/android/include",
+    ],
+
+    name: "libc_dns",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+}
+
+// ========================================================
+// libc_freebsd.a - upstream FreeBSD C library code
+// ========================================================
+//
+// These files are built with the freebsd-compat.h header file
+// automatically included.
+
+cc_library_static {
+    srcs: [
+        "upstream-freebsd/lib/libc/gen/ldexp.c",
+        "upstream-freebsd/lib/libc/gen/sleep.c",
+        "upstream-freebsd/lib/libc/gen/usleep.c",
+        "upstream-freebsd/lib/libc/stdlib/getopt_long.c",
+        "upstream-freebsd/lib/libc/stdlib/qsort.c",
+        "upstream-freebsd/lib/libc/stdlib/quick_exit.c",
+        "upstream-freebsd/lib/libc/stdlib/realpath.c",
+        "upstream-freebsd/lib/libc/string/wcpcpy.c",
+        "upstream-freebsd/lib/libc/string/wcpncpy.c",
+        "upstream-freebsd/lib/libc/string/wcscasecmp.c",
+        "upstream-freebsd/lib/libc/string/wcscspn.c",
+        "upstream-freebsd/lib/libc/string/wcsdup.c",
+        "upstream-freebsd/lib/libc/string/wcslcat.c",
+        "upstream-freebsd/lib/libc/string/wcsncasecmp.c",
+        "upstream-freebsd/lib/libc/string/wcsncat.c",
+        "upstream-freebsd/lib/libc/string/wcsncmp.c",
+        "upstream-freebsd/lib/libc/string/wcsncpy.c",
+        "upstream-freebsd/lib/libc/string/wcsnlen.c",
+        "upstream-freebsd/lib/libc/string/wcspbrk.c",
+        "upstream-freebsd/lib/libc/string/wcsspn.c",
+        "upstream-freebsd/lib/libc/string/wcstok.c",
+        "upstream-freebsd/lib/libc/string/wmemchr.c",
+        "upstream-freebsd/lib/libc/string/wmemset.c",
+
+        // May be overriden by per-arch optimized versions
+        "upstream-freebsd/lib/libc/string/wcscat.c",
+        "upstream-freebsd/lib/libc/string/wcschr.c",
+        "upstream-freebsd/lib/libc/string/wcscmp.c",
+        "upstream-freebsd/lib/libc/string/wcscpy.c",
+        "upstream-freebsd/lib/libc/string/wcslen.c",
+        "upstream-freebsd/lib/libc/string/wcsrchr.c",
+        "upstream-freebsd/lib/libc/string/wmemcmp.c",
+        "upstream-freebsd/lib/libc/string/wmemmove.c",
+    ],
+    arch: {
+        arm64: {
+            exclude_srcs: [
+                "upstream-freebsd/lib/libc/string/wmemmove.c",
+            ],
+        },
+        x86: {
+            exclude_srcs: [
+                "upstream-freebsd/lib/libc/string/wcschr.c",
+                "upstream-freebsd/lib/libc/string/wcscmp.c",
+                "upstream-freebsd/lib/libc/string/wcslen.c",
+                "upstream-freebsd/lib/libc/string/wcsrchr.c",
+            ],
+        },
+        x86_sse3: {
+            exclude_srcs: [
+                "upstream-freebsd/lib/libc/string/wcscpy.c",
+                "upstream-freebsd/lib/libc/string/wcscat.c",
+            ],
+        },
+        x86_sse4: {
+            exclude_srcs: [
+                "upstream-freebsd/lib/libc/string/wmemcmp.c",
+            ],
+        },
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+
+    cflags: libc_common_cflags + [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-include freebsd-compat.h",
+    ],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    local_include_dirs: [
+        "upstream-freebsd/android/include",
+    ],
+
+    name: "libc_freebsd",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+}
+
+// ========================================================
+// libc_netbsd.a - upstream NetBSD C library code
+// ========================================================
+//
+// These files are built with the netbsd-compat.h header file
+// automatically included.
+
+cc_library_static {
+
+    srcs: [
+        "upstream-netbsd/common/lib/libc/stdlib/random.c",
+        "upstream-netbsd/lib/libc/gen/ftw.c",
+        "upstream-netbsd/lib/libc/gen/nftw.c",
+        "upstream-netbsd/lib/libc/gen/nice.c",
+        "upstream-netbsd/lib/libc/gen/popen.c",
+        "upstream-netbsd/lib/libc/gen/psignal.c",
+        "upstream-netbsd/lib/libc/gen/utime.c",
+        "upstream-netbsd/lib/libc/gen/utmp.c",
+        "upstream-netbsd/lib/libc/inet/nsap_addr.c",
+        "upstream-netbsd/lib/libc/regex/regcomp.c",
+        "upstream-netbsd/lib/libc/regex/regerror.c",
+        "upstream-netbsd/lib/libc/regex/regexec.c",
+        "upstream-netbsd/lib/libc/regex/regfree.c",
+        "upstream-netbsd/lib/libc/stdlib/bsearch.c",
+        "upstream-netbsd/lib/libc/stdlib/div.c",
+        "upstream-netbsd/lib/libc/stdlib/drand48.c",
+        "upstream-netbsd/lib/libc/stdlib/erand48.c",
+        "upstream-netbsd/lib/libc/stdlib/jrand48.c",
+        "upstream-netbsd/lib/libc/stdlib/lcong48.c",
+        "upstream-netbsd/lib/libc/stdlib/ldiv.c",
+        "upstream-netbsd/lib/libc/stdlib/lldiv.c",
+        "upstream-netbsd/lib/libc/stdlib/lrand48.c",
+        "upstream-netbsd/lib/libc/stdlib/mrand48.c",
+        "upstream-netbsd/lib/libc/stdlib/nrand48.c",
+        "upstream-netbsd/lib/libc/stdlib/_rand48.c",
+        "upstream-netbsd/lib/libc/stdlib/rand_r.c",
+        "upstream-netbsd/lib/libc/stdlib/reallocarr.c",
+        "upstream-netbsd/lib/libc/stdlib/seed48.c",
+        "upstream-netbsd/lib/libc/stdlib/srand48.c",
+        "upstream-netbsd/lib/libc/string/memccpy.c",
+        "upstream-netbsd/lib/libc/string/strcasestr.c",
+        "upstream-netbsd/lib/libc/string/strcoll.c",
+        "upstream-netbsd/lib/libc/string/strxfrm.c",
+    ],
+    multilib: {
+        lib32: {
+            // LP32 cruft
+            srcs: ["upstream-netbsd/common/lib/libc/hash/sha1/sha1.c"],
+        },
+    },
+    cflags: libc_common_cflags + [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-DPOSIX_MISTAKE",
+        "-include netbsd-compat.h",
+    ],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    local_include_dirs: [
+        "upstream-netbsd/android/include",
+        "upstream-netbsd/lib/libc/include",
+    ],
+
+    name: "libc_netbsd",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+}
+
+// ========================================================
+// libc_openbsd_ndk.a - upstream OpenBSD C library code
+// that can be safely included in the libc_ndk.a (doesn't
+// contain any troublesome global data or constructors).
+// ========================================================
+//
+// These files are built with the openbsd-compat.h header file
+// automatically included.
+
+cc_library_static {
+    name: "libc_openbsd_ndk",
+    srcs: [
+        "upstream-openbsd/lib/libc/compat-43/killpg.c",
+        "upstream-openbsd/lib/libc/gen/alarm.c",
+        "upstream-openbsd/lib/libc/gen/ctype_.c",
+        "upstream-openbsd/lib/libc/gen/daemon.c",
+        "upstream-openbsd/lib/libc/gen/err.c",
+        "upstream-openbsd/lib/libc/gen/errx.c",
+        "upstream-openbsd/lib/libc/gen/exec.c",
+        "upstream-openbsd/lib/libc/gen/fnmatch.c",
+        "upstream-openbsd/lib/libc/gen/ftok.c",
+        "upstream-openbsd/lib/libc/gen/getprogname.c",
+        "upstream-openbsd/lib/libc/gen/isctype.c",
+        "upstream-openbsd/lib/libc/gen/setprogname.c",
+        "upstream-openbsd/lib/libc/gen/time.c",
+        "upstream-openbsd/lib/libc/gen/tolower_.c",
+        "upstream-openbsd/lib/libc/gen/toupper_.c",
+        "upstream-openbsd/lib/libc/gen/verr.c",
+        "upstream-openbsd/lib/libc/gen/verrx.c",
+        "upstream-openbsd/lib/libc/gen/vwarn.c",
+        "upstream-openbsd/lib/libc/gen/vwarnx.c",
+        "upstream-openbsd/lib/libc/gen/warn.c",
+        "upstream-openbsd/lib/libc/gen/warnx.c",
+        "upstream-openbsd/lib/libc/locale/btowc.c",
+        "upstream-openbsd/lib/libc/locale/mbrlen.c",
+        "upstream-openbsd/lib/libc/locale/mbstowcs.c",
+        "upstream-openbsd/lib/libc/locale/mbtowc.c",
+        "upstream-openbsd/lib/libc/locale/wcscoll.c",
+        "upstream-openbsd/lib/libc/locale/wcstod.c",
+        "upstream-openbsd/lib/libc/locale/wcstof.c",
+        "upstream-openbsd/lib/libc/locale/wcstoimax.c",
+        "upstream-openbsd/lib/libc/locale/wcstol.c",
+        "upstream-openbsd/lib/libc/locale/wcstold.c",
+        "upstream-openbsd/lib/libc/locale/wcstoll.c",
+        "upstream-openbsd/lib/libc/locale/wcstombs.c",
+        "upstream-openbsd/lib/libc/locale/wcstoul.c",
+        "upstream-openbsd/lib/libc/locale/wcstoull.c",
+        "upstream-openbsd/lib/libc/locale/wcstoumax.c",
+        "upstream-openbsd/lib/libc/locale/wcsxfrm.c",
+        "upstream-openbsd/lib/libc/locale/wctob.c",
+        "upstream-openbsd/lib/libc/locale/wctomb.c",
+        "upstream-openbsd/lib/libc/net/htonl.c",
+        "upstream-openbsd/lib/libc/net/htons.c",
+        "upstream-openbsd/lib/libc/net/inet_addr.c",
+        "upstream-openbsd/lib/libc/net/inet_lnaof.c",
+        "upstream-openbsd/lib/libc/net/inet_makeaddr.c",
+        "upstream-openbsd/lib/libc/net/inet_netof.c",
+        "upstream-openbsd/lib/libc/net/inet_network.c",
+        "upstream-openbsd/lib/libc/net/inet_ntoa.c",
+        "upstream-openbsd/lib/libc/net/inet_ntop.c",
+        "upstream-openbsd/lib/libc/net/inet_pton.c",
+        "upstream-openbsd/lib/libc/net/ntohl.c",
+        "upstream-openbsd/lib/libc/net/ntohs.c",
+        "upstream-openbsd/lib/libc/stdio/asprintf.c",
+        "upstream-openbsd/lib/libc/stdio/clrerr.c",
+        "upstream-openbsd/lib/libc/stdio/dprintf.c",
+        "upstream-openbsd/lib/libc/stdio/fclose.c",
+        "upstream-openbsd/lib/libc/stdio/fdopen.c",
+        "upstream-openbsd/lib/libc/stdio/feof.c",
+        "upstream-openbsd/lib/libc/stdio/ferror.c",
+        "upstream-openbsd/lib/libc/stdio/fflush.c",
+        "upstream-openbsd/lib/libc/stdio/fgetc.c",
+        "upstream-openbsd/lib/libc/stdio/fgetln.c",
+        "upstream-openbsd/lib/libc/stdio/fgetpos.c",
+        "upstream-openbsd/lib/libc/stdio/fgets.c",
+        "upstream-openbsd/lib/libc/stdio/fgetwc.c",
+        "upstream-openbsd/lib/libc/stdio/fgetws.c",
+        "upstream-openbsd/lib/libc/stdio/fileno.c",
+        "upstream-openbsd/lib/libc/stdio/flags.c",
+        "upstream-openbsd/lib/libc/stdio/fmemopen.c",
+        "upstream-openbsd/lib/libc/stdio/fopen.c",
+        "upstream-openbsd/lib/libc/stdio/fprintf.c",
+        "upstream-openbsd/lib/libc/stdio/fpurge.c",
+        "upstream-openbsd/lib/libc/stdio/fputc.c",
+        "upstream-openbsd/lib/libc/stdio/fputs.c",
+        "upstream-openbsd/lib/libc/stdio/fputwc.c",
+        "upstream-openbsd/lib/libc/stdio/fputws.c",
+        "upstream-openbsd/lib/libc/stdio/freopen.c",
+        "upstream-openbsd/lib/libc/stdio/fscanf.c",
+        "upstream-openbsd/lib/libc/stdio/fseek.c",
+        "upstream-openbsd/lib/libc/stdio/fsetpos.c",
+        "upstream-openbsd/lib/libc/stdio/ftell.c",
+        "upstream-openbsd/lib/libc/stdio/funopen.c",
+        "upstream-openbsd/lib/libc/stdio/fvwrite.c",
+        "upstream-openbsd/lib/libc/stdio/fwalk.c",
+        "upstream-openbsd/lib/libc/stdio/fwide.c",
+        "upstream-openbsd/lib/libc/stdio/fwprintf.c",
+        "upstream-openbsd/lib/libc/stdio/fwrite.c",
+        "upstream-openbsd/lib/libc/stdio/fwscanf.c",
+        "upstream-openbsd/lib/libc/stdio/getc.c",
+        "upstream-openbsd/lib/libc/stdio/getchar.c",
+        "upstream-openbsd/lib/libc/stdio/getdelim.c",
+        "upstream-openbsd/lib/libc/stdio/getline.c",
+        "upstream-openbsd/lib/libc/stdio/gets.c",
+        "upstream-openbsd/lib/libc/stdio/getwc.c",
+        "upstream-openbsd/lib/libc/stdio/getwchar.c",
+        "upstream-openbsd/lib/libc/stdio/makebuf.c",
+        "upstream-openbsd/lib/libc/stdio/mktemp.c",
+        "upstream-openbsd/lib/libc/stdio/open_memstream.c",
+        "upstream-openbsd/lib/libc/stdio/open_wmemstream.c",
+        "upstream-openbsd/lib/libc/stdio/perror.c",
+        "upstream-openbsd/lib/libc/stdio/printf.c",
+        "upstream-openbsd/lib/libc/stdio/putc.c",
+        "upstream-openbsd/lib/libc/stdio/putchar.c",
+        "upstream-openbsd/lib/libc/stdio/puts.c",
+        "upstream-openbsd/lib/libc/stdio/putwc.c",
+        "upstream-openbsd/lib/libc/stdio/putwchar.c",
+        "upstream-openbsd/lib/libc/stdio/refill.c",
+        "upstream-openbsd/lib/libc/stdio/remove.c",
+        "upstream-openbsd/lib/libc/stdio/rewind.c",
+        "upstream-openbsd/lib/libc/stdio/rget.c",
+        "upstream-openbsd/lib/libc/stdio/scanf.c",
+        "upstream-openbsd/lib/libc/stdio/setbuf.c",
+        "upstream-openbsd/lib/libc/stdio/setbuffer.c",
+        "upstream-openbsd/lib/libc/stdio/setvbuf.c",
+        "upstream-openbsd/lib/libc/stdio/sscanf.c",
+        "upstream-openbsd/lib/libc/stdio/swprintf.c",
+        "upstream-openbsd/lib/libc/stdio/swscanf.c",
+        "upstream-openbsd/lib/libc/stdio/tempnam.c",
+        "upstream-openbsd/lib/libc/stdio/tmpnam.c",
+        "upstream-openbsd/lib/libc/stdio/ungetc.c",
+        "upstream-openbsd/lib/libc/stdio/ungetwc.c",
+        "upstream-openbsd/lib/libc/stdio/vasprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vdprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vfprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vfscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vfwprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vfwscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vsnprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vsprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vsscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vswprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vswscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vwprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vwscanf.c",
+        "upstream-openbsd/lib/libc/stdio/wbuf.c",
+        "upstream-openbsd/lib/libc/stdio/wprintf.c",
+        "upstream-openbsd/lib/libc/stdio/wscanf.c",
+        "upstream-openbsd/lib/libc/stdio/wsetup.c",
+        "upstream-openbsd/lib/libc/stdlib/abs.c",
+        "upstream-openbsd/lib/libc/stdlib/atoi.c",
+        "upstream-openbsd/lib/libc/stdlib/atol.c",
+        "upstream-openbsd/lib/libc/stdlib/atoll.c",
+        "upstream-openbsd/lib/libc/stdlib/getenv.c",
+        "upstream-openbsd/lib/libc/stdlib/insque.c",
+        "upstream-openbsd/lib/libc/stdlib/imaxabs.c",
+        "upstream-openbsd/lib/libc/stdlib/imaxdiv.c",
+        "upstream-openbsd/lib/libc/stdlib/labs.c",
+        "upstream-openbsd/lib/libc/stdlib/llabs.c",
+        "upstream-openbsd/lib/libc/stdlib/lsearch.c",
+        "upstream-openbsd/lib/libc/stdlib/reallocarray.c",
+        "upstream-openbsd/lib/libc/stdlib/remque.c",
+        "upstream-openbsd/lib/libc/stdlib/setenv.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoimax.c",
+        "upstream-openbsd/lib/libc/stdlib/strtol.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoll.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoul.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoull.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoumax.c",
+        "upstream-openbsd/lib/libc/stdlib/system.c",
+        "upstream-openbsd/lib/libc/stdlib/tfind.c",
+        "upstream-openbsd/lib/libc/stdlib/tsearch.c",
+        "upstream-openbsd/lib/libc/string/strcasecmp.c",
+        "upstream-openbsd/lib/libc/string/strcspn.c",
+        "upstream-openbsd/lib/libc/string/strdup.c",
+        "upstream-openbsd/lib/libc/string/strndup.c",
+        "upstream-openbsd/lib/libc/string/strpbrk.c",
+        "upstream-openbsd/lib/libc/string/strsep.c",
+        "upstream-openbsd/lib/libc/string/strspn.c",
+        "upstream-openbsd/lib/libc/string/strstr.c",
+        "upstream-openbsd/lib/libc/string/strtok.c",
+        "upstream-openbsd/lib/libc/string/wmemcpy.c",
+        "upstream-openbsd/lib/libc/string/wcslcpy.c",
+        "upstream-openbsd/lib/libc/string/wcsstr.c",
+        "upstream-openbsd/lib/libc/string/wcswidth.c",
+    ],
+
+    cflags: libc_common_cflags + [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-Wno-unused-parameter",
+        "-include openbsd-compat.h",
+    ],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    local_include_dirs: [
+        "private",
+        "stdio",
+        "upstream-openbsd/android/include",
+        "upstream-openbsd/lib/libc/include",
+        "upstream-openbsd/lib/libc/gdtoa/",
+    ],
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+}
+
+// ========================================================
+// libc_openbsd.a - upstream OpenBSD C library code
+// ========================================================
+//
+// These files are built with the openbsd-compat.h header file
+// automatically included.
+cc_library_static {
+    srcs: [
+        // These two depend on getentropy_linux.c, which isn't in libc_ndk.a.
+        "upstream-openbsd/lib/libc/crypt/arc4random.c",
+        "upstream-openbsd/lib/libc/crypt/arc4random_uniform.c",
+
+        // May be overriden by per-arch optimized versions
+        "upstream-openbsd/lib/libc/string/memchr.c",
+        "upstream-openbsd/lib/libc/string/memmove.c",
+        "upstream-openbsd/lib/libc/string/memrchr.c",
+        "upstream-openbsd/lib/libc/string/stpcpy.c",
+        "upstream-openbsd/lib/libc/string/stpncpy.c",
+        "upstream-openbsd/lib/libc/string/strcat.c",
+        "upstream-openbsd/lib/libc/string/strcmp.c",
+        "upstream-openbsd/lib/libc/string/strcpy.c",
+        "upstream-openbsd/lib/libc/string/strlcat.c",
+        "upstream-openbsd/lib/libc/string/strlcpy.c",
+        "upstream-openbsd/lib/libc/string/strncat.c",
+        "upstream-openbsd/lib/libc/string/strncmp.c",
+        "upstream-openbsd/lib/libc/string/strncpy.c",
+    ],
+    multilib: {
+        lib32: {
+            // LP32 cruft
+            srcs: ["upstream-openbsd/lib/libc/stdio/putw.c"],
+        },
+    },
+
+    arch: {
+        arm: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/strcmp.c",
+                "upstream-openbsd/lib/libc/string/strcpy.c",
+            ],
+        },
+        cortex_a7: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+            ],
+        },
+        cortex_a53: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+            ],
+        },
+        cortex_a8: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+            ],
+        },
+        cortex_a9: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+            ],
+        },
+        cortex_a15: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+            ],
+        },
+        denver: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+            ],
+        },
+        krait: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+            ],
+        },
+
+        arm64: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memchr.c",
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcmp.c",
+                "upstream-openbsd/lib/libc/string/strcpy.c",
+                "upstream-openbsd/lib/libc/string/strncmp.c",
+            ],
+        },
+
+        mips: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/strcmp.c",
+            ],
+        },
+
+        mips64: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/strcmp.c",
+            ],
+        },
+
+        x86: {
+             exclude_srcs: [
+                 "upstream-openbsd/lib/libc/string/memchr.c",
+                 "upstream-openbsd/lib/libc/string/memmove.c",
+                 "upstream-openbsd/lib/libc/string/memrchr.c",
+                 "upstream-openbsd/lib/libc/string/stpcpy.c",
+                 "upstream-openbsd/lib/libc/string/stpncpy.c",
+                 "upstream-openbsd/lib/libc/string/strcat.c",
+                 "upstream-openbsd/lib/libc/string/strcmp.c",
+                 "upstream-openbsd/lib/libc/string/strcpy.c",
+                 "upstream-openbsd/lib/libc/string/strncmp.c",
+                 "upstream-openbsd/lib/libc/string/strncpy.c",
+                 ],
+        },
+        x86_sse3: {
+             exclude_srcs: [
+                 "upstream-openbsd/lib/libc/string/strlcat.c",
+                 "upstream-openbsd/lib/libc/string/strlcpy.c",
+                 "upstream-openbsd/lib/libc/string/strncat.c",
+             ],
+        },
+
+        x86_64: {
+             exclude_srcs: [
+                 "upstream-openbsd/lib/libc/string/memmove.c",
+                 "upstream-openbsd/lib/libc/string/stpcpy.c",
+                 "upstream-openbsd/lib/libc/string/stpncpy.c",
+                 "upstream-openbsd/lib/libc/string/strcat.c",
+                 "upstream-openbsd/lib/libc/string/strcmp.c",
+                 "upstream-openbsd/lib/libc/string/strcpy.c",
+                 "upstream-openbsd/lib/libc/string/strlcat.c",
+                 "upstream-openbsd/lib/libc/string/strlcpy.c",
+                 "upstream-openbsd/lib/libc/string/strncat.c",
+                 "upstream-openbsd/lib/libc/string/strncmp.c",
+                 "upstream-openbsd/lib/libc/string/strncpy.c",
+             ],
+            clang: use_clang_x86_64,
+        },
+    },
+
+    cflags: libc_common_cflags + [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-Wno-unused-parameter",
+        "-include openbsd-compat.h",
+    ],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    local_include_dirs: [
+        "private",
+        "stdio",
+        "upstream-openbsd/android/include",
+        "upstream-openbsd/lib/libc/include",
+        "upstream-openbsd/lib/libc/gdtoa/",
+    ],
+
+    name: "libc_openbsd",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+}
+
+// ========================================================
+// libc_gdtoa.a - upstream OpenBSD C library gdtoa code
+// ========================================================
+//
+// These files are built with the openbsd-compat.h header file
+// automatically included.
+
+cc_library_static {
+    srcs: [
+        "upstream-openbsd/android/gdtoa_support.cpp",
+        "upstream-openbsd/lib/libc/gdtoa/dmisc.c",
+        "upstream-openbsd/lib/libc/gdtoa/dtoa.c",
+        "upstream-openbsd/lib/libc/gdtoa/gdtoa.c",
+        "upstream-openbsd/lib/libc/gdtoa/gethex.c",
+        "upstream-openbsd/lib/libc/gdtoa/gmisc.c",
+        "upstream-openbsd/lib/libc/gdtoa/hd_init.c",
+        "upstream-openbsd/lib/libc/gdtoa/hdtoa.c",
+        "upstream-openbsd/lib/libc/gdtoa/hexnan.c",
+        "upstream-openbsd/lib/libc/gdtoa/ldtoa.c",
+        "upstream-openbsd/lib/libc/gdtoa/misc.c",
+        "upstream-openbsd/lib/libc/gdtoa/smisc.c",
+        "upstream-openbsd/lib/libc/gdtoa/strtod.c",
+        "upstream-openbsd/lib/libc/gdtoa/strtodg.c",
+        "upstream-openbsd/lib/libc/gdtoa/strtof.c",
+        "upstream-openbsd/lib/libc/gdtoa/strtord.c",
+        "upstream-openbsd/lib/libc/gdtoa/sum.c",
+        "upstream-openbsd/lib/libc/gdtoa/ulp.c",
+    ],
+    multilib: {
+        lib64: {
+            srcs: ["upstream-openbsd/lib/libc/gdtoa/strtorQ.c"]
+        },
+    },
+
+    cflags: libc_common_cflags + [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-fvisibility=hidden",
+        "-include openbsd-compat.h",
+    ],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    local_include_dirs: [
+        "private",
+        "upstream-openbsd/android/include",
+        "upstream-openbsd/lib/libc/include",
+    ],
+
+    name: "libc_gdtoa",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+}
+
+// ========================================================
+// libc_bionic.a - home-grown C library code
+// ========================================================
+
+cc_library_static {
+    srcs: [
+        // The fork implementation depends on pthread data, so we can't include
+        // it in libc_ndk.a.
+        "bionic/fork.cpp",
+
+        // The data that backs getauxval is initialized in the libc init
+        // functions which are invoked by the linker. If this file is included
+        // in libc_ndk.a, only one of the copies of the global data will be
+        // initialized, resulting in nullptr dereferences.
+        "bionic/getauxval.cpp",
+
+        // These four require getauxval, which isn't available on older
+        // platforms.
+        "bionic/getentropy_linux.c",
+        "bionic/sysconf.cpp",
+        "bionic/vdso.cpp",
+        "bionic/setjmp_cookie.cpp",
+    ],
+    cflags: libc_common_cflags + ["-Wframe-larger-than=2048"],
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags + ["-Wold-style-cast"],
+    product_variables: libc_common_product_variables,
+    include_dirs: ["bionic/libstdc++/include"],
+    name: "libc_bionic",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+}
+
+// ========================================================
+// libc_bionic_ndk.a- The portions of libc_bionic that can
+// be safely used in libc_ndk.a (no troublesome global data
+// or constructors).
+// ========================================================
+cc_library_static {
+    srcs: [
+        "bionic/abort.cpp",
+        "bionic/accept.cpp",
+        "bionic/accept4.cpp",
+        "bionic/access.cpp",
+        "bionic/assert.cpp",
+        "bionic/atof.cpp",
+        "bionic/bionic_systrace.cpp",
+        "bionic/bionic_time_conversions.cpp",
+        "bionic/brk.cpp",
+        "bionic/c16rtomb.cpp",
+        "bionic/c32rtomb.cpp",
+        "bionic/chmod.cpp",
+        "bionic/chown.cpp",
+        "bionic/clearenv.cpp",
+        "bionic/clock.cpp",
+        "bionic/clock_getcpuclockid.cpp",
+        "bionic/clock_nanosleep.cpp",
+        "bionic/clone.cpp",
+        "bionic/close.cpp",
+        "bionic/__cmsg_nxthdr.cpp",
+        "bionic/connect.cpp",
+        "bionic/ctype.cpp",
+        "bionic/dirent.cpp",
+        "bionic/dup2.cpp",
+        "bionic/epoll_create.cpp",
+        "bionic/epoll_pwait.cpp",
+        "bionic/epoll_wait.cpp",
+        "bionic/__errno.cpp",
+        "bionic/error.cpp",
+        "bionic/eventfd_read.cpp",
+        "bionic/eventfd_write.cpp",
+        "bionic/faccessat.cpp",
+        "bionic/fchmod.cpp",
+        "bionic/fchmodat.cpp",
+        "bionic/ffs.cpp",
+        "bionic/fgetxattr.cpp",
+        "bionic/flistxattr.cpp",
+        "bionic/flockfile.cpp",
+        "bionic/fpclassify.cpp",
+        "bionic/fsetxattr.cpp",
+        "bionic/ftruncate.cpp",
+        "bionic/futimens.cpp",
+        "bionic/getcwd.cpp",
+        "bionic/gethostname.cpp",
+        "bionic/getpgrp.cpp",
+        "bionic/getpid.cpp",
+        "bionic/gettid.cpp",
+        "bionic/__gnu_basename.cpp",
+        "bionic/inotify_init.cpp",
+        "bionic/lchown.cpp",
+        "bionic/lfs64_support.cpp",
+        "bionic/__libc_current_sigrtmax.cpp",
+        "bionic/__libc_current_sigrtmin.cpp",
+        "bionic/libc_init_common.cpp",
+        "bionic/libc_logging.cpp",
+        "bionic/libgen.cpp",
+        "bionic/link.cpp",
+        "bionic/locale.cpp",
+        "bionic/lstat.cpp",
+        "bionic/malloc_info.cpp",
+        "bionic/mbrtoc16.cpp",
+        "bionic/mbrtoc32.cpp",
+        "bionic/mbstate.cpp",
+        "bionic/mempcpy.cpp",
+        "bionic/mkdir.cpp",
+        "bionic/mkfifo.cpp",
+        "bionic/mknod.cpp",
+        "bionic/mntent.cpp",
+        "bionic/NetdClientDispatch.cpp",
+        "bionic/open.cpp",
+        "bionic/pathconf.cpp",
+        "bionic/pause.cpp",
+        "bionic/pipe.cpp",
+        "bionic/poll.cpp",
+        "bionic/posix_fadvise.cpp",
+        "bionic/posix_fallocate.cpp",
+        "bionic/posix_madvise.cpp",
+        "bionic/posix_timers.cpp",
+        "bionic/ptrace.cpp",
+        "bionic/pty.cpp",
+        "bionic/raise.cpp",
+        "bionic/rand.cpp",
+        "bionic/readlink.cpp",
+        "bionic/reboot.cpp",
+        "bionic/recv.cpp",
+        "bionic/rename.cpp",
+        "bionic/rmdir.cpp",
+        "bionic/scandir.cpp",
+        "bionic/sched_getaffinity.cpp",
+        "bionic/sched_getcpu.cpp",
+        "bionic/semaphore.cpp",
+        "bionic/send.cpp",
+        "bionic/setegid.cpp",
+        "bionic/__set_errno.cpp",
+        "bionic/seteuid.cpp",
+        "bionic/setpgrp.cpp",
+        "bionic/sigaction.cpp",
+        "bionic/sigaddset.cpp",
+        "bionic/sigdelset.cpp",
+        "bionic/sigemptyset.cpp",
+        "bionic/sigfillset.cpp",
+        "bionic/sigismember.cpp",
+        "bionic/signal.cpp",
+        "bionic/signalfd.cpp",
+        "bionic/sigpending.cpp",
+        "bionic/sigprocmask.cpp",
+        "bionic/sigqueue.cpp",
+        "bionic/sigsuspend.cpp",
+        "bionic/sigtimedwait.cpp",
+        "bionic/sigwait.cpp",
+        "bionic/sigwaitinfo.cpp",
+        "bionic/socket.cpp",
+        "bionic/stat.cpp",
+        "bionic/statvfs.cpp",
+        "bionic/strchrnul.cpp",
+        "bionic/strerror.cpp",
+        "bionic/strerror_r.cpp",
+        "bionic/strsignal.cpp",
+        "bionic/strtold.cpp",
+        "bionic/stubs.cpp",
+        "bionic/symlink.cpp",
+        "bionic/sysinfo.cpp",
+        "bionic/syslog.cpp",
+        "bionic/sys_siglist.c",
+        "bionic/sys_signame.c",
+        "bionic/system_properties.cpp",
+        "bionic/tdestroy.cpp",
+        "bionic/termios.cpp",
+        "bionic/thread_private.cpp",
+        "bionic/tmpfile.cpp",
+        "bionic/umount.cpp",
+        "bionic/unlink.cpp",
+        "bionic/utimes.cpp",
+        "bionic/wait.cpp",
+        "bionic/wchar.cpp",
+        "bionic/wctype.cpp",
+        "bionic/wmempcpy.cpp",
+
+        // May be overriden by per-arch optimized versions
+        "bionic/__memcpy_chk.cpp",
+        "bionic/__memset_chk.cpp",
+        "bionic/__strcat_chk.cpp",
+        "bionic/__strcpy_chk.cpp",
+        "bionic/strchr.cpp",
+        "bionic/strnlen.c",
+        "bionic/strrchr.cpp",
+    ],
+    cflags: libc_common_cflags + ["-Wframe-larger-than=2048"],
+
+    arch: {
+
+        arm: {
+            srcs: [
+                "arch-arm/bionic/abort_arm.S",
+                "arch-arm/bionic/atomics_arm.c",
+                "arch-arm/bionic/__bionic_clone.S",
+                "arch-arm/bionic/_exit_with_stack_teardown.S",
+                "arch-arm/bionic/libgcc_compat.c",
+                "arch-arm/bionic/popcount_tab.c",
+                "arch-arm/bionic/__restore.S",
+                "arch-arm/bionic/setjmp.S",
+                "arch-arm/bionic/syscall.S",
+                "arch-arm/bionic/vfork.S",
+
+                "arch-arm/generic/bionic/memcmp.S",
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+            ],
+            exclude_srcs: [
+                "bionic/__memcpy_chk.cpp",
+                "bionic/__memset_chk.cpp",
+            ],
+        },
+        cortex_a7: {
+            srcs: [
+                "arch-arm/cortex-a7/bionic/memset.S",
+
+                "arch-arm/cortex-a15/bionic/memcpy.S",
+                "arch-arm/cortex-a15/bionic/stpcpy.S",
+                "arch-arm/cortex-a15/bionic/strcat.S",
+                "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a15/bionic/strcmp.S",
+                "arch-arm/cortex-a15/bionic/strcpy.S",
+                "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                "arch-arm/cortex-a15/bionic/strlen.S",
+
+                "arch-arm/denver/bionic/memmove.S",
+            ],
+            exclude_srcs: [
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+                "bionic/__strcat_chk.cpp",
+                "bionic/__strcpy_chk.cpp",
+            ],
+        },
+        cortex_a53: {
+            srcs: [
+                "arch-arm/cortex-a53/bionic/memcpy.S",
+                "arch-arm/cortex-a53/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
+
+                "arch-arm/cortex-a7/bionic/memset.S",
+
+                "arch-arm/cortex-a15/bionic/stpcpy.S",
+                "arch-arm/cortex-a15/bionic/strcat.S",
+                "arch-arm/cortex-a15/bionic/strcmp.S",
+                "arch-arm/cortex-a15/bionic/strcpy.S",
+                "arch-arm/cortex-a15/bionic/strlen.S",
+
+                "arch-arm/denver/bionic/memmove.S",
+            ],
+            exclude_srcs: [
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+                "bionic/__strcat_chk.cpp",
+                "bionic/__strcpy_chk.cpp",
+            ],
+        },
+        cortex_a8: {
+            srcs: [
+                "arch-arm/cortex-a15/bionic/memcpy.S",
+                "arch-arm/cortex-a15/bionic/memset.S",
+                "arch-arm/cortex-a15/bionic/stpcpy.S",
+                "arch-arm/cortex-a15/bionic/strcat.S",
+                "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a15/bionic/strcmp.S",
+                "arch-arm/cortex-a15/bionic/strcpy.S",
+                "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                "arch-arm/cortex-a15/bionic/strlen.S",
+
+                "arch-arm/denver/bionic/memmove.S",
+            ],
+            exclude_srcs: [
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+                "bionic/__strcat_chk.cpp",
+                "bionic/__strcpy_chk.cpp",
+            ],
+        },
+        cortex_a9: {
+            srcs: [
+                "arch-arm/cortex-a9/bionic/memcpy.S",
+                "arch-arm/cortex-a9/bionic/memset.S",
+                "arch-arm/cortex-a9/bionic/stpcpy.S",
+                "arch-arm/cortex-a9/bionic/strcat.S",
+                "arch-arm/cortex-a9/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a9/bionic/strcmp.S",
+                "arch-arm/cortex-a9/bionic/strcpy.S",
+                "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
+                "arch-arm/cortex-a9/bionic/strlen.S",
+
+                "arch-arm/denver/bionic/memmove.S",
+            ],
+            exclude_srcs: [
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+                "bionic/__strcat_chk.cpp",
+                "bionic/__strcpy_chk.cpp",
+            ],
+        },
+        cortex_a15: {
+            srcs: [
+                "arch-arm/cortex-a15/bionic/memcpy.S",
+                "arch-arm/cortex-a15/bionic/memset.S",
+                "arch-arm/cortex-a15/bionic/stpcpy.S",
+                "arch-arm/cortex-a15/bionic/strcat.S",
+                "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a15/bionic/strcmp.S",
+                "arch-arm/cortex-a15/bionic/strcpy.S",
+                "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                "arch-arm/cortex-a15/bionic/strlen.S",
+
+                "arch-arm/denver/bionic/memmove.S",
+            ],
+            exclude_srcs: [
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+                "bionic/__strcat_chk.cpp",
+                "bionic/__strcpy_chk.cpp",
+            ],
+        },
+        denver: {
+            srcs: [
+                "arch-arm/denver/bionic/memcpy.S",
+                "arch-arm/denver/bionic/memmove.S",
+                "arch-arm/denver/bionic/memset.S",
+                "arch-arm/denver/bionic/__strcat_chk.S",
+                "arch-arm/denver/bionic/__strcpy_chk.S",
+
+                // Use cortex-a15 versions of strcat/strcpy/strlen.
+                "arch-arm/cortex-a15/bionic/stpcpy.S",
+                "arch-arm/cortex-a15/bionic/strcat.S",
+                "arch-arm/cortex-a15/bionic/strcmp.S",
+                "arch-arm/cortex-a15/bionic/strcpy.S",
+                "arch-arm/cortex-a15/bionic/strlen.S",
+            ],
+            exclude_srcs: [
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+                "bionic/__strcat_chk.cpp",
+                "bionic/__strcpy_chk.cpp",
+            ],
+        },
+        krait: {
+            srcs: [
+                "arch-arm/krait/bionic/memcpy.S",
+                "arch-arm/krait/bionic/memset.S",
+                "arch-arm/krait/bionic/strcmp.S",
+                "arch-arm/krait/bionic/__strcat_chk.S",
+                "arch-arm/krait/bionic/__strcpy_chk.S",
+
+                // Use cortex-a15 versions of strcat/strcpy/strlen.
+                "arch-arm/cortex-a15/bionic/stpcpy.S",
+                "arch-arm/cortex-a15/bionic/strcat.S",
+                "arch-arm/cortex-a15/bionic/strcpy.S",
+                "arch-arm/cortex-a15/bionic/strlen.S",
+
+                "arch-arm/denver/bionic/memmove.S",
+            ],
+            exclude_srcs: [
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+                "bionic/__strcat_chk.cpp",
+                "bionic/__strcpy_chk.cpp",
+            ],
+        },
+
+        arm64: {
+            srcs: [
+                "arch-arm64/bionic/__bionic_clone.S",
+                "arch-arm64/bionic/_exit_with_stack_teardown.S",
+                "arch-arm64/bionic/setjmp.S",
+                "arch-arm64/bionic/__set_tls.c",
+                "arch-arm64/bionic/syscall.S",
+                "arch-arm64/bionic/vfork.S",
+
+                "arch-arm64/generic/bionic/memchr.S",
+                "arch-arm64/generic/bionic/memcmp.S",
+                "arch-arm64/generic/bionic/memcpy.S",
+                "arch-arm64/generic/bionic/memmove.S",
+                "arch-arm64/generic/bionic/memset.S",
+                "arch-arm64/generic/bionic/stpcpy.S",
+                "arch-arm64/generic/bionic/strchr.S",
+                "arch-arm64/generic/bionic/strcmp.S",
+                "arch-arm64/generic/bionic/strcpy.S",
+                "arch-arm64/generic/bionic/strlen.S",
+                "arch-arm64/generic/bionic/strncmp.S",
+                "arch-arm64/generic/bionic/strnlen.S",
+                "arch-arm64/generic/bionic/wmemmove.S",
+            ],
+            exclude_srcs: [
+                "bionic/__memcpy_chk.cpp",
+                "bionic/strchr.cpp",
+                "bionic/strnlen.c",
+            ],
+        },
+        denver64: {
+            srcs: [
+                "arch-arm64/denver64/bionic/memcpy.S",
+                "arch-arm64/denver64/bionic/memset.S",
+            ],
+            exclude_srcs: [
+                "arch-arm64/generic/bionic/memcpy.S",
+                "arch-arm64/generic/bionic/memset.S",
+            ],
+        },
+
+        mips: {
+            srcs: [
+                "arch-mips/bionic/__bionic_clone.S",
+                "arch-mips/bionic/bzero.S",
+                "arch-mips/bionic/cacheflush.cpp",
+                "arch-mips/bionic/_exit_with_stack_teardown.S",
+                "arch-mips/bionic/setjmp.S",
+                "arch-mips/bionic/syscall.S",
+                "arch-mips/bionic/vfork.S",
+
+                "arch-mips/string/memcmp.c",
+                "arch-mips/string/memcpy.S",
+                "arch-mips/string/memset.S",
+                "arch-mips/string/strcmp.S",
+                "arch-mips/string/strlen.c",
+            ],
+        },
+        mips_rev6: {
+            srcs: [
+                "arch-mips/string/mips_strlen.c"
+            ],
+            exclude_srcs: [
+                "arch-mips/string/strlen.c"
+            ],
+        },
+
+        mips64: {
+            srcs: [
+                "arch-mips64/bionic/__bionic_clone.S",
+                "arch-mips64/bionic/_exit_with_stack_teardown.S",
+                "arch-mips64/bionic/setjmp.S",
+                "arch-mips64/bionic/syscall.S",
+                "arch-mips64/bionic/vfork.S",
+                "arch-mips64/bionic/stat.cpp",
+
+                "arch-mips/string/memcmp.c",
+                "arch-mips/string/memcpy.S",
+                "arch-mips/string/memset.S",
+                "arch-mips/string/strcmp.S",
+                "arch-mips/string/strlen.c",
+            ],
+        },
+
+        x86: {
+            srcs: [
+                "arch-x86/bionic/__bionic_clone.S",
+                "arch-x86/bionic/_exit_with_stack_teardown.S",
+                "arch-x86/bionic/libgcc_compat.c",
+                "arch-x86/bionic/__restore.S",
+                "arch-x86/bionic/setjmp.S",
+                "arch-x86/bionic/__set_tls.c",
+                "arch-x86/bionic/syscall.S",
+                "arch-x86/bionic/vfork.S",
+
+                "arch-x86/generic/string/memcmp.S",
+                "arch-x86/generic/string/strcmp.S",
+                "arch-x86/generic/string/strncmp.S",
+                "arch-x86/generic/string/strcat.S",
+                "arch-x86/atom/string/sse2-memchr-atom.S",
+                "arch-x86/atom/string/sse2-memrchr-atom.S",
+                "arch-x86/atom/string/sse2-strchr-atom.S",
+                "arch-x86/atom/string/sse2-strnlen-atom.S",
+                "arch-x86/atom/string/sse2-strrchr-atom.S",
+                "arch-x86/atom/string/sse2-wcschr-atom.S",
+                "arch-x86/atom/string/sse2-wcsrchr-atom.S",
+                "arch-x86/atom/string/sse2-wcslen-atom.S",
+                "arch-x86/atom/string/sse2-wcscmp-atom.S",
+                "arch-x86/silvermont/string/sse2-bcopy-slm.S",
+                "arch-x86/silvermont/string/sse2-bzero-slm.S",
+                "arch-x86/silvermont/string/sse2-memcpy-slm.S",
+                "arch-x86/silvermont/string/sse2-memmove-slm.S",
+                "arch-x86/silvermont/string/sse2-memset-slm.S",
+                "arch-x86/silvermont/string/sse2-stpcpy-slm.S",
+                "arch-x86/silvermont/string/sse2-stpncpy-slm.S",
+                "arch-x86/silvermont/string/sse2-strcpy-slm.S",
+                "arch-x86/silvermont/string/sse2-strlen-slm.S",
+                "arch-x86/silvermont/string/sse2-strncpy-slm.S",
+            ],
+        },
+        x86_sse3: {
+            srcs: [
+                "arch-x86/atom/string/ssse3-strncat-atom.S",
+                "arch-x86/atom/string/ssse3-strlcat-atom.S",
+                "arch-x86/atom/string/ssse3-strlcpy-atom.S",
+                "arch-x86/atom/string/ssse3-strcmp-atom.S",
+                "arch-x86/atom/string/ssse3-strncmp-atom.S",
+                "arch-x86/atom/string/ssse3-strcat-atom.S",
+                "arch-x86/atom/string/ssse3-wcscat-atom.S",
+                "arch-x86/atom/string/ssse3-wcscpy-atom.S",
+            ],
+            exclude_srcs: [
+                "arch-x86/generic/string/strcmp.S",
+                "arch-x86/generic/string/strncmp.S",
+                "arch-x86/generic/string/strcat.S",
+            ],
+        },
+        x86_sse4: {
+            srcs: [
+                "arch-x86/silvermont/string/sse4-memcmp-slm.S",
+                "arch-x86/silvermont/string/sse4-wmemcmp-slm.S",
+            ],
+            exclude_srcs: [
+                "arch-x86/generic/string/memcmp.S",
+            ],
+        },
+
+
+        x86_64: {
+            clang: use_clang_x86_64,
+            srcs: [
+                "arch-x86_64/bionic/__bionic_clone.S",
+                "arch-x86_64/bionic/_exit_with_stack_teardown.S",
+                "arch-x86_64/bionic/__restore_rt.S",
+                "arch-x86_64/bionic/setjmp.S",
+                "arch-x86_64/bionic/__set_tls.c",
+                "arch-x86_64/bionic/syscall.S",
+                "arch-x86_64/bionic/vfork.S",
+
+                "arch-x86_64/string/sse2-memcpy-slm.S",
+                "arch-x86_64/string/sse2-memmove-slm.S",
+                "arch-x86_64/string/sse2-memset-slm.S",
+                "arch-x86_64/string/sse2-stpcpy-slm.S",
+                "arch-x86_64/string/sse2-stpncpy-slm.S",
+                "arch-x86_64/string/sse2-strcat-slm.S",
+                "arch-x86_64/string/sse2-strcpy-slm.S",
+                "arch-x86_64/string/sse2-strlcat-slm.S",
+                "arch-x86_64/string/sse2-strlcpy-slm.S",
+                "arch-x86_64/string/sse2-strlen-slm.S",
+                "arch-x86_64/string/sse2-strncat-slm.S",
+                "arch-x86_64/string/sse2-strncpy-slm.S",
+                "arch-x86_64/string/sse4-memcmp-slm.S",
+                "arch-x86_64/string/ssse3-strcmp-slm.S",
+                "arch-x86_64/string/ssse3-strncmp-slm.S",
+            ],
+        },
+
+    },
+    multilib: {
+        lib32: {
+            // LP32 cruft
+            srcs: ["bionic/mmap.cpp"]
+        },
+    },
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags + ["-Wold-style-cast"],
+    product_variables: libc_common_product_variables,
+    local_include_dirs: ["stdio"],
+    include_dirs: ["bionic/libstdc++/include"],
+    name: "libc_bionic_ndk",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+}
+
+cc_library_static {
+    name: "libc_thread_atexit_impl",
+    srcs: ["bionic/__cxa_thread_atexit_impl.cpp"],
+    cflags: libc_common_cflags + ["-Wframe-larger-than=2048"],
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags + ["-Wold-style-cast"],
+    product_variables: libc_common_product_variables,
+    include_dirs: ["bionic/libstdc++/include"],
+    // TODO: Clang tries to use __tls_get_addr which is not supported yet
+    // remove after it is implemented.
+    clang: false,
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+}
+
+// ========================================================
+// libc_pthread.a - pthreads parts that previously lived in
+// libc_bionic.a. Relocated to their own library because
+// they can't be included in libc_ndk.a (as they layout of
+// pthread_t has changed over the years and has ABI
+// compatibility issues).
+// ========================================================
+
+cc_library_static {
+    srcs: [
+        "bionic/pthread_atfork.cpp",
+        "bionic/pthread_attr.cpp",
+        "bionic/pthread_cond.cpp",
+        "bionic/pthread_create.cpp",
+        "bionic/pthread_detach.cpp",
+        "bionic/pthread_equal.cpp",
+        "bionic/pthread_exit.cpp",
+        "bionic/pthread_getcpuclockid.cpp",
+        "bionic/pthread_getschedparam.cpp",
+        "bionic/pthread_gettid_np.cpp",
+        "bionic/pthread_internal.cpp",
+        "bionic/pthread_join.cpp",
+        "bionic/pthread_key.cpp",
+        "bionic/pthread_kill.cpp",
+        "bionic/pthread_mutex.cpp",
+        "bionic/pthread_once.cpp",
+        "bionic/pthread_rwlock.cpp",
+        "bionic/pthread_self.cpp",
+        "bionic/pthread_setname_np.cpp",
+        "bionic/pthread_setschedparam.cpp",
+        "bionic/pthread_sigmask.cpp",
+    ],
+    cflags: libc_common_cflags + ["-Wframe-larger-than=2048"],
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags + ["-Wold-style-cast"],
+    product_variables: libc_common_product_variables,
+    include_dirs: ["bionic/libstdc++/include"],
+    name: "libc_pthread",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+}
+
+// ========================================================
+// libc_cxa.a - Things traditionally in libstdc++
+// ========================================================
+
+cc_library_static {
+    srcs: [
+        "bionic/__cxa_guard.cpp",
+        "bionic/__cxa_pure_virtual.cpp",
+        "bionic/new.cpp",
+    ],
+    cflags: libc_common_cflags + ["-fvisibility=hidden"],
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    include_dirs: ["bionic/libstdc++/include"],
+    name: "libc_cxa",
+    clang: true, // GCC refuses to hide new/delete
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    // b/17574078: Need to disable coverage until we have a prebuilt libprofile_rt.
+    // Since this is a static library built with clang, it needs to link
+    // libprofile_rt when it is linked into the final binary. Since the final binary
+    // is built with GCC, it won't link libprofile_rt. We can't very easily just add
+    // libprofile_rt to all link lines the way we've done for libgcov because
+    // libprofile_rt isn't prebuilt, and it would be tricky to write a rule that
+    // would make sure libprofile_rt is built.
+    native_coverage: false,
+}
+
+// ========================================================
+// libc_syscalls.a
+// ========================================================
+
+cc_library_static {
+    arch: {
+        arm: {
+            srcs: ["arch-arm/syscalls/**/*.S"],
+        },
+        arm64: {
+            srcs: ["arch-arm64/syscalls/**/*.S"],
+        },
+        mips: {
+            srcs: ["arch-mips/syscalls/**/*.S"],
+        },
+        mips64: {
+            srcs: ["arch-mips64/syscalls/**/*.S"],
+        },
+        x86: {
+            srcs: ["arch-x86/syscalls/**/*.S"],
+        },
+        x86_64: {
+            clang: use_clang_x86_64,
+            srcs: ["arch-x86_64/syscalls/**/*.S"],
+        },
+    },
+    name: "libc_syscalls",
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+}
+
+// ========================================================
+// libc_aeabi.a
+// This is an LP32 ARM-only library that needs to be built with -fno-builtin
+// to avoid infinite recursion. For the other architectures we just build an
+// empty library to keep this makefile simple.
+// ========================================================
+
+cc_library_static {
+    arch: {
+        arm: {
+            srcs: ["arch-arm/bionic/__aeabi.c"],
+        },
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+    name: "libc_aeabi",
+    cflags: libc_common_cflags + ["-fno-builtin"],
+    product_variables: libc_common_product_variables,
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+}
+
+// ========================================================
+// libc_ndk.a
+// Compatibility library for the NDK. This library contains
+// all the parts of libc that are safe to statically link.
+// We can't safely statically link things that can only run
+// on a certain version of the OS. Examples include
+// anything that talks to netd (a large portion of the DNS
+// code) and anything that is dependent on the layout of a
+// data structure that has changed across releases (such as
+// pthread_t).
+// ========================================================
+
+cc_library_static {
+    name: "libc_ndk",
+    srcs: libc_common_src_files + ["bionic/malloc_debug_common.cpp"],
+    multilib: {
+        lib32: {
+            srcs: libc_common_src_files_32,
+        },
+    },
+    arch: {
+        arm: {
+            srcs: [
+                "arch-arm/bionic/exidx_dynamic.c",
+                "arch-common/bionic/crtbegin_so.c",
+                "arch-arm/bionic/atexit_legacy.c",
+                "arch-common/bionic/crtend_so.S",
+            ],
+            whole_static_libs: ["libc_aeabi"],
+        },
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+
+    cflags: libc_common_cflags + [
+        "-fvisibility=hidden",
+        "-DLIBC_STATIC",
+    ],
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+
+    whole_static_libs: [
+        "libc_bionic_ndk",
+        "libc_cxa",
+        "libc_freebsd",
+        "libc_gdtoa",
+        "libc_malloc",
+        "libc_netbsd",
+        "libc_openbsd_ndk",
+        "libc_stack_protector",
+        "libc_syscalls",
+        "libc_tzcode",
+        "libm",
+    ],
+
+    stl: "none",
+    system_shared_libs: [],
+
+    // TODO: split out the asflags.
+    asflags: libc_common_cflags,
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+}
+
+// ========================================================
+// libc_common.a
+// ========================================================
+
+cc_library_static {
+    srcs: libc_common_src_files,
+    multilib: {
+        lib32: {
+            srcs: libc_common_src_files_32,
+        },
+    },
+    cflags: libc_common_cflags,
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    name: "libc_common",
+
+    whole_static_libs: [
+        "libc_bionic",
+        "libc_bionic_ndk",
+        "libc_cxa",
+        "libc_dns",
+        "libc_freebsd",
+        "libc_gdtoa",
+        "libc_malloc",
+        "libc_netbsd",
+        "libc_openbsd",
+        "libc_openbsd_ndk",
+        "libc_pthread",
+        "libc_stack_protector",
+        "libc_syscalls",
+        "libc_thread_atexit_impl",
+        "libc_tzcode",
+    ],
+
+    arch: {
+        arm: {
+            whole_static_libs: ["libc_aeabi"],
+        },
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+
+    stl: "none",
+    system_shared_libs: [],
+
+    // TODO: split out the asflags.
+    asflags: libc_common_cflags,
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+}
+
+// ========================================================
+// libc_nomalloc.a
+// ========================================================
+//
+// This is a version of the static C library that does not
+// include malloc. It's useful in situations when the user wants
+// to provide their own malloc implementation, or wants to
+// explicitly disallow the use of malloc, such as in the
+// dynamic linker.
+
+cc_library_static {
+    srcs: [
+        "bionic/dl_iterate_phdr_static.cpp",
+        "bionic/libc_init_static.cpp",
+    ],
+
+    arch: {
+        arm: {
+            srcs: ["arch-arm/bionic/exidx_static.c"],
+        },
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+
+    cflags: libc_common_cflags + ["-DLIBC_STATIC"],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+
+    name: "libc_nomalloc",
+
+    whole_static_libs: ["libc_common"],
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+}
+
+// ========================================================
+// libc_malloc.a: the _prefixed_ malloc functions (like dlcalloc).
+// ========================================================
+cc_library_static {
+    product_variables: libc_common_product_variables + {
+        device_uses_jemalloc: {
+            srcs: ["bionic/jemalloc_wrapper.cpp"],
+            whole_static_libs: ["libjemalloc"],
+        },
+        device_uses_dlmalloc: {
+            srcs: ["bionic/dlmalloc.c"],
+        },
+    },
+    cflags: libc_common_cflags + ["-fvisibility=hidden"],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    name: "libc_malloc",
+    stl: "none",
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+}
+
+// ========================================================
+// libc.a + libc.so
+// ========================================================
+cc_library {
+    name: "libc",
+    cflags: libc_common_cflags,
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables + {
+        platform_sdk_version: {
+            asflags: ["-DPLATFORM_SDK_VERSION=%d"],
+        },
+    },
+    srcs: ["bionic/malloc_debug_common.cpp"],
+    static: {
+        srcs: [
+            "bionic/dl_iterate_phdr_static.cpp",
+            "bionic/libc_init_static.cpp",
+        ],
+        cflags: ["-DLIBC_STATIC"],
+    },
+    shared: {
+        srcs: [
+            "arch-common/bionic/crtbegin_so.c",
+            "arch-common/bionic/crtbrand.S",
+            "bionic/libc_init_dynamic.cpp",
+            "bionic/NetdClient.cpp",
+            "arch-common/bionic/crtend_so.S",
+        ],
+    },
+
+    required: ["tzdata"],
+
+    // Leave the symbols in the shared library so that stack unwinders can produce
+    // meaningful name resolution.
+    strip: "keep_symbols",
+
+    // WARNING: The only library libc.so should depend on is libdl.so!  If you add other libraries,
+    // make sure to add -Wl,--exclude-libs=libgcc.a to the LOCAL_LDFLAGS for those libraries.  This
+    // ensures that symbols that are pulled into those new libraries from libgcc.a are not declared
+    // external; if that were the case, then libc would not pull those symbols from libgcc.a as it
+    // should, instead relying on the external symbols from the dependent libraries.  That would
+    // create a "cloaked" dependency on libgcc.a in libc though the libraries, which is not what
+    // you wanted!
+
+    shared_libs: ["libdl"],
+    whole_static_libs: ["libc_common"],
+    stl: "none",
+    system_shared_libs: [],
+
+    // Don't re-export new/delete and friends, even if the compiler really wants to.
+    version_script: "libc.map",
+
+    // We'd really like to do this for all architectures, but since this wasn't done
+    // before, these symbols must continue to be exported on LP32 for binary
+    // compatibility.
+    multilib: {
+        lib64: {
+            ldflags: ["-Wl,--exclude-libs,libgcc.a"],
+        },
+    },
+
+    nocrt: true,
+
+    // special for arm
+    arch: {
+        arm: {
+            //TODO: This is to work around b/24465209. Remove after root cause is fixed
+            ldflags: ["-Wl,--hash-style=both"],
+
+            shared: {
+                srcs: ["arch-arm/bionic/exidx_dynamic.c"],
+            },
+            static: {
+                srcs: ["arch-arm/bionic/exidx_static.c"],
+            },
+            cflags: ["-DCRT_LEGACY_WORKAROUND"],
+            srcs: [
+                "arch-arm/bionic/atexit_legacy.c",
+            ],
+        },
+        x86: {
+            //TODO: This is to work around b/24465209. Remove after root cause is fixed
+            ldflags: ["-Wl,--hash-style=both"],
+        },
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+}
+
+// For all builds, except for the -user build we will enable memory
+// allocation checking (including memory leaks, buffer overwrites, etc.)
+// Note that all these checks are also controlled by env. settings
+// that can enable, or disable specific checks. Note also that some of
+// the checks are available only in emulator and are implemeted in
+// libc_malloc_qemu_instrumented.so.
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// ifneq ($(TARGET_BUILD_VARIANT),user)
+// ========================================================
+// libc_malloc_debug_leak.so
+// ========================================================
+cc_library_shared {
+    cflags: libc_common_cflags,
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+
+    srcs: [
+        "bionic/debug_backtrace.cpp",
+        "bionic/debug_mapinfo.cpp",
+        "bionic/libc_logging.cpp",
+        "bionic/malloc_debug_leak.cpp",
+        "bionic/malloc_debug_check.cpp",
+    ],
+
+    name: "libc_malloc_debug_leak",
+
+    shared_libs: [
+        "libc",
+        "libdl",
+    ],
+    stl: "none",
+    system_shared_libs: [],
+    // Only need this for arm since libc++ uses its own unwind code that
+    // doesn't mix with the other default unwind code.
+    arch: {
+        arm: {
+            static_libs: [
+                "libunwind_llvm",
+                "libc++abi",
+            ],
+            ldflags: ["-Wl,--exclude-libs,libunwind_llvm.a"],
+        },
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+    allow_undefined_symbols: true,
+
+    // Don't re-export new/delete and friends, even if the compiler really wants to.
+    version_script: "version_script.txt",
+
+    // Don't install on release build
+    tags: [
+        "eng",
+        "debug",
+    ],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+}
+
+// ========================================================
+// libc_malloc_debug_qemu.so
+// ========================================================
+cc_library_shared {
+    cflags: libc_common_cflags + ["-DMALLOC_QEMU_INSTRUMENT"],
+
+    conlyflags: libc_common_conlyflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+
+    srcs: [
+        "bionic/libc_logging.cpp",
+        "bionic/malloc_debug_qemu.cpp",
+    ],
+
+    name: "libc_malloc_debug_qemu",
+
+    shared_libs: [
+        "libc",
+        "libdl",
+    ],
+    stl: "none",
+    system_shared_libs: [],
+
+    // Don't re-export new/delete and friends, even if the compiler really wants to.
+    version_script: "version_script.txt",
+
+    // Don't install on release build
+    tags: [
+        "eng",
+        "debug",
+    ],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    arch: {
+        x86_64: {
+            clang: use_clang_x86_64,
+        },
+    },
+}
+
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// endif
+//!user
+
+// ========================================================
+// libstdc++.so + libstdc++.a
+// ========================================================
+cc_library {
+    include_dirs: ["bionic/libstdc++/include"],
+    cflags: libc_common_cflags,
+    cppflags: libc_common_cppflags,
+    product_variables: libc_common_product_variables,
+    srcs: [
+        "bionic/__cxa_guard.cpp",
+        "bionic/__cxa_pure_virtual.cpp",
+        "bionic/new.cpp",
+        "bionic/libc_logging.cpp",
+    ],
+    name: "libstdc++",
+
+    stl: "none",
+    system_shared_libs: ["libc"],
+    sanitize: ["never"],
+    native_coverage: bionic_coverage,
+
+    //TODO: This is to work around b/24465209. Remove after root cause is fixed
+    arch: {
+        arm: {
+            ldflags: ["-Wl,--hash-style=both"],
+        },
+        x86: {
+            ldflags: ["-Wl,--hash-style=both"],
+        },
+    },
+}
+
+crt_arch_flags = {
+    arm: {
+        local_include_dirs: ["arch-arm/include"],
+        cflags: ["-mthumb-interwork"],
+    },
+    arm64: {
+        local_include_dirs: ["arch-arm64/include"],
+    },
+    mips: {
+        local_include_dirs: ["arch-mips/include"],
+        ldflags: ["-melf32ltsmip"],
+    },
+    mips64: {
+        local_include_dirs: ["arch-mips64/include"],
+        ldflags: ["-melf64ltsmip"],
+    },
+    x86: {
+        cflags: ["-m32"],
+        ldflags: ["-melf_i386"],
+        local_include_dirs: ["arch-x86/include"],
+    },
+    x86_64: {
+        cflags: ["-m64"],
+        ldflags: ["-melf_x86_64"],
+        local_include_dirs: ["arch-x86_64/include"],
+    },
+}
+
+crt_arch_so_flags = crt_arch_flags + {
+    mips: {
+        cflags: ["-fPIC"],
+    },
+    mips64: {
+        cflags: ["-fPIC"],
+    },
+    x86: {
+        cflags: ["-fPIC"],
+    },
+    x86_64: {
+        cflags: ["-fPIC"],
+    },
+}
+
+// Android.mk:start
+// # crt obj files
+// # ========================================================
+// # crtbrand.c needs <stdint.h> and a #define for the platform SDK version.
+// libc_crt_target_cflags := \
+//    -I$(LOCAL_PATH)/include \
+//    -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION) \
+//
+// my_2nd_arch_prefix :=
+// include $(LOCAL_PATH)/arch-$(TARGET_ARCH)/$(TARGET_ARCH).mk
+// include $(LOCAL_PATH)/crt.mk
+// ifdef TARGET_2ND_ARCH
+// my_2nd_arch_prefix := $(TARGET_2ND_ARCH_VAR_PREFIX)
+// include $(LOCAL_PATH)/arch-$(TARGET_2ND_ARCH)/$(TARGET_2ND_ARCH).mk
+// include $(LOCAL_PATH)/crt.mk
+// my_2nd_arch_prefix :=
+// endif
+//
+// include $(call all-makefiles-under,$(LOCAL_PATH))
+// Android.mk:end
+cc_object {
+    name: "crtbrand",
+    local_include_dirs: ["include"],
+    product_variables: {
+        platform_sdk_version: {
+            asflags: ["-DPLATFORM_SDK_VERSION=%d"],
+        },
+    },
+    srcs: ["arch-common/bionic/crtbrand.S"],
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_so_flags,
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_so1",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtbegin_so.c"],
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_so_flags,
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_so",
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_so_flags,
+    deps: [
+        "crtbegin_so1",
+        "crtbrand",
+    ],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtend_so",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtend_so.S"],
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_so_flags,
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_static1",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtbegin.c"],
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_flags + {
+        arm64: {
+            srcs: [
+                "arch-arm64/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+        mips: {
+            srcs: [
+                "arch-mips/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+        mips64: {
+            srcs: [
+                "arch-mips64/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+    },
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_static",
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_flags,
+    deps: [
+        "crtbegin_static1",
+        "crtbrand",
+    ],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_dynamic1",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtbegin.c"],
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_flags + {
+        arm64: {
+            srcs: [
+                "arch-arm64/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+        mips: {
+            srcs: [
+                "arch-mips/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+        mips64: {
+            srcs: [
+                "arch-mips64/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+    },
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_dynamic",
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_flags,
+    deps: [
+        "crtbegin_dynamic1",
+        "crtbrand",
+    ],
+}
+
+// Android.mk:ignore
+cc_object {
+    // We rename crtend.o to crtend_android.o to avoid a
+    // name clash between gcc and bionic.
+    name: "crtend_android",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtend.S"],
+    no_default_compiler_flags: true,
+
+    arch: crt_arch_flags,
+}
diff --git a/libc/Android.mk b/libc/Android.mk
index 4b98ee7..140ec82 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -1,6 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 
-bionic_coverage := false
+bionic_coverage ?= false
 
 # Make everything depend on any changes to included makefiles.
 libc_common_additional_dependencies := $(LOCAL_PATH)/Android.mk
@@ -59,6 +59,7 @@
     bionic/system_properties_compat.c \
     stdio/findfp.c \
     stdio/fread.c \
+    stdio/refill.c \
     stdio/snprintf.c\
     stdio/sprintf.c \
     stdio/stdio.c \
@@ -104,6 +105,7 @@
     bionic/accept.cpp \
     bionic/accept4.cpp \
     bionic/access.cpp \
+    bionic/arpa_inet.cpp \
     bionic/assert.cpp \
     bionic/atof.cpp \
     bionic/bionic_systrace.cpp \
@@ -250,10 +252,11 @@
 # dereferences.
 libc_bionic_src_files += bionic/getauxval.cpp
 
-# These three require getauxval, which isn't available on older platforms.
+# These four require getauxval, which isn't available on older platforms.
 libc_bionic_src_files += bionic/getentropy_linux.c
 libc_bionic_src_files += bionic/sysconf.cpp
 libc_bionic_src_files += bionic/vdso.cpp
+libc_bionic_src_files += bionic/setjmp_cookie.cpp
 
 libc_cxa_src_files := \
     bionic/__cxa_guard.cpp \
@@ -264,12 +267,7 @@
     upstream-freebsd/lib/libc/gen/ldexp.c \
     upstream-freebsd/lib/libc/gen/sleep.c \
     upstream-freebsd/lib/libc/gen/usleep.c \
-    upstream-freebsd/lib/libc/stdlib/abs.c \
     upstream-freebsd/lib/libc/stdlib/getopt_long.c \
-    upstream-freebsd/lib/libc/stdlib/imaxabs.c \
-    upstream-freebsd/lib/libc/stdlib/imaxdiv.c \
-    upstream-freebsd/lib/libc/stdlib/labs.c \
-    upstream-freebsd/lib/libc/stdlib/llabs.c \
     upstream-freebsd/lib/libc/stdlib/qsort.c \
     upstream-freebsd/lib/libc/stdlib/quick_exit.c \
     upstream-freebsd/lib/libc/stdlib/realpath.c \
@@ -317,6 +315,7 @@
     upstream-netbsd/lib/libc/stdlib/nrand48.c \
     upstream-netbsd/lib/libc/stdlib/_rand48.c \
     upstream-netbsd/lib/libc/stdlib/rand_r.c \
+    upstream-netbsd/lib/libc/stdlib/reallocarr.c \
     upstream-netbsd/lib/libc/stdlib/seed48.c \
     upstream-netbsd/lib/libc/stdlib/srand48.c \
     upstream-netbsd/lib/libc/string/memccpy.c \
@@ -351,7 +350,7 @@
     $(libc_upstream_openbsd_gdtoa_src_files) \
     upstream-openbsd/lib/libc/gdtoa/strtorQ.c \
 
-# These two depend on getentropy_linux.cpp, which isn't in libc_ndk.a.
+# These two depend on getentropy_linux.c, which isn't in libc_ndk.a.
 libc_upstream_openbsd_src_files := \
     upstream-openbsd/lib/libc/crypt/arc4random.c \
     upstream-openbsd/lib/libc/crypt/arc4random_uniform.c \
@@ -398,11 +397,9 @@
     upstream-openbsd/lib/libc/locale/wctomb.c \
     upstream-openbsd/lib/libc/net/htonl.c \
     upstream-openbsd/lib/libc/net/htons.c \
-    upstream-openbsd/lib/libc/net/inet_addr.c \
     upstream-openbsd/lib/libc/net/inet_lnaof.c \
     upstream-openbsd/lib/libc/net/inet_makeaddr.c \
     upstream-openbsd/lib/libc/net/inet_netof.c \
-    upstream-openbsd/lib/libc/net/inet_network.c \
     upstream-openbsd/lib/libc/net/inet_ntoa.c \
     upstream-openbsd/lib/libc/net/inet_ntop.c \
     upstream-openbsd/lib/libc/net/inet_pton.c \
@@ -462,7 +459,6 @@
     upstream-openbsd/lib/libc/stdio/puts.c \
     upstream-openbsd/lib/libc/stdio/putwc.c \
     upstream-openbsd/lib/libc/stdio/putwchar.c \
-    upstream-openbsd/lib/libc/stdio/refill.c \
     upstream-openbsd/lib/libc/stdio/remove.c \
     upstream-openbsd/lib/libc/stdio/rewind.c \
     upstream-openbsd/lib/libc/stdio/rget.c \
@@ -496,11 +492,16 @@
     upstream-openbsd/lib/libc/stdio/wprintf.c \
     upstream-openbsd/lib/libc/stdio/wscanf.c \
     upstream-openbsd/lib/libc/stdio/wsetup.c \
+    upstream-openbsd/lib/libc/stdlib/abs.c \
     upstream-openbsd/lib/libc/stdlib/atoi.c \
     upstream-openbsd/lib/libc/stdlib/atol.c \
     upstream-openbsd/lib/libc/stdlib/atoll.c \
     upstream-openbsd/lib/libc/stdlib/getenv.c \
     upstream-openbsd/lib/libc/stdlib/insque.c \
+    upstream-openbsd/lib/libc/stdlib/imaxabs.c \
+    upstream-openbsd/lib/libc/stdlib/imaxdiv.c \
+    upstream-openbsd/lib/libc/stdlib/labs.c \
+    upstream-openbsd/lib/libc/stdlib/llabs.c \
     upstream-openbsd/lib/libc/stdlib/lsearch.c \
     upstream-openbsd/lib/libc/stdlib/reallocarray.c \
     upstream-openbsd/lib/libc/stdlib/remque.c \
@@ -686,11 +687,13 @@
 
 LOCAL_CFLAGS := $(libc_common_cflags) \
     -fvisibility=hidden \
+    -Wno-unused-parameter \
 
 # Don't use ridiculous amounts of stack.
 LOCAL_CFLAGS += -DALL_STATE
 # Include tzsetwall, timelocal, timegm, time2posix, and posix2time.
 LOCAL_CFLAGS += -DSTD_INSPIRED
+LOCAL_CFLAGS += -DTHREAD_SAFE
 # The name of the tm_gmtoff field in our struct tm.
 LOCAL_CFLAGS += -DTM_GMTOFF=tm_gmtoff
 # Where we store our tzdata.
@@ -1385,7 +1388,11 @@
 # compatibility.
 LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
 
-# TODO: This is to work around b/19059885. Remove after root cause is fixed
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
+
+# TODO: This is to work around b/24465209. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
 LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
 
@@ -1453,6 +1460,10 @@
 # Don't re-export new/delete and friends, even if the compiler really wants to.
 LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
 
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
+
 # Don't install on release build
 LOCAL_MODULE_TAGS := eng debug
 LOCAL_SANITIZE := never
@@ -1493,6 +1504,10 @@
 # Don't re-export new/delete and friends, even if the compiler really wants to.
 LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
 
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
+
 # Don't install on release build
 LOCAL_MODULE_TAGS := eng debug
 LOCAL_SANITIZE := never
@@ -1517,7 +1532,7 @@
 LOCAL_CFLAGS := $(libc_common_cflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 
-# TODO: This is to work around b/19059885. Remove after root cause is fixed
+# TODO: This is to work around b/24465209. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
 LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
 
diff --git a/libc/arch-arm/bionic/__restore.S b/libc/arch-arm/bionic/__restore.S
index 9898125..8c1e41d 100644
--- a/libc/arch-arm/bionic/__restore.S
+++ b/libc/arch-arm/bionic/__restore.S
@@ -34,7 +34,9 @@
 // __restore_rt (but covered by the .fnstart/.fnend) so that although they're
 // not inside the functions from objdump's point of view, an unwinder that
 // blindly looks at the previous instruction (but is then smart enough to check
-// the DWARF information to find out where it landed) gets the right answer.
+// the unwind information to find out where it landed) gets the right answer.
+// Make sure not to have both DWARF and ARM unwind information, so only
+// use the ARM unwind information.
 
 // We need to place .fnstart ourselves (but we may as well keep the free .fnend).
 #undef __bionic_asm_custom_entry
@@ -44,18 +46,18 @@
   .save {r0-r15}
   .pad #32
   nop
-ENTRY_PRIVATE(__restore)
+ENTRY_PRIVATE_NO_DWARF(__restore)
   // This function must have exactly this instruction sequence.
   mov r7, #__NR_sigreturn
   swi #0
-END(__restore)
+END_NO_DWARF(__restore)
 
   .fnstart
   .save {r0-r15}
   .pad #160
   nop
-ENTRY_PRIVATE(__restore_rt)
+ENTRY_PRIVATE_NO_DWARF(__restore_rt)
   // This function must have exactly this instruction sequence.
   mov r7, #__NR_rt_sigreturn
   swi #0
-END(__restore_rt)
+END_NO_DWARF(__restore_rt)
diff --git a/libc/arch-arm/bionic/setjmp.S b/libc/arch-arm/bionic/setjmp.S
index 8220c08..a119529 100644
--- a/libc/arch-arm/bionic/setjmp.S
+++ b/libc/arch-arm/bionic/setjmp.S
@@ -51,13 +51,13 @@
 // The internal structure of a jmp_buf is totally private.
 // Current layout (may change in the future):
 //
-// word   name         description
-// 0      magic        magic number
-// 1      sigmask      signal mask (not used with _setjmp / _longjmp)
-// 2      float_base   base of float registers (d8 to d15)
-// 18     float_state  floating-point status and control register
-// 19     core_base    base of core registers (r4 to r14)
-// 30     reserved     reserved entries (room to grow)
+// word   name            description
+// 0      sigflag/cookie  setjmp cookie in top 31 bits, signal mask flag in low bit
+// 1      sigmask         signal mask (not used with _setjmp / _longjmp)
+// 2      float_base      base of float registers (d8 to d15)
+// 18     float_state     floating-point status and control register
+// 19     core_base       base of core registers (r4 to r14)
+// 30     reserved        reserved entries (room to grow)
 // 64
 //
 // NOTE: float_base must be at an even word index, since the
@@ -80,33 +80,79 @@
   b sigsetjmp
 END(_setjmp)
 
+#define MANGLE_REGISTERS 1
+.macro m_mangle_registers reg
+#if MANGLE_REGISTERS
+  eor r4, r4, \reg
+  eor r5, r5, \reg
+  eor r6, r6, \reg
+  eor r7, r7, \reg
+  eor r8, r8, \reg
+  eor r9, r9, \reg
+  eor r10, r10, \reg
+  eor r11, r11, \reg
+  eor r12, r12, \reg
+  eor r13, r13, \reg
+  eor r14, r14, \reg
+#endif
+.endm
+
+.macro m_unmangle_registers reg
+  m_mangle_registers \reg
+.endm
+
 // int sigsetjmp(sigjmp_buf env, int save_signal_mask);
 ENTRY(sigsetjmp)
-  // Record whether or not we're saving the signal mask.
+  stmfd sp!, {r0, lr}
+  .cfi_def_cfa_offset 8
+  .cfi_rel_offset r0, 0
+  .cfi_rel_offset lr, 4
+
+  mov r0, r1
+  bl __bionic_setjmp_cookie_get
+  mov r1, r0
+
+  ldmfd sp, {r0}
+
+  // Save the setjmp cookie for later.
+  bic r2, r1, #1
+  stmfd sp!, {r2}
+  .cfi_adjust_cfa_offset 4
+
+  // Record the setjmp cookie and whether or not we're saving the signal mask.
   str r1, [r0, #(_JB_SIGFLAG * 4)]
 
   // Do we need to save the signal mask?
-  teq r1, #0
+  tst r1, #1
   beq 1f
 
-  // Get current signal mask.
-  stmfd sp!, {r0, r14}
-  .cfi_def_cfa_offset 8
-  .cfi_rel_offset r0, 0
-  .cfi_rel_offset r14, 4
-  mov r0, #0
-  bl sigblock
-  mov r1, r0
-  ldmfd sp!, {r0, r14}
-  .cfi_def_cfa_offset 0
+  // Align the stack.
+  sub sp, #4
+  .cfi_adjust_cfa_offset 4
 
-  // Save the signal mask.
-  str r1, [r0, #(_JB_SIGMASK * 4)]
+  // Save the current signal mask.
+  add r2, r0, #(_JB_SIGMASK * 4)
+  mov r0, #2 // SIG_SETMASK
+  mov r1, #0
+  bl sigprocmask
+
+  // Unalign the stack.
+  add sp, #4
+  .cfi_adjust_cfa_offset -4
 
 1:
+  ldmfd sp!, {r2}
+  .cfi_adjust_cfa_offset -4
+  ldmfd sp!, {r0, lr}
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore r0
+  .cfi_restore lr
+
   // Save core registers.
   add r1, r0, #(_JB_CORE_BASE * 4)
+  m_mangle_registers r2
   stmia r1, {r4-r14}
+  m_unmangle_registers r2
 
   // Save floating-point registers.
   add r1, r0, #(_JB_FLOAT_BASE * 4)
@@ -122,29 +168,30 @@
 
 // void siglongjmp(sigjmp_buf env, int value);
 ENTRY(siglongjmp)
-  // Do we need to restore the signal mask?
-  ldr r2, [r0, #(_JB_SIGFLAG * 4)]
-  teq r2, #0
-  beq 1f
-
-  // Restore the signal mask.
-  stmfd sp!, {r0, r1, r14}
+  stmfd sp!, {r0, r1, lr}
   .cfi_def_cfa_offset 12
   .cfi_rel_offset r0, 0
   .cfi_rel_offset r1, 4
-  .cfi_rel_offset r14, 8
-  sub sp, sp, #4 // Align the stack.
-  .cfi_adjust_cfa_offset 4
+  .cfi_rel_offset lr, 8
 
+  // Fetch the signal flag.
+  ldr r1, [r0, #(_JB_SIGFLAG * 4)]
+
+  // Do we need to restore the signal mask?
+  ands r1, r1, #1
+  beq 1f
+
+  // Restore the signal mask.
   ldr r0, [r0, #(_JB_SIGMASK * 4)]
   bl sigsetmask
 
-  add sp, sp, #4 // Unalign the stack.
-  .cfi_adjust_cfa_offset -4
-  ldmfd sp!, {r0, r1, r14}
-  .cfi_def_cfa_offset 0
-
 1:
+  ldmfd sp!, {r0, r1, lr}
+  .cfi_adjust_cfa_offset -12
+  .cfi_restore r0
+  .cfi_restore r1
+  .cfi_restore lr
+
   // Restore floating-point registers.
   add r2, r0, #(_JB_FLOAT_BASE * 4)
   vldmia r2, {d8-d15}
@@ -154,16 +201,24 @@
   fmxr fpscr, r2
 
   // Restore core registers.
+  ldr r3, [r0, #(_JB_SIGFLAG * 4)]
+  bic r3, r3, #1
   add r2, r0, #(_JB_CORE_BASE * 4)
   ldmia r2, {r4-r14}
+  m_unmangle_registers r3
 
-  // Validate sp and r14.
-  teq sp, #0
-  teqne r14, #0
-  bleq longjmperror
+  // Save the return value/address and check the setjmp cookie.
+  stmfd sp!, {r1, lr}
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset lr, 4
+  mov r0, r3
+  bl __bionic_setjmp_cookie_check
 
-  // Set return value.
-  mov r0, r1
+  // Restore return value/address.
+  ldmfd sp!, {r0, lr}
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore lr
+
   teq r0, #0
   moveq r0, #1
   bx lr
diff --git a/libc/arch-arm/cortex-a15/bionic/strcat.S b/libc/arch-arm/cortex-a15/bionic/strcat.S
index b174aa9..157cc9f 100644
--- a/libc/arch-arm/cortex-a15/bionic/strcat.S
+++ b/libc/arch-arm/cortex-a15/bionic/strcat.S
@@ -169,13 +169,20 @@
 .L_strcpy_align_to_64:
     tst     r3, #4
     beq     .L_strcpy_check_src_align
-    ldr     r2, [r1], #4
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .L_strcpy_zero_in_first_register
-    str     r2, [r0], #4
+    // Read one byte at a time since we don't know the src alignment
+    // and we don't want to read into a different page.
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .L_strcpy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .L_strcpy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .L_strcpy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .L_strcpy_complete
 
 .L_strcpy_check_src_align:
     // At this point dst is aligned to a double word, check if src
diff --git a/libc/arch-arm/cortex-a15/bionic/string_copy.S b/libc/arch-arm/cortex-a15/bionic/string_copy.S
index 20f0e91..92d1c98 100644
--- a/libc/arch-arm/cortex-a15/bionic/string_copy.S
+++ b/libc/arch-arm/cortex-a15/bionic/string_copy.S
@@ -149,13 +149,20 @@
 .Lstringcopy_align_to_64:
     tst     r3, #4
     beq     .Lstringcopy_check_src_align
-    ldr     r2, [r1], #4
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .Lstringcopy_zero_in_first_register
-    str     r2, [r0], #4
+    // Read one byte at a time since we don't have any idea about the alignment
+    // of the source and we don't want to read into a different page.
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
 
 .Lstringcopy_check_src_align:
     // At this point dst is aligned to a double word, check if src
diff --git a/libc/arch-arm/cortex-a53.a57/cortex-a53.a57.mk b/libc/arch-arm/cortex-a53.a57/cortex-a53.a57.mk
new file mode 100644
index 0000000..0eec165
--- /dev/null
+++ b/libc/arch-arm/cortex-a53.a57/cortex-a53.a57.mk
@@ -0,0 +1,21 @@
+# This file represents the best optimized routines that are the middle
+# ground when running on a big/little system that is cortex-a57/cortex-a53.
+# The cortex-a7 optimized routines, and the cortex-a53 optimized routines
+# decrease performance on cortex-a57 processors by as much as 20%.
+
+libc_bionic_src_files_arm += \
+    arch-arm/cortex-a15/bionic/memcpy.S \
+    arch-arm/cortex-a15/bionic/memset.S \
+    arch-arm/cortex-a15/bionic/stpcpy.S \
+    arch-arm/cortex-a15/bionic/strcat.S \
+    arch-arm/cortex-a15/bionic/__strcat_chk.S \
+    arch-arm/cortex-a15/bionic/strcmp.S \
+    arch-arm/cortex-a15/bionic/strcpy.S \
+    arch-arm/cortex-a15/bionic/__strcpy_chk.S \
+    arch-arm/cortex-a15/bionic/strlen.S \
+
+libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memcmp.S \
+
+libc_bionic_src_files_arm += \
+    arch-arm/denver/bionic/memmove.S \
diff --git a/libc/arch-arm/cortex-a9/bionic/strcat.S b/libc/arch-arm/cortex-a9/bionic/strcat.S
index f5a855e..9077a74 100644
--- a/libc/arch-arm/cortex-a9/bionic/strcat.S
+++ b/libc/arch-arm/cortex-a9/bionic/strcat.S
@@ -70,7 +70,7 @@
 
     .macro m_scan_byte
     ldrb    r3, [r0]
-    cbz     r3, strcat_r0_scan_done
+    cbz     r3, .Lstrcat_r0_scan_done
     add     r0, #1
     .endm // m_scan_byte
 
@@ -84,10 +84,10 @@
     // Quick check to see if src is empty.
     ldrb        r2, [r1]
     pld         [r1, #0]
-    cbnz        r2, strcat_continue
+    cbnz        r2, .Lstrcat_continue
     bx          lr
 
-strcat_continue:
+.Lstrcat_continue:
     // To speed up really small dst strings, unroll checking the first 4 bytes.
     m_push
     m_scan_byte
@@ -96,10 +96,10 @@
     m_scan_byte
 
     ands    r3, r0, #7
-    bne     strcat_align_src
+    bne     .Lstrcat_align_src
 
     .p2align 2
-strcat_mainloop:
+.Lstrcat_mainloop:
     ldmia   r0!, {r2, r3}
 
     pld     [r0, #64]
@@ -107,28 +107,28 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_first_register
+    bne     .Lstrcat_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_second_register
-    b       strcat_mainloop
+    bne     .Lstrcat_zero_in_second_register
+    b       .Lstrcat_mainloop
 
-strcat_zero_in_first_register:
+.Lstrcat_zero_in_first_register:
     sub     r0, r0, #4
 
-strcat_zero_in_second_register:
+.Lstrcat_zero_in_second_register:
     // Check for zero in byte 0.
     tst     ip, #0x80
     it      ne
     subne   r0, r0, #4
-    bne     strcat_r0_scan_done
+    bne     .Lstrcat_r0_scan_done
     // Check for zero in byte 1.
     tst     ip, #0x8000
     it      ne
     subne   r0, r0, #3
-    bne     strcat_r0_scan_done
+    bne     .Lstrcat_r0_scan_done
     // Check for zero in byte 2.
     tst     ip, #0x800000
     it      ne
@@ -137,33 +137,33 @@
     // Zero is in byte 3.
     subeq   r0, r0, #1
 
-strcat_r0_scan_done:
+.Lstrcat_r0_scan_done:
     // Unroll the first 8 bytes that will be copied.
-    m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
+    m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r5, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r5, cmd=cbnz, label=.Lstrcpy_continue
 
-strcpy_finish:
+.Lstrcpy_finish:
     m_ret   inst=pop
 
-strcpy_continue:
+.Lstrcpy_continue:
     pld     [r1, #0]
     ands    r3, r0, #7
-    bne     strcpy_align_dst
+    bne     .Lstrcpy_align_dst
 
-strcpy_check_src_align:
+.Lstrcpy_check_src_align:
     // At this point dst is aligned to a double word, check if src
     // is also aligned to a double word.
     ands    r3, r1, #7
-    bne     strcpy_unaligned_copy
+    bne     .Lstrcpy_unaligned_copy
 
     .p2align 2
-strcpy_mainloop:
+.Lstrcpy_mainloop:
     ldmia   r1!, {r2, r3}
 
     pld     [r1, #64]
@@ -171,17 +171,17 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_mainloop
+    b       .Lstrcpy_mainloop
 
-strcpy_zero_in_first_register:
+.Lstrcpy_zero_in_first_register:
     lsls    lr, ip, #17
     itt     ne
     strbne  r2, [r0]
@@ -198,7 +198,7 @@
     strb    r3, [r0]
     m_ret   inst=pop
 
-strcpy_zero_in_second_register:
+.Lstrcpy_zero_in_second_register:
     lsls    lr, ip, #17
     ittt    ne
     stmiane r0!, {r2}
@@ -218,18 +218,18 @@
     strb    r4, [r0]
     m_ret   inst=pop
 
-strcpy_align_dst:
+.Lstrcpy_align_dst:
     // Align to a double word (64 bits).
     rsb     r3, r3, #8
     lsls    ip, r3, #31
-    beq     strcpy_align_to_32
+    beq     .Lstrcpy_align_to_32
 
     ldrb    r2, [r1], #1
     strb    r2, [r0], #1
-    cbz     r2, strcpy_complete
+    cbz     r2, .Lstrcpy_complete
 
-strcpy_align_to_32:
-    bcc     strcpy_align_to_64
+.Lstrcpy_align_to_32:
+    bcc     .Lstrcpy_align_to_64
 
     ldrb    r4, [r1], #1
     strb    r4, [r0], #1
@@ -242,76 +242,83 @@
     it      eq
     m_ret   inst=popeq
 
-strcpy_align_to_64:
+.Lstrcpy_align_to_64:
     tst     r3, #4
-    beq     strcpy_check_src_align
-    ldr     r2, [r1], #4
+    beq     .Lstrcpy_check_src_align
+    // Read one byte at a time since we don't know the src alignment
+    // and we don't want to read into a different page.
+    ldrb    r4, [r1], #1
+    strb    r4, [r0], #1
+    cbz     r4, .Lstrcpy_complete
+    ldrb    r5, [r1], #1
+    strb    r5, [r0], #1
+    cbz     r5, .Lstrcpy_complete
+    ldrb    r4, [r1], #1
+    strb    r4, [r0], #1
+    cbz     r4, .Lstrcpy_complete
+    ldrb    r5, [r1], #1
+    strb    r5, [r0], #1
+    cbz     r5, .Lstrcpy_complete
+    b       .Lstrcpy_check_src_align
 
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
-    stmia   r0!, {r2}
-    b       strcpy_check_src_align
-
-strcpy_complete:
+.Lstrcpy_complete:
     m_ret   inst=pop
 
-strcpy_unaligned_copy:
+.Lstrcpy_unaligned_copy:
     // Dst is aligned to a double word, while src is at an unknown alignment.
     // There are 7 different versions of the unaligned copy code
     // to prevent overreading the src. The mainloop of every single version
     // will store 64 bits per loop. The difference is how much of src can
     // be read without potentially crossing a page boundary.
     tbb     [pc, r3]
-strcpy_unaligned_branchtable:
+.Lstrcpy_unaligned_branchtable:
     .byte 0
-    .byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign7 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign6 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign5 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign4 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign3 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign2 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign1 - .Lstrcpy_unaligned_branchtable)/2)
 
     .p2align 2
     // Can read 7 bytes before possibly crossing a page.
-strcpy_unalign7:
+.Lstrcpy_unalign7:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     ldrb    r3, [r1]
-    cbz     r3, strcpy_unalign7_copy5bytes
+    cbz     r3, .Lstrcpy_unalign7_copy5bytes
     ldrb    r4, [r1, #1]
-    cbz     r4, strcpy_unalign7_copy6bytes
+    cbz     r4, .Lstrcpy_unalign7_copy6bytes
     ldrb    r5, [r1, #2]
-    cbz     r5, strcpy_unalign7_copy7bytes
+    cbz     r5, .Lstrcpy_unalign7_copy7bytes
 
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     lsrs    ip, r3, #24
     stmia   r0!, {r2, r3}
-    beq     strcpy_unalign_return
-    b       strcpy_unalign7
+    beq     .Lstrcpy_unalign_return
+    b       .Lstrcpy_unalign7
 
-strcpy_unalign7_copy5bytes:
+.Lstrcpy_unalign7_copy5bytes:
     stmia   r0!, {r2}
     strb    r3, [r0]
-strcpy_unalign_return:
+.Lstrcpy_unalign_return:
     m_ret   inst=pop
 
-strcpy_unalign7_copy6bytes:
+.Lstrcpy_unalign7_copy6bytes:
     stmia   r0!, {r2}
     strb    r3, [r0], #1
     strb    r4, [r0], #1
     m_ret   inst=pop
 
-strcpy_unalign7_copy7bytes:
+.Lstrcpy_unalign7_copy7bytes:
     stmia   r0!, {r2}
     strb    r3, [r0], #1
     strb    r4, [r0], #1
@@ -320,30 +327,30 @@
 
     .p2align 2
     // Can read 6 bytes before possibly crossing a page.
-strcpy_unalign6:
+.Lstrcpy_unalign6:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     ldrb    r4, [r1]
-    cbz     r4, strcpy_unalign_copy5bytes
+    cbz     r4, .Lstrcpy_unalign_copy5bytes
     ldrb    r5, [r1, #1]
-    cbz     r5, strcpy_unalign_copy6bytes
+    cbz     r5, .Lstrcpy_unalign_copy6bytes
 
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     tst     r3, #0xff0000
-    beq     strcpy_unalign6_copy7bytes
+    beq     .Lstrcpy_unalign6_copy7bytes
     lsrs    ip, r3, #24
     stmia   r0!, {r2, r3}
-    beq     strcpy_unalign_return
-    b       strcpy_unalign6
+    beq     .Lstrcpy_unalign_return
+    b       .Lstrcpy_unalign6
 
-strcpy_unalign6_copy7bytes:
+.Lstrcpy_unalign6_copy7bytes:
     stmia   r0!, {r2}
     strh    r3, [r0], #2
     lsr     r3, #16
@@ -352,16 +359,16 @@
 
     .p2align 2
     // Can read 5 bytes before possibly crossing a page.
-strcpy_unalign5:
+.Lstrcpy_unalign5:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     ldrb    r4, [r1]
-    cbz     r4, strcpy_unalign_copy5bytes
+    cbz     r4, .Lstrcpy_unalign_copy5bytes
 
     ldr     r3, [r1], #4
 
@@ -370,17 +377,17 @@
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign5
+    b       .Lstrcpy_unalign5
 
-strcpy_unalign_copy5bytes:
+.Lstrcpy_unalign_copy5bytes:
     stmia   r0!, {r2}
     strb    r4, [r0]
     m_ret   inst=pop
 
-strcpy_unalign_copy6bytes:
+.Lstrcpy_unalign_copy6bytes:
     stmia   r0!, {r2}
     strb    r4, [r0], #1
     strb    r5, [r0]
@@ -388,13 +395,13 @@
 
     .p2align 2
     // Can read 4 bytes before possibly crossing a page.
-strcpy_unalign4:
+.Lstrcpy_unalign4:
     ldmia   r1!, {r2}
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     ldmia   r1!, {r3}
     pld     [r1, #64]
@@ -402,20 +409,20 @@
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign4
+    b       .Lstrcpy_unalign4
 
     .p2align 2
     // Can read 3 bytes before possibly crossing a page.
-strcpy_unalign3:
+.Lstrcpy_unalign3:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign3_copy1byte
+    cbz     r2, .Lstrcpy_unalign3_copy1byte
     ldrb    r3, [r1, #1]
-    cbz     r3, strcpy_unalign3_copy2bytes
+    cbz     r3, .Lstrcpy_unalign3_copy2bytes
     ldrb    r4, [r1, #2]
-    cbz     r4, strcpy_unalign3_copy3bytes
+    cbz     r4, .Lstrcpy_unalign3_copy3bytes
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
@@ -423,26 +430,26 @@
     pld     [r1, #64]
 
     lsrs    lr, r2, #24
-    beq     strcpy_unalign_copy4bytes
+    beq     .Lstrcpy_unalign_copy4bytes
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign3
+    b       .Lstrcpy_unalign3
 
-strcpy_unalign3_copy1byte:
+.Lstrcpy_unalign3_copy1byte:
     strb    r2, [r0]
     m_ret   inst=pop
 
-strcpy_unalign3_copy2bytes:
+.Lstrcpy_unalign3_copy2bytes:
     strb    r2, [r0], #1
     strb    r3, [r0]
     m_ret   inst=pop
 
-strcpy_unalign3_copy3bytes:
+.Lstrcpy_unalign3_copy3bytes:
     strb    r2, [r0], #1
     strb    r3, [r0], #1
     strb    r4, [r0]
@@ -450,34 +457,34 @@
 
     .p2align 2
     // Can read 2 bytes before possibly crossing a page.
-strcpy_unalign2:
+.Lstrcpy_unalign2:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign_copy1byte
+    cbz     r2, .Lstrcpy_unalign_copy1byte
     ldrb    r3, [r1, #1]
-    cbz     r3, strcpy_unalign_copy2bytes
+    cbz     r3, .Lstrcpy_unalign_copy2bytes
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     tst     r2, #0xff0000
-    beq     strcpy_unalign_copy3bytes
+    beq     .Lstrcpy_unalign_copy3bytes
     lsrs    ip, r2, #24
-    beq     strcpy_unalign_copy4bytes
+    beq     .Lstrcpy_unalign_copy4bytes
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign2
+    b       .Lstrcpy_unalign2
 
     .p2align 2
     // Can read 1 byte before possibly crossing a page.
-strcpy_unalign1:
+.Lstrcpy_unalign1:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign_copy1byte
+    cbz     r2, .Lstrcpy_unalign_copy1byte
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
@@ -487,62 +494,62 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign1
+    b       .Lstrcpy_unalign1
 
-strcpy_unalign_copy1byte:
+.Lstrcpy_unalign_copy1byte:
     strb    r2, [r0]
     m_ret   inst=pop
 
-strcpy_unalign_copy2bytes:
+.Lstrcpy_unalign_copy2bytes:
     strb    r2, [r0], #1
     strb    r3, [r0]
     m_ret   inst=pop
 
-strcpy_unalign_copy3bytes:
+.Lstrcpy_unalign_copy3bytes:
     strh    r2, [r0], #2
     lsr     r2, #16
     strb    r2, [r0]
     m_ret   inst=pop
 
-strcpy_unalign_copy4bytes:
+.Lstrcpy_unalign_copy4bytes:
     stmia   r0, {r2}
     m_ret   inst=pop
 
-strcat_align_src:
+.Lstrcat_align_src:
     // Align to a double word (64 bits).
     rsb     r3, r3, #8
     lsls    ip, r3, #31
-    beq     strcat_align_to_32
+    beq     .Lstrcat_align_to_32
     ldrb    r2, [r0], #1
-    cbz     r2, strcat_r0_update
+    cbz     r2, .Lstrcat_r0_update
 
-strcat_align_to_32:
-    bcc     strcat_align_to_64
+.Lstrcat_align_to_32:
+    bcc     .Lstrcat_align_to_64
     ldrb    r2, [r0], #1
-    cbz     r2, strcat_r0_update
+    cbz     r2, .Lstrcat_r0_update
     ldrb    r2, [r0], #1
-    cbz     r2, strcat_r0_update
+    cbz     r2, .Lstrcat_r0_update
 
-strcat_align_to_64:
+.Lstrcat_align_to_64:
     tst     r3, #4
-    beq     strcat_mainloop
+    beq     .Lstrcat_mainloop
     ldr     r3, [r0], #4
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_second_register
-    b       strcat_mainloop
+    bne     .Lstrcat_zero_in_second_register
+    b       .Lstrcat_mainloop
 
-strcat_r0_update:
+.Lstrcat_r0_update:
     sub     r0, r0, #1
-    b strcat_r0_scan_done
+    b .Lstrcat_r0_scan_done
 END(strcat)
diff --git a/libc/arch-arm/cortex-a9/bionic/string_copy.S b/libc/arch-arm/cortex-a9/bionic/string_copy.S
index caf5a11..642db0f 100644
--- a/libc/arch-arm/cortex-a9/bionic/string_copy.S
+++ b/libc/arch-arm/cortex-a9/bionic/string_copy.S
@@ -244,13 +244,20 @@
 .Lstringcopy_align_to_64:
     tst     r3, #4
     beq     .Lstringcopy_check_src_align
-    ldr     r2, [r1], #4
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .Lstringcopy_zero_in_first_register
-    stmia   r0!, {r2}
+    // Read one byte at a time since we don't have any idea about the alignment
+    // of the source and we don't want to read into a different page.
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
     b       .Lstringcopy_check_src_align
 
 .Lstringcopy_complete:
diff --git a/libc/arch-arm/krait/bionic/__strcat_chk.S b/libc/arch-arm/krait/bionic/__strcat_chk.S
index 246f159..1a39c5b 100644
--- a/libc/arch-arm/krait/bionic/__strcat_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
 ENTRY(__strcat_chk)
     pld     [r0, #0]
     push    {r0, lr}
-    .cfi_def_cfa_offset 8
+    .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
     push    {r4, r5}
@@ -177,7 +177,7 @@
 .L_strlen_done:
     add     r2, r3, r4
     cmp     r2, lr
-    bhi     __strcat_chk_failed
+    bhi     .L_strcat_chk_failed
 
     // Set up the registers for the memcpy code.
     mov     r1, r5
@@ -185,20 +185,17 @@
     mov     r2, r4
     add     r0, r0, r3
     pop     {r4, r5}
-END(__strcat_chk)
+    .cfi_adjust_cfa_offset -8
+    .cfi_restore r4
+    .cfi_restore r5
 
-#define MEMCPY_BASE         __strcat_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
 #include "memcpy_base.S"
 
-ENTRY_PRIVATE(__strcat_chk_failed)
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
+    // Undo the above cfi directives.
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
-
+.L_strcat_chk_failed:
     ldr     r0, error_message
     ldr     r1, error_code
 1:
@@ -208,7 +205,7 @@
     .word   BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
 error_message:
     .word   error_string-(1b+4)
-END(__strcat_chk_failed)
+END(__strcat_chk)
 
     .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/__strcpy_chk.S b/libc/arch-arm/krait/bionic/__strcpy_chk.S
index db76686..00202f3 100644
--- a/libc/arch-arm/krait/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
 ENTRY(__strcpy_chk)
     pld     [r0, #0]
     push    {r0, lr}
-    .cfi_def_cfa_offset 8
+    .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
 
@@ -149,21 +149,14 @@
     pld     [r1, #64]
     ldr     r0, [sp]
     cmp     r3, lr
-    bhs     __strcpy_chk_failed
+    bhs     .L_strcpy_chk_failed
 
     // Add 1 for copy length to get the string terminator.
     add     r2, r3, #1
-END(__strcpy_chk)
 
-#define MEMCPY_BASE         __strcpy_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
 #include "memcpy_base.S"
 
-ENTRY_PRIVATE(__strcpy_chk_failed)
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
-
+.L_strcpy_chk_failed:
     ldr     r0, error_message
     ldr     r1, error_code
 1:
@@ -173,7 +166,7 @@
     .word   BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
 error_message:
     .word   error_string-(1b+4)
-END(__strcpy_chk_failed)
+END(__strcpy_chk)
 
     .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/memcpy.S b/libc/arch-arm/krait/bionic/memcpy.S
index 9ff46a8..5d27b57 100644
--- a/libc/arch-arm/krait/bionic/memcpy.S
+++ b/libc/arch-arm/krait/bionic/memcpy.S
@@ -45,7 +45,7 @@
 
 ENTRY(__memcpy_chk)
         cmp         r2, r3
-        bhi         __memcpy_chk_fail
+        bhi         .L_memcpy_chk_fail
 
         // Fall through to memcpy...
 END(__memcpy_chk)
@@ -53,19 +53,20 @@
 ENTRY(memcpy)
         pld     [r1, #64]
         stmfd   sp!, {r0, lr}
-        .cfi_def_cfa_offset 8
+        .cfi_adjust_cfa_offset 8
         .cfi_rel_offset r0, 0
         .cfi_rel_offset lr, 4
-END(memcpy)
 
-#define MEMCPY_BASE         __memcpy_base
-#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
 #include "memcpy_base.S"
 
-ENTRY_PRIVATE(__memcpy_chk_fail)
+        // Undo the cfi directives from above.
+        .cfi_adjust_cfa_offset -8
+        .cfi_restore r0
+        .cfi_restore lr
+.L_memcpy_chk_fail:
         // Preserve lr for backtrace.
         push    {lr}
-        .cfi_def_cfa_offset 4
+        .cfi_adjust_cfa_offset 4
         .cfi_rel_offset lr, 0
 
         ldr     r0, error_message
@@ -77,7 +78,7 @@
         .word   BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
 error_message:
         .word   error_string-(1b+4)
-END(__memcpy_chk_fail)
+END(memcpy)
 
         .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/memcpy_base.S b/libc/arch-arm/krait/bionic/memcpy_base.S
index 6c098ac..76c5a84 100644
--- a/libc/arch-arm/krait/bionic/memcpy_base.S
+++ b/libc/arch-arm/krait/bionic/memcpy_base.S
@@ -1,122 +1,191 @@
-/*
- * Copyright (C) 2013 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.
- */
+/***************************************************************************
+ Copyright (c) 2009-2013 The Linux Foundation. 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 The Linux Foundation nor the names of its contributors may
+       be used to endorse or promote products derived from this software
+       without specific prior written permission.
 
-/*
- * This code assumes it is running on a processor that supports all arm v7
- * instructions, that supports neon instructions, and that has a 32 byte
- * cache line.
- */
+ 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.
+  ***************************************************************************/
 
-// Assumes neon instructions and a cache line size of 32 bytes.
+/* Assumes neon instructions and a cache line size of 64 bytes. */
 
-ENTRY_PRIVATE(MEMCPY_BASE)
-        .cfi_def_cfa_offset 8
-        .cfi_rel_offset r0, 0
-        .cfi_rel_offset lr, 4
+#include <machine/cpu-features.h>
+#include <machine/asm.h>
 
-        /* do we have at least 16-bytes to copy (needed for alignment below) */
-        cmp         r2, #16
-        blo         5f
+#define PLDOFFS	(10)
+#define PLDTHRESH (PLDOFFS)
+#define BBTHRESH (4096/64)
+#define PLDSIZE (64)
 
-        /* align destination to cache-line for the write-buffer */
-        rsb         r3, r0, #0
-        ands        r3, r3, #0xF
-        beq         2f
+#if (PLDOFFS < 1)
+#error Routine does not support offsets less than 1
+#endif
 
-        /* copy up to 15-bytes (count in r3) */
-        sub         r2, r2, r3
-        movs        ip, r3, lsl #31
-        itt         mi
-        ldrbmi      lr, [r1], #1
-        strbmi      lr, [r0], #1
-        itttt       cs
-        ldrbcs      ip, [r1], #1
-        ldrbcs      lr, [r1], #1
-        strbcs      ip, [r0], #1
-        strbcs      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]!
+#if (PLDTHRESH < PLDOFFS)
+#error PLD threshold must be greater than or equal to the PLD offset
+#endif
 
-2:      /* make sure we have at least 64 bytes to copy */
-        subs        r2, r2, #64
-        blo         2f
+	.text
+	.fpu    neon
 
-1:      /* The main loop copies 64 bytes at a time */
-        vld1.8      {d0  - d3},   [r1]!
-        vld1.8      {d4  - d7},   [r1]!
-        pld         [r1, #(32*8)]
-        subs        r2, r2, #64
-        vst1.8      {d0  - d3},   [r0, :128]!
-        vst1.8      {d4  - d7},   [r0, :128]!
-        bhs         1b
+.L_memcpy_base:
+	cmp	r2, #4
+	blt	.L_neon_lt4
+	cmp	r2, #16
+	blt	.L_neon_lt16
+	cmp	r2, #32
+	blt	.L_neon_16
+	cmp	r2, #64
+	blt	.L_neon_copy_32_a
 
-2:      /* fix-up the remaining count and make sure we have >= 32 bytes left */
-        adds        r2, r2, #32
-        blo         4f
+	mov	r12, r2, lsr #6
+	cmp	r12, #PLDTHRESH
+	ble	.L_neon_copy_64_loop_nopld
 
-        /* Copy 32 bytes. These cache lines were already preloaded */
-        vld1.8      {d0 - d3},  [r1]!
-        sub         r2, r2, #32
-        vst1.8      {d0 - d3},  [r0, :128]!
+	push	{r9, r10}
+	.cfi_adjust_cfa_offset 8
+	.cfi_rel_offset r9, 0
+	.cfi_rel_offset r10, 4
 
-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]!
+	cmp	r12, #BBTHRESH
+	ble	.L_neon_prime_pump
 
-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
-        itt         mi
-        ldrbmi      r3, [r1], #1
-        strbmi      r3, [r0], #1
-        itttt       cs
-        ldrbcs      ip, [r1], #1
-        ldrbcs      lr, [r1], #1
-        strbcs      ip, [r0], #1
-        strbcs      lr, [r0], #1
+	add	lr, r0, #0x400
+	add	r9, r1, #(PLDOFFS*PLDSIZE)
+	sub	lr, lr, r9
+	lsl	lr, lr, #21
+	lsr	lr, lr, #21
+	add	lr, lr, #(PLDOFFS*PLDSIZE)
+	cmp	r12, lr, lsr #6
+	ble	.L_neon_prime_pump
 
-        ldmfd       sp!, {r0, pc}
-END(MEMCPY_BASE)
+	itt	gt
+	movgt	r9, #(PLDOFFS)
+	rsbsgt	r9, r9, lr, lsr #6
+	ble	.L_neon_prime_pump
+
+	add	r10, r1, lr
+	bic	r10, #0x3F
+
+	sub	r12, r12, lr, lsr #6
+
+	cmp	r9, r12
+	itee	le
+	suble	r12, r12, r9
+	movgt	r9, r12
+	movgt	r12, #0
+
+	pld	[r1, #((PLDOFFS-1)*PLDSIZE)]
+.L_neon_copy_64_loop_outer_doublepld:
+	pld	[r1, #((PLDOFFS)*PLDSIZE)]
+	vld1.32	{q0, q1}, [r1]!
+	vld1.32	{q2, q3}, [r1]!
+	ldr	r3, [r10]
+	subs	r9, r9, #1
+	vst1.32	{q0, q1}, [r0]!
+	vst1.32	{q2, q3}, [r0]!
+	add	r10, #64
+	bne	.L_neon_copy_64_loop_outer_doublepld
+	cmp	r12, #0
+	beq	.L_neon_pop_before_nopld
+
+	cmp	r12, #(512*1024/64)
+	blt	.L_neon_copy_64_loop_outer
+
+.L_neon_copy_64_loop_ddr:
+	vld1.32	{q0, q1}, [r1]!
+	vld1.32	{q2, q3}, [r1]!
+	pld	[r10]
+	subs	r12, r12, #1
+	vst1.32	{q0, q1}, [r0]!
+	vst1.32	{q2, q3}, [r0]!
+	add	r10, #64
+	bne	.L_neon_copy_64_loop_ddr
+	b	.L_neon_pop_before_nopld
+
+.L_neon_prime_pump:
+	mov	lr, #(PLDOFFS*PLDSIZE)
+	add	r10, r1, #(PLDOFFS*PLDSIZE)
+	bic	r10, #0x3F
+	sub	r12, r12, #PLDOFFS
+	ldr	r3, [r10, #(-1*PLDSIZE)]
+
+.L_neon_copy_64_loop_outer:
+	vld1.32	{q0, q1}, [r1]!
+	vld1.32	{q2, q3}, [r1]!
+	ldr	r3, [r10]
+	subs	r12, r12, #1
+	vst1.32	{q0, q1}, [r0]!
+	vst1.32	{q2, q3}, [r0]!
+	add	r10, #64
+	bne	.L_neon_copy_64_loop_outer
+
+.L_neon_pop_before_nopld:
+	mov	r12, lr, lsr #6
+	pop	{r9, r10}
+	.cfi_adjust_cfa_offset -8
+	.cfi_restore r9
+	.cfi_restore r10
+
+.L_neon_copy_64_loop_nopld:
+	vld1.32	{q8, q9}, [r1]!
+	vld1.32	{q10, q11}, [r1]!
+	subs	r12, r12, #1
+	vst1.32	{q8, q9}, [r0]!
+	vst1.32	{q10, q11}, [r0]!
+	bne	.L_neon_copy_64_loop_nopld
+	ands	r2, r2, #0x3f
+	beq	.L_neon_exit
+
+.L_neon_copy_32_a:
+	movs	r3, r2, lsl #27
+	bcc	.L_neon_16
+	vld1.32	{q0,q1}, [r1]!
+	vst1.32	{q0,q1}, [r0]!
+
+.L_neon_16:
+	bpl	.L_neon_lt16
+	vld1.32	{q8}, [r1]!
+	vst1.32	{q8}, [r0]!
+	ands	r2, r2, #0x0f
+	beq	.L_neon_exit
+
+.L_neon_lt16:
+	movs	r3, r2, lsl #29
+	bcc	1f
+	vld1.8	{d0}, [r1]!
+	vst1.8	{d0}, [r0]!
+1:
+	bge	.L_neon_lt4
+	vld4.8	{d0[0], d1[0], d2[0], d3[0]}, [r1]!
+	vst4.8	{d0[0], d1[0], d2[0], d3[0]}, [r0]!
+
+.L_neon_lt4:
+	movs	r2, r2, lsl #31
+	itt	cs
+	ldrhcs	r3, [r1], #2
+	strhcs	r3, [r0], #2
+	itt	mi
+	ldrbmi	r3, [r1]
+	strbmi	r3, [r0]
+
+.L_neon_exit:
+	pop	{r0, pc}
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index ba0a226..c06a671 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -52,6 +52,29 @@
 #define _JB_D10_D11     (_JB_D12_D13 + 2)
 #define _JB_D8_D9       (_JB_D10_D11 + 2)
 
+#define MANGLE_REGISTERS 1
+.macro m_mangle_registers reg, sp_reg
+#if MANGLE_REGISTERS
+  eor x19, x19, \reg
+  eor x20, x20, \reg
+  eor x21, x21, \reg
+  eor x22, x22, \reg
+  eor x23, x23, \reg
+  eor x24, x24, \reg
+  eor x25, x25, \reg
+  eor x26, x26, \reg
+  eor x27, x27, \reg
+  eor x28, x28, \reg
+  eor x29, x29, \reg
+  eor x30, x30, \reg
+  eor \sp_reg, \sp_reg, \reg
+#endif
+.endm
+
+.macro m_unmangle_registers reg, sp_reg
+  m_mangle_registers \reg, sp_reg=\sp_reg
+.endm
+
 ENTRY(setjmp)
   mov w1, #1
   b sigsetjmp
@@ -64,23 +87,47 @@
 
 // int sigsetjmp(sigjmp_buf env, int save_signal_mask);
 ENTRY(sigsetjmp)
-  // Record whether or not we're saving the signal mask.
-  str w1, [x0, #(_JB_SIGFLAG * 8)]
+  stp x0, x30, [sp, #-16]!
+  .cfi_def_cfa_offset 16
+  .cfi_rel_offset x0, 0
+  .cfi_rel_offset x30, 8
+
+  // Get the cookie and store it along with the signal flag.
+  mov x0, x1
+  bl __bionic_setjmp_cookie_get
+  mov x1, x0
+  ldr x0, [sp, #0]
+  str x1, [x0, #(_JB_SIGFLAG * 8)]
 
   // Do we need to save the signal mask?
-  cbz w1, 1f
+  tbz w1, #0, 1f
+
+  // Save the cookie for later.
+  stp x1, xzr, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
 
   // Save current signal mask.
-  stp x0, x30, [sp, #-16]!
   // The 'how' argument is ignored if new_mask is NULL.
   mov x1, #0 // NULL.
   add x2, x0, #(_JB_SIGMASK * 8) // old_mask.
   bl sigprocmask
-  ldp x0, x30, [sp], #16
+
+  ldp x1, xzr, [sp], #16
+  .cfi_adjust_cfa_offset -16
 
 1:
+  // Restore original x0 and lr.
+  ldp x0, x30, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x0
+  .cfi_restore x30
+
+  // Mask off the signal flag bit.
+  bic x1, x1, #1
+
   // Save core registers.
   mov x10, sp
+  m_mangle_registers x1, sp_reg=x10
   stp x30, x10, [x0, #(_JB_X30_SP  * 8)]
   stp x28, x29, [x0, #(_JB_X28_X29 * 8)]
   stp x26, x27, [x0, #(_JB_X26_X27 * 8)]
@@ -88,6 +135,7 @@
   stp x22, x23, [x0, #(_JB_X22_X23 * 8)]
   stp x20, x21, [x0, #(_JB_X20_X21 * 8)]
   str x19,      [x0, #(_JB_X19     * 8)]
+  m_unmangle_registers x1, sp_reg=x10
 
   // Save floating point registers.
   stp d14, d15, [x0, #(_JB_D14_D15 * 8)]
@@ -102,30 +150,60 @@
 // void siglongjmp(sigjmp_buf env, int value);
 ENTRY(siglongjmp)
   // Do we need to restore the signal mask?
-  ldr w9, [x0, #(_JB_SIGFLAG * 8)]
-  cbz w9, 1f
+  ldr x2, [x0, #(_JB_SIGFLAG * 8)]
+  tbz w2, #0, 1f
+
+  stp x0, x30, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
+  .cfi_rel_offset x0, 0
+  .cfi_rel_offset x30, 8
 
   // Restore signal mask.
-  stp x0, x30, [sp, #-16]!
   mov x19, x1 // Save 'value'.
+
   mov x2, x0
   mov x0, #2 // SIG_SETMASK
   add x1, x2, #(_JB_SIGMASK * 8) // new_mask.
   mov x2, #0 // NULL.
   bl sigprocmask
   mov x1, x19 // Restore 'value'.
-  ldp x0, x30, [sp], #16
 
+  // Restore original x0 and lr.
+  ldp x0, x30, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x0
+  .cfi_restore x30
+
+  ldr x2, [x0, #(_JB_SIGFLAG * 8)]
 1:
   // Restore core registers.
+  bic x2, x2, #1
   ldp x30, x10, [x0, #(_JB_X30_SP  * 8)]
-  mov sp, x10
   ldp x28, x29, [x0, #(_JB_X28_X29 * 8)]
   ldp x26, x27, [x0, #(_JB_X26_X27 * 8)]
   ldp x24, x25, [x0, #(_JB_X24_X25 * 8)]
   ldp x22, x23, [x0, #(_JB_X22_X23 * 8)]
   ldp x20, x21, [x0, #(_JB_X20_X21 * 8)]
   ldr x19,      [x0, #(_JB_X19     * 8)]
+  m_unmangle_registers x2, sp_reg=x10
+  mov sp, x10
+
+  stp x0, x1, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
+  .cfi_rel_offset x0, 0
+  .cfi_rel_offset x1, 8
+  stp x30, xzr, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
+  .cfi_rel_offset x30, 0
+  ldr x0, [x0, #(_JB_SIGFLAG * 8)]
+  bl __bionic_setjmp_cookie_check
+  ldp x30, xzr, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x30
+  ldp x0, x1, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x0
+  .cfi_restore x1
 
   // Restore floating point registers.
   ldp d14, d15, [x0, #(_JB_D14_D15 * 8)]
@@ -133,13 +211,6 @@
   ldp d10, d11, [x0, #(_JB_D10_D11 * 8)]
   ldp d8,  d9,  [x0, #(_JB_D8_D9   * 8)]
 
-  // Validate sp (sp mod 16 = 0) and lr (lr mod 4 = 0).
-  tst x30, #3
-  b.ne longjmperror
-  mov x10, sp
-  tst x10, #15
-  b.ne longjmperror
-
   // Set return value.
   cmp w1, wzr
   csinc w0, w1, wzr, ne
diff --git a/libc/arch-mips/bionic/setjmp.S b/libc/arch-mips/bionic/setjmp.S
index 3ef0f11..73002e8 100644
--- a/libc/arch-mips/bionic/setjmp.S
+++ b/libc/arch-mips/bionic/setjmp.S
@@ -132,10 +132,9 @@
 /*     	field:		byte offset:	size:						*/
 /*     	dynam filler	(0*4)		   0-4 bytes of rounddown filler, DON'T TOUCH!!
 						often overlays user storage!!		*/
-#define	SC_MAGIC_OFFSET	(1*4)		/* 4 bytes, identify jmpbuf, first actual field */
-#define	SC_FLAG_OFFSET	(2*4)		/* 4 bytes, savesigs flag */
-#define	SC_FPSR_OFFSET	(3*4)		/* 4 bytes, floating point control/status reg */
+#define	SC_FPSR_OFFSET	(1*4)		/* 4 bytes, floating point control/status reg */
 /* following fields are 8-byte aligned */
+#define	SC_FLAG_OFFSET	(2*4)		/* 8 bytes, cookie and savesigs flag, first actual field  */
 #define	SC_MASK_OFFSET	(4*4)		/* 16 bytes, mips32/mips64 version of sigset_t */
 #define	SC_SPARE_OFFSET	(8*4)		/* 8 bytes, reserved for future uses */
 
@@ -166,6 +165,16 @@
 #error _JBLEN is too small
 #endif
 
+.macro m_mangle_reg_and_store reg, cookie, temp, offset
+	xor	\temp, \reg, \cookie
+	REG_S	\temp, \offset
+.endm
+
+.macro m_unmangle_reg_and_load reg, cookie, temp, offset
+	REG_L	\temp, \offset
+	xor	\reg, \temp, \cookie
+.endm
+
 /*
  *
  *  GPOFF and FRAMESIZE must be the same for all setjmp/longjmp routines
@@ -190,36 +199,46 @@
 	li	t0, ~7
 	and	a0, t0				# round jmpbuf addr DOWN to 8-byte boundary
 #endif
-	sw	a1, SC_FLAG_OFFSET(a0)		# save savesigs flag
-	beqz	a1, 1f				# do saving of signal mask?
-
 	REG_S	ra, RAOFF(sp)			# spill state
 	REG_S	a0, A0OFF(sp)
+
+	# get the cookie and store it along with the signal flag.
+	move	a0, a1
+	jal	__bionic_setjmp_cookie_get
+	REG_L	a0, A0OFF(sp)
+
+	REG_S	v0, SC_FLAG_OFFSET(a0)		# save cookie and savesigs flag
+	andi	t0, v0, 1			# extract savesigs flag
+
+	beqz	t0, 1f				# do saving of signal mask?
+
 	# call sigprocmask(int how ignored, sigset_t* null, sigset_t* SC_MASK(a0)):
 	LA	a2, SC_MASK_OFFSET(a0)		# gets current signal mask
 	li	a0, 0				# how; ignored when new mask is null
 	li	a1, 0				# null new mask
 	jal	sigprocmask			# get current signal mask
 	REG_L	a0, A0OFF(sp)
-	REG_L	ra, RAOFF(sp)
 1:
-	li	v0, 0xACEDBADE			# sigcontext magic number
-	sw	v0, SC_MAGIC_OFFSET(a0)
+	REG_L	gp, GPOFF(sp)			# restore spills
+	REG_L	ra, RAOFF(sp)
+	REG_L	t0, SC_FLAG_OFFSET(a0)		# move cookie to temp reg
+
 	# callee-saved long-sized regs:
-	REG_S	ra, SC_REGS+0*REGSZ(a0)
-	REG_S	s0, SC_REGS+1*REGSZ(a0)
-	REG_S	s1, SC_REGS+2*REGSZ(a0)
-	REG_S	s2, SC_REGS+3*REGSZ(a0)
-	REG_S	s3, SC_REGS+4*REGSZ(a0)
-	REG_S	s4, SC_REGS+5*REGSZ(a0)
-	REG_S	s5, SC_REGS+6*REGSZ(a0)
-	REG_S	s6, SC_REGS+7*REGSZ(a0)
-	REG_S	s7, SC_REGS+8*REGSZ(a0)
-	REG_S	s8, SC_REGS+9*REGSZ(a0)
-	REG_L	v0, GPOFF(sp)
-	REG_S	v0, SC_REGS+10*REGSZ(a0)	# save gp
-	PTR_ADDU v0, sp, FRAMESZ
-	REG_S	v0, SC_REGS+11*REGSZ(a0)	# save orig sp
+	PTR_ADDU v1, sp, FRAMESZ		# save orig sp
+
+	# m_mangle_reg_and_store reg, cookie, temp, offset
+	m_mangle_reg_and_store	ra, t0, t1, SC_REGS+0*REGSZ(a0)
+	m_mangle_reg_and_store	s0, t0, t2, SC_REGS+1*REGSZ(a0)
+	m_mangle_reg_and_store	s1, t0, t3, SC_REGS+2*REGSZ(a0)
+	m_mangle_reg_and_store	s2, t0, t1, SC_REGS+3*REGSZ(a0)
+	m_mangle_reg_and_store	s3, t0, t2, SC_REGS+4*REGSZ(a0)
+	m_mangle_reg_and_store	s4, t0, t3, SC_REGS+5*REGSZ(a0)
+	m_mangle_reg_and_store	s5, t0, t1, SC_REGS+6*REGSZ(a0)
+	m_mangle_reg_and_store	s6, t0, t2, SC_REGS+7*REGSZ(a0)
+	m_mangle_reg_and_store	s7, t0, t3, SC_REGS+8*REGSZ(a0)
+	m_mangle_reg_and_store	s8, t0, t1, SC_REGS+9*REGSZ(a0)
+	m_mangle_reg_and_store	gp, t0, t2, SC_REGS+10*REGSZ(a0)
+	m_mangle_reg_and_store	v1, t0, t3, SC_REGS+11*REGSZ(a0)
 
 	cfc1	v0, $31
 
@@ -288,36 +307,41 @@
 	li	t0, ~7
 	and	a0, t0				# round jmpbuf addr DOWN to 8-byte boundary
 #endif
-	lw	v0, SC_MAGIC_OFFSET(a0)
-	li	t0, 0xACEDBADE
-	bne	v0, t0, longjmp_botch		# jump if error
 
-	lw	t0, SC_FLAG_OFFSET(a0)		# get savesigs flag
+	move	s1, a1				# temp spill
+	move	s0, a0
+
+	# extract savesigs flag
+	REG_L	s2, SC_FLAG_OFFSET(s0)
+	andi	t0, s2, 1
 	beqz	t0, 1f				# restore signal mask?
 
-	REG_S	a1, A1OFF(sp)			# temp spill
-	REG_S	a0, A0OFF(sp)
-        # call sigprocmask(int how SIG_SETMASK, sigset_t* SC_MASK(a0), sigset_t* null):
-	LA	a1, SC_MASK_OFFSET(a0)		# signals being restored
+	# call sigprocmask(int how SIG_SETMASK, sigset_t* SC_MASK(a0), sigset_t* null):
+	LA	a1, SC_MASK_OFFSET(s0)		# signals being restored
 	li	a0, 3				# mips SIG_SETMASK
 	li	a2, 0				# null
 	jal	sigprocmask			# restore signal mask
-	REG_L	a0, A0OFF(sp)
-	REG_L	a1, A1OFF(sp)
 1:
+	move	t0, s2				# get cookie to temp reg
+	move	a1, s1
+	move	a0, s0
+
 	# callee-saved long-sized regs:
-	REG_L	ra, SC_REGS+0*REGSZ(a0)
-	REG_L	s0, SC_REGS+1*REGSZ(a0)
-	REG_L	s1, SC_REGS+2*REGSZ(a0)
-	REG_L	s2, SC_REGS+3*REGSZ(a0)
-	REG_L	s3, SC_REGS+4*REGSZ(a0)
-	REG_L	s4, SC_REGS+5*REGSZ(a0)
-	REG_L	s5, SC_REGS+6*REGSZ(a0)
-	REG_L	s6, SC_REGS+7*REGSZ(a0)
-	REG_L	s7, SC_REGS+8*REGSZ(a0)
-	REG_L	s8, SC_REGS+9*REGSZ(a0)
-	REG_L	gp, SC_REGS+10*REGSZ(a0)
-	REG_L	sp, SC_REGS+11*REGSZ(a0)
+
+	# m_unmangle_reg_and_load reg, cookie, temp, offset
+	# don't restore gp yet, old value is needed for cookie_check call
+	m_unmangle_reg_and_load ra, t0, t1, SC_REGS+0*REGSZ(a0)
+	m_unmangle_reg_and_load s0, t0, t2, SC_REGS+1*REGSZ(a0)
+	m_unmangle_reg_and_load s1, t0, t3, SC_REGS+2*REGSZ(a0)
+	m_unmangle_reg_and_load s2, t0, t1, SC_REGS+3*REGSZ(a0)
+	m_unmangle_reg_and_load s3, t0, t2, SC_REGS+4*REGSZ(a0)
+	m_unmangle_reg_and_load s4, t0, t3, SC_REGS+5*REGSZ(a0)
+	m_unmangle_reg_and_load s5, t0, t1, SC_REGS+6*REGSZ(a0)
+	m_unmangle_reg_and_load s6, t0, t2, SC_REGS+7*REGSZ(a0)
+	m_unmangle_reg_and_load s7, t0, t3, SC_REGS+8*REGSZ(a0)
+	m_unmangle_reg_and_load s8, t0, t1, SC_REGS+9*REGSZ(a0)
+	m_unmangle_reg_and_load v1, t0, t2, SC_REGS+10*REGSZ(a0)
+	m_unmangle_reg_and_load sp, t0, t3, SC_REGS+11*REGSZ(a0)
 
 	lw	v0, SC_FPSR_OFFSET(a0)
 	ctc1	v0, $31			# restore old fr mode before fp values
@@ -341,15 +365,22 @@
 	l.d	$f28, SC_FPREGS+4*REGSZ_FP(a0)
 	l.d	$f30, SC_FPREGS+5*REGSZ_FP(a0)
 #endif
-	bne	a1, zero, 1f
-	li	a1, 1			# never return 0!
-1:
-	move	v0, a1
-	j	ra			# return to setjmp call site
 
-longjmp_botch:
-	jal	longjmperror
-	jal	abort
+	# check cookie
+	PTR_SUBU sp, FRAMESZ
+	REG_S	v1, GPOFF(sp)
+	REG_S	ra, RAOFF(sp)
+	REG_S	a1, A1OFF(sp)
+	move	a0, t0
+	jal	__bionic_setjmp_cookie_check
+	REG_L	gp, GPOFF(sp)
+	REG_L	ra, RAOFF(sp)
+	REG_L	a1, A1OFF(sp)
+	PTR_ADDU sp, FRAMESZ
+
+	sltiu	t0, a1, 1		# never return 0!
+	xor	v0, a1, t0
+	j	ra			# return to setjmp call site
 END(siglongjmp)
 
 ALIAS_SYMBOL(longjmp, siglongjmp)
diff --git a/libc/arch-x86/bionic/setjmp.S b/libc/arch-x86/bionic/setjmp.S
index 18ad810..86e6e3c 100644
--- a/libc/arch-x86/bionic/setjmp.S
+++ b/libc/arch-x86/bionic/setjmp.S
@@ -41,30 +41,49 @@
 #define _JB_SIGMASK 6
 #define _JB_SIGFLAG 7
 
+.macro m_mangle_registers reg
+  xorl \reg,%edx
+  xorl \reg,%ebx
+  xorl \reg,%esp
+  xorl \reg,%ebp
+  xorl \reg,%esi
+  xorl \reg,%edi
+.endm
+
+.macro m_unmangle_registers reg
+  m_mangle_registers \reg
+.endm
+
 ENTRY(setjmp)
   movl 4(%esp),%ecx
-  movl $1,(_JB_SIGFLAG * 4)(%ecx)
-  jmp .L_sigsetjmp_signal_mask
+  mov $1,%eax
+  jmp .L_sigsetjmp
 END(setjmp)
 
 ENTRY(_setjmp)
   movl 4(%esp),%ecx
-  movl $0,(_JB_SIGFLAG * 4)(%ecx)
-  jmp .L_sigsetjmp_no_signal_mask
+  movl $0,%eax
+  jmp .L_sigsetjmp
 END(_setjmp)
 
 ENTRY(sigsetjmp)
   movl 4(%esp),%ecx
   movl 8(%esp),%eax
 
-  // Record whether or not the signal mask is valid.
+.L_sigsetjmp:
+  PIC_PROLOGUE
+  pushl %eax
+  call PIC_PLT(__bionic_setjmp_cookie_get)
+  addl $4,%esp
+  PIC_EPILOGUE
+
+  // Record the setjmp cookie and whether or not we're saving the signal mask.
   movl %eax,(_JB_SIGFLAG * 4)(%ecx)
 
   // Do we need to save the signal mask?
-  testl %eax,%eax
+  testl $1,%eax
   jz 1f
 
-.L_sigsetjmp_signal_mask:
   // Get the current signal mask.
   PIC_PROLOGUE
   pushl $0
@@ -76,16 +95,21 @@
   movl 4(%esp),%ecx
   movl %eax,(_JB_SIGMASK * 4)(%ecx)
 
-.L_sigsetjmp_no_signal_mask:
 1:
+  // Fetch the setjmp cookie and clear the signal flag bit.
+  movl (_JB_SIGFLAG * 4)(%ecx),%eax
+  andl $-2,%eax
+
   // Save the callee-save registers.
   movl 0(%esp),%edx
+  m_mangle_registers %eax
   movl %edx,(_JB_EDX * 4)(%ecx)
   movl %ebx,(_JB_EBX * 4)(%ecx)
   movl %esp,(_JB_ESP * 4)(%ecx)
   movl %ebp,(_JB_EBP * 4)(%ecx)
   movl %esi,(_JB_ESI * 4)(%ecx)
   movl %edi,(_JB_EDI * 4)(%ecx)
+  m_unmangle_registers %eax
 
   xorl %eax,%eax
   ret
@@ -94,7 +118,8 @@
 ENTRY(siglongjmp)
   // Do we have a signal mask to restore?
   movl 4(%esp),%edx
-  cmpl $0,(_JB_SIGFLAG * 4)(%edx)
+  movl (_JB_SIGFLAG * 4)(%edx), %eax
+  testl $1,%eax
   jz 1f
 
   // Restore the signal mask.
@@ -108,12 +133,31 @@
   // Restore the callee-save registers.
   movl 4(%esp),%edx
   movl 8(%esp),%eax
-  movl (_JB_EDX * 4)(%edx),%ecx
-  movl (_JB_EBX * 4)(%edx),%ebx
-  movl (_JB_ESP * 4)(%edx),%esp
-  movl (_JB_EBP * 4)(%edx),%ebp
-  movl (_JB_ESI * 4)(%edx),%esi
-  movl (_JB_EDI * 4)(%edx),%edi
+
+  movl (_JB_SIGFLAG * 4)(%edx),%ecx
+  andl $-2,%ecx
+
+  movl %ecx,%ebx
+  movl %ecx,%esp
+  movl %ecx,%ebp
+  movl %ecx,%esi
+  movl %ecx,%edi
+  xorl (_JB_EDX * 4)(%edx),%ecx
+  xorl (_JB_EBX * 4)(%edx),%ebx
+  xorl (_JB_ESP * 4)(%edx),%esp
+  xorl (_JB_EBP * 4)(%edx),%ebp
+  xorl (_JB_ESI * 4)(%edx),%esi
+  xorl (_JB_EDI * 4)(%edx),%edi
+
+  PIC_PROLOGUE
+  pushl %eax
+  pushl %ecx
+  pushl (_JB_SIGFLAG * 4)(%edx)
+  call PIC_PLT(__bionic_setjmp_cookie_check)
+  addl $4,%esp
+  popl %ecx
+  popl %eax
+  PIC_EPILOGUE
 
   testl %eax,%eax
   jnz 2f
diff --git a/libc/arch-x86_64/bionic/setjmp.S b/libc/arch-x86_64/bionic/setjmp.S
index 5559f54..56ebb07 100644
--- a/libc/arch-x86_64/bionic/setjmp.S
+++ b/libc/arch-x86_64/bionic/setjmp.S
@@ -50,6 +50,25 @@
 #define _JB_SIGMASK 9
 #define _JB_SIGMASK_RT 10 // sigprocmask will write here too.
 
+#define MANGLE_REGISTERS 1
+.macro m_mangle_registers reg
+#if MANGLE_REGISTERS
+  xorq \reg,%rbx
+  xorq \reg,%rbp
+  xorq \reg,%r12
+  xorq \reg,%r13
+  xorq \reg,%r14
+  xorq \reg,%r15
+  xorq \reg,%rsp
+  xorq \reg,%r11
+#endif
+.endm
+
+.macro m_unmangle_registers reg
+  m_mangle_registers \reg
+.endm
+
+
 ENTRY(setjmp)
   movl $1,%esi
   jmp PIC_PLT(sigsetjmp)
@@ -62,11 +81,17 @@
 
 // int sigsetjmp(sigjmp_buf env, int save_signal_mask);
 ENTRY(sigsetjmp)
-  // Record whether or not we're saving the signal mask.
-  movl %esi,(_JB_SIGFLAG * 8)(%rdi)
+  pushq %rdi
+  movq %rsi,%rdi
+  call PIC_PLT(__bionic_setjmp_cookie_get)
+  popq %rdi
+
+  // Record setjmp cookie and whether or not we're saving the signal mask.
+  movq %rax,(_JB_SIGFLAG * 8)(%rdi)
+  pushq %rax
 
   // Do we need to save the signal mask?
-  testl %esi,%esi
+  testq $1,%rax
   jz 2f
 
   // Save current signal mask.
@@ -79,7 +104,10 @@
 
 2:
   // Save the callee-save registers.
+  popq %rax
+  andq $-2,%rax
   movq (%rsp),%r11
+  m_mangle_registers %rax
   movq %rbx,(_JB_RBX * 8)(%rdi)
   movq %rbp,(_JB_RBP * 8)(%rdi)
   movq %r12,(_JB_R12 * 8)(%rdi)
@@ -88,6 +116,7 @@
   movq %r15,(_JB_R15 * 8)(%rdi)
   movq %rsp,(_JB_RSP * 8)(%rdi)
   movq %r11,(_JB_PC  * 8)(%rdi)
+  m_unmangle_registers %rax
 
   xorl %eax,%eax
   ret
@@ -99,7 +128,9 @@
   pushq %rsi // Push 'value'.
 
   // Do we need to restore the signal mask?
-  cmpl $0,(_JB_SIGFLAG * 8)(%rdi)
+  movq (_JB_SIGFLAG * 8)(%rdi), %rdi
+  pushq %rdi // Push cookie
+  testq $1, %rdi
   jz 2f
 
   // Restore the signal mask.
@@ -109,6 +140,10 @@
   call PIC_PLT(sigprocmask)
 
 2:
+  // Fetch the setjmp cookie and clear the signal flag bit.
+  popq %rcx
+  andq $-2, %rcx
+
   popq %rax // Pop 'value'.
 
   // Restore the callee-save registers.
@@ -120,7 +155,17 @@
   movq (_JB_RSP * 8)(%r12),%rsp
   movq (_JB_PC  * 8)(%r12),%r11
   movq (_JB_R12 * 8)(%r12),%r12
+  m_unmangle_registers %rcx
 
+  // Check the cookie.
+  pushq %rax
+  pushq %r11
+  movq %rcx, %rdi
+  call PIC_PLT(__bionic_setjmp_cookie_check)
+  popq %r11
+  popq %rax
+
+  // Return 1 if value is 0.
   testl %eax,%eax
   jnz 1f
   incl %eax
diff --git a/libc/bionic/arpa_inet.cpp b/libc/bionic/arpa_inet.cpp
new file mode 100644
index 0000000..9d4afe3
--- /dev/null
+++ b/libc/bionic/arpa_inet.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+
+#include "private/ErrnoRestorer.h"
+
+// The difference between inet_network(3) and inet_addr(3) is that
+// inet_network uses host order and inet_addr network order.
+in_addr_t inet_network(const char* cp) {
+  in_addr_t network_order = inet_addr(cp);
+  return ntohl(network_order);
+}
+
+in_addr_t inet_addr(const char* cp) {
+  in_addr addr;
+  return inet_aton(cp, &addr) ? addr.s_addr : INADDR_NONE;
+}
+
+int inet_aton(const char* cp, in_addr* addr) {
+  ErrnoRestorer errno_restorer;
+
+  unsigned long parts[4];
+  size_t i;
+  for (i = 0; i < 4; ++i) {
+    char* end;
+    errno = 0;
+    parts[i] = strtoul(cp, &end, 0);
+    if (errno != 0 || end == cp || (*end != '.' && *end != '\0')) return 0;
+    if (*end == '\0') break;
+    cp = end + 1;
+  }
+
+  uint32_t result = 0;
+  if (i == 0) {
+    // a (a 32-bit).
+    if (parts[0] > 0xffffffff) return 0;
+    result = parts[0];
+  } else if (i == 1) {
+    // a.b (b 24-bit).
+    if (parts[0] > 0xff || parts[1] > 0xffffff) return 0;
+    result = (parts[0] << 24) | parts[1];
+  } else if (i == 2) {
+    // a.b.c (c 16-bit).
+    if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xffff) return 0;
+    result = (parts[0] << 24) | (parts[1] << 16) | parts[2];
+  } else if (i == 3) {
+    // a.b.c.d (d 8-bit).
+    if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff || parts[3] > 0xff) return 0;
+    result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
+  } else {
+    return 0;
+  }
+
+  if (addr != nullptr) addr->s_addr = htonl(result);
+  return 1;
+}
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index de72cb2..6fb8ebe 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -50,14 +50,11 @@
   uintptr_t offset;
   char permissions[4];
   int name_pos;
-  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start,
+  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start,
              &end, permissions, &offset, &name_pos) < 2) {
     return NULL;
   }
 
-  while (isspace(line[name_pos])) {
-    name_pos += 1;
-  }
   const char* name = line + name_pos;
   size_t name_len = strlen(name);
   if (name_len && name[name_len - 1] == '\n') {
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 3ca6c0d..4995414 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -42,10 +42,12 @@
 #include <unistd.h>
 
 #include "private/bionic_auxv.h"
+#include "private/bionic_globals.h"
 #include "private/bionic_ssp.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
 #include "private/libc_logging.h"
+#include "private/WriteProtected.h"
 #include "pthread_internal.h"
 
 extern "C" abort_msg_t** __abort_message_ptr;
@@ -53,7 +55,7 @@
 extern "C" int __set_tls(void* ptr);
 extern "C" int __set_tid_address(int* tid_address);
 
-__LIBC_HIDDEN__ void __libc_init_vdso();
+__LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
 
 // Not public, but well-known in the BSDs.
 const char* __progname;
@@ -104,6 +106,17 @@
   __init_alternate_signal_stack(&main_thread);
 }
 
+void __libc_init_globals(KernelArgumentBlock& args) {
+  // Initialize libc globals that are needed in both the linker and in libc.
+  // In dynamic binaries, this is run at least twice for different copies of the
+  // globals, once for the linker's copy and once for the one in libc.so.
+  __libc_globals.initialize();
+  __libc_globals.mutate([&args](libc_globals* globals) {
+    __libc_init_vdso(globals, args);
+    __libc_init_setjmp_cookie(globals, args);
+  });
+}
+
 void __libc_init_common(KernelArgumentBlock& args) {
   // Initialize various globals.
   environ = args.envp;
@@ -120,8 +133,6 @@
   __pthread_internal_add(main_thread);
 
   __system_properties_init(); // Requires 'environ'.
-
-  __libc_init_vdso();
 }
 
 __noreturn static void __early_abort(int line) {
@@ -235,38 +246,37 @@
 
 static bool __is_unsafe_environment_variable(const char* name) {
   // None of these should be allowed in setuid programs.
-  static const char* const UNSAFE_VARIABLE_NAMES[] = {
-      "GCONV_PATH",
-      "GETCONF_DIR",
-      "HOSTALIASES",
-      "JE_MALLOC_CONF",
-      "LD_AOUT_LIBRARY_PATH",
-      "LD_AOUT_PRELOAD",
-      "LD_AUDIT",
-      "LD_DEBUG",
-      "LD_DEBUG_OUTPUT",
-      "LD_DYNAMIC_WEAK",
-      "LD_LIBRARY_PATH",
-      "LD_ORIGIN_PATH",
-      "LD_PRELOAD",
-      "LD_PROFILE",
-      "LD_SHOW_AUXV",
-      "LD_USE_LOAD_BIAS",
-      "LOCALDOMAIN",
-      "LOCPATH",
-      "MALLOC_CHECK_",
-      "MALLOC_CONF",
-      "MALLOC_TRACE",
-      "NIS_PATH",
-      "NLSPATH",
-      "RESOLV_HOST_CONF",
-      "RES_OPTIONS",
-      "TMPDIR",
-      "TZDIR",
-      nullptr
+  static constexpr const char* UNSAFE_VARIABLE_NAMES[] = {
+    "GCONV_PATH",
+    "GETCONF_DIR",
+    "HOSTALIASES",
+    "JE_MALLOC_CONF",
+    "LD_AOUT_LIBRARY_PATH",
+    "LD_AOUT_PRELOAD",
+    "LD_AUDIT",
+    "LD_DEBUG",
+    "LD_DEBUG_OUTPUT",
+    "LD_DYNAMIC_WEAK",
+    "LD_LIBRARY_PATH",
+    "LD_ORIGIN_PATH",
+    "LD_PRELOAD",
+    "LD_PROFILE",
+    "LD_SHOW_AUXV",
+    "LD_USE_LOAD_BIAS",
+    "LOCALDOMAIN",
+    "LOCPATH",
+    "MALLOC_CHECK_",
+    "MALLOC_CONF",
+    "MALLOC_TRACE",
+    "NIS_PATH",
+    "NLSPATH",
+    "RESOLV_HOST_CONF",
+    "RES_OPTIONS",
+    "TMPDIR",
+    "TZDIR",
   };
-  for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) {
-    if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) {
+  for (const auto& unsafe_variable_name : UNSAFE_VARIABLE_NAMES) {
+    if (env_match(name, unsafe_variable_name) != nullptr) {
       return true;
     }
   }
diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h
index 673ad5b..5066652 100644
--- a/libc/bionic/libc_init_common.h
+++ b/libc/bionic/libc_init_common.h
@@ -51,6 +51,9 @@
 #if defined(__cplusplus)
 
 class KernelArgumentBlock;
+
+__LIBC_HIDDEN__ void __libc_init_globals(KernelArgumentBlock& args);
+
 __LIBC_HIDDEN__ void __libc_init_common(KernelArgumentBlock& args);
 
 __LIBC_HIDDEN__ void __libc_init_AT_SECURE(KernelArgumentBlock& args);
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 78125f9..3bb6e89 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -74,6 +74,7 @@
   // __libc_init_common() will change the TLS area so the old one won't be accessible anyway.
   *args_slot = NULL;
 
+  __libc_init_globals(*args);
   __libc_init_common(*args);
 
   // Hooks for various libraries to let them know that we're starting up.
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 2b1a8cb..2fe86d0 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -84,7 +84,12 @@
                             int (*slingshot)(int, char**, char**),
                             structors_array_t const * const structors) {
   KernelArgumentBlock args(raw_args);
+
   __libc_init_main_thread(args);
+
+  // Initializing the globals requires TLS to be available for errno.
+  __libc_init_globals(args);
+
   __libc_init_AT_SECURE(args);
   __libc_init_common(args);
 
diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp
index 7ad3431..cfa58fc 100644
--- a/libc/bionic/pthread_attr.cpp
+++ b/libc/bionic/pthread_attr.cpp
@@ -114,6 +114,36 @@
   return 0;
 }
 
+static uintptr_t __get_main_stack_startstack() {
+  FILE* fp = fopen("/proc/self/stat", "re");
+  if (fp == nullptr) {
+    __libc_fatal("couldn't open /proc/self/stat: %s", strerror(errno));
+  }
+
+  char line[BUFSIZ];
+  if (fgets(line, sizeof(line), fp) == nullptr) {
+    __libc_fatal("couldn't read /proc/self/stat: %s", strerror(errno));
+  }
+
+  fclose(fp);
+
+  // See man 5 proc. There's no reason comm can't contain ' ' or ')',
+  // so we search backwards for the end of it. We're looking for this field:
+  //
+  //  startstack %lu (28) The address of the start (i.e., bottom) of the stack.
+  uintptr_t startstack = 0;
+  const char* end_of_comm = strrchr(line, ')');
+  if (sscanf(end_of_comm + 1, " %*c "
+             "%*d %*d %*d %*d %*d "
+             "%*u %*u %*u %*u %*u %*u %*u "
+             "%*d %*d %*d %*d %*d %*d "
+             "%*u %*u %*d %*u %*u %*u %" SCNuPTR, &startstack) != 1) {
+    __libc_fatal("couldn't parse /proc/self/stat");
+  }
+
+  return startstack;
+}
+
 static int __pthread_attr_getstack_main_thread(void** stack_base, size_t* stack_size) {
   ErrnoRestorer errno_restorer;
 
@@ -127,20 +157,19 @@
     stack_limit.rlim_cur = 8 * 1024 * 1024;
   }
 
-  // It shouldn't matter which thread we are because we're just looking for "[stack]", but
-  // valgrind seems to mess with the stack enough that the kernel will report "[stack:pid]"
-  // instead if you look in /proc/self/maps, so we need to look in /proc/pid/task/pid/maps.
-  char path[64];
-  snprintf(path, sizeof(path), "/proc/self/task/%d/maps", getpid());
-  FILE* fp = fopen(path, "re");
-  if (fp == NULL) {
-    return errno;
+  // Ask the kernel where our main thread's stack started.
+  uintptr_t startstack = __get_main_stack_startstack();
+
+  // Hunt for the region that contains that address.
+  FILE* fp = fopen("/proc/self/maps", "re");
+  if (fp == nullptr) {
+    __libc_fatal("couldn't open /proc/self/maps");
   }
   char line[BUFSIZ];
   while (fgets(line, sizeof(line), fp) != NULL) {
-    if (ends_with(line, " [stack]\n")) {
-      uintptr_t lo, hi;
-      if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) {
+    uintptr_t lo, hi;
+    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) {
+      if (lo <= startstack && startstack <= hi) {
         *stack_size = stack_limit.rlim_cur;
         *stack_base = reinterpret_cast<void*>(hi - *stack_size);
         fclose(fp);
@@ -148,7 +177,7 @@
       }
     }
   }
-  __libc_fatal("No [stack] line found in \"%s\"!", path);
+  __libc_fatal("Stack not found in /proc/self/maps");
 }
 
 int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) {
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 3b91e6a..6a39a21 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -130,8 +130,13 @@
  */
 #define PTHREAD_STACK_SIZE_DEFAULT ((1 * 1024 * 1024) - SIGSTKSZ)
 
-/* Leave room for a guard page in the internally created signal stacks. */
+// Leave room for a guard page in the internally created signal stacks.
+#if defined(__LP64__)
+// SIGSTKSZ is not big enough for 64-bit arch. See http://b/23041777.
+#define SIGNAL_STACK_SIZE (16 * 1024 + PAGE_SIZE)
+#else
 #define SIGNAL_STACK_SIZE (SIGSTKSZ + PAGE_SIZE)
+#endif
 
 /* Needed by fork. */
 __LIBC_HIDDEN__ extern void __bionic_atfork_run_prepare();
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index 0b04650..ff84443 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -80,7 +80,7 @@
 #define SEMCOUNT_ONE              SEMCOUNT_FROM_VALUE(1)
 
 // The value -1 as a sem->count bit-pattern.
-#define SEMCOUNT_MINUS_ONE        SEMCOUNT_FROM_VALUE(-1)
+#define SEMCOUNT_MINUS_ONE        SEMCOUNT_FROM_VALUE(~0U)
 
 #define SEMCOUNT_DECREMENT(sval)    (((sval) - (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK)
 #define SEMCOUNT_INCREMENT(sval)    (((sval) + (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK)
diff --git a/libc/bionic/setjmp_cookie.cpp b/libc/bionic/setjmp_cookie.cpp
new file mode 100644
index 0000000..ce57fd1
--- /dev/null
+++ b/libc/bionic/setjmp_cookie.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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 <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/auxv.h>
+#include <sys/cdefs.h>
+
+#include "private/bionic_globals.h"
+#include "private/libc_logging.h"
+#include "private/KernelArgumentBlock.h"
+
+void __libc_init_setjmp_cookie(libc_globals* globals,
+                               KernelArgumentBlock& args) {
+  char* random_data = reinterpret_cast<char*>(args.getauxval(AT_RANDOM));
+  long value = *reinterpret_cast<long*>(random_data + 8);
+
+  // Mask off the last bit to store the signal flag.
+  globals->setjmp_cookie = value & ~1;
+}
+
+extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_get(long sigflag) {
+  if (sigflag & ~1) {
+    __libc_fatal("unexpected sigflag value: %ld", sigflag);
+  }
+
+  return __libc_globals->setjmp_cookie | sigflag;
+}
+
+// Aborts if cookie doesn't match, returns the signal flag otherwise.
+extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_check(long cookie) {
+  if (__libc_globals->setjmp_cookie != (cookie & ~1)) {
+    __libc_fatal("setjmp cookie mismatch");
+  }
+
+  return cookie & 1;
+}
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 41c78bc..0340f0e 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -206,7 +206,7 @@
 // u0_a1234 -> 0 * AID_USER + AID_APP + 1234
 // u2_i1000 -> 2 * AID_USER + AID_ISOLATED_START + 1000
 // u1_system -> 1 * AID_USER + android_ids['system']
-// returns 0 and sets errno to ENOENT in case of error
+// returns 0 and sets errno to ENOENT in case of error.
 static id_t app_id_from_name(const char* name, bool is_group) {
   char* end;
   unsigned long userid;
@@ -312,6 +312,54 @@
   }
 }
 
+// Translate an OEM name to the corresponding user/group id.
+// oem_XXX -> AID_OEM_RESERVED_2_START + XXX, iff XXX is within range.
+static id_t oem_id_from_name(const char* name) {
+  unsigned int id;
+  if (sscanf(name, "oem_%u", &id) != 1) {
+    return 0;
+  }
+  // Check OEM id is within range.
+  if (id > (AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START)) {
+    return 0;
+  }
+  return AID_OEM_RESERVED_2_START + static_cast<id_t>(id);
+}
+
+static passwd* oem_id_to_passwd(uid_t uid, passwd_state_t* state) {
+  if (uid < AID_OEM_RESERVED_2_START || uid > AID_OEM_RESERVED_2_END) {
+    return NULL;
+  }
+
+  snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u",
+           uid - AID_OEM_RESERVED_2_START);
+  snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
+  snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
+
+  passwd* pw = &state->passwd_;
+  pw->pw_name  = state->name_buffer_;
+  pw->pw_dir   = state->dir_buffer_;
+  pw->pw_shell = state->sh_buffer_;
+  pw->pw_uid   = uid;
+  pw->pw_gid   = uid;
+  return pw;
+}
+
+static group* oem_id_to_group(gid_t gid, group_state_t* state) {
+  if (gid < AID_OEM_RESERVED_2_START || gid > AID_OEM_RESERVED_2_END) {
+    return NULL;
+  }
+
+  snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_),
+           "oem_%u", gid - AID_OEM_RESERVED_2_START);
+
+  group* gr = &state->group_;
+  gr->gr_name   = state->group_name_buffer_;
+  gr->gr_gid    = gid;
+  gr->gr_mem[0] = gr->gr_name;
+  return gr;
+}
+
 // Translate a uid into the corresponding name.
 // 0 to AID_APP-1                   -> "system", "radio", etc.
 // AID_APP to AID_ISOLATED_START-1  -> u0_a1234
@@ -371,6 +419,11 @@
   if (pw != NULL) {
     return pw;
   }
+  // Handle OEM range.
+  pw = oem_id_to_passwd(uid, state);
+  if (pw != NULL) {
+    return pw;
+  }
   return app_id_to_passwd(uid, state);
 }
 
@@ -384,6 +437,11 @@
   if (pw != NULL) {
     return pw;
   }
+  // Handle OEM range.
+  pw = oem_id_to_passwd(oem_id_from_name(login), state);
+  if (pw != NULL) {
+    return pw;
+  }
   return app_id_to_passwd(app_id_from_name(login, false), state);
 }
 
@@ -407,6 +465,11 @@
   if (grp != NULL) {
     return grp;
   }
+  // Handle OEM range.
+  grp = oem_id_to_group(gid, state);
+  if (grp != NULL) {
+    return grp;
+  }
   return app_id_to_group(gid, state);
 }
 
@@ -423,6 +486,11 @@
   if (grp != NULL) {
     return grp;
   }
+  // Handle OEM range.
+  grp = oem_id_to_group(oem_id_from_name(name), state);
+  if (grp != NULL) {
+    return grp;
+  }
   return app_id_to_group(app_id_from_name(name, true), state);
 }
 
diff --git a/libc/bionic/sysinfo.cpp b/libc/bionic/sysinfo.cpp
index a48bfea..1cb5c79 100644
--- a/libc/bionic/sysinfo.cpp
+++ b/libc/bionic/sysinfo.cpp
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "private/get_cpu_count_from_string.h"
 #include "private/ScopedReaddir.h"
 
 static bool __matches_cpuN(const char* s) {
@@ -61,26 +62,18 @@
 }
 
 int get_nprocs() {
-  FILE* fp = fopen("/proc/stat", "re");
-  if (fp == NULL) {
-    return 1;
-  }
-
-  int result = 0;
-  char buf[256];
-  while (fgets(buf, sizeof(buf), fp) != NULL) {
-    // Extract just the first word from the line.
-    // 'cpu0 7976751 1364388 3116842 469770388 8629405 0 49047 0 0 0'
-    char* p = strchr(buf, ' ');
-    if (p != NULL) {
-      *p = 0;
+  int cpu_count = 1;
+  FILE* fp = fopen("/sys/devices/system/cpu/online", "re");
+  if (fp != nullptr) {
+    char* line = nullptr;
+    size_t len = 0;
+    if (getline(&line, &len, fp) != -1) {
+      cpu_count = GetCpuCountFromString(line);
+      free(line);
     }
-    if (__matches_cpuN(buf)) {
-      ++result;
-    }
+    fclose(fp);
   }
-  fclose(fp);
-  return result;
+  return cpu_count;
 }
 
 static int __get_meminfo_page_count(const char* pattern) {
diff --git a/libc/bionic/vdso.cpp b/libc/bionic/vdso.cpp
index 9eae3d5..029c148 100644
--- a/libc/bionic/vdso.cpp
+++ b/libc/bionic/vdso.cpp
@@ -14,66 +14,47 @@
  * limitations under the License.
  */
 
-#include <link.h>
-#include <string.h>
-#include <sys/auxv.h>
-#include <unistd.h>
+#include "private/bionic_globals.h"
+#include "private/bionic_vdso.h"
 
 #if defined(__aarch64__) || defined(__x86_64__) || defined (__i386__)
 
-#if defined(__aarch64__)
-#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
-#define VDSO_GETTIMEOFDAY_SYMBOL  "__kernel_gettimeofday"
-#elif defined(__x86_64__) || defined(__i386__)
-#define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
-#define VDSO_GETTIMEOFDAY_SYMBOL  "__vdso_gettimeofday"
-#endif
-
-#include <errno.h>
 #include <limits.h>
-#include <sys/mman.h>
+#include <link.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/time.h>
 #include <time.h>
-
-#include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
-
-extern "C" int __clock_gettime(int, timespec*);
-extern "C" int __gettimeofday(timeval*, struct timezone*);
-
-struct vdso_entry {
-  const char* name;
-  void* fn;
-};
-
-enum {
-  VDSO_CLOCK_GETTIME = 0,
-  VDSO_GETTIMEOFDAY,
-  VDSO_END
-};
-
-static union {
-  vdso_entry entries[VDSO_END];
-  char padding[PAGE_SIZE];
-} vdso __attribute__((aligned(PAGE_SIZE))) = {{
-  [VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, reinterpret_cast<void*>(__clock_gettime) },
-  [VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, reinterpret_cast<void*>(__gettimeofday) },
-}};
+#include <unistd.h>
+#include "private/KernelArgumentBlock.h"
 
 int clock_gettime(int clock_id, timespec* tp) {
-  int (*vdso_clock_gettime)(int, timespec*) =
-      reinterpret_cast<int (*)(int, timespec*)>(vdso.entries[VDSO_CLOCK_GETTIME].fn);
-  return vdso_clock_gettime(clock_id, tp);
+  auto vdso_clock_gettime = reinterpret_cast<decltype(&clock_gettime)>(
+    __libc_globals->vdso[VDSO_CLOCK_GETTIME].fn);
+  if (__predict_true(vdso_clock_gettime)) {
+    return vdso_clock_gettime(clock_id, tp);
+  }
+  return __clock_gettime(clock_id, tp);
 }
 
 int gettimeofday(timeval* tv, struct timezone* tz) {
-  int (*vdso_gettimeofday)(timeval*, struct timezone*) =
-      reinterpret_cast<int (*)(timeval*, struct timezone*)>(vdso.entries[VDSO_GETTIMEOFDAY].fn);
-  return vdso_gettimeofday(tv, tz);
+  auto vdso_gettimeofday = reinterpret_cast<decltype(&gettimeofday)>(
+    __libc_globals->vdso[VDSO_GETTIMEOFDAY].fn);
+  if (__predict_true(vdso_gettimeofday)) {
+    return vdso_gettimeofday(tv, tz);
+  }
+  return __gettimeofday(tv, tz);
 }
 
-static void __libc_init_vdso_entries() {
+void __libc_init_vdso(libc_globals* globals, KernelArgumentBlock& args) {
+  auto&& vdso = globals->vdso;
+  vdso[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL,
+                               reinterpret_cast<void*>(__clock_gettime) };
+  vdso[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL,
+                              reinterpret_cast<void*>(__gettimeofday) };
+
   // Do we have a vdso?
-  uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR);
+  uintptr_t vdso_ehdr_addr = args.getauxval(AT_SYSINFO_EHDR);
   ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr);
   if (vdso_ehdr == nullptr) {
     return;
@@ -123,27 +104,16 @@
   // Are there any symbols we want?
   for (size_t i = 0; i < symbol_count; ++i) {
     for (size_t j = 0; j < VDSO_END; ++j) {
-      if (strcmp(vdso.entries[j].name, strtab + symtab[i].st_name) == 0) {
-        vdso.entries[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value);
+      if (strcmp(vdso[j].name, strtab + symtab[i].st_name) == 0) {
+        vdso[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value);
       }
     }
   }
 }
 
-void __libc_init_vdso() {
-  __libc_init_vdso_entries();
-
-  // We can't use PR_SET_VMA because this isn't an anonymous region.
-  // Long-term we should be able to replace all of this with ifuncs.
-  static_assert(PAGE_SIZE == sizeof(vdso), "sizeof(vdso) too large");
-  if (mprotect(vdso.entries, sizeof(vdso), PROT_READ) == -1) {
-    __libc_fatal("failed to mprotect PROT_READ vdso function pointer table: %s", strerror(errno));
-  }
-}
-
 #else
 
-void __libc_init_vdso() {
+void __libc_init_vdso(libc_globals*, KernelArgumentBlock&) {
 }
 
 #endif
diff --git a/libc/include/netinet/udp.h b/libc/include/netinet/udp.h
index 25e0dfc..d4eb368 100644
--- a/libc/include/netinet/udp.h
+++ b/libc/include/netinet/udp.h
@@ -25,31 +25,29 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _NETINET_UDP_H
 #define _NETINET_UDP_H
 
-/*
- * We would include linux/udp.h, but it brings in too much other stuff
- */
+#include <sys/types.h>
 
-#ifdef __FAVOR_BSD
+#include <linux/udp.h>
 
 struct udphdr {
-    u_int16_t uh_sport;	/* source port */
-    u_int16_t uh_dport;	/* destination port */
-    u_int16_t uh_ulen;	/* udp length */
-    u_int16_t uh_sum;	/* udp checksum */
+    __extension__ union {
+        struct /* BSD names */ {
+            u_int16_t uh_sport;
+            u_int16_t uh_dport;
+            u_int16_t uh_ulen;
+            u_int16_t uh_sum;
+        };
+        struct /* Linux names */ {
+            u_int16_t source;
+            u_int16_t dest;
+            u_int16_t len;
+            u_int16_t check;
+        };
+    };
 };
 
-#else
-
-struct udphdr {
-    __u16  source;
-    __u16  dest;
-    __u16  len;
-    __u16  check;
-};
-
-#endif /* __FAVOR_BSD */
-
 #endif /* _NETINET_UDP_H */
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index c4bfb4f..1df4b54 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -38,14 +38,6 @@
 #ifndef	_STDIO_H_
 #define	_STDIO_H_
 
-/*
- * This file must contain a reference to __gnuc_va_list so that GCC's
- * fixincludes knows that that's what's being used for va_list, and so
- * to leave our <stdio.h> alone. (fixincludes gets in the way of pointing
- * one toolchain at various different sets of platform headers.)
- * If you alter this comment, be sure to keep "__gnuc_va_list" in it!
- */
-
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
@@ -59,94 +51,9 @@
 
 typedef off_t fpos_t;		/* stdio file position type */
 
-/*
- * NB: to fit things in six character monocase externals, the stdio
- * code uses the prefix `__s' for stdio objects, typically followed
- * by a three-character attempt at a mnemonic.
- */
+struct __sFILE;
+typedef struct __sFILE FILE;
 
-/* stdio buffers */
-#if defined(__LP64__)
-struct __sbuf {
-  unsigned char* _base;
-  size_t _size;
-};
-#else
-struct __sbuf {
-	unsigned char *_base;
-	int	_size;
-};
-#endif
-
-/*
- * stdio state variables.
- *
- * The following always hold:
- *
- *	if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
- *		_lbfsize is -_bf._size, else _lbfsize is 0
- *	if _flags&__SRD, _w is 0
- *	if _flags&__SWR, _r is 0
- *
- * This ensures that the getc and putc macros (or inline functions) never
- * try to write or read from a file that is in `read' or `write' mode.
- * (Moreover, they can, and do, automatically switch from read mode to
- * write mode, and back, on "r+" and "w+" files.)
- *
- * _lbfsize is used only to make the inline line-buffered output stream
- * code as compact as possible.
- *
- * _ub, _up, and _ur are used when ungetc() pushes back more characters
- * than fit in the current _bf, or when ungetc() pushes back a character
- * that does not match the previous one in _bf.  When this happens,
- * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
- * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
- *
- * NOTE: if you change this structure, you also need to update the
- * std() initializer in findfp.c.
- */
-typedef	struct __sFILE {
-	unsigned char *_p;	/* current position in (some) buffer */
-	int	_r;		/* read space left for getc() */
-	int	_w;		/* write space left for putc() */
-#if defined(__LP64__)
-	int	_flags;		/* flags, below; this FILE is free if 0 */
-	int	_file;		/* fileno, if Unix descriptor, else -1 */
-#else
-	short	_flags;		/* flags, below; this FILE is free if 0 */
-	short	_file;		/* fileno, if Unix descriptor, else -1 */
-#endif
-	struct	__sbuf _bf;	/* the buffer (at least 1 byte, if !NULL) */
-	int	_lbfsize;	/* 0 or -_bf._size, for inline putc */
-
-	/* operations */
-	void	*_cookie;	/* cookie passed to io functions */
-	int	(*_close)(void *);
-	int	(*_read)(void *, char *, int);
-	fpos_t	(*_seek)(void *, fpos_t, int);
-	int	(*_write)(void *, const char *, int);
-
-	/* extension data, to avoid further ABI breakage */
-	struct	__sbuf _ext;
-	/* data for long sequences of ungetc() */
-	unsigned char *_up;	/* saved _p when _p is doing ungetc data */
-	int	_ur;		/* saved _r when _r is counting ungetc data */
-
-	/* tricks to meet minimum requirements even when malloc() fails */
-	unsigned char _ubuf[3];	/* guarantee an ungetc() buffer */
-	unsigned char _nbuf[1];	/* guarantee a getc() buffer */
-
-	/* separate buffer for fgetln() when line crosses buffer boundary */
-	struct	__sbuf _lb;	/* buffer for fgetln() */
-
-	/* Unix stdio files get aligned to block boundaries on fseek() */
-	int	_blksize;	/* stat.st_blksize (may be != _bf._size) */
-	fpos_t	_offset;	/* current lseek offset */
-} FILE;
-
-/* Legacy BSD implementation of stdin/stdout/stderr. */
-extern FILE __sF[];
-/* More obvious implementation. */
 extern FILE* stdin;
 extern FILE* stdout;
 extern FILE* stderr;
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 3ad4f42..58038cd 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -130,30 +130,9 @@
 #define	__volatile
 #endif	/* !__GNUC__ */
 
-/*
- * In non-ANSI C environments, new programs will want ANSI-only C keywords
- * deleted from the program and old programs will want them left alone.
- * Programs using the ANSI C keywords const, inline etc. as normal
- * identifiers should define -DNO_ANSI_KEYWORDS.
- */
-#ifndef	NO_ANSI_KEYWORDS
-#define	const		__const		/* convert ANSI C keywords */
-#define	inline		__inline
-#define	signed		__signed
-#define	volatile	__volatile
-#endif /* !NO_ANSI_KEYWORDS */
 #endif	/* !(__STDC__ || __cplusplus) */
 
 /*
- * Used for internal auditing of the NetBSD source tree.
- */
-#ifdef __AUDIT__
-#define	__aconst	__const
-#else
-#define	__aconst
-#endif
-
-/*
  * The following macro is used to remove const cast-away warnings
  * from gcc -Wcast-qual; it should be used with caution because it
  * can hide valid errors; in particular most valid uses are in
@@ -164,75 +143,19 @@
  */
 #define __UNCONST(a)	((void *)(unsigned long)(const void *)(a))
 
-/*
- * GCC2 provides __extension__ to suppress warnings for various GNU C
- * language extensions under "-ansi -pedantic".
- */
-#if !__GNUC_PREREQ(2, 0)
-#define	__extension__		/* delete __extension__ if non-gcc or gcc1 */
-#endif
-
-/*
- * GCC1 and some versions of GCC2 declare dead (non-returning) and
- * pure (no side effects) functions using "volatile" and "const";
- * unfortunately, these then cause warnings under "-ansi -pedantic".
- * GCC2 uses a new, peculiar __attribute__((attrs)) style.  All of
- * these work for GNU C++ (modulo a slight glitch in the C++ grammar
- * in the distribution version of 2.5.5).
- */
-#if !__GNUC_PREREQ(2, 5)
-#define	__attribute__(x)	/* delete __attribute__ if non-gcc or gcc1 */
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-#define	__dead		__volatile
-#define	__pure		__const
-#endif
-#endif
-
-/* Delete pseudo-keywords wherever they are not available or needed. */
-#ifndef __dead
-#define	__dead
-#define	__pure
-#endif
-
-#if __GNUC_PREREQ(2, 7)
-#define	__unused	__attribute__((__unused__))
-#else
-#define	__unused	/* delete */
-#endif
-
+#define __dead __attribute__((__noreturn__))
+#define __pure __attribute__((__const__))
 #define __pure2 __attribute__((__const__)) /* Android-added: used by FreeBSD libm */
 
-#if __GNUC_PREREQ(3, 1)
-#define	__used		__attribute__((__used__))
-#else
-#define	__used		/* delete */
-#endif
+#define	__unused	__attribute__((__unused__))
 
-#if __GNUC_PREREQ(2, 7)
+#define	__used		__attribute__((__used__))
+
 #define	__packed	__attribute__((__packed__))
 #define	__aligned(x)	__attribute__((__aligned__(x)))
 #define	__section(x)	__attribute__((__section__(x)))
-#elif defined(__lint__)
-#define	__packed	/* delete */
-#define	__aligned(x)	/* delete */
-#define	__section(x)	/* delete */
-#else
-#define	__packed	error: no __packed for this compiler
-#define	__aligned(x)	error: no __aligned for this compiler
-#define	__section(x)	error: no __section for this compiler
-#endif
 
-#if !__GNUC_PREREQ(2, 8)
-#define	__extension__
-#endif
-
-#if __GNUC_PREREQ(2, 8)
 #define __statement(x)	__extension__(x)
-#elif defined(lint)
-#define __statement(x)	(0)
-#else
-#define __statement(x)	(x)
-#endif
 
 #define __nonnull(args) __attribute__((__nonnull__ args))
 
@@ -240,43 +163,20 @@
 #define __scanflike(x, y) __attribute__((__format__(scanf, x, y))) __nonnull((x))
 
 /*
- * C99 defines the restrict type qualifier keyword, which was made available
- * in GCC 2.92.
+ * C99 defines the restrict type qualifier keyword.
  */
 #if defined(__STDC__VERSION__) && __STDC_VERSION__ >= 199901L
 #define	__restrict	restrict
-#else
-#if !__GNUC_PREREQ(2, 92)
-#define	__restrict	/* delete __restrict when not supported */
-#endif
 #endif
 
 /*
- * C99 defines __func__ predefined identifier, which was made available
- * in GCC 2.95.
+ * C99 defines __func__ predefined identifier.
  */
 #if !defined(__STDC_VERSION__) || !(__STDC_VERSION__ >= 199901L)
-#if __GNUC_PREREQ(2, 6)
 #define	__func__	__PRETTY_FUNCTION__
-#elif __GNUC_PREREQ(2, 4)
-#define	__func__	__FUNCTION__
-#else
-#define	__func__	""
-#endif
 #endif /* !(__STDC_VERSION__ >= 199901L) */
 
 /*
- * A barrier to stop the optimizer from moving code or assume live
- * register values. This is gcc specific, the version is more or less
- * arbitrary, might work with older compilers.
- */
-#if __GNUC_PREREQ(2, 95)
-#define	__insn_barrier()	__asm __volatile("":::"memory")
-#else
-#define	__insn_barrier()	/* */
-#endif
-
-/*
  * GNU C version 2.96 adds explicit branch prediction so that
  * the CPU back-end can hint the processor and also so that
  * code blocks can be reordered such that the predicted path
@@ -304,43 +204,19 @@
  *	  basic block reordering that this affects can often generate
  *	  larger code.
  */
-#if __GNUC_PREREQ(2, 96)
 #define	__predict_true(exp)	__builtin_expect((exp) != 0, 1)
 #define	__predict_false(exp)	__builtin_expect((exp) != 0, 0)
-#else
-#define	__predict_true(exp)	(exp)
-#define	__predict_false(exp)	(exp)
-#endif
 
-#if __GNUC_PREREQ(2, 96)
 #define __noreturn    __attribute__((__noreturn__))
 #define __mallocfunc  __attribute__((malloc))
 #define __purefunc    __attribute__((pure))
-#else
-#define __noreturn
-#define __mallocfunc
-#define __purefunc
-#endif
 
-#if __GNUC_PREREQ(3, 1)
 #define __always_inline __attribute__((__always_inline__))
-#else
-#define __always_inline
-#endif
 
-#if __GNUC_PREREQ(3, 4)
 #define __wur __attribute__((__warn_unused_result__))
-#else
-#define __wur
-#endif
 
-#if __GNUC_PREREQ(4, 3)
 #define __errorattr(msg) __attribute__((__error__(msg)))
 #define __warnattr(msg) __attribute__((__warning__(msg)))
-#else
-#define __errorattr(msg)
-#define __warnattr(msg)
-#endif
 
 #define __errordecl(name, msg) extern void name(void) __errorattr(msg)
 
@@ -540,19 +416,14 @@
  * http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html for details.
  */
 #if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0
-#define __BIONIC_FORTIFY 1
-#if _FORTIFY_SOURCE == 2
-#define __bos(s) __builtin_object_size((s), 1)
-#else
-#define __bos(s) __builtin_object_size((s), 0)
-#endif
-#define __bos0(s) __builtin_object_size((s), 0)
-
-#if __GNUC_PREREQ(4,3) || __has_attribute(__artificial__)
-#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__))
-#else
-#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline))
-#endif
+#  define __BIONIC_FORTIFY 1
+#  if _FORTIFY_SOURCE == 2
+#    define __bos(s) __builtin_object_size((s), 1)
+#  else
+#    define __bos(s) __builtin_object_size((s), 0)
+#  endif
+#  define __bos0(s) __builtin_object_size((s), 0)
+#  define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__))
 #endif
 #define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1)
 
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index ff8a815..c0720b8 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -50,19 +50,15 @@
 #ifdef __mips__
 #define SOCK_DGRAM      1
 #define SOCK_STREAM     2
+#else
+#define SOCK_STREAM     1
+#define SOCK_DGRAM      2
+#endif
 #define SOCK_RAW        3
 #define SOCK_RDM        4
 #define SOCK_SEQPACKET  5
 #define SOCK_DCCP       6
 #define SOCK_PACKET     10
-#else
-#define SOCK_STREAM      1
-#define SOCK_DGRAM       2
-#define SOCK_RAW         3
-#define SOCK_RDM         4
-#define SOCK_SEQPACKET   5
-#define SOCK_PACKET      10
-#endif
 
 #define SOCK_CLOEXEC O_CLOEXEC
 #define SOCK_NONBLOCK O_NONBLOCK
diff --git a/libc/include/sys/wait.h b/libc/include/sys/wait.h
index 12b7308..2317b02 100644
--- a/libc/include/sys/wait.h
+++ b/libc/include/sys/wait.h
@@ -44,6 +44,7 @@
 #define WIFEXITED(s)    (WTERMSIG(s) == 0)
 #define WIFSTOPPED(s)   (WTERMSIG(s) == 0x7f)
 #define WIFSIGNALED(s)  (WTERMSIG((s)+1) >= 2)
+#define WIFCONTINUED(s) ((s) == 0xffff)
 
 #define W_EXITCODE(ret, sig)    ((ret) << 8 | (sig))
 #define W_STOPCODE(sig)         ((sig) << 8 | 0x7f)
diff --git a/libc/include/utmp.h b/libc/include/utmp.h
index ebf2372..7eeea41 100644
--- a/libc/include/utmp.h
+++ b/libc/include/utmp.h
@@ -46,7 +46,16 @@
 #define UT_HOSTSIZE 16
 #endif
 
-#define USER_PROCESS 7
+#define EMPTY         0
+#define RUN_LVL       1
+#define BOOT_TIME     2
+#define NEW_TIME      3
+#define OLD_TIME      4
+#define INIT_PROCESS  5
+#define LOGIN_PROCESS 6
+#define USER_PROCESS  7
+#define DEAD_PROCESS  8
+#define ACCOUNTING    9
 
 struct lastlog
 {
diff --git a/libc/kernel/common/scsi/scsi.h b/libc/kernel/common/scsi/scsi.h
new file mode 100644
index 0000000..9e5edd7
--- /dev/null
+++ b/libc/kernel/common/scsi/scsi.h
@@ -0,0 +1,261 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _SCSI_SCSI_H
+#define _SCSI_SCSI_H
+#include <linux/types.h>
+#define TEST_UNIT_READY 0x00
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define REZERO_UNIT 0x01
+#define REQUEST_SENSE 0x03
+#define FORMAT_UNIT 0x04
+#define READ_BLOCK_LIMITS 0x05
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define REASSIGN_BLOCKS 0x07
+#define INITIALIZE_ELEMENT_STATUS 0x07
+#define READ_6 0x08
+#define WRITE_6 0x0a
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SEEK_6 0x0b
+#define READ_REVERSE 0x0f
+#define WRITE_FILEMARKS 0x10
+#define SPACE 0x11
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define INQUIRY 0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT 0x15
+#define RESERVE 0x16
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define RELEASE 0x17
+#define COPY 0x18
+#define ERASE 0x19
+#define MODE_SENSE 0x1a
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define START_STOP 0x1b
+#define RECEIVE_DIAGNOSTIC 0x1c
+#define SEND_DIAGNOSTIC 0x1d
+#define ALLOW_MEDIUM_REMOVAL 0x1e
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define READ_FORMAT_CAPACITIES 0x23
+#define SET_WINDOW 0x24
+#define READ_CAPACITY 0x25
+#define READ_10 0x28
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define WRITE_10 0x2a
+#define SEEK_10 0x2b
+#define POSITION_TO_ELEMENT 0x2b
+#define WRITE_VERIFY 0x2e
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define VERIFY 0x2f
+#define SEARCH_HIGH 0x30
+#define SEARCH_EQUAL 0x31
+#define SEARCH_LOW 0x32
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SET_LIMITS 0x33
+#define PRE_FETCH 0x34
+#define READ_POSITION 0x34
+#define SYNCHRONIZE_CACHE 0x35
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define LOCK_UNLOCK_CACHE 0x36
+#define READ_DEFECT_DATA 0x37
+#define MEDIUM_SCAN 0x38
+#define COMPARE 0x39
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define COPY_VERIFY 0x3a
+#define WRITE_BUFFER 0x3b
+#define READ_BUFFER 0x3c
+#define UPDATE_BLOCK 0x3d
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define READ_LONG 0x3e
+#define WRITE_LONG 0x3f
+#define CHANGE_DEFINITION 0x40
+#define WRITE_SAME 0x41
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define UNMAP 0x42
+#define READ_TOC 0x43
+#define READ_HEADER 0x44
+#define GET_EVENT_STATUS_NOTIFICATION 0x4a
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define LOG_SELECT 0x4c
+#define LOG_SENSE 0x4d
+#define XDWRITEREAD_10 0x53
+#define MODE_SELECT_10 0x55
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define RESERVE_10 0x56
+#define RELEASE_10 0x57
+#define MODE_SENSE_10 0x5a
+#define PERSISTENT_RESERVE_IN 0x5e
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PERSISTENT_RESERVE_OUT 0x5f
+#define VARIABLE_LENGTH_CMD 0x7f
+#define REPORT_LUNS 0xa0
+#define SECURITY_PROTOCOL_IN 0xa2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MAINTENANCE_IN 0xa3
+#define MAINTENANCE_OUT 0xa4
+#define MOVE_MEDIUM 0xa5
+#define EXCHANGE_MEDIUM 0xa6
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define READ_12 0xa8
+#define WRITE_12 0xaa
+#define READ_MEDIA_SERIAL_NUMBER 0xab
+#define WRITE_VERIFY_12 0xae
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define VERIFY_12 0xaf
+#define SEARCH_HIGH_12 0xb0
+#define SEARCH_EQUAL_12 0xb1
+#define SEARCH_LOW_12 0xb2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SECURITY_PROTOCOL_OUT 0xb5
+#define READ_ELEMENT_STATUS 0xb8
+#define SEND_VOLUME_TAG 0xb6
+#define WRITE_LONG_2 0xea
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define EXTENDED_COPY 0x83
+#define RECEIVE_COPY_RESULTS 0x84
+#define ACCESS_CONTROL_IN 0x86
+#define ACCESS_CONTROL_OUT 0x87
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define READ_16 0x88
+#define COMPARE_AND_WRITE 0x89
+#define WRITE_16 0x8a
+#define READ_ATTRIBUTE 0x8c
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define WRITE_ATTRIBUTE 0x8d
+#define VERIFY_16 0x8f
+#define SYNCHRONIZE_CACHE_16 0x91
+#define WRITE_SAME_16 0x93
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SERVICE_ACTION_IN 0x9e
+#define GOOD 0x00
+#define CHECK_CONDITION 0x01
+#define CONDITION_GOOD 0x02
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define BUSY 0x04
+#define INTERMEDIATE_GOOD 0x08
+#define INTERMEDIATE_C_GOOD 0x0a
+#define RESERVATION_CONFLICT 0x0c
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define COMMAND_TERMINATED 0x11
+#define QUEUE_FULL 0x14
+#define ACA_ACTIVE 0x18
+#define TASK_ABORTED 0x20
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define STATUS_MASK 0xfe
+#define NO_SENSE 0x00
+#define RECOVERED_ERROR 0x01
+#define NOT_READY 0x02
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MEDIUM_ERROR 0x03
+#define HARDWARE_ERROR 0x04
+#define ILLEGAL_REQUEST 0x05
+#define UNIT_ATTENTION 0x06
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define DATA_PROTECT 0x07
+#define BLANK_CHECK 0x08
+#define COPY_ABORTED 0x0a
+#define ABORTED_COMMAND 0x0b
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define VOLUME_OVERFLOW 0x0d
+#define MISCOMPARE 0x0e
+#define TYPE_DISK 0x00
+#define TYPE_TAPE 0x01
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TYPE_PRINTER 0x02
+#define TYPE_PROCESSOR 0x03
+#define TYPE_WORM 0x04
+#define TYPE_ROM 0x05
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TYPE_SCANNER 0x06
+#define TYPE_MOD 0x07
+#define TYPE_MEDIUM_CHANGER 0x08
+#define TYPE_COMM 0x09
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TYPE_RAID 0x0c
+#define TYPE_ENCLOSURE 0x0d
+#define TYPE_RBC 0x0e
+#define TYPE_OSD 0x11
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TYPE_ZBC 0x14
+#define TYPE_WLUN 0x1e
+#define TYPE_NO_LUN 0x7f
+struct ccs_modesel_head {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u8 _r1;
+  __u8 medium;
+  __u8 _r2;
+  __u8 block_desc_length;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u8 density;
+  __u8 number_blocks_hi;
+  __u8 number_blocks_med;
+  __u8 number_blocks_lo;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u8 _r3;
+  __u8 block_length_hi;
+  __u8 block_length_med;
+  __u8 block_length_lo;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
+#define COMMAND_COMPLETE 0x00
+#define EXTENDED_MESSAGE 0x01
+#define EXTENDED_MODIFY_DATA_POINTER 0x00
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define EXTENDED_SDTR 0x01
+#define EXTENDED_EXTENDED_IDENTIFY 0x02
+#define EXTENDED_WDTR 0x03
+#define EXTENDED_PPR 0x04
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define EXTENDED_MODIFY_BIDI_DATA_PTR 0x05
+#define SAVE_POINTERS 0x02
+#define RESTORE_POINTERS 0x03
+#define DISCONNECT 0x04
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define INITIATOR_ERROR 0x05
+#define ABORT_TASK_SET 0x06
+#define MESSAGE_REJECT 0x07
+#define NOP 0x08
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MSG_PARITY_ERROR 0x09
+#define LINKED_CMD_COMPLETE 0x0a
+#define LINKED_FLG_CMD_COMPLETE 0x0b
+#define TARGET_RESET 0x0c
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ABORT_TASK 0x0d
+#define CLEAR_TASK_SET 0x0e
+#define INITIATE_RECOVERY 0x0f
+#define RELEASE_RECOVERY 0x10
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define CLEAR_ACA 0x16
+#define LOGICAL_UNIT_RESET 0x17
+#define SIMPLE_QUEUE_TAG 0x20
+#define HEAD_OF_QUEUE_TAG 0x21
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ORDERED_QUEUE_TAG 0x22
+#define IGNORE_WIDE_RESIDUE 0x23
+#define ACA 0x24
+#define QAS_REQUEST 0x55
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define BUS_DEVICE_RESET TARGET_RESET
+#define ABORT ABORT_TASK_SET
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+#define SCSI_IOCTL_PROBE_HOST 0x5385
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
+#define SCSI_IOCTL_GET_PCI 0x5387
+#endif
diff --git a/libc/kernel/common/scsi/scsi_ioctl.h b/libc/kernel/common/scsi/scsi_ioctl.h
new file mode 100644
index 0000000..c2f64a7
--- /dev/null
+++ b/libc/kernel/common/scsi/scsi_ioctl.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _SCSI_IOCTL_H
+#define _SCSI_IOCTL_H
+#define SCSI_IOCTL_SEND_COMMAND 1
+#define SCSI_IOCTL_TEST_UNIT_READY 2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SCSI_IOCTL_BENCHMARK_COMMAND 3
+#define SCSI_IOCTL_SYNC 4
+#define SCSI_IOCTL_START_UNIT 5
+#define SCSI_IOCTL_STOP_UNIT 6
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SCSI_IOCTL_DOORLOCK 0x5380
+#define SCSI_IOCTL_DOORUNLOCK 0x5381
+#define SCSI_REMOVAL_PREVENT 1
+#define SCSI_REMOVAL_ALLOW 0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#endif
diff --git a/libc/kernel/common/scsi/sg.h b/libc/kernel/common/scsi/sg.h
new file mode 100644
index 0000000..a38eccb
--- /dev/null
+++ b/libc/kernel/common/scsi/sg.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _SCSI_GENERIC_H
+#define _SCSI_GENERIC_H
+#include <linux/compiler.h>
+typedef struct sg_iovec {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  void __user * iov_base;
+  size_t iov_len;
+} sg_iovec_t;
+typedef struct sg_io_hdr {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  int interface_id;
+  int dxfer_direction;
+  unsigned char cmd_len;
+  unsigned char mx_sb_len;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned short iovec_count;
+  unsigned int dxfer_len;
+  void __user * dxferp;
+  unsigned char __user * cmdp;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  void __user * sbp;
+  unsigned int timeout;
+  unsigned int flags;
+  int pack_id;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  void __user * usr_ptr;
+  unsigned char status;
+  unsigned char masked_status;
+  unsigned char msg_status;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned char sb_len_wr;
+  unsigned short host_status;
+  unsigned short driver_status;
+  int resid;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned int duration;
+  unsigned int info;
+} sg_io_hdr_t;
+#define SG_INTERFACE_ID_ORIG 'S'
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_DXFER_NONE (- 1)
+#define SG_DXFER_TO_DEV (- 2)
+#define SG_DXFER_FROM_DEV (- 3)
+#define SG_DXFER_TO_FROM_DEV (- 4)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_DXFER_UNKNOWN (- 5)
+#define SG_FLAG_DIRECT_IO 1
+#define SG_FLAG_UNUSED_LUN_INHIBIT 2
+#define SG_FLAG_MMAP_IO 4
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_FLAG_NO_DXFER 0x10000
+#define SG_FLAG_Q_AT_TAIL 0x10
+#define SG_FLAG_Q_AT_HEAD 0x20
+#define SG_INFO_OK_MASK 0x1
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_INFO_OK 0x0
+#define SG_INFO_CHECK 0x1
+#define SG_INFO_DIRECT_IO_MASK 0x6
+#define SG_INFO_INDIRECT_IO 0x0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_INFO_DIRECT_IO 0x2
+#define SG_INFO_MIXED_IO 0x4
+typedef struct sg_scsi_id {
+  int host_no;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  int channel;
+  int scsi_id;
+  int lun;
+  int scsi_type;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  short h_cmd_per_lun;
+  short d_queue_depth;
+  int unused[2];
+} sg_scsi_id_t;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+typedef struct sg_req_info {
+  char req_state;
+  char orphan;
+  char sg_io_owned;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  char problem;
+  int pack_id;
+  void __user * usr_ptr;
+  unsigned int duration;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  int unused;
+} sg_req_info_t;
+#define SG_EMULATED_HOST 0x2203
+#define SG_SET_TRANSFORM 0x2204
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_GET_TRANSFORM 0x2205
+#define SG_SET_RESERVED_SIZE 0x2275
+#define SG_GET_RESERVED_SIZE 0x2272
+#define SG_GET_SCSI_ID 0x2276
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_SET_FORCE_LOW_DMA 0x2279
+#define SG_GET_LOW_DMA 0x227a
+#define SG_SET_FORCE_PACK_ID 0x227b
+#define SG_GET_PACK_ID 0x227c
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_GET_NUM_WAITING 0x227d
+#define SG_GET_SG_TABLESIZE 0x227F
+#define SG_GET_VERSION_NUM 0x2282
+#define SG_SCSI_RESET 0x2284
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_SCSI_RESET_NOTHING 0
+#define SG_SCSI_RESET_DEVICE 1
+#define SG_SCSI_RESET_BUS 2
+#define SG_SCSI_RESET_HOST 3
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_SCSI_RESET_TARGET 4
+#define SG_IO 0x2285
+#define SG_GET_REQUEST_TABLE 0x2286
+#define SG_SET_KEEP_ORPHAN 0x2287
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_GET_KEEP_ORPHAN 0x2288
+#define SG_GET_ACCESS_COUNT 0x2289
+#define SG_SCATTER_SZ (8 * 4096)
+#define SG_DEFAULT_RETRIES 0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_DEF_FORCE_LOW_DMA 0
+#define SG_DEF_FORCE_PACK_ID 0
+#define SG_DEF_KEEP_ORPHAN 0
+#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_MAX_QUEUE 16
+#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE
+typedef struct sg_io_hdr Sg_io_hdr;
+typedef struct sg_io_vec Sg_io_vec;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+typedef struct sg_scsi_id Sg_scsi_id;
+typedef struct sg_req_info Sg_req_info;
+#define SG_MAX_SENSE 16
+struct sg_header {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  int pack_len;
+  int reply_len;
+  int pack_id;
+  int result;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned int twelve_byte : 1;
+  unsigned int target_status : 5;
+  unsigned int host_status : 8;
+  unsigned int driver_status : 8;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned int other_flags : 10;
+  unsigned char sense_buffer[SG_MAX_SENSE];
+};
+#define SG_SET_TIMEOUT 0x2201
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_GET_TIMEOUT 0x2202
+#define SG_GET_COMMAND_Q 0x2270
+#define SG_SET_COMMAND_Q 0x2271
+#define SG_SET_DEBUG 0x227e
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_NEXT_CMD_LEN 0x2283
+#define SG_DEFAULT_TIMEOUT (60 * HZ)
+#define SG_DEF_COMMAND_Q 0
+#define SG_DEF_UNDERRUN_FLAG 0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#endif
diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py
index 0e0ed76..e84bcf9 100755
--- a/libc/kernel/tools/clean_header.py
+++ b/libc/kernel/tools/clean_header.py
@@ -73,90 +73,77 @@
 from defaults import *
 from utils import *
 
-noUpdate = 1
+def print_error(no_update, msg):
+    if no_update:
+        panic(msg)
+    sys.stderr.write("warning: " + msg)
 
-def cleanupFile(path, original_path):
+
+def cleanupFile(dst_dir, src_dir, rel_path, no_update = True):
     """reads an original header and perform the cleanup operation on it
        this functions returns the destination path and the clean header
        as a single string"""
     # check the header path
-    src_path = path
+    full_path = os.path.join(src_dir, rel_path)
 
-    if not os.path.exists(src_path):
-        if noUpdate:
-            panic( "file does not exist: '%s'\n" % path )
-        sys.stderr.write( "warning: file does not exit: %s\n" % path )
+    if not os.path.exists(full_path):
+        print_error(no_update, "file does not exist: '%s'\n" % full_path)
         return None, None
 
-    if not os.path.isfile(src_path):
-        if noUpdate:
-            panic( "path is not a file: '%s'\n" % path )
-        sys.stderr.write( "warning: not a file: %s\n" % path )
+    if not os.path.isfile(full_path):
+        print_error(no_update, "path is not a file: '%s'\n" % full_path)
         return None, None
 
-    if os.path.commonprefix( [ src_path, original_path ] ) != original_path:
-        if noUpdate:
-            panic( "file is not in 'original' directory: %s\n" % path );
-        sys.stderr.write( "warning: file not in 'original' ignored: %s\n" % path )
-        return None, None
-
-    src_path = src_path[len(original_path):]
-    if len(src_path) > 0 and src_path[0] == '/':
-        src_path = src_path[1:]
-
-    if len(src_path) == 0:
-        panic( "oops, internal error, can't extract correct relative path\n" )
-
     # convert into destination path, extracting architecture if needed
     # and the corresponding list of known static functions
     #
     arch = None
     statics = kernel_known_generic_statics
-    m = re.match(r"asm-([\w\d_\+\.\-]+)(/.*)", src_path)
+    m = re.match(r"asm-([\w\d_\+\.\-]+)(/.*)", rel_path)
     if m and m.group(1) != 'generic':
         dst_path = "arch-%s/asm/%s" % m.groups()
-        arch     = m.group(1)
-        statics  = statics.union( kernel_known_statics.get( arch, set() ) )
+        arch = m.group(1)
+        statics  = statics.union(kernel_known_statics.get(arch, set()))
     else:
         # process headers under the uapi directory
         # note the "asm" level has been explicitly added in the original
         # kernel header tree for architectural-dependent uapi headers
-        m_uapi = re.match(r"(uapi)/([\w\d_\+\.\-]+)(/.*)", src_path)
+        m_uapi = re.match(r"(uapi)/([\w\d_\+\.\-]+)(/.*)", rel_path)
         if m_uapi:
-            dst_path = src_path
+            dst_path = rel_path
             m_uapi_arch = re.match(r"asm-([\w\d_\+\.\-]+)", m_uapi.group(2))
             if m_uapi_arch and m_uapi_arch.group(1) != 'generic':
-                arch     = m_uapi_arch.group(1)
-                statics  = statics.union( kernel_known_statics.get( arch, set() ) )
+                arch = m_uapi_arch.group(1)
+                statics = statics.union(kernel_known_statics.get(arch, set()))
         # common headers (ie non-asm and non-uapi)
         else:
-            dst_path = "common/" + src_path
+            dst_path = os.path.join("common", rel_path)
 
-    dst_path = os.path.normpath( kernel_cleaned_path + "/" + dst_path )
+    dst_path = os.path.join(dst_dir, dst_path)
 
     # now, let's parse the file
     #
     parser = cpp.BlockParser()
-    blocks = parser.parseFile(path)
+    blocks = parser.parseFile(full_path)
     if not parser.parsed:
-        sys.stderr.write( "error: can't parse '%s'" % path )
-        sys.exit(1)
+        print_error(no_update, "can't parse '%s'%" % full_path)
+        return None, None
 
     macros = kernel_known_macros.copy()
     if arch and arch in kernel_default_arch_macros:
         macros.update(kernel_default_arch_macros[arch])
 
     if arch and arch in kernel_arch_token_replacements:
-        blocks.replaceTokens( kernel_arch_token_replacements[arch] )
+        blocks.replaceTokens(kernel_arch_token_replacements[arch])
 
-    blocks.optimizeMacros( macros )
+    blocks.optimizeMacros(macros)
     blocks.optimizeIf01()
-    blocks.removeVarsAndFuncs( statics )
-    blocks.replaceTokens( kernel_token_replacements )
-    blocks.removeMacroDefines( kernel_ignored_macros )
+    blocks.removeVarsAndFuncs(statics)
+    blocks.replaceTokens(kernel_token_replacements)
+    blocks.removeMacroDefines(kernel_ignored_macros)
 
     out = StringOutput()
-    out.write( kernel_disclaimer )
+    out.write(kernel_disclaimer)
     blocks.writeWithWarning(out, kernel_warning, 4)
     return dst_path, out.get()
 
@@ -183,28 +170,31 @@
         sys.exit(1)
 
     try:
-        optlist, args = getopt.getopt( sys.argv[1:], 'uvk:d:' )
+        optlist, args = getopt.getopt(sys.argv[1:], 'uvk:d:')
     except:
         # unrecognized option
-        sys.stderr.write( "error: unrecognized option\n" )
+        sys.stderr.write("error: unrecognized option\n")
         usage()
 
+    no_update = True
+    dst_dir = get_kernel_dir()
+    src_dir = get_kernel_headers_original_dir()
     for opt, arg in optlist:
         if opt == '-u':
-            noUpdate = 0
+            no_update = False
         elif opt == '-v':
             logging.basicConfig(level=logging.DEBUG)
         elif opt == '-k':
-            kernel_original_path = arg
+            src_dir = arg
         elif opt == '-d':
-            kernel_cleaned_path = arg
+            dst_dir = arg
 
     if len(args) == 0:
         usage()
 
-    if noUpdate:
+    if no_update:
         for path in args:
-            dst_path, newdata = cleanupFile(path,kernel_original_path)
+            dst_path, newdata = cleanupFile(dst_dir, src_dir, path)
             print newdata
 
         sys.exit(0)
@@ -214,12 +204,12 @@
     b = BatchFileUpdater()
 
     for path in args:
-        dst_path, newdata = cleanupFile(path,kernel_original_path)
+        dst_path, newdata = cleanupFile(dst_dir, src_dir, path, no_update)
         if not dst_path:
             continue
 
-        b.readFile( dst_path )
-        r = b.editFile( dst_path, newdata )
+        b.readFile(dst_path)
+        r = b.editFile(dst_path, newdata)
         if r == 0:
             r = "unchanged"
         elif r == 1:
@@ -227,7 +217,7 @@
         else:
             r = "added"
 
-        print "cleaning: %-*s -> %-*s (%s)" % ( 35, path, 35, dst_path, r )
+        print "cleaning: %-*s -> %-*s (%s)" % (35, path, 35, dst_path, r)
 
 
     b.updateGitFiles()
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 8aba998..773d22f 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -12,12 +12,6 @@
 # tree. used when looking for sources...
 kernel_dirs = [ "linux", "asm", "asm-generic", "mtd" ]
 
-# path to the directory containing the original kernel headers
-kernel_original_path = os.path.normpath( find_program_dir() + '/../../../../external/kernel-headers/original' )
-
-# path to the default location of the cleaned-up headers
-kernel_cleaned_path = os.path.normpath( find_program_dir() + '/..' )
-
 # a special value that is used to indicate that a given macro is known to be
 # undefined during optimization
 kCppUndefinedMacro = "<<<undefined>>>"
@@ -70,6 +64,8 @@
     # The kernel's SIGRTMIN/SIGRTMAX are absolute limits; userspace steals a few.
     "SIGRTMIN": "__SIGRTMIN",
     "SIGRTMAX": "__SIGRTMAX",
+    # We want to support both BSD and Linux member names in struct udphdr.
+    "udphdr": "__kernel_udphdr",
     }
 
 # this is the set of known static inline functions that we want to keep
diff --git a/libc/kernel/tools/generate_uapi_headers.sh b/libc/kernel/tools/generate_uapi_headers.sh
index 90ba0ed..3c80d9f 100755
--- a/libc/kernel/tools/generate_uapi_headers.sh
+++ b/libc/kernel/tools/generate_uapi_headers.sh
@@ -99,6 +99,35 @@
   done
 }
 
+function check_hdrs () {
+  local src_dir=$1
+  local tgt_dir=$2
+  local kernel_dir=$3
+
+  local search_dirs=()
+
+  # This only works if none of the filenames have spaces.
+  for file in $(ls -d ${src_dir}/* 2> /dev/null); do
+    if [[ -d "${file}" ]]; then
+      search_dirs+=("${file}")
+    elif [[ -f  "${file}" ]] && [[ "${file}" =~ .h$ ]]; then
+      tgt_file=${tgt_dir}/$(basename ${file})
+      if [[ -e ${tgt_file} ]] && ! diff "${file}" "${tgt_file}" > /dev/null; then
+        if [[ ${file} =~ ${kernel_dir}/*(.+) ]]; then
+          echo "New version of ${BASH_REMATCH[1]} found in kernel headers."
+        else
+          echo "New version of ${file} found in kernel headers."
+        fi
+        echo "This file needs to be updated manually."
+      fi
+    fi
+  done
+
+  for dir in "${search_dirs[@]}"; do
+    check_hdrs "${dir}" ${tgt_dir}/$(basename ${dir}) "${kernel_dir}"
+  done
+}
+
 trap cleanup EXIT
 # This automatically triggers a call to cleanup.
 trap "exit 1" HUP INT TERM TSTP
@@ -207,3 +236,8 @@
                  "${KERNEL_DIR}/${src_dir}/arch/${arch}/include/generated/asm" \
                  "${ANDROID_KERNEL_DIR}/uapi/asm-${arch}/asm"
 done
+
+# Verify if modified headers have changed.
+check_hdrs "${KERNEL_DIR}/${src_dir}/include/scsi" \
+           "${ANDROID_KERNEL_DIR}/scsi" \
+           "${KERNEL_DIR}/${src_dir}"
diff --git a/libc/kernel/tools/update_all.py b/libc/kernel/tools/update_all.py
index f45d4e0..7f3657c 100755
--- a/libc/kernel/tools/update_all.py
+++ b/libc/kernel/tools/update_all.py
@@ -6,72 +6,93 @@
 
 def usage():
     print """\
-  usage: %(progname)s [kernel-original-path]
+  usage: %(progname)s [kernel-original-path] [kernel-modified-path]
 
     this program is used to update all the auto-generated clean headers
     used by the Bionic C library. it assumes the following:
 
-      - a set of source kernel headers is located in '../original',
-        relative to the program's directory
+      - a set of source kernel headers is located in
+        'external/kernel-headers/original', relative to the current
+        android tree
 
-      - the clean headers will be placed in '../arch-<arch>/asm',
-        '../common/linux', '../common/asm-generic', etc..
+      - a set of manually modified kernel header files located in
+        'external/kernel-headers/modified', relative to the current
+        android tree
+
+      - the clean headers will be placed in 'bionic/libc/kernel/arch-<arch>/asm',
+        'bionic/libc/kernel/common', etc..
 """ % { "progname" : os.path.basename(sys.argv[0]) }
     sys.exit(0)
 
 try:
-    optlist, args = getopt.getopt( sys.argv[1:], '' )
+    optlist, args = getopt.getopt(sys.argv[1:], '')
 except:
     # unrecognized option
-    sys.stderr.write( "error: unrecognized option\n" )
+    sys.stderr.write("error: unrecognized option\n")
     usage()
 
-if len(optlist) > 0 or len(args) > 1:
+if len(optlist) > 0 or len(args) > 2:
     usage()
 
-progdir = find_program_dir()
-
-if len(args) == 1:
+modified_dir = get_kernel_headers_modified_dir()
+if len(args) == 1 or len(args) == 2:
     original_dir = args[0]
     if not os.path.isdir(original_dir):
-        panic( "Not a directory: %s\n" % original_dir )
+        panic("Not a directory: %s\n" % original_dir)
+
+    if len(args) == 2:
+        modified_dir = args[1]
+        if not os.path.isdir(modified_dir):
+            panic("Not a directory: %s\n" % modified_dir)
 else:
-    original_dir = kernel_original_path
+    original_dir = get_kernel_headers_original_dir()
     if not os.path.isdir(original_dir):
-        panic( "Missing directory, please specify one through command-line: %s\n" % original_dir )
+        panic("Missing directory, please specify one through command-line: %s\n" % original_dir)
 
-skip_ion = False
+if not os.path.isdir(modified_dir):
+    modified_dir = None
 
-# find all source files in 'original'
-#
-sources = []
-warning_ion = []
-for root, dirs, files in os.walk( original_dir ):
+# Find all source files in 'original'.
+sources = dict()
+original_dir = os.path.normpath(original_dir)
+original_dir_len = len(original_dir) + 1
+for root, _, files in os.walk(original_dir):
     for file in files:
-        if skip_ion and (file == "ion.h" or file == "ion_test.h"):
-            warning_ion.append("  Skipped file %s/%s" % (root, file))
-            continue
-        base, ext = os.path.splitext(file)
+        _, ext = os.path.splitext(file)
         if ext == ".h":
-            sources.append( "%s/%s" % (root,file) )
+            rel_path = os.path.normpath(os.path.join(root, file))
+            rel_path = rel_path[original_dir_len:]
+            # Check to see if there is a modified header to use instead.
+            if modified_dir and os.path.exists(os.path.join(modified_dir, rel_path)):
+                sources[rel_path] = False
+            else:
+                sources[rel_path] = True
+
 
 b = BatchFileUpdater()
 
+kernel_dir = get_kernel_dir()
 for arch in kernel_archs:
-    b.readDir( os.path.normpath( progdir + "/../arch-%s" % arch ) )
+    b.readDir(os.path.join(kernel_dir, "arch-%s" % arch))
 
-b.readDir( os.path.normpath( progdir + "/../common" ) )
-
-#print "OLD " + repr(b.old_files)
+b.readDir(os.path.join(kernel_dir, "common"))
 
 oldlen = 120
-for path in sources:
-    dst_path, newdata = clean_header.cleanupFile(path, original_dir)
+android_root_len = len(get_android_root()) + 1
+for rel_path in sorted(sources):
+    if sources[rel_path]:
+        src_dir = original_dir
+        src_str = "<original>/"
+    else:
+        src_dir = modified_dir
+        src_str = "<modified>/"
+    dst_path, newdata = clean_header.cleanupFile(kernel_dir, src_dir, rel_path)
     if not dst_path:
         continue
 
-    b.readFile( dst_path )
-    r = b.editFile( dst_path, newdata )
+    dst_path = os.path.join(kernel_dir, dst_path)
+    b.readFile(dst_path)
+    r = b.editFile(dst_path, newdata)
     if r == 0:
         state = "unchanged"
     elif r == 1:
@@ -79,9 +100,11 @@
     else:
         state = "added"
 
-    str = "cleaning: %-*s -> %-*s (%s)" % ( 35, "<original>" + path[len(original_dir):], 35, dst_path, state )
+    # dst_path is guaranteed to include android root.
+    rel_dst_path = dst_path[android_root_len:]
+    str = "cleaning: %-*s -> %-*s (%s)" % (35, src_str + rel_path, 35, rel_dst_path, state)
     if sys.stdout.isatty():
-        print "%-*s" % (oldlen,str),
+        print "%-*s" % (oldlen, str),
         if (r == 0):
             print "\r",
         else:
@@ -92,11 +115,8 @@
 
     oldlen = len(str)
 
-print "%-*s" % (oldlen,"Done!")
+print "%-*s" % (oldlen, "Done!")
 
 b.updateGitFiles()
 
-if warning_ion:
-    print "NOTE: Due to import into aosp, some files were not processed."
-    print "\n".join(warning_ion)
 sys.exit(0)
diff --git a/libc/kernel/tools/utils.py b/libc/kernel/tools/utils.py
index e5a310e..e2cc9ce 100644
--- a/libc/kernel/tools/utils.py
+++ b/libc/kernel/tools/utils.py
@@ -13,8 +13,26 @@
     sys.exit(1)
 
 
-def find_program_dir():
-    return os.path.dirname(sys.argv[0])
+def get_kernel_headers_dir():
+    return os.path.join(get_android_root(), "external/kernel-headers")
+
+
+def get_kernel_headers_original_dir():
+    return os.path.join(get_kernel_headers_dir(), "original")
+
+
+def get_kernel_headers_modified_dir():
+    return os.path.join(get_kernel_headers_dir(), "modified")
+
+
+def get_kernel_dir():
+    return os.path.join(get_android_root(), "bionic/libc/kernel")
+
+
+def get_android_root():
+    if "ANDROID_BUILD_TOP" in os.environ:
+        return os.environ["ANDROID_BUILD_TOP"]
+    panic("Unable to find root of tree, did you forget to lunch a target?")
 
 
 class StringOutput:
diff --git a/libc/kernel/uapi/linux/udp.h b/libc/kernel/uapi/linux/udp.h
index e1d546c..a3e9e97 100644
--- a/libc/kernel/uapi/linux/udp.h
+++ b/libc/kernel/uapi/linux/udp.h
@@ -19,7 +19,7 @@
 #ifndef _UAPI_LINUX_UDP_H
 #define _UAPI_LINUX_UDP_H
 #include <linux/types.h>
-struct udphdr {
+struct __kernel_udphdr {
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
   __be16 source;
   __be16 dest;
diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h
new file mode 100644
index 0000000..1133e2a
--- /dev/null
+++ b/libc/private/WriteProtected.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _PRIVATE_WRITEPROTECTED_H
+#define _PRIVATE_WRITEPROTECTED_H
+
+#include <errno.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+
+#include "private/bionic_macros.h"
+#include "private/bionic_prctl.h"
+#include "private/libc_logging.h"
+
+template <typename T>
+union WriteProtectedContents {
+  T value;
+  char padding[PAGE_SIZE];
+
+  WriteProtectedContents() = default;
+  DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents);
+} __attribute__((aligned(PAGE_SIZE)));
+
+// Write protected wrapper class that aligns its contents to a page boundary,
+// and sets the memory protection to be non-writable, except when being modified
+// explicitly.
+template <typename T>
+class WriteProtected {
+  static_assert(sizeof(T) < PAGE_SIZE,
+                "WriteProtected only supports contents up to PAGE_SIZE");
+  static_assert(__is_pod(T), "WriteProtected only supports POD contents");
+
+  WriteProtectedContents<T> contents;
+
+ public:
+  WriteProtected() = default;
+  DISALLOW_COPY_AND_ASSIGN(WriteProtected);
+
+  void initialize() {
+    // Not strictly necessary, but this will hopefully segfault if we initialize
+    // multiple times by accident.
+    memset(&contents, 0, sizeof(contents));
+
+    if (mprotect(&contents, PAGE_SIZE, PROT_READ)) {
+      __libc_fatal("failed to make WriteProtected nonwritable in initialize");
+    }
+  }
+
+  const T* operator->() {
+    return &contents.value;
+  }
+
+  const T& operator*() {
+    return contents.value;
+  }
+
+  template <typename Mutator>
+  void mutate(Mutator mutator) {
+    if (mprotect(&contents, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+      __libc_fatal("failed to make WriteProtected writable in mutate: %s",
+                   strerror(errno));
+    }
+    mutator(&contents.value);
+    if (mprotect(&contents, PAGE_SIZE, PROT_READ) != 0) {
+      __libc_fatal("failed to make WriteProtected nonwritable in mutate: %s",
+                   strerror(errno));
+    }
+  }
+};
+
+#endif
diff --git a/libc/private/bionic_asm.h b/libc/private/bionic_asm.h
index 5fca222..e2084d4 100644
--- a/libc/private/bionic_asm.h
+++ b/libc/private/bionic_asm.h
@@ -38,25 +38,36 @@
 
 #include <machine/asm.h>
 
-#define ENTRY(f) \
+#define ENTRY_NO_DWARF(f) \
     .text; \
     .globl f; \
     .align __bionic_asm_align; \
     .type f, __bionic_asm_function_type; \
     f: \
     __bionic_asm_custom_entry(f); \
+
+#define ENTRY(f) \
+    ENTRY_NO_DWARF(f) \
     .cfi_startproc \
 
+#define END_NO_DWARF(f) \
+    .size f, .-f; \
+    __bionic_asm_custom_end(f) \
+
 #define END(f) \
     .cfi_endproc; \
-    .size f, .-f; \
-    __bionic_asm_custom_end(f) \
+    END_NO_DWARF(f) \
 
 /* Like ENTRY, but with hidden visibility. */
 #define ENTRY_PRIVATE(f) \
     ENTRY(f); \
     .hidden f \
 
+/* Like ENTRY_NO_DWARF, but with hidden visibility. */
+#define ENTRY_PRIVATE_NO_DWARF(f) \
+    ENTRY_NO_DWARF(f); \
+    .hidden f \
+
 #define ALIAS_SYMBOL(alias, original) \
     .globl alias; \
     .equ alias, original
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
new file mode 100644
index 0000000..644b5a4
--- /dev/null
+++ b/libc/private/bionic_globals.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 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 _PRIVATE_BIONIC_GLOBALS_H
+#define _PRIVATE_BIONIC_GLOBALS_H
+
+#include <sys/cdefs.h>
+#include "private/bionic_vdso.h"
+#include "private/WriteProtected.h"
+
+struct libc_globals {
+  vdso_entry vdso[VDSO_END];
+  long setjmp_cookie;
+};
+
+__LIBC_HIDDEN__ extern WriteProtected<libc_globals> __libc_globals;
+
+class KernelArgumentBlock;
+__LIBC_HIDDEN__ void __libc_init_vdso(libc_globals* globals,
+                                      KernelArgumentBlock& args);
+__LIBC_HIDDEN__ void __libc_init_setjmp_cookie(libc_globals* globals,
+                                               KernelArgumentBlock& args);
+
+#endif
diff --git a/libc/private/bionic_vdso.h b/libc/private/bionic_vdso.h
new file mode 100644
index 0000000..5400de5
--- /dev/null
+++ b/libc/private/bionic_vdso.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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 _PRIVATE_BIONIC_VDSO_H
+#define _PRIVATE_BIONIC_VDSO_H
+
+#include <time.h>
+
+#if defined(__aarch64__)
+#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
+#define VDSO_GETTIMEOFDAY_SYMBOL  "__kernel_gettimeofday"
+#elif defined(__x86_64__) || defined(__i386__)
+#define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
+#define VDSO_GETTIMEOFDAY_SYMBOL  "__vdso_gettimeofday"
+#endif
+
+extern "C" int __clock_gettime(int, timespec*);
+extern "C" int __gettimeofday(timeval*, struct timezone*);
+
+struct vdso_entry {
+  const char* name;
+  void* fn;
+};
+
+enum {
+  VDSO_CLOCK_GETTIME = 0,
+  VDSO_GETTIMEOFDAY,
+  VDSO_END
+};
+
+#endif  // _PRIVATE_BIONIC_VDSO_H
diff --git a/libc/private/get_cpu_count_from_string.h b/libc/private/get_cpu_count_from_string.h
new file mode 100644
index 0000000..a0cb95d
--- /dev/null
+++ b/libc/private/get_cpu_count_from_string.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 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 <ctype.h>
+#include <stdlib.h>
+
+// Parse a string like: 0, 2-4, 6.
+static int GetCpuCountFromString(const char* s) {
+  int cpu_count = 0;
+  int last_cpu = -1;
+  while (*s != '\0') {
+    if (isdigit(*s)) {
+      int cpu = static_cast<int>(strtol(s, const_cast<char**>(&s), 10));
+      if (last_cpu != -1) {
+        cpu_count += cpu - last_cpu;
+      } else {
+        cpu_count++;
+      }
+      last_cpu = cpu;
+    } else {
+      if (*s == ',') {
+        last_cpu = -1;
+      }
+      s++;
+    }
+  }
+  return cpu_count;
+}
diff --git a/libc/stdio/fileext.h b/libc/stdio/fileext.h
deleted file mode 100644
index 6cacc0f..0000000
--- a/libc/stdio/fileext.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*	$OpenBSD: fileext.h,v 1.2 2005/06/17 20:40:32 espie Exp $	*/
-/* $NetBSD: fileext.h,v 1.5 2003/07/18 21:46:41 nathanw Exp $ */
-
-/*-
- * Copyright (c)2001 Citrus 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:
- * 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.
- *
- * $Citrus$
- */
-
-#ifndef _FILEEXT_H_
-#define _FILEEXT_H_
-
-#include <pthread.h>
-#include <stdbool.h>
-
-__BEGIN_DECLS
-
-/*
- * file extension
- */
-struct __sfileext {
-	struct	__sbuf _ub;		/* ungetc buffer */
-	struct wchar_io_data _wcio;	/* wide char io status */
-	pthread_mutex_t _lock;		/* file lock */
-	bool _stdio_handles_locking;	/* __fsetlocking support */
-};
-
-#if defined(__cplusplus)
-#define _EXT(fp) reinterpret_cast<__sfileext*>((fp)->_ext._base)
-#else
-#define _EXT(fp) ((struct __sfileext *)((fp)->_ext._base))
-#endif
-
-#define _UB(fp) _EXT(fp)->_ub
-#define _FLOCK(fp)  _EXT(fp)->_lock
-
-#define _FILEEXT_INIT(fp) \
-do { \
-	_UB(fp)._base = NULL; \
-	_UB(fp)._size = 0; \
-	WCIO_INIT(fp); \
-	pthread_mutexattr_t attr; \
-	pthread_mutexattr_init(&attr); \
-	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
-	pthread_mutex_init(&_FLOCK(fp), &attr); \
-	pthread_mutexattr_destroy(&attr); \
-	_EXT(fp)->_stdio_handles_locking = true; \
-} while (0)
-
-#define _FILEEXT_SETUP(f, fext) \
-do { \
-	(f)->_ext._base = (unsigned char *)(fext); \
-	_FILEEXT_INIT(f); \
-} while (0)
-
-__END_DECLS
-
-#endif /* _FILEEXT_H_ */
diff --git a/libc/stdio/findfp.c b/libc/stdio/findfp.c
index 5e51198..2696cfd 100644
--- a/libc/stdio/findfp.c
+++ b/libc/stdio/findfp.c
@@ -60,15 +60,20 @@
 _THREAD_PRIVATE_MUTEX(__sfp_mutex);
 
 static struct __sfileext __sFext[3];
+
+// __sF is exported for backwards compatibility. Until M, we didn't have symbols
+// for stdin/stdout/stderr; they were macros accessing __sF.
 FILE __sF[3] = {
 	std(__SRD, STDIN_FILENO),		/* stdin */
 	std(__SWR, STDOUT_FILENO),		/* stdout */
 	std(__SWR|__SNBF, STDERR_FILENO)	/* stderr */
 };
+
+struct glue __sglue = { &uglue, 3, __sF };
+
 FILE* stdin = &__sF[0];
 FILE* stdout = &__sF[1];
 FILE* stderr = &__sF[2];
-struct glue __sglue = { &uglue, 3, __sF };
 
 static struct glue *
 moreglue(int n)
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index ce04141..749de7b 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -32,17 +32,114 @@
  * SUCH DAMAGE.
  */
 
+#ifndef __BIONIC_STDIO_LOCAL_H__
+#define __BIONIC_STDIO_LOCAL_H__
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <wchar.h>
+#include "wcio.h"
+
 /*
  * Information local to this implementation of stdio,
  * in particular, macros and private variables.
  */
 
-#include <wchar.h>
-#include "wcio.h"
-#include "fileext.h"
-
 __BEGIN_DECLS
 
+struct __sbuf {
+  unsigned char* _base;
+#if defined(__LP64__)
+  size_t _size;
+#else
+  int _size;
+#endif
+};
+
+struct __sFILE {
+	unsigned char *_p;	/* current position in (some) buffer */
+	int	_r;		/* read space left for getc() */
+	int	_w;		/* write space left for putc() */
+#if defined(__LP64__)
+	int	_flags;		/* flags, below; this FILE is free if 0 */
+	int	_file;		/* fileno, if Unix descriptor, else -1 */
+#else
+	short	_flags;		/* flags, below; this FILE is free if 0 */
+	short	_file;		/* fileno, if Unix descriptor, else -1 */
+#endif
+	struct	__sbuf _bf;	/* the buffer (at least 1 byte, if !NULL) */
+	int	_lbfsize;	/* 0 or -_bf._size, for inline putc */
+
+	/* operations */
+	void	*_cookie;	/* cookie passed to io functions */
+	int	(*_close)(void *);
+	int	(*_read)(void *, char *, int);
+	fpos_t	(*_seek)(void *, fpos_t, int);
+	int	(*_write)(void *, const char *, int);
+
+	/* extension data, to avoid further ABI breakage */
+	struct	__sbuf _ext;
+	/* data for long sequences of ungetc() */
+	unsigned char *_up;	/* saved _p when _p is doing ungetc data */
+	int	_ur;		/* saved _r when _r is counting ungetc data */
+
+	/* tricks to meet minimum requirements even when malloc() fails */
+	unsigned char _ubuf[3];	/* guarantee an ungetc() buffer */
+	unsigned char _nbuf[1];	/* guarantee a getc() buffer */
+
+	/* separate buffer for fgetln() when line crosses buffer boundary */
+	struct	__sbuf _lb;	/* buffer for fgetln() */
+
+	/* Unix stdio files get aligned to block boundaries on fseek() */
+	int	_blksize;	/* stat.st_blksize (may be != _bf._size) */
+	fpos_t	_offset;	/* current lseek offset */
+};
+
+/*
+ * file extension
+ */
+struct __sfileext {
+  /* ungetc buffer */
+  struct __sbuf _ub;
+
+  /* wide char io status */
+  struct wchar_io_data _wcio;
+
+  /* file lock */
+  pthread_mutex_t _lock;
+
+  /* __fsetlocking support */
+  bool _stdio_handles_locking;
+};
+
+#if defined(__cplusplus)
+#define _EXT(fp) reinterpret_cast<__sfileext*>((fp)->_ext._base)
+#else
+#define _EXT(fp) ((struct __sfileext *)((fp)->_ext._base))
+#endif
+
+#define _UB(fp) _EXT(fp)->_ub
+#define _FLOCK(fp)  _EXT(fp)->_lock
+
+#define _FILEEXT_INIT(fp) \
+do { \
+	_UB(fp)._base = NULL; \
+	_UB(fp)._size = 0; \
+	WCIO_INIT(fp); \
+	pthread_mutexattr_t attr; \
+	pthread_mutexattr_init(&attr); \
+	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
+	pthread_mutex_init(&_FLOCK(fp), &attr); \
+	pthread_mutexattr_destroy(&attr); \
+	_EXT(fp)->_stdio_handles_locking = true; \
+} while (0)
+
+#define _FILEEXT_SETUP(f, fext) \
+do { \
+	(f)->_ext._base = (unsigned char *)(fext); \
+	_FILEEXT_INIT(f); \
+} while (0)
+
 /*
  * Android <= KitKat had getc/putc macros in <stdio.h> that referred
  * to __srget/__swbuf, so those symbols need to be public for LP32
@@ -143,3 +240,5 @@
 #pragma GCC visibility pop
 
 __END_DECLS
+
+#endif
diff --git a/libc/upstream-openbsd/lib/libc/stdio/refill.c b/libc/stdio/refill.c
similarity index 98%
rename from libc/upstream-openbsd/lib/libc/stdio/refill.c
rename to libc/stdio/refill.c
index 165c72a..e87c7b9 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/refill.c
+++ b/libc/stdio/refill.c
@@ -58,9 +58,11 @@
 
 	fp->_r = 0;		/* largely a convenience for callers */
 
+#if !defined(__ANDROID__)
 	/* SysV does not make this test; take it out for compatibility */
 	if (fp->_flags & __SEOF)
 		return (EOF);
+#endif
 
 	/* if not already reading, have to be reading and writing */
 	if ((fp->_flags & __SRD) == 0) {
diff --git a/libc/tzcode/asctime.c b/libc/tzcode/asctime.c
index fea24e4..337a313 100644
--- a/libc/tzcode/asctime.c
+++ b/libc/tzcode/asctime.c
@@ -55,7 +55,7 @@
 ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648     -2147483648\n
 ** (two three-character abbreviations, five strings denoting integers,
 ** seven explicit spaces, two explicit colons, a newline,
-** and a trailing ASCII nul).
+** and a trailing NUL byte).
 ** The values above are for systems where an int is 32 bits and are provided
 ** as an example; the define below calculates the maximum for the system at
 ** hand.
@@ -99,11 +99,11 @@
 	** Assume that strftime is unaffected by other out-of-range members
 	** (e.g., timeptr->tm_mday) when processing "%Y".
 	*/
-	(void) strftime(year, sizeof year, "%Y", timeptr);
+	strftime(year, sizeof year, "%Y", timeptr);
 	/*
 	** We avoid using snprintf since it's not available on all systems.
 	*/
-	(void) snprintf(result, sizeof(result), /* Android change: use snprintf. */
+	snprintf(result, sizeof(result), /* Android change: use snprintf. */
 		((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
 		wn, mn,
 		timeptr->tm_mday, timeptr->tm_hour,
@@ -112,11 +112,7 @@
 	if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime)
 		return strcpy(buf, result);
 	else {
-#ifdef EOVERFLOW
 		errno = EOVERFLOW;
-#else /* !defined EOVERFLOW */
-		errno = EINVAL;
-#endif /* !defined EOVERFLOW */
 		return NULL;
 	}
 }
diff --git a/libc/tzcode/difftime.c b/libc/tzcode/difftime.c
index 449cdf0..ba2fd03 100644
--- a/libc/tzcode/difftime.c
+++ b/libc/tzcode/difftime.c
@@ -7,42 +7,52 @@
 
 #include "private.h"	/* for time_t and TYPE_SIGNED */
 
+/* Return -X as a double.  Using this avoids casting to 'double'.  */
+static double
+dminus(double x)
+{
+  return -x;
+}
+
 double ATTRIBUTE_CONST
-difftime(const time_t time1, const time_t time0)
+difftime(time_t time1, time_t time0)
 {
 	/*
-	** If (sizeof (double) > sizeof (time_t)) simply convert and subtract
+	** If double is large enough, simply convert and subtract
 	** (assuming that the larger type has more precision).
 	*/
-	if (sizeof (double) > sizeof (time_t))
-		return (double) time1 - (double) time0;
-	if (!TYPE_SIGNED(time_t)) {
-		/*
-		** The difference of two unsigned values can't overflow
-		** if the minuend is greater than or equal to the subtrahend.
-		*/
-		if (time1 >= time0)
-			return            time1 - time0;
-		else	return -(double) (time0 - time1);
+	if (sizeof (time_t) < sizeof (double)) {
+	  double t1 = time1, t0 = time0;
+	  return t1 - t0;
 	}
+
+	/*
+	** The difference of two unsigned values can't overflow
+	** if the minuend is greater than or equal to the subtrahend.
+	*/
+	if (!TYPE_SIGNED(time_t))
+	  return time0 <= time1 ? time1 - time0 : dminus(time0 - time1);
+
+	/* Use uintmax_t if wide enough.  */
+	if (sizeof (time_t) <= sizeof (uintmax_t)) {
+	  uintmax_t t1 = time1, t0 = time0;
+	  return time0 <= time1 ? t1 - t0 : dminus(t0 - t1);
+	}
+
 	/*
 	** Handle cases where both time1 and time0 have the same sign
 	** (meaning that their difference cannot overflow).
 	*/
 	if ((time1 < 0) == (time0 < 0))
-		return time1 - time0;
+	  return time1 - time0;
+
 	/*
-	** time1 and time0 have opposite signs.
-	** Punt if uintmax_t is too narrow.
+	** The values have opposite signs and uintmax_t is too narrow.
 	** This suffers from double rounding; attempt to lessen that
 	** by using long double temporaries.
 	*/
-	if (sizeof (uintmax_t) < sizeof (time_t))
-		return (long double) time1 - (long double) time0;
-	/*
-	** Stay calm...decent optimizers will eliminate the complexity below.
-	*/
-	if (time1 >= 0 /* && time0 < 0 */)
-		return    (uintmax_t) time1 + (uintmax_t) (-1 - time0) + 1;
-	return -(double) ((uintmax_t) time0 + (uintmax_t) (-1 - time1) + 1);
+	{
+	  long double t1 = time1, t0 = time0;
+	  return t1 - t0;
+	}
 }
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index bf09c5e..79c4a9a 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -10,10 +10,30 @@
 
 /*LINTLIBRARY*/
 
+#define LOCALTIME_IMPLEMENTATION
 #include "private.h"
+
 #include "tzfile.h"
 #include "fcntl.h"
 
+#if THREAD_SAFE
+# include <pthread.h>
+static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
+static int lock(void) { return pthread_mutex_lock(&locallock); }
+static void unlock(void) { pthread_mutex_unlock(&locallock); }
+#else
+static int lock(void) { return 0; }
+static void unlock(void) { }
+#endif
+
+/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
+   NETBSD_INSPIRED is defined, and are private otherwise.  */
+#if NETBSD_INSPIRED
+# define NETBSD_INSPIRED_EXTERN
+#else
+# define NETBSD_INSPIRED_EXTERN static
+#endif
+
 #ifndef TZ_ABBR_MAX_LEN
 #define TZ_ABBR_MAX_LEN 16
 #endif /* !defined TZ_ABBR_MAX_LEN */
@@ -38,19 +58,6 @@
 #define OPEN_MODE   O_RDONLY
 #endif /* !defined O_BINARY */
 
-#if 0
-#  define  XLOG(xx)  printf xx , fflush(stdout)
-#else
-#  define  XLOG(x)   do{}while (0)
-#endif
-
-/* BEGIN android-added: thread-safety. */
-#include <pthread.h>
-static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER;
-static inline void _tzLock(void) { pthread_mutex_lock(&_tzMutex); }
-static inline void _tzUnlock(void) { pthread_mutex_unlock(&_tzMutex); }
-/* END android-added */
-
 #ifndef WILDABBR
 /*
 ** Someone might make incorrect use of a time zone abbreviation:
@@ -91,10 +98,10 @@
 
 struct ttinfo {              /* time type information */
     int_fast32_t tt_gmtoff;  /* UT offset in seconds */
-    int          tt_isdst;   /* used to set tm_isdst */
+    bool         tt_isdst;   /* used to set tm_isdst */
     int          tt_abbrind; /* abbreviation list index */
-    int          tt_ttisstd; /* TRUE if transition is std time */
-    int          tt_ttisgmt; /* TRUE if transition is UT */
+    bool         tt_ttisstd; /* transition is std time */
+    bool         tt_ttisgmt; /* transition is UT */
 };
 
 struct lsinfo {              /* leap second information */
@@ -102,6 +109,7 @@
     int_fast64_t ls_corr;    /* correction to apply */
 };
 
+#define SMALLEST(a, b)	(((a) < (b)) ? (a) : (b))
 #define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
 
 #ifdef TZNAME_MAX
@@ -116,8 +124,8 @@
     int           timecnt;
     int           typecnt;
     int           charcnt;
-    int           goback;
-    int           goahead;
+    bool          goback;
+    bool          goahead;
     time_t        ats[TZ_MAX_TIMES];
     unsigned char types[TZ_MAX_TIMES];
     struct ttinfo ttis[TZ_MAX_TYPES];
@@ -127,74 +135,29 @@
     int           defaulttype; /* for early times or if no transitions */
 };
 
+enum r_type {
+  JULIAN_DAY,		/* Jn = Julian day */
+  DAY_OF_YEAR,		/* n = day of year */
+  MONTH_NTH_DAY_OF_WEEK	/* Mm.n.d = month, week, day of week */
+};
+
 struct rule {
-    int          r_type; /* type of rule; see below */
+	enum r_type	r_type;		/* type of rule */
     int          r_day;  /* day number of rule */
     int          r_week; /* week number of rule */
     int          r_mon;  /* month number of rule */
     int_fast32_t r_time; /* transition time of rule */
 };
 
-#define JULIAN_DAY             0       /* Jn = Julian day */
-#define DAY_OF_YEAR            1       /* n = day of year */
-#define MONTH_NTH_DAY_OF_WEEK  2       /* Mm.n.d = month, week, day of week */
-
-/*
-** Prototypes for static functions.
-*/
-
-/* NOTE: all internal functions assume that _tzLock() was already called */
-
-static int __bionic_open_tzdata(const char*, int*);
-static int_fast32_t detzcode(const char * codep);
-static int_fast64_t detzcode64(const char * codep);
-static int      differ_by_repeat(time_t t1, time_t t0);
-static const char * getzname(const char * strp) ATTRIBUTE_PURE;
-static const char * getqzname(const char * strp, const int delim)
-        ATTRIBUTE_PURE;
-static const char * getnum(const char * strp, int * nump, int min,
-                int max);
-static const char * getsecs(const char * strp, int_fast32_t * secsp);
-static const char * getoffset(const char * strp, int_fast32_t * offsetp);
-static const char * getrule(const char * strp, struct rule * rulep);
-static void     gmtload(struct state * sp);
-static struct tm *  gmtsub(const time_t * timep, int_fast32_t offset,
-                struct tm * tmp, struct state * sp); // android-changed: added sp.
-static struct tm *  localsub(const time_t * timep, int_fast32_t offset,
-                struct tm * tmp, struct state * sp); // android-changed: added sp.
-static int      increment_overflow(int * number, int delta);
-static int      leaps_thru_end_of(int y) ATTRIBUTE_PURE;
-static int      increment_overflow32(int_fast32_t * number, int delta);
-static int      increment_overflow_time(time_t *t, int_fast32_t delta);
-static int      normalize_overflow32(int_fast32_t * tensptr,
-                int * unitsptr, int base);
-static int      normalize_overflow(int * tensptr, int * unitsptr,
-                int base);
-static void     settzname(void);
-static time_t       time1(struct tm * tmp,
-                struct tm * (*funcp)(const time_t *,
-                int_fast32_t, struct tm *, struct state *), // android-changed: added state*.
-                int_fast32_t, struct state * sp); // android-changed: added sp.
-static time_t       time2(struct tm * tmp,
-                struct tm * (*funcp)(const time_t *,
-                int_fast32_t, struct tm*, struct state *), // android-changed: added state*.
-                int_fast32_t offset, int * okayp, struct state * sp); // android-changed: added sp.
-static time_t       time2sub(struct tm *tmp,
-                struct tm * (*funcp) (const time_t *,
-                int_fast32_t, struct tm*, struct state *), // android-changed: added state*.
-                int_fast32_t offset, int * okayp, int do_norm_secs, struct state * sp); // android-change: added sp.
-static struct tm *  timesub(const time_t * timep, int_fast32_t offset,
-                const struct state * sp, struct tm * tmp);
-static int      tmcomp(const struct tm * atmp,
-                const struct tm * btmp);
-static int_fast32_t transtime(int year, const struct rule * rulep,
-                int_fast32_t offset)
-        ATTRIBUTE_PURE;
-static int      typesequiv(const struct state * sp, int a, int b);
-static int      tzload(const char * name, struct state * sp,
-                int doextend);
-static int      tzparse(const char * name, struct state * sp,
-                int lastditch);
+static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
+			 struct tm *);
+static bool increment_overflow(int *, int);
+static bool increment_overflow_time(time_t *, int_fast32_t);
+static bool normalize_overflow32(int_fast32_t *, int *, int);
+static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
+			  struct tm *);
+static bool typesequiv(struct state const *, int, int);
+static bool tzparse(char const *, struct state *, bool);
 
 #ifdef ALL_STATE
 static struct state * lclptr;
@@ -214,7 +177,6 @@
 
 static char lcl_TZname[TZ_STRLEN_MAX + 1];
 static int  lcl_is_set;
-static int  gmt_is_set;
 
 char * tzname[2] = {
     (char *) wildabbr,
@@ -229,107 +191,150 @@
 ** Thanks to Paul Eggert for noting this.
 */
 
-static struct tm    tmGlobal;
+static struct tm	tm;
 
 #ifdef USG_COMPAT
-long                timezone = 0;
-int                 daylight = 0;
+long			timezone;
+int			daylight;
 #endif /* defined USG_COMPAT */
 
 #ifdef ALTZONE
-long                altzone = 0;
+long			altzone;
 #endif /* defined ALTZONE */
 
+/* Initialize *S to a value based on GMTOFF, ISDST, and ABBRIND.  */
+static void
+init_ttinfo(struct ttinfo *s, int_fast32_t gmtoff, bool isdst, int abbrind)
+{
+  s->tt_gmtoff = gmtoff;
+  s->tt_isdst = isdst;
+  s->tt_abbrind = abbrind;
+  s->tt_ttisstd = false;
+  s->tt_ttisgmt = false;
+}
+
 static int_fast32_t
 detzcode(const char *const codep)
 {
-    register int_fast32_t result;
-    register int          i;
+	register int_fast32_t	result;
+	register int		i;
+	int_fast32_t one = 1;
+	int_fast32_t halfmaxval = one << (32 - 2);
+	int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
+	int_fast32_t minval = -1 - maxval;
 
-    result = (codep[0] & 0x80) ? -1 : 0;
-    for (i = 0; i < 4; ++i)
-        result = (result << 8) | (codep[i] & 0xff);
-    return result;
+	result = codep[0] & 0x7f;
+	for (i = 1; i < 4; ++i)
+		result = (result << 8) | (codep[i] & 0xff);
+
+	if (codep[0] & 0x80) {
+	  /* Do two's-complement negation even on non-two's-complement machines.
+	     If the result would be minval - 1, return minval.  */
+	  result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
+	  result += minval;
+	}
+	return result;
 }
 
 static int_fast64_t
 detzcode64(const char *const codep)
 {
-    register int_fast64_t result;
-    register int          i;
+	register uint_fast64_t result;
+	register int	i;
+	int_fast64_t one = 1;
+	int_fast64_t halfmaxval = one << (64 - 2);
+	int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
+	int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
 
-    result = (codep[0] & 0x80) ? -1 : 0;
-    for (i = 0; i < 8; ++i)
-        result = (result << 8) | (codep[i] & 0xff);
-    return result;
+	result = codep[0] & 0x7f;
+	for (i = 1; i < 8; ++i)
+		result = (result << 8) | (codep[i] & 0xff);
+
+	if (codep[0] & 0x80) {
+	  /* Do two's-complement negation even on non-two's-complement machines.
+	     If the result would be minval - 1, return minval.  */
+	  result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
+	  result += minval;
+	}
+	return result;
+}
+
+static void
+update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
+{
+  tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
+#ifdef USG_COMPAT
+  if (!ttisp->tt_isdst)
+    timezone = - ttisp->tt_gmtoff;
+#endif
+#ifdef ALTZONE
+  if (ttisp->tt_isdst)
+    altzone = - ttisp->tt_gmtoff;
+#endif
 }
 
 static void
 settzname(void)
 {
-    register struct state * const sp = lclptr;
-    register int                  i;
+	register struct state * const	sp = lclptr;
+	register int			i;
 
-    tzname[0] = tzname[1] = (char *) wildabbr;
+	tzname[0] = tzname[1] = (char *) wildabbr;
 #ifdef USG_COMPAT
-    daylight = 0;
-    timezone = 0;
+	daylight = 0;
+	timezone = 0;
 #endif /* defined USG_COMPAT */
 #ifdef ALTZONE
-    altzone = 0;
+	altzone = 0;
 #endif /* defined ALTZONE */
-    if (sp == NULL) {
-        tzname[0] = tzname[1] = (char *) gmt;
-        return;
-    }
-    /*
-    ** And to get the latest zone names into tzname. . .
-    */
-    for (i = 0; i < sp->typecnt; ++i) {
-        register const struct ttinfo * const    ttisp = &sp->ttis[i];
-
-        tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind];
-    }
-    for (i = 0; i < sp->timecnt; ++i) {
-        register const struct ttinfo * const    ttisp =
-                            &sp->ttis[
-                                sp->types[i]];
-
-        tzname[ttisp->tt_isdst] =
-            &sp->chars[ttisp->tt_abbrind];
+	if (sp == NULL) {
+		tzname[0] = tzname[1] = (char *) gmt;
+		return;
+	}
+	/*
+	** And to get the latest zone names into tzname. . .
+	*/
+	for (i = 0; i < sp->typecnt; ++i) {
+		register const struct ttinfo * const	ttisp = &sp->ttis[i];
+		update_tzname_etc(sp, ttisp);
+	}
+	for (i = 0; i < sp->timecnt; ++i) {
+		register const struct ttinfo * const	ttisp =
+							&sp->ttis[
+								sp->types[i]];
+		update_tzname_etc(sp, ttisp);
 #ifdef USG_COMPAT
-        if (ttisp->tt_isdst)
-            daylight = 1;
-        if (!ttisp->tt_isdst)
-            timezone = -(ttisp->tt_gmtoff);
+		if (ttisp->tt_isdst)
+			daylight = 1;
 #endif /* defined USG_COMPAT */
-#ifdef ALTZONE
-        if (ttisp->tt_isdst)
-            altzone = -(ttisp->tt_gmtoff);
-#endif /* defined ALTZONE */
-    }
-    /*
-    ** Finally, scrub the abbreviations.
-    ** First, replace bogus characters.
-    */
-    for (i = 0; i < sp->charcnt; ++i)
-        if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
-            sp->chars[i] = TZ_ABBR_ERR_CHAR;
-    /*
-    ** Second, truncate long abbreviations.
-    */
-    for (i = 0; i < sp->typecnt; ++i) {
-        register const struct ttinfo * const    ttisp = &sp->ttis[i];
-        register char *             cp = &sp->chars[ttisp->tt_abbrind];
-
-        if (strlen(cp) > TZ_ABBR_MAX_LEN &&
-            strcmp(cp, GRANDPARENTED) != 0)
-                *(cp + TZ_ABBR_MAX_LEN) = '\0';
-    }
+	}
 }
 
-static int
-differ_by_repeat(const time_t t1 __unused, const time_t t0 __unused)
+static void
+scrub_abbrs(struct state *sp)
+{
+	int i;
+	/*
+	** First, replace bogus characters.
+	*/
+	for (i = 0; i < sp->charcnt; ++i)
+		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
+			sp->chars[i] = TZ_ABBR_ERR_CHAR;
+	/*
+	** Second, truncate long abbreviations.
+	*/
+	for (i = 0; i < sp->typecnt; ++i) {
+		register const struct ttinfo * const	ttisp = &sp->ttis[i];
+		register char *				cp = &sp->chars[ttisp->tt_abbrind];
+
+		if (strlen(cp) > TZ_ABBR_MAX_LEN &&
+			strcmp(cp, GRANDPARENTED) != 0)
+				*(cp + TZ_ABBR_MAX_LEN) = '\0';
+	}
+}
+
+static bool
+differ_by_repeat(const time_t t1, const time_t t0)
 {
     if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
         return 0;
@@ -338,318 +343,387 @@
 #endif
 }
 
-static int
-tzload(register const char* name, register struct state* const sp,
-       register const int doextend)
-{
-    register const char * p;
-    register int          i;
-    register int          fid;
-    register int          stored;
-    register int          nread;
-    typedef union {
-        struct tzhead tzhead;
-        char          buf[2 * sizeof(struct tzhead) +
-                      2 * sizeof *sp +
-                      4 * TZ_MAX_TIMES];
-    } u_t;
-    union local_storage {
-        /*
-        ** Section 4.9.1 of the C standard says that
-        ** "FILENAME_MAX expands to an integral constant expression
-        ** that is the size needed for an array of char large enough
-        ** to hold the longest file name string that the implementation
-        ** guarantees can be opened."
-        */
-        //char            fullname[FILENAME_MAX + 1];
+/* Input buffer for data read from a compiled tz file.  */
+union input_buffer {
+  /* The first part of the buffer, interpreted as a header.  */
+  struct tzhead tzhead;
 
-        /* The main part of the storage for this function.  */
-        struct {
-            u_t u;
-            struct state st;
-        } u;
-    };
-    //register char *fullname;
-    register u_t *up;
-    register union local_storage *lsp;
-#ifdef ALL_STATE
-    lsp = malloc(sizeof *lsp);
-    if (!lsp)
-        return -1;
-#else /* !defined ALL_STATE */
-    union local_storage ls;
-    lsp = &ls;
-#endif /* !defined ALL_STATE */
-    //fullname = lsp->fullname;
-    up = &lsp->u.u;
-
-    sp->goback = sp->goahead = FALSE;
-
-    if (! name) {
-        name = TZDEFAULT;
-        if (! name)
-            goto oops;
-    }
-
-    int toread;
-    fid = __bionic_open_tzdata(name, &toread);
-    if (fid < 0)
-        goto oops;
-
-    nread = read(fid, up->buf, sizeof up->buf);
-    if (close(fid) < 0 || nread <= 0)
-        goto oops;
-    for (stored = 4; stored <= 8; stored *= 2) {
-        int ttisstdcnt;
-        int ttisgmtcnt;
-        int timecnt;
-
-        ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
-        ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
-        sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
-        sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
-        sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
-        sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
-        p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
-        if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
-            sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
-            sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
-            sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
-            (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
-            (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
-                goto oops;
-        if (nread - (p - up->buf) <
-            sp->timecnt * stored +       /* ats */
-            sp->timecnt +                /* types */
-            sp->typecnt * 6 +            /* ttinfos */
-            sp->charcnt +                /* chars */
-            sp->leapcnt * (stored + 4) + /* lsinfos */
-            ttisstdcnt +                 /* ttisstds */
-            ttisgmtcnt)                  /* ttisgmts */
-                goto oops;
-        timecnt = 0;
-        for (i = 0; i < sp->timecnt; ++i) {
-            int_fast64_t at
-              = stored == 4 ? detzcode(p) : detzcode64(p);
-            sp->types[i] = ((TYPE_SIGNED(time_t)
-                     ? time_t_min <= at
-                     : 0 <= at)
-                    && at <= time_t_max);
-            if (sp->types[i]) {
-                if (i && !timecnt && at != time_t_min) {
-                    /*
-                    ** Keep the earlier record, but tweak
-                    ** it so that it starts with the
-                    ** minimum time_t value.
-                    */
-                    sp->types[i - 1] = 1;
-                    sp->ats[timecnt++] = time_t_min;
-                }
-                sp->ats[timecnt++] = at;
-            }
-            p += stored;
-        }
-        timecnt = 0;
-        for (i = 0; i < sp->timecnt; ++i) {
-            unsigned char typ = *p++;
-            if (sp->typecnt <= typ)
-                goto oops;
-            if (sp->types[i])
-                sp->types[timecnt++] = typ;
-        }
-        sp->timecnt = timecnt;
-        for (i = 0; i < sp->typecnt; ++i) {
-            register struct ttinfo *    ttisp;
-
-            ttisp = &sp->ttis[i];
-            ttisp->tt_gmtoff = detzcode(p);
-            p += 4;
-            ttisp->tt_isdst = (unsigned char) *p++;
-            if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
-                goto oops;
-            ttisp->tt_abbrind = (unsigned char) *p++;
-            if (ttisp->tt_abbrind < 0 ||
-                ttisp->tt_abbrind > sp->charcnt)
-                    goto oops;
-        }
-        for (i = 0; i < sp->charcnt; ++i)
-            sp->chars[i] = *p++;
-        sp->chars[i] = '\0';    /* ensure '\0' at end */
-        for (i = 0; i < sp->leapcnt; ++i) {
-            register struct lsinfo *    lsisp;
-
-            lsisp = &sp->lsis[i];
-            lsisp->ls_trans = (stored == 4) ?
-                detzcode(p) : detzcode64(p);
-            p += stored;
-            lsisp->ls_corr = detzcode(p);
-            p += 4;
-        }
-        for (i = 0; i < sp->typecnt; ++i) {
-            register struct ttinfo *    ttisp;
-
-            ttisp = &sp->ttis[i];
-            if (ttisstdcnt == 0)
-                ttisp->tt_ttisstd = FALSE;
-            else {
-                ttisp->tt_ttisstd = *p++;
-                if (ttisp->tt_ttisstd != TRUE &&
-                    ttisp->tt_ttisstd != FALSE)
-                        goto oops;
-            }
-        }
-        for (i = 0; i < sp->typecnt; ++i) {
-            register struct ttinfo *    ttisp;
-
-            ttisp = &sp->ttis[i];
-            if (ttisgmtcnt == 0)
-                ttisp->tt_ttisgmt = FALSE;
-            else {
-                ttisp->tt_ttisgmt = *p++;
-                if (ttisp->tt_ttisgmt != TRUE &&
-                    ttisp->tt_ttisgmt != FALSE)
-                        goto oops;
-            }
-        }
-        /*
-        ** If this is an old file, we're done.
-        */
-        if (up->tzhead.tzh_version[0] == '\0')
-            break;
-        nread -= p - up->buf;
-        for (i = 0; i < nread; ++i)
-            up->buf[i] = p[i];
-        /*
-        ** If this is a signed narrow time_t system, we're done.
-        */
-        if (TYPE_SIGNED(time_t) && stored >= (int) sizeof(time_t))
-            break;
-    }
-    if (doextend && nread > 2 &&
-        up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
-        sp->typecnt + 2 <= TZ_MAX_TYPES) {
-            struct state    *ts = &lsp->u.st;
-            register int result;
-
-            up->buf[nread - 1] = '\0';
-            result = tzparse(&up->buf[1], ts, FALSE);
-            if (result == 0 && ts->typecnt == 2 &&
-                sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) {
-                    for (i = 0; i < 2; ++i)
-                        ts->ttis[i].tt_abbrind +=
-                            sp->charcnt;
-                    for (i = 0; i < ts->charcnt; ++i)
-                        sp->chars[sp->charcnt++] =
-                            ts->chars[i];
-                    i = 0;
-                    while (i < ts->timecnt &&
-                        ts->ats[i] <=
-                        sp->ats[sp->timecnt - 1])
-                            ++i;
-                    while (i < ts->timecnt &&
-                        sp->timecnt < TZ_MAX_TIMES) {
-                        sp->ats[sp->timecnt] =
-                            ts->ats[i];
-                        sp->types[sp->timecnt] =
-                            sp->typecnt +
-                            ts->types[i];
-                        ++sp->timecnt;
-                        ++i;
-                    }
-                    sp->ttis[sp->typecnt++] = ts->ttis[0];
-                    sp->ttis[sp->typecnt++] = ts->ttis[1];
-            }
-    }
-    if (sp->timecnt > 1) {
-        for (i = 1; i < sp->timecnt; ++i)
-            if (typesequiv(sp, sp->types[i], sp->types[0]) &&
-                    differ_by_repeat(sp->ats[i], sp->ats[0])) {
-                sp->goback = TRUE;
-                break;
-            }
-            for (i = sp->timecnt - 2; i >= 0; --i)
-                if (typesequiv(sp, sp->types[sp->timecnt - 1],
-                               sp->types[i]) &&
-                        differ_by_repeat(sp->ats[sp->timecnt - 1],
-                                         sp->ats[i])) {
-                    sp->goahead = TRUE;
-                    break;
-            }
-        }
-        /*
-        ** If type 0 is is unused in transitions,
-        ** it's the type to use for early times.
-        */
-        for (i = 0; i < sp->typecnt; ++i)
-            if (sp->types[i] == 0)
-                break;
-        i = (i >= sp->typecnt) ? 0 : -1;
-        /*
-        ** Absent the above,
-        ** if there are transition times
-        ** and the first transition is to a daylight time
-        ** find the standard type less than and closest to
-        ** the type of the first transition.
-        */
-        if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
-            i = sp->types[0];
-            while (--i >= 0)
-                if (!sp->ttis[i].tt_isdst)
-                    break;
-        }
-        /*
-        ** If no result yet, find the first standard type.
-        ** If there is none, punt to type zero.
-        */
-        if (i < 0) {
-            i = 0;
-            while (sp->ttis[i].tt_isdst)
-                if (++i >= sp->typecnt) {
-                    i = 0;
-                    break;
-                }
-        }
-        sp->defaulttype = i;
-#ifdef ALL_STATE
-        free(up);
-#endif /* defined ALL_STATE */
-        return 0;
-oops:
-#ifdef ALL_STATE
-        free(up);
-#endif /* defined ALL_STATE */
-        return -1;
-}
-
-static int
-typesequiv(const struct state *const sp, const int a, const int b)
-{
-    register int result;
-
-    if (sp == NULL ||
-        a < 0 || a >= sp->typecnt ||
-        b < 0 || b >= sp->typecnt)
-            result = FALSE;
-    else {
-        register const struct ttinfo *  ap = &sp->ttis[a];
-        register const struct ttinfo *  bp = &sp->ttis[b];
-        result = ap->tt_gmtoff == bp->tt_gmtoff &&
-            ap->tt_isdst == bp->tt_isdst &&
-            ap->tt_ttisstd == bp->tt_ttisstd &&
-            ap->tt_ttisgmt == bp->tt_ttisgmt &&
-            strcmp(&sp->chars[ap->tt_abbrind],
-            &sp->chars[bp->tt_abbrind]) == 0;
-    }
-    return result;
-}
-
-static const int mon_lengths[2][MONSPERYEAR] = {
-    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
-    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+  /* The entire buffer.  */
+  char buf[2 * sizeof(struct tzhead) + 2 * sizeof (struct state)
+	   + 4 * TZ_MAX_TIMES];
 };
 
-static const int year_lengths[2] = {
-    DAYSPERNYEAR, DAYSPERLYEAR
+/* Local storage needed for 'tzloadbody'.  */
+union local_storage {
+  /* The file name to be opened.  */
+  char fullname[FILENAME_MAX + 1];
+
+  /* The results of analyzing the file's contents after it is opened.  */
+  struct {
+    /* The input buffer.  */
+    union input_buffer u;
+
+    /* A temporary state used for parsing a TZ string in the file.  */
+    struct state st;
+  } u;
+};
+
+static int __bionic_open_tzdata(const char*);
+
+/* Load tz data from the file named NAME into *SP.  Read extended
+   format if DOEXTEND.  Use *LSP for temporary storage.  Return 0 on
+   success, an errno value on failure.  */
+static int
+tzloadbody(char const *name, struct state *sp, bool doextend,
+	   union local_storage *lsp)
+{
+	register int			i;
+	register int			fid;
+	register int			stored;
+	register ssize_t		nread;
+#if !defined(__ANDROID__)
+	register bool doaccess;
+	register char *fullname = lsp->fullname;
+#endif
+	register union input_buffer *up = &lsp->u.u;
+	register int tzheadsize = sizeof (struct tzhead);
+
+	sp->goback = sp->goahead = false;
+
+	if (! name) {
+		name = TZDEFAULT;
+		if (! name)
+		  return EINVAL;
+	}
+
+#if defined(__ANDROID__)
+	fid = __bionic_open_tzdata(name);
+#else
+	if (name[0] == ':')
+		++name;
+	doaccess = name[0] == '/';
+	if (!doaccess) {
+		char const *p = TZDIR;
+		if (! p)
+		  return EINVAL;
+		if (sizeof lsp->fullname - 1 <= strlen(p) + strlen(name))
+		  return ENAMETOOLONG;
+		strcpy(fullname, p);
+		strcat(fullname, "/");
+		strcat(fullname, name);
+		/* Set doaccess if '.' (as in "../") shows up in name.  */
+		if (strchr(name, '.'))
+			doaccess = true;
+		name = fullname;
+	}
+	if (doaccess && access(name, R_OK) != 0)
+	  return errno;
+	fid = open(name, OPEN_MODE);
+#endif
+	if (fid < 0)
+	  return errno;
+
+	nread = read(fid, up->buf, sizeof up->buf);
+	if (nread < tzheadsize) {
+	  int err = nread < 0 ? errno : EINVAL;
+	  close(fid);
+	  return err;
+	}
+	if (close(fid) < 0)
+	  return errno;
+	for (stored = 4; stored <= 8; stored *= 2) {
+		int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
+		int_fast32_t ttisgmtcnt = detzcode(up->tzhead.tzh_ttisgmtcnt);
+		int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
+		int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
+		int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
+		int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
+		char const *p = up->buf + tzheadsize;
+		if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
+		       && 0 < typecnt && typecnt < TZ_MAX_TYPES
+		       && 0 <= timecnt && timecnt < TZ_MAX_TIMES
+		       && 0 <= charcnt && charcnt < TZ_MAX_CHARS
+		       && (ttisstdcnt == typecnt || ttisstdcnt == 0)
+		       && (ttisgmtcnt == typecnt || ttisgmtcnt == 0)))
+		  return EINVAL;
+		if (nread
+		    < (tzheadsize		/* struct tzhead */
+		       + timecnt * stored	/* ats */
+		       + timecnt		/* types */
+		       + typecnt * 6		/* ttinfos */
+		       + charcnt		/* chars */
+		       + leapcnt * (stored + 4)	/* lsinfos */
+		       + ttisstdcnt		/* ttisstds */
+		       + ttisgmtcnt))		/* ttisgmts */
+		  return EINVAL;
+		sp->leapcnt = leapcnt;
+		sp->timecnt = timecnt;
+		sp->typecnt = typecnt;
+		sp->charcnt = charcnt;
+
+		/* Read transitions, discarding those out of time_t range.
+		   But pretend the last transition before time_t_min
+		   occurred at time_t_min.  */
+		timecnt = 0;
+		for (i = 0; i < sp->timecnt; ++i) {
+			int_fast64_t at
+			  = stored == 4 ? detzcode(p) : detzcode64(p);
+			sp->types[i] = at <= time_t_max;
+			if (sp->types[i]) {
+			  time_t attime
+			    = ((TYPE_SIGNED(time_t) ? at < time_t_min : at < 0)
+			       ? time_t_min : at);
+			  if (timecnt && attime <= sp->ats[timecnt - 1]) {
+			    if (attime < sp->ats[timecnt - 1])
+			      return EINVAL;
+			    sp->types[i - 1] = 0;
+			    timecnt--;
+			  }
+			  sp->ats[timecnt++] = attime;
+			}
+			p += stored;
+		}
+
+		timecnt = 0;
+		for (i = 0; i < sp->timecnt; ++i) {
+			unsigned char typ = *p++;
+			if (sp->typecnt <= typ)
+			  return EINVAL;
+			if (sp->types[i])
+				sp->types[timecnt++] = typ;
+		}
+		sp->timecnt = timecnt;
+		for (i = 0; i < sp->typecnt; ++i) {
+			register struct ttinfo *	ttisp;
+			unsigned char isdst, abbrind;
+
+			ttisp = &sp->ttis[i];
+			ttisp->tt_gmtoff = detzcode(p);
+			p += 4;
+			isdst = *p++;
+			if (! (isdst < 2))
+			  return EINVAL;
+			ttisp->tt_isdst = isdst;
+			abbrind = *p++;
+			if (! (abbrind < sp->charcnt))
+			  return EINVAL;
+			ttisp->tt_abbrind = abbrind;
+		}
+		for (i = 0; i < sp->charcnt; ++i)
+			sp->chars[i] = *p++;
+		sp->chars[i] = '\0';	/* ensure '\0' at end */
+
+		/* Read leap seconds, discarding those out of time_t range.  */
+		leapcnt = 0;
+		for (i = 0; i < sp->leapcnt; ++i) {
+		  int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
+		  int_fast32_t corr = detzcode(p + stored);
+		  p += stored + 4;
+		  if (tr <= time_t_max) {
+		    time_t trans
+		      = ((TYPE_SIGNED(time_t) ? tr < time_t_min : tr < 0)
+			 ? time_t_min : tr);
+		    if (leapcnt && trans <= sp->lsis[leapcnt - 1].ls_trans) {
+		      if (trans < sp->lsis[leapcnt - 1].ls_trans)
+			return EINVAL;
+		      leapcnt--;
+		    }
+		    sp->lsis[leapcnt].ls_trans = trans;
+		    sp->lsis[leapcnt].ls_corr = corr;
+		    leapcnt++;
+		  }
+		}
+		sp->leapcnt = leapcnt;
+
+		for (i = 0; i < sp->typecnt; ++i) {
+			register struct ttinfo *	ttisp;
+
+			ttisp = &sp->ttis[i];
+			if (ttisstdcnt == 0)
+				ttisp->tt_ttisstd = false;
+			else {
+				if (*p != true && *p != false)
+				  return EINVAL;
+				ttisp->tt_ttisstd = *p++;
+			}
+		}
+		for (i = 0; i < sp->typecnt; ++i) {
+			register struct ttinfo *	ttisp;
+
+			ttisp = &sp->ttis[i];
+			if (ttisgmtcnt == 0)
+				ttisp->tt_ttisgmt = false;
+			else {
+				if (*p != true && *p != false)
+						return EINVAL;
+				ttisp->tt_ttisgmt = *p++;
+			}
+		}
+		/*
+		** If this is an old file, we're done.
+		*/
+		if (up->tzhead.tzh_version[0] == '\0')
+			break;
+		nread -= p - up->buf;
+		memmove(up->buf, p, nread);
+	}
+	if (doextend && nread > 2 &&
+		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
+		sp->typecnt + 2 <= TZ_MAX_TYPES) {
+			struct state	*ts = &lsp->u.st;
+
+			up->buf[nread - 1] = '\0';
+			if (tzparse(&up->buf[1], ts, false)
+			    && ts->typecnt == 2) {
+
+			  /* Attempt to reuse existing abbreviations.
+			     Without this, America/Anchorage would stop
+			     working after 2037 when TZ_MAX_CHARS is 50, as
+			     sp->charcnt equals 42 (for LMT CAT CAWT CAPT AHST
+			     AHDT YST AKDT AKST) and ts->charcnt equals 10
+			     (for AKST AKDT).  Reusing means sp->charcnt can
+			     stay 42 in this example.  */
+			  int gotabbr = 0;
+			  int charcnt = sp->charcnt;
+			  for (i = 0; i < 2; i++) {
+			    char *tsabbr = ts->chars + ts->ttis[i].tt_abbrind;
+			    int j;
+			    for (j = 0; j < charcnt; j++)
+			      if (strcmp(sp->chars + j, tsabbr) == 0) {
+				ts->ttis[i].tt_abbrind = j;
+				gotabbr++;
+				break;
+			      }
+			    if (! (j < charcnt)) {
+			      int tsabbrlen = strlen(tsabbr);
+			      if (j + tsabbrlen < TZ_MAX_CHARS) {
+				strcpy(sp->chars + j, tsabbr);
+				charcnt = j + tsabbrlen + 1;
+				ts->ttis[i].tt_abbrind = j;
+				gotabbr++;
+			      }
+			    }
+			  }
+			  if (gotabbr == 2) {
+			    sp->charcnt = charcnt;
+			    for (i = 0; i < ts->timecnt; i++)
+			      if (sp->ats[sp->timecnt - 1] < ts->ats[i])
+				break;
+			    while (i < ts->timecnt
+				   && sp->timecnt < TZ_MAX_TIMES) {
+			      sp->ats[sp->timecnt] = ts->ats[i];
+			      sp->types[sp->timecnt] = (sp->typecnt
+							+ ts->types[i]);
+			      sp->timecnt++;
+			      i++;
+			    }
+			    sp->ttis[sp->typecnt++] = ts->ttis[0];
+			    sp->ttis[sp->typecnt++] = ts->ttis[1];
+			  }
+			}
+	}
+	if (sp->timecnt > 1) {
+		for (i = 1; i < sp->timecnt; ++i)
+			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
+				differ_by_repeat(sp->ats[i], sp->ats[0])) {
+					sp->goback = true;
+					break;
+				}
+		for (i = sp->timecnt - 2; i >= 0; --i)
+			if (typesequiv(sp, sp->types[sp->timecnt - 1],
+				sp->types[i]) &&
+				differ_by_repeat(sp->ats[sp->timecnt - 1],
+				sp->ats[i])) {
+					sp->goahead = true;
+					break;
+		}
+	}
+	/*
+	** If type 0 is is unused in transitions,
+	** it's the type to use for early times.
+	*/
+	for (i = 0; i < sp->timecnt; ++i)
+		if (sp->types[i] == 0)
+			break;
+	i = i < sp->timecnt ? -1 : 0;
+	/*
+	** Absent the above,
+	** if there are transition times
+	** and the first transition is to a daylight time
+	** find the standard type less than and closest to
+	** the type of the first transition.
+	*/
+	if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
+		i = sp->types[0];
+		while (--i >= 0)
+			if (!sp->ttis[i].tt_isdst)
+				break;
+	}
+	/*
+	** If no result yet, find the first standard type.
+	** If there is none, punt to type zero.
+	*/
+	if (i < 0) {
+		i = 0;
+		while (sp->ttis[i].tt_isdst)
+			if (++i >= sp->typecnt) {
+				i = 0;
+				break;
+			}
+	}
+	sp->defaulttype = i;
+	return 0;
+}
+
+/* Load tz data from the file named NAME into *SP.  Read extended
+   format if DOEXTEND.  Return 0 on success, an errno value on failure.  */
+static int
+tzload(char const *name, struct state *sp, bool doextend)
+{
+#ifdef ALL_STATE
+  union local_storage *lsp = malloc(sizeof *lsp);
+  if (!lsp)
+    return errno;
+  else {
+    int err = tzloadbody(name, sp, doextend, lsp);
+    free(lsp);
+    return err;
+  }
+#else
+  union local_storage ls;
+  return tzloadbody(name, sp, doextend, &ls);
+#endif
+}
+
+static bool
+typesequiv(const struct state *sp, int a, int b)
+{
+	register bool result;
+
+	if (sp == NULL ||
+		a < 0 || a >= sp->typecnt ||
+		b < 0 || b >= sp->typecnt)
+			result = false;
+	else {
+		register const struct ttinfo *	ap = &sp->ttis[a];
+		register const struct ttinfo *	bp = &sp->ttis[b];
+		result = ap->tt_gmtoff == bp->tt_gmtoff &&
+			ap->tt_isdst == bp->tt_isdst &&
+			ap->tt_ttisstd == bp->tt_ttisstd &&
+			ap->tt_ttisgmt == bp->tt_ttisgmt &&
+			strcmp(&sp->chars[ap->tt_abbrind],
+			&sp->chars[bp->tt_abbrind]) == 0;
+	}
+	return result;
+}
+
+static const int	mon_lengths[2][MONSPERYEAR] = {
+	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int	year_lengths[2] = {
+	DAYSPERNYEAR, DAYSPERLYEAR
 };
 
 /*
@@ -658,15 +732,15 @@
 ** character.
 */
 
-static const char *
-getzname(register const char * strp)
+static const char * ATTRIBUTE_PURE
+getzname(register const char *strp)
 {
-    register char   c;
+	register char	c;
 
-    while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
-        c != '+')
-            ++strp;
-    return strp;
+	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
+		c != '+')
+			++strp;
+	return strp;
 }
 
 /*
@@ -678,14 +752,14 @@
 ** We don't do any checking here; checking is done later in common-case code.
 */
 
-static const char *
+static const char * ATTRIBUTE_PURE
 getqzname(register const char *strp, const int delim)
 {
-    register int c;
+	register int	c;
 
-    while ((c = *strp) != '\0' && c != delim)
-        ++strp;
-    return strp;
+	while ((c = *strp) != '\0' && c != delim)
+		++strp;
+	return strp;
 }
 
 /*
@@ -696,24 +770,24 @@
 */
 
 static const char *
-getnum(register const char * strp, int * const nump, const int min, const int max)
+getnum(register const char *strp, int *const nump, const int min, const int max)
 {
-    register char c;
-    register int  num;
+	register char	c;
+	register int	num;
 
-    if (strp == NULL || !is_digit(c = *strp))
-        return NULL;
-    num = 0;
-    do {
-        num = num * 10 + (c - '0');
-        if (num > max)
-            return NULL;    /* illegal value */
-        c = *++strp;
-    } while (is_digit(c));
-    if (num < min)
-        return NULL;        /* illegal value */
-    *nump = num;
-    return strp;
+	if (strp == NULL || !is_digit(c = *strp))
+		return NULL;
+	num = 0;
+	do {
+		num = num * 10 + (c - '0');
+		if (num > max)
+			return NULL;	/* illegal value */
+		c = *++strp;
+	} while (is_digit(c));
+	if (num < min)
+		return NULL;		/* illegal value */
+	*nump = num;
+	return strp;
 }
 
 /*
@@ -727,34 +801,34 @@
 static const char *
 getsecs(register const char *strp, int_fast32_t *const secsp)
 {
-    int num;
+	int	num;
 
-    /*
-    ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
-    ** "M10.4.6/26", which does not conform to Posix,
-    ** but which specifies the equivalent of
-    ** "02:00 on the first Sunday on or after 23 Oct".
-    */
-    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
-    if (strp == NULL)
-        return NULL;
-    *secsp = num * (int_fast32_t) SECSPERHOUR;
-    if (*strp == ':') {
-        ++strp;
-        strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
-        if (strp == NULL)
-            return NULL;
-        *secsp += num * SECSPERMIN;
-        if (*strp == ':') {
-            ++strp;
-            /* 'SECSPERMIN' allows for leap seconds. */
-            strp = getnum(strp, &num, 0, SECSPERMIN);
-            if (strp == NULL)
-                return NULL;
-            *secsp += num;
-        }
-    }
-    return strp;
+	/*
+	** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
+	** "M10.4.6/26", which does not conform to Posix,
+	** but which specifies the equivalent of
+	** "02:00 on the first Sunday on or after 23 Oct".
+	*/
+	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
+	if (strp == NULL)
+		return NULL;
+	*secsp = num * (int_fast32_t) SECSPERHOUR;
+	if (*strp == ':') {
+		++strp;
+		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+		if (strp == NULL)
+			return NULL;
+		*secsp += num * SECSPERMIN;
+		if (*strp == ':') {
+			++strp;
+			/* 'SECSPERMIN' allows for leap seconds.  */
+			strp = getnum(strp, &num, 0, SECSPERMIN);
+			if (strp == NULL)
+				return NULL;
+			*secsp += num;
+		}
+	}
+	return strp;
 }
 
 /*
@@ -767,19 +841,19 @@
 static const char *
 getoffset(register const char *strp, int_fast32_t *const offsetp)
 {
-    register int neg = 0;
+	register bool neg = false;
 
-    if (*strp == '-') {
-        neg = 1;
-        ++strp;
-    } else if (*strp == '+')
-        ++strp;
-    strp = getsecs(strp, offsetp);
-    if (strp == NULL)
-        return NULL;        /* illegal time */
-    if (neg)
-        *offsetp = -*offsetp;
-    return strp;
+	if (*strp == '-') {
+		neg = true;
+		++strp;
+	} else if (*strp == '+')
+		++strp;
+	strp = getsecs(strp, offsetp);
+	if (strp == NULL)
+		return NULL;		/* illegal time */
+	if (neg)
+		*offsetp = -*offsetp;
+	return strp;
 }
 
 /*
@@ -790,49 +864,49 @@
 */
 
 static const char *
-getrule(const char * strp, register struct rule * const rulep)
+getrule(const char *strp, register struct rule *const rulep)
 {
-    if (*strp == 'J') {
-        /*
-        ** Julian day.
-        */
-        rulep->r_type = JULIAN_DAY;
-        ++strp;
-        strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
-    } else if (*strp == 'M') {
-        /*
-        ** Month, week, day.
-        */
-        rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
-        ++strp;
-        strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
-        if (strp == NULL)
-            return NULL;
-        if (*strp++ != '.')
-            return NULL;
-        strp = getnum(strp, &rulep->r_week, 1, 5);
-        if (strp == NULL)
-            return NULL;
-        if (*strp++ != '.')
-            return NULL;
-        strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
-    } else if (is_digit(*strp)) {
-        /*
-        ** Day of year.
-        */
-        rulep->r_type = DAY_OF_YEAR;
-        strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
-    } else  return NULL;        /* invalid format */
-    if (strp == NULL)
-        return NULL;
-    if (*strp == '/') {
-        /*
-        ** Time specified.
-        */
-        ++strp;
-        strp = getoffset(strp, &rulep->r_time);
-    } else  rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
-    return strp;
+	if (*strp == 'J') {
+		/*
+		** Julian day.
+		*/
+		rulep->r_type = JULIAN_DAY;
+		++strp;
+		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+	} else if (*strp == 'M') {
+		/*
+		** Month, week, day.
+		*/
+		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+		++strp;
+		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+		if (strp == NULL)
+			return NULL;
+		if (*strp++ != '.')
+			return NULL;
+		strp = getnum(strp, &rulep->r_week, 1, 5);
+		if (strp == NULL)
+			return NULL;
+		if (*strp++ != '.')
+			return NULL;
+		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+	} else if (is_digit(*strp)) {
+		/*
+		** Day of year.
+		*/
+		rulep->r_type = DAY_OF_YEAR;
+		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+	} else	return NULL;		/* invalid format */
+	if (strp == NULL)
+		return NULL;
+	if (*strp == '/') {
+		/*
+		** Time specified.
+		*/
+		++strp;
+		strp = getoffset(strp, &rulep->r_time);
+	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
+	return strp;
 }
 
 /*
@@ -840,11 +914,11 @@
 ** effect, calculate the year-relative time that rule takes effect.
 */
 
-static int_fast32_t
+static int_fast32_t ATTRIBUTE_PURE
 transtime(const int year, register const struct rule *const rulep,
           const int_fast32_t offset)
 {
-    register int          leapyear;
+    register bool         leapyear;
     register int_fast32_t value;
     register int          i;
     int d, m1, yy0, yy1, yy2, dow;
@@ -931,457 +1005,537 @@
 ** appropriate.
 */
 
-static int
-tzparse(const char * name, register struct state * const sp,
-        const int lastditch)
+static bool
+tzparse(const char *name, struct state *sp, bool lastditch)
 {
-    const char *         stdname;
-    const char *         dstname;
-    size_t               stdlen;
-    size_t               dstlen;
-    int_fast32_t         stdoffset;
-    int_fast32_t         dstoffset;
-    register char *      cp;
-    register int         load_result;
-    static struct ttinfo zttinfo;
+	const char *			stdname;
+	const char *			dstname;
+	size_t				stdlen;
+	size_t				dstlen;
+	size_t				charcnt;
+	int_fast32_t			stdoffset;
+	int_fast32_t			dstoffset;
+	register char *			cp;
+	register bool			load_ok;
 
-    stdname = name;
-    if (lastditch) {
-        stdlen = strlen(name);  /* length of standard zone name */
-        name += stdlen;
-        if (stdlen >= sizeof sp->chars)
-            stdlen = (sizeof sp->chars) - 1;
-        stdoffset = 0;
-    } else {
-        if (*name == '<') {
-            name++;
-            stdname = name;
-            name = getqzname(name, '>');
-            if (*name != '>')
-                return (-1);
-            stdlen = name - stdname;
-            name++;
-        } else {
-            name = getzname(name);
-            stdlen = name - stdname;
-        }
-        if (*name == '\0')
-            return -1;
-        name = getoffset(name, &stdoffset);
-        if (name == NULL)
-            return -1;
-    }
-    load_result = tzload(TZDEFRULES, sp, FALSE);
-    if (load_result != 0)
-        sp->leapcnt = 0;        /* so, we're off a little */
-    if (*name != '\0') {
-        if (*name == '<') {
-            dstname = ++name;
-            name = getqzname(name, '>');
-            if (*name != '>')
-                return -1;
-            dstlen = name - dstname;
-            name++;
-        } else {
-            dstname = name;
-            name = getzname(name);
-            dstlen = name - dstname; /* length of DST zone name */
-        }
-        if (*name != '\0' && *name != ',' && *name != ';') {
-            name = getoffset(name, &dstoffset);
-            if (name == NULL)
-                return -1;
-        } else  dstoffset = stdoffset - SECSPERHOUR;
-        if (*name == '\0' && load_result != 0)
-            name = TZDEFRULESTRING;
-        if (*name == ',' || *name == ';') {
-            struct rule  start;
-            struct rule  end;
-            register int year;
-            register int yearlim;
-            register int timecnt;
-            time_t       janfirst;
+	stdname = name;
+	if (lastditch) {
+		stdlen = sizeof gmt - 1;
+		name += stdlen;
+		stdoffset = 0;
+	} else {
+		if (*name == '<') {
+			name++;
+			stdname = name;
+			name = getqzname(name, '>');
+			if (*name != '>')
+			  return false;
+			stdlen = name - stdname;
+			name++;
+		} else {
+			name = getzname(name);
+			stdlen = name - stdname;
+		}
+		if (!stdlen)
+		  return false;
+		name = getoffset(name, &stdoffset);
+		if (name == NULL)
+		  return false;
+	}
+	charcnt = stdlen + 1;
+	if (sizeof sp->chars < charcnt)
+	  return false;
+	load_ok = tzload(TZDEFRULES, sp, false) == 0;
+	if (!load_ok)
+		sp->leapcnt = 0;		/* so, we're off a little */
+	if (*name != '\0') {
+		if (*name == '<') {
+			dstname = ++name;
+			name = getqzname(name, '>');
+			if (*name != '>')
+			  return false;
+			dstlen = name - dstname;
+			name++;
+		} else {
+			dstname = name;
+			name = getzname(name);
+			dstlen = name - dstname; /* length of DST zone name */
+		}
+		if (!dstlen)
+		  return false;
+		charcnt += dstlen + 1;
+		if (sizeof sp->chars < charcnt)
+		  return false;
+		if (*name != '\0' && *name != ',' && *name != ';') {
+			name = getoffset(name, &dstoffset);
+			if (name == NULL)
+			  return false;
+		} else	dstoffset = stdoffset - SECSPERHOUR;
+		if (*name == '\0' && !load_ok)
+			name = TZDEFRULESTRING;
+		if (*name == ',' || *name == ';') {
+			struct rule	start;
+			struct rule	end;
+			register int	year;
+			register int	yearlim;
+			register int	timecnt;
+			time_t		janfirst;
 
-            ++name;
-            if ((name = getrule(name, &start)) == NULL)
-                return -1;
-            if (*name++ != ',')
-                return -1;
-            if ((name = getrule(name, &end)) == NULL)
-                return -1;
-            if (*name != '\0')
-                return -1;
-            sp->typecnt = 2;    /* standard time and DST */
-            /*
-            ** Two transitions per year, from EPOCH_YEAR forward.
-            */
-            sp->ttis[0] = sp->ttis[1] = zttinfo;
-            sp->ttis[0].tt_gmtoff = -dstoffset;
-            sp->ttis[0].tt_isdst = 1;
-            sp->ttis[0].tt_abbrind = stdlen + 1;
-            sp->ttis[1].tt_gmtoff = -stdoffset;
-            sp->ttis[1].tt_isdst = 0;
-            sp->ttis[1].tt_abbrind = 0;
-            sp->defaulttype = 0;
-            timecnt = 0;
-            janfirst = 0;
-            yearlim = EPOCH_YEAR + YEARSPERREPEAT;
-            for (year = EPOCH_YEAR; year < yearlim; year++) {
-                int_fast32_t
-                  starttime = transtime(year, &start, stdoffset),
-                  endtime = transtime(year, &end, dstoffset);
-                int_fast32_t
-                yearsecs = (year_lengths[isleap(year)]
-                            * SECSPERDAY);
-                int reversed = endtime < starttime;
-                if (reversed) {
-                    int_fast32_t swap = starttime;
-                    starttime = endtime;
-                    endtime = swap;
-                }
-                if (reversed
-                    || (starttime < endtime
-                        && (endtime - starttime
-                            < (yearsecs
-                               + (stdoffset - dstoffset))))) {
-                    if (TZ_MAX_TIMES - 2 < timecnt)
-                        break;
-                    yearlim = year + YEARSPERREPEAT + 1;
-                    sp->ats[timecnt] = janfirst;
-                    if (increment_overflow_time
-                        (&sp->ats[timecnt], starttime))
-                        break;
-                    sp->types[timecnt++] = reversed;
-                    sp->ats[timecnt] = janfirst;
-                    if (increment_overflow_time
-                        (&sp->ats[timecnt], endtime))
-                        break;
-                    sp->types[timecnt++] = !reversed;
-                    }
-                if (increment_overflow_time(&janfirst, yearsecs))
-                    break;
-            }
-            sp->timecnt = timecnt;
-            if (!timecnt)
-                sp->typecnt = 1;    /* Perpetual DST.  */
-        } else {
-            register int_fast32_t   theirstdoffset;
-            register int_fast32_t   theirdstoffset;
-            register int_fast32_t   theiroffset;
-            register int    isdst;
-            register int    i;
-            register int    j;
+			++name;
+			if ((name = getrule(name, &start)) == NULL)
+			  return false;
+			if (*name++ != ',')
+			  return false;
+			if ((name = getrule(name, &end)) == NULL)
+			  return false;
+			if (*name != '\0')
+			  return false;
+			sp->typecnt = 2;	/* standard time and DST */
+			/*
+			** Two transitions per year, from EPOCH_YEAR forward.
+			*/
+			init_ttinfo(&sp->ttis[0], -dstoffset, true, stdlen + 1);
+			init_ttinfo(&sp->ttis[1], -stdoffset, false, 0);
+			sp->defaulttype = 0;
+			timecnt = 0;
+			janfirst = 0;
+			yearlim = EPOCH_YEAR + YEARSPERREPEAT;
+			for (year = EPOCH_YEAR; year < yearlim; year++) {
+				int_fast32_t
+				  starttime = transtime(year, &start, stdoffset),
+				  endtime = transtime(year, &end, dstoffset);
+				int_fast32_t
+				  yearsecs = (year_lengths[isleap(year)]
+					      * SECSPERDAY);
+				bool reversed = endtime < starttime;
+				if (reversed) {
+					int_fast32_t swap = starttime;
+					starttime = endtime;
+					endtime = swap;
+				}
+				if (reversed
+				    || (starttime < endtime
+					&& (endtime - starttime
+					    < (yearsecs
+					       + (stdoffset - dstoffset))))) {
+					if (TZ_MAX_TIMES - 2 < timecnt)
+						break;
+					yearlim = year + YEARSPERREPEAT + 1;
+					sp->ats[timecnt] = janfirst;
+					if (increment_overflow_time
+					    (&sp->ats[timecnt], starttime))
+						break;
+					sp->types[timecnt++] = reversed;
+					sp->ats[timecnt] = janfirst;
+					if (increment_overflow_time
+					    (&sp->ats[timecnt], endtime))
+						break;
+					sp->types[timecnt++] = !reversed;
+				}
+				if (increment_overflow_time(&janfirst, yearsecs))
+					break;
+			}
+			sp->timecnt = timecnt;
+			if (!timecnt)
+				sp->typecnt = 1;	/* Perpetual DST.  */
+		} else {
+			register int_fast32_t	theirstdoffset;
+			register int_fast32_t	theirdstoffset;
+			register int_fast32_t	theiroffset;
+			register bool		isdst;
+			register int		i;
+			register int		j;
 
-            if (*name != '\0')
-                return -1;
-            /*
-            ** Initial values of theirstdoffset and theirdstoffset.
-            */
-            theirstdoffset = 0;
-            for (i = 0; i < sp->timecnt; ++i) {
-                j = sp->types[i];
-                if (!sp->ttis[j].tt_isdst) {
-                    theirstdoffset =
-                        -sp->ttis[j].tt_gmtoff;
-                    break;
-                }
-            }
-            theirdstoffset = 0;
-            for (i = 0; i < sp->timecnt; ++i) {
-                j = sp->types[i];
-                if (sp->ttis[j].tt_isdst) {
-                    theirdstoffset =
-                        -sp->ttis[j].tt_gmtoff;
-                    break;
-                }
-            }
-            /*
-            ** Initially we're assumed to be in standard time.
-            */
-            isdst = FALSE;
-            theiroffset = theirstdoffset;
-            /*
-            ** Now juggle transition times and types
-            ** tracking offsets as you do.
-            */
-            for (i = 0; i < sp->timecnt; ++i) {
-                j = sp->types[i];
-                sp->types[i] = sp->ttis[j].tt_isdst;
-                if (sp->ttis[j].tt_ttisgmt) {
-                    /* No adjustment to transition time */
-                } else {
-                    /*
-                    ** If summer time is in effect, and the
-                    ** transition time was not specified as
-                    ** standard time, add the summer time
-                    ** offset to the transition time;
-                    ** otherwise, add the standard time
-                    ** offset to the transition time.
-                    */
-                    /*
-                    ** Transitions from DST to DDST
-                    ** will effectively disappear since
-                    ** POSIX provides for only one DST
-                    ** offset.
-                    */
-                    if (isdst && !sp->ttis[j].tt_ttisstd) {
-                        sp->ats[i] += dstoffset -
-                            theirdstoffset;
-                    } else {
-                        sp->ats[i] += stdoffset -
-                            theirstdoffset;
-                    }
-                }
-                theiroffset = -sp->ttis[j].tt_gmtoff;
-                if (sp->ttis[j].tt_isdst)
-                    theirdstoffset = theiroffset;
-                else    theirstdoffset = theiroffset;
-            }
-            /*
-            ** Finally, fill in ttis.
-            */
-            sp->ttis[0] = sp->ttis[1] = zttinfo;
-            sp->ttis[0].tt_gmtoff = -stdoffset;
-            sp->ttis[0].tt_isdst = FALSE;
-            sp->ttis[0].tt_abbrind = 0;
-            sp->ttis[1].tt_gmtoff = -dstoffset;
-            sp->ttis[1].tt_isdst = TRUE;
-            sp->ttis[1].tt_abbrind = stdlen + 1;
-            sp->typecnt = 2;
-            sp->defaulttype = 0;
-        }
-    } else {
-        dstlen = 0;
-        sp->typecnt = 1;        /* only standard time */
-        sp->timecnt = 0;
-        sp->ttis[0] = zttinfo;
-        sp->ttis[0].tt_gmtoff = -stdoffset;
-        sp->ttis[0].tt_isdst = 0;
-        sp->ttis[0].tt_abbrind = 0;
-        sp->defaulttype = 0;
-    }
-    sp->charcnt = stdlen + 1;
-    if (dstlen != 0)
-        sp->charcnt += dstlen + 1;
-    if ((size_t) sp->charcnt > sizeof sp->chars)
-        return -1;
-    cp = sp->chars;
-    (void) strncpy(cp, stdname, stdlen);
-    cp += stdlen;
-    *cp++ = '\0';
-    if (dstlen != 0) {
-        (void) strncpy(cp, dstname, dstlen);
-        *(cp + dstlen) = '\0';
-    }
-    return 0;
+			if (*name != '\0')
+			  return false;
+			/*
+			** Initial values of theirstdoffset and theirdstoffset.
+			*/
+			theirstdoffset = 0;
+			for (i = 0; i < sp->timecnt; ++i) {
+				j = sp->types[i];
+				if (!sp->ttis[j].tt_isdst) {
+					theirstdoffset =
+						-sp->ttis[j].tt_gmtoff;
+					break;
+				}
+			}
+			theirdstoffset = 0;
+			for (i = 0; i < sp->timecnt; ++i) {
+				j = sp->types[i];
+				if (sp->ttis[j].tt_isdst) {
+					theirdstoffset =
+						-sp->ttis[j].tt_gmtoff;
+					break;
+				}
+			}
+			/*
+			** Initially we're assumed to be in standard time.
+			*/
+			isdst = false;
+			theiroffset = theirstdoffset;
+			/*
+			** Now juggle transition times and types
+			** tracking offsets as you do.
+			*/
+			for (i = 0; i < sp->timecnt; ++i) {
+				j = sp->types[i];
+				sp->types[i] = sp->ttis[j].tt_isdst;
+				if (sp->ttis[j].tt_ttisgmt) {
+					/* No adjustment to transition time */
+				} else {
+					/*
+					** If summer time is in effect, and the
+					** transition time was not specified as
+					** standard time, add the summer time
+					** offset to the transition time;
+					** otherwise, add the standard time
+					** offset to the transition time.
+					*/
+					/*
+					** Transitions from DST to DDST
+					** will effectively disappear since
+					** POSIX provides for only one DST
+					** offset.
+					*/
+					if (isdst && !sp->ttis[j].tt_ttisstd) {
+						sp->ats[i] += dstoffset -
+							theirdstoffset;
+					} else {
+						sp->ats[i] += stdoffset -
+							theirstdoffset;
+					}
+				}
+				theiroffset = -sp->ttis[j].tt_gmtoff;
+				if (sp->ttis[j].tt_isdst)
+					theirdstoffset = theiroffset;
+				else	theirstdoffset = theiroffset;
+			}
+			/*
+			** Finally, fill in ttis.
+			*/
+			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
+			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
+			sp->typecnt = 2;
+			sp->defaulttype = 0;
+		}
+	} else {
+		dstlen = 0;
+		sp->typecnt = 1;		/* only standard time */
+		sp->timecnt = 0;
+		init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
+		sp->defaulttype = 0;
+	}
+	sp->charcnt = charcnt;
+	cp = sp->chars;
+	memcpy(cp, stdname, stdlen);
+	cp += stdlen;
+	*cp++ = '\0';
+	if (dstlen != 0) {
+		memcpy(cp, dstname, dstlen);
+		*(cp + dstlen) = '\0';
+	}
+	return true;
 }
 
 static void
-gmtload(struct state * const sp)
+gmtload(struct state *const sp)
 {
-    if (tzload(gmt, sp, TRUE) != 0)
-        (void) tzparse(gmt, sp, TRUE);
+	if (tzload(gmt, sp, true) != 0)
+		tzparse(gmt, sp, true);
 }
 
-#ifndef STD_INSPIRED
-/*
-** A non-static declaration of tzsetwall in a system header file
-** may cause a warning about this upcoming static declaration...
-*/
-static
-#endif /* !defined STD_INSPIRED */
+/* Initialize *SP to a value appropriate for the TZ setting NAME.
+   Return 0 on success, an errno value on failure.  */
+static int
+zoneinit(struct state *sp, char const *name)
+{
+  if (name && ! name[0]) {
+    /*
+    ** User wants it fast rather than right.
+    */
+    sp->leapcnt = 0;		/* so, we're off a little */
+    sp->timecnt = 0;
+    sp->typecnt = 0;
+    sp->charcnt = 0;
+    sp->goback = sp->goahead = false;
+    init_ttinfo(&sp->ttis[0], 0, false, 0);
+    strcpy(sp->chars, gmt);
+    sp->defaulttype = 0;
+    return 0;
+  } else {
+    int err = tzload(name, sp, true);
+    if (err != 0 && name && name[0] != ':' && tzparse(name, sp, false))
+      err = 0;
+    if (err == 0)
+      scrub_abbrs(sp);
+    return err;
+  }
+}
+
+static void
+tzsetlcl(char const *name)
+{
+  struct state *sp = lclptr;
+  int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
+  if (lcl < 0
+      ? lcl_is_set < 0
+      : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
+    return;
+#ifdef ALL_STATE
+  if (! sp)
+    lclptr = sp = malloc(sizeof *lclptr);
+#endif /* defined ALL_STATE */
+  if (sp) {
+    if (zoneinit(sp, name) != 0)
+      zoneinit(sp, "");
+    if (0 < lcl)
+      strcpy(lcl_TZname, name);
+  }
+  settzname();
+  lcl_is_set = lcl;
+}
+
+#ifdef STD_INSPIRED
 void
 tzsetwall(void)
 {
-    if (lcl_is_set < 0)
-        return;
-    lcl_is_set = -1;
-
-#ifdef ALL_STATE
-    if (lclptr == NULL) {
-        lclptr = malloc(sizeof *lclptr);
-        if (lclptr == NULL) {
-            settzname();    /* all we can do */
-            return;
-        }
-    }
-#endif /* defined ALL_STATE */
-    if (tzload(NULL, lclptr, TRUE) != 0)
-        gmtload(lclptr);
-    settzname();
+  if (lock() != 0)
+    return;
+  tzsetlcl(NULL);
+  unlock();
 }
+#endif
 
-#include <sys/system_properties.h> // For __system_property_get.
+#if defined(__ANDROID__)
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h> // For __system_property_serial.
+#endif
 
 static void
-tzset_locked(void)
+tzset_unlocked(void)
 {
-    register const char * name;
+#if defined(__ANDROID__)
+  const char * name = getenv("TZ");
 
-    name = getenv("TZ");
+  // Try the "persist.sys.timezone" system property.
+  if (name == NULL) {
+    static const prop_info *pi;
 
-    // try the "persist.sys.timezone" system property first
-    static char buf[PROP_VALUE_MAX];
-    if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0) {
+    if (!pi) {
+      pi = __system_property_find("persist.sys.timezone");
+    }
+    if (pi) {
+      static char buf[PROP_VALUE_MAX];
+      static uint32_t s = -1;
+      static bool ok = false;
+      uint32_t serial = __system_property_serial(pi);
+      if (serial != s) {
+        ok = __system_property_read(pi, 0, buf) > 0;
+        s = serial;
+      }
+      if (ok) {
         name = buf;
+      }
     }
+  }
 
-    if (name == NULL) {
-        tzsetwall();
-        return;
-    }
-
-    if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
-        return;
-    lcl_is_set = strlen(name) < sizeof lcl_TZname;
-    if (lcl_is_set)
-        (void) strcpy(lcl_TZname, name);
-
-#ifdef ALL_STATE
-    if (lclptr == NULL) {
-        lclptr = malloc(sizeof *lclptr);
-        if (lclptr == NULL) {
-            settzname();    /* all we can do */
-            return;
-        }
-    }
-#endif /* defined ALL_STATE */
-    if (*name == '\0') {
-        /*
-        ** User wants it fast rather than right.
-        */
-        lclptr->leapcnt = 0;        /* so, we're off a little */
-        lclptr->timecnt = 0;
-        lclptr->typecnt = 0;
-        lclptr->ttis[0].tt_isdst = 0;
-        lclptr->ttis[0].tt_gmtoff = 0;
-        lclptr->ttis[0].tt_abbrind = 0;
-        (void) strcpy(lclptr->chars, gmt);
-        lclptr->defaulttype = 0;
-    } else if (tzload(name, lclptr, TRUE) != 0)
-        if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
-            (void) gmtload(lclptr);
-    settzname();
+  tzsetlcl(name);
+#else
+  tzsetlcl(getenv("TZ"));
+#endif
 }
 
 void
 tzset(void)
 {
-    _tzLock();
-    tzset_locked();
-    _tzUnlock();
+  if (lock() != 0)
+    return;
+  tzset_unlocked();
+  unlock();
+}
+
+static void
+gmtcheck(void)
+{
+  static bool gmt_is_set;
+  if (lock() != 0)
+    return;
+  if (! gmt_is_set) {
+#ifdef ALL_STATE
+    gmtptr = malloc(sizeof *gmtptr);
+#endif
+    if (gmtptr)
+      gmtload(gmtptr);
+    gmt_is_set = true;
+  }
+  unlock();
+}
+
+#if NETBSD_INSPIRED
+
+timezone_t
+tzalloc(char const *name)
+{
+  timezone_t sp = malloc(sizeof *sp);
+  if (sp) {
+    int err = zoneinit(sp, name);
+    if (err != 0) {
+      free(sp);
+      errno = err;
+      return NULL;
+    }
+  }
+  return sp;
+}
+
+void
+tzfree(timezone_t sp)
+{
+  free(sp);
 }
 
 /*
+** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
+** ctime_r are obsolescent and have potential security problems that
+** ctime_rz would share.  Callers can instead use localtime_rz + strftime.
+**
+** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
+** in zones with three or more time zone abbreviations.
+** Callers can instead use localtime_rz + strftime.
+*/
+
+#endif
+
+/*
 ** The easy way to behave "as if no library function calls" localtime
-** is to not call it--so we drop its guts into "localsub", which can be
-** freely called. (And no, the PANS doesn't require the above behavior--
+** is to not call it, so we drop its guts into "localsub", which can be
+** freely called. (And no, the PANS doesn't require the above behavior,
 ** but it *is* desirable.)
 **
-** The unused offset argument is for the benefit of mktime variants.
+** If successful and SETNAME is nonzero,
+** set the applicable parts of tzname, timezone and altzone;
+** however, it's OK to omit this step if the time zone is POSIX-compatible,
+** since in that case tzset should have already done this step correctly.
+** SETNAME's type is intfast32_t for compatibility with gmtsub,
+** but it is actually a boolean and its value should be 0 or 1.
 */
 
 /*ARGSUSED*/
 static struct tm *
-localsub(const time_t * const timep, const int_fast32_t offset,
-         struct tm * const tmp, struct state * sp) // android-changed: added sp.
+localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
+	 struct tm *const tmp)
 {
-    register const struct ttinfo * ttisp;
-    register int         i;
-    register struct tm * result;
-    const time_t         t = *timep;
+	register const struct ttinfo *	ttisp;
+	register int			i;
+	register struct tm *		result;
+	const time_t			t = *timep;
 
-    // BEGIN android-changed: support user-supplied sp.
-    if (sp == NULL) {
-        sp = lclptr;
-    }
-    // END android-changed
-    if (sp == NULL)
-        return gmtsub(timep, offset, tmp, sp); // android-changed: added sp.
-    if ((sp->goback && t < sp->ats[0]) ||
-        (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
-            time_t          newt = t;
-            register time_t seconds;
-            register time_t years;
+	if (sp == NULL) {
+	  /* Don't bother to set tzname etc.; tzset has already done it.  */
+	  return gmtsub(gmtptr, timep, 0, tmp);
+	}
+	if ((sp->goback && t < sp->ats[0]) ||
+		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
+			time_t			newt = t;
+			register time_t		seconds;
+			register time_t		years;
 
-            if (t < sp->ats[0])
-                seconds = sp->ats[0] - t;
-            else    seconds = t - sp->ats[sp->timecnt - 1];
-            --seconds;
-            years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
-            seconds = years * AVGSECSPERYEAR;
-            if (t < sp->ats[0])
-                newt += seconds;
-            else    newt -= seconds;
-            if (newt < sp->ats[0] ||
-                newt > sp->ats[sp->timecnt - 1])
-                    return NULL;    /* "cannot happen" */
-            result = localsub(&newt, offset, tmp, sp); // android-changed: added sp.
-            if (result == tmp) {
-                register time_t newy;
+			if (t < sp->ats[0])
+				seconds = sp->ats[0] - t;
+			else	seconds = t - sp->ats[sp->timecnt - 1];
+			--seconds;
+			years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
+			seconds = years * AVGSECSPERYEAR;
+			if (t < sp->ats[0])
+				newt += seconds;
+			else	newt -= seconds;
+			if (newt < sp->ats[0] ||
+				newt > sp->ats[sp->timecnt - 1])
+					return NULL;	/* "cannot happen" */
+			result = localsub(sp, &newt, setname, tmp);
+			if (result) {
+				register int_fast64_t newy;
 
-                newy = tmp->tm_year;
-                if (t < sp->ats[0])
-                    newy -= years;
-                else    newy += years;
-                tmp->tm_year = newy;
-                if (tmp->tm_year != newy)
-                    return NULL;
-            }
-            return result;
-    }
-    if (sp->timecnt == 0 || t < sp->ats[0]) {
-        i = sp->defaulttype;
-    } else {
-        register int lo = 1;
-        register int hi = sp->timecnt;
+				newy = result->tm_year;
+				if (t < sp->ats[0])
+					newy -= years;
+				else	newy += years;
+				if (! (INT_MIN <= newy && newy <= INT_MAX))
+					return NULL;
+				result->tm_year = newy;
+			}
+			return result;
+	}
+	if (sp->timecnt == 0 || t < sp->ats[0]) {
+		i = sp->defaulttype;
+	} else {
+		register int	lo = 1;
+		register int	hi = sp->timecnt;
 
-        while (lo < hi) {
-            register int    mid = (lo + hi) >> 1;
+		while (lo < hi) {
+			register int	mid = (lo + hi) >> 1;
 
-            if (t < sp->ats[mid])
-                hi = mid;
-            else    lo = mid + 1;
-        }
-        i = (int) sp->types[lo - 1];
-    }
-    ttisp = &sp->ttis[i];
-    /*
-    ** To get (wrong) behavior that's compatible with System V Release 2.0
-    ** you'd replace the statement below with
-    **  t += ttisp->tt_gmtoff;
-    **  timesub(&t, 0L, sp, tmp);
-    */
-    result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
-    tmp->tm_isdst = ttisp->tt_isdst;
-    tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
+			if (t < sp->ats[mid])
+				hi = mid;
+			else	lo = mid + 1;
+		}
+		i = (int) sp->types[lo - 1];
+	}
+	ttisp = &sp->ttis[i];
+	/*
+	** To get (wrong) behavior that's compatible with System V Release 2.0
+	** you'd replace the statement below with
+	**	t += ttisp->tt_gmtoff;
+	**	timesub(&t, 0L, sp, tmp);
+	*/
+	result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+	if (result) {
+	  result->tm_isdst = ttisp->tt_isdst;
 #ifdef TM_ZONE
-    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
+	  result->TM_ZONE = (char *) &sp->chars[ttisp->tt_abbrind];
 #endif /* defined TM_ZONE */
-    return result;
+	  if (setname)
+	    update_tzname_etc(sp, ttisp);
+	}
+	return result;
+}
+
+#if NETBSD_INSPIRED
+
+struct tm *
+localtime_rz(struct state *sp, time_t const *timep, struct tm *tmp)
+{
+  return localsub(sp, timep, 0, tmp);
+}
+
+#endif
+
+static struct tm *
+localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
+{
+  int err = lock();
+  if (err) {
+    errno = err;
+    return NULL;
+  }
+  if (setname || !lcl_is_set)
+    tzset_unlocked();
+  tmp = localsub(lclptr, timep, setname, tmp);
+  unlock();
+  return tmp;
 }
 
 struct tm *
-localtime(const time_t * const timep)
+localtime(const time_t *timep)
 {
-    return localtime_r(timep, &tmGlobal);
+  return localtime_tzset(timep, &tm, true);
 }
 
-/*
-** Re-entrant version of localtime.
-*/
-
 struct tm *
-localtime_r(const time_t * const timep, struct tm * tmp)
+localtime_r(const time_t *timep, struct tm *tmp)
 {
-    struct tm* result;
-
-    _tzLock();
-    tzset_locked();
-    result = localsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
-    _tzUnlock();
-
-    return result;
+  return localtime_tzset(timep, tmp, false);
 }
 
 /*
@@ -1389,37 +1543,22 @@
 */
 
 static struct tm *
-gmtsub(const time_t * const timep, const int_fast32_t offset,
-       struct tm *const tmp, struct state * sp __unused) // android-changed: added sp.
+gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
+       struct tm *tmp)
 {
-    register struct tm * result;
+	register struct tm *	result;
 
-    if (!gmt_is_set) {
-#ifdef ALL_STATE
-        gmtptr = malloc(sizeof *gmtptr);
-        gmt_is_set = gmtptr != NULL;
-#else
-        gmt_is_set = TRUE;
-#endif /* defined ALL_STATE */
-        if (gmt_is_set)
-            gmtload(gmtptr);
-    }
-    result = timesub(timep, offset, gmtptr, tmp);
+	result = timesub(timep, offset, gmtptr, tmp);
 #ifdef TM_ZONE
-    /*
-    ** Could get fancy here and deliver something such as
-    ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
-    ** but this is no time for a treasure hunt.
-    */
-    tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt;
+	/*
+	** Could get fancy here and deliver something such as
+	** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
+	** but this is no time for a treasure hunt.
+	*/
+	tmp->TM_ZONE = ((char *)
+			(offset ? wildabbr : gmtptr ? gmtptr->chars : gmt));
 #endif /* defined TM_ZONE */
-    return result;
-}
-
-struct tm *
-gmtime(const time_t * const timep)
-{
-    return gmtime_r(timep, &tmGlobal);
+	return result;
 }
 
 /*
@@ -1427,23 +1566,25 @@
 */
 
 struct tm *
-gmtime_r(const time_t * const timep, struct tm * tmp)
+gmtime_r(const time_t *timep, struct tm *tmp)
 {
-    struct tm* result;
+  gmtcheck();
+  return gmtsub(gmtptr, timep, 0, tmp);
+}
 
-    _tzLock();
-    result = gmtsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
-    _tzUnlock();
-
-    return result;
+struct tm *
+gmtime(const time_t *timep)
+{
+  return gmtime_r(timep, &tm);
 }
 
 #ifdef STD_INSPIRED
 
 struct tm *
-offtime(const time_t *const timep, const long offset)
+offtime(const time_t *timep, long offset)
 {
-    return gmtsub(timep, offset, &tmGlobal, NULL); // android-changed: extra parameter.
+  gmtcheck();
+  return gmtsub(gmtptr, timep, offset, &tm);
 }
 
 #endif /* defined STD_INSPIRED */
@@ -1453,597 +1594,610 @@
 ** where, to make the math easy, the answer for year zero is defined as zero.
 */
 
-static int
+static int ATTRIBUTE_PURE
 leaps_thru_end_of(register const int y)
 {
-    return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
-        -(leaps_thru_end_of(-(y + 1)) + 1);
+	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
+		-(leaps_thru_end_of(-(y + 1)) + 1);
 }
 
 static struct tm *
-timesub(const time_t *const timep, const int_fast32_t offset,
-        register const struct state *const sp,
-        register struct tm *const tmp)
+timesub(const time_t *timep, int_fast32_t offset,
+	const struct state *sp, struct tm *tmp)
 {
-    register const struct lsinfo * lp;
-    register time_t       tdays;
-    register int          idays;  /* unsigned would be so 2003 */
-    register int_fast64_t rem;
-    int                   y;
-    register const int *  ip;
-    register int_fast64_t corr;
-    register int          hit;
-    register int          i;
+	register const struct lsinfo *	lp;
+	register time_t			tdays;
+	register int			idays;	/* unsigned would be so 2003 */
+	register int_fast64_t		rem;
+	int				y;
+	register const int *		ip;
+	register int_fast64_t		corr;
+	register bool			hit;
+	register int			i;
 
-    corr = 0;
-    hit = 0;
-    i = (sp == NULL) ? 0 : sp->leapcnt;
-    while (--i >= 0) {
-        lp = &sp->lsis[i];
-        if (*timep >= lp->ls_trans) {
-            if (*timep == lp->ls_trans) {
-                hit = ((i == 0 && lp->ls_corr > 0) ||
-                    lp->ls_corr > sp->lsis[i - 1].ls_corr);
-                if (hit)
-                    while (i > 0 &&
-                        sp->lsis[i].ls_trans ==
-                        sp->lsis[i - 1].ls_trans + 1 &&
-                        sp->lsis[i].ls_corr ==
-                        sp->lsis[i - 1].ls_corr + 1) {
-                            ++hit;
-                            --i;
-                    }
-            }
-            corr = lp->ls_corr;
-            break;
-        }
-    }
-    y = EPOCH_YEAR;
-    tdays = *timep / SECSPERDAY;
-    rem = *timep - tdays * SECSPERDAY;
-    while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
-        int     newy;
-        register time_t tdelta;
-        register int    idelta;
-        register int    leapdays;
+	corr = 0;
+	hit = false;
+	i = (sp == NULL) ? 0 : sp->leapcnt;
+	while (--i >= 0) {
+		lp = &sp->lsis[i];
+		if (*timep >= lp->ls_trans) {
+			if (*timep == lp->ls_trans) {
+				hit = ((i == 0 && lp->ls_corr > 0) ||
+					lp->ls_corr > sp->lsis[i - 1].ls_corr);
+				if (hit)
+					while (i > 0 &&
+						sp->lsis[i].ls_trans ==
+						sp->lsis[i - 1].ls_trans + 1 &&
+						sp->lsis[i].ls_corr ==
+						sp->lsis[i - 1].ls_corr + 1) {
+							++hit;
+							--i;
+					}
+			}
+			corr = lp->ls_corr;
+			break;
+		}
+	}
+	y = EPOCH_YEAR;
+	tdays = *timep / SECSPERDAY;
+	rem = *timep % SECSPERDAY;
+	while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
+		int		newy;
+		register time_t	tdelta;
+		register int	idelta;
+		register int	leapdays;
 
-        tdelta = tdays / DAYSPERLYEAR;
-        if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
-               && tdelta <= INT_MAX))
-                return NULL;
-        idelta = tdelta;
-        if (idelta == 0)
-            idelta = (tdays < 0) ? -1 : 1;
-        newy = y;
-        if (increment_overflow(&newy, idelta))
-            return NULL;
-        leapdays = leaps_thru_end_of(newy - 1) -
-            leaps_thru_end_of(y - 1);
-        tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
-        tdays -= leapdays;
-        y = newy;
-    }
-    {
-        register int_fast32_t   seconds;
-
-        seconds = tdays * SECSPERDAY;
-        tdays = seconds / SECSPERDAY;
-        rem += seconds - tdays * SECSPERDAY;
-    }
-    /*
-    ** Given the range, we can now fearlessly cast...
-    */
-    idays = tdays;
-    rem += offset - corr;
-    while (rem < 0) {
-        rem += SECSPERDAY;
-        --idays;
-    }
-    while (rem >= SECSPERDAY) {
-        rem -= SECSPERDAY;
-        ++idays;
-    }
-    while (idays < 0) {
-        if (increment_overflow(&y, -1))
-            return NULL;
-        idays += year_lengths[isleap(y)];
-    }
-    while (idays >= year_lengths[isleap(y)]) {
-        idays -= year_lengths[isleap(y)];
-        if (increment_overflow(&y, 1))
-            return NULL;
-    }
-    tmp->tm_year = y;
-    if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
-        return NULL;
-    tmp->tm_yday = idays;
-    /*
-    ** The "extra" mods below avoid overflow problems.
-    */
-    tmp->tm_wday = EPOCH_WDAY +
-        ((y - EPOCH_YEAR) % DAYSPERWEEK) *
-        (DAYSPERNYEAR % DAYSPERWEEK) +
-        leaps_thru_end_of(y - 1) -
-        leaps_thru_end_of(EPOCH_YEAR - 1) +
-        idays;
-    tmp->tm_wday %= DAYSPERWEEK;
-    if (tmp->tm_wday < 0)
-        tmp->tm_wday += DAYSPERWEEK;
-    tmp->tm_hour = (int) (rem / SECSPERHOUR);
-    rem %= SECSPERHOUR;
-    tmp->tm_min = (int) (rem / SECSPERMIN);
-    /*
-    ** A positive leap second requires a special
-    ** representation. This uses "... ??:59:60" et seq.
-    */
-    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
-    ip = mon_lengths[isleap(y)];
-    for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
-        idays -= ip[tmp->tm_mon];
-    tmp->tm_mday = (int) (idays + 1);
-    tmp->tm_isdst = 0;
+		tdelta = tdays / DAYSPERLYEAR;
+		if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
+		       && tdelta <= INT_MAX))
+		  goto out_of_range;
+		idelta = tdelta;
+		if (idelta == 0)
+			idelta = (tdays < 0) ? -1 : 1;
+		newy = y;
+		if (increment_overflow(&newy, idelta))
+		  goto out_of_range;
+		leapdays = leaps_thru_end_of(newy - 1) -
+			leaps_thru_end_of(y - 1);
+		tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
+		tdays -= leapdays;
+		y = newy;
+	}
+	/*
+	** Given the range, we can now fearlessly cast...
+	*/
+	idays = tdays;
+	rem += offset - corr;
+	while (rem < 0) {
+		rem += SECSPERDAY;
+		--idays;
+	}
+	while (rem >= SECSPERDAY) {
+		rem -= SECSPERDAY;
+		++idays;
+	}
+	while (idays < 0) {
+		if (increment_overflow(&y, -1))
+		  goto out_of_range;
+		idays += year_lengths[isleap(y)];
+	}
+	while (idays >= year_lengths[isleap(y)]) {
+		idays -= year_lengths[isleap(y)];
+		if (increment_overflow(&y, 1))
+		  goto out_of_range;
+	}
+	tmp->tm_year = y;
+	if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
+	  goto out_of_range;
+	tmp->tm_yday = idays;
+	/*
+	** The "extra" mods below avoid overflow problems.
+	*/
+	tmp->tm_wday = EPOCH_WDAY +
+		((y - EPOCH_YEAR) % DAYSPERWEEK) *
+		(DAYSPERNYEAR % DAYSPERWEEK) +
+		leaps_thru_end_of(y - 1) -
+		leaps_thru_end_of(EPOCH_YEAR - 1) +
+		idays;
+	tmp->tm_wday %= DAYSPERWEEK;
+	if (tmp->tm_wday < 0)
+		tmp->tm_wday += DAYSPERWEEK;
+	tmp->tm_hour = (int) (rem / SECSPERHOUR);
+	rem %= SECSPERHOUR;
+	tmp->tm_min = (int) (rem / SECSPERMIN);
+	/*
+	** A positive leap second requires a special
+	** representation. This uses "... ??:59:60" et seq.
+	*/
+	tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
+	ip = mon_lengths[isleap(y)];
+	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
+		idays -= ip[tmp->tm_mon];
+	tmp->tm_mday = (int) (idays + 1);
+	tmp->tm_isdst = 0;
 #ifdef TM_GMTOFF
-    tmp->TM_GMTOFF = offset;
+	tmp->TM_GMTOFF = offset;
 #endif /* defined TM_GMTOFF */
-    return tmp;
+	return tmp;
+
+ out_of_range:
+	errno = EOVERFLOW;
+	return NULL;
 }
 
 char *
-ctime(const time_t * const timep)
+ctime(const time_t *timep)
 {
 /*
 ** Section 4.12.3.2 of X3.159-1989 requires that
-**  The ctime function converts the calendar time pointed to by timer
-**  to local time in the form of a string. It is equivalent to
-**      asctime(localtime(timer))
+**	The ctime function converts the calendar time pointed to by timer
+**	to local time in the form of a string. It is equivalent to
+**		asctime(localtime(timer))
 */
-    return asctime(localtime(timep));
+  struct tm *tmp = localtime(timep);
+  return tmp ? asctime(tmp) : NULL;
 }
 
 char *
-ctime_r(const time_t * const timep, char * buf)
+ctime_r(const time_t *timep, char *buf)
 {
-    struct tm   mytm;
-
-    return asctime_r(localtime_r(timep, &mytm), buf);
+  struct tm mytm;
+  struct tm *tmp = localtime_r(timep, &mytm);
+  return tmp ? asctime_r(tmp, buf) : NULL;
 }
 
 /*
 ** Adapted from code provided by Robert Elz, who writes:
-**  The "best" way to do mktime I think is based on an idea of Bob
-**  Kridle's (so its said...) from a long time ago.
-**  It does a binary search of the time_t space. Since time_t's are
-**  just 32 bits, its a max of 32 iterations (even at 64 bits it
-**  would still be very reasonable).
+**	The "best" way to do mktime I think is based on an idea of Bob
+**	Kridle's (so its said...) from a long time ago.
+**	It does a binary search of the time_t space. Since time_t's are
+**	just 32 bits, its a max of 32 iterations (even at 64 bits it
+**	would still be very reasonable).
 */
 
 #ifndef WRONG
-#define WRONG   (-1)
+#define WRONG	(-1)
 #endif /* !defined WRONG */
 
 /*
 ** Normalize logic courtesy Paul Eggert.
 */
 
-static int
-increment_overflow(int *const ip, int j)
+static bool
+increment_overflow(int *ip, int j)
 {
-    register int const i = *ip;
+	register int const	i = *ip;
 
-    /*
-    ** If i >= 0 there can only be overflow if i + j > INT_MAX
-    ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
-    ** If i < 0 there can only be overflow if i + j < INT_MIN
-    ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
-    */
-    if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
-        return TRUE;
-    *ip += j;
-    return FALSE;
+	/*
+	** If i >= 0 there can only be overflow if i + j > INT_MAX
+	** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
+	** If i < 0 there can only be overflow if i + j < INT_MIN
+	** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
+	*/
+	if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
+		return true;
+	*ip += j;
+	return false;
 }
 
-static int
+static bool
 increment_overflow32(int_fast32_t *const lp, int const m)
 {
-    register int_fast32_t const l = *lp;
+	register int_fast32_t const	l = *lp;
 
-    if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
-        return TRUE;
-    *lp += m;
-    return FALSE;
+	if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
+		return true;
+	*lp += m;
+	return false;
 }
 
-static int
+static bool
 increment_overflow_time(time_t *tp, int_fast32_t j)
 {
-    /*
-    ** This is like
-    ** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
-    ** except that it does the right thing even if *tp + j would overflow.
-    */
-    if (! (j < 0
-           ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
-           : *tp <= time_t_max - j))
-        return TRUE;
-    *tp += j;
-    return FALSE;
+	/*
+	** This is like
+	** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
+	** except that it does the right thing even if *tp + j would overflow.
+	*/
+	if (! (j < 0
+	       ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
+	       : *tp <= time_t_max - j))
+		return true;
+	*tp += j;
+	return false;
 }
 
-static int
+static bool
 normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
 {
-    register int tensdelta;
+	register int	tensdelta;
 
-    tensdelta = (*unitsptr >= 0) ?
-        (*unitsptr / base) :
-        (-1 - (-1 - *unitsptr) / base);
-    *unitsptr -= tensdelta * base;
-    return increment_overflow(tensptr, tensdelta);
+	tensdelta = (*unitsptr >= 0) ?
+		(*unitsptr / base) :
+		(-1 - (-1 - *unitsptr) / base);
+	*unitsptr -= tensdelta * base;
+	return increment_overflow(tensptr, tensdelta);
+}
+
+static bool
+normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
+{
+	register int	tensdelta;
+
+	tensdelta = (*unitsptr >= 0) ?
+		(*unitsptr / base) :
+		(-1 - (-1 - *unitsptr) / base);
+	*unitsptr -= tensdelta * base;
+	return increment_overflow32(tensptr, tensdelta);
 }
 
 static int
-normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr,
-             const int base)
+tmcomp(register const struct tm *const atmp,
+       register const struct tm *const btmp)
 {
-    register int tensdelta;
+	register int	result;
 
-    tensdelta = (*unitsptr >= 0) ?
-        (*unitsptr / base) :
-        (-1 - (-1 - *unitsptr) / base);
-    *unitsptr -= tensdelta * base;
-    return increment_overflow32(tensptr, tensdelta);
-}
-
-static int
-tmcomp(register const struct tm * const atmp,
-       register const struct tm * const btmp)
-{
-    register int result;
-
-    if (atmp->tm_year != btmp->tm_year)
-        return atmp->tm_year < btmp->tm_year ? -1 : 1;
-    if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
-        (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
-        (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
-        (result = (atmp->tm_min - btmp->tm_min)) == 0)
-            result = atmp->tm_sec - btmp->tm_sec;
-    return result;
+	if (atmp->tm_year != btmp->tm_year)
+		return atmp->tm_year < btmp->tm_year ? -1 : 1;
+	if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+		(result = (atmp->tm_min - btmp->tm_min)) == 0)
+			result = atmp->tm_sec - btmp->tm_sec;
+	return result;
 }
 
 static time_t
-time2sub(struct tm * const tmp,
-         struct tm *(*const funcp)(const time_t*, int_fast32_t, struct tm*, struct state*),
-         const int_fast32_t offset,
-         int * const okayp,
-         const int do_norm_secs, struct state * sp) // android-changed: added sp
+time2sub(struct tm *const tmp,
+	 struct tm *(*funcp)(struct state const *, time_t const *,
+			     int_fast32_t, struct tm *),
+	 struct state const *sp,
+	 const int_fast32_t offset,
+	 bool *okayp,
+	 bool do_norm_secs)
 {
-    register int          dir;
-    register int          i, j;
-    register int          saved_seconds;
-    register int_fast32_t li;
-    register time_t       lo;
-    register time_t       hi;
-    int_fast32_t          y;
-    time_t                newt;
-    time_t                t;
-    struct tm             yourtm, mytm;
+	register int			dir;
+	register int			i, j;
+	register int			saved_seconds;
+	register int_fast32_t		li;
+	register time_t			lo;
+	register time_t			hi;
+	int_fast32_t			y;
+	time_t				newt;
+	time_t				t;
+	struct tm			yourtm, mytm;
 
-    *okayp = FALSE;
-    yourtm = *tmp;
-    if (do_norm_secs) {
-        if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
-            SECSPERMIN))
-                return WRONG;
-    }
-    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
-        return WRONG;
-    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
-        return WRONG;
-    y = yourtm.tm_year;
-    if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
-        return WRONG;
-    /*
-    ** Turn y into an actual year number for now.
-    ** It is converted back to an offset from TM_YEAR_BASE later.
-    */
-    if (increment_overflow32(&y, TM_YEAR_BASE))
-        return WRONG;
-    while (yourtm.tm_mday <= 0) {
-        if (increment_overflow32(&y, -1))
-            return WRONG;
-        li = y + (1 < yourtm.tm_mon);
-        yourtm.tm_mday += year_lengths[isleap(li)];
-    }
-    while (yourtm.tm_mday > DAYSPERLYEAR) {
-        li = y + (1 < yourtm.tm_mon);
-        yourtm.tm_mday -= year_lengths[isleap(li)];
-        if (increment_overflow32(&y, 1))
-            return WRONG;
-    }
-    for ( ; ; ) {
-        i = mon_lengths[isleap(y)][yourtm.tm_mon];
-        if (yourtm.tm_mday <= i)
-            break;
-        yourtm.tm_mday -= i;
-        if (++yourtm.tm_mon >= MONSPERYEAR) {
-            yourtm.tm_mon = 0;
-            if (increment_overflow32(&y, 1))
-                return WRONG;
-        }
-    }
-    if (increment_overflow32(&y, -TM_YEAR_BASE))
-        return WRONG;
-    yourtm.tm_year = y;
-    if (yourtm.tm_year != y)
-        return WRONG;
-    if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
-        saved_seconds = 0;
-    else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
-        /*
-        ** We can't set tm_sec to 0, because that might push the
-        ** time below the minimum representable time.
-        ** Set tm_sec to 59 instead.
-        ** This assumes that the minimum representable time is
-        ** not in the same minute that a leap second was deleted from,
-        ** which is a safer assumption than using 58 would be.
-        */
-        if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
-            return WRONG;
-        saved_seconds = yourtm.tm_sec;
-        yourtm.tm_sec = SECSPERMIN - 1;
-    } else {
-        saved_seconds = yourtm.tm_sec;
-        yourtm.tm_sec = 0;
-    }
-    /*
-    ** Do a binary search (this works whatever time_t's type is).
-    */
-    if (!TYPE_SIGNED(time_t)) {
-        lo = 0;
-        hi = lo - 1;
-    } else {
-        lo = 1;
-        for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
-            lo *= 2;
-        hi = -(lo + 1);
-    }
-    for ( ; ; ) {
-        t = lo / 2 + hi / 2;
-        if (t < lo)
-            t = lo;
-        else if (t > hi)
-            t = hi;
-        if ((*funcp)(&t, offset, &mytm, sp) == NULL) { // android-changed: added sp.
-            /*
-            ** Assume that t is too extreme to be represented in
-            ** a struct tm; arrange things so that it is less
-            ** extreme on the next pass.
-            */
-            dir = (t > 0) ? 1 : -1;
-        } else  dir = tmcomp(&mytm, &yourtm);
-        if (dir != 0) {
-            if (t == lo) {
-                if (t == time_t_max)
-                    return WRONG;
-                ++t;
-                ++lo;
-            } else if (t == hi) {
-                if (t == time_t_min)
-                    return WRONG;
-                --t;
-                --hi;
-            }
-            if (lo > hi)
-                return WRONG;
-            if (dir > 0)
-                hi = t;
-            else    lo = t;
-            continue;
-        }
-        if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
-            break;
-        /*
-        ** Right time, wrong type.
-        ** Hunt for right time, right type.
-        ** It's okay to guess wrong since the guess
-        ** gets checked.
-        */
-        // BEGIN android-changed: support user-supplied sp
-        if (sp == NULL) {
-            sp = (struct state *)
-                ((funcp == localsub) ? lclptr : gmtptr);
-        }
-        // END android-changed
-        if (sp == NULL)
-            return WRONG;
-        for (i = sp->typecnt - 1; i >= 0; --i) {
-            if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
-                continue;
-            for (j = sp->typecnt - 1; j >= 0; --j) {
-                if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
-                    continue;
-                newt = t + sp->ttis[j].tt_gmtoff -
-                    sp->ttis[i].tt_gmtoff;
-                if ((*funcp)(&newt, offset, &mytm, sp) == NULL) // android-changed: added sp.
-                    continue;
-                if (tmcomp(&mytm, &yourtm) != 0)
-                    continue;
-                if (mytm.tm_isdst != yourtm.tm_isdst)
-                    continue;
-                /*
-                ** We have a match.
-                */
-                t = newt;
-                goto label;
-            }
-        }
-        return WRONG;
-    }
+	*okayp = false;
+	yourtm = *tmp;
+	if (do_norm_secs) {
+		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
+			SECSPERMIN))
+				return WRONG;
+	}
+	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
+		return WRONG;
+	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
+		return WRONG;
+	y = yourtm.tm_year;
+	if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
+		return WRONG;
+	/*
+	** Turn y into an actual year number for now.
+	** It is converted back to an offset from TM_YEAR_BASE later.
+	*/
+	if (increment_overflow32(&y, TM_YEAR_BASE))
+		return WRONG;
+	while (yourtm.tm_mday <= 0) {
+		if (increment_overflow32(&y, -1))
+			return WRONG;
+		li = y + (1 < yourtm.tm_mon);
+		yourtm.tm_mday += year_lengths[isleap(li)];
+	}
+	while (yourtm.tm_mday > DAYSPERLYEAR) {
+		li = y + (1 < yourtm.tm_mon);
+		yourtm.tm_mday -= year_lengths[isleap(li)];
+		if (increment_overflow32(&y, 1))
+			return WRONG;
+	}
+	for ( ; ; ) {
+		i = mon_lengths[isleap(y)][yourtm.tm_mon];
+		if (yourtm.tm_mday <= i)
+			break;
+		yourtm.tm_mday -= i;
+		if (++yourtm.tm_mon >= MONSPERYEAR) {
+			yourtm.tm_mon = 0;
+			if (increment_overflow32(&y, 1))
+				return WRONG;
+		}
+	}
+	if (increment_overflow32(&y, -TM_YEAR_BASE))
+		return WRONG;
+	if (! (INT_MIN <= y && y <= INT_MAX))
+		return WRONG;
+	yourtm.tm_year = y;
+	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
+		saved_seconds = 0;
+	else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
+		/*
+		** We can't set tm_sec to 0, because that might push the
+		** time below the minimum representable time.
+		** Set tm_sec to 59 instead.
+		** This assumes that the minimum representable time is
+		** not in the same minute that a leap second was deleted from,
+		** which is a safer assumption than using 58 would be.
+		*/
+		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
+			return WRONG;
+		saved_seconds = yourtm.tm_sec;
+		yourtm.tm_sec = SECSPERMIN - 1;
+	} else {
+		saved_seconds = yourtm.tm_sec;
+		yourtm.tm_sec = 0;
+	}
+	/*
+	** Do a binary search (this works whatever time_t's type is).
+	*/
+	lo = time_t_min;
+	hi = time_t_max;
+	for ( ; ; ) {
+		t = lo / 2 + hi / 2;
+		if (t < lo)
+			t = lo;
+		else if (t > hi)
+			t = hi;
+		if (! funcp(sp, &t, offset, &mytm)) {
+			/*
+			** Assume that t is too extreme to be represented in
+			** a struct tm; arrange things so that it is less
+			** extreme on the next pass.
+			*/
+			dir = (t > 0) ? 1 : -1;
+		} else	dir = tmcomp(&mytm, &yourtm);
+		if (dir != 0) {
+			if (t == lo) {
+				if (t == time_t_max)
+					return WRONG;
+				++t;
+				++lo;
+			} else if (t == hi) {
+				if (t == time_t_min)
+					return WRONG;
+				--t;
+				--hi;
+			}
+			if (lo > hi)
+				return WRONG;
+			if (dir > 0)
+				hi = t;
+			else	lo = t;
+			continue;
+		}
+#if defined TM_GMTOFF && ! UNINIT_TRAP
+		if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
+		    && (yourtm.TM_GMTOFF < 0
+			? (-SECSPERDAY <= yourtm.TM_GMTOFF
+			   && (mytm.TM_GMTOFF <=
+			       (SMALLEST (INT_FAST32_MAX, LONG_MAX)
+				+ yourtm.TM_GMTOFF)))
+			: (yourtm.TM_GMTOFF <= SECSPERDAY
+			   && ((BIGGEST (INT_FAST32_MIN, LONG_MIN)
+				+ yourtm.TM_GMTOFF)
+			       <= mytm.TM_GMTOFF)))) {
+		  /* MYTM matches YOURTM except with the wrong UTC offset.
+		     YOURTM.TM_GMTOFF is plausible, so try it instead.
+		     It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
+		     since the guess gets checked.  */
+		  time_t altt = t;
+		  int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
+		  if (!increment_overflow_time(&altt, diff)) {
+		    struct tm alttm;
+		    if (funcp(sp, &altt, offset, &alttm)
+			&& alttm.tm_isdst == mytm.tm_isdst
+			&& alttm.TM_GMTOFF == yourtm.TM_GMTOFF
+			&& tmcomp(&alttm, &yourtm) == 0) {
+		      t = altt;
+		      mytm = alttm;
+		    }
+		  }
+		}
+#endif
+		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
+			break;
+		/*
+		** Right time, wrong type.
+		** Hunt for right time, right type.
+		** It's okay to guess wrong since the guess
+		** gets checked.
+		*/
+		if (sp == NULL)
+			return WRONG;
+		for (i = sp->typecnt - 1; i >= 0; --i) {
+			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
+				continue;
+			for (j = sp->typecnt - 1; j >= 0; --j) {
+				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
+					continue;
+				newt = t + sp->ttis[j].tt_gmtoff -
+					sp->ttis[i].tt_gmtoff;
+				if (! funcp(sp, &newt, offset, &mytm))
+					continue;
+				if (tmcomp(&mytm, &yourtm) != 0)
+					continue;
+				if (mytm.tm_isdst != yourtm.tm_isdst)
+					continue;
+				/*
+				** We have a match.
+				*/
+				t = newt;
+				goto label;
+			}
+		}
+		return WRONG;
+	}
 label:
-    newt = t + saved_seconds;
-    if ((newt < t) != (saved_seconds < 0))
-        return WRONG;
-    t = newt;
-    if ((*funcp)(&t, offset, tmp, sp)) // android-changed: added sp.
-        *okayp = TRUE;
-    return t;
+	newt = t + saved_seconds;
+	if ((newt < t) != (saved_seconds < 0))
+		return WRONG;
+	t = newt;
+	if (funcp(sp, &t, offset, tmp))
+		*okayp = true;
+	return t;
 }
 
 static time_t
-time2(struct tm * const tmp,
-      struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *, struct state *), // android-changed: added sp.
+time2(struct tm * const	tmp,
+      struct tm *(*funcp)(struct state const *, time_t const *,
+			  int_fast32_t, struct tm *),
+      struct state const *sp,
       const int_fast32_t offset,
-      int *const okayp, struct state* sp) // android-changed: added sp.
+      bool *okayp)
 {
-    time_t t;
+	time_t	t;
 
-    /*
-    ** First try without normalization of seconds
-    ** (in case tm_sec contains a value associated with a leap second).
-    ** If that fails, try with normalization of seconds.
-    */
-    t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
-    return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
+	/*
+	** First try without normalization of seconds
+	** (in case tm_sec contains a value associated with a leap second).
+	** If that fails, try with normalization of seconds.
+	*/
+	t = time2sub(tmp, funcp, sp, offset, okayp, false);
+	return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
 }
 
 static time_t
-time1(struct tm * const tmp,
-      struct tm * (* const funcp) (const time_t *, int_fast32_t, struct tm *, struct state *), // android-changed: added sp.
-      const int_fast32_t offset, struct state * sp) // android-changed: added sp.
+time1(struct tm *const tmp,
+      struct tm *(*funcp) (struct state const *, time_t const *,
+			   int_fast32_t, struct tm *),
+      struct state const *sp,
+      const int_fast32_t offset)
 {
-    register time_t t;
-    register int    samei, otheri;
-    register int    sameind, otherind;
-    register int    i;
-    register int    nseen;
-    char            seen[TZ_MAX_TYPES];
-    unsigned char   types[TZ_MAX_TYPES];
-    int             okay;
+	register time_t			t;
+	register int			samei, otheri;
+	register int			sameind, otherind;
+	register int			i;
+	register int			nseen;
+	char				seen[TZ_MAX_TYPES];
+	unsigned char			types[TZ_MAX_TYPES];
+	bool				okay;
 
-    if (tmp == NULL) {
-        errno = EINVAL;
-        return WRONG;
-    }
-    if (tmp->tm_isdst > 1)
-        tmp->tm_isdst = 1;
-    t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
-    if (okay)
-        return t;
-    if (tmp->tm_isdst < 0)
+	if (tmp == NULL) {
+		errno = EINVAL;
+		return WRONG;
+	}
+	if (tmp->tm_isdst > 1)
+		tmp->tm_isdst = 1;
+	t = time2(tmp, funcp, sp, offset, &okay);
+	if (okay)
+		return t;
+	if (tmp->tm_isdst < 0)
 #ifdef PCTS
-        /*
-        ** POSIX Conformance Test Suite code courtesy Grant Sullivan.
-        */
-        tmp->tm_isdst = 0;  /* reset to std and try again */
+		/*
+		** POSIX Conformance Test Suite code courtesy Grant Sullivan.
+		*/
+		tmp->tm_isdst = 0;	/* reset to std and try again */
 #else
-        return t;
+		return t;
 #endif /* !defined PCTS */
-    /*
-    ** We're supposed to assume that somebody took a time of one type
-    ** and did some math on it that yielded a "struct tm" that's bad.
-    ** We try to divine the type they started from and adjust to the
-    ** type they need.
-    */
-    // BEGIN android-changed: support user-supplied sp.
-    if (sp == NULL) {
-        sp = (struct state *) ((funcp == localsub) ?  lclptr : gmtptr);
-    }
-    // BEGIN android-changed
-    if (sp == NULL)
-        return WRONG;
-    for (i = 0; i < sp->typecnt; ++i)
-        seen[i] = FALSE;
-    nseen = 0;
-    for (i = sp->timecnt - 1; i >= 0; --i)
-        if (!seen[sp->types[i]]) {
-            seen[sp->types[i]] = TRUE;
-            types[nseen++] = sp->types[i];
-        }
-    for (sameind = 0; sameind < nseen; ++sameind) {
-        samei = types[sameind];
-        if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
-            continue;
-        for (otherind = 0; otherind < nseen; ++otherind) {
-            otheri = types[otherind];
-            if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
-                continue;
-            tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
-                    sp->ttis[samei].tt_gmtoff;
-            tmp->tm_isdst = !tmp->tm_isdst;
-            t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
-            if (okay)
-                return t;
-            tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
-                    sp->ttis[samei].tt_gmtoff;
-            tmp->tm_isdst = !tmp->tm_isdst;
-        }
-    }
-    return WRONG;
+	/*
+	** We're supposed to assume that somebody took a time of one type
+	** and did some math on it that yielded a "struct tm" that's bad.
+	** We try to divine the type they started from and adjust to the
+	** type they need.
+	*/
+	if (sp == NULL)
+		return WRONG;
+	for (i = 0; i < sp->typecnt; ++i)
+		seen[i] = false;
+	nseen = 0;
+	for (i = sp->timecnt - 1; i >= 0; --i)
+		if (!seen[sp->types[i]]) {
+			seen[sp->types[i]] = true;
+			types[nseen++] = sp->types[i];
+		}
+	for (sameind = 0; sameind < nseen; ++sameind) {
+		samei = types[sameind];
+		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
+			continue;
+		for (otherind = 0; otherind < nseen; ++otherind) {
+			otheri = types[otherind];
+			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
+				continue;
+			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
+					sp->ttis[samei].tt_gmtoff;
+			tmp->tm_isdst = !tmp->tm_isdst;
+			t = time2(tmp, funcp, sp, offset, &okay);
+			if (okay)
+				return t;
+			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
+					sp->ttis[samei].tt_gmtoff;
+			tmp->tm_isdst = !tmp->tm_isdst;
+		}
+	}
+	return WRONG;
 }
 
+static time_t
+mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
+{
+  if (sp)
+    return time1(tmp, localsub, sp, setname);
+  else {
+    gmtcheck();
+    return time1(tmp, gmtsub, gmtptr, 0);
+  }
+}
+
+#if NETBSD_INSPIRED
+
 time_t
-mktime(struct tm * const tmp)
+mktime_z(struct state *sp, struct tm *tmp)
 {
-    _tzLock();
-    tzset_locked();
-    time_t result = time1(tmp, localsub, 0L, NULL); // android-changed: extra parameter.
-    _tzUnlock();
-    return result;
+  return mktime_tzname(sp, tmp, false);
+}
+
+#endif
+
+time_t
+mktime(struct tm *tmp)
+{
+  time_t t;
+  int err = lock();
+  if (err) {
+    errno = err;
+    return -1;
+  }
+  tzset_unlocked();
+  t = mktime_tzname(lclptr, tmp, true);
+  unlock();
+  return t;
 }
 
 #ifdef STD_INSPIRED
 
 time_t
-timelocal(struct tm * const tmp)
+timelocal(struct tm *tmp)
 {
-    if (tmp != NULL)
-        tmp->tm_isdst = -1; /* in case it wasn't initialized */
-    return mktime(tmp);
+	if (tmp != NULL)
+		tmp->tm_isdst = -1;	/* in case it wasn't initialized */
+	return mktime(tmp);
 }
 
 time_t
-timegm(struct tm * const tmp)
+timegm(struct tm *tmp)
 {
-    time_t result;
-
-    if (tmp != NULL)
-        tmp->tm_isdst = 0;
-    _tzLock();
-    result = time1(tmp, gmtsub, 0L, NULL); // android-changed: extra parameter.
-    _tzUnlock();
-
-    return result;
+  return timeoff(tmp, 0);
 }
 
 time_t
-timeoff(struct tm *const tmp, const long offset)
+timeoff(struct tm *tmp, long offset)
 {
-    if (tmp != NULL)
-        tmp->tm_isdst = 0;
-    return time1(tmp, gmtsub, offset, NULL); // android-changed: extra parameter.
+  if (tmp)
+    tmp->tm_isdst = 0;
+  gmtcheck();
+  return time1(tmp, gmtsub, gmtptr, offset);
 }
 
 #endif /* defined STD_INSPIRED */
 
-#ifdef CMUCS
-
-/*
-** The following is supplied for compatibility with
-** previous versions of the CMUCS runtime library.
-*/
-
-long
-gtime(struct tm * const tmp)
-{
-    const time_t t = mktime(tmp);
-
-    if (t == WRONG)
-        return -1;
-    return t;
-}
-
-#endif /* defined CMUCS */
-
 /*
 ** XXX--is the below the right way to conditionalize??
 */
@@ -2059,64 +2213,105 @@
 */
 
 static int_fast64_t
-leapcorr(time_t * timep)
+leapcorr(struct state const *sp, time_t t)
 {
-    register struct state *  sp;
-    register struct lsinfo * lp;
-    register int             i;
+	register struct lsinfo const *	lp;
+	register int			i;
 
-    sp = lclptr;
-    i = sp->leapcnt;
-    while (--i >= 0) {
-        lp = &sp->lsis[i];
-        if (*timep >= lp->ls_trans)
-            return lp->ls_corr;
-    }
-    return 0;
+	i = sp->leapcnt;
+	while (--i >= 0) {
+		lp = &sp->lsis[i];
+		if (t >= lp->ls_trans)
+			return lp->ls_corr;
+	}
+	return 0;
+}
+
+NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
+time2posix_z(struct state *sp, time_t t)
+{
+  return t - leapcorr(sp, t);
 }
 
 time_t
 time2posix(time_t t)
 {
-    tzset();
-    return t - leapcorr(&t);
+  int err = lock();
+  if (err) {
+    errno = err;
+    return -1;
+  }
+  if (!lcl_is_set)
+    tzset_unlocked();
+  if (lclptr)
+    t = time2posix_z(lclptr, t);
+  unlock();
+  return t;
+}
+
+NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
+posix2time_z(struct state *sp, time_t t)
+{
+	time_t	x;
+	time_t	y;
+	/*
+	** For a positive leap second hit, the result
+	** is not unique. For a negative leap second
+	** hit, the corresponding time doesn't exist,
+	** so we return an adjacent second.
+	*/
+	x = t + leapcorr(sp, t);
+	y = x - leapcorr(sp, x);
+	if (y < t) {
+		do {
+			x++;
+			y = x - leapcorr(sp, x);
+		} while (y < t);
+		x -= y != t;
+	} else if (y > t) {
+		do {
+			--x;
+			y = x - leapcorr(sp, x);
+		} while (y > t);
+		x += y != t;
+	}
+	return x;
 }
 
 time_t
 posix2time(time_t t)
 {
-    time_t x;
-    time_t y;
-
-    tzset();
-    /*
-    ** For a positive leap second hit, the result
-    ** is not unique. For a negative leap second
-    ** hit, the corresponding time doesn't exist,
-    ** so we return an adjacent second.
-    */
-    x = t + leapcorr(&t);
-    y = x - leapcorr(&x);
-    if (y < t) {
-        do {
-            x++;
-            y = x - leapcorr(&x);
-        } while (y < t);
-        if (t != y)
-            return x - 1;
-    } else if (y > t) {
-        do {
-            --x;
-            y = x - leapcorr(&x);
-        } while (y > t);
-        if (t != y)
-            return x + 1;
-    }
-    return x;
+  int err = lock();
+  if (err) {
+    errno = err;
+    return -1;
+  }
+  if (!lcl_is_set)
+    tzset_unlocked();
+  if (lclptr)
+    t = posix2time_z(lclptr, t);
+  unlock();
+  return t;
 }
 
 #endif /* defined STD_INSPIRED */
 
+#ifdef time_tz
+
+/* Convert from the underlying system's time_t to the ersatz time_tz,
+   which is called 'time_t' in this file.  */
+
+time_t
+time(time_t *p)
+{
+  time_t r = sys_time(0);
+  if (p)
+    *p = r;
+  return r;
+}
+
+#endif
+
 // BEGIN android-added
 
 #include <assert.h>
@@ -2124,7 +2319,7 @@
 #include <arpa/inet.h> // For ntohl(3).
 
 static int __bionic_open_tzdata_path(const char* path_prefix_variable, const char* path_suffix,
-                                     const char* olson_id, int* data_size) {
+                                     const char* olson_id) {
   const char* path_prefix = getenv(path_prefix_variable);
   if (path_prefix == NULL) {
     fprintf(stderr, "%s: %s not set!\n", __FUNCTION__, path_prefix_variable);
@@ -2139,7 +2334,6 @@
   snprintf(path, path_length, "%s/%s", path_prefix, path_suffix);
   int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
   if (fd == -1) {
-    XLOG(("%s: could not open \"%s\": %s\n", __FUNCTION__, path, strerror(errno)));
     free(path);
     return -2; // Distinguish failure to find any data from failure to find a specific id.
   }
@@ -2223,7 +2417,6 @@
 
     if (strcmp(this_id, olson_id) == 0) {
       specific_zone_offset = ntohl(entry->start) + ntohl(header.data_offset);
-      *data_size = ntohl(entry->length);
       break;
     }
 
@@ -2232,7 +2425,6 @@
   free(index);
 
   if (specific_zone_offset == -1) {
-    XLOG(("%s: couldn't find zone \"%s\"\n", __FUNCTION__, olson_id));
     free(path);
     close(fd);
     return -1;
@@ -2252,10 +2444,10 @@
   return fd;
 }
 
-static int __bionic_open_tzdata(const char* olson_id, int* data_size) {
-  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata", olson_id, data_size);
+static int __bionic_open_tzdata(const char* olson_id) {
+  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata", olson_id);
   if (fd < 0) {
-    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id, data_size);
+    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id);
     if (fd == -2) {
       // The first thing that 'recovery' does is try to format the current time. It doesn't have
       // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
@@ -2267,7 +2459,7 @@
 
 // Caches the most recent timezone (http://b/8270865).
 static int __bionic_tzload_cached(const char* name, struct state* const sp, const int doextend) {
-  _tzLock();
+  lock();
 
   // Our single-item cache.
   static char* g_cached_time_zone_name;
@@ -2276,7 +2468,7 @@
   // Do we already have this timezone cached?
   if (g_cached_time_zone_name != NULL && strcmp(name, g_cached_time_zone_name) == 0) {
     *sp = g_cached_time_zone;
-    _tzUnlock();
+    unlock();
     return 0;
   }
 
@@ -2289,7 +2481,7 @@
     g_cached_time_zone = *sp;
   }
 
-  _tzUnlock();
+  unlock();
   return rc;
 }
 
@@ -2301,12 +2493,12 @@
 
   if (st == NULL)
     return 0;
-  if (__bionic_tzload_cached(tz, st, TRUE) != 0) {
+  if (__bionic_tzload_cached(tz, st, true) != 0) {
     // TODO: not sure what's best here, but for now, we fall back to gmt.
     gmtload(st);
   }
 
-  return_value = time1(tmp, localsub, 0L, st);
+  return_value = time1(tmp, localsub, st, 0L);
   free(st);
   return return_value;
 }
diff --git a/libc/tzcode/private.h b/libc/tzcode/private.h
index c30c711..1c176e6 100644
--- a/libc/tzcode/private.h
+++ b/libc/tzcode/private.h
@@ -19,13 +19,9 @@
 
 /*
 ** Defaults for preprocessor symbols.
-** You can override these in your C compiler options, e.g. '-DHAVE_ADJTIME=0'.
+** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'.
 */
 
-#ifndef HAVE_ADJTIME
-#define HAVE_ADJTIME		1
-#endif /* !defined HAVE_ADJTIME */
-
 #ifndef HAVE_GETTEXT
 #define HAVE_GETTEXT		0
 #endif /* !defined HAVE_GETTEXT */
@@ -38,9 +34,9 @@
 #define HAVE_LINK		1
 #endif /* !defined HAVE_LINK */
 
-#ifndef HAVE_SETTIMEOFDAY
-#define HAVE_SETTIMEOFDAY	3
-#endif /* !defined HAVE_SETTIMEOFDAY */
+#ifndef HAVE_STRDUP
+#define HAVE_STRDUP 1
+#endif
 
 #ifndef HAVE_SYMLINK
 #define HAVE_SYMLINK		1
@@ -59,32 +55,61 @@
 #endif /* !defined HAVE_UNISTD_H */
 
 #ifndef HAVE_UTMPX_H
-#define HAVE_UTMPX_H		0
+#define HAVE_UTMPX_H		1
 #endif /* !defined HAVE_UTMPX_H */
 
-#if !defined(__ANDROID__)
-#ifndef LOCALE_HOME
-#define LOCALE_HOME		"/usr/lib/locale"
-#endif /* !defined LOCALE_HOME */
-#endif // __ANDROID__
+#ifndef NETBSD_INSPIRED
+# define NETBSD_INSPIRED 1
+#endif
 
 #if HAVE_INCOMPATIBLE_CTIME_R
 #define asctime_r _incompatible_asctime_r
 #define ctime_r _incompatible_ctime_r
 #endif /* HAVE_INCOMPATIBLE_CTIME_R */
 
+/* Enable tm_gmtoff and tm_zone on GNUish systems.  */
+#define _GNU_SOURCE 1
+/* Fix asctime_r on Solaris 10.  */
+#define _POSIX_PTHREAD_SEMANTICS 1
+/* Enable strtoimax on Solaris 10.  */
+#define __EXTENSIONS__ 1
+
 /*
 ** Nested includes
 */
 
+/* Avoid clashes with NetBSD by renaming NetBSD's declarations.  */
+#define localtime_rz sys_localtime_rz
+#define mktime_z sys_mktime_z
+#define posix2time_z sys_posix2time_z
+#define time2posix_z sys_time2posix_z
+#define timezone_t sys_timezone_t
+#define tzalloc sys_tzalloc
+#define tzfree sys_tzfree
+#include <time.h>
+#undef localtime_rz
+#undef mktime_z
+#undef posix2time_z
+#undef time2posix_z
+#undef timezone_t
+#undef tzalloc
+#undef tzfree
+
 #include "sys/types.h"	/* for time_t */
 #include "stdio.h"
-#include "errno.h"
 #include "string.h"
 #include "limits.h"	/* for CHAR_BIT et al. */
-#include "time.h"
 #include "stdlib.h"
 
+#include "errno.h"
+
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG EINVAL
+#endif
+#ifndef EOVERFLOW
+# define EOVERFLOW EINVAL
+#endif
+
 #if HAVE_GETTEXT
 #include "libintl.h"
 #endif /* HAVE_GETTEXT */
@@ -104,6 +129,14 @@
 #include "unistd.h"	/* for F_OK, R_OK, and other POSIX goodness */
 #endif /* HAVE_UNISTD_H */
 
+#ifndef HAVE_STRFTIME_L
+# if _POSIX_VERSION < 200809
+#  define HAVE_STRFTIME_L 0
+# else
+#  define HAVE_STRFTIME_L 1
+# endif
+#endif
+
 #ifndef F_OK
 #define F_OK	0
 #endif /* !defined F_OK */
@@ -138,65 +171,98 @@
 # include <inttypes.h>
 #endif
 
-#ifndef INT_FAST64_MAX
 /* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX.  */
-#if defined LLONG_MAX || defined __LONG_LONG_MAX__
-typedef long long	int_fast64_t;
+#ifdef __LONG_LONG_MAX__
+# ifndef LLONG_MAX
+#  define LLONG_MAX __LONG_LONG_MAX__
+# endif
+# ifndef LLONG_MIN
+#  define LLONG_MIN (-1 - LLONG_MAX)
+# endif
+#endif
+
+#ifndef INT_FAST64_MAX
 # ifdef LLONG_MAX
+typedef long long	int_fast64_t;
 #  define INT_FAST64_MIN LLONG_MIN
 #  define INT_FAST64_MAX LLONG_MAX
 # else
-#  define INT_FAST64_MIN __LONG_LONG_MIN__
-#  define INT_FAST64_MAX __LONG_LONG_MAX__
-# endif
-# define SCNdFAST64 "lld"
-#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
-#if (LONG_MAX >> 31) < 0xffffffff
+#  if LONG_MAX >> 31 < 0xffffffff
 Please use a compiler that supports a 64-bit integer type (or wider);
 you may need to compile with "-DHAVE_STDINT_H".
-#endif /* (LONG_MAX >> 31) < 0xffffffff */
+#  endif
 typedef long		int_fast64_t;
-# define INT_FAST64_MIN LONG_MIN
-# define INT_FAST64_MAX LONG_MAX
-# define SCNdFAST64 "ld"
-#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
-#endif /* !defined INT_FAST64_MAX */
+#  define INT_FAST64_MIN LONG_MIN
+#  define INT_FAST64_MAX LONG_MAX
+# endif
+#endif
+
+#ifndef SCNdFAST64
+# if INT_FAST64_MAX == LLONG_MAX
+#  define SCNdFAST64 "lld"
+# else
+#  define SCNdFAST64 "ld"
+# endif
+#endif
 
 #ifndef INT_FAST32_MAX
 # if INT_MAX >> 31 == 0
 typedef long int_fast32_t;
+#  define INT_FAST32_MAX LONG_MAX
+#  define INT_FAST32_MIN LONG_MIN
 # else
 typedef int int_fast32_t;
+#  define INT_FAST32_MAX INT_MAX
+#  define INT_FAST32_MIN INT_MIN
 # endif
 #endif
 
 #ifndef INTMAX_MAX
-# if defined LLONG_MAX || defined __LONG_LONG_MAX__
+# ifdef LLONG_MAX
 typedef long long intmax_t;
 #  define strtoimax strtoll
-#  define PRIdMAX "lld"
-#  ifdef LLONG_MAX
-#   define INTMAX_MAX LLONG_MAX
-#   define INTMAX_MIN LLONG_MIN
-#  else
-#   define INTMAX_MAX __LONG_LONG_MAX__
-#   define INTMAX_MIN __LONG_LONG_MIN__
-#  endif
+#  define INTMAX_MAX LLONG_MAX
+#  define INTMAX_MIN LLONG_MIN
 # else
 typedef long intmax_t;
 #  define strtoimax strtol
-#  define PRIdMAX "ld"
 #  define INTMAX_MAX LONG_MAX
 #  define INTMAX_MIN LONG_MIN
 # endif
 #endif
 
+#ifndef PRIdMAX
+# if INTMAX_MAX == LLONG_MAX
+#  define PRIdMAX "lld"
+# else
+#  define PRIdMAX "ld"
+# endif
+#endif
+
+#ifndef UINT_FAST64_MAX
+# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
+typedef unsigned long long uint_fast64_t;
+# else
+#  if ULONG_MAX >> 31 >> 1 < 0xffffffff
+Please use a compiler that supports a 64-bit integer type (or wider);
+you may need to compile with "-DHAVE_STDINT_H".
+#  endif
+typedef unsigned long	uint_fast64_t;
+# endif
+#endif
+
 #ifndef UINTMAX_MAX
 # if defined ULLONG_MAX || defined __LONG_LONG_MAX__
 typedef unsigned long long uintmax_t;
-#  define PRIuMAX "llu"
 # else
 typedef unsigned long uintmax_t;
+# endif
+#endif
+
+#ifndef PRIuMAX
+# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
+#  define PRIuMAX "llu"
+# else
 #  define PRIuMAX "lu"
 # endif
 #endif
@@ -239,16 +305,6 @@
 */
 
 /*
-** Some time.h implementations don't declare asctime_r.
-** Others might define it as a macro.
-** Fix the former without affecting the latter.
-*/
-
-#ifndef asctime_r
-extern char *	asctime_r(struct tm const *, char *);
-#endif
-
-/*
 ** Compile with -Dtime_tz=T to build the tz package with a private
 ** time_t type equivalent to T rather than the system-supplied time_t.
 ** This debugging feature can test unusual design decisions
@@ -256,7 +312,11 @@
 ** typical platforms.
 */
 #ifdef time_tz
+# ifdef LOCALTIME_IMPLEMENTATION
 static time_t sys_time(time_t *x) { return time(x); }
+# endif
+
+typedef time_tz tz_time_t;
 
 # undef  ctime
 # define ctime tz_ctime
@@ -272,14 +332,40 @@
 # define localtime tz_localtime
 # undef  localtime_r
 # define localtime_r tz_localtime_r
+# undef  localtime_rz
+# define localtime_rz tz_localtime_rz
 # undef  mktime
 # define mktime tz_mktime
+# undef  mktime_z
+# define mktime_z tz_mktime_z
+# undef  offtime
+# define offtime tz_offtime
+# undef  posix2time
+# define posix2time tz_posix2time
+# undef  posix2time_z
+# define posix2time_z tz_posix2time_z
 # undef  time
 # define time tz_time
+# undef  time2posix
+# define time2posix tz_time2posix
+# undef  time2posix_z
+# define time2posix_z tz_time2posix_z
 # undef  time_t
 # define time_t tz_time_t
-
-typedef time_tz time_t;
+# undef  timegm
+# define timegm tz_timegm
+# undef  timelocal
+# define timelocal tz_timelocal
+# undef  timeoff
+# define timeoff tz_timeoff
+# undef  tzalloc
+# define tzalloc tz_tzalloc
+# undef  tzfree
+# define tzfree tz_tzfree
+# undef  tzset
+# define tzset tz_tzset
+# undef  tzsetwall
+# define tzsetwall tz_tzsetwall
 
 char *ctime(time_t const *);
 char *ctime_r(time_t const *, char *);
@@ -289,36 +375,111 @@
 struct tm *localtime(time_t const *);
 struct tm *localtime_r(time_t const *restrict, struct tm *restrict);
 time_t mktime(struct tm *);
-
-static time_t
-time(time_t *p)
-{
-	time_t r = sys_time(0);
-	if (p)
-		*p = r;
-	return r;
-}
+time_t time(time_t *);
+void tzset(void);
 #endif
 
 /*
-** Private function declarations.
+** Some time.h implementations don't declare asctime_r.
+** Others might define it as a macro.
+** Fix the former without affecting the latter.
+** Similarly for timezone, daylight, and altzone.
 */
 
-char *		icatalloc(char * old, const char * new);
-char *		icpyalloc(const char * string);
-const char *	scheck(const char * string, const char * format);
+#ifndef asctime_r
+extern char *	asctime_r(struct tm const *restrict, char *restrict);
+#endif
+
+#ifdef USG_COMPAT
+# ifndef timezone
+extern long timezone;
+# endif
+# ifndef daylight
+extern int daylight;
+# endif
+#endif
+#if defined ALTZONE && !defined altzone
+extern long altzone;
+#endif
+
+/*
+** The STD_INSPIRED functions are similar, but most also need
+** declarations if time_tz is defined.
+*/
+
+#ifdef STD_INSPIRED
+# if !defined tzsetwall || defined time_tz
+void tzsetwall(void);
+# endif
+# if !defined offtime || defined time_tz
+struct tm *offtime(time_t const *, long);
+# endif
+# if !defined timegm || defined time_tz
+time_t timegm(struct tm *);
+# endif
+# if !defined timelocal || defined time_tz
+time_t timelocal(struct tm *);
+# endif
+# if !defined timeoff || defined time_tz
+time_t timeoff(struct tm *, long);
+# endif
+# if !defined time2posix || defined time_tz
+time_t time2posix(time_t);
+# endif
+# if !defined posix2time || defined time_tz
+time_t posix2time(time_t);
+# endif
+#endif
+
+/* Infer TM_ZONE on systems where this information is known, but suppress
+   guessing if NO_TM_ZONE is defined.  Similarly for TM_GMTOFF.  */
+#if (defined __GLIBC__ \
+     || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
+     || (defined __APPLE__ && defined __MACH__))
+# if !defined TM_GMTOFF && !defined NO_TM_GMTOFF
+#  define TM_GMTOFF tm_gmtoff
+# endif
+# if !defined TM_ZONE && !defined NO_TM_ZONE
+#  define TM_ZONE tm_zone
+# endif
+#endif
+
+/*
+** Define functions that are ABI compatible with NetBSD but have
+** better prototypes.  NetBSD 6.1.4 defines a pointer type timezone_t
+** and labors under the misconception that 'const timezone_t' is a
+** pointer to a constant.  This use of 'const' is ineffective, so it
+** is not done here.  What we call 'struct state' NetBSD calls
+** 'struct __state', but this is a private name so it doesn't matter.
+*/
+#if NETBSD_INSPIRED
+typedef struct state *timezone_t;
+struct tm *localtime_rz(timezone_t restrict, time_t const *restrict,
+			struct tm *restrict);
+time_t mktime_z(timezone_t restrict, struct tm *restrict);
+timezone_t tzalloc(char const *);
+void tzfree(timezone_t);
+# ifdef STD_INSPIRED
+#  if !defined posix2time_z || defined time_tz
+time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_PURE;
+#  endif
+#  if !defined time2posix_z || defined time_tz
+time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
+#  endif
+# endif
+#endif
 
 /*
 ** Finally, some convenience items.
 */
 
-#ifndef TRUE
-#define TRUE	1
-#endif /* !defined TRUE */
-
-#ifndef FALSE
-#define FALSE	0
-#endif /* !defined FALSE */
+#if __STDC_VERSION__ < 199901
+# define true 1
+# define false 0
+# define bool int
+#else
+# include <stdbool.h>
+#endif
 
 #ifndef TYPE_BIT
 #define TYPE_BIT(type)	(sizeof (type) * CHAR_BIT)
@@ -328,15 +489,20 @@
 #define TYPE_SIGNED(type) (((type) -1) < 0)
 #endif /* !defined TYPE_SIGNED */
 
-/* The minimum and maximum finite time values.  */
-static time_t const time_t_min =
-  (TYPE_SIGNED(time_t)
-   ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
-   : 0);
-static time_t const time_t_max =
-  (TYPE_SIGNED(time_t)
-   ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
-   : -1);
+#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
+
+/* Max and min values of the integer type T, of which only the bottom
+   B bits are used, and where the highest-order used bit is considered
+   to be a sign bit if T is signed.  */
+#define MAXVAL(t, b)						\
+  ((t) (((t) 1 << ((b) - 1 - TYPE_SIGNED(t)))			\
+	- 1 + ((t) 1 << ((b) - 1 - TYPE_SIGNED(t)))))
+#define MINVAL(t, b)						\
+  ((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0))
+
+/* The minimum and maximum finite time values.  This assumes no padding.  */
+static time_t const time_t_min = MINVAL(time_t, TYPE_BIT(time_t));
+static time_t const time_t_max = MAXVAL(time_t, TYPE_BIT(time_t));
 
 #ifndef INT_STRLEN_MAXIMUM
 /*
@@ -360,6 +526,10 @@
 # define INITIALIZE(x)
 #endif
 
+#ifndef UNINIT_TRAP
+# define UNINIT_TRAP 0
+#endif
+
 /*
 ** For the benefit of GNU folk...
 ** '_(MSGID)' uses the current locale's message library string for MSGID.
@@ -374,7 +544,7 @@
 #endif /* !HAVE_GETTEXT */
 #endif /* !defined _ */
 
-#if !defined TZ_DOMAIN && defined TZ_DOMAINDIR
+#if !defined TZ_DOMAIN && defined HAVE_GETTEXT
 # define TZ_DOMAIN "tz"
 #endif
 
@@ -405,8 +575,4 @@
 #define SECSPERREPEAT_BITS	34	/* ceil(log2(SECSPERREPEAT)) */
 #endif /* !defined SECSPERREPEAT_BITS */
 
-/*
-** UNIX was a registered trademark of The Open Group in 2003.
-*/
-
 #endif /* !defined PRIVATE_H */
diff --git a/libc/tzcode/strftime.c b/libc/tzcode/strftime.c
index 4328b4c..10dfb4b 100644
--- a/libc/tzcode/strftime.c
+++ b/libc/tzcode/strftime.c
@@ -55,15 +55,7 @@
     const char *    date_fmt;
 };
 
-#ifdef LOCALE_HOME
-#include "sys/stat.h"
-static struct lc_time_T                localebuf;
-static struct lc_time_T *      _loc(void);
-#define Locale _loc()
-#endif /* defined LOCALE_HOME */
-#ifndef LOCALE_HOME
 #define Locale  (&C_time_locale)
-#endif /* !defined LOCALE_HOME */
 
 static const struct lc_time_T   C_time_locale = {
     {
@@ -115,7 +107,7 @@
 static char *   _conv(int, const char *, char *, const char *);
 static char *   _fmt(const char *, const struct tm *, char *, const char *,
             int *);
-static char *   _yconv(int, int, int, int, char *, const char *, int);
+static char *   _yconv(int, int, bool, bool, char *, const char *, int);
 static char *   getformat(int, char *, char *, char *, char *);
 
 extern char *   tzname[];
@@ -132,32 +124,28 @@
 #define FORCE_LOWER_CASE 0x100
 
 size_t
-strftime(char * const s, const size_t maxsize, const char *const format,
-        const struct tm *const t)
+strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
 {
     char *  p;
     int warn;
 
     tzset();
-#ifdef LOCALE_HOME
-    localebuf.mon[0] = 0;
-#endif /* defined LOCALE_HOME */
     warn = IN_NONE;
     p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
 #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
     if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
-        (void) fprintf(stderr, "\n");
+        fprintf(stderr, "\n");
         if (format == NULL)
-            (void) fprintf(stderr, "NULL strftime format ");
-        else    (void) fprintf(stderr, "strftime format \"%s\" ",
+            fprintf(stderr, "NULL strftime format ");
+        else    fprintf(stderr, "strftime format \"%s\" ",
                 format);
-        (void) fprintf(stderr, "yields only two digits of years in ");
+        fprintf(stderr, "yields only two digits of years in ");
         if (warn == IN_SOME)
-            (void) fprintf(stderr, "some locales");
+            fprintf(stderr, "some locales");
         else if (warn == IN_THIS)
-            (void) fprintf(stderr, "the current locale");
-        else    (void) fprintf(stderr, "all locales");
-        (void) fprintf(stderr, "\n");
+            fprintf(stderr, "the current locale");
+        else    fprintf(stderr, "all locales");
+        fprintf(stderr, "\n");
     }
 #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
     if (p == s + maxsize)
@@ -171,20 +159,17 @@
     switch (modifier) {
     case '_':
         return underscore;
-
     case '-':
         return dash;
-
     case '0':
         return zero;
     }
-
     return normal;
 }
 
 static char *
-_fmt(const char *format, const struct tm *const t, char * pt,
-        const char *const ptlim, int *warnp)
+_fmt(const char *format, const struct tm *t, char *pt,
+        const char *ptlim, int *warnp)
 {
     for ( ; *format; ++format) {
         if (*format == '%') {
@@ -227,8 +212,8 @@
                 ** something completely different.
                 ** (ado, 1993-05-24)
                 */
-                pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
-                    pt, ptlim, modifier);
+                pt = _yconv(t->tm_year, TM_YEAR_BASE,
+                    true, false, pt, ptlim, modifier);
                 continue;
             case 'c':
                 {
@@ -245,10 +230,7 @@
                                 pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
                 continue;
             case 'd':
-                                pt = _conv(t->tm_mday,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                                pt = _conv(t->tm_mday, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'E':
             case 'O':
@@ -270,31 +252,21 @@
                 modifier = *format;
                 goto label;
             case 'e':
-                pt = _conv(t->tm_mday,
-                                           getformat(modifier, "%2d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_mday, getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'F':
                 pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
                 continue;
             case 'H':
-                pt = _conv(t->tm_hour,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_hour, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'I':
                 pt = _conv((t->tm_hour % 12) ?
                     (t->tm_hour % 12) : 12,
-                    getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
+                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'j':
-                pt = _conv(t->tm_yday + 1,
-                           getformat(modifier, "%03d", "%3d", "%d", "%03d"),
-                           pt, ptlim);
+                pt = _conv(t->tm_yday + 1, getformat(modifier, "%03d", "%3d", "%d", "%03d"), pt, ptlim);
                 continue;
             case 'k':
                 /*
@@ -307,10 +279,7 @@
                 ** "%l" have been swapped.
                 ** (ado, 1993-05-24)
                 */
-                pt = _conv(t->tm_hour,
-                                           getformat(modifier, "%2d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_hour, getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
 #ifdef KITCHEN_SINK
             case 'K':
@@ -332,36 +301,23 @@
                 */
                 pt = _conv((t->tm_hour % 12) ?
                     (t->tm_hour % 12) : 12,
-                    getformat(modifier, "%2d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
+                    getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'M':
-                pt = _conv(t->tm_min,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_min, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'm':
-                pt = _conv(t->tm_mon + 1,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_mon + 1, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'n':
                 pt = _add("\n", pt, ptlim, modifier);
                 continue;
+            case 'P':
             case 'p':
                 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
                     Locale->pm :
                     Locale->am,
-                    pt, ptlim, modifier);
-                continue;
-            case 'P':
-                pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
-                    Locale->pm :
-                    Locale->am,
-                    pt, ptlim, FORCE_LOWER_CASE);
+                    pt, ptlim, (*format == 'P') ? FORCE_LOWER_CASE : modifier);
                 continue;
             case 'R':
                 pt = _fmt("%H:%M", t, pt, ptlim, warnp);
@@ -370,10 +326,7 @@
                 pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
                 continue;
             case 'S':
-                pt = _conv(t->tm_sec,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_sec, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 's':
                 {
@@ -385,10 +338,10 @@
                     tm = *t;
                     mkt = mktime64(&tm);
                     if (TYPE_SIGNED(time64_t))
-                        (void) snprintf(buf, sizeof(buf), "%lld",
-                            (long long) mkt);
-                    else    (void) snprintf(buf, sizeof(buf), "%llu",
-                            (unsigned long long) mkt);
+                        snprintf(buf, sizeof(buf), "%"PRIdMAX,
+                                 (intmax_t) mkt);
+                    else    snprintf(buf, sizeof(buf), "%"PRIuMAX,
+                                     (uintmax_t) mkt);
                     pt = _add(buf, pt, ptlim, modifier);
                 }
                 continue;
@@ -401,9 +354,7 @@
             case 'U':
                 pt = _conv((t->tm_yday + DAYSPERWEEK -
                     t->tm_wday) / DAYSPERWEEK,
-                    getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
+                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'u':
                 /*
@@ -413,7 +364,8 @@
                 ** (ado, 1993-05-24)
                 */
                 pt = _conv((t->tm_wday == 0) ?
-                    DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim);
+                    DAYSPERWEEK : t->tm_wday,
+                    "%d", pt, ptlim);
                 continue;
             case 'V':   /* ISO 8601 week number */
             case 'G':   /* ISO 8601 year (four digits) */
@@ -493,14 +445,15 @@
                             w = 53;
 #endif /* defined XPG4_1994_04_09 */
                     if (*format == 'V')
-                        pt = _conv(w,
-                                getformat(modifier, "%02d", "%2d", "%d", "%02d"),
+                        pt = _conv(w, getformat(modifier, "%02d", "%2d", "%d", "%02d"),
                                pt, ptlim);
                     else if (*format == 'g') {
                         *warnp = IN_ALL;
-                        pt = _yconv(year, base, 0, 1,
+                        pt = _yconv(year, base,
+                            false, true,
                             pt, ptlim, modifier);
-                    } else  pt = _yconv(year, base, 1, 1,
+                    } else  pt = _yconv(year, base,
+                            true, true,
                             pt, ptlim, modifier);
                 }
                 continue;
@@ -517,9 +470,7 @@
                     (t->tm_wday ?
                     (t->tm_wday - 1) :
                     (DAYSPERWEEK - 1))) / DAYSPERWEEK,
-                    getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
+                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'w':
                 pt = _conv(t->tm_wday, "%d", pt, ptlim);
@@ -540,23 +491,23 @@
                 continue;
             case 'y':
                 *warnp = IN_ALL;
-                pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
+                pt = _yconv(t->tm_year, TM_YEAR_BASE,
+                    false, true,
                     pt, ptlim, modifier);
                 continue;
             case 'Y':
-                pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
+                pt = _yconv(t->tm_year, TM_YEAR_BASE,
+                    true, true,
                     pt, ptlim, modifier);
                 continue;
             case 'Z':
 #ifdef TM_ZONE
-                if (t->TM_ZONE != NULL)
-                    pt = _add(t->TM_ZONE, pt, ptlim,
-                                                  modifier);
-                else
-#endif /* defined TM_ZONE */
+                pt = _add(t->TM_ZONE, pt, ptlim, modifier);
+#else
                 if (t->tm_isdst >= 0)
                     pt = _add(tzname[t->tm_isdst != 0],
-                        pt, ptlim, modifier);
+                        pt, ptlim);
+#endif
                 /*
                 ** C99 says that %Z must be replaced by the
                 ** empty string if the time zone is not
@@ -613,10 +564,7 @@
                 diff /= SECSPERMIN;
                 diff = (diff / MINSPERHOUR) * 100 +
                     (diff % MINSPERHOUR);
-                pt = _conv(diff,
-                                           getformat(modifier, "%04d",
-                                                     "%4d", "%d", "%04d"),
-                                           pt, ptlim);
+                pt = _conv(diff, getformat(modifier, "%04d", "%4d", "%d", "%04d"), pt, ptlim);
                 }
                 continue;
             case '+':
@@ -641,13 +589,12 @@
 }
 
 static char *
-_conv(const int n, const char *const format, char *const pt,
-        const char *const ptlim)
+_conv(int n, const char *format, char *pt, const char *ptlim)
 {
-    char    buf[INT_STRLEN_MAXIMUM(int) + 1];
+	char	buf[INT_STRLEN_MAXIMUM(int) + 1];
 
-    (void) snprintf(buf, sizeof(buf), format, n);
-    return _add(buf, pt, ptlim, 0);
+	snprintf(buf, sizeof(buf), format, n);
+	return _add(buf, pt, ptlim, 0);
 }
 
 static char *
@@ -699,8 +646,8 @@
 */
 
 static char *
-_yconv(const int a, const int b, const int convert_top, const int convert_yy,
-        char *pt, const char *const ptlim, int modifier)
+_yconv(int a, int b, bool convert_top, bool convert_yy,
+       char *pt, const char *ptlim, int modifier)
 {
     register int    lead;
     register int    trail;
diff --git a/libc/tzcode/tzfile.h b/libc/tzcode/tzfile.h
index 529650d..ebecd68 100644
--- a/libc/tzcode/tzfile.h
+++ b/libc/tzcode/tzfile.h
@@ -40,7 +40,7 @@
 struct tzhead {
 	char	tzh_magic[4];		/* TZ_MAGIC */
 	char	tzh_version[1];		/* '\0' or '2' or '3' as of 2013 */
-	char	tzh_reserved[15];	/* reserved--must be zero */
+	char	tzh_reserved[15];	/* reserved; must be zero */
 	char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
 	char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
 	char	tzh_leapcnt[4];		/* coded number of leap seconds */
@@ -62,13 +62,13 @@
 **	tzh_leapcnt repetitions of
 **		one (char [4])		coded leap second transition times
 **		one (char [4])		total correction after above
-**	tzh_ttisstdcnt (char)s		indexed by type; if TRUE, transition
-**					time is standard time, if FALSE,
+**	tzh_ttisstdcnt (char)s		indexed by type; if 1, transition
+**					time is standard time, if 0,
 **					transition time is wall clock time
 **					if absent, transition times are
 **					assumed to be wall clock time
-**	tzh_ttisgmtcnt (char)s		indexed by type; if TRUE, transition
-**					time is UT, if FALSE,
+**	tzh_ttisgmtcnt (char)s		indexed by type; if 1, transition
+**					time is UT, if 0,
 **					transition time is local time
 **					if absent, transition times are
 **					assumed to be local time
@@ -97,7 +97,7 @@
 */
 
 #ifndef TZ_MAX_TIMES
-#define TZ_MAX_TIMES	1200
+#define TZ_MAX_TIMES	2000
 #endif /* !defined TZ_MAX_TIMES */
 
 #ifndef TZ_MAX_TYPES
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/imaxabs.c b/libc/upstream-freebsd/lib/libc/stdlib/imaxabs.c
deleted file mode 100644
index 35e3dee..0000000
--- a/libc/upstream-freebsd/lib/libc/stdlib/imaxabs.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-
- * Copyright (c) 2001 Mike Barcroft <mike@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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <inttypes.h>
-
-intmax_t
-imaxabs(intmax_t j)
-{
-	return (j < 0 ? -j : j);
-}
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/imaxdiv.c b/libc/upstream-freebsd/lib/libc/stdlib/imaxdiv.c
deleted file mode 100644
index 7dae467..0000000
--- a/libc/upstream-freebsd/lib/libc/stdlib/imaxdiv.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*-
- * Copyright (c) 2001 Mike Barcroft <mike@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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <inttypes.h>
-
-/* See comments in div.c for implementation details. */
-imaxdiv_t
-imaxdiv(intmax_t numer, intmax_t denom)
-{
-	imaxdiv_t retval;
-
-	retval.quot = numer / denom;
-	retval.rem = numer % denom;
-	if (numer >= 0 && retval.rem < 0) {
-		retval.quot++;
-		retval.rem -= denom;
-	}
-	return (retval);
-}
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/labs.c b/libc/upstream-freebsd/lib/libc/stdlib/labs.c
deleted file mode 100644
index 816370e..0000000
--- a/libc/upstream-freebsd/lib/libc/stdlib/labs.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*-
- * Copyright (c) 1990, 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)labs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <stdlib.h>
-
-long
-labs(j)
-	long j;
-{
-	return(j < 0 ? -j : j);
-}
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/llabs.c b/libc/upstream-freebsd/lib/libc/stdlib/llabs.c
deleted file mode 100644
index 2bfbada..0000000
--- a/libc/upstream-freebsd/lib/libc/stdlib/llabs.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-
- * Copyright (c) 2001 Mike Barcroft <mike@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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <stdlib.h>
-
-long long
-llabs(long long j)
-{
-	return (j < 0 ? -j : j);
-}
diff --git a/libc/upstream-netbsd/android/include/netbsd-compat.h b/libc/upstream-netbsd/android/include/netbsd-compat.h
index 04bc728..0212d16 100644
--- a/libc/upstream-netbsd/android/include/netbsd-compat.h
+++ b/libc/upstream-netbsd/android/include/netbsd-compat.h
@@ -31,4 +31,7 @@
 #define __readlockenv() 0
 #define __unlockenv() 0
 
+#include <stddef.h>
+int reallocarr(void*, size_t, size_t);
+
 #endif
diff --git a/libc/upstream-netbsd/lib/libc/regex/regcomp.c b/libc/upstream-netbsd/lib/libc/regex/regcomp.c
index 2644a22..6af9734 100644
--- a/libc/upstream-netbsd/lib/libc/regex/regcomp.c
+++ b/libc/upstream-netbsd/lib/libc/regex/regcomp.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: regcomp.c,v 1.33 2012/03/13 21:13:43 christos Exp $	*/
+/*	$NetBSD: regcomp.c,v 1.36 2015/09/12 19:08:47 christos Exp $	*/
 
 /*-
  * Copyright (c) 1992, 1993, 1994
@@ -76,7 +76,7 @@
 #if 0
 static char sccsid[] = "@(#)regcomp.c	8.5 (Berkeley) 3/20/94";
 #else
-__RCSID("$NetBSD: regcomp.c,v 1.33 2012/03/13 21:13:43 christos Exp $");
+__RCSID("$NetBSD: regcomp.c,v 1.36 2015/09/12 19:08:47 christos Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -262,12 +262,11 @@
 		len = strlen(pattern);
 
 	/* do the mallocs early so failure handling is easy */
-	g = (struct re_guts *)malloc(sizeof(struct re_guts) +
-							(NC-1)*sizeof(cat_t));
+	g = malloc(sizeof(struct re_guts) + (NC - 1) * sizeof(cat_t));
 	if (g == NULL)
 		return(REG_ESPACE);
 	p->ssize = len/(size_t)2*(size_t)3 + (size_t)1;	/* ugh */
-	p->strip = malloc(p->ssize * sizeof(sop));
+	p->strip = calloc(p->ssize, sizeof(sop));
 	p->slen = 0;
 	if (p->strip == NULL) {
 		free(g);
@@ -1075,19 +1074,19 @@
     int ch)
 {
 	cat_t *cap;
+	unsigned char uc = (unsigned char)ch;
 
 	_DIAGASSERT(p != NULL);
 
 	cap = p->g->categories;
-	if ((p->g->cflags&REG_ICASE) && isalpha((unsigned char) ch)
-	    && othercase((unsigned char) ch) != (unsigned char) ch)
-		bothcases(p, (unsigned char) ch);
+	if ((p->g->cflags & REG_ICASE) && isalpha(uc) && othercase(uc) != uc)
+		bothcases(p, uc);
 	else {
-		EMIT(OCHAR, (sopno)(unsigned char)ch);
-		if (cap[ch] == 0) {
+		EMIT(OCHAR, (sopno)uc);
+		if (cap[uc] == 0) {
 			_DIAGASSERT(__type_fit(unsigned char,
 			    p->g->ncategories + 1));
-			cap[ch] = (unsigned char)p->g->ncategories++;
+			cap[uc] = (unsigned char)p->g->ncategories++;
 		}
 	}
 }
@@ -1236,6 +1235,7 @@
 	cset *cs;
 	size_t css;
 	size_t i;
+	void *old_ptr;
 
 	_DIAGASSERT(p != NULL);
 
@@ -1248,28 +1248,18 @@
 		nbytes = nc / CHAR_BIT * css;
 		if (MEMSIZE(p) > MEMLIMIT)
 			goto oomem;
-		if (p->g->sets == NULL)
-			p->g->sets = malloc(nc * sizeof(cset));
-		else
-			p->g->sets = realloc(p->g->sets, nc * sizeof(cset));
-		if (p->g->setbits == NULL)
-			p->g->setbits = malloc(nbytes);
-		else {
-			p->g->setbits = realloc(p->g->setbits, nbytes);
-			/* xxx this isn't right if setbits is now NULL */
+		if (reallocarr(&p->g->sets, nc, sizeof(cset)))
+			goto oomem;
+		old_ptr = p->g->setbits;
+		if (reallocarr(&p->g->setbits, nc / CHAR_BIT, css)) {
+			free(old_ptr);
+			goto oomem;
+		}
+		if (old_ptr != p->g->setbits) {
 			for (i = 0; i < no; i++)
 				p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
 		}
-		if (p->g->sets != NULL && p->g->setbits != NULL)
-			(void) memset((char *)p->g->setbits + (nbytes - css),
-								0, css);
-		else {
-oomem:
-			no = 0;
-			SETERROR(REG_ESPACE);
-			/* caller's responsibility not to do set ops */
-			return NULL;
-		}
+		(void) memset((char *)p->g->setbits + (nbytes - css), 0, css);
 	}
 
 	cs = &p->g->sets[no];
@@ -1280,6 +1270,11 @@
 	cs->multis = NULL;
 
 	return(cs);
+
+oomem:
+	SETERROR(REG_ESPACE);
+	/* caller's responsibility not to do set ops */
+	return NULL;
 }
 
 /*
@@ -1763,30 +1758,18 @@
  == static void enlarge(struct parse *p, sopno size);
  */
 static int
-enlarge(
-    struct parse *p,
-    sopno size)
+enlarge(struct parse *p, sopno size)
 {
-	sop *sp;
-	sopno osize;
-
 	_DIAGASSERT(p != NULL);
 
 	if (p->ssize >= size)
 		return 1;
 
-	osize = p->ssize;
-	p->ssize = size;
-	if (MEMSIZE(p) > MEMLIMIT)
-		goto oomem;
-	sp = realloc(p->strip, p->ssize * sizeof(sop));
-	if (sp == NULL) {
-oomem:
-		p->ssize = osize;
+	if (MEMSIZE(p) > MEMLIMIT || reallocarr(&p->strip, size, sizeof(sop))) {
 		SETERROR(REG_ESPACE);
 		return 0;
 	}
-	p->strip = sp;
+	p->ssize = size;
 	return 1;
 }
 
@@ -1804,11 +1787,9 @@
 	_DIAGASSERT(g != NULL);
 
 	g->nstates = p->slen;
-	g->strip = realloc(p->strip, p->slen * sizeof(sop));
-	if (g->strip == NULL) {
-		SETERROR(REG_ESPACE);
-		g->strip = p->strip;
-	}
+	g->strip = p->strip;
+	reallocarr(&g->strip, p->slen, sizeof(sop));
+	/* Ignore error as tries to free memory only. */
 }
 
 /*
diff --git a/libc/upstream-netbsd/lib/libc/stdlib/reallocarr.c b/libc/upstream-netbsd/lib/libc/stdlib/reallocarr.c
new file mode 100644
index 0000000..6ffe811
--- /dev/null
+++ b/libc/upstream-netbsd/lib/libc/stdlib/reallocarr.c
@@ -0,0 +1,95 @@
+/* $NetBSD: reallocarr.c,v 1.5 2015/08/20 22:27:49 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2015 Joerg Sonnenberger <joerg@NetBSD.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 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 HOLDERS 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.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: reallocarr.c,v 1.5 2015/08/20 22:27:49 kamil Exp $");
+
+#include "namespace.h"
+#include <errno.h>
+/* Old POSIX has SIZE_MAX in limits.h */
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _LIBC
+#ifdef __weak_alias
+__weak_alias(reallocarr, _reallocarr)
+#endif
+#endif
+
+#define SQRT_SIZE_MAX (((size_t)1) << (sizeof(size_t) * CHAR_BIT / 2))
+
+#if !HAVE_REALLOCARR
+int
+reallocarr(void *ptr, size_t number, size_t size)
+{
+	int saved_errno, result;
+	void *optr;
+	void *nptr;
+
+	saved_errno = errno;
+	memcpy(&optr, ptr, sizeof(ptr));
+	if (number == 0 || size == 0) {
+		free(optr);
+		nptr = NULL;
+		memcpy(ptr, &nptr, sizeof(ptr));
+		errno = saved_errno;
+		return 0;
+	}
+
+	/*
+	 * Try to avoid division here.
+	 *
+	 * It isn't possible to overflow during multiplication if neither
+	 * operand uses any of the most significant half of the bits.
+	 */
+	if (__predict_false((number|size) >= SQRT_SIZE_MAX &&
+	                    number > SIZE_MAX / size)) {
+		errno = saved_errno;
+		return EOVERFLOW;
+	}
+
+	nptr = realloc(optr, number * size);
+	if (__predict_false(nptr == NULL)) {
+		result = errno;
+	} else {
+		result = 0;
+		memcpy(ptr, &nptr, sizeof(ptr));
+	}
+	errno = saved_errno;
+	return result;
+}
+#endif
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_addr.c b/libc/upstream-openbsd/lib/libc/net/inet_addr.c
deleted file mode 100644
index 18762ab..0000000
--- a/libc/upstream-openbsd/lib/libc/net/inet_addr.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*	$OpenBSD: inet_addr.c,v 1.10 2013/11/24 23:51:28 deraadt Exp $	*/
-
-/*
- * ++Copyright++ 1983, 1990, 1993
- * -
- * Copyright (c) 1983, 1990, 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/types.h>
-#include <sys/param.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-
-/*
- * Ascii internet address interpretation routine.
- * The value returned is in network order.
- */
-in_addr_t
-inet_addr(const char *cp)
-{
-	struct in_addr val;
-
-	if (inet_aton(cp, &val))
-		return (val.s_addr);
-	return (INADDR_NONE);
-}
-
-/* 
- * Check whether "cp" is a valid ascii representation
- * of an Internet address and convert to a binary address.
- * Returns 1 if the address is valid, 0 if not.
- * This replaces inet_addr, the return value from which
- * cannot distinguish between failure and a local broadcast address.
- */
-int
-inet_aton(const char *cp, struct in_addr *addr)
-{
-	in_addr_t val;
-	int base, n;
-	char c;
-	u_int parts[4];
-	u_int *pp = parts;
-
-	c = *cp;
-	for (;;) {
-		/*
-		 * Collect number up to ``.''.
-		 * Values are specified as for C:
-		 * 0x=hex, 0=octal, isdigit=decimal.
-		 */
-		if (!isdigit((unsigned char)c))
-			return (0);
-		val = 0; base = 10;
-		if (c == '0') {
-			c = *++cp;
-			if (c == 'x' || c == 'X')
-				base = 16, c = *++cp;
-			else
-				base = 8;
-		}
-		for (;;) {
-			if (isascii((unsigned char)c) &&
-			    isdigit((unsigned char)c)) {
-				val = (val * base) + (c - '0');
-				c = *++cp;
-			} else if (base == 16 &&
-			    isascii((unsigned char)c) &&
-			    isxdigit((unsigned char)c)) {
-				val = (val << 4) |
-				    (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
-				c = *++cp;
-			} else
-				break;
-		}
-		if (c == '.') {
-			/*
-			 * Internet format:
-			 *	a.b.c.d
-			 *	a.b.c	(with c treated as 16 bits)
-			 *	a.b	(with b treated as 24 bits)
-			 */
-			if (pp >= parts + 3)
-				return (0);
-			*pp++ = val;
-			c = *++cp;
-		} else
-			break;
-	}
-	/*
-	 * Check for trailing characters.
-	 */
-	if (c != '\0' &&
-	    (!isascii((unsigned char)c) || !isspace((unsigned char)c)))
-		return (0);
-	/*
-	 * Concoct the address according to
-	 * the number of parts specified.
-	 */
-	n = pp - parts + 1;
-	switch (n) {
-
-	case 0:
-		return (0);		/* initial nondigit */
-
-	case 1:				/* a -- 32 bits */
-		break;
-
-	case 2:				/* a.b -- 8.24 bits */
-		if ((val > 0xffffff) || (parts[0] > 0xff))
-			return (0);
-		val |= parts[0] << 24;
-		break;
-
-	case 3:				/* a.b.c -- 8.8.16 bits */
-		if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff))
-			return (0);
-		val |= (parts[0] << 24) | (parts[1] << 16);
-		break;
-
-	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
-		if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff))
-			return (0);
-		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
-		break;
-	}
-	if (addr)
-		addr->s_addr = htonl(val);
-	return (1);
-}
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_network.c b/libc/upstream-openbsd/lib/libc/net/inet_network.c
deleted file mode 100644
index ecf554e..0000000
--- a/libc/upstream-openbsd/lib/libc/net/inet_network.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*	$OpenBSD: inet_network.c,v 1.11 2013/11/25 17:29:19 deraadt Exp $ */
-/*
- * Copyright (c) 1983, 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/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-
-/*
- * Internet network address interpretation routine.
- * The library routines call this routine to interpret
- * network numbers.
- */
-in_addr_t
-inet_network(const char *cp)
-{
-	in_addr_t val, base, n;
-	u_char c;
-	in_addr_t parts[4], *pp = parts;
-	int i;
-
-again:
-	val = 0; base = 10;
-	if (*cp == '0')
-		base = 8, cp++;
-	if (*cp == 'x' || *cp == 'X')
-		base = 16, cp++;
-	while ((c = *cp)) {
-		if (isdigit(c)) {
-			val = (val * base) + (c - '0');
-			cp++;
-			continue;
-		}
-		if (base == 16 && isxdigit(c)) {
-			val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
-			cp++;
-			continue;
-		}
-		break;
-	}
-	if (*cp == '.') {
-		if (pp >= parts + 3)
-			return (INADDR_NONE);
-		*pp++ = val, cp++;
-		goto again;
-	}
-	if (*cp && !isspace(*cp))
-		return (INADDR_NONE);
-	*pp++ = val;
-	n = pp - parts;
-	for (val = 0, i = 0; i < 4; i++) {
-		val <<= 8;
-		if (i < n)
-			val |= parts[i] & 0xff;
-	}
-	return (val);
-}
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/abs.c b/libc/upstream-openbsd/lib/libc/stdlib/abs.c
similarity index 83%
rename from libc/upstream-freebsd/lib/libc/stdlib/abs.c
rename to libc/upstream-openbsd/lib/libc/stdlib/abs.c
index 8758947..5d2fbae 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/abs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/abs.c
@@ -1,6 +1,7 @@
+/*	$OpenBSD: abs.c,v 1.5 2005/08/08 08:05:36 espie Exp $ */
 /*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990 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
@@ -27,17 +28,10 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)abs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <stdlib.h>
 
 int
-abs(j)
-	int j;
+abs(int j)
 {
 	return(j < 0 ? -j : j);
 }
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/abs.c b/libc/upstream-openbsd/lib/libc/stdlib/imaxabs.c
similarity index 81%
copy from libc/upstream-freebsd/lib/libc/stdlib/abs.c
copy to libc/upstream-openbsd/lib/libc/stdlib/imaxabs.c
index 8758947..b7e910e 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/abs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/imaxabs.c
@@ -1,6 +1,8 @@
+/*	$OpenBSD: imaxabs.c,v 1.1 2006/01/13 17:58:09 millert Exp $	*/
+
 /*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990 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
@@ -27,17 +29,10 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)abs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+#include <inttypes.h>
 
-#include <stdlib.h>
-
-int
-abs(j)
-	int j;
+intmax_t
+imaxabs(intmax_t j)
 {
-	return(j < 0 ? -j : j);
+	return (j < 0 ? -j : j);
 }
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/abs.c b/libc/upstream-openbsd/lib/libc/stdlib/imaxdiv.c
similarity index 74%
copy from libc/upstream-freebsd/lib/libc/stdlib/abs.c
copy to libc/upstream-openbsd/lib/libc/stdlib/imaxdiv.c
index 8758947..0515a94 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/abs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/imaxdiv.c
@@ -1,6 +1,10 @@
-/*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+/*	$OpenBSD: imaxdiv.c,v 1.1 2006/01/13 17:58:09 millert Exp $	*/
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,17 +31,20 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)abs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+#include <inttypes.h>		/* imaxdiv_t */
 
-#include <stdlib.h>
-
-int
-abs(j)
-	int j;
+imaxdiv_t
+imaxdiv(intmax_t num, intmax_t denom)
 {
-	return(j < 0 ? -j : j);
+	imaxdiv_t r;
+
+	/* see div.c for comments */
+
+	r.quot = num / denom;
+	r.rem = num % denom;
+	if (num >= 0 && r.rem < 0) {
+		r.quot++;
+		r.rem -= denom;
+	}
+	return (r);
 }
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/abs.c b/libc/upstream-openbsd/lib/libc/stdlib/labs.c
similarity index 83%
copy from libc/upstream-freebsd/lib/libc/stdlib/abs.c
copy to libc/upstream-openbsd/lib/libc/stdlib/labs.c
index 8758947..ca60b9a 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/abs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/labs.c
@@ -1,6 +1,7 @@
+/*	$OpenBSD: labs.c,v 1.5 2005/08/08 08:05:36 espie Exp $ */
 /*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990 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
@@ -27,17 +28,10 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)abs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <stdlib.h>
 
-int
-abs(j)
-	int j;
+long
+labs(long j)
 {
 	return(j < 0 ? -j : j);
 }
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/abs.c b/libc/upstream-openbsd/lib/libc/stdlib/llabs.c
similarity index 82%
copy from libc/upstream-freebsd/lib/libc/stdlib/abs.c
copy to libc/upstream-openbsd/lib/libc/stdlib/llabs.c
index 8758947..fc2cd82 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/abs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/llabs.c
@@ -1,6 +1,8 @@
+/*	$OpenBSD: llabs.c,v 1.3 2007/01/08 19:39:25 deraadt Exp $	*/
+
 /*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990 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
@@ -27,17 +29,10 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)abs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <stdlib.h>
 
-int
-abs(j)
-	int j;
+long long
+llabs(long long j)
 {
-	return(j < 0 ? -j : j);
+	return (j < 0 ? -j : j);
 }
diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
index f22464e..c464f46 100644
--- a/libc/zoneinfo/tzdata
+++ b/libc/zoneinfo/tzdata
Binary files differ
diff --git a/libdl/Android.bp b/libdl/Android.bp
new file mode 100644
index 0000000..46dd0eb
--- /dev/null
+++ b/libdl/Android.bp
@@ -0,0 +1,47 @@
+//
+// libdl
+//
+cc_library {
+
+    // NOTE: --exclude-libs=libgcc.a makes sure that any symbols libdl.so pulls from
+    // libgcc.a are made static to libdl.so.  This in turn ensures that libraries that
+    // a) pull symbols from libgcc.a and b) depend on libdl.so will not rely on libdl.so
+    // to provide those symbols, but will instead pull them from libgcc.a.  Specifically,
+    // we use this property to make sure libc.so has its own copy of the code from
+    // libgcc.a it uses.
+    //
+    // DO NOT REMOVE --exclude-libs!
+
+    ldflags: ["-Wl,--exclude-libs=libgcc.a"],
+    version_script: "libdl.map",
+
+    // for x86, exclude libgcc_eh.a for the same reasons as above
+    arch: {
+        x86: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+        },
+        x86_64: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+        },
+    },
+    srcs: ["libdl.c"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wunused",
+        "-Werror",
+    ],
+    stl: "none",
+
+    name: "libdl",
+
+    // NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
+    // few symbols from libc. Using --no-undefined here results in having to link
+    // against libc creating a circular dependency which is removed and we end up
+    // with missing symbols. Since this library is just a bunch of stubs, we set
+    // LOCAL_ALLOW_UNDEFINED_SYMBOLS to remove --no-undefined from the linker flags.
+    allow_undefined_symbols: true,
+    system_shared_libs: [],
+
+    sanitize: ["never"],
+}
diff --git a/libm/Android.bp b/libm/Android.bp
new file mode 100644
index 0000000..3ae086f
--- /dev/null
+++ b/libm/Android.bp
@@ -0,0 +1,382 @@
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// ifneq ($(TARGET_USE_PRIVATE_LIBM),true)
+
+bionic_coverage = false
+
+// TODO: this comes from from upstream's libc, not libm, but it's an
+// implementation detail that should have hidden visibility, so it needs
+// to be in whatever library the math code is in.
+libm_common_src_files = ["digittoint.c"]
+
+// TODO: this is not in the BSDs.
+libm_common_src_files += [
+    "significandl.c",
+    "sincos.c",
+]
+
+libm_common_src_files += [
+    "upstream-freebsd/lib/msun/bsdsrc/b_exp.c",
+    "upstream-freebsd/lib/msun/bsdsrc/b_log.c",
+    "upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c",
+    "upstream-freebsd/lib/msun/src/catrig.c",
+    "upstream-freebsd/lib/msun/src/catrigf.c",
+    "upstream-freebsd/lib/msun/src/e_acos.c",
+    "upstream-freebsd/lib/msun/src/e_acosf.c",
+    "upstream-freebsd/lib/msun/src/e_acosh.c",
+    "upstream-freebsd/lib/msun/src/e_acoshf.c",
+    "upstream-freebsd/lib/msun/src/e_asin.c",
+    "upstream-freebsd/lib/msun/src/e_asinf.c",
+    "upstream-freebsd/lib/msun/src/e_atan2.c",
+    "upstream-freebsd/lib/msun/src/e_atan2f.c",
+    "upstream-freebsd/lib/msun/src/e_atanh.c",
+    "upstream-freebsd/lib/msun/src/e_atanhf.c",
+    "upstream-freebsd/lib/msun/src/e_cosh.c",
+    "upstream-freebsd/lib/msun/src/e_coshf.c",
+    "upstream-freebsd/lib/msun/src/e_exp.c",
+    "upstream-freebsd/lib/msun/src/e_expf.c",
+    "upstream-freebsd/lib/msun/src/e_fmod.c",
+    "upstream-freebsd/lib/msun/src/e_fmodf.c",
+    "upstream-freebsd/lib/msun/src/e_gamma.c",
+    "upstream-freebsd/lib/msun/src/e_gammaf.c",
+    "upstream-freebsd/lib/msun/src/e_gammaf_r.c",
+    "upstream-freebsd/lib/msun/src/e_gamma_r.c",
+    "upstream-freebsd/lib/msun/src/e_hypot.c",
+    "upstream-freebsd/lib/msun/src/e_hypotf.c",
+    "upstream-freebsd/lib/msun/src/e_j0.c",
+    "upstream-freebsd/lib/msun/src/e_j0f.c",
+    "upstream-freebsd/lib/msun/src/e_j1.c",
+    "upstream-freebsd/lib/msun/src/e_j1f.c",
+    "upstream-freebsd/lib/msun/src/e_jn.c",
+    "upstream-freebsd/lib/msun/src/e_jnf.c",
+    "upstream-freebsd/lib/msun/src/e_lgamma.c",
+    "upstream-freebsd/lib/msun/src/e_lgammaf.c",
+    "upstream-freebsd/lib/msun/src/e_lgammaf_r.c",
+    "upstream-freebsd/lib/msun/src/e_lgamma_r.c",
+    "upstream-freebsd/lib/msun/src/e_log10.c",
+    "upstream-freebsd/lib/msun/src/e_log10f.c",
+    "upstream-freebsd/lib/msun/src/e_log2.c",
+    "upstream-freebsd/lib/msun/src/e_log2f.c",
+    "upstream-freebsd/lib/msun/src/e_log.c",
+    "upstream-freebsd/lib/msun/src/e_logf.c",
+    "upstream-freebsd/lib/msun/src/e_pow.c",
+    "upstream-freebsd/lib/msun/src/e_powf.c",
+    "upstream-freebsd/lib/msun/src/e_remainder.c",
+    "upstream-freebsd/lib/msun/src/e_remainderf.c",
+    "upstream-freebsd/lib/msun/src/e_rem_pio2.c",
+    "upstream-freebsd/lib/msun/src/e_rem_pio2f.c",
+    "upstream-freebsd/lib/msun/src/e_scalb.c",
+    "upstream-freebsd/lib/msun/src/e_scalbf.c",
+    "upstream-freebsd/lib/msun/src/e_sinh.c",
+    "upstream-freebsd/lib/msun/src/e_sinhf.c",
+    "upstream-freebsd/lib/msun/src/e_sqrt.c",
+    "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+    "upstream-freebsd/lib/msun/src/imprecise.c",
+    "upstream-freebsd/lib/msun/src/k_cos.c",
+    "upstream-freebsd/lib/msun/src/k_cosf.c",
+    "upstream-freebsd/lib/msun/src/k_exp.c",
+    "upstream-freebsd/lib/msun/src/k_expf.c",
+    "upstream-freebsd/lib/msun/src/k_rem_pio2.c",
+    "upstream-freebsd/lib/msun/src/k_sin.c",
+    "upstream-freebsd/lib/msun/src/k_sinf.c",
+    "upstream-freebsd/lib/msun/src/k_tan.c",
+    "upstream-freebsd/lib/msun/src/k_tanf.c",
+    "upstream-freebsd/lib/msun/src/s_asinh.c",
+    "upstream-freebsd/lib/msun/src/s_asinhf.c",
+    "upstream-freebsd/lib/msun/src/s_atan.c",
+    "upstream-freebsd/lib/msun/src/s_atanf.c",
+    "upstream-freebsd/lib/msun/src/s_carg.c",
+    "upstream-freebsd/lib/msun/src/s_cargf.c",
+    "upstream-freebsd/lib/msun/src/s_cargl.c",
+    "upstream-freebsd/lib/msun/src/s_cbrt.c",
+    "upstream-freebsd/lib/msun/src/s_cbrtf.c",
+    "upstream-freebsd/lib/msun/src/s_ccosh.c",
+    "upstream-freebsd/lib/msun/src/s_ccoshf.c",
+    "upstream-freebsd/lib/msun/src/s_ceil.c",
+    "upstream-freebsd/lib/msun/src/s_ceilf.c",
+    "upstream-freebsd/lib/msun/src/s_cexp.c",
+    "upstream-freebsd/lib/msun/src/s_cexpf.c",
+    "upstream-freebsd/lib/msun/src/s_cimag.c",
+    "upstream-freebsd/lib/msun/src/s_cimagf.c",
+    "upstream-freebsd/lib/msun/src/s_cimagl.c",
+    "upstream-freebsd/lib/msun/src/s_conj.c",
+    "upstream-freebsd/lib/msun/src/s_conjf.c",
+    "upstream-freebsd/lib/msun/src/s_conjl.c",
+    "upstream-freebsd/lib/msun/src/s_copysign.c",
+    "upstream-freebsd/lib/msun/src/s_copysignf.c",
+    "upstream-freebsd/lib/msun/src/s_cos.c",
+    "upstream-freebsd/lib/msun/src/s_cosf.c",
+    "upstream-freebsd/lib/msun/src/s_cproj.c",
+    "upstream-freebsd/lib/msun/src/s_cprojf.c",
+    "upstream-freebsd/lib/msun/src/s_cprojl.c",
+    "upstream-freebsd/lib/msun/src/s_creal.c",
+    "upstream-freebsd/lib/msun/src/s_crealf.c",
+    "upstream-freebsd/lib/msun/src/s_creall.c",
+    "upstream-freebsd/lib/msun/src/s_csinh.c",
+    "upstream-freebsd/lib/msun/src/s_csinhf.c",
+    "upstream-freebsd/lib/msun/src/s_csqrt.c",
+    "upstream-freebsd/lib/msun/src/s_csqrtf.c",
+    "upstream-freebsd/lib/msun/src/s_csqrtl.c",
+    "upstream-freebsd/lib/msun/src/s_ctanh.c",
+    "upstream-freebsd/lib/msun/src/s_ctanhf.c",
+    "upstream-freebsd/lib/msun/src/s_erf.c",
+    "upstream-freebsd/lib/msun/src/s_erff.c",
+    "upstream-freebsd/lib/msun/src/s_exp2.c",
+    "upstream-freebsd/lib/msun/src/s_exp2f.c",
+    "upstream-freebsd/lib/msun/src/s_expm1.c",
+    "upstream-freebsd/lib/msun/src/s_expm1f.c",
+    "upstream-freebsd/lib/msun/src/s_fdim.c",
+    "upstream-freebsd/lib/msun/src/s_finite.c",
+    "upstream-freebsd/lib/msun/src/s_finitef.c",
+    "upstream-freebsd/lib/msun/src/s_floor.c",
+    "upstream-freebsd/lib/msun/src/s_floorf.c",
+    "upstream-freebsd/lib/msun/src/s_fma.c",
+    "upstream-freebsd/lib/msun/src/s_fmaf.c",
+    "upstream-freebsd/lib/msun/src/s_fmax.c",
+    "upstream-freebsd/lib/msun/src/s_fmaxf.c",
+    "upstream-freebsd/lib/msun/src/s_fmin.c",
+    "upstream-freebsd/lib/msun/src/s_fminf.c",
+    "upstream-freebsd/lib/msun/src/s_frexp.c",
+    "upstream-freebsd/lib/msun/src/s_frexpf.c",
+    "upstream-freebsd/lib/msun/src/s_ilogb.c",
+    "upstream-freebsd/lib/msun/src/s_ilogbf.c",
+    "upstream-freebsd/lib/msun/src/s_llrint.c",
+    "upstream-freebsd/lib/msun/src/s_llrintf.c",
+    "upstream-freebsd/lib/msun/src/s_llround.c",
+    "upstream-freebsd/lib/msun/src/s_llroundf.c",
+    "upstream-freebsd/lib/msun/src/s_log1p.c",
+    "upstream-freebsd/lib/msun/src/s_log1pf.c",
+    "upstream-freebsd/lib/msun/src/s_logb.c",
+    "upstream-freebsd/lib/msun/src/s_logbf.c",
+    "upstream-freebsd/lib/msun/src/s_lrint.c",
+    "upstream-freebsd/lib/msun/src/s_lrintf.c",
+    "upstream-freebsd/lib/msun/src/s_lround.c",
+    "upstream-freebsd/lib/msun/src/s_lroundf.c",
+    "upstream-freebsd/lib/msun/src/s_modf.c",
+    "upstream-freebsd/lib/msun/src/s_modff.c",
+    "upstream-freebsd/lib/msun/src/s_nan.c",
+    "upstream-freebsd/lib/msun/src/s_nearbyint.c",
+    "upstream-freebsd/lib/msun/src/s_nextafter.c",
+    "upstream-freebsd/lib/msun/src/s_nextafterf.c",
+    "upstream-freebsd/lib/msun/src/s_remquo.c",
+    "upstream-freebsd/lib/msun/src/s_remquof.c",
+    "upstream-freebsd/lib/msun/src/s_rint.c",
+    "upstream-freebsd/lib/msun/src/s_rintf.c",
+    "upstream-freebsd/lib/msun/src/s_round.c",
+    "upstream-freebsd/lib/msun/src/s_roundf.c",
+    "upstream-freebsd/lib/msun/src/s_scalbln.c",
+    "upstream-freebsd/lib/msun/src/s_scalbn.c",
+    "upstream-freebsd/lib/msun/src/s_scalbnf.c",
+    "upstream-freebsd/lib/msun/src/s_signgam.c",
+    "upstream-freebsd/lib/msun/src/s_significand.c",
+    "upstream-freebsd/lib/msun/src/s_significandf.c",
+    "upstream-freebsd/lib/msun/src/s_sin.c",
+    "upstream-freebsd/lib/msun/src/s_sinf.c",
+    "upstream-freebsd/lib/msun/src/s_tan.c",
+    "upstream-freebsd/lib/msun/src/s_tanf.c",
+    "upstream-freebsd/lib/msun/src/s_tanh.c",
+    "upstream-freebsd/lib/msun/src/s_tanhf.c",
+    "upstream-freebsd/lib/msun/src/s_tgammaf.c",
+    "upstream-freebsd/lib/msun/src/s_trunc.c",
+    "upstream-freebsd/lib/msun/src/s_truncf.c",
+    "upstream-freebsd/lib/msun/src/w_cabs.c",
+    "upstream-freebsd/lib/msun/src/w_cabsf.c",
+    "upstream-freebsd/lib/msun/src/w_cabsl.c",
+    "upstream-freebsd/lib/msun/src/w_drem.c",
+    "upstream-freebsd/lib/msun/src/w_dremf.c",
+]
+
+libm_common_src_files += [
+    "fake_long_double.c",
+    "signbit.c",
+    "fabs.cpp",
+]
+
+libm_ld128_src_files = [
+    "upstream-freebsd/lib/msun/src/e_acosl.c",
+    "upstream-freebsd/lib/msun/src/e_acoshl.c",
+    "upstream-freebsd/lib/msun/src/e_asinl.c",
+    "upstream-freebsd/lib/msun/src/e_atan2l.c",
+    "upstream-freebsd/lib/msun/src/e_atanhl.c",
+    "upstream-freebsd/lib/msun/src/e_fmodl.c",
+    "upstream-freebsd/lib/msun/src/e_hypotl.c",
+    "upstream-freebsd/lib/msun/src/e_lgammal.c",
+    "upstream-freebsd/lib/msun/src/e_remainderl.c",
+    "upstream-freebsd/lib/msun/src/e_sqrtl.c",
+    "upstream-freebsd/lib/msun/src/s_asinhl.c",
+    "upstream-freebsd/lib/msun/src/s_atanl.c",
+    "upstream-freebsd/lib/msun/src/s_cbrtl.c",
+    "upstream-freebsd/lib/msun/src/s_ceill.c",
+    "upstream-freebsd/lib/msun/src/s_copysignl.c",
+    "upstream-freebsd/lib/msun/src/e_coshl.c",
+    "upstream-freebsd/lib/msun/src/s_cosl.c",
+    "upstream-freebsd/lib/msun/src/s_floorl.c",
+    "upstream-freebsd/lib/msun/src/s_fmal.c",
+    "upstream-freebsd/lib/msun/src/s_fmaxl.c",
+    "upstream-freebsd/lib/msun/src/s_fminl.c",
+    "upstream-freebsd/lib/msun/src/s_modfl.c",
+    "upstream-freebsd/lib/msun/src/s_frexpl.c",
+    "upstream-freebsd/lib/msun/src/s_ilogbl.c",
+    "upstream-freebsd/lib/msun/src/s_llrintl.c",
+    "upstream-freebsd/lib/msun/src/s_llroundl.c",
+    "upstream-freebsd/lib/msun/src/s_logbl.c",
+    "upstream-freebsd/lib/msun/src/s_lrintl.c",
+    "upstream-freebsd/lib/msun/src/s_lroundl.c",
+    "upstream-freebsd/lib/msun/src/s_nextafterl.c",
+    "upstream-freebsd/lib/msun/src/s_nexttoward.c",
+    "upstream-freebsd/lib/msun/src/s_nexttowardf.c",
+    "upstream-freebsd/lib/msun/src/s_remquol.c",
+    "upstream-freebsd/lib/msun/src/s_rintl.c",
+    "upstream-freebsd/lib/msun/src/s_roundl.c",
+    "upstream-freebsd/lib/msun/src/s_scalbnl.c",
+    "upstream-freebsd/lib/msun/src/e_sinhl.c",
+    "upstream-freebsd/lib/msun/src/s_sinl.c",
+    "upstream-freebsd/lib/msun/src/s_tanhl.c",
+    "upstream-freebsd/lib/msun/src/s_tanl.c",
+    "upstream-freebsd/lib/msun/src/s_truncl.c",
+]
+
+libm_ld128_src_files += [
+    "upstream-freebsd/lib/msun/ld128/invtrig.c",
+    "upstream-freebsd/lib/msun/ld128/e_lgammal_r.c",
+    "upstream-freebsd/lib/msun/ld128/k_cosl.c",
+    "upstream-freebsd/lib/msun/ld128/k_sinl.c",
+    "upstream-freebsd/lib/msun/ld128/k_tanl.c",
+    "upstream-freebsd/lib/msun/ld128/s_erfl.c",
+    "upstream-freebsd/lib/msun/ld128/s_exp2l.c",
+    "upstream-freebsd/lib/msun/ld128/s_expl.c",
+    "upstream-freebsd/lib/msun/ld128/s_logl.c",
+    "upstream-freebsd/lib/msun/ld128/s_nanl.c",
+]
+
+// TODO: re-enable i387/e_sqrtf.S for x86, and maybe others.
+
+libm_common_cflags = [
+    "-D__BIONIC_NO_MATH_INLINES",
+    "-DFLT_EVAL_METHOD=0",
+    "-include freebsd-compat.h",
+    "-Wno-missing-braces",
+    "-Wno-parentheses",
+    "-Wno-sign-compare",
+    "-Wno-uninitialized",
+    "-Wno-unknown-pragmas",
+    "-fvisibility=hidden",
+]
+
+// Workaround the GCC "(long)fn -> lfn" optimization bug which will result in
+// self recursions for lrint, lrintf, and lrintl.
+// BUG: 14225968
+libm_common_cflags += [
+    "-fno-builtin-rint",
+    "-fno-builtin-rintf",
+    "-fno-builtin-rintl",
+]
+
+libm_common_local_includes = ["upstream-freebsd/lib/msun/src/"]
+
+libm_ld_local_includes = ["upstream-freebsd/lib/msun/ld128/"]
+
+//
+// libm.so and libm.a for target.
+//
+cc_library {
+    name: "libm",
+
+    cflags: libm_common_cflags,
+    include_dirs: ["bionic/libc"],
+    local_include_dirs: libm_common_local_includes,
+    srcs: libm_common_src_files,
+    system_shared_libs: ["libc"],
+
+    native_coverage: bionic_coverage,
+    sanitize: ["never"],
+
+    version_script: "libm.map",
+
+    multilib: {
+        lib64: {
+            srcs: libm_ld128_src_files,
+            local_include_dirs: libm_ld_local_includes,
+            // We'd really like to do this for all architectures, but since this wasn't done
+            // before, these symbols must continue to be exported on LP32 for binary
+            // compatibility.
+            ldflags: ["-Wl,--exclude-libs,libgcc.a"],
+        },
+    },
+
+    // arch-specific settings
+    arch: {
+        arm: {
+            srcs: [
+                "arm/fenv.c",
+                "arm/sqrt.S",
+                "arm/floor.S",
+            ],
+            exclude_srcs: [
+                // TODO: these require neon not available in arm
+                "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                "upstream-freebsd/lib/msun/src/s_floor.c",
+            ],
+            instruction_set: "arm",
+            ldflags: ["-Wl,--hash-style=both"],
+        },
+
+        arm64: {
+            srcs: [
+                "arm64/fenv.c",
+                "arm64/ceil.S",
+                "arm64/fma.S",
+                "arm64/floor.S",
+                "arm64/lrint.S",
+                "arm64/rint.S",
+                "arm64/sqrt.S",
+                "arm64/trunc.S",
+            ],
+            exclude_srcs: [
+                "upstream-freebsd/lib/msun/src/s_ceil.c",
+                "upstream-freebsd/lib/msun/src/s_ceilf.c",
+                "upstream-freebsd/lib/msun/src/s_fma.c",
+                "upstream-freebsd/lib/msun/src/s_fmaf.c",
+                "upstream-freebsd/lib/msun/src/s_floor.c",
+                "upstream-freebsd/lib/msun/src/s_floorf.c",
+                "upstream-freebsd/lib/msun/src/s_llrint.c",
+                "upstream-freebsd/lib/msun/src/s_llrintf.c",
+                "upstream-freebsd/lib/msun/src/s_lrint.c",
+                "upstream-freebsd/lib/msun/src/s_lrintf.c",
+                "upstream-freebsd/lib/msun/src/s_rint.c",
+                "upstream-freebsd/lib/msun/src/s_rintf.c",
+                "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                "upstream-freebsd/lib/msun/src/s_trunc.c",
+                "upstream-freebsd/lib/msun/src/s_truncf.c",
+            ],
+        },
+
+        mips: {
+            srcs: ["mips/fenv.c"],
+        },
+
+        mips64: {
+            srcs: ["mips/fenv.c"],
+        },
+
+        x86: {
+            local_include_dirs: ["i387"],
+            srcs: ["i387/fenv.c"],
+            // Clang has wrong long double sizes for x86.
+            clang: false,
+            ldflags: ["-Wl,--hash-style=both"],
+        },
+
+        x86_64: {
+            srcs: ["amd64/fenv.c"],
+            // Clang has wrong long double sizes for x86.
+            clang: false,
+        },
+    },
+
+    stl: "none",
+}
+
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// endif
diff --git a/libm/Android.mk b/libm/Android.mk
index d447417..fb8df07 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -514,7 +514,7 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/libm.map
 
-# TODO: This is to work around b/19059885. Remove after root cause is fixed
+# TODO: This is to work around b/24465209. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
 LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
 
diff --git a/linker/Android.mk b/linker/Android.mk
index d8487d3..8be53a1 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -2,7 +2,9 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES := \
     debugger.cpp \
     dlfcn.cpp \
     linker.cpp \
@@ -12,6 +14,7 @@
     linker_libc_support.c \
     linker_memory.cpp \
     linker_phdr.cpp \
+    linker_utils.cpp \
     rt.cpp \
 
 LOCAL_SRC_FILES_arm     := arch/arm/begin.S
@@ -35,8 +38,8 @@
     -fvisibility=hidden \
     -Wall -Wextra -Wunused -Werror \
 
-LOCAL_CFLAGS_arm += -D__work_around_b_19059885__
-LOCAL_CFLAGS_x86 += -D__work_around_b_19059885__
+LOCAL_CFLAGS_arm += -D__work_around_b_24465209__
+LOCAL_CFLAGS_x86 += -D__work_around_b_24465209__
 
 LOCAL_CONLYFLAGS += \
     -std=gnu99 \
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 3967ad5..406cdee 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -41,6 +41,7 @@
 
 #include <new>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 // Private C library headers.
@@ -57,10 +58,12 @@
 #include "linker_phdr.h"
 #include "linker_relocs.h"
 #include "linker_reloc_iterators.h"
+#include "linker_utils.h"
 
 #include "base/strings.h"
 #include "ziparchive/zip_archive.h"
 
+extern void __libc_init_globals(KernelArgumentBlock&);
 extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
 
 // Override macros to use C++ style casts.
@@ -359,13 +362,13 @@
 
 static bool realpath_fd(int fd, std::string* realpath) {
   std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
-  snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
+  __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
   if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
     PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
     return false;
   }
 
-  *realpath = std::string(&buf[0]);
+  *realpath = &buf[0];
   return true;
 }
 
@@ -1121,15 +1124,64 @@
   return nullptr;
 }
 
-static int open_library_in_zipfile(const char* const path,
-                                   off64_t* file_offset) {
-  TRACE("Trying zip file open from path '%s'", path);
+class ZipArchiveCache {
+ public:
+  ZipArchiveCache() {}
+  ~ZipArchiveCache();
+
+  bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
+
+  std::unordered_map<std::string, ZipArchiveHandle> cache_;
+};
+
+bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
+  std::string key(zip_path);
+
+  auto it = cache_.find(key);
+  if (it != cache_.end()) {
+    *handle = it->second;
+    return true;
+  }
+
+  int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
+  if (fd == -1) {
+    return false;
+  }
+
+  if (OpenArchiveFd(fd, "", handle) != 0) {
+    // invalid zip-file (?)
+    close(fd);
+    return false;
+  }
+
+  cache_[key] = *handle;
+  return true;
+}
+
+ZipArchiveCache::~ZipArchiveCache() {
+  for (auto it : cache_) {
+    CloseArchive(it.second);
+  }
+}
+
+static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
+                                   const char* const input_path,
+                                   off64_t* file_offset, std::string* realpath) {
+  std::string normalized_path;
+  if (!normalize_path(input_path, &normalized_path)) {
+    return -1;
+  }
+
+  const char* const path = normalized_path.c_str();
+  TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path);
 
   // Treat an '!/' separator inside a path as the separator between the name
   // of the zip file on disk and the subdirectory to search within it.
   // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
   // "bar/bas/x.so" within "foo.zip".
-  const char* separator = strstr(path, kZipFileSeparator);
+  const char* const separator = strstr(path, kZipFileSeparator);
   if (separator == nullptr) {
     return -1;
   }
@@ -1150,16 +1202,12 @@
   }
 
   ZipArchiveHandle handle;
-  if (OpenArchiveFd(fd, "", &handle, false) != 0) {
+  if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
     // invalid zip-file (?)
     close(fd);
     return -1;
   }
 
-  auto archive_guard = make_scope_guard([&]() {
-    CloseArchive(handle);
-  });
-
   ZipEntry entry;
 
   if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
@@ -1175,6 +1223,15 @@
   }
 
   *file_offset = entry.offset;
+
+  if (realpath_fd(fd, realpath)) {
+    *realpath += separator;
+  } else {
+    PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
+          normalized_path.c_str());
+    *realpath = normalized_path;
+  }
+
   return fd;
 }
 
@@ -1188,7 +1245,7 @@
   return true;
 }
 
-static int open_library_on_default_path(const char* name, off64_t* file_offset) {
+static int open_library_on_default_path(const char* name, off64_t* file_offset, std::string* realpath) {
   for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
     char buf[512];
     if (!format_path(buf, sizeof(buf), g_default_ld_paths[i], name)) {
@@ -1198,6 +1255,10 @@
     int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
     if (fd != -1) {
       *file_offset = 0;
+      if (!realpath_fd(fd, realpath)) {
+        PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
+        *realpath = buf;
+      }
       return fd;
     }
   }
@@ -1205,8 +1266,10 @@
   return -1;
 }
 
-static int open_library_on_paths(const char* name, off64_t* file_offset,
-                                 const std::vector<std::string>& paths) {
+static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
+                                 const char* name, off64_t* file_offset,
+                                 const std::vector<std::string>& paths,
+                                 std::string* realpath) {
   for (const auto& path_str : paths) {
     char buf[512];
     const char* const path = path_str.c_str();
@@ -1216,13 +1279,17 @@
 
     int fd = -1;
     if (strstr(buf, kZipFileSeparator) != nullptr) {
-      fd = open_library_in_zipfile(buf, file_offset);
+      fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
     }
 
     if (fd == -1) {
       fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
       if (fd != -1) {
         *file_offset = 0;
+        if (!realpath_fd(fd, realpath)) {
+          PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
+          *realpath = buf;
+        }
       }
     }
 
@@ -1234,13 +1301,15 @@
   return -1;
 }
 
-static int open_library(const char* name, soinfo *needed_by, off64_t* file_offset) {
+static int open_library(ZipArchiveCache* zip_archive_cache,
+                        const char* name, soinfo *needed_by,
+                        off64_t* file_offset, std::string* realpath) {
   TRACE("[ opening %s ]", name);
 
   // If the name contains a slash, we should attempt to open it directly and not search the paths.
   if (strchr(name, '/') != nullptr) {
     if (strstr(name, kZipFileSeparator) != nullptr) {
-      int fd = open_library_in_zipfile(name, file_offset);
+      int fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
       if (fd != -1) {
         return fd;
       }
@@ -1249,18 +1318,24 @@
     int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
     if (fd != -1) {
       *file_offset = 0;
+      if (!realpath_fd(fd, realpath)) {
+        PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
+        *realpath = name;
+      }
     }
     return fd;
   }
 
   // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
-  int fd = open_library_on_paths(name, file_offset, g_ld_library_paths);
+  int fd = open_library_on_paths(zip_archive_cache, name, file_offset, g_ld_library_paths, realpath);
   if (fd == -1 && needed_by) {
-    fd = open_library_on_paths(name, file_offset, needed_by->get_dt_runpath());
+    fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
   }
+
   if (fd == -1) {
-    fd = open_library_on_default_path(name, file_offset);
+    fd = open_library_on_default_path(name, file_offset, realpath);
   }
+
   return fd;
 }
 
@@ -1291,7 +1366,8 @@
 static soinfo* load_library(int fd, off64_t file_offset,
                             LoadTaskList& load_tasks,
                             const char* name, int rtld_flags,
-                            const android_dlextinfo* extinfo) {
+                            const android_dlextinfo* extinfo,
+                            const std::string& realpath) {
   if ((file_offset % PAGE_SIZE) != 0) {
     DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
     return nullptr;
@@ -1333,12 +1409,6 @@
     return nullptr;
   }
 
-  std::string realpath = name;
-  if (!realpath_fd(fd, &realpath)) {
-    PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name);
-    realpath = name;
-  }
-
   // Read the ELF header and load the segments.
   ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
   if (!elf_reader.Load(extinfo)) {
@@ -1367,25 +1437,33 @@
   return si;
 }
 
-static soinfo* load_library(LoadTaskList& load_tasks, const char* name,
+static soinfo* load_library(ZipArchiveCache* zip_archive_cache,
+                            LoadTaskList& load_tasks, const char* name,
                             soinfo* needed_by, int rtld_flags,
                             const android_dlextinfo* extinfo) {
+  off64_t file_offset;
+  std::string realpath;
   if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
-    off64_t file_offset = 0;
+    file_offset = 0;
     if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
       file_offset = extinfo->library_fd_offset;
     }
-    return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+
+    if (!realpath_fd(extinfo->library_fd, &realpath)) {
+      PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
+            "Will use given name.", name);
+      realpath = name;
+    }
+    return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo, realpath);
   }
 
   // Open the file.
-  off64_t file_offset;
-  int fd = open_library(name, needed_by, &file_offset);
+  int fd = open_library(zip_archive_cache, name, needed_by, &file_offset, &realpath);
   if (fd == -1) {
     DL_ERR("library \"%s\" not found", name);
     return nullptr;
   }
-  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo, realpath);
   close(fd);
   return result;
 }
@@ -1427,7 +1505,8 @@
   return false;
 }
 
-static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
+static soinfo* find_library_internal(ZipArchiveCache* zip_archive_cache,
+                                     LoadTaskList& load_tasks, const char* name,
                                      soinfo* needed_by, int rtld_flags,
                                      const android_dlextinfo* extinfo) {
   soinfo* candidate;
@@ -1441,7 +1520,7 @@
   TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
       name, candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
 
-  soinfo* si = load_library(load_tasks, name, needed_by, rtld_flags, extinfo);
+  soinfo* si = load_library(zip_archive_cache, load_tasks, name, needed_by, rtld_flags, extinfo);
 
   // In case we were unable to load the library but there
   // is a candidate loaded under the same soname but different
@@ -1521,15 +1600,18 @@
     }
   });
 
+  ZipArchiveCache zip_archive_cache;
+
   // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
   for (LoadTask::unique_ptr task(load_tasks.pop_front());
       task.get() != nullptr; task.reset(load_tasks.pop_front())) {
     soinfo* needed_by = task->get_needed_by();
     bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
 
-    soinfo* si = find_library_internal(load_tasks, task->get_name(), needed_by,
-                                       rtld_flags,
+    soinfo* si = find_library_internal(&zip_archive_cache, load_tasks,
+                                       task->get_name(), needed_by, rtld_flags,
                                        is_dt_needed ? nullptr : extinfo);
+
     if (si == nullptr) {
       return false;
     }
@@ -1656,7 +1738,7 @@
           }
         }
       } else {
-#if !defined(__work_around_b_19059885__)
+#if !defined(__work_around_b_24465209__)
         __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
 #else
         PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
@@ -2435,7 +2517,7 @@
 }
 
 const char* soinfo::get_realpath() const {
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
   if (has_min_version(2)) {
     return realpath_.c_str();
   } else {
@@ -2447,7 +2529,7 @@
 }
 
 const char* soinfo::get_soname() const {
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
   if (has_min_version(2)) {
     return soname_;
   } else {
@@ -2978,7 +3060,7 @@
     switch (d->d_tag) {
       case DT_SONAME:
         soname_ = get_string(d->d_un.d_val);
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
         strlcpy(old_name_, soname_, sizeof(old_name_));
 #endif
         break;
@@ -3025,14 +3107,13 @@
 #if !defined(__LP64__)
   if (has_text_relocations) {
     // Fail if app is targeting sdk version > 22
-    // TODO (dimitry): remove != __ANDROID_API__ check once http://b/20020312 is fixed
-    if (get_application_target_sdk_version() != __ANDROID_API__
-        && get_application_target_sdk_version() > 22) {
+    if (get_application_target_sdk_version() > 22) {
+      PRINT("%s: has text relocations", get_realpath());
       DL_ERR("%s: has text relocations", get_realpath());
       return false;
     }
     // Make segments writable to allow text relocations to work properly. We will later call
-    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
+    // phdr_table_protect_segments() after all of them are applied.
     DL_WARN("%s has text relocations. This is wasting memory and prevents "
             "security hardening. Please fix.", get_realpath());
     if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
@@ -3504,6 +3585,9 @@
 
   __libc_init_main_thread(args);
 
+  // Initialize the linker's static libc's globals
+  __libc_init_globals(args);
+
   // Initialize the linker's own global variables
   linker_so.call_constructors();
 
diff --git a/linker/linker.h b/linker/linker.h
index 6f8bf1f..39d3ff1 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -88,7 +88,7 @@
 
 #define SOINFO_VERSION 2
 
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
 #define SOINFO_NAME_LEN 128
 #endif
 
@@ -163,7 +163,7 @@
 struct soinfo {
  public:
   typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
  private:
   char old_name_[SOINFO_NAME_LEN];
 #endif
@@ -174,13 +174,13 @@
   ElfW(Addr) base;
   size_t size;
 
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
   uint32_t unused1;  // DO NOT USE, maintained for compatibility.
 #endif
 
   ElfW(Dyn)* dynamic;
 
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
   uint32_t unused2; // DO NOT USE, maintained for compatibility
   uint32_t unused3; // DO NOT USE, maintained for compatibility
 #endif
@@ -298,7 +298,7 @@
   bool is_gnu_hash() const;
 
   bool inline has_min_version(uint32_t min_version __unused) const {
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
     return (flags_ & FLAG_NEW_SOINFO) != 0 && version_ >= min_version;
 #else
     return true;
diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp
index 4dc97c8..27fb68b 100644
--- a/linker/linker_mips.cpp
+++ b/linker/linker_mips.cpp
@@ -230,7 +230,7 @@
   uint16_t version;  // version of this structure
   uint8_t  isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size;
   uint8_t  fp_abi;  // mips32 ABI variants for floating point
-  uint16_t isa_ext, ases, flags1, flags2;
+  uint32_t isa_ext, ases, flags1, flags2;
 };
 
 // Bits of flags1:
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
new file mode 100644
index 0000000..5d39d83
--- /dev/null
+++ b/linker/linker_utils.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "linker_utils.h"
+#include "linker_debug.h"
+
+bool normalize_path(const char* path, std::string* normalized_path) {
+  // Input should be an absolute path
+  if (path[0] != '/') {
+    PRINT("canonize_path - invalid input: '%s', the input path should be absolute", path);
+    return false;
+  }
+
+  const size_t len = strlen(path) + 1;
+  char buf[len];
+
+  const char* in_ptr = path;
+  char* out_ptr = buf;
+
+  while (*in_ptr != 0) {
+    if (*in_ptr == '/') {
+      char c1 = in_ptr[1];
+      if (c1 == '.') {
+        char c2 = in_ptr[2];
+        if (c2 == '/') {
+          in_ptr += 2;
+          continue;
+        } else if (c2 == '.' && (in_ptr[3] == '/' || in_ptr[3] == 0)) {
+          in_ptr += 3;
+          while (out_ptr > buf && *--out_ptr != '/') {
+          }
+          if (in_ptr[0] == 0) {
+            // retain '/'
+            out_ptr++;
+          }
+          continue;
+        }
+      } else if (c1 == '/') {
+        ++in_ptr;
+        continue;
+      }
+    }
+    *out_ptr++ = *in_ptr++;
+  }
+
+  *out_ptr = 0;
+  *normalized_path = buf;
+  return true;
+}
+
diff --git a/libc/upstream-freebsd/android/include/spinlock.h b/linker/linker_utils.h
similarity index 72%
copy from libc/upstream-freebsd/android/include/spinlock.h
copy to linker/linker_utils.h
index f5c3785..fc79fd1 100644
--- a/libc/upstream-freebsd/android/include/spinlock.h
+++ b/linker/linker_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#ifndef __LINKER_UTILS_H
+#define __LINKER_UTILS_H
 
-#ifndef _BIONIC_FREEBSD_SPINLOCK_H_included
-#define _BIONIC_FREEBSD_SPINLOCK_H_included
+#include <string>
 
-/* TODO: until we have the FreeBSD findfp.c, this is useless. */
+bool normalize_path(const char* path, std::string* normalized_path);
 
 #endif
diff --git a/linker/tests/Android.mk b/linker/tests/Android.mk
index 0aaee3e..a061877 100644
--- a/linker/tests/Android.mk
+++ b/linker/tests/Android.mk
@@ -27,11 +27,14 @@
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../libc/
 
 LOCAL_SRC_FILES := \
+  linker_globals.cpp \
   linked_list_test.cpp \
   linker_block_allocator_test.cpp \
   ../linker_block_allocator.cpp \
   linker_memory_allocator_test.cpp \
-  ../linker_allocator.cpp
+  ../linker_allocator.cpp \
+  linker_utils_test.cpp \
+  ../linker_utils.cpp
 
 # for __libc_fatal
 LOCAL_SRC_FILES += ../../libc/bionic/libc_logging.cpp
diff --git a/libc/upstream-freebsd/android/include/spinlock.h b/linker/tests/linker_globals.cpp
similarity index 78%
rename from libc/upstream-freebsd/android/include/spinlock.h
rename to linker/tests/linker_globals.cpp
index f5c3785..7762a87 100644
--- a/libc/upstream-freebsd/android/include/spinlock.h
+++ b/linker/tests/linker_globals.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_FREEBSD_SPINLOCK_H_included
-#define _BIONIC_FREEBSD_SPINLOCK_H_included
+// To enable logging
+int g_ld_debug_verbosity = 0;
 
-/* TODO: until we have the FreeBSD findfp.c, this is useless. */
-
-#endif
diff --git a/linker/tests/linker_memory_allocator_test.cpp b/linker/tests/linker_memory_allocator_test.cpp
index f002a0d..defd4f3 100644
--- a/linker/tests/linker_memory_allocator_test.cpp
+++ b/linker/tests/linker_memory_allocator_test.cpp
@@ -53,7 +53,7 @@
   LinkerMemoryAllocator allocator;
   void* ptr = allocator.alloc(0);
   ASSERT_TRUE(ptr != nullptr);
-  free(ptr);
+  allocator.free(ptr);
 }
 
 TEST(linker_memory, test_free_nullptr) {
@@ -110,7 +110,7 @@
 
   ASSERT_TRUE(memcmp(reallocated_ptr, model, 4000) == 0);
 
-  ASSERT_EQ(nullptr, realloc(reallocated_ptr, 0));
+  ASSERT_EQ(nullptr, allocator.realloc(reallocated_ptr, 0));
 }
 
 TEST(linker_memory, test_small_smoke) {
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
new file mode 100644
index 0000000..458474e
--- /dev/null
+++ b/linker/tests/linker_utils_test.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include "../linker_utils.h"
+
+TEST(linker_utils, normalize_path_smoke) {
+  std::string output;
+  ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
+  ASSERT_EQ("/root/dir/dir2/zipfile!/dir/afile", output);
+
+  ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/.../zipfile!/.dir/dir9//..///afile", &output));
+  ASSERT_EQ("/root/dir/dir2/somedir/.../zipfile!/.dir/afile", output);
+
+  ASSERT_TRUE(normalize_path("/root/..", &output));
+  ASSERT_EQ("/", output);
+
+  ASSERT_TRUE(normalize_path("/root/notroot/..", &output));
+  ASSERT_EQ("/root/", output);
+
+  ASSERT_TRUE(normalize_path("/a/../../b", &output));
+  ASSERT_EQ("/b", output);
+
+  output = "unchanged";
+  ASSERT_FALSE(normalize_path("root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
+  ASSERT_EQ("unchanged", output);
+}
diff --git a/tests/Android.mk b/tests/Android.mk
index 3f2fb91..e2c4fb4 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -69,6 +69,7 @@
     math_test.cpp \
     mntent_test.cpp \
     netdb_test.cpp \
+    netinet_udp_test.cpp \
     pthread_test.cpp \
     pty_test.cpp \
     regex_test.cpp \
@@ -252,7 +253,7 @@
 
 libBionicCtsGtestMain_cflags := $(test_cflags)
 
-libBionicCtsGtestMain_cppflags := $(test_cppflags) -DUSING_GTEST_OUTPUT_FORMAT
+libBionicCtsGtestMain_cppflags := $(test_cppflags) -DUSING_GTEST_OUTPUT_FORMAT \
 
 module := libBionicCtsGtestMain
 module_tag := optional
@@ -300,7 +301,6 @@
 
 bionic-unit-tests_c_includes := \
     bionic/libc \
-    $(call include-path-for, libpagemap) \
 
 bionic-unit-tests_shared_libraries_target := \
     libdl \
@@ -420,6 +420,8 @@
 LOCAL_CLANG := false
 LOCAL_MODULE := bionic-compile-time-tests-g++
 LOCAL_CPPFLAGS := -Wall
+# Disable color diagnostics so the warnings output matches the source
+LOCAL_CPPFLAGS +=  -fdiagnostics-color=never
 LOCAL_SRC_FILES := fortify_compilation_test.cpp
 include $(BUILD_STATIC_LIBRARY)
 
@@ -437,6 +439,8 @@
 LOCAL_CLANG := true
 LOCAL_MODULE := bionic-compile-time-tests-clang++
 LOCAL_CPPFLAGS := -Wall
+# Disable color diagnostics so the warnings output matches the source
+LOCAL_CPPFLAGS += -fno-color-diagnostics
 # FileCheck will error if there aren't any CLANG: lines in the file, but there
 # don't appear to be any cases where clang _does_ emit warnings for sn?printf :(
 LOCAL_SRC_FILES :=
@@ -450,6 +454,7 @@
 # Make sure to create ANDROID_DATA/local/tmp if doesn't exist.
 # Use the current target out directory as ANDROID_DATA.
 # BIONIC_TEST_FLAGS is either empty or it comes from the user.
+.PHONY: bionic-unit-tests-glibc-run
 bionic-unit-tests-glibc-run: bionic-unit-tests-glibc
 	mkdir -p $(TARGET_OUT_DATA)/local/tmp
 	ANDROID_DATA=$(TARGET_OUT_DATA) \
@@ -467,6 +472,7 @@
 TEST_TIMEOUT := 0
 
 # BIONIC_TEST_FLAGS is either empty or it comes from the user.
+.PHONY: bionic-unit-tests-run-on-host32
 bionic-unit-tests-run-on-host32: bionic-unit-tests bionic-prepare-run-on-host
 	ANDROID_DATA=$(TARGET_OUT_DATA) \
 	ANDROID_DNS_MODE=local \
@@ -476,6 +482,7 @@
 
 ifeq ($(TARGET_IS_64_BIT),true)
 # add target to run lp64 tests
+.PHONY: bionic-unit-tests-run-on-host64
 bionic-unit-tests-run-on-host64: bionic-unit-tests bionic-prepare-run-on-host
 	ANDROID_DATA=$(TARGET_OUT_DATA) \
 	ANDROID_DNS_MODE=local \
diff --git a/tests/arpa_inet_test.cpp b/tests/arpa_inet_test.cpp
index 5e53337..a368b8f 100644
--- a/tests/arpa_inet_test.cpp
+++ b/tests/arpa_inet_test.cpp
@@ -24,8 +24,85 @@
 
 TEST(arpa_inet, inet_aton) {
   in_addr a;
-  ASSERT_EQ(1, inet_aton("127.0.0.1", &a));
+
+  // a.b.c.d
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1.2.3", &a));
+  ASSERT_EQ((htonl)(0x7f010203), a.s_addr);
+
+  // a.b.c
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1.2", &a));
+  ASSERT_EQ((htonl)(0x7f010002), a.s_addr);
+
+  // a.b
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1", &a));
   ASSERT_EQ((htonl)(0x7f000001), a.s_addr);
+
+  // a
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0x7f000001", &a));
+  ASSERT_EQ((htonl)(0x7f000001), a.s_addr);
+
+  // Hex (0x) and mixed-case hex digits.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0xFf.0.0.1", &a));
+  ASSERT_EQ((htonl)(0xff000001), a.s_addr);
+
+  // Hex (0X) and mixed-case hex digits.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0XfF.0.0.1", &a));
+  ASSERT_EQ((htonl)(0xff000001), a.s_addr);
+
+  // Octal.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0177.0.0.1", &a));
+  ASSERT_EQ((htonl)(0x7f000001), a.s_addr);
+
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("036", &a));
+  ASSERT_EQ((htonl)(036U), a.s_addr);
+}
+
+TEST(arpa_inet, inet_aton_nullptr) {
+  ASSERT_EQ(0, inet_aton("", nullptr));
+  ASSERT_EQ(1, inet_aton("127.0.0.1", nullptr));
+}
+
+TEST(arpa_inet, inet_aton_invalid) {
+  ASSERT_EQ(0, inet_aton("", nullptr)); // Empty.
+  ASSERT_EQ(0, inet_aton("x", nullptr)); // Leading junk.
+  ASSERT_EQ(0, inet_aton("127.0.0.1x", nullptr)); // Trailing junk.
+  ASSERT_EQ(0, inet_aton("09.0.0.1", nullptr)); // Invalid octal.
+  ASSERT_EQ(0, inet_aton("0xg.0.0.1", nullptr)); // Invalid hex.
+
+  ASSERT_EQ(0, inet_aton("1.2.3.4.5", nullptr)); // Too many dots.
+  ASSERT_EQ(0, inet_aton("1.2.3.4.", nullptr)); // Trailing dot.
+
+  // Out of range a.b.c.d form.
+  ASSERT_EQ(0, inet_aton("999.0.0.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.999.0.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.999.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.0.999", nullptr));
+
+  // Out of range a.b.c form.
+  ASSERT_EQ(0, inet_aton("256.0.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.256.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.0x10000", nullptr));
+
+  // Out of range a.b form.
+  ASSERT_EQ(0, inet_aton("256.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0x1000000", nullptr));
+
+  // Out of range a form.
+  ASSERT_EQ(0, inet_aton("0x100000000", nullptr));
+
+  // 64-bit overflow.
+  ASSERT_EQ(0, inet_aton("0x10000000000000000", nullptr));
+
+  // Out of range octal.
+  ASSERT_EQ(0, inet_aton("0400.0.0.1", nullptr));
 }
 
 TEST(arpa_inet, inet_lnaof) {
@@ -45,6 +122,8 @@
 
 TEST(arpa_inet, inet_network) {
   ASSERT_EQ(0x7f000001U, inet_network("127.0.0.1"));
+  ASSERT_EQ(0x7fU, inet_network("0x7f"));
+  ASSERT_EQ(~0U, inet_network(""));
 }
 
 TEST(arpa_inet, inet_ntoa) {
diff --git a/tests/buffer_tests.cpp b/tests/buffer_tests.cpp
index 7d830bb..a5a0c2a 100644
--- a/tests/buffer_tests.cpp
+++ b/tests/buffer_tests.cpp
@@ -381,15 +381,19 @@
   // Make the second page unreadable and unwritable.
   ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_NONE) == 0);
 
-  uint8_t* dst = new uint8_t[pagesize];
-  for (size_t i = 0; i < pagesize; i++) {
-    uint8_t* src = &memory[pagesize-i];
+  uint8_t* dst_buffer = new uint8_t[2*pagesize];
+  // Change the dst alignment as we change the source.
+  for (size_t i = 0; i < 16; i++) {
+    uint8_t* dst = &dst_buffer[i];
+    for (size_t j = 0; j < pagesize; j++) {
+      uint8_t* src = &memory[pagesize-j];
 
-    test_func(src, dst, i);
+      test_func(src, dst, j);
+    }
   }
   ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
   free(memory);
-  delete[] dst;
+  delete[] dst_buffer;
 }
 
 void RunCmpBufferOverreadTest(
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 44b899e..d5a5e56 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -52,15 +52,16 @@
 #define LIBSIZE 1024*1024 // how much address space to reserve for it
 
 #if defined(__LP64__)
-#define LIBPATH_PREFIX "/nativetest64/libdlext_test_fd/"
+#define LIBPATH_PREFIX "/nativetest64/"
 #else
-#define LIBPATH_PREFIX "/nativetest/libdlext_test_fd/"
+#define LIBPATH_PREFIX "/nativetest/"
 #endif
 
-#define LIBPATH LIBPATH_PREFIX "libdlext_test_fd.so"
-#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_fd_zipaligned.zip"
+#define LIBPATH LIBPATH_PREFIX "libdlext_test_fd/libdlext_test_fd.so"
+#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_zip/libdlext_test_zip_zipaligned.zip"
+#define LIBZIPPATH_WITH_RUNPATH LIBPATH_PREFIX "libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip"
 
-#define LIBZIP_OFFSET 2*PAGE_SIZE
+#define LIBZIP_OFFSET PAGE_SIZE
 
 class DlExtTest : public ::testing::Test {
 protected:
@@ -131,9 +132,9 @@
   handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo);
   ASSERT_DL_NOTNULL(handle_);
 
-  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
-  ASSERT_DL_NOTNULL(f);
-  EXPECT_EQ(4, f());
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
 }
 
 TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
@@ -163,7 +164,7 @@
   ASSERT_TRUE(handle_ == nullptr);
   ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" is negative", dlerror());
 
-  extinfo.library_fd_offset = PAGE_SIZE;
+  extinfo.library_fd_offset = 0;
   handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle_ == nullptr);
   ASSERT_EQ("dlopen failed: \"" + lib_realpath + "\" has bad ELF magic", dlerror());
@@ -218,17 +219,34 @@
 TEST(dlfcn, dlopen_from_zip_absolute_path) {
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
 
-  void* handle = dlopen((lib_path + "!/libdir/libdlext_test_fd.so").c_str(), RTLD_NOW);
+  void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
-  int (*fn)(void);
-  fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
-  ASSERT_TRUE(fn != nullptr);
-  EXPECT_EQ(4, fn());
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
 
   dlclose(handle);
 }
 
+TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH_WITH_RUNPATH;
+
+  void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW);
+
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef void *(* dlopen_b_fn)();
+  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+
+  void *p = fn();
+  ASSERT_TRUE(p != nullptr) << dlerror();
+
+  dlclose(p);
+  dlclose(handle);
+}
+
 TEST(dlfcn, dlopen_from_zip_ld_library_path) {
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir";
 
@@ -238,12 +256,12 @@
 
   ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror();
 
-  void* handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
+  void* handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
   ASSERT_TRUE(handle == nullptr);
 
   android_update_LD_LIBRARY_PATH(lib_path.c_str());
 
-  handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
+  handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
   int (*fn)(void);
@@ -251,6 +269,10 @@
   ASSERT_TRUE(fn != nullptr);
   EXPECT_EQ(4, fn());
 
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
+
   dlclose(handle);
 }
 
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 00cbdc6..ed972ba 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -830,10 +830,11 @@
 }
 
 #if defined(__LP64__)
-#define BIONIC_PATH_TO_LIBC "/system/lib64/libc.so"
+#define PATH_TO_SYSTEM_LIB "/system/lib64/"
 #else
-#define BIONIC_PATH_TO_LIBC "/system/lib/libc.so"
+#define PATH_TO_SYSTEM_LIB "/system/lib/"
 #endif
+#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
 
 TEST(dlfcn, dladdr_libc) {
 #if defined(__BIONIC__)
@@ -843,7 +844,7 @@
 
   // /system/lib is symlink when this test is executed on host.
   char libc_realpath[PATH_MAX];
-  ASSERT_TRUE(realpath(BIONIC_PATH_TO_LIBC, libc_realpath) == libc_realpath);
+  ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath);
 
   ASSERT_STREQ(libc_realpath, info.dli_fname);
   // TODO: add check for dfi_fbase
@@ -1063,7 +1064,7 @@
   return 0;
 }
 
-TEST(dlfcn, dt_runpath) {
+TEST(dlfcn, dt_runpath_smoke) {
   void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
@@ -1076,3 +1077,17 @@
 
   dlclose(handle);
 }
+
+TEST(dlfcn, dt_runpath_absolute_path) {
+  void* handle = dlopen(PATH_TO_SYSTEM_LIB "libtest_dt_runpath_d.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef void *(* dlopen_b_fn)();
+  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+
+  void *p = fn();
+  ASSERT_TRUE(p != nullptr);
+
+  dlclose(handle);
+}
diff --git a/tests/file-check-cxx b/tests/file-check-cxx
index 8ece835..4018265 100755
--- a/tests/file-check-cxx
+++ b/tests/file-check-cxx
@@ -2,10 +2,10 @@
 FILECHECK=$1
 CXX=$2
 PREFIX=$3
-ARGS=${*:4}
-SOURCE=$(echo $ARGS | grep -oP '\S+\.cpp\b')
-OBJ=$(echo $ARGS | grep -oP '\S+\.o\b')
-$CXX $ARGS 2>&1 | $FILECHECK -check-prefix=$PREFIX $SOURCE
+shift 3
+SOURCE=$(echo "$@" | grep -oP '\S+\.cpp\b')
+OBJ=$(echo "$@" | grep -oP '\S+\.o\b')
+$CXX "$@" 2>&1 | $FILECHECK -check-prefix=$PREFIX $SOURCE
 if [ "$?" -eq 0 ]; then
   touch $OBJ
 else
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 6788a5d..3b9f6b9 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -69,7 +69,7 @@
 using testing::internal::COLOR_YELLOW;
 using testing::internal::ColoredPrintf;
 
-constexpr int DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS = 60000;
+constexpr int DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS = 90000;
 constexpr int DEFAULT_GLOBAL_TEST_RUN_WARNLINE_MS = 2000;
 
 // The time each test can run before killed for the reason of timeout.
@@ -100,7 +100,7 @@
          "      Don't use isolation mode, run all tests in a single process.\n"
          "  --deadline=[TIME_IN_MS]\n"
          "      Run each test in no longer than [TIME_IN_MS] time.\n"
-         "      It takes effect only in isolation mode. Deafult deadline is 60000 ms.\n"
+         "      It takes effect only in isolation mode. Deafult deadline is 90000 ms.\n"
          "  --warnline=[TIME_IN_MS]\n"
          "      Test running longer than [TIME_IN_MS] will be warned.\n"
          "      It takes effect only in isolation mode. Default warnline is 2000 ms.\n"
@@ -635,7 +635,7 @@
     sigquit_flag = false;
     // Print current running tests.
     printf("List of current running tests:\n");
-    for (auto& child_proc : child_proc_list) {
+    for (const auto& child_proc : child_proc_list) {
       if (child_proc.pid != 0) {
         std::string test_name = testcase_list[child_proc.testcase_id].GetTestName(child_proc.test_id);
         int64_t current_time_ns = NanoTime();
@@ -646,7 +646,7 @@
   } else if (sigint_flag) {
     sigint_flag = false;
     // Kill current running tests.
-    for (auto& child_proc : child_proc_list) {
+    for (const auto& child_proc : child_proc_list) {
       if (child_proc.pid != 0) {
         // Send SIGKILL to ensure the child process can be killed unconditionally.
         kill(child_proc.pid, SIGKILL);
@@ -877,7 +877,7 @@
   return all_tests_passed;
 }
 
-static size_t GetProcessorCount() {
+static size_t GetDefaultJobCount() {
   return static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
 }
 
@@ -988,7 +988,7 @@
   }
 
   // Init default isolation test options.
-  options.job_count = GetProcessorCount();
+  options.job_count = GetDefaultJobCount();
   options.test_deadline_ms = DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS;
   options.test_warnline_ms = DEFAULT_GLOBAL_TEST_RUN_WARNLINE_MS;
   options.gtest_color = testing::GTEST_FLAG(color);
diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk
index 7cc0dae..c06f4a9 100644
--- a/tests/libs/Android.build.dlext_testzip.mk
+++ b/tests/libs/Android.build.dlext_testzip.mk
@@ -21,21 +21,62 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_MODULE := libdlext_test_fd_zipaligned
+LOCAL_MODULE := libdlext_test_zip_zipaligned
 LOCAL_MODULE_SUFFIX := .zip
 LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_fd
+LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_zip
 LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
 my_shared_libs := \
-  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_fd.so
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_zip.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libatest_simple_zip.so
 
-$(LOCAL_BUILT_MODULE): PRIVATE_ALIGNMENT := 4096 # PAGE_SIZE
 $(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN)
-	@echo "Zipalign $(PRIVATE_ALIGNMENT): $@"
+	@echo "Zipalign: $@"
 	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir
 	$(hide) cp $^ $(dir $@)/libdir
-	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@).unaligned empty_file.txt libdir/*.so)
-	$(hide) $(ZIPALIGN) $(PRIVATE_ALIGNMENT) $@.unaligned $@
+	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir/*.so)
+	$(hide) $(ZIPALIGN) -p 4 $@.unaligned $@
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE := libdlext_test_runpath_zip_zipaligned
+LOCAL_MODULE_SUFFIX := .zip
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_runpath_zip
+LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
+
+include $(BUILD_SYSTEM)/base_rules.mk
+my_shared_libs := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so
+
+
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_D := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_A := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_B := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_C := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_X := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so
+$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN)
+	@echo "Zipalign: $@"
+	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir && \
+    mkdir -p $(dir $@)/libdir/dt_runpath_a && mkdir -p $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_D) $(dir $@)/libdir
+	$(hide) cp $(PRIVATE_LIB_A) $(dir $@)/libdir/dt_runpath_a
+	$(hide) cp $(PRIVATE_LIB_B) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_C) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_X) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir)
+	$(hide) $(ZIPALIGN) -p 4 $@.unaligned $@
+
diff --git a/tests/libs/Android.build.dt_runpath.mk b/tests/libs/Android.build.dt_runpath.mk
index 44c8125..4544bb1 100644
--- a/tests/libs/Android.build.dt_runpath.mk
+++ b/tests/libs/Android.build.dt_runpath.mk
@@ -18,6 +18,19 @@
 # Libraries used by dt_runpath tests.
 # -----------------------------------------------------------------------------
 
+#
+# Dependencies
+#
+# libtest_dt_runpath_d.so                       runpath: ${ORIGIN}/dt_runpath_b_c_x
+# |-> dt_runpath_b_c_x/libtest_dt_runpath_b.so  runpath: ${ORIGIN}/../dt_runpath_a
+# |   |-> dt_runpath_a/libtest_dt_runpath_a.so
+# |-> dt_runpath_b_c_x/libtest_dt_runpath_c.so  runpath: ${ORIGIN}/invalid_dt_runpath
+# |   |-> libtest_dt_runpath_a.so (soname)
+#
+# This one is used to test dlopen
+# dt_runpath_b_c_x/libtest_dt_runpath_x.so
+#
+
 # A leaf library in a non-standard directory.
 libtest_dt_runpath_a_src_files := \
     empty.cpp
@@ -57,6 +70,20 @@
 module := libtest_dt_runpath_d
 include $(LOCAL_PATH)/Android.build.testlib.mk
 
+# D version for open-from-zip test with runpath
+libtest_dt_runpath_d_zip_src_files := \
+    dlopen_b.cpp
+
+libtest_dt_runpath_d_zip_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
+libtest_dt_runpath_d_zip_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--enable-new-dtags
+libtest_dt_runpath_d_zip_install_to_out_data := true
+module := libtest_dt_runpath_d_zip
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(TEST_PATH)/Android.build.mk
+
+
 # A leaf library in a directory library D has DT_RUNPATH for.
 libtest_dt_runpath_x_src_files := \
     empty.cpp
@@ -64,3 +91,4 @@
 libtest_dt_runpath_x_relative_path := dt_runpath_b_c_x
 module := libtest_dt_runpath_x
 include $(LOCAL_PATH)/Android.build.testlib.mk
+
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index b13400e..3391d79 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -126,6 +126,32 @@
 build_target := SHARED_LIBRARY
 include $(TEST_PATH)/Android.build.mk
 
+
+# -----------------------------------------------------------------------------
+# Libraries used by dlext tests for open from a zip-file
+# -----------------------------------------------------------------------------
+libdlext_test_zip_src_files := \
+    dlext_test_library.cpp \
+
+libdlext_test_zip_shared_libraries := libatest_simple_zip
+
+libdlext_test_zip_install_to_out_data := true
+module := libdlext_test_zip
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(TEST_PATH)/Android.build.mk
+
+libatest_simple_zip_src_files := \
+    dlopen_testlib_simple.cpp
+
+libatest_simple_zip_install_to_out_data := true
+module := libatest_simple_zip
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(TEST_PATH)/Android.build.mk
+
 # ----------------------------------------------------------------------------
 # Library with soname which does not match filename
 # ----------------------------------------------------------------------------
diff --git a/tests/libs/dlopen_b.cpp b/tests/libs/dlopen_b.cpp
index 5291d81..cd81e16 100644
--- a/tests/libs/dlopen_b.cpp
+++ b/tests/libs/dlopen_b.cpp
@@ -4,8 +4,9 @@
   // remove once it is fixed
   static int dummy = 0;
 
-  // This is not supposed to succeed. Even though this library has DT_RUNPATH
-  // for libtest_dt_runpath_x.so, it is not taked into account for dlopen.
+  // This is supposed to succeed because this library has DT_RUNPATH
+  // for libtest_dt_runpath_x.so which should be taken into account
+  // by dlopen.
   void *handle = dlopen("libtest_dt_runpath_x.so", RTLD_NOW);
   if (handle != nullptr) {
     dummy++;
diff --git a/tests/netinet_udp_test.cpp b/tests/netinet_udp_test.cpp
new file mode 100644
index 0000000..661458e
--- /dev/null
+++ b/tests/netinet_udp_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <netinet/udp.h>
+
+#include <gtest/gtest.h>
+
+#if defined(__BIONIC__)
+  #define UDPHDR_USES_ANON_UNION
+#elif defined(__GLIBC_PREREQ)
+  #if __GLIBC_PREREQ(2, 18)
+    #define UDPHDR_USES_ANON_UNION
+  #endif
+#endif
+
+TEST(netinet_udp, compat) {
+#if defined(UDPHDR_USES_ANON_UNION)
+    static_assert(offsetof(udphdr, uh_sport) == offsetof(udphdr, source), "udphdr::source");
+    static_assert(offsetof(udphdr, uh_dport) == offsetof(udphdr, dest), "udphdr::dest");
+    static_assert(offsetof(udphdr, uh_ulen) == offsetof(udphdr, len), "udphdr::len");
+    static_assert(offsetof(udphdr, uh_sum) == offsetof(udphdr, check), "udphdr::check");
+
+    udphdr u;
+    u.uh_sport = 0x1111;
+    u.uh_dport = 0x2222;
+    u.uh_ulen = 0x3333;
+    u.uh_sum = 0x4444;
+    ASSERT_EQ(0x1111, u.source);
+    ASSERT_EQ(0x2222, u.dest);
+    ASSERT_EQ(0x3333, u.len);
+    ASSERT_EQ(0x4444, u.check);
+#endif
+}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index eeb1541..9f887e3 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -27,6 +27,7 @@
 #include <sys/syscall.h>
 #include <time.h>
 #include <unistd.h>
+#include <unwind.h>
 
 #include <atomic>
 #include <regex>
@@ -40,6 +41,8 @@
 #include "BionicDeathTest.h"
 #include "ScopedSignalHandler.h"
 
+#include "utils.h"
+
 extern "C" pid_t gettid();
 
 TEST(pthread, pthread_key_create) {
@@ -67,7 +70,7 @@
   std::vector<pthread_key_t> keys;
 
   auto scope_guard = make_scope_guard([&keys]{
-    for (auto key : keys) {
+    for (const auto& key : keys) {
       EXPECT_EQ(0, pthread_key_delete(key));
     }
   });
@@ -105,7 +108,7 @@
   }
 
   // Don't leak keys.
-  for (auto key : keys) {
+  for (const auto& key : keys) {
     EXPECT_EQ(0, pthread_key_delete(key));
   }
   keys.clear();
@@ -1157,19 +1160,14 @@
 #if defined(__BIONIC__)
   // What does /proc/self/maps' [stack] line say?
   void* maps_stack_hi = NULL;
-  FILE* fp = fopen("/proc/self/maps", "r");
-  ASSERT_TRUE(fp != NULL);
-  char line[BUFSIZ];
-  while (fgets(line, sizeof(line), fp) != NULL) {
-    uintptr_t lo, hi;
-    char name[10];
-    sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d %10s", &lo, &hi, name);
-    if (strcmp(name, "[stack]") == 0) {
-      maps_stack_hi = reinterpret_cast<void*>(hi);
+  std::vector<map_record> maps;
+  ASSERT_TRUE(Maps::parse_maps(&maps));
+  for (const auto& map : maps) {
+    if (map.pathname == "[stack]") {
+      maps_stack_hi = reinterpret_cast<void*>(map.addr_end);
       break;
     }
   }
-  fclose(fp);
 
   // The high address of the /proc/self/maps [stack] region should equal stack_base + stack_size.
   // Remember that the stack grows down (and is mapped in on demand), so the low address of the
@@ -1220,6 +1218,67 @@
 #endif
 }
 
+struct GetStackSignalHandlerArg {
+  volatile bool done;
+  void* signal_handler_sp;
+  void* main_stack_base;
+  size_t main_stack_size;
+};
+
+static GetStackSignalHandlerArg getstack_signal_handler_arg;
+
+static void getstack_signal_handler(int sig) {
+  ASSERT_EQ(SIGUSR1, sig);
+  // Use sleep() to make current thread be switched out by the kernel to provoke the error.
+  sleep(1);
+  pthread_attr_t attr;
+  ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attr));
+  void* stack_base;
+  size_t stack_size;
+  ASSERT_EQ(0, pthread_attr_getstack(&attr, &stack_base, &stack_size));
+  getstack_signal_handler_arg.signal_handler_sp = &attr;
+  getstack_signal_handler_arg.main_stack_base = stack_base;
+  getstack_signal_handler_arg.main_stack_size = stack_size;
+  getstack_signal_handler_arg.done = true;
+}
+
+// The previous code obtained the main thread's stack by reading the entry in
+// /proc/self/task/<pid>/maps that was labeled [stack]. Unfortunately, on x86/x86_64, the kernel
+// relies on sp0 in task state segment(tss) to label the stack map with [stack]. If the kernel
+// switches a process while the main thread is in an alternate stack, then the kernel will label
+// the wrong map with [stack]. This test verifies that when the above situation happens, the main
+// thread's stack is found correctly.
+TEST(pthread, pthread_attr_getstack_in_signal_handler) {
+  const size_t sig_stack_size = 16 * 1024;
+  void* sig_stack = mmap(NULL, sig_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
+                         -1, 0);
+  ASSERT_NE(MAP_FAILED, sig_stack);
+  stack_t ss;
+  ss.ss_sp = sig_stack;
+  ss.ss_size = sig_stack_size;
+  ss.ss_flags = 0;
+  stack_t oss;
+  ASSERT_EQ(0, sigaltstack(&ss, &oss));
+
+  ScopedSignalHandler handler(SIGUSR1, getstack_signal_handler, SA_ONSTACK);
+  getstack_signal_handler_arg.done = false;
+  kill(getpid(), SIGUSR1);
+  ASSERT_EQ(true, getstack_signal_handler_arg.done);
+
+  // Verify if the stack used by the signal handler is the alternate stack just registered.
+  ASSERT_LE(sig_stack, getstack_signal_handler_arg.signal_handler_sp);
+  ASSERT_GE(reinterpret_cast<char*>(sig_stack) + sig_stack_size,
+            getstack_signal_handler_arg.signal_handler_sp);
+
+  // Verify if the main thread's stack got in the signal handler is correct.
+  ASSERT_LE(getstack_signal_handler_arg.main_stack_base, &ss);
+  ASSERT_GE(reinterpret_cast<char*>(getstack_signal_handler_arg.main_stack_base) +
+            getstack_signal_handler_arg.main_stack_size, reinterpret_cast<void*>(&ss));
+
+  ASSERT_EQ(0, sigaltstack(&oss, nullptr));
+  ASSERT_EQ(0, munmap(sig_stack, sig_stack_size));
+}
+
 static void pthread_attr_getstack_18908062_helper(void*) {
   char local_variable;
   pthread_attr_t attributes;
@@ -1493,8 +1552,8 @@
   }
 
   ~StrictAlignmentAllocator() {
-    for (auto& p : allocated_array) {
-      delete [] p;
+    for (const auto& p : allocated_array) {
+      delete[] p;
     }
   }
 
@@ -1571,3 +1630,26 @@
   GTEST_LOG_(INFO) << "This test tests bionic implementation details on 64 bit devices.";
 #endif
 }
+
+extern _Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx, void* arg);
+
+static volatile bool signal_handler_on_altstack_done;
+
+static void SignalHandlerOnAltStack(int signo, siginfo_t*, void*) {
+  ASSERT_EQ(SIGUSR1, signo);
+  // Check if we have enough stack space for unwinding.
+  int count = 0;
+  _Unwind_Backtrace(FrameCounter, &count);
+  ASSERT_GT(count, 0);
+  // Check if we have enough stack space for logging.
+  std::string s(2048, '*');
+  GTEST_LOG_(INFO) << s;
+  signal_handler_on_altstack_done = true;
+}
+
+TEST(pthread, big_enough_signal_stack_for_64bit_arch) {
+  signal_handler_on_altstack_done = false;
+  ScopedSignalHandler handler(SIGUSR1, SignalHandlerOnAltStack, SA_SIGINFO | SA_ONSTACK);
+  kill(getpid(), SIGUSR1);
+  ASSERT_TRUE(signal_handler_on_altstack_done);
+}
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index a3b5885..c75ab51 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -212,3 +212,38 @@
     CHECK_FREGS;
   }
 }
+
+#if defined(__arm__)
+#define __JB_SIGFLAG 0
+#elif defined(__aarch64__)
+#define __JB_SIGFLAG 0
+#elif defined(__i386__)
+#define __JB_SIGFLAG 7
+#elif defined(__x86_64)
+#define __JB_SIGFLAG 8
+#elif defined(__mips__) && defined(__LP64__)
+#define __JB_SIGFLAG 1
+#elif defined(__mips__)
+#define __JB_SIGFLAG 2
+#endif
+
+TEST(setjmp, setjmp_cookie) {
+  jmp_buf jb;
+  int value = setjmp(jb);
+  ASSERT_EQ(0, value);
+
+#if defined(__mips__) && !defined(__LP64__)
+  // round address to 8-byte boundry
+  uintptr_t jb_aligned = reinterpret_cast<uintptr_t>(jb) & ~7L;
+  long* sigflag = reinterpret_cast<long*>(jb_aligned) + __JB_SIGFLAG;
+#else
+  long* sigflag = reinterpret_cast<long*>(jb) + __JB_SIGFLAG;
+#endif
+
+  // Make sure there's actually a cookie.
+  EXPECT_NE(0, *sigflag & ~1);
+
+  // Wipe it out
+  *sigflag &= 1;
+  EXPECT_DEATH(longjmp(jb, 0), "");
+}
diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp
index d1b3402..afd9e7f 100644
--- a/tests/stack_unwinding_test.cpp
+++ b/tests/stack_unwinding_test.cpp
@@ -34,7 +34,7 @@
 #define noinline __attribute__((__noinline__))
 #define __unused __attribute__((__unused__))
 
-static _Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx __unused, void* arg) {
+_Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx __unused, void* arg) {
   int* count_ptr = reinterpret_cast<int*>(arg);
 
 #if SHOW_FRAME_LOCATIONS
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 62677cd..afb1511 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -1012,3 +1012,39 @@
 
   fclose(fp);
 }
+
+// https://code.google.com/p/android/issues/detail?id=184847
+TEST(stdio, fread_EOF_184847) {
+  TemporaryFile tf;
+  char buf[6] = {0};
+
+  FILE* fw = fopen(tf.filename, "w");
+  ASSERT_TRUE(fw != nullptr);
+
+  FILE* fr = fopen(tf.filename, "r");
+  ASSERT_TRUE(fr != nullptr);
+
+  fwrite("a", 1, 1, fw);
+  fflush(fw);
+  ASSERT_EQ(1U, fread(buf, 1, 1, fr));
+  ASSERT_STREQ("a", buf);
+
+  // 'fr' is now at EOF.
+  ASSERT_EQ(0U, fread(buf, 1, 1, fr));
+  ASSERT_TRUE(feof(fr));
+
+  // Write some more...
+  fwrite("z", 1, 1, fw);
+  fflush(fw);
+
+  // ...and check that we can read it back.
+  // (BSD thinks that once a stream has hit EOF, it must always return EOF. SysV disagrees.)
+  ASSERT_EQ(1U, fread(buf, 1, 1, fr));
+  ASSERT_STREQ("z", buf);
+
+  // But now we're done.
+  ASSERT_EQ(0U, fread(buf, 1, 1, fr));
+
+  fclose(fr);
+  fclose(fw);
+}
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 80190d7..842e1c7 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -1174,7 +1174,7 @@
   return 1;
 }
 
-#define STRCAT_DST_LEN  128
+#define STRCAT_DST_LEN  64
 
 static void DoStrcatTest(uint8_t* src, uint8_t* dst, size_t len) {
   if (len >= 1) {
@@ -1189,7 +1189,7 @@
       int value2 = 32 + (value + 2) % 96;
       memset(cmp_buf, value2, sizeof(cmp_buf));
 
-      for (size_t i = 1; i <= STRCAT_DST_LEN; i++) {
+      for (size_t i = 1; i <= STRCAT_DST_LEN;) {
         memset(dst, value2, i-1);
         memset(dst+i-1, 0, len-i);
         src[len-i] = '\0';
@@ -1197,6 +1197,13 @@
                                                          reinterpret_cast<char*>(src))));
         ASSERT_TRUE(memcmp(dst, cmp_buf, i-1) == 0);
         ASSERT_TRUE(memcmp(src, dst+i-1, len-i+1) == 0);
+        // This is an expensive loop, so don't loop through every value,
+        // get to a certain size and then start doubling.
+        if (i < 16) {
+          i++;
+        } else {
+          i <<= 1;
+        }
       }
     } else {
       dst[0] = '\0';
@@ -1229,7 +1236,7 @@
       int value2 = 32 + (value + 2) % 96;
       memset(cmp_buf, value2, sizeof(cmp_buf));
 
-      for (size_t i = 1; i <= STRCAT_DST_LEN; i++) {
+      for (size_t i = 1; i <= STRCAT_DST_LEN;) {
         memset(dst, value2, i-1);
         memset(dst+i-1, 0, len-i);
         src[len-i] = '\0';
@@ -1237,6 +1244,13 @@
                                  reinterpret_cast<char*>(src), len));
         ASSERT_TRUE(memcmp(dst, cmp_buf, i-1) == 0);
         ASSERT_TRUE(memcmp(src, dst+i-1, len-i+1) == 0);
+        // This is an expensive loop, so don't loop through every value,
+        // get to a certain size and then start doubling.
+        if (i < 16) {
+          i++;
+        } else {
+          i <<= 1;
+        }
       }
     } else {
       dst[0] = '\0';
diff --git a/tests/stubs_test.cpp b/tests/stubs_test.cpp
index 2d1bdee..c81ca58 100644
--- a/tests/stubs_test.cpp
+++ b/tests/stubs_test.cpp
@@ -122,6 +122,14 @@
   check_get_passwd("radio", 1001, TYPE_SYSTEM);
 }
 
+TEST(getpwnam, oem_id_0) {
+  check_get_passwd("oem_0", 5000, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, oem_id_999) {
+  check_get_passwd("oem_999", 5999, TYPE_SYSTEM);
+}
+
 TEST(getpwnam, app_id_nobody) {
   check_get_passwd("nobody", 9999, TYPE_SYSTEM);
 }
@@ -247,6 +255,14 @@
   check_get_group("radio", 1001);
 }
 
+TEST(getgrnam, oem_id_0) {
+  check_get_group("oem_0", 5000);
+}
+
+TEST(getgrnam, oem_id_999) {
+  check_get_group("oem_999", 5999);
+}
+
 TEST(getgrnam, app_id_nobody) {
   check_get_group("nobody", 9999);
 }
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 052997a..c685e94 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -296,8 +296,8 @@
   Counter counter(Counter::CountAndDisarmNotifyFunction);
   ASSERT_EQ(0, counter.Value());
 
-  counter.SetTime(0, 1, 1, 0);
-  usleep(500000);
+  counter.SetTime(0, 500000000, 1, 0);
+  sleep(1);
 
   // The count should just be 1 because we disarmed the timer the first time it fired.
   ASSERT_EQ(1, counter.Value());
@@ -381,8 +381,8 @@
   ASSERT_EQ(0, counter2.Value());
   ASSERT_EQ(0, counter3.Value());
 
-  counter2.SetTime(0, 1, 0, 0);
-  usleep(500000);
+  counter2.SetTime(0, 500000000, 0, 0);
+  sleep(1);
 
   EXPECT_EQ(0, counter1.Value());
   EXPECT_EQ(1, counter2.Value());
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 8e1f412..0a97abc 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -30,6 +30,11 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <base/file.h>
+#include <base/strings.h>
+
+#include "private/get_cpu_count_from_string.h"
+
 static void* get_brk() {
   return sbrk(0);
 }
@@ -819,6 +824,28 @@
 #endif // defined(__BIONIC__)
 }
 
+TEST(unistd, get_cpu_count_from_string) {
+  ASSERT_EQ(0, GetCpuCountFromString(" "));
+  ASSERT_EQ(1, GetCpuCountFromString("0"));
+  ASSERT_EQ(40, GetCpuCountFromString("0-39"));
+  ASSERT_EQ(4, GetCpuCountFromString("0, 1-2, 4\n"));
+}
+
+TEST(unistd, sysconf_SC_NPROCESSORS_ONLN) {
+  std::string line;
+  ASSERT_TRUE(android::base::ReadFileToString("/sys/devices/system/cpu/online", &line));
+  long online_cpus = 0;
+  for (const std::string& s : android::base::Split(line, ",")) {
+    std::vector<std::string> numbers = android::base::Split(s, "-");
+    if (numbers.size() == 1u) {
+      online_cpus++;
+    } else {
+      online_cpus += atoi(numbers[1].c_str()) - atoi(numbers[0].c_str()) + 1;
+    }
+  }
+  ASSERT_EQ(online_cpus, sysconf(_SC_NPROCESSORS_ONLN));
+}
+
 TEST(unistd, dup2_same) {
   // POSIX says of dup2:
   // If fildes2 is already a valid open file descriptor ...
diff --git a/tests/utils.h b/tests/utils.h
index fd012a3..53cf6b6 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -38,9 +38,7 @@
 class Maps {
  public:
   static bool parse_maps(std::vector<map_record>* maps) {
-    char path[64];
-    snprintf(path, sizeof(path), "/proc/self/task/%d/maps", getpid());
-    FILE* fp = fopen(path, "re");
+    FILE* fp = fopen("/proc/self/maps", "re");
     if (fp == nullptr) {
       return false;
     }
@@ -53,11 +51,11 @@
     while (fgets(line, sizeof(line), fp) != nullptr) {
       map_record record;
       uint32_t dev_major, dev_minor;
-      char pathstr[BUFSIZ];
+      int path_offset;
       char prot[5]; // sizeof("rwxp")
-      if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %x:%x %lu %s",
+      if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %x:%x %lu %n",
             &record.addr_start, &record.addr_end, prot, &record.offset,
-            &dev_major, &dev_minor, &record.inode, pathstr) == 8) {
+            &dev_major, &dev_minor, &record.inode, &path_offset) == 7) {
         record.perms = 0;
         if (prot[0] == 'r') {
           record.perms |= PROT_READ;
@@ -72,7 +70,10 @@
         // TODO: parse shared/private?
 
         record.device = makedev(dev_major, dev_minor);
-        record.pathname = pathstr;
+        record.pathname = line + path_offset;
+        if (!record.pathname.empty() && record.pathname.back() == '\n') {
+          record.pathname.pop_back();
+        }
         maps->push_back(record);
       }
     }
diff --git a/tools/relocation_packer/src/elf_file.cc b/tools/relocation_packer/src/elf_file.cc
index 4004239..014883d 100644
--- a/tools/relocation_packer/src/elf_file.cc
+++ b/tools/relocation_packer/src/elf_file.cc
@@ -739,7 +739,7 @@
   VLOG(1) << "Packed         (no padding): " << packed_bytes_estimate << " bytes";
 
   if (packed.empty()) {
-    LOG(INFO) << "Too few relocations to pack";
+    VLOG(1) << "Too few relocations to pack";
     return true;
   }
 
@@ -752,16 +752,16 @@
   // hole_size needs to be page_aligned.
   hole_size -= hole_size % kPreserveAlignment;
 
-  LOG(INFO) << "Compaction                 : " << hole_size << " bytes";
+  VLOG(1) << "Compaction                 : " << hole_size << " bytes";
 
   // Adjusting for alignment may have removed any packing benefit.
   if (hole_size == 0) {
-    LOG(INFO) << "Too few relocations to pack after alignment";
+    VLOG(1) << "Too few relocations to pack after alignment";
     return true;
   }
 
   if (hole_size <= 0) {
-    LOG(INFO) << "Packing relocations saves no space";
+    VLOG(1) << "Packing relocations saves no space";
     return true;
   }