merge from open-source master

Change-Id: If77618a329fc7b497c44c2585e644bc50e7e1406
diff --git a/.gitignore b/.gitignore
index 0db5b03..5a5ea87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 *.pyc
+*.*~
 libc/kernel/original
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2007 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/libc/Android.mk b/libc/Android.mk
index f627640..d8cc721 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -26,6 +26,7 @@
 	unistd/initgroups.c \
 	unistd/isatty.c \
 	unistd/issetugid.c \
+	unistd/killpg.c \
 	unistd/lseek64.c \
 	unistd/mmap.c \
 	unistd/nice.c \
@@ -46,7 +47,10 @@
 	unistd/sbrk.c \
 	unistd/send.c \
 	unistd/setegid.c \
+	unistd/setuid.c \
 	unistd/seteuid.c \
+	unistd/setreuid.c \
+	unistd/setresuid.c \
 	unistd/setpgrp.c \
 	unistd/sigblock.c \
 	unistd/siginterrupt.c \
@@ -215,14 +219,19 @@
 	bionic/__errno.c \
 	bionic/__set_errno.c \
 	bionic/_rand48.c \
+	bionic/cpuacct.c \
 	bionic/arc4random.c \
 	bionic/basename.c \
 	bionic/basename_r.c \
+	bionic/clearenv.c \
 	bionic/dirname.c \
 	bionic/dirname_r.c \
 	bionic/drand48.c \
 	bionic/erand48.c \
+	bionic/err.c \
+	bionic/fdprintf.c \
 	bionic/fork.c \
+	bionic/fts.c \
 	bionic/if_nametoindex.c \
 	bionic/if_indextoname.c \
 	bionic/ioctl.c \
@@ -270,13 +279,18 @@
 	netbsd/nameser/ns_ttl.c \
 	netbsd/nameser/ns_netint.c \
 	netbsd/nameser/ns_print.c \
-	netbsd/nameser/ns_samedomain.c
+	netbsd/nameser/ns_samedomain.c \
+	regex/regcomp.c \
+	regex/regerror.c \
+	regex/regexec.c \
+	regex/regfree.c \
 
 # Architecture specific source files go here
 # =========================================================
 ifeq ($(TARGET_ARCH),arm)
 libc_common_src_files += \
 	bionic/eabi.c \
+	bionic/bionic_clone.c \
 	arch-arm/bionic/__get_pc.S \
 	arch-arm/bionic/__get_sp.S \
 	arch-arm/bionic/_exit_with_stack_teardown.S \
@@ -398,7 +412,16 @@
 		-DNEED_PSELECT=1		\
 		-DINET6 \
 		-I$(LOCAL_PATH)/private \
-		-DUSE_DL_PREFIX
+		-DUSE_DL_PREFIX \
+		-DPOSIX_MISTAKE
+
+# these macro definitions are required to implement the
+# 'timezone' and 'daylight' global variables, as well as
+# properly update the 'tm_gmtoff' field in 'struct tm'.
+#
+libc_common_cflags += \
+    -DTM_GMTOFF=tm_gmtoff \
+    -DUSG_COMPAT=1
 
 ifeq ($(strip $(DEBUG_BIONIC_LIBC)),true)
   libc_common_cflags += -DDEBUG
@@ -532,17 +555,12 @@
 LOCAL_SRC_FILES := \
 	$(libc_arch_static_src_files) \
 	bionic/dlmalloc.c \
+	bionic/malloc_debug_common.c \
 	bionic/libc_init_static.c
 
-LOCAL_CFLAGS := $(libc_common_cflags)
-
-ifeq ($(WITH_MALLOC_CHECK_LIBC_A),true)
-  LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-  LOCAL_SRC_FILES += bionic/malloc_leak.c.arm
-endif
-
+LOCAL_CFLAGS := $(libc_common_cflags) \
+                -DLIBC_STATIC
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
-
 LOCAL_MODULE := libc
 LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
@@ -561,7 +579,7 @@
 LOCAL_SRC_FILES := \
 	$(libc_arch_dynamic_src_files) \
 	bionic/dlmalloc.c \
-	bionic/malloc_leak.c.arm \
+	bionic/malloc_debug_common.c \
 	bionic/libc_init_dynamic.c
 
 LOCAL_MODULE:= libc
@@ -581,8 +599,16 @@
 include $(BUILD_SHARED_LIBRARY)
 
 
+# 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.
+ifneq ($(TARGET_BUILD_VARIANT),user)
+
 # ========================================================
-# libc_debug.so
+# libc_malloc_debug_leak.so
 # ========================================================
 include $(CLEAR_VARS)
 
@@ -593,30 +619,49 @@
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 
 LOCAL_SRC_FILES := \
-	$(libc_arch_dynamic_src_files) \
-	bionic/dlmalloc.c \
-	bionic/malloc_leak.c.arm \
-	bionic/libc_init_dynamic.c
+	bionic/malloc_debug_leak.c
 
-LOCAL_MODULE:= libc_debug
+LOCAL_MODULE:= libc_malloc_debug_leak
 
-# 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 an "cloaked" dependency on libgcc.a in libc though the libraries, which is not what
-# you wanted!
-
-LOCAL_SHARED_LIBRARIES := libdl
+LOCAL_SHARED_LIBRARIES := libc
 LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 # Don't prelink
 LOCAL_PRELINK_MODULE := false
 # Don't install on release build
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := eng debug
 
 include $(BUILD_SHARED_LIBRARY)
 
+
+# ========================================================
+# libc_malloc_debug_qemu.so
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := \
+	$(libc_common_cflags) \
+	-DMALLOC_QEMU_INSTRUMENT
+
+LOCAL_C_INCLUDES := $(libc_common_c_includes)
+
+LOCAL_SRC_FILES := \
+	bionic/malloc_debug_qemu.c
+
+LOCAL_MODULE:= libc_malloc_debug_qemu
+
+LOCAL_SHARED_LIBRARIES := libc
+LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
+LOCAL_SYSTEM_SHARED_LIBRARIES :=
+# Don't prelink
+LOCAL_PRELINK_MODULE := false
+# Don't install on release build
+LOCAL_MODULE_TAGS := eng debug
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif	#!user
+
+
 # ========================================================
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 684b43e..8c664d7 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -34,10 +34,15 @@
 pid_t   __fork:fork (void)           2
 pid_t   _waitpid:waitpid (pid_t, int*, int, struct rusage*)   -1,7
 int     waitid(int, pid_t, struct siginfo_t*, int,void*)          280,284
-pid_t   __clone:clone(int (*fn)(void*), void *child_stack, int flags, void *arg)  120
+
+# NOTE: this system call is never called directly, but we list it there
+#       to have __NR_clone properly defined.
+#
+pid_t   __sys_clone:clone (int, void*, int*, void*, int*) 120
+
 int     execve (const char*, char* const*, char* const*)  11
 
-int     setuid:setuid32 (uid_t)    213
+int     __setuid:setuid32 (uid_t)    213
 uid_t   getuid:getuid32 ()         199
 gid_t   getgid:getgid32 ()         200
 uid_t   geteuid:geteuid32 ()       201
@@ -51,8 +56,8 @@
 pid_t   setsid()                   66
 int     setgid:setgid32(gid_t)     214
 int     seteuid:seteuid32(uid_t)   stub
-int     setreuid:setreuid32(uid_t, uid_t)   203
-int     setresuid:setresuid32(uid_t, uid_t, uid_t)   208
+int     __setreuid:setreuid32(uid_t, uid_t)   203
+int     __setresuid:setresuid32(uid_t, uid_t, uid_t)   208
 int     setresgid:setresgid32(gid_t, gid_t, gid_t)   210
 void*   __brk:brk(void*)           45
 # see comments in arch-arm/bionic/kill.S to understand why we don't generate an ARM stub for kill/tkill
@@ -74,6 +79,7 @@
 int     prctl(int option, unsigned int arg2, unsigned int arg3, unsigned int arg4, unsigned int arg5)  172
 int     capget(cap_user_header_t header, cap_user_data_t data) 184
 int     capset(cap_user_header_t header, const cap_user_data_t data) 185
+int     sigaltstack(const stack_t*, stack_t*) 186
 int     acct(const char*  filepath)  51
 
 # file descriptors
@@ -222,6 +228,10 @@
 int sched_get_priority_min(int policy)  160
 int sched_rr_get_interval(pid_t pid, struct timespec *interval)  161
 
+# io priorities
+int ioprio_set(int which, int who, int ioprio) 314,289
+int ioprio_get(int which, int who) 315,290
+
 # other
 int     uname(struct utsname *)  122
 pid_t   __wait4:wait4(pid_t pid, int *status, int options, struct rusage *rusage)   114
diff --git a/libc/arch-arm/bionic/__get_pc.S b/libc/arch-arm/bionic/__get_pc.S
index d1377c7..4fc8929 100644
--- a/libc/arch-arm/bionic/__get_pc.S
+++ b/libc/arch-arm/bionic/__get_pc.S
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 .global __get_pc
+.type __get_pc, %function
 
 __get_pc:
 	mov r0, pc
diff --git a/libc/arch-arm/bionic/__get_sp.S b/libc/arch-arm/bionic/__get_sp.S
index 9acaf3d..0a313a3 100644
--- a/libc/arch-arm/bionic/__get_sp.S
+++ b/libc/arch-arm/bionic/__get_sp.S
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 .global __get_sp
+.type __get_sp, %function
 
 __get_sp:
 	mov r0, sp
diff --git a/libc/arch-arm/bionic/atomics_arm.S b/libc/arch-arm/bionic/atomics_arm.S
index 0cd0b92..047541f 100644
--- a/libc/arch-arm/bionic/atomics_arm.S
+++ b/libc/arch-arm/bionic/atomics_arm.S
@@ -28,11 +28,13 @@
 #include <sys/linux-syscalls.h>
 
 .global __atomic_cmpxchg
+.type __atomic_cmpxchg, %function
 .global __atomic_swap
+.type __atomic_swap, %function
 .global __atomic_dec
+.type __atomic_dec, %function
 .global __atomic_inc
-.global __futex_wait
-.global __futex_wake
+.type __atomic_inc, %function
 
 #define FUTEX_WAIT 0
 #define FUTEX_WAKE 1
@@ -153,10 +155,34 @@
     bx      lr
 
 /* __futex_wait(*ftx, val, *timespec) */
-/* __futex_syscall(*ftx, op, val, *timespec, *addr2, val3) */
+/* __futex_wake(*ftx, counter) */
+/* __futex_syscall3(*ftx, op, val) */
+/* __futex_syscall4(*ftx, op, val, *timespec) */
+
+.global __futex_wait
+.type __futex_wait, %function
+
+.global __futex_wake
+.type __futex_wake, %function
+
+.global __futex_syscall3
+.type __futex_syscall3, %function
+
+.global __futex_syscall4
+.type __futex_syscall4, %function
 
 #if __ARM_EABI__
 
+__futex_syscall3:
+    .fnstart
+    stmdb   sp!, {r4, r7}
+    .save   {r4, r7}
+    ldr     r7, =__NR_futex
+    swi     #0
+    ldmia   sp!, {r4, r7}
+    bx      lr
+    .fnend
+
 __futex_wait:
     .fnstart
     stmdb   sp!, {r4, r7}
@@ -181,6 +207,10 @@
 
 #else
 
+__futex_syscall3:
+    swi     #__NR_futex
+    bx      lr
+
 __futex_wait:
     mov     r3, r2
     mov     r2, r1
@@ -195,3 +225,6 @@
     bx      lr
 
 #endif
+
+__futex_syscall4:
+    b __futex_syscall3
diff --git a/libc/arch-arm/bionic/clone.S b/libc/arch-arm/bionic/clone.S
index 791c73d..9c25053 100644
--- a/libc/arch-arm/bionic/clone.S
+++ b/libc/arch-arm/bionic/clone.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2010 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,48 +27,102 @@
  */
 #include <sys/linux-syscalls.h>
 
-	.text
-	.type __pthread_clone, #function
-	.global __pthread_clone
-	.align 4
-    
-__pthread_clone:
-	@ insert the args onto the new stack
-	str     r0, [r1, #-4]
-	str     r3, [r1, #-8]
+    .text
+    .type __pthread_clone, #function
+    .global __pthread_clone
+    .align 4
+    .fnstart
 
-	@ do the system call
-	@ get flags
-	
+__pthread_clone:
+    @ insert the args onto the new stack
+    str     r0, [r1, #-4]
+    str     r3, [r1, #-8]
+
+    @ do the system call
+    @ get flags
+
     mov     r0, r2
-	
+
     @ new sp is already in r1
 
 #if __ARM_EABI__
     stmfd   sp!, {r4, r7}
     ldr     r7, =__NR_clone
-	swi     #0
+    swi     #0
 #else
-	swi     #__NR_clone
+    swi     #__NR_clone
 #endif
 
-	movs    r0, r0
+    movs    r0, r0
 #if __ARM_EABI__
     ldmnefd sp!, {r4, r7}
 #endif
-	blt     __error
-	bxne    lr
+    blt     __error
+    bxne    lr
 
 
-	@ pick the function arg and call address off the stack and jump
-	@ to the C __thread_entry function which does some setup and then
-	@ calls the thread's start function
+    @ pick the function arg and call address off the stack and jump
+    @ to the C __thread_entry function which does some setup and then
+    @ calls the thread's start function
 
-	ldr     r0, [sp, #-4]
-	ldr     r1, [sp, #-8]
-	mov     r2, sp			@ __thread_entry needs the TLS pointer
-	b       __thread_entry
+    ldr     r0, [sp, #-4]
+    ldr     r1, [sp, #-8]
+    mov     r2, sp			@ __thread_entry needs the TLS pointer
+    b       __thread_entry
 
 __error:
-	mov     r0, #-1
-	bx      lr
+    mov     r0, #-1
+    bx      lr
+    .fnend
+
+
+    #
+    # This function is defined as:
+    #
+    #   pid_t  __bionic_clone( int  flags, void *child_stack,
+    #                          pid_t *pid, void *tls, pid_t *ctid,
+    #                          int  (*fn)(void *), void* arg );
+    #
+    # NOTE: This is not the same signature than the GLibc
+    #       __clone function here !! Placing 'fn' and 'arg'
+    #       at the end of the parameter list makes the
+    #       implementation much simpler.
+    #
+    .type __bionic_clone, #function
+    .globl __bionic_clone
+    .align 4
+    .fnstart
+
+__bionic_clone:
+    mov     ip, sp
+    .save   {r4, r5, r6, r7}
+
+    # save registers to parent stack
+    stmfd   sp!, {r4, r5, r6, r7}
+
+    # load extra parameters
+    ldmfd   ip, {r4, r5, r6}
+
+    # store 'fn' and 'arg' to the child stack
+    str     r5, [r1, #-4]
+    str     r6, [r1, #-8]
+
+    # system call
+    ldr     r7, =__NR_clone
+    swi     #0
+    movs    r0, r0
+    beq     1f
+
+    # in parent, reload saved registers
+    # then either exit or error
+    #
+    ldmfd   sp!, {r4, r5, r6, r7}
+    bxne    lr
+    b       __set_syscall_errno
+
+1:  # in the child - pick arguments
+    ldr    r0, [sp, #-4]
+    ldr    r1, [sp, #-8]
+    b      __bionic_clone_entry
+
+    .fnend
diff --git a/libc/arch-arm/bionic/memcpy.S b/libc/arch-arm/bionic/memcpy.S
index 024d885..ba55996 100644
--- a/libc/arch-arm/bionic/memcpy.S
+++ b/libc/arch-arm/bionic/memcpy.S
@@ -28,7 +28,7 @@
 
 #include <machine/cpu-features.h>
 
-#if __ARM_ARCH__ == 7 || defined(__ARM_NEON__)
+#if defined(__ARM_NEON__)
 
         .text
         .fpu    neon
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index 706cb0c..4a8caac 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -4,9 +4,9 @@
 syscall_src += arch-arm/syscalls/_exit_thread.S
 syscall_src += arch-arm/syscalls/__fork.S
 syscall_src += arch-arm/syscalls/waitid.S
-syscall_src += arch-arm/syscalls/__clone.S
+syscall_src += arch-arm/syscalls/__sys_clone.S
 syscall_src += arch-arm/syscalls/execve.S
-syscall_src += arch-arm/syscalls/setuid.S
+syscall_src += arch-arm/syscalls/__setuid.S
 syscall_src += arch-arm/syscalls/getuid.S
 syscall_src += arch-arm/syscalls/getgid.S
 syscall_src += arch-arm/syscalls/geteuid.S
@@ -19,8 +19,8 @@
 syscall_src += arch-arm/syscalls/getppid.S
 syscall_src += arch-arm/syscalls/setsid.S
 syscall_src += arch-arm/syscalls/setgid.S
-syscall_src += arch-arm/syscalls/setreuid.S
-syscall_src += arch-arm/syscalls/setresuid.S
+syscall_src += arch-arm/syscalls/__setreuid.S
+syscall_src += arch-arm/syscalls/__setresuid.S
 syscall_src += arch-arm/syscalls/setresgid.S
 syscall_src += arch-arm/syscalls/__brk.S
 syscall_src += arch-arm/syscalls/__ptrace.S
@@ -37,6 +37,7 @@
 syscall_src += arch-arm/syscalls/prctl.S
 syscall_src += arch-arm/syscalls/capget.S
 syscall_src += arch-arm/syscalls/capset.S
+syscall_src += arch-arm/syscalls/sigaltstack.S
 syscall_src += arch-arm/syscalls/acct.S
 syscall_src += arch-arm/syscalls/read.S
 syscall_src += arch-arm/syscalls/write.S
@@ -150,6 +151,8 @@
 syscall_src += arch-arm/syscalls/sched_get_priority_max.S
 syscall_src += arch-arm/syscalls/sched_get_priority_min.S
 syscall_src += arch-arm/syscalls/sched_rr_get_interval.S
+syscall_src += arch-arm/syscalls/ioprio_set.S
+syscall_src += arch-arm/syscalls/ioprio_get.S
 syscall_src += arch-arm/syscalls/uname.S
 syscall_src += arch-arm/syscalls/__wait4.S
 syscall_src += arch-arm/syscalls/umask.S
diff --git a/libc/arch-arm/syscalls/setresuid.S b/libc/arch-arm/syscalls/__setresuid.S
similarity index 81%
rename from libc/arch-arm/syscalls/setresuid.S
rename to libc/arch-arm/syscalls/__setresuid.S
index 266c1a1..7710772 100644
--- a/libc/arch-arm/syscalls/setresuid.S
+++ b/libc/arch-arm/syscalls/__setresuid.S
@@ -2,12 +2,12 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setresuid, #function
-    .globl setresuid
+    .type __setresuid, #function
+    .globl __setresuid
     .align 4
     .fnstart
 
-setresuid:
+__setresuid:
     .save   {r4, r7}
     stmfd   sp!, {r4, r7}
     ldr     r7, =__NR_setresuid32
diff --git a/libc/arch-arm/syscalls/setreuid.S b/libc/arch-arm/syscalls/__setreuid.S
similarity index 82%
rename from libc/arch-arm/syscalls/setreuid.S
rename to libc/arch-arm/syscalls/__setreuid.S
index 0f94b47..0c68866 100644
--- a/libc/arch-arm/syscalls/setreuid.S
+++ b/libc/arch-arm/syscalls/__setreuid.S
@@ -2,12 +2,12 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setreuid, #function
-    .globl setreuid
+    .type __setreuid, #function
+    .globl __setreuid
     .align 4
     .fnstart
 
-setreuid:
+__setreuid:
     .save   {r4, r7}
     stmfd   sp!, {r4, r7}
     ldr     r7, =__NR_setreuid32
diff --git a/libc/arch-arm/syscalls/setuid.S b/libc/arch-arm/syscalls/__setuid.S
similarity index 83%
rename from libc/arch-arm/syscalls/setuid.S
rename to libc/arch-arm/syscalls/__setuid.S
index 31cf446..efc6e56 100644
--- a/libc/arch-arm/syscalls/setuid.S
+++ b/libc/arch-arm/syscalls/__setuid.S
@@ -2,12 +2,12 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setuid, #function
-    .globl setuid
+    .type __setuid, #function
+    .globl __setuid
     .align 4
     .fnstart
 
-setuid:
+__setuid:
     .save   {r4, r7}
     stmfd   sp!, {r4, r7}
     ldr     r7, =__NR_setuid32
diff --git a/libc/arch-arm/syscalls/__sys_clone.S b/libc/arch-arm/syscalls/__sys_clone.S
new file mode 100644
index 0000000..9fe2641
--- /dev/null
+++ b/libc/arch-arm/syscalls/__sys_clone.S
@@ -0,0 +1,21 @@
+/* autogenerated by gensyscalls.py */
+#include <sys/linux-syscalls.h>
+
+    .text
+    .type __sys_clone, #function
+    .globl __sys_clone
+    .align 4
+    .fnstart
+
+__sys_clone:
+    mov     ip, sp
+    .save   {r4, r5, r6, r7}
+    stmfd   sp!, {r4, r5, r6, r7}
+    ldmfd   ip, {r4, r5, r6}
+    ldr     r7, =__NR_clone
+    swi     #0
+    ldmfd   sp!, {r4, r5, r6, r7}
+    movs    r0, r0
+    bxpl    lr
+    b       __set_syscall_errno
+    .fnend
diff --git a/libc/arch-arm/syscalls/__clone.S b/libc/arch-arm/syscalls/ioprio_get.S
similarity index 73%
rename from libc/arch-arm/syscalls/__clone.S
rename to libc/arch-arm/syscalls/ioprio_get.S
index 650e2c0..d686e98 100644
--- a/libc/arch-arm/syscalls/__clone.S
+++ b/libc/arch-arm/syscalls/ioprio_get.S
@@ -2,15 +2,15 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type __clone, #function
-    .globl __clone
+    .type ioprio_get, #function
+    .globl ioprio_get
     .align 4
     .fnstart
 
-__clone:
+ioprio_get:
     .save   {r4, r7}
     stmfd   sp!, {r4, r7}
-    ldr     r7, =__NR_clone
+    ldr     r7, =__NR_ioprio_get
     swi     #0
     ldmfd   sp!, {r4, r7}
     movs    r0, r0
diff --git a/libc/arch-arm/syscalls/__clone.S b/libc/arch-arm/syscalls/ioprio_set.S
similarity index 73%
copy from libc/arch-arm/syscalls/__clone.S
copy to libc/arch-arm/syscalls/ioprio_set.S
index 650e2c0..a812557 100644
--- a/libc/arch-arm/syscalls/__clone.S
+++ b/libc/arch-arm/syscalls/ioprio_set.S
@@ -2,15 +2,15 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type __clone, #function
-    .globl __clone
+    .type ioprio_set, #function
+    .globl ioprio_set
     .align 4
     .fnstart
 
-__clone:
+ioprio_set:
     .save   {r4, r7}
     stmfd   sp!, {r4, r7}
-    ldr     r7, =__NR_clone
+    ldr     r7, =__NR_ioprio_set
     swi     #0
     ldmfd   sp!, {r4, r7}
     movs    r0, r0
diff --git a/libc/arch-arm/syscalls/__clone.S b/libc/arch-arm/syscalls/sigaltstack.S
similarity index 72%
copy from libc/arch-arm/syscalls/__clone.S
copy to libc/arch-arm/syscalls/sigaltstack.S
index 650e2c0..3625d0b 100644
--- a/libc/arch-arm/syscalls/__clone.S
+++ b/libc/arch-arm/syscalls/sigaltstack.S
@@ -2,15 +2,15 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type __clone, #function
-    .globl __clone
+    .type sigaltstack, #function
+    .globl sigaltstack
     .align 4
     .fnstart
 
-__clone:
+sigaltstack:
     .save   {r4, r7}
     stmfd   sp!, {r4, r7}
-    ldr     r7, =__NR_clone
+    ldr     r7, =__NR_sigaltstack
     swi     #0
     ldmfd   sp!, {r4, r7}
     movs    r0, r0
diff --git a/libc/arch-sh/bionic/atomics_sh.c b/libc/arch-sh/bionic/atomics_sh.c
index 16966f7..c7815ff 100644
--- a/libc/arch-sh/bionic/atomics_sh.c
+++ b/libc/arch-sh/bionic/atomics_sh.c
@@ -98,3 +98,13 @@
 {
     return futex(ftx, FUTEX_WAKE, count, NULL, NULL, 0);
 }
+
+int __futex_syscall3(volatile void *ftx, int op, int val)
+{
+    return futex(ftx, op, val, NULL, NULL, 0);
+}
+
+int __futex_syscall4(volative void *ftx, int op, int val, const struct timespec *timeout)
+{
+    return futex(ftx, op, val, (void *)timeout, NULL, 0);
+}
diff --git a/libc/arch-sh/bionic/clone.S b/libc/arch-sh/bionic/clone.S
index 0bbaecb..9cb19ee 100644
--- a/libc/arch-sh/bionic/clone.S
+++ b/libc/arch-sh/bionic/clone.S
@@ -72,3 +72,8 @@
     .align 2
 0:  .long   __NR_clone
 1:  .long   __thread_entry
+
+/* XXX: TODO: Add __bionic_clone here
+ *            See bionic/bionic_clone.c and arch-arm/bionic/clone.S
+ *            for more details...
+ */
\ No newline at end of file
diff --git a/libc/arch-sh/syscalls.mk b/libc/arch-sh/syscalls.mk
index cefb2ec..ab2f3d1 100644
--- a/libc/arch-sh/syscalls.mk
+++ b/libc/arch-sh/syscalls.mk
@@ -5,9 +5,9 @@
 syscall_src += arch-sh/syscalls/__fork.S
 syscall_src += arch-sh/syscalls/_waitpid.S
 syscall_src += arch-sh/syscalls/waitid.S
-syscall_src += arch-sh/syscalls/__clone.S
+syscall_src += arch-sh/syscalls/__sys_clone.S
 syscall_src += arch-sh/syscalls/execve.S
-syscall_src += arch-sh/syscalls/setuid.S
+syscall_src += arch-sh/syscalls/__setuid.S
 syscall_src += arch-sh/syscalls/getuid.S
 syscall_src += arch-sh/syscalls/getgid.S
 syscall_src += arch-sh/syscalls/geteuid.S
@@ -20,8 +20,8 @@
 syscall_src += arch-sh/syscalls/getppid.S
 syscall_src += arch-sh/syscalls/setsid.S
 syscall_src += arch-sh/syscalls/setgid.S
-syscall_src += arch-sh/syscalls/setreuid.S
-syscall_src += arch-sh/syscalls/setresuid.S
+syscall_src += arch-sh/syscalls/__setreuid.S
+syscall_src += arch-sh/syscalls/__setresuid.S
 syscall_src += arch-sh/syscalls/setresgid.S
 syscall_src += arch-sh/syscalls/__brk.S
 syscall_src += arch-sh/syscalls/kill.S
@@ -41,6 +41,7 @@
 syscall_src += arch-sh/syscalls/prctl.S
 syscall_src += arch-sh/syscalls/capget.S
 syscall_src += arch-sh/syscalls/capset.S
+syscall_src += arch-sh/syscalls/sigaltstack.S
 syscall_src += arch-sh/syscalls/acct.S
 syscall_src += arch-sh/syscalls/read.S
 syscall_src += arch-sh/syscalls/write.S
@@ -139,6 +140,8 @@
 syscall_src += arch-sh/syscalls/sched_get_priority_max.S
 syscall_src += arch-sh/syscalls/sched_get_priority_min.S
 syscall_src += arch-sh/syscalls/sched_rr_get_interval.S
+syscall_src += arch-sh/syscalls/ioprio_set.S
+syscall_src += arch-sh/syscalls/ioprio_get.S
 syscall_src += arch-sh/syscalls/uname.S
 syscall_src += arch-sh/syscalls/__wait4.S
 syscall_src += arch-sh/syscalls/umask.S
diff --git a/libc/arch-sh/syscalls/setresuid.S b/libc/arch-sh/syscalls/__setresuid.S
similarity index 87%
rename from libc/arch-sh/syscalls/setresuid.S
rename to libc/arch-sh/syscalls/__setresuid.S
index 41fe349..424100e 100644
--- a/libc/arch-sh/syscalls/setresuid.S
+++ b/libc/arch-sh/syscalls/__setresuid.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setresuid, @function
-    .globl setresuid
+    .type __setresuid, @function
+    .globl __setresuid
     .align 4
 
-setresuid:
+__setresuid:
 
     /* invoke trap */
     mov.l   0f, r3  /* trap num */
diff --git a/libc/arch-sh/syscalls/setreuid.S b/libc/arch-sh/syscalls/__setreuid.S
similarity index 88%
rename from libc/arch-sh/syscalls/setreuid.S
rename to libc/arch-sh/syscalls/__setreuid.S
index 025df27..6990748 100644
--- a/libc/arch-sh/syscalls/setreuid.S
+++ b/libc/arch-sh/syscalls/__setreuid.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setreuid, @function
-    .globl setreuid
+    .type __setreuid, @function
+    .globl __setreuid
     .align 4
 
-setreuid:
+__setreuid:
 
     /* invoke trap */
     mov.l   0f, r3  /* trap num */
diff --git a/libc/arch-sh/syscalls/setuid.S b/libc/arch-sh/syscalls/__setuid.S
similarity index 89%
rename from libc/arch-sh/syscalls/setuid.S
rename to libc/arch-sh/syscalls/__setuid.S
index 1fb3148..f563de7 100644
--- a/libc/arch-sh/syscalls/setuid.S
+++ b/libc/arch-sh/syscalls/__setuid.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setuid, @function
-    .globl setuid
+    .type __setuid, @function
+    .globl __setuid
     .align 4
 
-setuid:
+__setuid:
 
     /* invoke trap */
     mov.l   0f, r3  /* trap num */
diff --git a/libc/arch-sh/syscalls/__clone.S b/libc/arch-sh/syscalls/__sys_clone.S
similarity index 74%
rename from libc/arch-sh/syscalls/__clone.S
rename to libc/arch-sh/syscalls/__sys_clone.S
index 1df6ca2..c2e7dd2 100644
--- a/libc/arch-sh/syscalls/__clone.S
+++ b/libc/arch-sh/syscalls/__sys_clone.S
@@ -2,15 +2,18 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type __clone, @function
-    .globl __clone
+    .type __sys_clone, @function
+    .globl __sys_clone
     .align 4
 
-__clone:
+__sys_clone:
+
+    /* get ready for additonal arg */
+    mov.l   @r15, r0
 
     /* invoke trap */
     mov.l   0f, r3  /* trap num */
-    trapa   #(4 + 0x10)
+    trapa   #(5 + 0x10)
 
     /* check return value */
     cmp/pz  r0
diff --git a/libc/arch-sh/syscalls/setreuid.S b/libc/arch-sh/syscalls/ioprio_get.S
similarity index 73%
copy from libc/arch-sh/syscalls/setreuid.S
copy to libc/arch-sh/syscalls/ioprio_get.S
index 025df27..802eb91 100644
--- a/libc/arch-sh/syscalls/setreuid.S
+++ b/libc/arch-sh/syscalls/ioprio_get.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setreuid, @function
-    .globl setreuid
+    .type ioprio_get, @function
+    .globl ioprio_get
     .align 4
 
-setreuid:
+ioprio_get:
 
     /* invoke trap */
     mov.l   0f, r3  /* trap num */
@@ -14,7 +14,7 @@
 
     /* check return value */
     cmp/pz  r0
-    bt      __NR_setreuid32_end
+    bt      __NR_ioprio_get_end
 
     /* keep error number */
     sts.l   pr, @-r15
@@ -23,10 +23,10 @@
     mov     r0, r4
     lds.l   @r15+, pr
 
-__NR_setreuid32_end:
+__NR_ioprio_get_end:
     rts
     nop
 
     .align  2
-0:  .long   __NR_setreuid32
+0:  .long   __NR_ioprio_get
 1:  .long   __set_syscall_errno
diff --git a/libc/arch-sh/syscalls/setresuid.S b/libc/arch-sh/syscalls/ioprio_set.S
similarity index 73%
copy from libc/arch-sh/syscalls/setresuid.S
copy to libc/arch-sh/syscalls/ioprio_set.S
index 41fe349..209d756 100644
--- a/libc/arch-sh/syscalls/setresuid.S
+++ b/libc/arch-sh/syscalls/ioprio_set.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setresuid, @function
-    .globl setresuid
+    .type ioprio_set, @function
+    .globl ioprio_set
     .align 4
 
-setresuid:
+ioprio_set:
 
     /* invoke trap */
     mov.l   0f, r3  /* trap num */
@@ -14,7 +14,7 @@
 
     /* check return value */
     cmp/pz  r0
-    bt      __NR_setresuid32_end
+    bt      __NR_ioprio_set_end
 
     /* keep error number */
     sts.l   pr, @-r15
@@ -23,10 +23,10 @@
     mov     r0, r4
     lds.l   @r15+, pr
 
-__NR_setresuid32_end:
+__NR_ioprio_set_end:
     rts
     nop
 
     .align  2
-0:  .long   __NR_setresuid32
+0:  .long   __NR_ioprio_set
 1:  .long   __set_syscall_errno
diff --git a/libc/arch-sh/syscalls/setreuid.S b/libc/arch-sh/syscalls/sigaltstack.S
similarity index 72%
copy from libc/arch-sh/syscalls/setreuid.S
copy to libc/arch-sh/syscalls/sigaltstack.S
index 025df27..8b03e27 100644
--- a/libc/arch-sh/syscalls/setreuid.S
+++ b/libc/arch-sh/syscalls/sigaltstack.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setreuid, @function
-    .globl setreuid
+    .type sigaltstack, @function
+    .globl sigaltstack
     .align 4
 
-setreuid:
+sigaltstack:
 
     /* invoke trap */
     mov.l   0f, r3  /* trap num */
@@ -14,7 +14,7 @@
 
     /* check return value */
     cmp/pz  r0
-    bt      __NR_setreuid32_end
+    bt      __NR_sigaltstack_end
 
     /* keep error number */
     sts.l   pr, @-r15
@@ -23,10 +23,10 @@
     mov     r0, r4
     lds.l   @r15+, pr
 
-__NR_setreuid32_end:
+__NR_sigaltstack_end:
     rts
     nop
 
     .align  2
-0:  .long   __NR_setreuid32
+0:  .long   __NR_sigaltstack
 1:  .long   __set_syscall_errno
diff --git a/libc/arch-x86/bionic/atomics_x86.S b/libc/arch-x86/bionic/atomics_x86.S
index 2370f23..666e182 100644
--- a/libc/arch-x86/bionic/atomics_x86.S
+++ b/libc/arch-x86/bionic/atomics_x86.S
@@ -41,6 +41,38 @@
     popl    %ebx
     ret
 
+/* int __futex_syscall3(volatile void *ftx, int op, int count) */
+.text
+.globl __futex_syscall3
+.type __futex_syscall3, @function
+.align 4
+__futex_syscall3:
+    pushl   %ebx
+    movl    8(%esp), %ebx      /* ftx */
+    movl    12(%esp), %ecx      /* op */
+    movl    16(%esp), %edx      /* value */
+    movl    $__NR_futex, %eax
+    int     $0x80
+    popl    %ebx
+    ret
+
+/* int __futex_syscall4(volatile void *ftx, int op, int val, const struct timespec *timeout) */
+.text
+.globl __futex_syscall4
+.type __futex_syscall4, @function
+.align 4
+__futex_syscall4:
+    pushl   %ebx
+    pushl   %esi
+    movl    12(%esp), %ebx      /* ftx */
+    movl    16(%esp), %ecx      /* op */
+    movl    20(%esp), %edx      /* val */
+    movl    24(%esp), %esi      /* timeout */
+    movl    $__NR_futex, %eax
+    int     $0x80
+    popl    %esi
+    popl    %ebx
+    ret
 
 /* int __atomic_cmpxchg(int old, int new, volatile int* addr) */
 
diff --git a/libc/arch-x86/bionic/atomics_x86.c b/libc/arch-x86/bionic/atomics_x86.c
deleted file mode 100644
index b7b20e6..0000000
--- a/libc/arch-x86/bionic/atomics_x86.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <sys/atomics.h>
-
-#define FUTEX_SYSCALL 240
-#define FUTEX_WAIT 0
-#define FUTEX_WAKE 1
-
-int __futex_wait(volatile void *ftx, int val)
-{
-    int ret;
-    asm volatile (
-        "int $0x80;"
-        : "=a" (ret)
-        : "0" (FUTEX_SYSCALL),
-          "b" (ftx),
-          "c" (FUTEX_WAIT),
-          "d" (val),
-          "S" (0)
-    );
-    return ret;
-}
-
-int __futex_wake(volatile void *ftx, int count)
-{
-    int ret;
-    asm volatile (
-        "int $0x80;"
-        : "=a" (ret)
-        : "0" (FUTEX_SYSCALL),
-          "b" (ftx),
-          "c" (FUTEX_WAKE),
-          "d" (count)
-    );
-    return ret;
-}
-
-int __atomic_cmpxchg(int old, int new, volatile int* addr) {
-    int xchg;
-    asm volatile (
-        "lock;"
-        "cmpxchg %%ecx, (%%edx);"
-        "setne %%al;"
-        : "=a" (xchg)
-        : "a" (old),
-          "c" (new),
-          "d" (addr)
-    );
-    return xchg;
-}
-
-int __atomic_swap(int new, volatile int* addr) {
-    int old;
-    asm volatile (
-        "lock;"
-        "xchg %%ecx, (%%edx);"
-        : "=c" (old)
-        : "c" (new),
-          "d" (addr)
-    );
-    return old;
-}
-
-int __atomic_dec(volatile int* addr) {
-    int old;
-    do {
-        old = *addr;
-    } while (atomic_cmpxchg(old, old-1, addr));
-    return old;
-}
-
-int __atomic_inc(volatile int* addr) {
-    int old;
-    do {
-        old = *addr;
-    } while (atomic_cmpxchg(old, old+1, addr));
-    return old;
-}
-
diff --git a/libc/arch-x86/bionic/clone.S b/libc/arch-x86/bionic/clone.S
index 361808d..3b50cc3 100644
--- a/libc/arch-x86/bionic/clone.S
+++ b/libc/arch-x86/bionic/clone.S
@@ -48,3 +48,8 @@
         popl    %ecx
         popl    %ebx
         ret
+
+/* XXX: TODO: Add __bionic_clone here
+ *            See bionic/bionic_clone.c and arch-arm/bionic/clone.S
+ *            for more details...
+ */
\ No newline at end of file
diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk
index 86d2308..ab026fe 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -5,9 +5,9 @@
 syscall_src += arch-x86/syscalls/__fork.S
 syscall_src += arch-x86/syscalls/_waitpid.S
 syscall_src += arch-x86/syscalls/waitid.S
-syscall_src += arch-x86/syscalls/__clone.S
+syscall_src += arch-x86/syscalls/__sys_clone.S
 syscall_src += arch-x86/syscalls/execve.S
-syscall_src += arch-x86/syscalls/setuid.S
+syscall_src += arch-x86/syscalls/__setuid.S
 syscall_src += arch-x86/syscalls/getuid.S
 syscall_src += arch-x86/syscalls/getgid.S
 syscall_src += arch-x86/syscalls/geteuid.S
@@ -20,8 +20,8 @@
 syscall_src += arch-x86/syscalls/getppid.S
 syscall_src += arch-x86/syscalls/setsid.S
 syscall_src += arch-x86/syscalls/setgid.S
-syscall_src += arch-x86/syscalls/setreuid.S
-syscall_src += arch-x86/syscalls/setresuid.S
+syscall_src += arch-x86/syscalls/__setreuid.S
+syscall_src += arch-x86/syscalls/__setresuid.S
 syscall_src += arch-x86/syscalls/setresgid.S
 syscall_src += arch-x86/syscalls/__brk.S
 syscall_src += arch-x86/syscalls/kill.S
@@ -40,6 +40,7 @@
 syscall_src += arch-x86/syscalls/prctl.S
 syscall_src += arch-x86/syscalls/capget.S
 syscall_src += arch-x86/syscalls/capset.S
+syscall_src += arch-x86/syscalls/sigaltstack.S
 syscall_src += arch-x86/syscalls/acct.S
 syscall_src += arch-x86/syscalls/read.S
 syscall_src += arch-x86/syscalls/write.S
@@ -153,6 +154,8 @@
 syscall_src += arch-x86/syscalls/sched_get_priority_max.S
 syscall_src += arch-x86/syscalls/sched_get_priority_min.S
 syscall_src += arch-x86/syscalls/sched_rr_get_interval.S
+syscall_src += arch-x86/syscalls/ioprio_set.S
+syscall_src += arch-x86/syscalls/ioprio_get.S
 syscall_src += arch-x86/syscalls/uname.S
 syscall_src += arch-x86/syscalls/__wait4.S
 syscall_src += arch-x86/syscalls/umask.S
diff --git a/libc/arch-x86/syscalls/setresuid.S b/libc/arch-x86/syscalls/__setresuid.S
similarity index 87%
rename from libc/arch-x86/syscalls/setresuid.S
rename to libc/arch-x86/syscalls/__setresuid.S
index f81cb39..c492dfb 100644
--- a/libc/arch-x86/syscalls/setresuid.S
+++ b/libc/arch-x86/syscalls/__setresuid.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setresuid, @function
-    .globl setresuid
+    .type __setresuid, @function
+    .globl __setresuid
     .align 4
 
-setresuid:
+__setresuid:
     pushl   %ebx
     pushl   %ecx
     pushl   %edx
diff --git a/libc/arch-x86/syscalls/setreuid.S b/libc/arch-x86/syscalls/__setreuid.S
similarity index 86%
rename from libc/arch-x86/syscalls/setreuid.S
rename to libc/arch-x86/syscalls/__setreuid.S
index 99e5d5b..111e999 100644
--- a/libc/arch-x86/syscalls/setreuid.S
+++ b/libc/arch-x86/syscalls/__setreuid.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setreuid, @function
-    .globl setreuid
+    .type __setreuid, @function
+    .globl __setreuid
     .align 4
 
-setreuid:
+__setreuid:
     pushl   %ebx
     pushl   %ecx
     mov     12(%esp), %ebx
diff --git a/libc/arch-x86/syscalls/setuid.S b/libc/arch-x86/syscalls/__setuid.S
similarity index 85%
rename from libc/arch-x86/syscalls/setuid.S
rename to libc/arch-x86/syscalls/__setuid.S
index de334c0..1e5f285 100644
--- a/libc/arch-x86/syscalls/setuid.S
+++ b/libc/arch-x86/syscalls/__setuid.S
@@ -2,11 +2,11 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setuid, @function
-    .globl setuid
+    .type __setuid, @function
+    .globl __setuid
     .align 4
 
-setuid:
+__setuid:
     pushl   %ebx
     mov     8(%esp), %ebx
     movl    $__NR_setuid32, %eax
diff --git a/libc/arch-x86/syscalls/__clone.S b/libc/arch-x86/syscalls/__sys_clone.S
similarity index 64%
rename from libc/arch-x86/syscalls/__clone.S
rename to libc/arch-x86/syscalls/__sys_clone.S
index 5862129..172d6af 100644
--- a/libc/arch-x86/syscalls/__clone.S
+++ b/libc/arch-x86/syscalls/__sys_clone.S
@@ -2,19 +2,21 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type __clone, @function
-    .globl __clone
+    .type __sys_clone, @function
+    .globl __sys_clone
     .align 4
 
-__clone:
+__sys_clone:
     pushl   %ebx
     pushl   %ecx
     pushl   %edx
     pushl   %esi
-    mov     20(%esp), %ebx
-    mov     24(%esp), %ecx
-    mov     28(%esp), %edx
-    mov     32(%esp), %esi
+    pushl   %edi
+    mov     24(%esp), %ebx
+    mov     28(%esp), %ecx
+    mov     32(%esp), %edx
+    mov     36(%esp), %esi
+    mov     40(%esp), %edi
     movl    $__NR_clone, %eax
     int     $0x80
     cmpl    $-129, %eax
@@ -25,6 +27,7 @@
     addl    $4, %esp
     orl     $-1, %eax
 1:
+    popl    %edi
     popl    %esi
     popl    %edx
     popl    %ecx
diff --git a/libc/arch-x86/syscalls/setreuid.S b/libc/arch-x86/syscalls/ioprio_get.S
similarity index 79%
copy from libc/arch-x86/syscalls/setreuid.S
copy to libc/arch-x86/syscalls/ioprio_get.S
index 99e5d5b..3620271 100644
--- a/libc/arch-x86/syscalls/setreuid.S
+++ b/libc/arch-x86/syscalls/ioprio_get.S
@@ -2,16 +2,16 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setreuid, @function
-    .globl setreuid
+    .type ioprio_get, @function
+    .globl ioprio_get
     .align 4
 
-setreuid:
+ioprio_get:
     pushl   %ebx
     pushl   %ecx
     mov     12(%esp), %ebx
     mov     16(%esp), %ecx
-    movl    $__NR_setreuid32, %eax
+    movl    $__NR_ioprio_get, %eax
     int     $0x80
     cmpl    $-129, %eax
     jb      1f
diff --git a/libc/arch-x86/syscalls/setresuid.S b/libc/arch-x86/syscalls/ioprio_set.S
similarity index 81%
copy from libc/arch-x86/syscalls/setresuid.S
copy to libc/arch-x86/syscalls/ioprio_set.S
index f81cb39..174d923 100644
--- a/libc/arch-x86/syscalls/setresuid.S
+++ b/libc/arch-x86/syscalls/ioprio_set.S
@@ -2,18 +2,18 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setresuid, @function
-    .globl setresuid
+    .type ioprio_set, @function
+    .globl ioprio_set
     .align 4
 
-setresuid:
+ioprio_set:
     pushl   %ebx
     pushl   %ecx
     pushl   %edx
     mov     16(%esp), %ebx
     mov     20(%esp), %ecx
     mov     24(%esp), %edx
-    movl    $__NR_setresuid32, %eax
+    movl    $__NR_ioprio_set, %eax
     int     $0x80
     cmpl    $-129, %eax
     jb      1f
diff --git a/libc/arch-x86/syscalls/setreuid.S b/libc/arch-x86/syscalls/sigaltstack.S
similarity index 78%
copy from libc/arch-x86/syscalls/setreuid.S
copy to libc/arch-x86/syscalls/sigaltstack.S
index 99e5d5b..d39419d 100644
--- a/libc/arch-x86/syscalls/setreuid.S
+++ b/libc/arch-x86/syscalls/sigaltstack.S
@@ -2,16 +2,16 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type setreuid, @function
-    .globl setreuid
+    .type sigaltstack, @function
+    .globl sigaltstack
     .align 4
 
-setreuid:
+sigaltstack:
     pushl   %ebx
     pushl   %ecx
     mov     12(%esp), %ebx
     mov     16(%esp), %ecx
-    movl    $__NR_setreuid32, %eax
+    movl    $__NR_sigaltstack, %eax
     int     $0x80
     cmpl    $-129, %eax
     jb      1f
diff --git a/libc/bionic/bionic_clone.c b/libc/bionic/bionic_clone.c
new file mode 100644
index 0000000..6b2fa58
--- /dev/null
+++ b/libc/bionic/bionic_clone.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+#define __GNU_SOURCE 1
+#include <sched.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* WARNING: AT THE MOMENT, THIS IS ONLY SUPPORTED ON ARM
+ */
+
+extern int  __bionic_clone(unsigned long   clone_flags,
+                           void*           newsp,
+                           int            *parent_tidptr,
+                           void           *new_tls,
+                           int            *child_tidptr,
+                           int            (*fn)(void *),
+                           void          *arg);
+
+extern void _exit_thread(int  retCode);
+
+/* this function is called from the __bionic_clone
+ * assembly fragment to call the thread function
+ * then exit. */
+extern void
+__bionic_clone_entry( int (*fn)(void *), void *arg )
+{
+    int  ret = (*fn)(arg);
+    _exit_thread(ret);
+}
+
+int
+clone(int (*fn)(void *), void *child_stack, int flags, void*  arg, ...)
+{
+    va_list  args;
+    int     *parent_tidptr = NULL;
+    void    *new_tls = NULL;
+    int     *child_tidptr = NULL;
+    int     ret;
+
+    /* extract optional parameters - they are cummulative */
+    va_start(args, arg);
+    if (flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID)) {
+        parent_tidptr = va_arg(args, int*);
+    }
+    if (flags & (CLONE_SETTLS|CLONE_CHILD_SETTID)) {
+        new_tls = va_arg(args, void*);
+    }
+    if (flags & CLONE_CHILD_SETTID) {
+        child_tidptr = va_arg(args, int*);
+    }
+    va_end(args);
+
+    ret = __bionic_clone(flags, child_stack, parent_tidptr, new_tls, child_tidptr, fn, arg);
+    return ret;
+}
diff --git a/libc/bionic/clearenv.c b/libc/bionic/clearenv.c
new file mode 100644
index 0000000..ffc58d9
--- /dev/null
+++ b/libc/bionic/clearenv.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+extern char** environ;
+
+int clearenv(void)
+{
+	char **P = environ;
+	int offset;
+
+	for (P = &environ[offset]; *P; ++P)
+		*P = 0;
+        return 0;
+}
diff --git a/libc/bionic/cpuacct.c b/libc/bionic/cpuacct.c
new file mode 100644
index 0000000..abdbc51
--- /dev/null
+++ b/libc/bionic/cpuacct.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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 <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+//#include <sys/types.h>
+
+int cpuacct_add(uid_t uid)
+{
+    int count;
+    FILE *fp;
+    char buf[80];
+
+    count = snprintf(buf, sizeof(buf), "/acct/uid/%d/tasks", uid);
+    fp = fopen(buf, "w+");
+    if (!fp) {
+        /* Note: sizeof("tasks") returns 6, which includes the NULL char */
+        buf[count - sizeof("tasks")] = 0;
+        if (mkdir(buf, 0775) < 0)
+            return -errno;
+
+        /* Note: sizeof("tasks") returns 6, which includes the NULL char */
+        buf[count - sizeof("tasks")] = '/';
+        fp = fopen(buf, "w+");
+    }
+    if (!fp)
+        return -errno;
+
+    fprintf(fp, "0");
+    if (fclose(fp))
+        return -errno;
+
+    return 0;
+}
diff --git a/libc/bionic/dlmalloc.c b/libc/bionic/dlmalloc.c
index f6f878e..19fbb75 100644
--- a/libc/bionic/dlmalloc.c
+++ b/libc/bionic/dlmalloc.c
@@ -390,9 +390,9 @@
   size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set
 
 REALLOC_ZERO_BYTES_FREES    default: not defined
-  This should be set if a call to realloc with zero bytes should 
-  be the same as a call to free. Some people think it should. Otherwise, 
-  since this malloc returns a unique pointer for malloc(0), so does 
+  This should be set if a call to realloc with zero bytes should
+  be the same as a call to free. Some people think it should. Otherwise,
+  since this malloc returns a unique pointer for malloc(0), so does
   realloc(p, 0).
 
 LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
@@ -671,7 +671,7 @@
 /* ------------------- Declarations of public routines ------------------- */
 
 /* Check an additional macro for the five primary functions */
-#if !defined(USE_DL_PREFIX) || !defined(MALLOC_LEAK_CHECK) 
+#ifndef USE_DL_PREFIX
 #define dlcalloc               calloc
 #define dlfree                 free
 #define dlmalloc               malloc
@@ -3627,7 +3627,7 @@
       m->seg.sflags = mmap_flag;
       m->magic = mparams.magic;
       init_bins(m);
-      if (is_global(m)) 
+      if (is_global(m))
         init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
       else {
         /* Offset top by embedded malloc_state */
@@ -3778,7 +3778,7 @@
     }
 
     /* Unmap any unused mmapped segments */
-    if (HAVE_MMAP) 
+    if (HAVE_MMAP)
       released += release_unused_segments(m);
 
     /* On failure, disable autotrim to avoid repeated failed future calls */
@@ -3986,7 +3986,7 @@
     while (a < alignment) a <<= 1;
     alignment = a;
   }
-  
+
   if (bytes >= MAX_REQUEST - alignment) {
     if (m != 0)  { /* Test isn't needed but avoids compiler warning */
       MALLOC_FAILURE_ACTION;
@@ -5446,5 +5446,5 @@
     Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
       * Based loosely on libg++-1.2X malloc. (It retains some of the overall
          structure of old version,  but most details differ.)
- 
+
 */
diff --git a/libc/bionic/dlmalloc.h b/libc/bionic/dlmalloc.h
index e5f7d4a..1b642d2 100644
--- a/libc/bionic/dlmalloc.h
+++ b/libc/bionic/dlmalloc.h
@@ -1,14 +1,14 @@
 /*
   Default header file for malloc-2.8.x, written by Doug Lea
   and released to the public domain, as explained at
-  http://creativecommons.org/licenses/publicdomain. 
- 
+  http://creativecommons.org/licenses/publicdomain.
+
   last update: Mon Aug 15 08:55:52 2005  Doug Lea  (dl at gee)
 
   This header is for ANSI C/C++ only.  You can set any of
   the following #defines before including:
 
-  * If USE_DL_PREFIX is defined, it is assumed that malloc.c 
+  * If USE_DL_PREFIX is defined, it is assumed that malloc.c
     was also compiled with this option, so all routines
     have names starting with "dl".
 
@@ -34,7 +34,7 @@
 #if !ONLY_MSPACES
 
 /* Check an additional macro for the five primary functions */
-#if !defined(USE_DL_PREFIX) || !defined(MALLOC_LEAK_CHECK) 
+#if !defined(USE_DL_PREFIX)
 #define dlcalloc               calloc
 #define dlfree                 free
 #define dlmalloc               malloc
diff --git a/libc/bionic/err.c b/libc/bionic/err.c
new file mode 100644
index 0000000..535b7e1
--- /dev/null
+++ b/libc/bionic/err.c
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+extern char *__progname;
+
+__noreturn void
+err(int eval, const char *fmt, ...)
+{
+        va_list ap;
+
+        va_start(ap, fmt);
+        verr(eval, fmt, ap);
+        va_end(ap);
+}
+
+__noreturn void
+errx(int eval, const char *fmt, ...)
+{
+        va_list ap;
+
+        va_start(ap, fmt);
+        verrx(eval, fmt, ap);
+        va_end(ap);
+}
+
+__noreturn void
+verr(int eval, const char *fmt, va_list ap)
+{
+        int sverrno;
+
+        sverrno = errno;
+        (void)fprintf(stderr, "%s: ", __progname);
+        if (fmt != NULL) {
+                (void)vfprintf(stderr, fmt, ap);
+                (void)fprintf(stderr, ": ");
+        }
+        (void)fprintf(stderr, "%s\n", strerror(sverrno));
+        exit(eval);
+}
+
+
+__noreturn void
+verrx(int eval, const char *fmt, va_list ap)
+{
+        (void)fprintf(stderr, "%s: ", __progname);
+        if (fmt != NULL)
+                (void)vfprintf(stderr, fmt, ap);
+        (void)fprintf(stderr, "\n");
+        exit(eval);
+}
+
+void
+warn(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vwarn(fmt, ap);
+	va_end(ap);
+}
+
+void
+warnx(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vwarnx(fmt, ap);
+	va_end(ap);
+}
+
+void
+vwarn(const char *fmt, va_list ap)
+{
+	int sverrno;
+
+	sverrno = errno;
+	(void)fprintf(stderr, "%s: ", __progname);
+	if (fmt != NULL) {
+		(void)vfprintf(stderr, fmt, ap);
+		(void)fprintf(stderr, ": ");
+	}
+	(void)fprintf(stderr, "%s\n", strerror(sverrno));
+}
+
+void
+vwarnx(const char *fmt, va_list ap)
+{
+	(void)fprintf(stderr, "%s: ", __progname);
+	if (fmt != NULL)
+		(void)vfprintf(stderr, fmt, ap);
+	(void)fprintf(stderr, "\n");
+}
diff --git a/libc/bionic/fdprintf.c b/libc/bionic/fdprintf.c
new file mode 100644
index 0000000..c1d05ad
--- /dev/null
+++ b/libc/bionic/fdprintf.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int vfdprintf(int fd, const char * __restrict format, __va_list ap)
+{
+	char *buf=0;
+	int ret;
+	ret = vasprintf(&buf, format, ap);
+	if (ret < 0)
+		goto end;
+
+	ret = write(fd, buf, ret);
+	free(buf);
+end:
+	return ret;
+}
+
+int fdprintf(int fd, const char * __restrict format, ...)
+{
+	__va_list ap;
+	int ret;
+
+	va_start(ap, format);
+	ret = vfdprintf(fd, format, ap);
+	va_end(ap);
+
+	return ret;
+}
diff --git a/libc/bionic/fork.c b/libc/bionic/fork.c
index 1c6a4ba..e20f548 100644
--- a/libc/bionic/fork.c
+++ b/libc/bionic/fork.c
@@ -43,6 +43,14 @@
     ret = __fork();
     if (ret != 0) {  /* not a child process */
         __timer_table_start_stop(0);
+    } else {
+        /*
+         * Newly created process must update cpu accounting.
+         * Call cpuacct_add passing in our uid, which will take
+         * the current task id and add it to the uid group passed
+         * as a parameter.
+         */
+        cpuacct_add(getuid());
     }
     return ret;
 }
diff --git a/libc/bionic/fts.c b/libc/bionic/fts.c
new file mode 100644
index 0000000..3dcfb28
--- /dev/null
+++ b/libc/bionic/fts.c
@@ -0,0 +1,1041 @@
+/*	$OpenBSD: fts.c,v 1.43 2009/08/27 16:19:27 millert Exp $	*/
+
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	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/param.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+static FTSENT	*fts_alloc(FTS *, char *, size_t);
+static FTSENT	*fts_build(FTS *, int);
+static void	 fts_lfree(FTSENT *);
+static void	 fts_load(FTS *, FTSENT *);
+static size_t	 fts_maxarglen(char * const *);
+static void	 fts_padjust(FTS *, FTSENT *);
+static int	 fts_palloc(FTS *, size_t);
+static FTSENT	*fts_sort(FTS *, FTSENT *, int);
+static u_short	 fts_stat(FTS *, FTSENT *, int);
+static int	 fts_safe_changedir(FTS *, FTSENT *, int, char *);
+
+#define	ISDOT(a)	(a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
+
+#define	CLR(opt)	(sp->fts_options &= ~(opt))
+#define	ISSET(opt)	(sp->fts_options & (opt))
+#define	SET(opt)	(sp->fts_options |= (opt))
+
+#define	FCHDIR(sp, fd)	(!ISSET(FTS_NOCHDIR) && fchdir(fd))
+
+/* fts_build flags */
+#define	BCHILD		1		/* fts_children */
+#define	BNAMES		2		/* fts_children, names only */
+#define	BREAD		3		/* fts_read */
+
+FTS *
+fts_open(char * const *argv, int options,
+    int (*compar)(const FTSENT **, const FTSENT **))
+{
+	FTS *sp;
+	FTSENT *p, *root;
+	int nitems;
+	FTSENT *parent, *tmp;
+	size_t len;
+
+	/* Options check. */
+	if (options & ~FTS_OPTIONMASK) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/* Allocate/initialize the stream */
+	if ((sp = calloc(1, sizeof(FTS))) == NULL)
+		return (NULL);
+	sp->fts_compar = compar;
+	sp->fts_options = options;
+
+	/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
+	if (ISSET(FTS_LOGICAL))
+		SET(FTS_NOCHDIR);
+
+	/*
+	 * Start out with 1K of path space, and enough, in any case,
+	 * to hold the user's paths.
+	 */
+	if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
+		goto mem1;
+
+	/* Allocate/initialize root's parent. */
+	if ((parent = fts_alloc(sp, "", 0)) == NULL)
+		goto mem2;
+	parent->fts_level = FTS_ROOTPARENTLEVEL;
+
+	/* Allocate/initialize root(s). */
+	for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
+		/* Don't allow zero-length paths. */
+		if ((len = strlen(*argv)) == 0) {
+			errno = ENOENT;
+			goto mem3;
+		}
+
+		if ((p = fts_alloc(sp, *argv, len)) == NULL)
+			goto mem3;
+		p->fts_level = FTS_ROOTLEVEL;
+		p->fts_parent = parent;
+		p->fts_accpath = p->fts_name;
+		p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
+
+		/* Command-line "." and ".." are real directories. */
+		if (p->fts_info == FTS_DOT)
+			p->fts_info = FTS_D;
+
+		/*
+		 * If comparison routine supplied, traverse in sorted
+		 * order; otherwise traverse in the order specified.
+		 */
+		if (compar) {
+			p->fts_link = root;
+			root = p;
+		} else {
+			p->fts_link = NULL;
+			if (root == NULL)
+				tmp = root = p;
+			else {
+				tmp->fts_link = p;
+				tmp = p;
+			}
+		}
+	}
+	if (compar && nitems > 1)
+		root = fts_sort(sp, root, nitems);
+
+	/*
+	 * Allocate a dummy pointer and make fts_read think that we've just
+	 * finished the node before the root(s); set p->fts_info to FTS_INIT
+	 * so that everything about the "current" node is ignored.
+	 */
+	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
+		goto mem3;
+	sp->fts_cur->fts_link = root;
+	sp->fts_cur->fts_info = FTS_INIT;
+
+	/*
+	 * If using chdir(2), grab a file descriptor pointing to dot to ensure
+	 * that we can get back here; this could be avoided for some paths,
+	 * but almost certainly not worth the effort.  Slashes, symbolic links,
+	 * and ".." are all fairly nasty problems.  Note, if we can't get the
+	 * descriptor we run anyway, just more slowly.
+	 */
+	if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
+		SET(FTS_NOCHDIR);
+
+	if (nitems == 0)
+		free(parent);
+
+	return (sp);
+
+mem3:	fts_lfree(root);
+	free(parent);
+mem2:	free(sp->fts_path);
+mem1:	free(sp);
+	return (NULL);
+}
+
+static void
+fts_load(FTS *sp, FTSENT *p)
+{
+	size_t len;
+	char *cp;
+
+	/*
+	 * Load the stream structure for the next traversal.  Since we don't
+	 * actually enter the directory until after the preorder visit, set
+	 * the fts_accpath field specially so the chdir gets done to the right
+	 * place and the user can access the first node.  From fts_open it's
+	 * known that the path will fit.
+	 */
+	len = p->fts_pathlen = p->fts_namelen;
+	memmove(sp->fts_path, p->fts_name, len + 1);
+	if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
+		len = strlen(++cp);
+		memmove(p->fts_name, cp, len + 1);
+		p->fts_namelen = len;
+	}
+	p->fts_accpath = p->fts_path = sp->fts_path;
+	sp->fts_dev = p->fts_dev;
+}
+
+int
+fts_close(FTS *sp)
+{
+	FTSENT *freep, *p;
+	int rfd, error = 0;
+
+	/*
+	 * This still works if we haven't read anything -- the dummy structure
+	 * points to the root list, so we step through to the end of the root
+	 * list which has a valid parent pointer.
+	 */
+	if (sp->fts_cur) {
+		for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+			freep = p;
+			p = p->fts_link ? p->fts_link : p->fts_parent;
+			free(freep);
+		}
+		free(p);
+	}
+
+	/* Stash the original directory fd if needed. */
+	rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd;
+
+	/* Free up child linked list, sort array, path buffer, stream ptr.*/
+	if (sp->fts_child)
+		fts_lfree(sp->fts_child);
+	if (sp->fts_array)
+		free(sp->fts_array);
+	free(sp->fts_path);
+	free(sp);
+
+	/* Return to original directory, checking for error. */
+	if (rfd != -1) {
+		int saved_errno;
+		error = fchdir(rfd);
+		saved_errno = errno;
+		(void)close(rfd);
+		errno = saved_errno;
+	}
+
+	return (error);
+}
+
+/*
+ * Special case of "/" at the end of the path so that slashes aren't
+ * appended which would cause paths to be written as "....//foo".
+ */
+#define	NAPPEND(p)							\
+	(p->fts_path[p->fts_pathlen - 1] == '/'				\
+	    ? p->fts_pathlen - 1 : p->fts_pathlen)
+
+FTSENT *
+fts_read(FTS *sp)
+{
+	FTSENT *p, *tmp;
+	int instr;
+	char *t;
+	int saved_errno;
+
+	/* If finished or unrecoverable error, return NULL. */
+	if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+		return (NULL);
+
+	/* Set current node pointer. */
+	p = sp->fts_cur;
+
+	/* Save and zero out user instructions. */
+	instr = p->fts_instr;
+	p->fts_instr = FTS_NOINSTR;
+
+	/* Any type of file may be re-visited; re-stat and re-turn. */
+	if (instr == FTS_AGAIN) {
+		p->fts_info = fts_stat(sp, p, 0);
+		return (p);
+	}
+
+	/*
+	 * Following a symlink -- SLNONE test allows application to see
+	 * SLNONE and recover.  If indirecting through a symlink, have
+	 * keep a pointer to current location.  If unable to get that
+	 * pointer, follow fails.
+	 */
+	if (instr == FTS_FOLLOW &&
+	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+		p->fts_info = fts_stat(sp, p, 1);
+		if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+			if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
+				p->fts_errno = errno;
+				p->fts_info = FTS_ERR;
+			} else
+				p->fts_flags |= FTS_SYMFOLLOW;
+		}
+		return (p);
+	}
+
+	/* Directory in pre-order. */
+	if (p->fts_info == FTS_D) {
+		/* If skipped or crossed mount point, do post-order visit. */
+		if (instr == FTS_SKIP ||
+		    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
+			if (p->fts_flags & FTS_SYMFOLLOW)
+				(void)close(p->fts_symfd);
+			if (sp->fts_child) {
+				fts_lfree(sp->fts_child);
+				sp->fts_child = NULL;
+			}
+			p->fts_info = FTS_DP;
+			return (p);
+		}
+
+		/* Rebuild if only read the names and now traversing. */
+		if (sp->fts_child && ISSET(FTS_NAMEONLY)) {
+			CLR(FTS_NAMEONLY);
+			fts_lfree(sp->fts_child);
+			sp->fts_child = NULL;
+		}
+
+		/*
+		 * Cd to the subdirectory.
+		 *
+		 * If have already read and now fail to chdir, whack the list
+		 * to make the names come out right, and set the parent errno
+		 * so the application will eventually get an error condition.
+		 * Set the FTS_DONTCHDIR flag so that when we logically change
+		 * directories back to the parent we don't do a chdir.
+		 *
+		 * If haven't read do so.  If the read fails, fts_build sets
+		 * FTS_STOP or the fts_info field of the node.
+		 */
+		if (sp->fts_child) {
+			if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
+				p->fts_errno = errno;
+				p->fts_flags |= FTS_DONTCHDIR;
+				for (p = sp->fts_child; p; p = p->fts_link)
+					p->fts_accpath =
+					    p->fts_parent->fts_accpath;
+			}
+		} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
+			if (ISSET(FTS_STOP))
+				return (NULL);
+			return (p);
+		}
+		p = sp->fts_child;
+		sp->fts_child = NULL;
+		goto name;
+	}
+
+	/* Move to the next node on this level. */
+next:	tmp = p;
+	if ((p = p->fts_link)) {
+		free(tmp);
+
+		/*
+		 * If reached the top, return to the original directory (or
+		 * the root of the tree), and load the paths for the next root.
+		 */
+		if (p->fts_level == FTS_ROOTLEVEL) {
+			if (FCHDIR(sp, sp->fts_rfd)) {
+				SET(FTS_STOP);
+				return (NULL);
+			}
+			fts_load(sp, p);
+			return (sp->fts_cur = p);
+		}
+
+		/*
+		 * User may have called fts_set on the node.  If skipped,
+		 * ignore.  If followed, get a file descriptor so we can
+		 * get back if necessary.
+		 */
+		if (p->fts_instr == FTS_SKIP)
+			goto next;
+		if (p->fts_instr == FTS_FOLLOW) {
+			p->fts_info = fts_stat(sp, p, 1);
+			if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+				if ((p->fts_symfd =
+				    open(".", O_RDONLY, 0)) < 0) {
+					p->fts_errno = errno;
+					p->fts_info = FTS_ERR;
+				} else
+					p->fts_flags |= FTS_SYMFOLLOW;
+			}
+			p->fts_instr = FTS_NOINSTR;
+		}
+
+name:		t = sp->fts_path + NAPPEND(p->fts_parent);
+		*t++ = '/';
+		memmove(t, p->fts_name, p->fts_namelen + 1);
+		return (sp->fts_cur = p);
+	}
+
+	/* Move up to the parent node. */
+	p = tmp->fts_parent;
+	free(tmp);
+
+	if (p->fts_level == FTS_ROOTPARENTLEVEL) {
+		/*
+		 * Done; free everything up and set errno to 0 so the user
+		 * can distinguish between error and EOF.
+		 */
+		free(p);
+		errno = 0;
+		return (sp->fts_cur = NULL);
+	}
+
+	/* NUL terminate the pathname. */
+	sp->fts_path[p->fts_pathlen] = '\0';
+
+	/*
+	 * Return to the parent directory.  If at a root node or came through
+	 * a symlink, go back through the file descriptor.  Otherwise, cd up
+	 * one directory.
+	 */
+	if (p->fts_level == FTS_ROOTLEVEL) {
+		if (FCHDIR(sp, sp->fts_rfd)) {
+			SET(FTS_STOP);
+			sp->fts_cur = p;
+			return (NULL);
+		}
+	} else if (p->fts_flags & FTS_SYMFOLLOW) {
+		if (FCHDIR(sp, p->fts_symfd)) {
+			saved_errno = errno;
+			(void)close(p->fts_symfd);
+			errno = saved_errno;
+			SET(FTS_STOP);
+			sp->fts_cur = p;
+			return (NULL);
+		}
+		(void)close(p->fts_symfd);
+	} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
+	    fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
+		SET(FTS_STOP);
+		sp->fts_cur = p;
+		return (NULL);
+	}
+	p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+	return (sp->fts_cur = p);
+}
+
+/*
+ * Fts_set takes the stream as an argument although it's not used in this
+ * implementation; it would be necessary if anyone wanted to add global
+ * semantics to fts using fts_set.  An error return is allowed for similar
+ * reasons.
+ */
+/* ARGSUSED */
+int
+fts_set(FTS *sp, FTSENT *p, int instr)
+{
+	if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
+	    instr != FTS_NOINSTR && instr != FTS_SKIP) {
+		errno = EINVAL;
+		return (1);
+	}
+	p->fts_instr = instr;
+	return (0);
+}
+
+FTSENT *
+fts_children(FTS *sp, int instr)
+{
+	FTSENT *p;
+	int fd;
+
+	if (instr && instr != FTS_NAMEONLY) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/* Set current node pointer. */
+	p = sp->fts_cur;
+
+	/*
+	 * Errno set to 0 so user can distinguish empty directory from
+	 * an error.
+	 */
+	errno = 0;
+
+	/* Fatal errors stop here. */
+	if (ISSET(FTS_STOP))
+		return (NULL);
+
+	/* Return logical hierarchy of user's arguments. */
+	if (p->fts_info == FTS_INIT)
+		return (p->fts_link);
+
+	/*
+	 * If not a directory being visited in pre-order, stop here.  Could
+	 * allow FTS_DNR, assuming the user has fixed the problem, but the
+	 * same effect is available with FTS_AGAIN.
+	 */
+	if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
+		return (NULL);
+
+	/* Free up any previous child list. */
+	if (sp->fts_child)
+		fts_lfree(sp->fts_child);
+
+	if (instr == FTS_NAMEONLY) {
+		SET(FTS_NAMEONLY);
+		instr = BNAMES;
+	} else
+		instr = BCHILD;
+
+	/*
+	 * If using chdir on a relative path and called BEFORE fts_read does
+	 * its chdir to the root of a traversal, we can lose -- we need to
+	 * chdir into the subdirectory, and we don't know where the current
+	 * directory is, so we can't get back so that the upcoming chdir by
+	 * fts_read will work.
+	 */
+	if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
+	    ISSET(FTS_NOCHDIR))
+		return (sp->fts_child = fts_build(sp, instr));
+
+	if ((fd = open(".", O_RDONLY, 0)) < 0)
+		return (NULL);
+	sp->fts_child = fts_build(sp, instr);
+	if (fchdir(fd)) {
+		(void)close(fd);
+		return (NULL);
+	}
+	(void)close(fd);
+	return (sp->fts_child);
+}
+
+/*
+ * This is the tricky part -- do not casually change *anything* in here.  The
+ * idea is to build the linked list of entries that are used by fts_children
+ * and fts_read.  There are lots of special cases.
+ *
+ * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
+ * set and it's a physical walk (so that symbolic links can't be directories),
+ * we can do things quickly.  First, if it's a 4.4BSD file system, the type
+ * of the file is in the directory entry.  Otherwise, we assume that the number
+ * of subdirectories in a node is equal to the number of links to the parent.
+ * The former skips all stat calls.  The latter skips stat calls in any leaf
+ * directories and for any files after the subdirectories in the directory have
+ * been found, cutting the stat calls by about 2/3.
+ */
+static FTSENT *
+fts_build(FTS *sp, int type)
+{
+	struct dirent *dp;
+	FTSENT *p, *head;
+	FTSENT *cur, *tail;
+	DIR *dirp;
+	void *oldaddr;
+	size_t len, maxlen;
+	int nitems, cderrno, descend, level, nlinks, nostat, doadjust;
+	int saved_errno;
+	char *cp;
+
+	/* Set current node pointer. */
+	cur = sp->fts_cur;
+
+	/*
+	 * Open the directory for reading.  If this fails, we're done.
+	 * If being called from fts_read, set the fts_info field.
+	 */
+	if ((dirp = opendir(cur->fts_accpath)) == NULL) {
+		if (type == BREAD) {
+			cur->fts_info = FTS_DNR;
+			cur->fts_errno = errno;
+		}
+		return (NULL);
+	}
+
+	/*
+	 * Nlinks is the number of possible entries of type directory in the
+	 * directory if we're cheating on stat calls, 0 if we're not doing
+	 * any stat calls at all, -1 if we're doing stats on everything.
+	 */
+	if (type == BNAMES)
+		nlinks = 0;
+	else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
+		nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
+		nostat = 1;
+	} else {
+		nlinks = -1;
+		nostat = 0;
+	}
+
+#ifdef notdef
+	(void)printf("nlinks == %d (cur: %u)\n", nlinks, cur->fts_nlink);
+	(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
+	    ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
+#endif
+	/*
+	 * If we're going to need to stat anything or we want to descend
+	 * and stay in the directory, chdir.  If this fails we keep going,
+	 * but set a flag so we don't chdir after the post-order visit.
+	 * We won't be able to stat anything, but we can still return the
+	 * names themselves.  Note, that since fts_read won't be able to
+	 * chdir into the directory, it will have to return different path
+	 * names than before, i.e. "a/b" instead of "b".  Since the node
+	 * has already been visited in pre-order, have to wait until the
+	 * post-order visit to return the error.  There is a special case
+	 * here, if there was nothing to stat then it's not an error to
+	 * not be able to stat.  This is all fairly nasty.  If a program
+	 * needed sorted entries or stat information, they had better be
+	 * checking FTS_NS on the returned nodes.
+	 */
+	cderrno = 0;
+	if (nlinks || type == BREAD) {
+		if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
+			if (nlinks && type == BREAD)
+				cur->fts_errno = errno;
+			cur->fts_flags |= FTS_DONTCHDIR;
+			descend = 0;
+			cderrno = errno;
+			(void)closedir(dirp);
+			dirp = NULL;
+		} else
+			descend = 1;
+	} else
+		descend = 0;
+
+	/*
+	 * Figure out the max file name length that can be stored in the
+	 * current path -- the inner loop allocates more path as necessary.
+	 * We really wouldn't have to do the maxlen calculations here, we
+	 * could do them in fts_read before returning the path, but it's a
+	 * lot easier here since the length is part of the dirent structure.
+	 *
+	 * If not changing directories set a pointer so that can just append
+	 * each new name into the path.
+	 */
+	len = NAPPEND(cur);
+	if (ISSET(FTS_NOCHDIR)) {
+		cp = sp->fts_path + len;
+		*cp++ = '/';
+	}
+	len++;
+	maxlen = sp->fts_pathlen - len;
+
+	/*
+	 * fts_level is a short so we must prevent it from wrapping
+	 * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL.
+	 */
+	level = cur->fts_level;
+	if (level < FTS_MAXLEVEL)
+	    level++;
+
+	/* Read the directory, attaching each entry to the `link' pointer. */
+	doadjust = 0;
+	for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
+		if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
+			continue;
+
+		if (!(p = fts_alloc(sp, dp->d_name, strlen(dp->d_name))))
+			goto mem1;
+		if (strlen(dp->d_name) >= maxlen) {	/* include space for NUL */
+			oldaddr = sp->fts_path;
+			if (fts_palloc(sp, strlen(dp->d_name) +len + 1)) {
+				/*
+				 * No more memory for path or structures.  Save
+				 * errno, free up the current structure and the
+				 * structures already allocated.
+				 */
+mem1:				saved_errno = errno;
+				if (p)
+					free(p);
+				fts_lfree(head);
+				(void)closedir(dirp);
+				cur->fts_info = FTS_ERR;
+				SET(FTS_STOP);
+				errno = saved_errno;
+				return (NULL);
+			}
+			/* Did realloc() change the pointer? */
+			if (oldaddr != sp->fts_path) {
+				doadjust = 1;
+				if (ISSET(FTS_NOCHDIR))
+					cp = sp->fts_path + len;
+			}
+			maxlen = sp->fts_pathlen - len;
+		}
+
+		p->fts_level = level;
+		p->fts_parent = sp->fts_cur;
+		p->fts_pathlen = len + strlen(dp->d_name);
+		if (p->fts_pathlen < len) {
+			/*
+			 * If we wrap, free up the current structure and
+			 * the structures already allocated, then error
+			 * out with ENAMETOOLONG.
+			 */
+			free(p);
+			fts_lfree(head);
+			(void)closedir(dirp);
+			cur->fts_info = FTS_ERR;
+			SET(FTS_STOP);
+			errno = ENAMETOOLONG;
+			return (NULL);
+		}
+
+		if (cderrno) {
+			if (nlinks) {
+				p->fts_info = FTS_NS;
+				p->fts_errno = cderrno;
+			} else
+				p->fts_info = FTS_NSOK;
+			p->fts_accpath = cur->fts_accpath;
+		} else if (nlinks == 0
+#ifdef DT_DIR
+		    || (nostat &&
+		    dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
+#endif
+		    ) {
+			p->fts_accpath =
+			    ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
+			p->fts_info = FTS_NSOK;
+		} else {
+			/* Build a file name for fts_stat to stat. */
+			if (ISSET(FTS_NOCHDIR)) {
+				p->fts_accpath = p->fts_path;
+				memmove(cp, p->fts_name, p->fts_namelen + 1);
+			} else
+				p->fts_accpath = p->fts_name;
+			/* Stat it. */
+			p->fts_info = fts_stat(sp, p, 0);
+
+			/* Decrement link count if applicable. */
+			if (nlinks > 0 && (p->fts_info == FTS_D ||
+			    p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
+				--nlinks;
+		}
+
+		/* We walk in directory order so "ls -f" doesn't get upset. */
+		p->fts_link = NULL;
+		if (head == NULL)
+			head = tail = p;
+		else {
+			tail->fts_link = p;
+			tail = p;
+		}
+		++nitems;
+	}
+	if (dirp)
+		(void)closedir(dirp);
+
+	/*
+	 * If realloc() changed the address of the path, adjust the
+	 * addresses for the rest of the tree and the dir list.
+	 */
+	if (doadjust)
+		fts_padjust(sp, head);
+
+	/*
+	 * If not changing directories, reset the path back to original
+	 * state.
+	 */
+	if (ISSET(FTS_NOCHDIR)) {
+		if (len == sp->fts_pathlen || nitems == 0)
+			--cp;
+		*cp = '\0';
+	}
+
+	/*
+	 * If descended after called from fts_children or after called from
+	 * fts_read and nothing found, get back.  At the root level we use
+	 * the saved fd; if one of fts_open()'s arguments is a relative path
+	 * to an empty directory, we wind up here with no other way back.  If
+	 * can't get back, we're done.
+	 */
+	if (descend && (type == BCHILD || !nitems) &&
+	    (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) :
+	    fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+		cur->fts_info = FTS_ERR;
+		SET(FTS_STOP);
+		return (NULL);
+	}
+
+	/* If didn't find anything, return NULL. */
+	if (!nitems) {
+		if (type == BREAD)
+			cur->fts_info = FTS_DP;
+		return (NULL);
+	}
+
+	/* Sort the entries. */
+	if (sp->fts_compar && nitems > 1)
+		head = fts_sort(sp, head, nitems);
+	return (head);
+}
+
+static u_short
+fts_stat(FTS *sp, FTSENT *p, int follow)
+{
+	FTSENT *t;
+	dev_t dev;
+	ino_t ino;
+	struct stat *sbp, sb;
+	int saved_errno;
+
+	/* If user needs stat info, stat buffer already allocated. */
+	sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
+
+	/*
+	 * If doing a logical walk, or application requested FTS_FOLLOW, do
+	 * a stat(2).  If that fails, check for a non-existent symlink.  If
+	 * fail, set the errno from the stat call.
+	 */
+	if (ISSET(FTS_LOGICAL) || follow) {
+		if (stat(p->fts_accpath, sbp)) {
+			saved_errno = errno;
+			if (!lstat(p->fts_accpath, sbp)) {
+				errno = 0;
+				return (FTS_SLNONE);
+			}
+			p->fts_errno = saved_errno;
+			goto err;
+		}
+	} else if (lstat(p->fts_accpath, sbp)) {
+		p->fts_errno = errno;
+err:		memset(sbp, 0, sizeof(struct stat));
+		return (FTS_NS);
+	}
+
+	if (S_ISDIR(sbp->st_mode)) {
+		/*
+		 * Set the device/inode.  Used to find cycles and check for
+		 * crossing mount points.  Also remember the link count, used
+		 * in fts_build to limit the number of stat calls.  It is
+		 * understood that these fields are only referenced if fts_info
+		 * is set to FTS_D.
+		 */
+		dev = p->fts_dev = sbp->st_dev;
+		ino = p->fts_ino = sbp->st_ino;
+		p->fts_nlink = sbp->st_nlink;
+
+		if (ISDOT(p->fts_name))
+			return (FTS_DOT);
+
+		/*
+		 * Cycle detection is done by brute force when the directory
+		 * is first encountered.  If the tree gets deep enough or the
+		 * number of symbolic links to directories is high enough,
+		 * something faster might be worthwhile.
+		 */
+		for (t = p->fts_parent;
+		    t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+			if (ino == t->fts_ino && dev == t->fts_dev) {
+				p->fts_cycle = t;
+				return (FTS_DC);
+			}
+		return (FTS_D);
+	}
+	if (S_ISLNK(sbp->st_mode))
+		return (FTS_SL);
+	if (S_ISREG(sbp->st_mode))
+		return (FTS_F);
+	return (FTS_DEFAULT);
+}
+
+static FTSENT *
+fts_sort(FTS *sp, FTSENT *head, int nitems)
+{
+	FTSENT **ap, *p;
+
+	/*
+	 * Construct an array of pointers to the structures and call qsort(3).
+	 * Reassemble the array in the order returned by qsort.  If unable to
+	 * sort for memory reasons, return the directory entries in their
+	 * current order.  Allocate enough space for the current needs plus
+	 * 40 so don't realloc one entry at a time.
+	 */
+	if (nitems > sp->fts_nitems) {
+		struct _ftsent **a;
+
+		sp->fts_nitems = nitems + 40;
+		if ((a = realloc(sp->fts_array,
+		    sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
+			if (sp->fts_array)
+				free(sp->fts_array);
+			sp->fts_array = NULL;
+			sp->fts_nitems = 0;
+			return (head);
+		}
+		sp->fts_array = a;
+	}
+	for (ap = sp->fts_array, p = head; p; p = p->fts_link)
+		*ap++ = p;
+	qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
+	for (head = *(ap = sp->fts_array); --nitems; ++ap)
+		ap[0]->fts_link = ap[1];
+	ap[0]->fts_link = NULL;
+	return (head);
+}
+
+static FTSENT *
+fts_alloc(FTS *sp, char *name, size_t namelen)
+{
+	FTSENT *p;
+	size_t len;
+
+	/*
+	 * The file name is a variable length array and no stat structure is
+	 * necessary if the user has set the nostat bit.  Allocate the FTSENT
+	 * structure, the file name and the stat structure in one chunk, but
+	 * be careful that the stat structure is reasonably aligned.  Since the
+	 * fts_name field is declared to be of size 1, the fts_name pointer is
+	 * namelen + 2 before the first possible address of the stat structure.
+	 */
+	len = sizeof(FTSENT) + namelen;
+	if (!ISSET(FTS_NOSTAT))
+		len += sizeof(struct stat) + ALIGNBYTES;
+	if ((p = malloc(len)) == NULL)
+		return (NULL);
+
+	memset(p, 0, len);
+	p->fts_path = sp->fts_path;
+	p->fts_namelen = namelen;
+	p->fts_instr = FTS_NOINSTR;
+	if (!ISSET(FTS_NOSTAT))
+		p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
+	memcpy(p->fts_name, name, namelen);
+
+	return (p);
+}
+
+static void
+fts_lfree(FTSENT *head)
+{
+	FTSENT *p;
+
+	/* Free a linked list of structures. */
+	while ((p = head)) {
+		head = head->fts_link;
+		free(p);
+	}
+}
+
+/*
+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
+ * Most systems will allow creation of paths much longer than MAXPATHLEN, even
+ * though the kernel won't resolve them.  Add the size (not just what's needed)
+ * plus 256 bytes so don't realloc the path 2 bytes at a time.
+ */
+static int
+fts_palloc(FTS *sp, size_t more)
+{
+	char *p;
+
+	/*
+	 * Check for possible wraparound.
+	 */
+	more += 256;
+	if (sp->fts_pathlen + more < sp->fts_pathlen) {
+		if (sp->fts_path)
+			free(sp->fts_path);
+		sp->fts_path = NULL;
+		errno = ENAMETOOLONG;
+		return (1);
+	}
+	sp->fts_pathlen += more;
+	p = realloc(sp->fts_path, sp->fts_pathlen);
+	if (p == NULL) {
+		if (sp->fts_path)
+			free(sp->fts_path);
+		sp->fts_path = NULL;
+		return (1);
+	}
+	sp->fts_path = p;
+	return (0);
+}
+
+/*
+ * When the path is realloc'd, have to fix all of the pointers in structures
+ * already returned.
+ */
+static void
+fts_padjust(FTS *sp, FTSENT *head)
+{
+	FTSENT *p;
+	char *addr = sp->fts_path;
+
+#define	ADJUST(p) {							\
+	if ((p)->fts_accpath != (p)->fts_name) {			\
+		(p)->fts_accpath =					\
+		    (char *)addr + ((p)->fts_accpath - (p)->fts_path);	\
+	}								\
+	(p)->fts_path = addr;						\
+}
+	/* Adjust the current set of children. */
+	for (p = sp->fts_child; p; p = p->fts_link)
+		ADJUST(p);
+
+	/* Adjust the rest of the tree, including the current level. */
+	for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
+		ADJUST(p);
+		p = p->fts_link ? p->fts_link : p->fts_parent;
+	}
+}
+
+static size_t
+fts_maxarglen(char * const *argv)
+{
+	size_t len, max;
+
+	for (max = 0; *argv; ++argv)
+		if ((len = strlen(*argv)) > max)
+			max = len;
+	return (max + 1);
+}
+
+/*
+ * Change to dir specified by fd or p->fts_accpath without getting
+ * tricked by someone changing the world out from underneath us.
+ * Assumes p->fts_dev and p->fts_ino are filled in.
+ */
+static int
+fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
+{
+	int ret, oerrno, newfd;
+	struct stat sb;
+
+	newfd = fd;
+	if (ISSET(FTS_NOCHDIR))
+		return (0);
+	if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
+		return (-1);
+	if (fstat(newfd, &sb)) {
+		ret = -1;
+		goto bail;
+	}
+	if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
+		errno = ENOENT;		/* disinformation */
+		ret = -1;
+		goto bail;
+	}
+	ret = fchdir(newfd);
+bail:
+	oerrno = errno;
+	if (fd < 0)
+		(void)close(newfd);
+	errno = oerrno;
+	return (ret);
+}
diff --git a/libc/bionic/libc_init_dynamic.c b/libc/bionic/libc_init_dynamic.c
index b479b27..682ebcf 100644
--- a/libc/bionic/libc_init_dynamic.c
+++ b/libc/bionic/libc_init_dynamic.c
@@ -52,8 +52,6 @@
 #include "libc_init_common.h"
 #include <bionic_tls.h>
 
-extern void malloc_debug_init();
-
 /* We flag the __libc_preinit function as a constructor to ensure
  * that its address is listed in libc.so's .init_array section.
  * This ensures that the function is called by the dynamic linker
@@ -78,12 +76,11 @@
 
     __libc_init_common(elfdata);
 
-#ifdef MALLOC_LEAK_CHECK
-    /* setup malloc leak checker, requires system properties */
+    /* Setup malloc routines accordingly to the environment.
+     * Requires system properties
+     */
     extern void malloc_debug_init(void);
     malloc_debug_init();
-#endif
-
 }
 
 __noreturn void __libc_init(uintptr_t *elfdata,
diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.c
index e6264bb..d097b6b 100644
--- a/libc/bionic/libc_init_static.c
+++ b/libc/bionic/libc_init_static.c
@@ -68,12 +68,6 @@
     /* Initialize the C runtime environment */
     __libc_init_common(elfdata);
 
-#ifdef MALLOC_LEAK_CHECK
-    /* setup malloc leak checker, requires system properties */
-    extern void malloc_debug_init(void);
-    malloc_debug_init();
-#endif
-
     /* Several Linux ABIs don't pass the onexit pointer, and the ones that
      * do never use it.  Therefore, we ignore it.
      */
diff --git a/libc/bionic/logd_write.c b/libc/bionic/logd_write.c
index 3336428..2c5bf42 100644
--- a/libc/bionic/logd_write.c
+++ b/libc/bionic/logd_write.c
@@ -66,7 +66,7 @@
 
 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
 
-log_channel_t log_channels[LOG_ID_MAX] = {
+static log_channel_t log_channels[LOG_ID_MAX] = {
     { __write_to_log_null, -1, NULL },
     { __write_to_log_init, -1, "/dev/"LOGGER_LOG_MAIN },
     { __write_to_log_init, -1, "/dev/"LOGGER_LOG_RADIO }
@@ -112,6 +112,7 @@
 
         log_channels[log_id].logger =
             (fd < 0) ? __write_to_log_null : __write_to_log_kernel;
+        log_channels[log_id].fd = fd;
 
         pthread_mutex_unlock(&log_init_lock);
 
diff --git a/libc/bionic/malloc_debug_common.c b/libc/bionic/malloc_debug_common.c
new file mode 100644
index 0000000..ec56826
--- /dev/null
+++ b/libc/bionic/malloc_debug_common.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/*
+ * Contains definition of structures, global variables, and implementation of
+ * routines that are used by malloc leak detection code and other components in
+ * the system. The trick is that some components expect these data and
+ * routines to be defined / implemented in libc.so library, regardless
+ * whether or not MALLOC_LEAK_CHECK macro is defined. To make things even
+ * more tricky, malloc leak detection code, implemented in
+ * libc_malloc_debug.so also requires access to these variables and routines
+ * (to fill allocation entry hash table, for example). So, all relevant
+ * variables and routines are defined / implemented here and exported
+ * to all, leak detection code and other components via dynamic (libc.so),
+ * or static (libc.a) linking.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "dlmalloc.h"
+#include "malloc_debug_common.h"
+
+/*
+ * In a VM process, this is set to 1 after fork()ing out of zygote.
+ */
+int gMallocLeakZygoteChild = 0;
+
+pthread_mutex_t gAllocationsMutex = PTHREAD_MUTEX_INITIALIZER;
+HashTable gHashTable;
+
+// =============================================================================
+// output functions
+// =============================================================================
+
+static int hash_entry_compare(const void* arg1, const void* arg2)
+{
+    HashEntry* e1 = *(HashEntry**)arg1;
+    HashEntry* e2 = *(HashEntry**)arg2;
+
+    size_t nbAlloc1 = e1->allocations;
+    size_t nbAlloc2 = e2->allocations;
+    size_t size1 = e1->size & ~SIZE_FLAG_MASK;
+    size_t size2 = e2->size & ~SIZE_FLAG_MASK;
+    size_t alloc1 = nbAlloc1 * size1;
+    size_t alloc2 = nbAlloc2 * size2;
+
+    // sort in descending order by:
+    // 1) total size
+    // 2) number of allocations
+    //
+    // This is used for sorting, not determination of equality, so we don't
+    // need to compare the bit flags.
+    int result;
+    if (alloc1 > alloc2) {
+        result = -1;
+    } else if (alloc1 < alloc2) {
+        result = 1;
+    } else {
+        if (nbAlloc1 > nbAlloc2) {
+            result = -1;
+        } else if (nbAlloc1 < nbAlloc2) {
+            result = 1;
+        } else {
+            result = 0;
+        }
+    }
+    return result;
+}
+
+/*
+ * Retrieve native heap information.
+ *
+ * "*info" is set to a buffer we allocate
+ * "*overallSize" is set to the size of the "info" buffer
+ * "*infoSize" is set to the size of a single entry
+ * "*totalMemory" is set to the sum of all allocations we're tracking; does
+ *   not include heap overhead
+ * "*backtraceSize" is set to the maximum number of entries in the back trace
+ */
+void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
+        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize)
+{
+    // don't do anything if we have invalid arguments
+    if (info == NULL || overallSize == NULL || infoSize == NULL ||
+            totalMemory == NULL || backtraceSize == NULL) {
+        return;
+    }
+
+    pthread_mutex_lock(&gAllocationsMutex);
+
+    if (gHashTable.count == 0) {
+        *info = NULL;
+        *overallSize = 0;
+        *infoSize = 0;
+        *totalMemory = 0;
+        *backtraceSize = 0;
+        goto done;
+    }
+
+    void** list = (void**)dlmalloc(sizeof(void*) * gHashTable.count);
+
+    // get the entries into an array to be sorted
+    int index = 0;
+    int i;
+    for (i = 0 ; i < HASHTABLE_SIZE ; i++) {
+        HashEntry* entry = gHashTable.slots[i];
+        while (entry != NULL) {
+            list[index] = entry;
+            *totalMemory = *totalMemory +
+                ((entry->size & ~SIZE_FLAG_MASK) * entry->allocations);
+            index++;
+            entry = entry->next;
+        }
+    }
+
+    // XXX: the protocol doesn't allow variable size for the stack trace (yet)
+    *infoSize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * BACKTRACE_SIZE);
+    *overallSize = *infoSize * gHashTable.count;
+    *backtraceSize = BACKTRACE_SIZE;
+
+    // now get A byte array big enough for this
+    *info = (uint8_t*)dlmalloc(*overallSize);
+
+    if (*info == NULL) {
+        *overallSize = 0;
+        goto out_nomem_info;
+    }
+
+    qsort((void*)list, gHashTable.count, sizeof(void*), hash_entry_compare);
+
+    uint8_t* head = *info;
+    const int count = gHashTable.count;
+    for (i = 0 ; i < count ; i++) {
+        HashEntry* entry = list[i];
+        size_t entrySize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * entry->numEntries);
+        if (entrySize < *infoSize) {
+            /* we're writing less than a full entry, clear out the rest */
+            memset(head + entrySize, 0, *infoSize - entrySize);
+        } else {
+            /* make sure the amount we're copying doesn't exceed the limit */
+            entrySize = *infoSize;
+        }
+        memcpy(head, &(entry->size), entrySize);
+        head += *infoSize;
+    }
+
+out_nomem_info:
+    dlfree(list);
+
+done:
+    pthread_mutex_unlock(&gAllocationsMutex);
+}
+
+void free_malloc_leak_info(uint8_t* info)
+{
+    dlfree(info);
+}
+
+struct mallinfo mallinfo()
+{
+    return dlmallinfo();
+}
+
+void* valloc(size_t bytes) {
+    /* assume page size of 4096 bytes */
+    return memalign( getpagesize(), bytes );
+}
+
+/* Support for malloc debugging.
+ * Note that if USE_DL_PREFIX is not defined, it's assumed that memory
+ * allocation routines are implemented somewhere else, so all our custom
+ * malloc routines should not be compiled at all.
+ */
+#ifdef USE_DL_PREFIX
+
+/* Table for dispatching malloc calls, initialized with default dispatchers. */
+const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) =
+{
+    dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign
+};
+
+/* Selector of dispatch table to use for dispatching malloc calls. */
+const MallocDebug* __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
+
+void* malloc(size_t bytes) {
+    return __libc_malloc_dispatch->malloc(bytes);
+}
+void free(void* mem) {
+    __libc_malloc_dispatch->free(mem);
+}
+void* calloc(size_t n_elements, size_t elem_size) {
+    return __libc_malloc_dispatch->calloc(n_elements, elem_size);
+}
+void* realloc(void* oldMem, size_t bytes) {
+    return __libc_malloc_dispatch->realloc(oldMem, bytes);
+}
+void* memalign(size_t alignment, size_t bytes) {
+    return __libc_malloc_dispatch->memalign(alignment, bytes);
+}
+
+/* We implement malloc debugging only in libc.so, so code bellow
+ * must be excluded if we compile this file for static libc.a
+ */
+#ifndef LIBC_STATIC
+#include <sys/system_properties.h>
+#include <dlfcn.h>
+#include "logd.h"
+
+// =============================================================================
+// log functions
+// =============================================================================
+
+#define debug_log(format, ...)  \
+   __libc_android_log_print(ANDROID_LOG_DEBUG, "libc", (format), ##__VA_ARGS__ )
+#define error_log(format, ...)  \
+   __libc_android_log_print(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
+#define info_log(format, ...)  \
+   __libc_android_log_print(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
+
+/* Table for dispatching malloc calls, depending on environment. */
+static MallocDebug gMallocUse __attribute__((aligned(32))) = {
+    dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign
+};
+
+extern char*  __progname;
+
+/* Handle to shared library where actual memory allocation is implemented.
+ * This library is loaded and memory allocation calls are redirected there
+ * when libc.debug.malloc environment variable contains value other than
+ * zero:
+ * 1  - For memory leak detections.
+ * 5  - For filling allocated / freed memory with patterns defined by
+ *      CHK_SENTINEL_VALUE, and CHK_FILL_FREE macros.
+ * 10 - For adding pre-, and post- allocation stubs in order to detect
+ *      buffer overruns.
+ * Note that emulator's memory allocation instrumentation is not controlled by
+ * libc.debug.malloc value, but rather by emulator, started with -memcheck
+ * option. Note also, that if emulator has started with -memcheck option,
+ * emulator's instrumented memory allocation will take over value saved in
+ * libc.debug.malloc. In other words, if emulator has started with -memcheck
+ * option, libc.debug.malloc value is ignored.
+ * Actual functionality for debug levels 1-10 is implemented in
+ * libc_malloc_debug_leak.so, while functionality for emultor's instrumented
+ * allocations is implemented in libc_malloc_debug_qemu.so and can be run inside
+  * the emulator only.
+ */
+static void* libc_malloc_impl_handle = NULL;
+
+/* Make sure we have MALLOC_ALIGNMENT that matches the one that is
+ * used in dlmalloc. Emulator's memchecker needs this value to properly
+ * align its guarding zones.
+ */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)8U)
+#endif  /* MALLOC_ALIGNMENT */
+
+/* Initializes memory allocation framework once per process. */
+static void malloc_init_impl(void)
+{
+    const char* so_name = NULL;
+    MallocDebugInit malloc_debug_initialize = NULL;
+    unsigned int qemu_running = 0;
+    unsigned int debug_level = 0;
+    unsigned int memcheck_enabled = 0;
+    char env[PROP_VALUE_MAX];
+    char memcheck_tracing[PROP_VALUE_MAX];
+
+    /* Get custom malloc debug level. Note that emulator started with
+     * memory checking option will have priority over debug level set in
+     * libc.debug.malloc system property. */
+    if (__system_property_get("ro.kernel.qemu", env) && atoi(env)) {
+        qemu_running = 1;
+        if (__system_property_get("ro.kernel.memcheck", memcheck_tracing)) {
+            if (memcheck_tracing[0] != '0') {
+                // Emulator has started with memory tracing enabled. Enforce it.
+                debug_level = 20;
+                memcheck_enabled = 1;
+            }
+        }
+    }
+
+    /* If debug level has not been set by memcheck option in the emulator,
+     * lets grab it from libc.debug.malloc system property. */
+    if (!debug_level && __system_property_get("libc.debug.malloc", env)) {
+        debug_level = atoi(env);
+    }
+
+    /* Debug level 0 means that we should use dlxxx allocation
+     * routines (default). */
+    if (!debug_level) {
+        return;
+    }
+
+    // Lets see which .so must be loaded for the requested debug level
+    switch (debug_level) {
+        case 1:
+        case 5:
+        case 10:
+            so_name = "/system/lib/libc_malloc_debug_leak.so";
+            break;
+        case 20:
+            // Quick check: debug level 20 can only be handled in emulator.
+            if (!qemu_running) {
+                error_log("%s: Debug level %d can only be set in emulator\n",
+                          __progname, debug_level);
+                return;
+            }
+            // Make sure that memory checking has been enabled in emulator.
+            if (!memcheck_enabled) {
+                error_log("%s: Memory checking is not enabled in the emulator\n",
+                          __progname);
+                return;
+            }
+            so_name = "/system/lib/libc_malloc_debug_qemu.so";
+            break;
+        default:
+            error_log("%s: Debug level %d is unknown\n",
+                      __progname, debug_level);
+            return;
+    }
+
+    // Load .so that implements the required malloc debugging functionality.
+    libc_malloc_impl_handle = dlopen(so_name, RTLD_LAZY);
+    if (libc_malloc_impl_handle == NULL) {
+        error_log("%s: Missing module %s required for malloc debug level %d\n",
+                 __progname, so_name, debug_level);
+        return;
+    }
+
+    // Initialize malloc debugging in the loaded module.
+    malloc_debug_initialize =
+            dlsym(libc_malloc_impl_handle, "malloc_debug_initialize");
+    if (malloc_debug_initialize == NULL) {
+        error_log("%s: Initialization routine is not found in %s\n",
+                  __progname, so_name);
+        dlclose(libc_malloc_impl_handle);
+        return;
+    }
+    if (malloc_debug_initialize()) {
+        dlclose(libc_malloc_impl_handle);
+        return;
+    }
+
+    if (debug_level == 20) {
+        // For memory checker we need to do extra initialization.
+        int (*memcheck_initialize)(int, const char*) =
+                dlsym(libc_malloc_impl_handle, "memcheck_initialize");
+        if (memcheck_initialize == NULL) {
+            error_log("%s: memcheck_initialize routine is not found in %s\n",
+                      __progname, so_name);
+            dlclose(libc_malloc_impl_handle);
+            return;
+        }
+        if (memcheck_initialize(MALLOC_ALIGNMENT, memcheck_tracing)) {
+            dlclose(libc_malloc_impl_handle);
+            return;
+        }
+    }
+
+    // Initialize malloc dispatch table with appropriate routines.
+    switch (debug_level) {
+        case 1:
+            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
+                    "%s using MALLOC_DEBUG = %d (leak checker)\n",
+                    __progname, debug_level);
+            gMallocUse.malloc =
+                dlsym(libc_malloc_impl_handle, "leak_malloc");
+            gMallocUse.free =
+                dlsym(libc_malloc_impl_handle, "leak_free");
+            gMallocUse.calloc =
+                dlsym(libc_malloc_impl_handle, "leak_calloc");
+            gMallocUse.realloc =
+                dlsym(libc_malloc_impl_handle, "leak_realloc");
+            gMallocUse.memalign =
+                dlsym(libc_malloc_impl_handle, "leak_memalign");
+            break;
+        case 5:
+            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
+                    "%s using MALLOC_DEBUG = %d (fill)\n",
+                    __progname, debug_level);
+            gMallocUse.malloc =
+                dlsym(libc_malloc_impl_handle, "fill_malloc");
+            gMallocUse.free =
+                dlsym(libc_malloc_impl_handle, "fill_free");
+            gMallocUse.calloc = dlcalloc;
+            gMallocUse.realloc =
+                dlsym(libc_malloc_impl_handle, "fill_realloc");
+            gMallocUse.memalign =
+                dlsym(libc_malloc_impl_handle, "fill_memalign");
+            break;
+        case 10:
+            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
+                    "%s using MALLOC_DEBUG = %d (sentinels, fill)\n",
+                    __progname, debug_level);
+            gMallocUse.malloc =
+                dlsym(libc_malloc_impl_handle, "chk_malloc");
+            gMallocUse.free =
+                dlsym(libc_malloc_impl_handle, "chk_free");
+            gMallocUse.calloc =
+                dlsym(libc_malloc_impl_handle, "chk_calloc");
+            gMallocUse.realloc =
+                dlsym(libc_malloc_impl_handle, "chk_realloc");
+            gMallocUse.memalign =
+                dlsym(libc_malloc_impl_handle, "chk_memalign");
+            break;
+        case 20:
+            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
+                "%s[%u] using MALLOC_DEBUG = %d (instrumented for emulator)\n",
+                __progname, getpid(), debug_level);
+            gMallocUse.malloc =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_malloc");
+            gMallocUse.free =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_free");
+            gMallocUse.calloc =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_calloc");
+            gMallocUse.realloc =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_realloc");
+            gMallocUse.memalign =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_memalign");
+            break;
+        default:
+            break;
+    }
+
+    // Make sure dispatch table is initialized
+    if ((gMallocUse.malloc == NULL) ||
+        (gMallocUse.free == NULL) ||
+        (gMallocUse.calloc == NULL) ||
+        (gMallocUse.realloc == NULL) ||
+        (gMallocUse.memalign == NULL)) {
+        error_log("%s: Cannot initialize malloc dispatch table for debug level"
+                  " %d: %p, %p, %p, %p, %p\n",
+                  __progname, debug_level,
+                  gMallocUse.malloc, gMallocUse.free,
+                  gMallocUse.calloc, gMallocUse.realloc,
+                  gMallocUse.memalign);
+        dlclose(libc_malloc_impl_handle);
+        libc_malloc_impl_handle = NULL;
+    } else {
+        __libc_malloc_dispatch = &gMallocUse;
+    }
+}
+
+static pthread_once_t  malloc_init_once_ctl = PTHREAD_ONCE_INIT;
+
+#endif  // !LIBC_STATIC
+#endif  // USE_DL_PREFIX
+
+/* Initializes memory allocation framework.
+ * This routine is called from __libc_init routines implemented
+ * in libc_init_static.c and libc_init_dynamic.c files.
+ */
+void malloc_debug_init(void)
+{
+    /* We need to initialize malloc iff we implement here custom
+     * malloc routines (i.e. USE_DL_PREFIX is defined) for libc.so */
+#if defined(USE_DL_PREFIX) && !defined(LIBC_STATIC)
+    if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
+        error_log("Unable to initialize malloc_debug component.");
+    }
+#endif  // USE_DL_PREFIX && !LIBC_STATIC
+}
diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h
new file mode 100644
index 0000000..87600d6
--- /dev/null
+++ b/libc/bionic/malloc_debug_common.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/*
+ * Contains declarations of types and constants used by malloc leak
+ * detection code in both, libc and libc_malloc_debug libraries.
+ */
+#ifndef MALLOC_DEBUG_COMMON_H
+#define MALLOC_DEBUG_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HASHTABLE_SIZE      1543
+#define BACKTRACE_SIZE      32
+/* flag definitions, currently sharing storage with "size" */
+#define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
+#define SIZE_FLAG_MASK          (SIZE_FLAG_ZYGOTE_CHILD)
+
+#define MAX_SIZE_T           (~(size_t)0)
+
+// =============================================================================
+// Structures
+// =============================================================================
+
+typedef struct HashEntry HashEntry;
+struct HashEntry {
+    size_t slot;
+    HashEntry* prev;
+    HashEntry* next;
+    size_t numEntries;
+    // fields above "size" are NOT sent to the host
+    size_t size;
+    size_t allocations;
+    intptr_t backtrace[0];
+};
+
+typedef struct HashTable HashTable;
+struct HashTable {
+    size_t count;
+    HashEntry* slots[HASHTABLE_SIZE];
+};
+
+/* Entry in malloc dispatch table. */
+typedef struct MallocDebug MallocDebug;
+struct MallocDebug {
+    /* Address of the actual malloc routine. */
+    void* (*malloc)(size_t bytes);
+    /* Address of the actual free routine. */
+    void  (*free)(void* mem);
+    /* Address of the actual calloc routine. */
+    void* (*calloc)(size_t n_elements, size_t elem_size);
+    /* Address of the actual realloc routine. */
+    void* (*realloc)(void* oldMem, size_t bytes);
+    /* Address of the actual memalign routine. */
+    void* (*memalign)(size_t alignment, size_t bytes);
+};
+
+/* Malloc debugging initialization routine.
+ * This routine must be implemented in .so modules that implement malloc
+ * debugging. This routine is called once per process from malloc_init_impl
+ * routine implemented in bionic/libc/bionic/malloc_debug_common.c when malloc
+ * debugging gets initialized for the process.
+ * Return:
+ *  0 on success, -1 on failure.
+ */
+typedef int (*MallocDebugInit)(void);
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // MALLOC_DEBUG_COMMON_H
diff --git a/libc/bionic/malloc_leak.c b/libc/bionic/malloc_debug_leak.c
similarity index 63%
rename from libc/bionic/malloc_leak.c
rename to libc/bionic/malloc_debug_leak.c
index 9796382..2ff8cee 100644
--- a/libc/bionic/malloc_leak.c
+++ b/libc/bionic/malloc_debug_leak.c
@@ -38,6 +38,7 @@
 #include <stdarg.h>
 #include <fcntl.h>
 #include <unwind.h>
+#include <dlfcn.h>
 
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -47,212 +48,37 @@
 
 #include "dlmalloc.h"
 #include "logd.h"
+#include "malloc_debug_common.h"
 
-// =============================================================================
-// Utilities directly used by Dalvik
-// =============================================================================
+// This file should be included into the build only when
+// MALLOC_LEAK_CHECK, or MALLOC_QEMU_INSTRUMENT, or both
+// macros are defined.
+#ifndef MALLOC_LEAK_CHECK
+#error MALLOC_LEAK_CHECK is not defined.
+#endif  // !MALLOC_LEAK_CHECK
 
-#define HASHTABLE_SIZE      1543
-#define BACKTRACE_SIZE      32
-/* flag definitions, currently sharing storage with "size" */
-#define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
-#define SIZE_FLAG_MASK          (SIZE_FLAG_ZYGOTE_CHILD)
-
-#define MAX_SIZE_T           (~(size_t)0)
-
-/*
- * In a VM process, this is set to 1 after fork()ing out of zygote.
- */
-int gMallocLeakZygoteChild = 0;
-
-// =============================================================================
-// Structures
-// =============================================================================
-
-typedef struct HashEntry HashEntry;
-struct HashEntry {
-    size_t slot;
-    HashEntry* prev;
-    HashEntry* next;
-    size_t numEntries;
-    // fields above "size" are NOT sent to the host
-    size_t size;
-    size_t allocations;
-    intptr_t backtrace[0];
-};
-
-typedef struct HashTable HashTable;
-struct HashTable {
-    size_t count;
-    HashEntry* slots[HASHTABLE_SIZE];
-};
-
-static pthread_mutex_t gAllocationsMutex = PTHREAD_MUTEX_INITIALIZER;
-static HashTable gHashTable;
+// Global variables defined in malloc_debug_common.c
+extern int gMallocLeakZygoteChild;
+extern pthread_mutex_t gAllocationsMutex;
+extern HashTable gHashTable;
+extern const MallocDebug __libc_malloc_default_dispatch;
+extern const MallocDebug* __libc_malloc_dispatch;
 
 // =============================================================================
 // log functions
 // =============================================================================
 
 #define debug_log(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak", (format), ##__VA_ARGS__ )
+    __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak_check", (format), ##__VA_ARGS__ )
+#define error_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_ERROR, "malloc_leak_check", (format), ##__VA_ARGS__ )
+#define info_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ )
 
-// =============================================================================
-// output functions
-// =============================================================================
+static int gTrapOnError = 1;
 
-static int hash_entry_compare(const void* arg1, const void* arg2)
-{
-    HashEntry* e1 = *(HashEntry**)arg1;
-    HashEntry* e2 = *(HashEntry**)arg2;
-
-    size_t nbAlloc1 = e1->allocations;
-    size_t nbAlloc2 = e2->allocations;
-    size_t size1 = e1->size & ~SIZE_FLAG_MASK;
-    size_t size2 = e2->size & ~SIZE_FLAG_MASK;
-    size_t alloc1 = nbAlloc1 * size1;
-    size_t alloc2 = nbAlloc2 * size2;
-
-    // sort in descending order by:
-    // 1) total size
-    // 2) number of allocations
-    //
-    // This is used for sorting, not determination of equality, so we don't
-    // need to compare the bit flags.
-    int result;
-    if (alloc1 > alloc2) {
-        result = -1;
-    } else if (alloc1 < alloc2) {
-        result = 1;
-    } else {
-        if (nbAlloc1 > nbAlloc2) {
-            result = -1;
-        } else if (nbAlloc1 < nbAlloc2) {
-            result = 1;
-        } else {
-            result = 0;
-        }
-    }
-    return result;
-}
-
-/*
- * Retrieve native heap information.
- *
- * "*info" is set to a buffer we allocate
- * "*overallSize" is set to the size of the "info" buffer
- * "*infoSize" is set to the size of a single entry
- * "*totalMemory" is set to the sum of all allocations we're tracking; does
- *   not include heap overhead
- * "*backtraceSize" is set to the maximum number of entries in the back trace
- */
-void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
-        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize)
-{
-    // don't do anything if we have invalid arguments
-    if (info == NULL || overallSize == NULL || infoSize == NULL ||
-            totalMemory == NULL || backtraceSize == NULL) {
-        return;
-    }
-
-    pthread_mutex_lock(&gAllocationsMutex);
-
-    if (gHashTable.count == 0) {
-        *info = NULL;
-        *overallSize = 0;
-        *infoSize = 0;
-        *totalMemory = 0;
-        *backtraceSize = 0;
-        goto done;
-    }
-    
-    void** list = (void**)dlmalloc(sizeof(void*) * gHashTable.count);
-
-    // debug_log("*****\ngHashTable.count = %d\n", gHashTable.count);
-    // debug_log("list = %p\n", list);
-
-    // get the entries into an array to be sorted
-    int index = 0;
-    int i;
-    for (i = 0 ; i < HASHTABLE_SIZE ; i++) {
-        HashEntry* entry = gHashTable.slots[i];
-        while (entry != NULL) {
-            list[index] = entry;
-            *totalMemory = *totalMemory +
-                ((entry->size & ~SIZE_FLAG_MASK) * entry->allocations);
-            index++;
-            entry = entry->next;
-        }
-    }
-
-    // debug_log("sorted list!\n");
-    // XXX: the protocol doesn't allow variable size for the stack trace (yet)
-    *infoSize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * BACKTRACE_SIZE);
-    *overallSize = *infoSize * gHashTable.count;
-    *backtraceSize = BACKTRACE_SIZE;
-
-    // debug_log("infoSize = 0x%x overall = 0x%x\n", *infoSize, *overallSize);
-    // now get A byte array big enough for this
-    *info = (uint8_t*)dlmalloc(*overallSize);
-
-    // debug_log("info = %p\n", info);
-    if (*info == NULL) {
-        *overallSize = 0;
-        goto out_nomem_info;
-    }
-
-    // debug_log("sorting list...\n");
-    qsort((void*)list, gHashTable.count, sizeof(void*), hash_entry_compare);
-
-    uint8_t* head = *info;
-    const int count = gHashTable.count;
-    for (i = 0 ; i < count ; i++) {
-        HashEntry* entry = list[i];
-        size_t entrySize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * entry->numEntries);
-        if (entrySize < *infoSize) {
-            /* we're writing less than a full entry, clear out the rest */
-            memset(head + entrySize, 0, *infoSize - entrySize);
-        } else {
-            /* make sure the amount we're copying doesn't exceed the limit */
-            entrySize = *infoSize;
-        }
-        memcpy(head, &(entry->size), entrySize);
-        head += *infoSize;
-    }
-
-out_nomem_info:
-    dlfree(list);
-
-done:
-    // debug_log("+++++ done!\n");
-    pthread_mutex_unlock(&gAllocationsMutex);
-}
-
-void free_malloc_leak_info(uint8_t* info)
-{
-    dlfree(info);
-}
-
-struct mallinfo mallinfo()
-{
-    return dlmallinfo();
-}
-
-void* valloc(size_t bytes) {
-    /* assume page size of 4096 bytes */
-    return memalign( getpagesize(), bytes );
-}
-
-
-/*
- * Code guarded by MALLOC_LEAK_CHECK is only needed when malloc check is
- * enabled. Currently we exclude them in libc.so, and only include them in
- * libc_debug.so.
- */
-#ifdef MALLOC_LEAK_CHECK
 #define MALLOC_ALIGNMENT    8
 #define GUARD               0x48151642
-
 #define DEBUG               0
 
 // =============================================================================
@@ -407,13 +233,13 @@
     if (state->count) {
         intptr_t ip = (intptr_t)_Unwind_GetIP(context);
         if (ip) {
-            state->addrs[0] = ip; 
+            state->addrs[0] = ip;
             state->addrs++;
             state->count--;
             return _URC_NO_REASON;
         }
     }
-    /* 
+    /*
      * If we run out of space to record the address or 0 has been seen, stop
      * unwinding the stack.
      */
@@ -431,70 +257,6 @@
 }
 
 // =============================================================================
-// malloc leak function dispatcher
-// =============================================================================
-
-static void* leak_malloc(size_t bytes);
-static void  leak_free(void* mem);
-static void* leak_calloc(size_t n_elements, size_t elem_size);
-static void* leak_realloc(void* oldMem, size_t bytes);
-static void* leak_memalign(size_t alignment, size_t bytes);
-
-static void* fill_malloc(size_t bytes);
-static void  fill_free(void* mem);
-static void* fill_realloc(void* oldMem, size_t bytes);
-static void* fill_memalign(size_t alignment, size_t bytes);
-
-static void* chk_malloc(size_t bytes);
-static void  chk_free(void* mem);
-static void* chk_calloc(size_t n_elements, size_t elem_size);
-static void* chk_realloc(void* oldMem, size_t bytes);
-static void* chk_memalign(size_t alignment, size_t bytes);
-
-typedef struct {
-    void* (*malloc)(size_t bytes);
-    void  (*free)(void* mem);
-    void* (*calloc)(size_t n_elements, size_t elem_size);
-    void* (*realloc)(void* oldMem, size_t bytes);
-    void* (*memalign)(size_t alignment, size_t bytes);
-} MallocDebug;
-
-static const MallocDebug gMallocEngineTable[] __attribute__((aligned(32))) =
-{
-    { dlmalloc,     dlfree,     dlcalloc,       dlrealloc,     dlmemalign },
-    { leak_malloc,  leak_free,  leak_calloc,    leak_realloc,  leak_memalign },
-    { fill_malloc,  fill_free,  dlcalloc,       fill_realloc,  fill_memalign },
-    { chk_malloc,   chk_free,   chk_calloc,     chk_realloc,   chk_memalign }
-};
-
-enum {
-    INDEX_NORMAL = 0,
-    INDEX_LEAK_CHECK,
-    INDEX_MALLOC_FILL,
-    INDEX_MALLOC_CHECK,
-};
-
-static MallocDebug const * gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
-static int gMallocDebugLevel;
-static int gTrapOnError = 1;
-
-void* malloc(size_t bytes) {
-    return gMallocDispatch->malloc(bytes);
-}
-void free(void* mem) {
-    gMallocDispatch->free(mem);
-}
-void* calloc(size_t n_elements, size_t elem_size) {
-    return gMallocDispatch->calloc(n_elements, elem_size);
-}
-void* realloc(void* oldMem, size_t bytes) {
-    return gMallocDispatch->realloc(oldMem, bytes);
-}
-void* memalign(size_t alignment, size_t bytes) {
-    return gMallocDispatch->memalign(alignment, bytes);
-}
-
-// =============================================================================
 // malloc check functions
 // =============================================================================
 
@@ -532,7 +294,9 @@
     va_list  args;
 
     pthread_mutex_lock(&gAllocationsMutex);
-        gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
+    {
+        const MallocDebug* current_dispatch = __libc_malloc_dispatch;
+        __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
         va_start(args, format);
         __libc_android_log_vprint(ANDROID_LOG_ERROR, "libc",
                                 format, args);
@@ -541,7 +305,8 @@
         if (gTrapOnError) {
             __builtin_trap();
         }
-        gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_CHECK];
+        __libc_malloc_dispatch = current_dispatch;
+    }
     pthread_mutex_unlock(&gAllocationsMutex);
 }
 
@@ -574,7 +339,7 @@
     buf = (char*)mem - CHK_SENTINEL_HEAD_SIZE;
     for (i=0 ; i<CHK_SENTINEL_HEAD_SIZE ; i++) {
         if (buf[i] != CHK_SENTINEL_VALUE) {
-            assert_log_message( 
+            assert_log_message(
                 "*** %s CHECK: buffer %p "
                 "corrupted %d bytes before allocation",
                 func, mem, CHK_SENTINEL_HEAD_SIZE-i);
@@ -590,7 +355,7 @@
     buf = (char*)mem + bytes;
     for (i=CHK_SENTINEL_TAIL_SIZE-1 ; i>=0 ; i--) {
         if (buf[i] != CHK_SENTINEL_VALUE) {
-            assert_log_message( 
+            assert_log_message(
                 "*** %s CHECK: buffer %p, size=%lu, "
                 "corrupted %d bytes after allocation",
                 func, buffer, bytes, i+1);
@@ -744,11 +509,11 @@
 
             intptr_t backtrace[BACKTRACE_SIZE];
             size_t numEntries = get_backtrace(backtrace, BACKTRACE_SIZE);
-    
+
             AllocationEntry* header = (AllocationEntry*)base;
             header->entry = record_backtrace(backtrace, numEntries, bytes);
             header->guard = GUARD;
-    
+
             // now increment base to point to after our header.
             // this should just work since our header is 8 bytes.
             base = (AllocationEntry*)base + 1;
@@ -766,7 +531,7 @@
 
         // check the guard to make sure it is valid
         AllocationEntry* header = (AllocationEntry*)mem - 1;
-        
+
         if (header->guard != GUARD) {
             // could be a memaligned block
             if (((void**)mem)[-1] == MEMALIGN_GUARD) {
@@ -774,7 +539,7 @@
                 header = (AllocationEntry*)mem - 1;
             }
         }
-        
+
         if (header->guard == GUARD || is_valid_entry(header->entry)) {
             // decrement the allocations
             HashEntry* entry = header->entry;
@@ -843,7 +608,7 @@
     // need to make sure it's a power of two
     if (alignment & (alignment-1))
         alignment = 1L << (31 - __builtin_clz(alignment));
-    
+
     // here, aligment is at least MALLOC_ALIGNMENT<<1 bytes
     // we will align by at least MALLOC_ALIGNMENT bytes
     // and at most alignment-MALLOC_ALIGNMENT bytes
@@ -856,7 +621,7 @@
 
         // align the pointer
         ptr += ((-ptr) % alignment);
-        
+
         // there is always enough space for the base pointer and the guard
         ((void**)ptr)[-1] = MEMALIGN_GUARD;
         ((void**)ptr)[-2] = base;
@@ -865,60 +630,12 @@
     }
     return base;
 }
-#endif /* MALLOC_LEAK_CHECK */
 
-// called from libc_init()
-extern char*  __progname;
-
-void malloc_debug_init()
+/* Initializes malloc debugging framework.
+ * See comments on MallocDebugInit in malloc_debug_common.h
+ */
+int malloc_debug_initialize(void)
 {
-    unsigned int level = 0;
-#ifdef MALLOC_LEAK_CHECK
-    // if MALLOC_LEAK_CHECK is enabled, use level=1 by default
-    level = 1;
-#endif
-    char env[PROP_VALUE_MAX];
-    int len = __system_property_get("libc.debug.malloc", env);
-
-    if (len) {
-        level = atoi(env);
-#ifndef MALLOC_LEAK_CHECK
-        /* Alert the user that libc_debug.so needs to be installed as libc.so
-         * when performing malloc checks.
-         */
-        if (level != 0) {
-            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
-                 "Malloc checks need libc_debug.so pushed to the device!\n");
-
-        }
-#endif
-    }
-
-#ifdef MALLOC_LEAK_CHECK
-    gMallocDebugLevel = level;
-    switch (level) {
-    default:
-    case 0:
-        gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
-        break;
-    case 1:
-        __libc_android_log_print(ANDROID_LOG_INFO, "libc",
-                "%s using MALLOC_DEBUG = %d (leak checker)\n",
-                __progname, level);
-        gMallocDispatch = &gMallocEngineTable[INDEX_LEAK_CHECK];
-        break;
-    case 5:
-        __libc_android_log_print(ANDROID_LOG_INFO, "libc",
-                "%s using MALLOC_DEBUG = %d (fill)\n", 
-                __progname, level);
-        gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_FILL];
-        break;
-    case 10:
-        __libc_android_log_print(ANDROID_LOG_INFO, "libc",
-                "%s using MALLOC_DEBUG = %d (sentinels, fill)\n", 
-                __progname, level);
-        gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_CHECK];
-        break;
-    }
-#endif
+    // We don't really have anything that requires initialization here.
+    return 0;
 }
diff --git a/libc/bionic/malloc_debug_qemu.c b/libc/bionic/malloc_debug_qemu.c
new file mode 100644
index 0000000..4b694e9
--- /dev/null
+++ b/libc/bionic/malloc_debug_qemu.c
@@ -0,0 +1,1014 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/*
+ * Contains implementation of memory allocation routines instrumented for
+ * usage in the emulator to detect memory allocation violations, such as
+ * memory leaks, buffer overruns, etc.
+ * Code, implemented here is intended to run in the emulated environment only,
+ * and serves simply as hooks into memory allocation routines. Main job of this
+ * code is to notify the emulator about memory being allocated/deallocated,
+ * providing information about each allocation. The idea is that emulator will
+ * keep list of currently allocated blocks, and, knowing boundaries of each
+ * block it will be able to verify that ld/st access to these blocks don't step
+ * over boundaries set for the user. To enforce that, each memory block
+ * allocated by this code is guarded with "prefix" and "suffix" areas, so
+ * every time emulator detects access to any of these guarding areas, it can be
+ * considered as access violation.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include "dlmalloc.h"
+#include "logd.h"
+#include "malloc_debug_common.h"
+
+/* This file should be included into the build only when
+ * MALLOC_QEMU_INSTRUMENT macro is defined. */
+#ifndef MALLOC_QEMU_INSTRUMENT
+#error MALLOC_QEMU_INSTRUMENT is not defined.
+#endif  // !MALLOC_QEMU_INSTRUMENT
+
+/* Controls access violation test performed to make sure that we catch AVs
+ * all the time they occur. See test_access_violation for more info. This macro
+ * is used for internal testing purposes and should always be set to zero for
+ * the production builds. */
+#define TEST_ACCESS_VIOLATIONS  0
+
+// =============================================================================
+// Communication structures
+// =============================================================================
+
+/* Describes memory block allocated from the heap. This structure is passed
+ * along with TRACE_DEV_REG_MALLOC event. This descriptor is used to inform
+ * the emulator about new memory block being allocated from the heap. The entire
+ * structure is initialized by the guest system before event is fired up. It is
+ * important to remember that same structure (an exact copy, except for
+ * replacing pointers with target_ulong) is also declared in the emulator's
+ * sources (file memcheck/memcheck_common.h). So, every time a change is made to
+ * any of these two declaration, another one must be also updated accordingly.
+ */
+typedef struct MallocDesc {
+    /* Pointer to the memory block actually allocated from the heap. Note that
+     * this is not the pointer that is returned to the malloc's caller. Pointer
+     * returned to the caller is calculated by adding value stored in this field
+     * to the value stored in prefix_size field of this structure.
+     */
+    void*       ptr;
+
+    /* Number of bytes requested by the malloc's caller. */
+    uint32_t    requested_bytes;
+
+    /* Byte size of the prefix data. Actual pointer returned to the malloc's
+     * caller is calculated by adding value stored in this field to the value
+     * stored in in the ptr field of this structure.
+     */
+    uint32_t    prefix_size;
+
+    /* Byte size of the suffix data. */
+    uint32_t    suffix_size;
+
+    /* Id of the process that initialized libc instance, in which allocation
+     * has occurred. This field is used by the emulator to report errors in
+     * the course of TRACE_DEV_REG_MALLOC event handling. In case of an error,
+     * emulator sets this field to zero (invalid value for a process ID).
+     */
+    uint32_t    libc_pid;
+
+    /* Id of the process in context of which allocation has occurred.
+     * Value in this field may differ from libc_pid value, if process that
+     * is doing allocation has been forked from the process that initialized
+     * libc instance.
+     */
+    uint32_t    allocator_pid;
+
+    /* Number of access violations detected on this allocation. */
+    uint32_t    av_count;
+} MallocDesc;
+
+/* Describes memory block info queried from emulator. This structure is passed
+ * along with TRACE_DEV_REG_QUERY_MALLOC event. When handling free and realloc
+ * calls, it is required that we have information about memory blocks that were
+ * actually allocated in previous calls to malloc, calloc, memalign, or realloc.
+ * Since we don't keep this information directly in the allocated block, but
+ * rather we keep it in the emulator, we need to query emulator for that
+ * information with TRACE_DEV_REG_QUERY_MALLOC query. The entire structure is
+ * initialized by the guest system before event is fired up. It is important to
+ * remember that same structure (an exact copy, except for replacing pointers
+ * with target_ulong) is also declared in the emulator's sources (file
+ * memcheck/memecheck_common.h). So, every time a change is made to any of these
+ * two declaration, another one must be also updated accordingly.
+ */
+typedef struct MallocDescQuery {
+    /* Pointer, for which information is queried. Note that this pointer doesn't
+     * have to be exact pointer returned to malloc's caller, but can point
+     * anywhere inside an allocated block, including guarding areas. Emulator
+     * will respond with information about allocated block that contains this
+     * pointer.
+     */
+    void*       ptr;
+
+    /* Id of the process that initialized libc instance, in which this query
+     * is called. This field is used by the emulator to report errors in
+     * the course of TRACE_DEV_REG_QUERY_MALLOC event handling. In case of an
+     * error, emulator sets this field to zero (invalid value for a process ID).
+     */
+    uint32_t    libc_pid;
+
+    /* Process ID in context of which query is made. */
+    uint32_t    query_pid;
+
+    /* Code of the allocation routine, in context of which query has been made:
+     *  1 - free
+     *  2 - realloc
+     */
+    uint32_t    routine;
+
+    /* Address of memory allocation descriptor for the queried pointer.
+     * Descriptor, addressed by this field is initialized by the emulator in
+     * response to the query.
+     */
+    MallocDesc*  desc;
+} MallocDescQuery;
+
+/* Describes memory block that is being freed back to the heap. This structure
+ * is passed along with TRACE_DEV_REG_FREE_PTR event. The entire structure is
+ * initialized by the guest system before event is fired up. It is important to
+ * remember that same structure (an exact copy, except for replacing pointers
+ * with target_ulong) is also declared in the emulator's sources (file
+ * memcheck/memecheck_common.h). So, every time a change is made to any of these
+ * two declaration, another one must be also updated accordingly.
+ */
+typedef struct MallocFree {
+    /* Pointer to be freed. */
+    void*       ptr;
+
+    /* Id of the process that initialized libc instance, in which this free
+     * is called. This field is used by the emulator to report errors in
+     * the course of TRACE_DEV_REG_FREE_PTR event handling. In case of an
+     * error, emulator sets this field to zero (invalid value for a process ID).
+     */
+    uint32_t    libc_pid;
+
+    /* Process ID in context of which memory is being freed. */
+    uint32_t    free_pid;
+} MallocFree;
+
+// =============================================================================
+// Communication events
+// =============================================================================
+
+/* Notifies the emulator that libc has been initialized for a process.
+ * Event's value parameter is PID for the process in context of which libc has
+ * been initialized.
+ */
+#define TRACE_DEV_REG_LIBC_INIT             1536
+
+/* Notifies the emulator about new memory block been allocated.
+ * Event's value parameter points to MallocDesc instance that contains
+ * allocated block information. Note that 'libc_pid' field of the descriptor
+ * is used by emulator to report failure in handling this event. In case
+ * of a failure emulator will zero that field before completing this event.
+ */
+#define TRACE_DEV_REG_MALLOC                1537
+
+/* Notifies the emulator about memory block being freed.
+ * Event's value parameter points to MallocFree descriptor that contains
+ * information about block that's being freed. Note that 'libc_pid' field
+ * of the descriptor is used by emulator to report failure in handling this
+ * event. In case of a failure emulator will zero that field before completing
+ * this event.
+ */
+#define TRACE_DEV_REG_FREE_PTR              1538
+
+/* Queries the emulator about allocated memory block information.
+ * Event's value parameter points to MallocDescQuery descriptor that contains
+ * query parameters. Note that 'libc_pid' field of the descriptor is used by
+ * emulator to report failure in handling this event. In case of a failure
+ * emulator will zero that field before completing this event.
+ */
+#define TRACE_DEV_REG_QUERY_MALLOC          1539
+
+/* Queries the emulator to print a string to its stdout.
+ * Event's value parameter points to a zero-terminated string to be printed.
+ */
+#define TRACE_DEV_REG_PRINT_USER_STR        1540
+
+static void notify_qemu_string(const char* str);
+static void qemu_log(int prio, const char* fmt, ...);
+static void dump_malloc_descriptor(char* str,
+                                   size_t str_buf_size,
+                                   const MallocDesc* desc);
+
+// =============================================================================
+// Macros
+// =============================================================================
+
+/* Defines default size of allocation prefix.
+ * Note that we make prefix area quite large in order to increase chances of
+ * catching buffer overflow. */
+#define DEFAULT_PREFIX_SIZE     (malloc_alignment * 4)
+
+/* Defines default size of allocation suffix.
+ * Note that we make suffix area quite large in order to increase chances of
+ * catching buffer overflow. */
+#define DEFAULT_SUFFIX_SIZE     (malloc_alignment * 4)
+
+/* Debug tracing has been enabled by the emulator. */
+#define DEBUG_TRACING_ENABLED   0x00000001
+/* Error tracing has been enabled by the emulator. */
+#define ERROR_TRACING_ENABLED   0x00000002
+/* Info tracing has been enabled by the emulator. */
+#define INFO_TRACING_ENABLED    0x00000004
+/* All tracing flags combined. */
+#define ALL_TRACING_ENABLED (DEBUG_TRACING_ENABLED |    \
+                             ERROR_TRACING_ENABLED |    \
+                             INFO_TRACING_ENABLED)
+
+/* Prints a string to the emulator's stdout.
+ * In early stages of system loading, logging mesages via
+ * __libc_android_log_print API is not available, because ADB API has not been
+ * hooked up yet. So, in order to see such messages we need to print them to
+ * the emulator's stdout.
+ * Parameters passed to this macro are the same as parameters for printf
+ * routine.
+ */
+#define TR(...)                                         \
+    do {                                                \
+        char tr_str[4096];                              \
+        snprintf(tr_str, sizeof(tr_str), __VA_ARGS__ ); \
+        tr_str[sizeof(tr_str) - 1] = '\0';              \
+        notify_qemu_string(&tr_str[0]);                 \
+    } while (0)
+
+// =============================================================================
+// Logging macros. Note that we simultaneously log messages to ADB and emulator.
+// =============================================================================
+
+/*
+ * Helper macros for checking if particular trace level is enabled.
+ */
+#define debug_LOG_ENABLED       ((tracing_flags & DEBUG_TRACING_ENABLED) != 0)
+#define error_LOG_ENABLED       ((tracing_flags & ERROR_TRACING_ENABLED) != 0)
+#define info_LOG_ENABLED        ((tracing_flags & INFO_TRACING_ENABLED)  != 0)
+#define tracing_enabled(type)   (type##_LOG_ENABLED)
+
+/*
+ * Logging helper macros.
+ */
+#define debug_log(format, ...)                                              \
+    do {                                                                    \
+        __libc_android_log_print(ANDROID_LOG_DEBUG, "memcheck",             \
+                                 (format), ##__VA_ARGS__ );                 \
+        if (tracing_flags & DEBUG_TRACING_ENABLED) {                        \
+            qemu_log(ANDROID_LOG_DEBUG, (format), ##__VA_ARGS__ );          \
+        }                                                                   \
+    } while (0)
+
+#define error_log(format, ...)                                              \
+    do {                                                                    \
+        __libc_android_log_print(ANDROID_LOG_ERROR, "memcheck",             \
+                                 (format), ##__VA_ARGS__ );                 \
+        if (tracing_flags & ERROR_TRACING_ENABLED) {                        \
+            qemu_log(ANDROID_LOG_ERROR, (format), ##__VA_ARGS__ );          \
+        }                                                                   \
+    } while (0)
+
+#define info_log(format, ...)                                               \
+    do {                                                                    \
+        __libc_android_log_print(ANDROID_LOG_INFO, "memcheck",              \
+                                 (format), ##__VA_ARGS__ );                 \
+        if (tracing_flags & INFO_TRACING_ENABLED) {                         \
+            qemu_log(ANDROID_LOG_INFO, (format), ##__VA_ARGS__ );           \
+        }                                                                   \
+    } while (0)
+
+/* Logs message dumping MallocDesc instance at the end of the message.
+ * Param:
+ *  type - Message type: debug, error, or info
+ *  desc - MallocDesc instance to dump.
+ *  frmt + rest - Formats message preceding dumped descriptor.
+*/
+#define log_mdesc(type, desc, frmt, ...)                                    \
+    do {                                                                    \
+        if (tracing_enabled(type)) {                                        \
+            char log_str[4096];                                             \
+            size_t str_len;                                                 \
+            snprintf(log_str, sizeof(log_str), frmt, ##__VA_ARGS__);        \
+            log_str[sizeof(log_str) - 1] = '\0';                            \
+            str_len = strlen(log_str);                                      \
+            dump_malloc_descriptor(log_str + str_len,                       \
+                                   sizeof(log_str) - str_len,               \
+                                   (desc));                                 \
+            type##_log(log_str);                                            \
+        }                                                                   \
+    } while (0)
+
+// =============================================================================
+// Static data
+// =============================================================================
+
+/* Emulator's magic page address.
+ * This page (mapped on /dev/qemu_trace device) is used to fire up events
+ * in the emulator. */
+static volatile void* qtrace = NULL;
+
+/* Cached PID of the process in context of which this libc instance
+ * has been initialized. */
+static uint32_t malloc_pid = 0;
+
+/* Memory allocation alignment that is used in dlmalloc.
+ * This variable is updated by memcheck_initialize routine. */
+static uint32_t malloc_alignment = 8;
+
+/* Tracing flags. These flags control which types of logging messages are
+ * enabled by the emulator. See XXX_TRACING_ENABLED for the values of flags
+ * stored in this variable. This variable is updated by memcheck_initialize
+ * routine. */
+static uint32_t tracing_flags = 0;
+
+// =============================================================================
+// Static routines
+// =============================================================================
+
+/* Gets pointer, returned to malloc caller for the given allocation decriptor.
+ * Param:
+ *  desc - Allocation descriptor.
+ * Return:
+ *  Pointer to the allocated memory returned to the malloc caller.
+ */
+static inline void*
+mallocdesc_user_ptr(const MallocDesc* desc)
+{
+    return (char*)desc->ptr + desc->prefix_size;
+}
+
+/* Gets size of memory block actually allocated from the heap for the given
+ * allocation decriptor.
+ * Param:
+ *  desc - Allocation descriptor.
+ * Return:
+ *  Size of memory block actually allocated from the heap.
+ */
+static inline uint32_t
+mallocdesc_alloc_size(const MallocDesc* desc)
+{
+    return desc->prefix_size + desc->requested_bytes + desc->suffix_size;
+}
+
+/* Gets pointer to the end of the allocated block for the given descriptor.
+ * Param:
+ *  desc - Descriptor for the memory block, allocated in malloc handler.
+ * Return:
+ *  Pointer to the end of (one byte past) the allocated block.
+ */
+static inline void*
+mallocdesc_alloc_end(const MallocDesc* desc)
+{
+    return (char*)desc->ptr + mallocdesc_alloc_size(desc);
+}
+
+/* Fires up an event in the emulator.
+ * Param:
+ *  code - Event code (one of the TRACE_DEV_XXX).
+ *  val  - Event's value parameter.
+ */
+static inline void
+notify_qemu(uint32_t code, uint32_t val)
+{
+    if (NULL != qtrace) {
+        *(volatile uint32_t*)((uint32_t)qtrace + ((code - 1024) << 2)) = val;
+    }
+}
+
+/* Prints a zero-terminated string to the emulator's stdout (fires up
+ * TRACE_DEV_REG_PRINT_USER_STR event in the emulator).
+ * Param:
+ *  str - Zero-terminated string to print.
+ */
+static void
+notify_qemu_string(const char* str)
+{
+    if (str != NULL) {
+        notify_qemu(TRACE_DEV_REG_PRINT_USER_STR, (uint32_t)str);
+    }
+}
+
+/* Fires up TRACE_DEV_REG_LIBC_INIT event in the emulator.
+ * Param:
+ *  pid - ID of the process that initialized libc.
+ */
+static void
+notify_qemu_libc_initialized(uint32_t pid)
+{
+    notify_qemu(TRACE_DEV_REG_LIBC_INIT, pid);
+}
+
+/* Fires up TRACE_DEV_REG_MALLOC event in the emulator.
+ * Param:
+ *  desc - Pointer to MallocDesc instance containing allocated block
+ *      information.
+ * Return:
+ *  Zero on success, or -1 on failure. Note that on failure libc_pid field of
+ *  the desc parameter passed to this routine has been zeroed out by the
+ *  emulator.
+ */
+static inline int
+notify_qemu_malloc(volatile MallocDesc* desc)
+{
+    desc->libc_pid = malloc_pid;
+    desc->allocator_pid = getpid();
+    desc->av_count = 0;
+    notify_qemu(TRACE_DEV_REG_MALLOC, (uint32_t)desc);
+
+    /* Emulator reports failure by zeroing libc_pid field of the
+     * descriptor. */
+    return desc->libc_pid != 0 ? 0 : -1;
+}
+
+/* Fires up TRACE_DEV_REG_FREE_PTR event in the emulator.
+ * Param:
+ *  ptr - Pointer to the memory block that's being freed.
+ * Return:
+ *  Zero on success, or -1 on failure.
+ */
+static inline int
+notify_qemu_free(void* ptr_to_free)
+{
+    volatile MallocFree free_desc;
+
+    free_desc.ptr = ptr_to_free;
+    free_desc.libc_pid = malloc_pid;
+    free_desc.free_pid = getpid();
+    notify_qemu(TRACE_DEV_REG_FREE_PTR, (uint32_t)&free_desc);
+
+    /* Emulator reports failure by zeroing libc_pid field of the
+     * descriptor. */
+    return free_desc.libc_pid != 0 ? 0 : -1;
+}
+
+/* Fires up TRACE_DEV_REG_QUERY_MALLOC event in the emulator.
+ * Param:
+ *  ptr - Pointer to request allocation information for.
+ *  desc - Pointer to MallocDesc instance that will receive allocation
+ *      information.
+ *  routine - Code of the allocation routine, in context of which query is made:
+ *      1 - free
+ *      2 - realloc
+ * Return:
+ *  Zero on success, or -1 on failure.
+ */
+static inline int
+query_qemu_malloc_info(void* ptr, MallocDesc* desc, uint32_t routine)
+{
+    volatile MallocDescQuery query;
+
+    query.ptr = ptr;
+    query.libc_pid = malloc_pid;
+    query.query_pid = getpid();
+    query.routine = routine;
+    query.desc = desc;
+    notify_qemu(TRACE_DEV_REG_QUERY_MALLOC, (uint32_t)&query);
+
+    /* Emulator reports failure by zeroing libc_pid field of the
+     * descriptor. */
+    return query.libc_pid != 0 ? 0 : -1;
+}
+
+/* Logs a message to emulator's stdout.
+ * Param:
+ *  prio - Message priority (debug, info, or error)
+ *  fmt + rest - Message format and parameters.
+ */
+static void
+qemu_log(int prio, const char* fmt, ...)
+{
+    va_list ap;
+    char buf[4096];
+    const char* prefix;
+
+    /* Choose message prefix depending on the priority value. */
+    switch (prio) {
+        case ANDROID_LOG_ERROR:
+            if (!tracing_enabled(error)) {
+                return;
+            }
+            prefix = "E";
+            break;
+        case ANDROID_LOG_INFO:
+            if (!tracing_enabled(info)) {
+                return;
+            }
+            prefix = "I";
+            break;
+        case ANDROID_LOG_DEBUG:
+        default:
+            if (!tracing_enabled(debug)) {
+                return;
+            }
+            prefix = "D";
+            break;
+    }
+
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+    buf[sizeof(buf) - 1] = '\0';
+
+    TR("%s/memcheck: %s\n", prefix, buf);
+}
+
+/* Dumps content of memory allocation descriptor to a string.
+ * Param:
+ *  str - String to dump descriptor to.
+ *  str_buf_size - Size of string's buffer.
+ *  desc - Descriptor to dump.
+ */
+static void
+dump_malloc_descriptor(char* str, size_t str_buf_size, const MallocDesc* desc)
+{
+    if (str_buf_size) {
+        snprintf(str, str_buf_size,
+            "MDesc: %p: %X <-> %X [%u + %u + %u] by pid=%03u in libc_pid=%03u",
+            mallocdesc_user_ptr(desc), (uint32_t)desc->ptr,
+            (uint32_t)mallocdesc_alloc_end(desc), desc->prefix_size,
+            desc->requested_bytes, desc->suffix_size, desc->allocator_pid,
+            desc->libc_pid);
+        str[str_buf_size - 1] = '\0';
+    }
+}
+
+#if TEST_ACCESS_VIOLATIONS
+/* Causes an access violation on allocation descriptor, and verifies that
+ * violation has been detected by memory checker in the emulator.
+ */
+static void
+test_access_violation(const MallocDesc* desc)
+{
+    MallocDesc desc_chk;
+    char ch;
+    volatile char* prefix = (volatile char*)desc->ptr;
+    volatile char* suffix = (volatile char*)mallocdesc_user_ptr(desc) +
+                                            desc->requested_bytes;
+    /* We're causing AV by reading from the prefix and suffix areas of the
+     * allocated block. This should produce two access violations, so when we
+     * get allocation descriptor from QEMU, av_counter should be bigger than
+     * av_counter of the original descriptor by 2. */
+    ch = *prefix;
+    ch = *suffix;
+    if (!query_qemu_malloc_info(mallocdesc_user_ptr(desc), &desc_chk, 2) &&
+        desc_chk.av_count != (desc->av_count + 2)) {
+        log_mdesc(error, &desc_chk,
+                  "<libc_pid=%03u, pid=%03u>: malloc: Access violation test failed:\n"
+                  "Expected violations count %u is not equal to the actually reported %u",
+                  malloc_pid, getpid(), desc->av_count + 2,
+                  desc_chk.av_count);
+    }
+}
+#endif  // TEST_ACCESS_VIOLATIONS
+
+// =============================================================================
+// API routines
+// =============================================================================
+
+void* qemu_instrumented_malloc(size_t bytes);
+void  qemu_instrumented_free(void* mem);
+void* qemu_instrumented_calloc(size_t n_elements, size_t elem_size);
+void* qemu_instrumented_realloc(void* mem, size_t bytes);
+void* qemu_instrumented_memalign(size_t alignment, size_t bytes);
+
+/* Initializes malloc debugging instrumentation for the emulator.
+ * This routine is called from malloc_init_impl routine implemented in
+ * bionic/libc/bionic/malloc_debug_common.c when malloc debugging gets
+ * initialized for a process. The way malloc debugging implementation is
+ * done, it is guaranteed that this routine will be called just once per
+ * process.
+ * Return:
+ *  0 on success, or -1 on failure.
+*/
+int
+malloc_debug_initialize(void)
+{
+    /* We will be using emulator's magic page to report memory allocation
+     * activities. In essence, what magic page does, it translates writes to
+     * the memory mapped spaces into writes to an I/O port that emulator
+     * "listens to" on the other end. Note that until we open and map that
+     * device, logging to emulator's stdout will not be available. */
+    int fd = open("/dev/qemu_trace", O_RDWR);
+    if (fd < 0) {
+        error_log("Unable to open /dev/qemu_trace");
+        return -1;
+    } else {
+        qtrace = mmap(0, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        close(fd);
+
+        if (qtrace == MAP_FAILED) {
+            qtrace = NULL;
+            error_log("Unable to mmap /dev/qemu_trace");
+            return -1;
+        }
+    }
+
+    /* Cache pid of the process this library has been initialized for. */
+    malloc_pid = getpid();
+
+    return 0;
+}
+
+/* Completes malloc debugging instrumentation for the emulator.
+ * Note that this routine is called after successful return from
+ * malloc_debug_initialize, which means that connection to the emulator via
+ * "magic page" has been established.
+ * Param:
+ *  alignment - Alignment requirement set for memiry allocations.
+ *  memcheck_param - Emulator's -memcheck option parameters. This string
+ *      contains abbreviation for guest events that are enabled for tracing.
+ * Return:
+ *  0 on success, or -1 on failure.
+*/
+int
+memcheck_initialize(int alignment, const char* memcheck_param)
+{
+    malloc_alignment = alignment;
+
+    /* Parse -memcheck parameter for the guest tracing flags. */
+    while (*memcheck_param != '\0') {
+        switch (*memcheck_param) {
+            case 'a':
+                // Enable all messages from the guest.
+                tracing_flags |= ALL_TRACING_ENABLED;
+                break;
+            case 'd':
+                // Enable debug messages from the guest.
+                tracing_flags |= DEBUG_TRACING_ENABLED;
+                break;
+            case 'e':
+                // Enable error messages from the guest.
+                tracing_flags |= ERROR_TRACING_ENABLED;
+                break;
+            case 'i':
+                // Enable info messages from the guest.
+                tracing_flags |= INFO_TRACING_ENABLED;
+                break;
+            default:
+                break;
+        }
+        if (tracing_flags == ALL_TRACING_ENABLED) {
+            break;
+        }
+        memcheck_param++;
+    }
+
+    notify_qemu_libc_initialized(malloc_pid);
+
+    debug_log("Instrumented for pid=%03u: malloc=%p, free=%p, calloc=%p, realloc=%p, memalign=%p",
+              malloc_pid, qemu_instrumented_malloc, qemu_instrumented_free,
+              qemu_instrumented_calloc, qemu_instrumented_realloc,
+              qemu_instrumented_memalign);
+
+    return 0;
+}
+
+/* This routine serves as entry point for 'malloc'.
+ * Primary responsibility of this routine is to allocate requested number of
+ * bytes (plus prefix, and suffix guards), and report allocation to the
+ * emulator.
+ */
+void*
+qemu_instrumented_malloc(size_t bytes)
+{
+    MallocDesc desc;
+
+    /* Initialize block descriptor and allocate memory. Note that dlmalloc
+     * returns a valid pointer on zero allocation. Lets mimic this behavior. */
+    desc.prefix_size = DEFAULT_PREFIX_SIZE;
+    desc.requested_bytes = bytes;
+    desc.suffix_size = DEFAULT_SUFFIX_SIZE;
+    desc.ptr = dlmalloc(mallocdesc_alloc_size(&desc));
+    if (desc.ptr == NULL) {
+        error_log("<libc_pid=%03u, pid=%03u> malloc(%u): dlmalloc(%u) failed.",
+                  malloc_pid, getpid(), bytes, mallocdesc_alloc_size(&desc));
+        return NULL;
+    }
+
+    // Fire up event in the emulator.
+    if (notify_qemu_malloc(&desc)) {
+        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: malloc: notify_malloc failed for ",
+                  malloc_pid, getpid());
+        dlfree(desc.ptr);
+        return NULL;
+    } else {
+#if TEST_ACCESS_VIOLATIONS
+        test_access_violation(&desc);
+#endif  // TEST_ACCESS_VIOLATIONS
+        log_mdesc(info, &desc, "+++ <libc_pid=%03u, pid=%03u> malloc(%u) -> ",
+                  malloc_pid, getpid(), bytes);
+        return mallocdesc_user_ptr(&desc);
+    }
+}
+
+/* This routine serves as entry point for 'malloc'.
+ * Primary responsibility of this routine is to free requested memory, and
+ * report free block to the emulator.
+ */
+void
+qemu_instrumented_free(void* mem)
+{
+    MallocDesc desc;
+
+    if (mem == NULL) {
+        // Just let go NULL free
+        dlfree(mem);
+        return;
+    }
+
+    // Query emulator for the freeing block information.
+    if (query_qemu_malloc_info(mem, &desc, 1)) {
+        error_log("<libc_pid=%03u, pid=%03u>: free(%p) query_info failed.",
+                  malloc_pid, getpid(), mem);
+        return;
+    }
+
+#if TEST_ACCESS_VIOLATIONS
+    test_access_violation(&desc);
+#endif  // TEST_ACCESS_VIOLATIONS
+
+    /* Make sure that pointer that's being freed matches what we expect
+     * for this memory block. Note that this violation should be already
+     * caught in the emulator. */
+    if (mem != mallocdesc_user_ptr(&desc)) {
+        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: free(%p) is invalid for ",
+                  malloc_pid, getpid(), mem);
+        return;
+    }
+
+    // Fire up event in the emulator and free block that was actually allocated.
+    if (notify_qemu_free(mem)) {
+        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: free(%p) notify_free failed for ",
+                  malloc_pid, getpid(), mem);
+    } else {
+        log_mdesc(info, &desc, "--- <libc_pid=%03u, pid=%03u> free(%p) -> ",
+                  malloc_pid, getpid(), mem);
+        dlfree(desc.ptr);
+    }
+}
+
+/* This routine serves as entry point for 'calloc'.
+ * This routine behaves similarly to qemu_instrumented_malloc.
+ */
+void*
+qemu_instrumented_calloc(size_t n_elements, size_t elem_size)
+{
+    MallocDesc desc;
+    void* ret;
+    size_t total_size;
+    size_t total_elements;
+
+    if (n_elements == 0 || elem_size == 0) {
+        // Just let go zero bytes allocation.
+        info_log("::: <libc_pid=%03u, pid=%03u>: Zero calloc redir to malloc",
+                 malloc_pid, getpid());
+        return qemu_instrumented_malloc(0);
+    }
+
+    /* Fail on overflow - just to be safe even though this code runs only
+     * within the debugging C library, not the production one */
+    if (n_elements && MAX_SIZE_T / n_elements < elem_size) {
+        return NULL;
+    }
+
+    /* Calculating prefix size. The trick here is to make sure that
+     * first element (returned to the caller) is properly aligned. */
+    if (DEFAULT_PREFIX_SIZE >= elem_size) {
+        /* If default alignment is bigger than element size, we will
+         * set our prefix size to the default alignment size. */
+        desc.prefix_size = DEFAULT_PREFIX_SIZE;
+        /* For the suffix we will use whatever bytes remain from the prefix
+         * allocation size, aligned to the size of an element, plus the usual
+         * default suffix size. */
+        desc.suffix_size = (DEFAULT_PREFIX_SIZE % elem_size) +
+                           DEFAULT_SUFFIX_SIZE;
+    } else {
+        /* Make sure that prefix, and suffix sizes is at least elem_size,
+         * and first element returned to the caller is properly aligned. */
+        desc.prefix_size = elem_size + DEFAULT_PREFIX_SIZE - 1;
+        desc.prefix_size &= ~(malloc_alignment - 1);
+        desc.suffix_size = DEFAULT_SUFFIX_SIZE;
+    }
+    desc.requested_bytes = n_elements * elem_size;
+    total_size = desc.requested_bytes + desc.prefix_size + desc.suffix_size;
+    total_elements = total_size / elem_size;
+    total_size %= elem_size;
+    if (total_size != 0) {
+        // Add extra to the suffix area.
+        total_elements++;
+        desc.suffix_size += (elem_size - total_size);
+    }
+    desc.ptr = dlcalloc(total_elements, elem_size);
+    if (desc.ptr == NULL) {
+        error_log("<libc_pid=%03u, pid=%03u> calloc: dlcalloc(%u(%u), %u) (prx=%u, sfx=%u) failed.",
+                   malloc_pid, getpid(), n_elements, total_elements, elem_size,
+                   desc.prefix_size, desc.suffix_size);
+        return NULL;
+    }
+
+    if (notify_qemu_malloc(&desc)) {
+        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: calloc(%u(%u), %u): notify_malloc failed for ",
+                  malloc_pid, getpid(), n_elements, total_elements, elem_size);
+        dlfree(desc.ptr);
+        return NULL;
+    } else {
+#if TEST_ACCESS_VIOLATIONS
+        test_access_violation(&desc);
+#endif  // TEST_ACCESS_VIOLATIONS
+        log_mdesc(info, &desc, "### <libc_pid=%03u, pid=%03u> calloc(%u(%u), %u) -> ",
+                  malloc_pid, getpid(), n_elements, total_elements, elem_size);
+        return mallocdesc_user_ptr(&desc);
+    }
+}
+
+/* This routine serves as entry point for 'realloc'.
+ * This routine behaves similarly to qemu_instrumented_free +
+ * qemu_instrumented_malloc. Note that this modifies behavior of "shrinking" an
+ * allocation, but overall it doesn't seem to matter, as caller of realloc
+ * should not expect that pointer returned after shrinking will remain the same.
+ */
+void*
+qemu_instrumented_realloc(void* mem, size_t bytes)
+{
+    MallocDesc new_desc;
+    MallocDesc cur_desc;
+    size_t to_copy;
+    void* ret;
+
+    if (mem == NULL) {
+        // Nothing to realloc. just do regular malloc.
+        info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %u) redir to malloc",
+                 malloc_pid, getpid(), mem, bytes);
+        return qemu_instrumented_malloc(bytes);
+    }
+
+    if (bytes == 0) {
+        // This is a "free" condition.
+        info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %u) redir to free and malloc",
+                 malloc_pid, getpid(), mem, bytes);
+        qemu_instrumented_free(mem);
+
+        // This is what dlrealloc does for a "free" realloc.
+        return NULL;
+    }
+
+    // Query emulator for the reallocating block information.
+    if (query_qemu_malloc_info(mem, &cur_desc, 2)) {
+        // Note that this violation should be already caught in the emulator.
+        error_log("<libc_pid=%03u, pid=%03u>: realloc(%p, %u) query_info failed.",
+                  malloc_pid, getpid(), mem, bytes);
+        return NULL;
+    }
+
+#if TEST_ACCESS_VIOLATIONS
+    test_access_violation(&cur_desc);
+#endif  // TEST_ACCESS_VIOLATIONS
+
+    /* Make sure that reallocating pointer value is what we would expect
+     * for this memory block. Note that this violation should be already caught
+     * in the emulator.*/
+    if (mem != mallocdesc_user_ptr(&cur_desc)) {
+        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %u) is invalid for ",
+                  malloc_pid, getpid(), mem, bytes);
+        return NULL;
+    }
+
+    /* TODO: We're a bit inefficient here, always allocating new block from
+     * the heap. If this realloc shrinks current buffer, we can just do the
+     * shrinking "in place", adjusting suffix_size in the allocation descriptor
+     * for this block that is stored in the emulator. */
+
+    // Initialize descriptor for the new block.
+    new_desc.prefix_size = DEFAULT_PREFIX_SIZE;
+    new_desc.requested_bytes = bytes;
+    new_desc.suffix_size = DEFAULT_SUFFIX_SIZE;
+    new_desc.ptr = dlmalloc(mallocdesc_alloc_size(&new_desc));
+    if (new_desc.ptr == NULL) {
+        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %u): dlmalloc(%u) failed on ",
+                  malloc_pid, getpid(), mem, bytes,
+                  mallocdesc_alloc_size(&new_desc));
+        return NULL;
+    }
+    ret = mallocdesc_user_ptr(&new_desc);
+
+    // Copy user data from old block to the new one.
+    to_copy = bytes < cur_desc.requested_bytes ? bytes :
+                                                 cur_desc.requested_bytes;
+    if (to_copy != 0) {
+        memcpy(ret, mallocdesc_user_ptr(&cur_desc), to_copy);
+    }
+
+    // Register new block with emulator.
+    if(notify_qemu_malloc(&new_desc)) {
+        log_mdesc(error, &new_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %u) notify_malloc failed -> ",
+                  malloc_pid, getpid(), mem, bytes);
+        log_mdesc(error, &cur_desc, "                                                                <- ");
+        dlfree(new_desc.ptr);
+        return NULL;
+    }
+
+#if TEST_ACCESS_VIOLATIONS
+    test_access_violation(&new_desc);
+#endif  // TEST_ACCESS_VIOLATIONS
+
+    // Free old block.
+    if (notify_qemu_free(mem)) {
+        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %u): notify_free failed for ",
+                  malloc_pid, getpid(), mem, bytes);
+        /* Since we registered new decriptor with the emulator, we need
+         * to unregister it before freeing newly allocated block. */
+        notify_qemu_free(mallocdesc_user_ptr(&new_desc));
+        dlfree(new_desc.ptr);
+        return NULL;
+    }
+    dlfree(cur_desc.ptr);
+
+    log_mdesc(info, &new_desc, "=== <libc_pid=%03u, pid=%03u>: realloc(%p, %u) -> ",
+              malloc_pid, getpid(), mem, bytes);
+    log_mdesc(info, &cur_desc, "                                               <- ");
+
+    return ret;
+}
+
+/* This routine serves as entry point for 'memalign'.
+ * This routine behaves similarly to qemu_instrumented_malloc.
+ */
+void*
+qemu_instrumented_memalign(size_t alignment, size_t bytes)
+{
+    MallocDesc desc;
+
+    if (bytes == 0) {
+        // Just let go zero bytes allocation.
+        info_log("::: <libc_pid=%03u, pid=%03u>: memalign(%X, %u) redir to malloc",
+                 malloc_pid, getpid(), alignment, bytes);
+        return qemu_instrumented_malloc(0);
+    }
+
+    /* Prefix size for aligned allocation must be equal to the alignment used
+     * for allocation in order to ensure proper alignment of the returned
+     * pointer, in case that alignment requirement is greater than prefix
+     * size. */
+    desc.prefix_size = alignment > DEFAULT_PREFIX_SIZE ? alignment :
+                                                         DEFAULT_PREFIX_SIZE;
+    desc.requested_bytes = bytes;
+    desc.suffix_size = DEFAULT_SUFFIX_SIZE;
+    desc.ptr = dlmemalign(desc.prefix_size, mallocdesc_alloc_size(&desc));
+    if (desc.ptr == NULL) {
+        error_log("<libc_pid=%03u, pid=%03u> memalign(%X, %u): dlmalloc(%u) failed.",
+                  malloc_pid, getpid(), alignment, bytes,
+                  mallocdesc_alloc_size(&desc));
+        return NULL;
+    }
+    if (notify_qemu_malloc(&desc)) {
+        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: memalign(%X, %u): notify_malloc failed for ",
+                  malloc_pid, getpid(), alignment, bytes);
+        dlfree(desc.ptr);
+        return NULL;
+    }
+
+#if TEST_ACCESS_VIOLATIONS
+    test_access_violation(&desc);
+#endif  // TEST_ACCESS_VIOLATIONS
+
+    log_mdesc(info, &desc, "@@@ <libc_pid=%03u, pid=%03u> memalign(%X, %u) -> ",
+              malloc_pid, getpid(), alignment, bytes);
+    return mallocdesc_user_ptr(&desc);
+}
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index 7d4056d..ae44b06 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -43,12 +43,16 @@
 #include <memory.h>
 #include <assert.h>
 #include <malloc.h>
+#include <linux/futex.h>
 
 extern int  __pthread_clone(int (*fn)(void*), void *child_stack, int flags, void *arg);
 extern void _exit_with_stack_teardown(void * stackBase, int stackSize, int retCode);
 extern void _exit_thread(int  retCode);
 extern int  __set_errno(int);
 
+#define  __likely(cond)    __builtin_expect(!!(cond), 1)
+#define  __unlikely(cond)  __builtin_expect(!!(cond), 0)
+
 void _thread_created_hook(pid_t thread_id) __attribute__((noinline));
 
 #define PTHREAD_ATTR_FLAG_DETACHED      0x00000001
@@ -711,6 +715,21 @@
 int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout);
 int __futex_wake(volatile void *ftx, int count);
 
+int __futex_syscall3(volatile void *ftx, int op, int val);
+int __futex_syscall4(volatile void *ftx, int op, int val, const struct timespec *timeout);
+
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG  128
+#endif
+
+#ifndef FUTEX_WAIT_PRIVATE
+#define FUTEX_WAIT_PRIVATE  (FUTEX_WAIT|FUTEX_PRIVATE_FLAG)
+#endif
+
+#ifndef FUTEX_WAKE_PRIVATE
+#define FUTEX_WAKE_PRIVATE  (FUTEX_WAKE|FUTEX_PRIVATE_FLAG)
+#endif
+
 // mutex lock states
 //
 // 0: unlocked
@@ -722,7 +741,8 @@
  * bits:     name     description
  * 31-16     tid      owner thread's kernel id (recursive and errorcheck only)
  * 15-14     type     mutex type
- * 13-2      counter  counter of recursive mutexes
+ * 13        shared   process-shared flag
+ * 12-2      counter  counter of recursive mutexes
  * 1-0       state    lock state (0, 1 or 2)
  */
 
@@ -736,9 +756,17 @@
 #define  MUTEX_TYPE_ERRORCHECK 0x8000
 
 #define  MUTEX_COUNTER_SHIFT  2
-#define  MUTEX_COUNTER_MASK   0x3ffc
+#define  MUTEX_COUNTER_MASK   0x1ffc
+#define  MUTEX_SHARED_MASK    0x2000
 
-
+/* a mutex attribute holds the following fields
+ *
+ * bits:     name       description
+ * 0-3       type       type of mutex
+ * 4         shared     process-shared flag
+ */
+#define  MUTEXATTR_TYPE_MASK   0x000f
+#define  MUTEXATTR_SHARED_MASK 0x0010
 
 
 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
@@ -763,10 +791,14 @@
 
 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
 {
-    if (attr && *attr >= PTHREAD_MUTEX_NORMAL &&
-                *attr <= PTHREAD_MUTEX_ERRORCHECK ) {
-        *type = *attr;
-        return 0;
+    if (attr) {
+        int  atype = (*attr & MUTEXATTR_TYPE_MASK);
+
+         if (atype >= PTHREAD_MUTEX_NORMAL &&
+             atype <= PTHREAD_MUTEX_ERRORCHECK) {
+            *type = atype;
+            return 0;
+        }
     }
     return EINVAL;
 }
@@ -775,7 +807,7 @@
 {
     if (attr && type >= PTHREAD_MUTEX_NORMAL &&
                 type <= PTHREAD_MUTEX_ERRORCHECK ) {
-        *attr = type;
+        *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type;
         return 0;
     }
     return EINVAL;
@@ -790,54 +822,70 @@
 
     switch (pshared) {
     case PTHREAD_PROCESS_PRIVATE:
+        *attr &= ~MUTEXATTR_SHARED_MASK;
+        return 0;
+
     case PTHREAD_PROCESS_SHARED:
         /* our current implementation of pthread actually supports shared
          * mutexes but won't cleanup if a process dies with the mutex held.
          * Nevertheless, it's better than nothing. Shared mutexes are used
          * by surfaceflinger and audioflinger.
          */
+        *attr |= MUTEXATTR_SHARED_MASK;
         return 0;
     }
-
-    return ENOTSUP;
+    return EINVAL;
 }
 
 int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared)
 {
-    if (!attr)
+    if (!attr || !pshared)
         return EINVAL;
 
-    *pshared = PTHREAD_PROCESS_PRIVATE;
+    *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED
+                                               : PTHREAD_PROCESS_PRIVATE;
     return 0;
 }
 
 int pthread_mutex_init(pthread_mutex_t *mutex,
                        const pthread_mutexattr_t *attr)
 {
-    if ( mutex ) {
-        if (attr == NULL) {
-            mutex->value = MUTEX_TYPE_NORMAL;
-            return 0;
-        }
-        switch ( *attr ) {
-        case PTHREAD_MUTEX_NORMAL:
-            mutex->value = MUTEX_TYPE_NORMAL;
-            return 0;
+    int value = 0;
 
-        case PTHREAD_MUTEX_RECURSIVE:
-            mutex->value = MUTEX_TYPE_RECURSIVE;
-            return 0;
+    if (mutex == NULL)
+        return EINVAL;
 
-        case PTHREAD_MUTEX_ERRORCHECK:
-            mutex->value = MUTEX_TYPE_ERRORCHECK;
-            return 0;
-        }
+    if (__likely(attr == NULL)) {
+        mutex->value = MUTEX_TYPE_NORMAL;
+        return 0;
     }
-    return EINVAL;
+
+    if ((*attr & MUTEXATTR_SHARED_MASK) != 0)
+        value |= MUTEX_SHARED_MASK;
+
+    switch (*attr & MUTEXATTR_TYPE_MASK) {
+    case PTHREAD_MUTEX_NORMAL:
+        value |= MUTEX_TYPE_NORMAL;
+        break;
+    case PTHREAD_MUTEX_RECURSIVE:
+        value |= MUTEX_TYPE_RECURSIVE;
+        break;
+    case PTHREAD_MUTEX_ERRORCHECK:
+        value |= MUTEX_TYPE_ERRORCHECK;
+        break;
+    default:
+        return EINVAL;
+    }
+
+    mutex->value = value;
+    return 0;
 }
 
 int pthread_mutex_destroy(pthread_mutex_t *mutex)
 {
+    if (__unlikely(mutex == NULL))
+        return EINVAL;
+
     mutex->value = 0xdead10cc;
     return 0;
 }
@@ -858,13 +906,15 @@
 static __inline__ void
 _normal_lock(pthread_mutex_t*  mutex)
 {
+    /* We need to preserve the shared flag during operations */
+    int  shared = mutex->value & MUTEX_SHARED_MASK;
     /*
      * The common case is an unlocked mutex, so we begin by trying to
      * change the lock's state from 0 to 1.  __atomic_cmpxchg() returns 0
      * if it made the swap successfully.  If the result is nonzero, this
      * lock is already held by another thread.
      */
-    if (__atomic_cmpxchg(0, 1, &mutex->value ) != 0) {
+    if (__atomic_cmpxchg(shared|0, shared|1, &mutex->value ) != 0) {
         /*
          * We want to go to sleep until the mutex is available, which
          * requires promoting it to state 2.  We need to swap in the new
@@ -881,8 +931,10 @@
          * that the mutex is in state 2 when we go to sleep on it, which
          * guarantees a wake-up call.
          */
-        while (__atomic_swap(2, &mutex->value ) != 0)
-            __futex_wait(&mutex->value, 2, 0);
+        int  wait_op = shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE;
+
+        while (__atomic_swap(shared|2, &mutex->value ) != (shared|0))
+            __futex_syscall4(&mutex->value, wait_op, shared|2, 0);
     }
 }
 
@@ -893,12 +945,16 @@
 static __inline__ void
 _normal_unlock(pthread_mutex_t*  mutex)
 {
+    /* We need to preserve the shared flag during operations */
+    int  shared = mutex->value & MUTEX_SHARED_MASK;
+
     /*
-     * The mutex value will be 1 or (rarely) 2.  We use an atomic decrement
+     * The mutex state will be 1 or (rarely) 2.  We use an atomic decrement
      * to release the lock.  __atomic_dec() returns the previous value;
      * if it wasn't 1 we have to do some additional work.
      */
-    if (__atomic_dec(&mutex->value) != 1) {
+    if (__atomic_dec(&mutex->value) != (shared|1)) {
+        int  wake_op = shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE;
         /*
          * Start by releasing the lock.  The decrement changed it from
          * "contended lock" to "uncontended lock", which means we still
@@ -913,7 +969,7 @@
          * _normal_lock(), because the __futex_wait() call there will
          * return immediately if the mutex value isn't 2.
          */
-        mutex->value = 0;
+        mutex->value = shared;
 
         /*
          * Wake up one waiting thread.  We don't know which thread will be
@@ -936,7 +992,7 @@
          * Either way we have correct behavior and nobody is orphaned on
          * the wait queue.
          */
-        __futex_wake(&mutex->value, 1);
+        __futex_syscall3(&mutex->value, wake_op, 1);
     }
 }
 
@@ -945,182 +1001,188 @@
 static void
 _recursive_lock(void)
 {
-    _normal_lock( &__recursive_lock);
+    _normal_lock(&__recursive_lock);
 }
 
 static void
 _recursive_unlock(void)
 {
-    _normal_unlock( &__recursive_lock );
+    _normal_unlock(&__recursive_lock );
 }
 
-#define  __likely(cond)    __builtin_expect(!!(cond), 1)
-#define  __unlikely(cond)  __builtin_expect(!!(cond), 0)
-
 int pthread_mutex_lock(pthread_mutex_t *mutex)
 {
-    if (__likely(mutex != NULL))
-    {
-        int  mtype = (mutex->value & MUTEX_TYPE_MASK);
+    int mtype, tid, new_lock_type, shared, wait_op;
 
-        if ( __likely(mtype == MUTEX_TYPE_NORMAL) ) {
-            _normal_lock(mutex);
-        }
-        else
-        {
-            int  tid = __get_thread()->kernel_id;
+    if (__unlikely(mutex == NULL))
+        return EINVAL;
 
-            if ( tid == MUTEX_OWNER(mutex) )
-            {
-                int  oldv, counter;
+    mtype = (mutex->value & MUTEX_TYPE_MASK);
+    shared = (mutex->value & MUTEX_SHARED_MASK);
 
-                if (mtype == MUTEX_TYPE_ERRORCHECK) {
-                    /* trying to re-lock a mutex we already acquired */
-                    return EDEADLK;
-                }
-                /*
-                 * We own the mutex, but other threads are able to change
-                 * the contents (e.g. promoting it to "contended"), so we
-                 * need to hold the global lock.
-                 */
-                _recursive_lock();
-                oldv         = mutex->value;
-                counter      = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK;
-                mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter;
-                _recursive_unlock();
-            }
-            else
-            {
-                /*
-                 * If the new lock is available immediately, we grab it in
-                 * the "uncontended" state.
-                 */
-                int new_lock_type = 1;
-
-                for (;;) {
-                    int  oldv;
-
-                    _recursive_lock();
-                    oldv = mutex->value;
-                    if (oldv == mtype) { /* uncontended released lock => 1 or 2 */
-                        mutex->value = ((tid << 16) | mtype | new_lock_type);
-                    } else if ((oldv & 3) == 1) { /* locked state 1 => state 2 */
-                        oldv ^= 3;
-                        mutex->value = oldv;
-                    }
-                    _recursive_unlock();
-
-                    if (oldv == mtype)
-                        break;
-
-                    /*
-                     * The lock was held, possibly contended by others.  From
-                     * now on, if we manage to acquire the lock, we have to
-                     * assume that others are still contending for it so that
-                     * we'll wake them when we unlock it.
-                     */
-                    new_lock_type = 2;
-
-                    __futex_wait( &mutex->value, oldv, 0 );
-                }
-            }
-        }
+    /* Handle normal case first */
+    if ( __likely(mtype == MUTEX_TYPE_NORMAL) ) {
+        _normal_lock(mutex);
         return 0;
     }
-    return EINVAL;
+
+    /* Do we already own this recursive or error-check mutex ? */
+    tid = __get_thread()->kernel_id;
+    if ( tid == MUTEX_OWNER(mutex) )
+    {
+        int  oldv, counter;
+
+        if (mtype == MUTEX_TYPE_ERRORCHECK) {
+            /* trying to re-lock a mutex we already acquired */
+            return EDEADLK;
+        }
+        /*
+         * We own the mutex, but other threads are able to change
+         * the contents (e.g. promoting it to "contended"), so we
+         * need to hold the global lock.
+         */
+        _recursive_lock();
+        oldv         = mutex->value;
+        counter      = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK;
+        mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter;
+        _recursive_unlock();
+        return 0;
+    }
+
+    /* We don't own the mutex, so try to get it.
+     *
+     * First, we try to change its state from 0 to 1, if this
+     * doesn't work, try to change it to state 2.
+     */
+    new_lock_type = 1;
+
+    /* compute futex wait opcode and restore shared flag in mtype */
+    wait_op = shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE;
+    mtype  |= shared;
+
+    for (;;) {
+        int  oldv;
+
+        _recursive_lock();
+        oldv = mutex->value;
+        if (oldv == mtype) { /* uncontended released lock => 1 or 2 */
+            mutex->value = ((tid << 16) | mtype | new_lock_type);
+        } else if ((oldv & 3) == 1) { /* locked state 1 => state 2 */
+            oldv ^= 3;
+            mutex->value = oldv;
+        }
+        _recursive_unlock();
+
+        if (oldv == mtype)
+            break;
+
+        /*
+         * The lock was held, possibly contended by others.  From
+         * now on, if we manage to acquire the lock, we have to
+         * assume that others are still contending for it so that
+         * we'll wake them when we unlock it.
+         */
+        new_lock_type = 2;
+
+        __futex_syscall4(&mutex->value, wait_op, oldv, NULL);
+    }
+    return 0;
 }
 
 
 int pthread_mutex_unlock(pthread_mutex_t *mutex)
 {
-    if (__likely(mutex != NULL))
-    {
-        int  mtype = (mutex->value & MUTEX_TYPE_MASK);
+    int mtype, tid, oldv, shared;
 
-        if (__likely(mtype == MUTEX_TYPE_NORMAL)) {
-            _normal_unlock(mutex);
-        }
-        else
-        {
-            int  tid = __get_thread()->kernel_id;
+    if (__unlikely(mutex == NULL))
+        return EINVAL;
 
-            if ( tid == MUTEX_OWNER(mutex) )
-            {
-                int  oldv;
+    mtype  = (mutex->value & MUTEX_TYPE_MASK);
+    shared = (mutex->value & MUTEX_SHARED_MASK);
 
-                _recursive_lock();
-                oldv = mutex->value;
-                if (oldv & MUTEX_COUNTER_MASK) {
-                    mutex->value = oldv - (1 << MUTEX_COUNTER_SHIFT);
-                    oldv = 0;
-                } else {
-                    mutex->value = mtype;
-                }
-                _recursive_unlock();
-
-                if ((oldv & 3) == 2)
-                    __futex_wake( &mutex->value, 1 );
-            }
-            else {
-                /* trying to unlock a lock we do not own */
-                return EPERM;
-            }
-        }
+    /* Handle common case first */
+    if (__likely(mtype == MUTEX_TYPE_NORMAL)) {
+        _normal_unlock(mutex);
         return 0;
     }
-    return EINVAL;
+
+    /* Do we already own this recursive or error-check mutex ? */
+    tid = __get_thread()->kernel_id;
+    if ( tid != MUTEX_OWNER(mutex) )
+        return EPERM;
+
+    /* We do, decrement counter or release the mutex if it is 0 */
+    _recursive_lock();
+    oldv = mutex->value;
+    if (oldv & MUTEX_COUNTER_MASK) {
+        mutex->value = oldv - (1 << MUTEX_COUNTER_SHIFT);
+        oldv = 0;
+    } else {
+        mutex->value = shared | mtype;
+    }
+    _recursive_unlock();
+
+    /* Wake one waiting thread, if any */
+    if ((oldv & 3) == 2) {
+        int wake_op = shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE;
+        __futex_syscall3(&mutex->value, wake_op, 1);
+    }
+    return 0;
 }
 
 
 int pthread_mutex_trylock(pthread_mutex_t *mutex)
 {
-    if (__likely(mutex != NULL))
+    int mtype, tid, oldv, shared;
+
+    if (__unlikely(mutex == NULL))
+        return EINVAL;
+
+    mtype  = (mutex->value & MUTEX_TYPE_MASK);
+    shared = (mutex->value & MUTEX_SHARED_MASK);
+
+    /* Handle common case first */
+    if ( __likely(mtype == MUTEX_TYPE_NORMAL) )
     {
-        int  mtype = (mutex->value & MUTEX_TYPE_MASK);
-
-        if ( __likely(mtype == MUTEX_TYPE_NORMAL) )
-        {
-            if (__atomic_cmpxchg(0, 1, &mutex->value) == 0)
-                return 0;
-
-            return EBUSY;
-        }
-        else
-        {
-            int  tid = __get_thread()->kernel_id;
-            int  oldv;
-
-            if ( tid == MUTEX_OWNER(mutex) )
-            {
-                int  oldv, counter;
-
-                if (mtype == MUTEX_TYPE_ERRORCHECK) {
-                    /* already locked by ourselves */
-                    return EDEADLK;
-                }
-
-                _recursive_lock();
-                oldv = mutex->value;
-                counter = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK;
-                mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter;
-                _recursive_unlock();
-                return 0;
-            }
-
-            /* try to lock it */
-            _recursive_lock();
-            oldv = mutex->value;
-            if (oldv == mtype)  /* uncontended released lock => state 1 */
-                mutex->value = ((tid << 16) | mtype | 1);
-            _recursive_unlock();
-
-            if (oldv != mtype)
-                return EBUSY;
-
+        if (__atomic_cmpxchg(shared|0, shared|1, &mutex->value) == 0)
             return 0;
-        }
+
+        return EBUSY;
     }
-    return EINVAL;
+
+    /* Do we already own this recursive or error-check mutex ? */
+    tid = __get_thread()->kernel_id;
+    if ( tid == MUTEX_OWNER(mutex) )
+    {
+        int counter;
+
+        if (mtype == MUTEX_TYPE_ERRORCHECK) {
+            /* already locked by ourselves */
+            return EDEADLK;
+        }
+
+        _recursive_lock();
+        oldv = mutex->value;
+        counter = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK;
+        mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter;
+        _recursive_unlock();
+        return 0;
+    }
+
+    /* Restore sharing bit in mtype */
+    mtype |= shared;
+
+    /* Try to lock it, just once. */
+    _recursive_lock();
+    oldv = mutex->value;
+    if (oldv == mtype)  /* uncontended released lock => state 1 */
+        mutex->value = ((tid << 16) | mtype | 1);
+    _recursive_unlock();
+
+    if (oldv != mtype)
+        return EBUSY;
+
+    return 0;
 }
 
 
@@ -1163,100 +1225,152 @@
     clockid_t        clock = CLOCK_MONOTONIC;
     struct timespec  abstime;
     struct timespec  ts;
+    int              mtype, tid, oldv, new_lock_type, shared, wait_op;
 
     /* compute absolute expiration time */
     __timespec_to_relative_msec(&abstime, msecs, clock);
 
-    if (__likely(mutex != NULL))
+    if (__unlikely(mutex == NULL))
+        return EINVAL;
+
+    mtype  = (mutex->value & MUTEX_TYPE_MASK);
+    shared = (mutex->value & MUTEX_SHARED_MASK);
+
+    /* Handle common case first */
+    if ( __likely(mtype == MUTEX_TYPE_NORMAL) )
     {
-        int  mtype = (mutex->value & MUTEX_TYPE_MASK);
+        int  wait_op = shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE;
 
-        if ( __likely(mtype == MUTEX_TYPE_NORMAL) )
-        {
-            /* fast path for unconteded lock */
-            if (__atomic_cmpxchg(0, 1, &mutex->value) == 0)
-                return 0;
-
-            /* loop while needed */
-            while (__atomic_swap(2, &mutex->value) != 0) {
-                if (__timespec_to_absolute(&ts, &abstime, clock) < 0)
-                    return EBUSY;
-
-                __futex_wait(&mutex->value, 2, &ts);
-            }
+        /* fast path for unconteded lock */
+        if (__atomic_cmpxchg(shared|0, shared|1, &mutex->value) == 0)
             return 0;
+
+        /* loop while needed */
+        while (__atomic_swap(shared|2, &mutex->value) != (shared|0)) {
+            if (__timespec_to_absolute(&ts, &abstime, clock) < 0)
+                return EBUSY;
+
+            __futex_syscall4(&mutex->value, wait_op, shared|2, &ts);
         }
-        else
-        {
-            int  tid = __get_thread()->kernel_id;
-            int  oldv;
-
-            if ( tid == MUTEX_OWNER(mutex) )
-            {
-                int  oldv, counter;
-
-                if (mtype == MUTEX_TYPE_ERRORCHECK) {
-                    /* already locked by ourselves */
-                    return EDEADLK;
-                }
-
-                _recursive_lock();
-                oldv = mutex->value;
-                counter = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK;
-                mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter;
-                _recursive_unlock();
-                return 0;
-            }
-            else
-            {
-                /*
-                 * If the new lock is available immediately, we grab it in
-                 * the "uncontended" state.
-                 */
-                int new_lock_type = 1;
-
-                for (;;) {
-                    int  oldv;
-                    struct timespec  ts;
-
-                    _recursive_lock();
-                    oldv = mutex->value;
-                    if (oldv == mtype) { /* uncontended released lock => 1 or 2 */
-                        mutex->value = ((tid << 16) | mtype | new_lock_type);
-                    } else if ((oldv & 3) == 1) { /* locked state 1 => state 2 */
-                        oldv ^= 3;
-                        mutex->value = oldv;
-                    }
-                    _recursive_unlock();
-
-                    if (oldv == mtype)
-                        break;
-
-                    /*
-                     * The lock was held, possibly contended by others.  From
-                     * now on, if we manage to acquire the lock, we have to
-                     * assume that others are still contending for it so that
-                     * we'll wake them when we unlock it.
-                     */
-                    new_lock_type = 2;
-
-                    if (__timespec_to_absolute(&ts, &abstime, clock) < 0)
-                        return EBUSY;
-
-                    __futex_wait( &mutex->value, oldv, &ts );
-                }
-                return 0;
-            }
-        }
+        return 0;
     }
-    return EINVAL;
+
+    /* Do we already own this recursive or error-check mutex ? */
+    tid = __get_thread()->kernel_id;
+    if ( tid == MUTEX_OWNER(mutex) )
+    {
+        int  oldv, counter;
+
+        if (mtype == MUTEX_TYPE_ERRORCHECK) {
+            /* already locked by ourselves */
+            return EDEADLK;
+        }
+
+        _recursive_lock();
+        oldv = mutex->value;
+        counter = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK;
+        mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter;
+        _recursive_unlock();
+        return 0;
+    }
+
+    /* We don't own the mutex, so try to get it.
+     *
+     * First, we try to change its state from 0 to 1, if this
+     * doesn't work, try to change it to state 2.
+     */
+    new_lock_type = 1;
+
+    /* Compute wait op and restore sharing bit in mtype */
+    wait_op = shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE;
+    mtype  |= shared;
+
+    for (;;) {
+        int  oldv;
+        struct timespec  ts;
+
+        _recursive_lock();
+        oldv = mutex->value;
+        if (oldv == mtype) { /* uncontended released lock => 1 or 2 */
+            mutex->value = ((tid << 16) | mtype | new_lock_type);
+        } else if ((oldv & 3) == 1) { /* locked state 1 => state 2 */
+            oldv ^= 3;
+            mutex->value = oldv;
+        }
+        _recursive_unlock();
+
+        if (oldv == mtype)
+            break;
+
+        /*
+         * The lock was held, possibly contended by others.  From
+         * now on, if we manage to acquire the lock, we have to
+         * assume that others are still contending for it so that
+         * we'll wake them when we unlock it.
+         */
+        new_lock_type = 2;
+
+        if (__timespec_to_absolute(&ts, &abstime, clock) < 0)
+            return EBUSY;
+
+        __futex_syscall4(&mutex->value, wait_op, oldv, &ts);
+    }
+    return 0;
 }
 
+int pthread_condattr_init(pthread_condattr_t *attr)
+{
+    if (attr == NULL)
+        return EINVAL;
+
+    *attr = PTHREAD_PROCESS_PRIVATE;
+    return 0;
+}
+
+int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared)
+{
+    if (attr == NULL || pshared == NULL)
+        return EINVAL;
+
+    *pshared = *attr;
+    return 0;
+}
+
+int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
+{
+    if (attr == NULL)
+        return EINVAL;
+
+    if (pshared != PTHREAD_PROCESS_SHARED &&
+        pshared != PTHREAD_PROCESS_PRIVATE)
+        return EINVAL;
+
+    *attr = pshared;
+    return 0;
+}
+
+int pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+    if (attr == NULL)
+        return EINVAL;
+
+    *attr = 0xdeada11d;
+    return 0;
+}
+
+/* We use one bit in condition variable values as the 'shared' flag
+ * The rest is a counter.
+ */
+#define COND_SHARED_MASK        0x0001
+#define COND_COUNTER_INCREMENT  0x0002
+#define COND_COUNTER_MASK       (~COND_SHARED_MASK)
+
+#define COND_IS_SHARED(c)  (((c)->value & COND_SHARED_MASK) != 0)
 
 /* XXX *technically* there is a race condition that could allow
  * XXX a signal to be missed.  If thread A is preempted in _wait()
  * XXX after unlocking the mutex and before waiting, and if other
- * XXX threads call signal or broadcast UINT_MAX times (exactly),
+ * XXX threads call signal or broadcast UINT_MAX/2 times (exactly),
  * XXX before thread A is scheduled again and calls futex_wait(),
  * XXX then the signal will be lost.
  */
@@ -1264,28 +1378,61 @@
 int pthread_cond_init(pthread_cond_t *cond,
                       const pthread_condattr_t *attr)
 {
+    if (cond == NULL)
+        return EINVAL;
+
     cond->value = 0;
+
+    if (attr != NULL && *attr == PTHREAD_PROCESS_SHARED)
+        cond->value |= COND_SHARED_MASK;
+
     return 0;
 }
 
 int pthread_cond_destroy(pthread_cond_t *cond)
 {
+    if (cond == NULL)
+        return EINVAL;
+
     cond->value = 0xdeadc04d;
     return 0;
 }
 
+/* This function is used by pthread_cond_broadcast and
+ * pthread_cond_signal to atomically decrement the counter
+ * then wake-up 'counter' threads.
+ */
+static int
+__pthread_cond_pulse(pthread_cond_t *cond, int  counter)
+{
+    long flags;
+    int  wake_op;
+
+    if (__unlikely(cond == NULL))
+        return EINVAL;
+
+    flags = (cond->value & ~COND_COUNTER_MASK);
+    for (;;) {
+        long oldval = cond->value;
+        long newval = ((oldval - COND_COUNTER_INCREMENT) & COND_COUNTER_MASK)
+                      | flags;
+        if (__atomic_cmpxchg(oldval, newval, &cond->value) == 0)
+            break;
+    }
+
+    wake_op = COND_IS_SHARED(cond) ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE;
+    __futex_syscall3(&cond->value, wake_op, counter);
+    return 0;
+}
+
 int pthread_cond_broadcast(pthread_cond_t *cond)
 {
-    __atomic_dec(&cond->value);
-    __futex_wake(&cond->value, INT_MAX);
-    return 0;
+    return __pthread_cond_pulse(cond, INT_MAX);
 }
 
 int pthread_cond_signal(pthread_cond_t *cond)
 {
-    __atomic_dec(&cond->value);
-    __futex_wake(&cond->value, 1);
-    return 0;
+    return __pthread_cond_pulse(cond, 1);
 }
 
 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
@@ -1299,9 +1446,10 @@
 {
     int  status;
     int  oldvalue = cond->value;
+    int  wait_op  = COND_IS_SHARED(cond) ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE;
 
     pthread_mutex_unlock(mutex);
-    status = __futex_wait(&cond->value, oldvalue, reltime);
+    status = __futex_syscall4(&cond->value, wait_op, oldvalue, reltime);
     pthread_mutex_lock(mutex);
 
     if (status == (-ETIMEDOUT)) return ETIMEDOUT;
@@ -1687,7 +1835,17 @@
 
 int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
 {
-    return __rt_sigprocmask(how, set, oset, _NSIG / 8);
+    /* pthread_sigmask must return the error code, but the syscall
+     * will set errno instead and return 0/-1
+     */
+    int ret, old_errno = errno;
+
+    ret = __rt_sigprocmask(how, set, oset, _NSIG / 8);
+    if (ret < 0)
+        ret = errno;
+
+    errno = old_errno;
+    return ret;
 }
 
 
diff --git a/libc/bionic/semaphore.c b/libc/bionic/semaphore.c
index 0c94600..84b9314 100644
--- a/libc/bionic/semaphore.c
+++ b/libc/bionic/semaphore.c
@@ -180,7 +180,7 @@
     if (sem == NULL)
         return EINVAL;
 
-    if (__atomic_inc((volatile int*)&sem->count) == 0)
+    if (__atomic_inc((volatile int*)&sem->count) >= 0)
         __futex_wake(&sem->count, 1);
 
     return 0;
@@ -196,7 +196,8 @@
     if (__atomic_dec_if_positive(&sem->count) > 0) {
         return 0;
     } else {
-        return EAGAIN;
+        errno = EAGAIN;
+        return -1;
     }
 }
 
diff --git a/libc/bionic/stubs.c b/libc/bionic/stubs.c
index 365f21a..d495674 100644
--- a/libc/bionic/stubs.c
+++ b/libc/bionic/stubs.c
@@ -185,7 +185,7 @@
         goto FAIL;
 
     id = strtoul(name+4, &end, 10);
-    if (id == 0 || *end != '\0')
+    if (*end != '\0')
         goto FAIL;
 
     id += AID_APP;
@@ -361,6 +361,12 @@
     return NULL;
 }
 
+int ttyname_r(int fd, char *buf, size_t buflen)
+{
+    fprintf(stderr, "FIX ME! implement ttyname_r() %s:%d\n", __FILE__, __LINE__);
+    return -ERANGE;
+}
+
 struct netent *getnetbyaddr(uint32_t net, int type)
 {
     fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
@@ -378,3 +384,20 @@
     fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
     return NULL;
 }
+
+char* getusershell(void)
+{
+    fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+    return NULL;
+}
+
+void setusershell(void)
+{
+    fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+}
+
+void endusershell(void)
+{
+    fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+}
+
diff --git a/libc/docs/CHANGES.TXT b/libc/docs/CHANGES.TXT
new file mode 100644
index 0000000..9080685
--- /dev/null
+++ b/libc/docs/CHANGES.TXT
@@ -0,0 +1,174 @@
+Bionic ChangeLog:
+-----------------
+
+Differences between current and Android 2.1:
+
+- Add support for SH-4 CPU architecture !
+
+- __atomic_swap(): use LDREX/STREX CPU instructions on ARMv6 and higher.
+
+- <arpa/telnet.h>: New header (declarations only, no implementation).
+
+- <err.h>: New header + implementation. GLibc compatibility.
+
+- <warn.h>: New header + implementation. GLibc compatibility.
+
+- <fts.h>: New header + implementation.
+
+- <mntent.h>: Add missing <stdio.h> include.
+
+- <regex.h>: New header + implementation.
+
+- <signal.h>: Added killpg()
+
+- <stdint.h>: Allow 64-bit type declarations on C99 builds.
+
+- <stdio.h>: Add fdprintf() and vfdprintf(). Note that GLibc provides
+  the confusing 'dprintf' and 'vdprintf()' functions instead.
+
+- <stdlib.h>: Fix ptsname_r(): the return type is int instead of char*.
+  The mistake comes from a GLibc man page bug (the man page listed a return
+  type of char*, while the implementation used int. Fixed in late 2009 only).
+  The Bionic implementation was incorrect. Technically, this is an ABI
+  breakage, but code that used this function probably never worked or
+  compiled properly anyway.
+
+- <strings.h>: Add missing <sys/types.h> include.
+
+- <sys/queue.h>: Added new header (no implementation - macro templates).
+
+- <sys/resource.h>: Add rlim_t proper definition.
+
+- <time64.h>: Add missing C++ header inclusion guards.
+
+- <unistd.h>: Add getusershell(), setusershell() and endusershell(), though
+  implementation are bogus. GLibc compatibility.
+
+- <wchar.h>: Add mbstowcs() and wcstombs()
+
+- add clone() implementation for ARM (x86 and SH-4 not working yet).
+
+- <sys/epoll.h>: <sys/system_properties.h>: Add missing C++ inclusion guards
+
+- fix getpwnam() and getpwgrp() to accept "app_0" as a valid user name.
+
+- fix sem_trywait() to return -1 and set errno to EAGAIN, instead of
+  returning EAGAIN directly.
+
+- fix sem_post() to wake up multiple threads when called rapidly in
+  succession.
+
+- DNS: partial implementation of RFC3484 (rule 1, 2, 5, 6, 8, 10 and
+  modified rule 9), for better address selection/sorting.
+  In the process, removed code that was previously used for "sortlist"
+  in /etc/resolv.conf. (resolv.conf is already ignored, so the latter
+  is a no-op for actual functionality.)
+
+- fix pthread_sigmask() to properly return an error code without touching
+  errno. Previous implementation returned -1 on error, setting errno, which
+  is not Posix compliant.
+
+- add sigaltstack() implementation for ARM.
+
+- <time.h>: Properly implement the 'timezone' and 'daylight' global variables
+  (they were not defined previously, though declared in the header).
+
+- <time.h>: Fix timezone management implementation to properly update
+  'tm_gmtoff' field in 'struct tm' structure.
+
+- DNS: get rid of spurious random DNS queries when trying to resolve
+  an unknown domain name. Due to an initialization bug, a random DNS search
+  list was generated for each thread if net.dns.search is not defined.
+
+- <pthread.h>: Add pthread_condattr_init/destroy/setpshared/getpshared functions
+  to enable proper shared conditional variable initialization.
+
+  Modify the pthread_mutex_t and pthread_cond_t implementation to use private
+  futexes for performance reasons. Mutexes and Condvars are no longer shareable
+  between processes by default anymore, unless you use PTHREAD_PROCESS_SHARED
+  with pthread_mutexattr_setpshared() and/or pthread_condattr_setpshared().
+
+-------------------------------------------------------------------------------
+Differences between Android 2.1 and 2.0.1:
+
+- zoneinfo: updated data tables to version 2009s
+
+
+-------------------------------------------------------------------------------
+Differences between Android 2.0.1 and 2.0:
+
+- abort(): ARM-specific hack to preserve the 'lr' register when abort()
+  is called (GCC does not preserve it by default since it thinks that
+  abort() never returns). This improves stack traces considerably.
+
+
+-------------------------------------------------------------------------------
+Differences between Android 2.0 and 1.6:
+
+- memcmp(), memcpy(): ARMv7 optimized versions.
+
+- pthread_mutexattr_setpshared(): implementation will not return ENOTSUP
+  if PTHREAD_PROCESS_SHARED is used, because our Mutex implementation can
+  work across multiple processes.
+
+  *HOWEVER* it does not use "robust futexes" which means that held mutexes
+  *are not* automatically released by the kernel when the owner process
+  crashes or exits. This is only done to simplify communication between
+  two always-live system processes, DO NOT USE THIS IN APPLICATIONS !
+
+- pthread_mutex_lock_timeout_np(): New Android-specific function to
+  perform a timed lock (). In case of timeout, it returns EBUSY.
+
+- pthread_cond_timedwait_monotonic_np(): Same as pthread_cond_timedwait()
+  but uses the monotonic clock(). Android-specific.
+
+- pthread_cond_timedwait_relative_np(): Same as pthread_cond_timedwait()
+  but uses a relative timeout instead. Android-specific.
+
+- <netinet/in.h>: Now includes <netinet/in6.h>.
+
+- <netinet/in6.h>: Added IPV6_JOIN_GROUP, IPV6_LEAVE_GROUP, IN6ADDR_ANY_INIT
+  and ipv6mr_interface definitions.
+
+- <time.h>:
+    * Add missing tzset() declaration.
+    * Add Android-specific strftime_tz().
+
+- getaddrinfo():
+    Only perform IPv6 lookup for AF_UNSPEC if we have IPv6 connectivity.
+    This saves one DNS query per lookup on non-IPv6 systems.
+
+- mktime(): Fix an infinite loop problen that appeared when switching to
+  GCC 4.4.0.
+
+- strftime(): fix incorrect handling of dates > 2038 due to 64-bit issue
+  in original code.
+
+-------------------------------------------------------------------------------
+Differences between Android 1.6 and 1.5:
+
+- C runtime: Fix runtime initialization to be called before any static C++
+  constructors. This allows these to use pthread functions properly.
+
+- __aeabi_atexit(): Fix implementation to properly call C++ static destructors
+  when the program exits (or when a shared library is unloaded).
+
+- <sys/stat.h>: added GLibc compatibility macros definitions:
+
+        #define  st_atimensec  st_atime_nsec
+        #define  st_mtimensec  st_mtime_nsec
+        #define  st_ctimensec  st_ctime_nsec
+
+- getaddrinfo(): implementation will now allow numeric ports if ai_socktype is
+  set to ANY. This is to match the GLibc behaviour.
+
+- getservent(): and getservent_r() incorrectly returned the port in host-endian
+  order in the s_port field. It now returns it in big-endian order.
+
+- DNS: Allow underscore in the middle of DNS labels. While not really
+  standard, this extension is needed for some VPN configurations and is
+  supported by other operating systems.
+
+- DNS: Support for DNS domain search lists through the new net.dns.search
+  system property. The corresponding value must be a space-separated list of
+  domain suffixes.
diff --git a/libc/include/arpa/telnet.h b/libc/include/arpa/telnet.h
new file mode 100644
index 0000000..d318e08
--- /dev/null
+++ b/libc/include/arpa/telnet.h
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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.
+ *
+ *	@(#)telnet.h	8.2 (Berkeley) 12/15/93
+ */
+
+#ifndef _ARPA_TELNET_H
+#define	_ARPA_TELNET_H 1
+
+/*
+ * Definitions for the TELNET protocol.
+ */
+#define	IAC	255		/* interpret as command: */
+#define	DONT	254		/* you are not to use option */
+#define	DO	253		/* please, you use option */
+#define	WONT	252		/* I won't use option */
+#define	WILL	251		/* I will use option */
+#define	SB	250		/* interpret as subnegotiation */
+#define	GA	249		/* you may reverse the line */
+#define	EL	248		/* erase the current line */
+#define	EC	247		/* erase the current character */
+#define	AYT	246		/* are you there */
+#define	AO	245		/* abort output--but let prog finish */
+#define	IP	244		/* interrupt process--permanently */
+#define	BREAK	243		/* break */
+#define	DM	242		/* data mark--for connect. cleaning */
+#define	NOP	241		/* nop */
+#define	SE	240		/* end sub negotiation */
+#define EOR     239             /* end of record (transparent mode) */
+#define	ABORT	238		/* Abort process */
+#define	SUSP	237		/* Suspend process */
+#define	xEOF	236		/* End of file: EOF is already used... */
+
+#define SYNCH	242		/* for telfunc calls */
+
+#ifdef TELCMDS
+char *telcmds[] = {
+	"EOF", "SUSP", "ABORT", "EOR",
+	"SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC",
+	"EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0,
+};
+#else
+extern char *telcmds[];
+#endif
+
+#define	TELCMD_FIRST	xEOF
+#define	TELCMD_LAST	IAC
+#define	TELCMD_OK(x)	((unsigned int)(x) <= TELCMD_LAST && \
+			 (unsigned int)(x) >= TELCMD_FIRST)
+#define	TELCMD(x)	telcmds[(x)-TELCMD_FIRST]
+
+/* telnet options */
+#define TELOPT_BINARY	0	/* 8-bit data path */
+#define TELOPT_ECHO	1	/* echo */
+#define	TELOPT_RCP	2	/* prepare to reconnect */
+#define	TELOPT_SGA	3	/* suppress go ahead */
+#define	TELOPT_NAMS	4	/* approximate message size */
+#define	TELOPT_STATUS	5	/* give status */
+#define	TELOPT_TM	6	/* timing mark */
+#define	TELOPT_RCTE	7	/* remote controlled transmission and echo */
+#define TELOPT_NAOL 	8	/* negotiate about output line width */
+#define TELOPT_NAOP 	9	/* negotiate about output page size */
+#define TELOPT_NAOCRD	10	/* negotiate about CR disposition */
+#define TELOPT_NAOHTS	11	/* negotiate about horizontal tabstops */
+#define TELOPT_NAOHTD	12	/* negotiate about horizontal tab disposition */
+#define TELOPT_NAOFFD	13	/* negotiate about formfeed disposition */
+#define TELOPT_NAOVTS	14	/* negotiate about vertical tab stops */
+#define TELOPT_NAOVTD	15	/* negotiate about vertical tab disposition */
+#define TELOPT_NAOLFD	16	/* negotiate about output LF disposition */
+#define TELOPT_XASCII	17	/* extended ascii character set */
+#define	TELOPT_LOGOUT	18	/* force logout */
+#define	TELOPT_BM	19	/* byte macro */
+#define	TELOPT_DET	20	/* data entry terminal */
+#define	TELOPT_SUPDUP	21	/* supdup protocol */
+#define	TELOPT_SUPDUPOUTPUT 22	/* supdup output */
+#define	TELOPT_SNDLOC	23	/* send location */
+#define	TELOPT_TTYPE	24	/* terminal type */
+#define	TELOPT_EOR	25	/* end or record */
+#define	TELOPT_TUID	26	/* TACACS user identification */
+#define	TELOPT_OUTMRK	27	/* output marking */
+#define	TELOPT_TTYLOC	28	/* terminal location number */
+#define	TELOPT_3270REGIME 29	/* 3270 regime */
+#define	TELOPT_X3PAD	30	/* X.3 PAD */
+#define	TELOPT_NAWS	31	/* window size */
+#define	TELOPT_TSPEED	32	/* terminal speed */
+#define	TELOPT_LFLOW	33	/* remote flow control */
+#define TELOPT_LINEMODE	34	/* Linemode option */
+#define TELOPT_XDISPLOC	35	/* X Display Location */
+#define TELOPT_OLD_ENVIRON 36	/* Old - Environment variables */
+#define	TELOPT_AUTHENTICATION 37/* Authenticate */
+#define	TELOPT_ENCRYPT	38	/* Encryption option */
+#define TELOPT_NEW_ENVIRON 39	/* New - Environment variables */
+#define	TELOPT_EXOPL	255	/* extended-options-list */
+
+
+#define	NTELOPTS	(1+TELOPT_NEW_ENVIRON)
+#ifdef TELOPTS
+const char *telopts[NTELOPTS+1] = {
+	"BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
+	"STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
+	"NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
+	"NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
+	"DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
+	"SEND LOCATION", "TERMINAL TYPE", "END OF RECORD",
+	"TACACS UID", "OUTPUT MARKING", "TTYLOC",
+	"3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW",
+	"LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION",
+	"ENCRYPT", "NEW-ENVIRON",
+	0,
+};
+#define	TELOPT_FIRST	TELOPT_BINARY
+#define	TELOPT_LAST	TELOPT_NEW_ENVIRON
+#define	TELOPT_OK(x)	((unsigned int)(x) <= TELOPT_LAST)
+#define	TELOPT(x)	telopts[(x)-TELOPT_FIRST]
+#endif
+
+/* sub-option qualifiers */
+#define	TELQUAL_IS	0	/* option is... */
+#define	TELQUAL_SEND	1	/* send option */
+#define	TELQUAL_INFO	2	/* ENVIRON: informational version of IS */
+#define	TELQUAL_REPLY	2	/* AUTHENTICATION: client version of IS */
+#define	TELQUAL_NAME	3	/* AUTHENTICATION: client version of IS */
+
+#define	LFLOW_OFF		0	/* Disable remote flow control */
+#define	LFLOW_ON		1	/* Enable remote flow control */
+#define	LFLOW_RESTART_ANY	2	/* Restart output on any char */
+#define	LFLOW_RESTART_XON	3	/* Restart output only on XON */
+
+/*
+ * LINEMODE suboptions
+ */
+
+#define	LM_MODE		1
+#define	LM_FORWARDMASK	2
+#define	LM_SLC		3
+
+#define	MODE_EDIT	0x01
+#define	MODE_TRAPSIG	0x02
+#define	MODE_ACK	0x04
+#define MODE_SOFT_TAB	0x08
+#define MODE_LIT_ECHO	0x10
+
+#define	MODE_MASK	0x1f
+
+/* Not part of protocol, but needed to simplify things... */
+#define MODE_FLOW		0x0100
+#define MODE_ECHO		0x0200
+#define MODE_INBIN		0x0400
+#define MODE_OUTBIN		0x0800
+#define MODE_FORCE		0x1000
+
+#define	SLC_SYNCH	1
+#define	SLC_BRK		2
+#define	SLC_IP		3
+#define	SLC_AO		4
+#define	SLC_AYT		5
+#define	SLC_EOR		6
+#define	SLC_ABORT	7
+#define	SLC_EOF		8
+#define	SLC_SUSP	9
+#define	SLC_EC		10
+#define	SLC_EL		11
+#define	SLC_EW		12
+#define	SLC_RP		13
+#define	SLC_LNEXT	14
+#define	SLC_XON		15
+#define	SLC_XOFF	16
+#define	SLC_FORW1	17
+#define	SLC_FORW2	18
+
+#define	NSLC		18
+
+/*
+ * For backwards compatibility, we define SLC_NAMES to be the
+ * list of names if SLC_NAMES is not defined.
+ */
+#define	SLC_NAMELIST	"0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \
+			"ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \
+			"LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0,
+#ifdef	SLC_NAMES
+const char *slc_names[] = {
+	SLC_NAMELIST
+};
+#else
+extern char *slc_names[];
+#define	SLC_NAMES SLC_NAMELIST
+#endif
+
+#define	SLC_NAME_OK(x)	((unsigned int)(x) <= NSLC)
+#define SLC_NAME(x)	slc_names[x]
+
+#define	SLC_NOSUPPORT	0
+#define	SLC_CANTCHANGE	1
+#define	SLC_VARIABLE	2
+#define	SLC_DEFAULT	3
+#define	SLC_LEVELBITS	0x03
+
+#define	SLC_FUNC	0
+#define	SLC_FLAGS	1
+#define	SLC_VALUE	2
+
+#define	SLC_ACK		0x80
+#define	SLC_FLUSHIN	0x40
+#define	SLC_FLUSHOUT	0x20
+
+#define	OLD_ENV_VAR	1
+#define	OLD_ENV_VALUE	0
+#define	NEW_ENV_VAR	0
+#define	NEW_ENV_VALUE	1
+#define	ENV_ESC		2
+#define ENV_USERVAR	3
+
+/*
+ * AUTHENTICATION suboptions
+ */
+
+/*
+ * Who is authenticating who ...
+ */
+#define	AUTH_WHO_CLIENT		0	/* Client authenticating server */
+#define	AUTH_WHO_SERVER		1	/* Server authenticating client */
+#define	AUTH_WHO_MASK		1
+
+/*
+ * amount of authentication done
+ */
+#define	AUTH_HOW_ONE_WAY	0
+#define	AUTH_HOW_MUTUAL		2
+#define	AUTH_HOW_MASK		2
+
+#define	AUTHTYPE_NULL		0
+#define	AUTHTYPE_KERBEROS_V4	1
+#define	AUTHTYPE_KERBEROS_V5	2
+#define	AUTHTYPE_SPX		3
+#define	AUTHTYPE_MINK		4
+#define	AUTHTYPE_CNT		5
+
+#define	AUTHTYPE_TEST		99
+
+#ifdef	AUTH_NAMES
+const char *authtype_names[] = {
+	"NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0,
+};
+#else
+extern char *authtype_names[];
+#endif
+
+#define	AUTHTYPE_NAME_OK(x)	((unsigned int)(x) < AUTHTYPE_CNT)
+#define	AUTHTYPE_NAME(x)	authtype_names[x]
+
+/*
+ * ENCRYPTion suboptions
+ */
+#define	ENCRYPT_IS		0	/* I pick encryption type ... */
+#define	ENCRYPT_SUPPORT		1	/* I support encryption types ... */
+#define	ENCRYPT_REPLY		2	/* Initial setup response */
+#define	ENCRYPT_START		3	/* Am starting to send encrypted */
+#define	ENCRYPT_END		4	/* Am ending encrypted */
+#define	ENCRYPT_REQSTART	5	/* Request you start encrypting */
+#define	ENCRYPT_REQEND		6	/* Request you send encrypting */
+#define	ENCRYPT_ENC_KEYID	7
+#define	ENCRYPT_DEC_KEYID	8
+#define	ENCRYPT_CNT		9
+
+#define	ENCTYPE_ANY		0
+#define	ENCTYPE_DES_CFB64	1
+#define	ENCTYPE_DES_OFB64	2
+#define	ENCTYPE_CNT		3
+
+#ifdef	ENCRYPT_NAMES
+const char *encrypt_names[] = {
+	"IS", "SUPPORT", "REPLY", "START", "END",
+	"REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID",
+	0,
+};
+const char *enctype_names[] = {
+	"ANY", "DES_CFB64",  "DES_OFB64",  0,
+};
+#else
+extern const char *encrypt_names[];
+extern const char *enctype_names[];
+#endif
+
+
+#define	ENCRYPT_NAME_OK(x)	((unsigned int)(x) < ENCRYPT_CNT)
+#define	ENCRYPT_NAME(x)		encrypt_names[x]
+
+#define	ENCTYPE_NAME_OK(x)	((unsigned int)(x) < ENCTYPE_CNT)
+#define	ENCTYPE_NAME(x)		enctype_names[x]
+
+#endif /* arpa/telnet.h */
diff --git a/libc/include/ctype.h b/libc/include/ctype.h
index b5f9ff4..58b76ea 100644
--- a/libc/include/ctype.h
+++ b/libc/include/ctype.h
@@ -59,7 +59,11 @@
 
 /* extern __inline is a GNU C extension */
 #ifdef __GNUC__
+#  if defined(__GNUC_STDC_INLINE__)
+#define	__CTYPE_INLINE	extern __inline __attribute__((__gnu_inline__))
+#  else
 #define	__CTYPE_INLINE	extern __inline
+#  endif
 #else
 #define	__CTYPE_INLINE	static __inline
 #endif
diff --git a/libc/include/err.h b/libc/include/err.h
index e69de29..1636efe 100644
--- a/libc/include/err.h
+++ b/libc/include/err.h
@@ -0,0 +1,90 @@
+/*	$OpenBSD: err.h,v 1.10 2006/01/06 18:53:04 millert Exp $	*/
+/*	$NetBSD: err.h,v 1.11 1994/10/26 00:55:52 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 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.
+ *
+ *	@(#)err.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _ERR_H_
+#define	_ERR_H_
+
+/*
+ * Don't use va_list in the err/warn prototypes.   Va_list is typedef'd in two
+ * places (<machine/varargs.h> and <machine/stdarg.h>), so if we include one
+ * of them here we may collide with the utility's includes.  It's unreasonable
+ * for utilities to have to include one of them to include err.h, so we get
+ * __va_list from <machine/_types.h> and use it.
+ */
+#include <sys/cdefs.h>
+#include <machine/_types.h>
+
+__BEGIN_DECLS
+
+__noreturn void	err(int, const char *, ...)
+			__attribute__((__format__ (printf, 2, 3)));
+__noreturn void	verr(int, const char *, __va_list)
+			__attribute__((__format__ (printf, 2, 0)));
+__noreturn void	errx(int, const char *, ...)
+			__attribute__((__format__ (printf, 2, 3)));
+__noreturn void	verrx(int, const char *, __va_list)
+			__attribute__((__format__ (printf, 2, 0)));
+void		warn(const char *, ...)
+			__attribute__((__format__ (printf, 1, 2)));
+void		vwarn(const char *, __va_list)
+			__attribute__((__format__ (printf, 1, 0)));
+void		warnx(const char *, ...)
+			__attribute__((__format__ (printf, 1, 2)));
+void		vwarnx(const char *, __va_list)
+			__attribute__((__format__ (printf, 1, 0)));
+
+/*
+ * The _* versions are for use in library functions so user-defined
+ * versions of err*,warn* do not get used.
+ */
+__noreturn void	_err(int, const char *, ...)
+			__attribute__((__format__ (printf, 2, 3)));
+__noreturn void	_verr(int, const char *, __va_list)
+			__attribute__((__format__ (printf, 2, 0)));
+__noreturn void	_errx(int, const char *, ...)
+			__attribute__((__format__ (printf, 2, 3)));
+__noreturn void	_verrx(int, const char *, __va_list)
+			__attribute__((__format__ (printf, 2, 0)));
+void		_warn(const char *, ...)
+			__attribute__((__format__ (printf, 1, 2)));
+void		_vwarn(const char *, __va_list)
+			__attribute__((__format__ (printf, 1, 0)));
+void		_warnx(const char *, ...)
+			__attribute__((__format__ (printf, 1, 2)));
+void		_vwarnx(const char *, __va_list)
+			__attribute__((__format__ (printf, 1, 0)));
+
+__END_DECLS
+
+#endif /* !_ERR_H_ */
diff --git a/libc/include/fts.h b/libc/include/fts.h
new file mode 100644
index 0000000..da26a88
--- /dev/null
+++ b/libc/include/fts.h
@@ -0,0 +1,125 @@
+/*	$OpenBSD: fts.h,v 1.12 2009/08/27 16:19:27 millert Exp $	*/
+/*	$NetBSD: fts.h,v 1.5 1994/12/28 01:41:50 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1989, 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.
+ *
+ *	@(#)fts.h	8.3 (Berkeley) 8/14/94
+ */
+
+#ifndef	_FTS_H_
+#define	_FTS_H_
+
+typedef struct {
+	struct _ftsent *fts_cur;	/* current node */
+	struct _ftsent *fts_child;	/* linked list of children */
+	struct _ftsent **fts_array;	/* sort array */
+	dev_t fts_dev;			/* starting device # */
+	char *fts_path;			/* path for this descent */
+	int fts_rfd;			/* fd for root */
+	size_t fts_pathlen;		/* sizeof(path) */
+	int fts_nitems;			/* elements in the sort array */
+	int (*fts_compar)();		/* compare function */
+
+#define	FTS_COMFOLLOW	0x0001		/* follow command line symlinks */
+#define	FTS_LOGICAL	0x0002		/* logical walk */
+#define	FTS_NOCHDIR	0x0004		/* don't change directories */
+#define	FTS_NOSTAT	0x0008		/* don't get stat info */
+#define	FTS_PHYSICAL	0x0010		/* physical walk */
+#define	FTS_SEEDOT	0x0020		/* return dot and dot-dot */
+#define	FTS_XDEV	0x0040		/* don't cross devices */
+#define	FTS_OPTIONMASK	0x00ff		/* valid user option mask */
+
+#define	FTS_NAMEONLY	0x1000		/* (private) child names only */
+#define	FTS_STOP	0x2000		/* (private) unrecoverable error */
+	int fts_options;		/* fts_open options, global flags */
+} FTS;
+
+typedef struct _ftsent {
+	struct _ftsent *fts_cycle;	/* cycle node */
+	struct _ftsent *fts_parent;	/* parent directory */
+	struct _ftsent *fts_link;	/* next file in directory */
+	long fts_number;	        /* local numeric value */
+	void *fts_pointer;	        /* local address value */
+	char *fts_accpath;		/* access path */
+	char *fts_path;			/* root path */
+	int fts_errno;			/* errno for this node */
+	int fts_symfd;			/* fd for symlink */
+	size_t fts_pathlen;		/* strlen(fts_path) */
+	size_t fts_namelen;		/* strlen(fts_name) */
+
+	ino_t fts_ino;			/* inode */
+	dev_t fts_dev;			/* device */
+	nlink_t fts_nlink;		/* link count */
+
+#define	FTS_ROOTPARENTLEVEL	-1
+#define	FTS_ROOTLEVEL		 0
+#define	FTS_MAXLEVEL		 0x7fff
+	short fts_level;		/* depth (-1 to N) */
+
+#define	FTS_D		 1		/* preorder directory */
+#define	FTS_DC		 2		/* directory that causes cycles */
+#define	FTS_DEFAULT	 3		/* none of the above */
+#define	FTS_DNR		 4		/* unreadable directory */
+#define	FTS_DOT		 5		/* dot or dot-dot */
+#define	FTS_DP		 6		/* postorder directory */
+#define	FTS_ERR		 7		/* error; errno is set */
+#define	FTS_F		 8		/* regular file */
+#define	FTS_INIT	 9		/* initialized only */
+#define	FTS_NS		10		/* stat(2) failed */
+#define	FTS_NSOK	11		/* no stat(2) requested */
+#define	FTS_SL		12		/* symbolic link */
+#define	FTS_SLNONE	13		/* symbolic link without target */
+	unsigned short fts_info;	/* user flags for FTSENT structure */
+
+#define	FTS_DONTCHDIR	 0x01		/* don't chdir .. to the parent */
+#define	FTS_SYMFOLLOW	 0x02		/* followed a symlink to get here */
+	unsigned short fts_flags;	/* private flags for FTSENT structure */
+
+#define	FTS_AGAIN	 1		/* read node again */
+#define	FTS_FOLLOW	 2		/* follow symbolic link */
+#define	FTS_NOINSTR	 3		/* no instructions */
+#define	FTS_SKIP	 4		/* discard node */
+	unsigned short fts_instr;	/* fts_set() instructions */
+
+	struct stat *fts_statp;		/* stat(2) information */
+	char fts_name[1];		/* file name */
+} FTSENT;
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+FTSENT	*fts_children(FTS *, int);
+int	 fts_close(FTS *);
+FTS	*fts_open(char * const *, int,
+	    int (*)(const FTSENT **, const FTSENT **));
+FTSENT	*fts_read(FTS *);
+int	 fts_set(FTS *, FTSENT *, int);
+__END_DECLS
+
+#endif /* !_FTS_H_ */
diff --git a/libc/include/mntent.h b/libc/include/mntent.h
index 468ff74..b83da1f 100644
--- a/libc/include/mntent.h
+++ b/libc/include/mntent.h
@@ -28,6 +28,7 @@
 #ifndef _MNTENT_H_
 #define _MNTENT_H_
 
+#include <stdio.h>
 
 #define MNTTYPE_IGNORE "ignore"
 
diff --git a/libc/include/netdb.h b/libc/include/netdb.h
index b0c3b72..c2e08ea 100644
--- a/libc/include/netdb.h
+++ b/libc/include/netdb.h
@@ -75,10 +75,6 @@
 
 #define  MAXHOSTNAMELEN  256
 
-/* BIONIC-BEGIN */
-#define  h_errno   (*__get_h_errno())
-extern int*  __get_h_errno(void);
-/* BIONIC-END */
 
 /*
  * Structures returned by network data base library.  All addresses are
@@ -203,6 +199,10 @@
 #define	SCOPE_DELIMITER	'%'
 
 __BEGIN_DECLS
+/* BIONIC-BEGIN */
+#define  h_errno   (*__get_h_errno())
+int*  __get_h_errno(void);
+/* BIONIC-END */
 void endhostent(void);
 void endnetent(void);
 void endnetgrent(void);
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 6603b3f..eb2d169 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -165,6 +165,11 @@
 int pthread_mutex_trylock(pthread_mutex_t *mutex);
 int pthread_mutex_timedlock(pthread_mutex_t *mutex, struct timespec*  ts);
 
+int pthread_condattr_init(pthread_condattr_t *attr);
+int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared);
+int pthread_condattr_setpshared(pthread_condattr_t* attr, int pshared);
+int pthread_condattr_destroy(pthread_condattr_t *attr);
+
 int pthread_cond_init(pthread_cond_t *cond,
                       const pthread_condattr_t *attr);
 int pthread_cond_destroy(pthread_cond_t *cond);
diff --git a/libc/include/regex.h b/libc/include/regex.h
new file mode 100644
index 0000000..aec38e3
--- /dev/null
+++ b/libc/include/regex.h
@@ -0,0 +1,105 @@
+/*	$OpenBSD: regex.h,v 1.6 2003/06/02 19:34:12 millert Exp $	*/
+/*	$NetBSD: regex.h,v 1.4.6.1 1996/06/10 18:57:07 explorer Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Henry Spencer.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * 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.
+ *
+ *	@(#)regex.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _REGEX_H_
+#define	_REGEX_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/* types */
+typedef off_t regoff_t;
+
+typedef struct {
+	int re_magic;
+	size_t re_nsub;		/* number of parenthesized subexpressions */
+	const char *re_endp;	/* end pointer for REG_PEND */
+	struct re_guts *re_g;	/* none of your business :-) */
+} regex_t;
+
+typedef struct {
+	regoff_t rm_so;		/* start of match */
+	regoff_t rm_eo;		/* end of match */
+} regmatch_t;
+
+/* regcomp() flags */
+#define	REG_BASIC	0000
+#define	REG_EXTENDED	0001
+#define	REG_ICASE	0002
+#define	REG_NOSUB	0004
+#define	REG_NEWLINE	0010
+#define	REG_NOSPEC	0020
+#define	REG_PEND	0040
+#define	REG_DUMP	0200
+
+/* regerror() flags */
+#define	REG_NOMATCH	 1
+#define	REG_BADPAT	 2
+#define	REG_ECOLLATE	 3
+#define	REG_ECTYPE	 4
+#define	REG_EESCAPE	 5
+#define	REG_ESUBREG	 6
+#define	REG_EBRACK	 7
+#define	REG_EPAREN	 8
+#define	REG_EBRACE	 9
+#define	REG_BADBR	10
+#define	REG_ERANGE	11
+#define	REG_ESPACE	12
+#define	REG_BADRPT	13
+#define	REG_EMPTY	14
+#define	REG_ASSERT	15
+#define	REG_INVARG	16
+#define	REG_ATOI	255	/* convert name to number (!) */
+#define	REG_ITOA	0400	/* convert number to name (!) */
+
+/* regexec() flags */
+#define	REG_NOTBOL	00001
+#define	REG_NOTEOL	00002
+#define	REG_STARTEND	00004
+#define	REG_TRACE	00400	/* tracing of execution */
+#define	REG_LARGE	01000	/* force large representation */
+#define	REG_BACKR	02000	/* force use of backref code */
+
+__BEGIN_DECLS
+int	regcomp(regex_t *, const char *, int);
+size_t	regerror(int, const regex_t *, char *, size_t);
+int	regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+void	regfree(regex_t *);
+__END_DECLS
+
+#endif /* !_REGEX_H_ */
diff --git a/libc/include/sched.h b/libc/include/sched.h
index 6600bae..33b9ad6 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -69,8 +69,9 @@
 #define CLONE_CHILD_SETTID   0x01000000
 #define CLONE_STOPPED        0x02000000
 
-extern int    clone(int (*fn)(void*), void *child_stack, int flags, void *arg);
-extern pid_t  __clone(int, void *);
+#ifdef __GNU_SOURCE
+extern int clone(int (*fn)(void *), void *child_stack, int flags, void*  arg, ...);
+#endif
 
 __END_DECLS
 
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 5540847..9e5ce61 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -118,6 +118,7 @@
 
 extern int raise(int);
 extern int kill(pid_t, int);
+extern int killpg(int pgrp, int sig);
 
 
 __END_DECLS
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 79e526b..f0e103e 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -112,6 +112,9 @@
  * 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 */
@@ -434,4 +437,15 @@
 #define getchar_unlocked()	getc_unlocked(stdin)
 #define putchar_unlocked(c)	putc_unlocked(c, stdout)
 
+#ifdef _GNU_SOURCE
+/*
+ * glibc defines dprintf(int, const char*, ...), which is poorly named
+ * and likely to conflict with locally defined debugging printfs
+ * fdprintf is a better name, and some programs that use fdprintf use a
+ * #define fdprintf dprintf for compatibility
+ */
+int fdprintf(int, const char*, ...);
+int vfdprintf(int, const char*, __va_list);
+#endif /* _GNU_SOURCE */
+
 #endif /* _STDIO_H_ */
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index acfe694..41e8d26 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -132,7 +132,7 @@
 
 extern int    unlockpt(int);
 extern char*  ptsname(int);
-extern char*  ptsname_r(int, char*, size_t);
+extern int    ptsname_r(int, char*, size_t);
 extern int    getpt(void);
 
 static __inline__ int grantpt(int __fd)
diff --git a/libc/include/sys/epoll.h b/libc/include/sys/epoll.h
index 1478caa..decdb46 100644
--- a/libc/include/sys/epoll.h
+++ b/libc/include/sys/epoll.h
@@ -28,6 +28,10 @@
 #ifndef _SYS_EPOLL_H_
 #define _SYS_EPOLL_H_
 
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
 #define EPOLLIN          0x00000001
 #define EPOLLPRI         0x00000002
 #define EPOLLOUT         0x00000004
@@ -62,5 +66,7 @@
 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
 int epoll_wait(int epfd, struct epoll_event *events, int max, int timeout);
 
+__END_DECLS
+
 #endif  /* _SYS_EPOLL_H_ */
 
diff --git a/libc/include/sys/linux-syscalls.h b/libc/include/sys/linux-syscalls.h
index 5d2b55e..30c58fd 100644
--- a/libc/include/sys/linux-syscalls.h
+++ b/libc/include/sys/linux-syscalls.h
@@ -42,6 +42,7 @@
 #define __NR_prctl                        (__NR_SYSCALL_BASE + 172)
 #define __NR_capget                       (__NR_SYSCALL_BASE + 184)
 #define __NR_capset                       (__NR_SYSCALL_BASE + 185)
+#define __NR_sigaltstack                  (__NR_SYSCALL_BASE + 186)
 #define __NR_acct                         (__NR_SYSCALL_BASE + 51)
 #define __NR_read                         (__NR_SYSCALL_BASE + 3)
 #define __NR_write                        (__NR_SYSCALL_BASE + 4)
@@ -170,6 +171,8 @@
 #define __NR_getsockopt                   (__NR_SYSCALL_BASE + 295)
 #define __NR_sendmsg                      (__NR_SYSCALL_BASE + 296)
 #define __NR_recvmsg                      (__NR_SYSCALL_BASE + 297)
+#define __NR_ioprio_set                   (__NR_SYSCALL_BASE + 314)
+#define __NR_ioprio_get                   (__NR_SYSCALL_BASE + 315)
 #define __NR_epoll_create                 (__NR_SYSCALL_BASE + 250)
 #define __NR_epoll_ctl                    (__NR_SYSCALL_BASE + 251)
 #define __NR_epoll_wait                   (__NR_SYSCALL_BASE + 252)
@@ -210,6 +213,8 @@
 #define __NR_timer_delete                 (__NR_SYSCALL_BASE + 263)
 #define __NR_utimes                       (__NR_SYSCALL_BASE + 271)
 #define __NR_socketcall                   (__NR_SYSCALL_BASE + 102)
+#define __NR_ioprio_set                   (__NR_SYSCALL_BASE + 289)
+#define __NR_ioprio_get                   (__NR_SYSCALL_BASE + 290)
 #define __NR_epoll_create                 (__NR_SYSCALL_BASE + 254)
 #define __NR_epoll_ctl                    (__NR_SYSCALL_BASE + 255)
 #define __NR_epoll_wait                   (__NR_SYSCALL_BASE + 256)
@@ -264,6 +269,8 @@
 #define __NR_socketcall                   (__NR_SYSCALL_BASE + 102)
 #define __NR_socketcall                   (__NR_SYSCALL_BASE + 102)
 #define __NR___socketcall                 (__NR_SYSCALL_BASE + 102)
+#define __NR_ioprio_set                   (__NR_SYSCALL_BASE + 289)
+#define __NR_ioprio_get                   (__NR_SYSCALL_BASE + 290)
 #define __NR_epoll_create                 (__NR_SYSCALL_BASE + 254)
 #define __NR_epoll_ctl                    (__NR_SYSCALL_BASE + 255)
 #define __NR_epoll_wait                   (__NR_SYSCALL_BASE + 256)
diff --git a/libc/include/sys/linux-unistd.h b/libc/include/sys/linux-unistd.h
index 12f7704..116d047 100644
--- a/libc/include/sys/linux-unistd.h
+++ b/libc/include/sys/linux-unistd.h
@@ -10,9 +10,9 @@
 pid_t            __fork (void);
 pid_t            _waitpid (pid_t, int*, int, struct rusage*);
 int              waitid (int, pid_t, struct siginfo_t*, int,void*);
-pid_t            __clone (int (*fn)(void*), void *child_stack, int flags, void *arg);
+pid_t            __sys_clone (int, void*, int*, void*, int*);
 int              execve (const char*, char* const*, char* const*);
-int              setuid (uid_t);
+int              __setuid (uid_t);
 uid_t            getuid (void);
 gid_t            getgid (void);
 uid_t            geteuid (void);
@@ -26,8 +26,8 @@
 pid_t            setsid (void);
 int              setgid (gid_t);
 int              seteuid (uid_t);
-int              setreuid (uid_t, uid_t);
-int              setresuid (uid_t, uid_t, uid_t);
+int              __setreuid (uid_t, uid_t);
+int              __setresuid (uid_t, uid_t, uid_t);
 int              setresgid (gid_t, gid_t, gid_t);
 void*            __brk (void*);
 int              kill (pid_t, int);
@@ -48,6 +48,7 @@
 int              prctl (int option, unsigned int arg2, unsigned int arg3, unsigned int arg4, unsigned int arg5);
 int              capget (cap_user_header_t header, cap_user_data_t data);
 int              capset (cap_user_header_t header, const cap_user_data_t data);
+int              sigaltstack (const stack_t*, stack_t*);
 int              acct (const char*  filepath);
 ssize_t          read (int, void*, size_t);
 ssize_t          write (int, const void*, size_t);
@@ -180,6 +181,8 @@
 int              sched_get_priority_max (int policy);
 int              sched_get_priority_min (int policy);
 int              sched_rr_get_interval (pid_t pid, struct timespec *interval);
+int              ioprio_set (int which, int who, int ioprio);
+int              ioprio_get (int which, int who);
 int              uname (struct utsname *);
 pid_t            __wait4 (pid_t pid, int *status, int options, struct rusage *rusage);
 mode_t           umask (mode_t);
diff --git a/libc/include/sys/queue.h b/libc/include/sys/queue.h
new file mode 100644
index 0000000..b0e6b38
--- /dev/null
+++ b/libc/include/sys/queue.h
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 1991, 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.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef	_SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The
+ * elements are singly linked for minimum space and pointer manipulation
+ * overhead at the expense of O(n) removal for arbitrary elements. New
+ * elements can be added to the list after an existing element or at the
+ * head of the list.  Elements being removed from the head of the list
+ * should use the explicit macro for this purpose for optimum
+ * efficiency. A singly-linked list may only be traversed in the forward
+ * direction.  Singly-linked lists are ideal for applications with large
+ * datasets and few or no removals or for implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+#define	LIST_INIT(head) do {						\
+	(head)->lh_first = NULL;					\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
+		(listelm)->field.le_next->field.le_prev =		\
+		    &(elm)->field.le_next;				\
+	(listelm)->field.le_next = (elm);				\
+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	(elm)->field.le_next = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &(elm)->field.le_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
+		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+	(head)->lh_first = (elm);					\
+	(elm)->field.le_prev = &(head)->lh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	if ((elm)->field.le_next != NULL)				\
+		(elm)->field.le_next->field.le_prev = 			\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = (elm)->field.le_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = ((head)->lh_first);				\
+		(var);							\
+		(var) = ((var)->field.le_next))
+
+/*
+ * List access methods.
+ */
+#define	LIST_EMPTY(head)		((head)->lh_first == NULL)
+#define	LIST_FIRST(head)		((head)->lh_first)
+#define	LIST_NEXT(elm, field)		((elm)->field.le_next)
+
+
+/*
+ * Singly-linked List definitions.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_INIT(head) do {						\
+	(head)->slh_first = NULL;					\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
+	(slistelm)->field.sle_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.sle_next = (head)->slh_first;			\
+	(head)->slh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	(head)->slh_first = (head)->slh_first->field.sle_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if ((head)->slh_first == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = (head)->slh_first;		\
+		while(curelm->field.sle_next != (elm))			\
+			curelm = curelm->field.sle_next;		\
+		curelm->field.sle_next =				\
+		    curelm->field.sle_next->field.sle_next;		\
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
+
+/*
+ * Singly-linked List access methods.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+#define	SLIST_FIRST(head)	((head)->slh_first)
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)					\
+struct name {								\
+	struct type *stqh_first;	/* first element */			\
+	struct type **stqh_last;	/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_INIT(head) do {						\
+	(head)->stqh_first = NULL;					\
+	(head)->stqh_last = &(head)->stqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.stqe_next = (head)->stqh_first) == NULL)	\
+		(head)->stqh_last = &(elm)->field.stqe_next;		\
+	(head)->stqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.stqe_next = NULL;					\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &(elm)->field.stqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
+		(head)->stqh_last = &(elm)->field.stqe_next;		\
+	(listelm)->field.stqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
+		(head)->stqh_last = &(head)->stqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if ((head)->stqh_first == (elm)) {				\
+		STAILQ_REMOVE_HEAD((head), field);			\
+	} else {							\
+		struct type *curelm = (head)->stqh_first;		\
+		while (curelm->field.stqe_next != (elm))			\
+			curelm = curelm->field.stqe_next;		\
+		if ((curelm->field.stqe_next =				\
+			curelm->field.stqe_next->field.stqe_next) == NULL) \
+			    (head)->stqh_last = &(curelm)->field.stqe_next; \
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->stqh_first);				\
+		(var);							\
+		(var) = ((var)->field.stqe_next))
+
+/*
+ * Singly-linked Tail queue access methods.
+ */
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+
+/*
+ * Simple queue definitions.
+ */
+#define	SIMPLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *sqh_first;	/* first element */			\
+	struct type **sqh_last;	/* addr of last next element */		\
+}
+
+#define	SIMPLEQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).sqh_first }
+
+#define	SIMPLEQ_ENTRY(type)						\
+struct {								\
+	struct type *sqe_next;	/* next element */			\
+}
+
+/*
+ * Simple queue functions.
+ */
+#define	SIMPLEQ_INIT(head) do {						\
+	(head)->sqh_first = NULL;					\
+	(head)->sqh_last = &(head)->sqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(head)->sqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.sqe_next = NULL;					\
+	*(head)->sqh_last = (elm);					\
+	(head)->sqh_last = &(elm)->field.sqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(listelm)->field.sqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_REMOVE_HEAD(head, field) do {				\
+	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+		(head)->sqh_last = &(head)->sqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_REMOVE(head, elm, type, field) do {			\
+	if ((head)->sqh_first == (elm)) {				\
+		SIMPLEQ_REMOVE_HEAD((head), field);			\
+	} else {							\
+		struct type *curelm = (head)->sqh_first;		\
+		while (curelm->field.sqe_next != (elm))			\
+			curelm = curelm->field.sqe_next;		\
+		if ((curelm->field.sqe_next =				\
+			curelm->field.sqe_next->field.sqe_next) == NULL) \
+			    (head)->sqh_last = &(curelm)->field.sqe_next; \
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->sqh_first);				\
+		(var);							\
+		(var) = ((var)->field.sqe_next))
+
+/*
+ * Simple queue access methods.
+ */
+#define	SIMPLEQ_EMPTY(head)		((head)->sqh_first == NULL)
+#define	SIMPLEQ_FIRST(head)		((head)->sqh_first)
+#define	SIMPLEQ_NEXT(elm, field)	((elm)->field.sqe_next)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define	_TAILQ_HEAD(name, type, qual)					\
+struct name {								\
+	qual type *tqh_first;		/* first element */		\
+	qual type *qual *tqh_last;	/* addr of last next element */	\
+}
+#define TAILQ_HEAD(name, type)	_TAILQ_HEAD(name, struct type,)
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	_TAILQ_ENTRY(type, qual)					\
+struct {								\
+	qual type *tqe_next;		/* next element */		\
+	qual type *qual *tqe_prev;	/* address of previous next element */\
+}
+#define TAILQ_ENTRY(type)	_TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_INIT(head) do {						\
+	(head)->tqh_first = NULL;					\
+	(head)->tqh_last = &(head)->tqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
+		(head)->tqh_first->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.tqe_next = NULL;					\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if (((elm)->field.tqe_next) != NULL)				\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = ((head)->tqh_first);				\
+		(var);							\
+		(var) = ((var)->field.tqe_next))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));	\
+		(var);							\
+		(var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+
+/*
+ * Tail queue access methods.
+ */
+#define	TAILQ_EMPTY(head)		((head)->tqh_first == NULL)
+#define	TAILQ_FIRST(head)		((head)->tqh_first)
+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
+
+#define	TAILQ_LAST(head, headname) \
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define	TAILQ_PREV(elm, headname, field) \
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+
+/*
+ * Circular queue definitions.
+ */
+#define	CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define	CIRCLEQ_HEAD_INITIALIZER(head)					\
+	{ (void *)&head, (void *)&head }
+
+#define	CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_INIT(head) do {						\
+	(head)->cqh_first = (void *)(head);				\
+	(head)->cqh_last = (void *)(head);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
+	(elm)->field.cqe_prev = (listelm);				\
+	if ((listelm)->field.cqe_next == (void *)(head))		\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
+	(listelm)->field.cqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
+	(elm)->field.cqe_next = (listelm);				\
+	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
+	if ((listelm)->field.cqe_prev == (void *)(head))		\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
+	(listelm)->field.cqe_prev = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.cqe_next = (head)->cqh_first;			\
+	(elm)->field.cqe_prev = (void *)(head);				\
+	if ((head)->cqh_last == (void *)(head))				\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(head)->cqh_first->field.cqe_prev = (elm);		\
+	(head)->cqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.cqe_next = (void *)(head);				\
+	(elm)->field.cqe_prev = (head)->cqh_last;			\
+	if ((head)->cqh_first == (void *)(head))			\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(head)->cqh_last->field.cqe_next = (elm);		\
+	(head)->cqh_last = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
+	if ((elm)->field.cqe_next == (void *)(head))			\
+		(head)->cqh_last = (elm)->field.cqe_prev;		\
+	else								\
+		(elm)->field.cqe_next->field.cqe_prev =			\
+		    (elm)->field.cqe_prev;				\
+	if ((elm)->field.cqe_prev == (void *)(head))			\
+		(head)->cqh_first = (elm)->field.cqe_next;		\
+	else								\
+		(elm)->field.cqe_prev->field.cqe_next =			\
+		    (elm)->field.cqe_next;				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->cqh_first);				\
+		(var) != (const void *)(head);				\
+		(var) = ((var)->field.cqe_next))
+
+#define	CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
+	for ((var) = ((head)->cqh_last);				\
+		(var) != (const void *)(head);				\
+		(var) = ((var)->field.cqe_prev))
+
+/*
+ * Circular queue access methods.
+ */
+#define	CIRCLEQ_EMPTY(head)		((head)->cqh_first == (void *)(head))
+#define	CIRCLEQ_FIRST(head)		((head)->cqh_first)
+#define	CIRCLEQ_LAST(head)		((head)->cqh_last)
+#define	CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
+#define	CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
+
+#define CIRCLEQ_LOOP_NEXT(head, elm, field)				\
+	(((elm)->field.cqe_next == (void *)(head))			\
+	    ? ((head)->cqh_first)					\
+	    : (elm->field.cqe_next))
+#define CIRCLEQ_LOOP_PREV(head, elm, field)				\
+	(((elm)->field.cqe_prev == (void *)(head))			\
+	    ? ((head)->cqh_last)					\
+	    : (elm->field.cqe_prev))
+
+#endif	/* sys/queue.h */
diff --git a/libc/include/sys/resource.h b/libc/include/sys/resource.h
index a7de6f0..ef325c7 100644
--- a/libc/include/sys/resource.h
+++ b/libc/include/sys/resource.h
@@ -40,6 +40,8 @@
 #include <linux/resource.h>
 #undef   getrusage
 
+typedef unsigned long rlim_t;
+
 __BEGIN_DECLS
 
 extern int getpriority(int, int);
diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h
index 2eb00cd..4fdc944 100644
--- a/libc/include/sys/system_properties.h
+++ b/libc/include/sys/system_properties.h
@@ -29,6 +29,10 @@
 #ifndef _INCLUDE_SYS_SYSTEM_PROPERTIES_H
 #define _INCLUDE_SYS_SYSTEM_PROPERTIES_H
 
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
 typedef struct prop_info prop_info;
 
 #define PROP_NAME_MAX   32
@@ -76,4 +80,6 @@
 */ 
 const prop_info *__system_property_find_nth(unsigned n);
 
+__END_DECLS
+
 #endif
diff --git a/libc/include/time64.h b/libc/include/time64.h
index 9da4bc7..7ec05af 100644
--- a/libc/include/time64.h
+++ b/libc/include/time64.h
@@ -31,9 +31,12 @@
 #ifndef TIME64_H
 #define TIME64_H
 
+#include <sys/cdefs.h>
 #include <time.h>
 #include <stdint.h>
 
+__BEGIN_DECLS
+
 typedef int64_t  time64_t;
 
 struct tm *gmtime64_r (const time64_t *, struct tm *);
@@ -51,4 +54,6 @@
 time64_t mktime64 (const struct tm *);
 time64_t timelocal64 (const struct tm *);
 
+__END_DECLS
+
 #endif /* TIME64_H */
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 1ada37e..b4f1dda 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -99,6 +99,10 @@
 extern int issetugid(void);
 extern char* getlogin(void);
 extern int getlogin_r(char* name, size_t namesize);
+extern char* getusershell(void);
+extern void setusershell(void);
+extern void endusershell(void);
+
 
 
 /* Macros for access() */
@@ -145,7 +149,7 @@
 extern int pause(void);
 extern unsigned int alarm(unsigned int);
 extern unsigned int sleep(unsigned int);
-extern void usleep(unsigned long);
+extern int usleep(unsigned long);
 
 extern int gethostname(char *, size_t);
 extern int sethostname(const char *, size_t);
@@ -163,6 +167,8 @@
 extern int optind, opterr, optopt;
 
 extern int isatty(int);
+extern char* ttyname(int);
+extern int ttyname_r(int, char*, size_t);
 
 extern int  acct(const char*  filepath);
 
@@ -185,6 +191,14 @@
 extern pid_t tcgetpgrp(int fd);
 extern int   tcsetpgrp(int fd, pid_t _pid);
 
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+
 __END_DECLS
 
 #endif /* _UNISTD_H_ */
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index e2feb60..97e1b5c 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -100,6 +100,7 @@
 extern size_t            mbrlen(const char *, size_t, mbstate_t *);
 extern size_t            mbrtowc(wchar_t *, const char *, size_t, mbstate_t *);
 extern size_t            mbsrtowcs(wchar_t *, const char **, size_t, mbstate_t *);
+extern size_t            mbstowcs(wchar_t *, const char *, size_t);
 extern wint_t            putwc(wchar_t, FILE *);
 extern wint_t            putwchar(wchar_t);
 extern int               swprintf(wchar_t *, size_t, const wchar_t *, ...);
@@ -130,6 +131,7 @@
 extern double            wcstod(const wchar_t *, wchar_t **);
 extern wchar_t          *wcstok(wchar_t *, const wchar_t *, wchar_t **);
 extern long int          wcstol(const wchar_t *, wchar_t **, int);
+extern size_t            wcstombs(char *, const wchar_t *, size_t);
 extern unsigned long int wcstoul(const wchar_t *, wchar_t **, int);
 extern wchar_t          *wcswcs(const wchar_t *, const wchar_t *);
 extern int               wcswidth(const wchar_t *, size_t);
diff --git a/libc/kernel/arch-arm/asm/ptrace.h b/libc/kernel/arch-arm/asm/ptrace.h
index c6dfea1..b6be08c 100644
--- a/libc/kernel/arch-arm/asm/ptrace.h
+++ b/libc/kernel/arch-arm/asm/ptrace.h
@@ -29,6 +29,8 @@
 #define PTRACE_GETCRUNCHREGS 25
 #define PTRACE_SETCRUNCHREGS 26
 
+#define PTRACE_GETVFPREGS 27
+
 #define USR26_MODE 0x00000000
 #define FIQ26_MODE 0x00000001
 #define IRQ26_MODE 0x00000002
@@ -61,7 +63,12 @@
 #ifndef __ASSEMBLY__
 
 struct pt_regs {
- long uregs[18];
+  long uregs[18];
+};
+
+struct user_vfp {
+  unsigned long long fpregs[32];
+  unsigned long fpscr;
 };
 
 #define ARM_cpsr uregs[16]
diff --git a/libc/kernel/common/asm-generic/swab.h b/libc/kernel/common/asm-generic/swab.h
new file mode 100644
index 0000000..592926d
--- /dev/null
+++ b/libc/kernel/common/asm-generic/swab.h
@@ -0,0 +1,23 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   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.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _ASM_GENERIC_SWAB_H
+#define _ASM_GENERIC_SWAB_H
+
+#include <asm/bitsperlong.h>
+
+#if __BITS_PER_LONG == 32
+#if defined(__GNUC__) && (!defined(__STRICT_ANSI__) || defined(__KERNEL__))
+#define __SWAB_64_THRU_32__
+#endif
+#endif
+
+#endif
diff --git a/libc/kernel/common/linux/android_pmem.h b/libc/kernel/common/linux/android_pmem.h
index bdf3aba..be0b342 100644
--- a/libc/kernel/common/linux/android_pmem.h
+++ b/libc/kernel/common/linux/android_pmem.h
@@ -23,6 +23,7 @@
 #define PMEM_CONNECT _IOW(PMEM_IOCTL_MAGIC, 6, unsigned int)
 
 #define PMEM_GET_TOTAL_SIZE _IOW(PMEM_IOCTL_MAGIC, 7, unsigned int)
+#define PMEM_CACHE_FLUSH _IOW(PMEM_IOCTL_MAGIC, 8, unsigned int)
 
 struct android_pmem_platform_data
 {
diff --git a/libc/kernel/common/linux/if_addr.h b/libc/kernel/common/linux/if_addr.h
new file mode 100644
index 0000000..9c1fa15
--- /dev/null
+++ b/libc/kernel/common/linux/if_addr.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   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.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef __LINUX_IF_ADDR_H
+#define __LINUX_IF_ADDR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ifaddrmsg
+{
+ __u8 ifa_family;
+ __u8 ifa_prefixlen;
+ __u8 ifa_flags;
+ __u8 ifa_scope;
+ __u32 ifa_index;
+};
+
+enum
+{
+ IFA_UNSPEC,
+ IFA_ADDRESS,
+ IFA_LOCAL,
+ IFA_LABEL,
+ IFA_BROADCAST,
+ IFA_ANYCAST,
+ IFA_CACHEINFO,
+ IFA_MULTICAST,
+ __IFA_MAX,
+};
+
+#define IFA_MAX (__IFA_MAX - 1)
+
+#define IFA_F_SECONDARY 0x01
+#define IFA_F_TEMPORARY IFA_F_SECONDARY
+
+#define IFA_F_NODAD 0x02
+#define IFA_F_OPTIMISTIC 0x04
+#define IFA_F_DADFAILED 0x08
+#define IFA_F_HOMEADDRESS 0x10
+#define IFA_F_DEPRECATED 0x20
+#define IFA_F_TENTATIVE 0x40
+#define IFA_F_PERMANENT 0x80
+
+struct ifa_cacheinfo
+{
+ __u32 ifa_prefered;
+ __u32 ifa_valid;
+ __u32 cstamp;
+ __u32 tstamp;
+};
+
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+#endif
diff --git a/libc/kernel/common/linux/if_arp.h b/libc/kernel/common/linux/if_arp.h
index 1da50f5..a3df6c8 100644
--- a/libc/kernel/common/linux/if_arp.h
+++ b/libc/kernel/common/linux/if_arp.h
@@ -39,6 +39,7 @@
 #define ARPHRD_ROSE 270
 #define ARPHRD_X25 271  
 #define ARPHRD_HWX25 272  
+#define ARPHRD_CAN 280  
 #define ARPHRD_PPP 512
 #define ARPHRD_CISCO 513  
 #define ARPHRD_HDLC ARPHRD_CISCO
@@ -72,6 +73,10 @@
 #define ARPHRD_IEEE80211 801  
 #define ARPHRD_IEEE80211_PRISM 802  
 #define ARPHRD_IEEE80211_RADIOTAP 803  
+#define ARPHRD_IEEE802154 804
+
+#define ARPHRD_PHONET 820  
+#define ARPHRD_PHONET_PIPE 821  
 
 #define ARPHRD_VOID 0xFFFF  
 #define ARPHRD_NONE 0xFFFE  
@@ -108,11 +113,11 @@
 
 struct arphdr
 {
- unsigned short ar_hrd;
- unsigned short ar_pro;
+ __be16 ar_hrd;
+ __be16 ar_pro;
  unsigned char ar_hln;
  unsigned char ar_pln;
- unsigned short ar_op;
+ __be16 ar_op;
 
 };
 
diff --git a/libc/kernel/common/linux/if_ether.h b/libc/kernel/common/linux/if_ether.h
index ff89c3d..1ba7a99 100644
--- a/libc/kernel/common/linux/if_ether.h
+++ b/libc/kernel/common/linux/if_ether.h
@@ -19,6 +19,7 @@
 #define ETH_ZLEN 60  
 #define ETH_DATA_LEN 1500  
 #define ETH_FRAME_LEN 1514  
+#define ETH_FCS_LEN 4  
 
 #define ETH_P_LOOP 0x0060  
 #define ETH_P_PUP 0x0200  
@@ -37,12 +38,14 @@
 #define ETH_P_DIAG 0x6005  
 #define ETH_P_CUST 0x6006  
 #define ETH_P_SCA 0x6007  
+#define ETH_P_TEB 0x6558  
 #define ETH_P_RARP 0x8035  
 #define ETH_P_ATALK 0x809B  
 #define ETH_P_AARP 0x80F3  
 #define ETH_P_8021Q 0x8100  
 #define ETH_P_IPX 0x8137  
 #define ETH_P_IPV6 0x86DD  
+#define ETH_P_PAUSE 0x8808  
 #define ETH_P_SLOW 0x8809  
 #define ETH_P_WCCP 0x883E  
 #define ETH_P_PPP_DISC 0x8863  
@@ -51,8 +54,13 @@
 #define ETH_P_MPLS_MC 0x8848  
 #define ETH_P_ATMMPOA 0x884c  
 #define ETH_P_ATMFATE 0x8884  
+#define ETH_P_PAE 0x888E  
 #define ETH_P_AOE 0x88A2  
 #define ETH_P_TIPC 0x88CA  
+#define ETH_P_1588 0x88F7  
+#define ETH_P_FCOE 0x8906  
+#define ETH_P_FIP 0x8914  
+#define ETH_P_EDSA 0xDADA  
 
 #define ETH_P_802_3 0x0001  
 #define ETH_P_AX25 0x0002  
@@ -63,6 +71,7 @@
 #define ETH_P_WAN_PPP 0x0007  
 #define ETH_P_PPP_MP 0x0008  
 #define ETH_P_LOCALTALK 0x0009  
+#define ETH_P_CAN 0x000C  
 #define ETH_P_PPPTALK 0x0010  
 #define ETH_P_TR_802_2 0x0011  
 #define ETH_P_MOBITEX 0x0015  
@@ -71,6 +80,10 @@
 #define ETH_P_ECONET 0x0018  
 #define ETH_P_HDLC 0x0019  
 #define ETH_P_ARCNET 0x001A  
+#define ETH_P_DSA 0x001B  
+#define ETH_P_TRAILER 0x001C  
+#define ETH_P_PHONET 0x00F5  
+#define ETH_P_IEEE802154 0x00F6  
 
 struct ethhdr {
  unsigned char h_dest[ETH_ALEN];
diff --git a/libc/kernel/common/linux/if_link.h b/libc/kernel/common/linux/if_link.h
new file mode 100644
index 0000000..e9d77d4
--- /dev/null
+++ b/libc/kernel/common/linux/if_link.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   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.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _LINUX_IF_LINK_H
+#define _LINUX_IF_LINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct rtnl_link_stats
+{
+ __u32 rx_packets;
+ __u32 tx_packets;
+ __u32 rx_bytes;
+ __u32 tx_bytes;
+ __u32 rx_errors;
+ __u32 tx_errors;
+ __u32 rx_dropped;
+ __u32 tx_dropped;
+ __u32 multicast;
+ __u32 collisions;
+
+ __u32 rx_length_errors;
+ __u32 rx_over_errors;
+ __u32 rx_crc_errors;
+ __u32 rx_frame_errors;
+ __u32 rx_fifo_errors;
+ __u32 rx_missed_errors;
+
+ __u32 tx_aborted_errors;
+ __u32 tx_carrier_errors;
+ __u32 tx_fifo_errors;
+ __u32 tx_heartbeat_errors;
+ __u32 tx_window_errors;
+
+ __u32 rx_compressed;
+ __u32 tx_compressed;
+};
+
+struct rtnl_link_ifmap
+{
+ __u64 mem_start;
+ __u64 mem_end;
+ __u64 base_addr;
+ __u16 irq;
+ __u8 dma;
+ __u8 port;
+};
+
+enum
+{
+ IFLA_UNSPEC,
+ IFLA_ADDRESS,
+ IFLA_BROADCAST,
+ IFLA_IFNAME,
+ IFLA_MTU,
+ IFLA_LINK,
+ IFLA_QDISC,
+ IFLA_STATS,
+ IFLA_COST,
+#define IFLA_COST IFLA_COST
+ IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+ IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+ IFLA_WIRELESS,
+#define IFLA_WIRELESS IFLA_WIRELESS
+ IFLA_PROTINFO,
+#define IFLA_PROTINFO IFLA_PROTINFO
+ IFLA_TXQLEN,
+#define IFLA_TXQLEN IFLA_TXQLEN
+ IFLA_MAP,
+#define IFLA_MAP IFLA_MAP
+ IFLA_WEIGHT,
+#define IFLA_WEIGHT IFLA_WEIGHT
+ IFLA_OPERSTATE,
+ IFLA_LINKMODE,
+ IFLA_LINKINFO,
+#define IFLA_LINKINFO IFLA_LINKINFO
+ IFLA_NET_NS_PID,
+ IFLA_IFALIAS,
+ __IFLA_MAX
+};
+
+#define IFLA_MAX (__IFLA_MAX - 1)
+
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+
+enum
+{
+ IFLA_INET6_UNSPEC,
+ IFLA_INET6_FLAGS,
+ IFLA_INET6_CONF,
+ IFLA_INET6_STATS,
+ IFLA_INET6_MCAST,
+ IFLA_INET6_CACHEINFO,
+ IFLA_INET6_ICMP6STATS,
+ __IFLA_INET6_MAX
+};
+
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+
+struct ifla_cacheinfo
+{
+ __u32 max_reasm_len;
+ __u32 tstamp;
+ __u32 reachable_time;
+ __u32 retrans_time;
+};
+
+enum
+{
+ IFLA_INFO_UNSPEC,
+ IFLA_INFO_KIND,
+ IFLA_INFO_DATA,
+ IFLA_INFO_XSTATS,
+ __IFLA_INFO_MAX,
+};
+
+#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1)
+
+enum
+{
+ IFLA_VLAN_UNSPEC,
+ IFLA_VLAN_ID,
+ IFLA_VLAN_FLAGS,
+ IFLA_VLAN_EGRESS_QOS,
+ IFLA_VLAN_INGRESS_QOS,
+ __IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_flags {
+ __u32 flags;
+ __u32 mask;
+};
+
+enum
+{
+ IFLA_VLAN_QOS_UNSPEC,
+ IFLA_VLAN_QOS_MAPPING,
+ __IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1)
+
+struct ifla_vlan_qos_mapping
+{
+ __u32 from;
+ __u32 to;
+};
+
+#endif
diff --git a/libc/kernel/common/linux/msm_kgsl.h b/libc/kernel/common/linux/msm_kgsl.h
index 740ba60..f543522 100644
--- a/libc/kernel/common/linux/msm_kgsl.h
+++ b/libc/kernel/common/linux/msm_kgsl.h
@@ -49,6 +49,10 @@
  unsigned int sbz;
  volatile unsigned int eoptimestamp;
  unsigned int sbz2;
+ volatile unsigned int ts_cmp_enable;
+ unsigned int sbz3;
+ volatile unsigned int ref_wait_ts;
+ unsigned int sbz4;
 };
 
 #define KGSL_DEVICE_MEMSTORE_OFFSET(field)   offsetof(struct kgsl_devmemstore, field)
@@ -65,7 +69,8 @@
  KGSL_PROP_DEVICE_POWER = 0x00000003,
  KGSL_PROP_SHMEM = 0x00000004,
  KGSL_PROP_SHMEM_APERTURES = 0x00000005,
- KGSL_PROP_MMU_ENABLE = 0x00000006
+ KGSL_PROP_MMU_ENABLE = 0x00000006,
+ KGSL_PROP_INTERRUPT_WAITS = 0x00000007,
 };
 
 struct kgsl_shadowprop {
diff --git a/libc/kernel/common/linux/msm_q6venc.h b/libc/kernel/common/linux/msm_q6venc.h
index 5b63680..dbe118a 100755
--- a/libc/kernel/common/linux/msm_q6venc.h
+++ b/libc/kernel/common/linux/msm_q6venc.h
@@ -14,96 +14,281 @@
 
 #include <linux/types.h>
 
-struct venc_buf {
- unsigned int src_id;
+#define VENC_MAX_RECON_BUFFERS 2
+
+#define VENC_FLAG_EOS 0x00000001
+#define VENC_FLAG_END_OF_FRAME 0x00000010
+#define VENC_FLAG_SYNC_FRAME 0x00000020
+#define VENC_FLAG_EXTRA_DATA 0x00000040
+#define VENC_FLAG_CODEC_CONFIG 0x00000080
+
+enum venc_flush_type {
+ VENC_FLUSH_INPUT,
+ VENC_FLUSH_OUTPUT,
+ VENC_FLUSH_ALL
+};
+
+enum venc_state_type {
+ VENC_STATE_PAUSE = 0x1,
+ VENC_STATE_START = 0x2,
+ VENC_STATE_STOP = 0x4
+};
+
+enum venc_event_type_enum {
+ VENC_EVENT_START_STATUS,
+ VENC_EVENT_STOP_STATUS,
+ VENC_EVENT_SUSPEND_STATUS,
+ VENC_EVENT_RESUME_STATUS,
+ VENC_EVENT_FLUSH_STATUS,
+ VENC_EVENT_RELEASE_INPUT,
+ VENC_EVENT_DELIVER_OUTPUT,
+ VENC_EVENT_UNKNOWN_STATUS
+};
+
+enum venc_status_code {
+ VENC_STATUS_SUCCESS,
+ VENC_STATUS_ERROR,
+ VENC_STATUS_INVALID_STATE,
+ VENC_STATUS_FLUSHING,
+ VENC_STATUS_INVALID_PARAM,
+ VENC_STATUS_CMD_QUEUE_FULL,
+ VENC_STATUS_CRITICAL,
+ VENC_STATUS_INSUFFICIENT_RESOURCES,
+ VENC_STATUS_TIMEOUT
+};
+
+enum venc_msg_code {
+ VENC_MSG_INDICATION,
+ VENC_MSG_INPUT_BUFFER_DONE,
+ VENC_MSG_OUTPUT_BUFFER_DONE,
+ VENC_MSG_NEED_OUTPUT_BUFFER,
+ VENC_MSG_FLUSH,
+ VENC_MSG_START,
+ VENC_MSG_STOP,
+ VENC_MSG_PAUSE,
+ VENC_MSG_RESUME,
+ VENC_MSG_STOP_READING_MSG
+};
+
+enum venc_error_code {
+ VENC_S_SUCCESS,
+ VENC_S_EFAIL,
+ VENC_S_EFATAL,
+ VENC_S_EBADPARAM,
+ VENC_S_EINVALSTATE,
+ VENC_S_ENOSWRES,
+ VENC_S_ENOHWRES,
+ VENC_S_EBUFFREQ,
+ VENC_S_EINVALCMD,
+ VENC_S_ETIMEOUT,
+ VENC_S_ENOREATMPT,
+ VENC_S_ENOPREREQ,
+ VENC_S_ECMDQFULL,
+ VENC_S_ENOTSUPP,
+ VENC_S_ENOTIMPL,
+ VENC_S_ENOTPMEM,
+ VENC_S_EFLUSHED,
+ VENC_S_EINSUFBUF,
+ VENC_S_ESAMESTATE,
+ VENC_S_EINVALTRANS
+};
+
+enum venc_mem_region_enum {
+ VENC_PMEM_EBI1,
+ VENC_PMEM_SMI
+};
+
+struct venc_buf_type {
+ unsigned int region;
+ unsigned int phys;
+ unsigned int size;
+ int offset;
+};
+
+struct venc_qp_range {
+ unsigned int min_qp;
+ unsigned int max_qp;
+};
+
+struct venc_frame_rate {
+ unsigned int frame_rate_num;
+ unsigned int frame_rate_den;
+};
+
+struct venc_slice_info {
+ unsigned int slice_mode;
+ unsigned int units_per_slice;
+};
+
+struct venc_extra_data {
+ unsigned int slice_extra_data_flag;
+ unsigned int slice_client_data1;
+ unsigned int slice_client_data2;
+ unsigned int slice_client_data3;
+ unsigned int none_extra_data_flag;
+ unsigned int none_client_data1;
+ unsigned int none_client_data2;
+ unsigned int none_client_data3;
+};
+
+struct venc_common_config {
+ unsigned int standard;
+ unsigned int input_frame_height;
+ unsigned int input_frame_width;
+ unsigned int output_frame_height;
+ unsigned int output_frame_width;
+ unsigned int rotation_angle;
+ unsigned int intra_period;
+ unsigned int rate_control;
+ struct venc_frame_rate frame_rate;
+ unsigned int bitrate;
+ struct venc_qp_range qp_range;
+ unsigned int iframe_qp;
+ unsigned int pframe_qp;
+ struct venc_slice_info slice_config;
+ struct venc_extra_data extra_data;
+};
+
+struct venc_nonio_buf_config {
+ struct venc_buf_type recon_buf1;
+ struct venc_buf_type recon_buf2;
+ struct venc_buf_type wb_buf;
+ struct venc_buf_type cmd_buf;
+ struct venc_buf_type vlc_buf;
+};
+
+struct venc_mpeg4_config {
+ unsigned int profile;
+ unsigned int level;
+ unsigned int time_resolution;
+ unsigned int ac_prediction;
+ unsigned int hec_interval;
+ unsigned int data_partition;
+ unsigned int short_header;
+ unsigned int rvlc_enable;
+};
+
+struct venc_h263_config {
+ unsigned int profile;
+ unsigned int level;
+};
+
+struct venc_h264_config {
+ unsigned int profile;
+ unsigned int level;
+ unsigned int max_nal;
+ unsigned int idr_period;
+};
+
+struct venc_pmem {
+ int src;
  int fd;
- unsigned long offset;
- unsigned long size;
+ unsigned int offset;
+ void *virt;
+ void *phys;
+ unsigned int size;
 };
 
-struct q6_init_config {
- unsigned short venc_standard;
- unsigned short partial_run_length_flag;
- unsigned short h263_annex_ispt;
- unsigned short h263_annex_jspt;
- unsigned short h263_annex_tspt;
- unsigned short rc_flag;
- unsigned short one_mv_flag;
- unsigned short acdc_pred_enable;
- unsigned short rounding_bit_ctrl;
- unsigned short rotation_flag;
- unsigned short max_mvx;
- unsigned short max_mvy;
- unsigned short enc_frame_height_inmb;
- unsigned short enc_frame_width_inmb;
- unsigned short dvs_frame_height;
- unsigned short dvs_frame_width;
+struct venc_buffer {
+ unsigned char *ptr_buffer;
+ unsigned int size;
+ unsigned int len;
+ unsigned int offset;
+ long long time_stamp;
+ unsigned int flags;
+ unsigned int client_data;
 
- unsigned int ref_frame_buf1_phy;
- unsigned int ref_frame_buf2_phy;
- unsigned int rlc_buf1_phy;
- unsigned int rlc_buf2_phy;
- unsigned int rlc_buf_length;
 };
 
-struct init_config {
- struct venc_buf ref_frame_buf1;
- struct venc_buf ref_frame_buf2;
- struct venc_buf rlc_buf1;
- struct venc_buf rlc_buf2;
- struct q6_init_config q6_init_config;
+struct venc_buffers {
+ struct venc_pmem recon_buf[VENC_MAX_RECON_BUFFERS];
+ struct venc_pmem wb_buf;
+ struct venc_pmem cmd_buf;
+ struct venc_pmem vlc_buf;
 };
 
-struct q6_encode_param {
- unsigned int luma_addr;
- unsigned int chroma_addr;
- unsigned int x_offset;
- unsigned int y_offset;
- unsigned int frame_rho_budget;
- unsigned int frame_type;
- unsigned int qp;
+struct venc_buffer_flush {
+ unsigned int flush_mode;
 };
 
-struct encode_param {
- struct venc_buf y_addr;
- unsigned long uv_offset;
- struct q6_encode_param q6_encode_param;
+union venc_msg_data {
+ struct venc_buffer buf;
+ struct venc_buffer_flush flush_ret;
+
 };
 
-struct intra_refresh {
- unsigned int intra_refresh_enable;
- unsigned int intra_mb_num;
+struct venc_msg {
+ unsigned int status_code;
+ unsigned int msg_code;
+ union venc_msg_data msg_data;
+ unsigned int msg_data_size;
 };
 
-struct rc_config {
- unsigned short max_frame_qp_up_delta;
- unsigned short max_frame_qp_down_delta;
- unsigned short min_frame_qp;
- unsigned short max_frame_qp;
+union venc_codec_config {
+ struct venc_mpeg4_config mpeg4_params;
+ struct venc_h263_config h263_params;
+ struct venc_h264_config h264_params;
 };
 
-struct q6_frame_type {
- unsigned int frame_type;
- unsigned int frame_len;
- unsigned int frame_addr;
- unsigned int map_table;
+struct venc_q6_config {
+ struct venc_common_config config_params;
+ union venc_codec_config codec_params;
+ struct venc_nonio_buf_config buf_params;
+ void *callback_event;
 };
 
-struct frame_type {
- struct venc_buf frame_addr;
- struct q6_frame_type q6_frame_type;
+struct venc_hdr_config {
+ struct venc_common_config config_params;
+ union venc_codec_config codec_params;
+};
+
+struct venc_init_config {
+ struct venc_q6_config q6_config;
+ struct venc_buffers q6_bufs;
+};
+
+struct venc_seq_config {
+ int size;
+ struct venc_pmem buf;
+ struct venc_q6_config q6_config;
 };
 
 #define VENC_IOCTL_MAGIC 'V'
 
-#define VENC_IOCTL_INITIALIZE _IOW(VENC_IOCTL_MAGIC, 1, struct init_config)
-#define VENC_IOCTL_ENCODE _IOW(VENC_IOCTL_MAGIC, 2, struct encode_param)
-#define VENC_IOCTL_INTRA_REFRESH _IOW(VENC_IOCTL_MAGIC, 3, struct intra_refresh)
-#define VENC_IOCTL_RC_CONFIG _IOW(VENC_IOCTL_MAGIC, 4, struct rc_config)
-#define VENC_IOCTL_ENCODE_CONFIG _IOW(VENC_IOCTL_MAGIC, 5, struct init_config)
-#define VENC_IOCTL_STOP _IO(VENC_IOCTL_MAGIC, 6)
-#define VENC_IOCTL_WAIT_FOR_ENCODE _IOR(VENC_IOCTL_MAGIC, 7, struct frame_type)
-#define VENC_IOCTL_STOP_ENCODE _IO(VENC_IOCTL_MAGIC, 8)
+#define VENC_IOCTL_CMD_READ_NEXT_MSG   _IOWR(VENC_IOCTL_MAGIC, 1, struct venc_msg)
+
+#define VENC_IOCTL_CMD_STOP_READ_MSG _IO(VENC_IOCTL_MAGIC, 2)
+
+#define VENC_IOCTL_SET_INPUT_BUFFER   _IOW(VENC_IOCTL_MAGIC, 3, struct venc_pmem)
+
+#define VENC_IOCTL_SET_OUTPUT_BUFFER   _IOW(VENC_IOCTL_MAGIC, 4, struct venc_pmem)
+
+#define VENC_IOCTL_CMD_START _IOW(VENC_IOCTL_MAGIC, 5, struct venc_init_config)
+
+#define VENC_IOCTL_CMD_ENCODE_FRAME   _IOW(VENC_IOCTL_MAGIC, 6, struct venc_buffer)
+
+#define VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER   _IOW(VENC_IOCTL_MAGIC, 7, struct venc_buffer)
+
+#define VENC_IOCTL_CMD_FLUSH   _IOW(VENC_IOCTL_MAGIC, 8, struct venc_buffer_flush)
+
+#define VENC_IOCTL_CMD_PAUSE _IO(VENC_IOCTL_MAGIC, 9)
+
+#define VENC_IOCTL_CMD_RESUME _IO(VENC_IOCTL_MAGIC, 10)
+
+#define VENC_IOCTL_CMD_STOP _IO(VENC_IOCTL_MAGIC, 11)
+
+#define VENC_IOCTL_SET_INTRA_PERIOD   _IOW(VENC_IOCTL_MAGIC, 12, int)
+
+#define VENC_IOCTL_CMD_REQUEST_IFRAME _IO(VENC_IOCTL_MAGIC, 13)
+
+#define VENC_IOCTL_GET_SEQUENCE_HDR   _IOWR(VENC_IOCTL_MAGIC, 14, struct venc_seq_config)
+
+#define VENC_IOCTL_SET_INTRA_REFRESH   _IOW(VENC_IOCTL_MAGIC, 15, int)
+
+#define VENC_IOCTL_SET_FRAME_RATE   _IOW(VENC_IOCTL_MAGIC, 16, struct venc_frame_rate)
+
+#define VENC_IOCTL_SET_TARGET_BITRATE   _IOW(VENC_IOCTL_MAGIC, 17, int)
+
+#define VENC_IOCTL_SET_QP_RANGE   _IOW(VENC_IOCTL_MAGIC, 18, struct venc_qp_range)
 
 #endif
-
diff --git a/libc/kernel/common/linux/neighbour.h b/libc/kernel/common/linux/neighbour.h
new file mode 100644
index 0000000..2189af0
--- /dev/null
+++ b/libc/kernel/common/linux/neighbour.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   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.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef __LINUX_NEIGHBOUR_H
+#define __LINUX_NEIGHBOUR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ndmsg
+{
+ __u8 ndm_family;
+ __u8 ndm_pad1;
+ __u16 ndm_pad2;
+ __s32 ndm_ifindex;
+ __u16 ndm_state;
+ __u8 ndm_flags;
+ __u8 ndm_type;
+};
+
+enum
+{
+ NDA_UNSPEC,
+ NDA_DST,
+ NDA_LLADDR,
+ NDA_CACHEINFO,
+ NDA_PROBES,
+ __NDA_MAX
+};
+
+#define NDA_MAX (__NDA_MAX - 1)
+
+#define NTF_USE 0x01
+#define NTF_PROXY 0x08  
+#define NTF_ROUTER 0x80
+
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE 0x02
+#define NUD_STALE 0x04
+#define NUD_DELAY 0x08
+#define NUD_PROBE 0x10
+#define NUD_FAILED 0x20
+
+#define NUD_NOARP 0x40
+#define NUD_PERMANENT 0x80
+#define NUD_NONE 0x00
+
+struct nda_cacheinfo
+{
+ __u32 ndm_confirmed;
+ __u32 ndm_used;
+ __u32 ndm_updated;
+ __u32 ndm_refcnt;
+};
+
+struct ndt_stats
+{
+ __u64 ndts_allocs;
+ __u64 ndts_destroys;
+ __u64 ndts_hash_grows;
+ __u64 ndts_res_failed;
+ __u64 ndts_lookups;
+ __u64 ndts_hits;
+ __u64 ndts_rcv_probes_mcast;
+ __u64 ndts_rcv_probes_ucast;
+ __u64 ndts_periodic_gc_runs;
+ __u64 ndts_forced_gc_runs;
+};
+
+enum {
+ NDTPA_UNSPEC,
+ NDTPA_IFINDEX,
+ NDTPA_REFCNT,
+ NDTPA_REACHABLE_TIME,
+ NDTPA_BASE_REACHABLE_TIME,
+ NDTPA_RETRANS_TIME,
+ NDTPA_GC_STALETIME,
+ NDTPA_DELAY_PROBE_TIME,
+ NDTPA_QUEUE_LEN,
+ NDTPA_APP_PROBES,
+ NDTPA_UCAST_PROBES,
+ NDTPA_MCAST_PROBES,
+ NDTPA_ANYCAST_DELAY,
+ NDTPA_PROXY_DELAY,
+ NDTPA_PROXY_QLEN,
+ NDTPA_LOCKTIME,
+ __NDTPA_MAX
+};
+#define NDTPA_MAX (__NDTPA_MAX - 1)
+
+struct ndtmsg
+{
+ __u8 ndtm_family;
+ __u8 ndtm_pad1;
+ __u16 ndtm_pad2;
+};
+
+struct ndt_config
+{
+ __u16 ndtc_key_len;
+ __u16 ndtc_entry_size;
+ __u32 ndtc_entries;
+ __u32 ndtc_last_flush;
+ __u32 ndtc_last_rand;
+ __u32 ndtc_hash_rnd;
+ __u32 ndtc_hash_mask;
+ __u32 ndtc_hash_chain_gc;
+ __u32 ndtc_proxy_qlen;
+};
+
+enum {
+ NDTA_UNSPEC,
+ NDTA_NAME,
+ NDTA_THRESH1,
+ NDTA_THRESH2,
+ NDTA_THRESH3,
+ NDTA_CONFIG,
+ NDTA_PARMS,
+ NDTA_STATS,
+ NDTA_GC_INTERVAL,
+ __NDTA_MAX
+};
+#define NDTA_MAX (__NDTA_MAX - 1)
+
+#endif
diff --git a/libc/kernel/common/linux/netlink.h b/libc/kernel/common/linux/netlink.h
index b6f1c06..75e889a 100644
--- a/libc/kernel/common/linux/netlink.h
+++ b/libc/kernel/common/linux/netlink.h
@@ -33,8 +33,13 @@
 #define NETLINK_KOBJECT_UEVENT 15  
 #define NETLINK_GENERIC 16
 
+#define NETLINK_SCSITRANSPORT 18  
+#define NETLINK_ECRYPTFS 19
+
 #define MAX_LINKS 32 
 
+struct net;
+
 struct sockaddr_nl
 {
  sa_family_t nl_family;
@@ -93,6 +98,8 @@
 #define NETLINK_ADD_MEMBERSHIP 1
 #define NETLINK_DROP_MEMBERSHIP 2
 #define NETLINK_PKTINFO 3
+#define NETLINK_BROADCAST_ERROR 4
+#define NETLINK_NO_ENOBUFS 5
 
 struct nl_pktinfo
 {
@@ -112,6 +119,10 @@
  __u16 nla_type;
 };
 
+#define NLA_F_NESTED (1 << 15)
+#define NLA_F_NET_BYTEORDER (1 << 14)
+#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
 #define NLA_ALIGNTO 4
 #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
 #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
diff --git a/libc/kernel/common/linux/pkt_cls.h b/libc/kernel/common/linux/pkt_cls.h
index 601a683..ffa29f7 100644
--- a/libc/kernel/common/linux/pkt_cls.h
+++ b/libc/kernel/common/linux/pkt_cls.h
@@ -12,6 +12,7 @@
 #ifndef __LINUX_PKT_CLS_H
 #define __LINUX_PKT_CLS_H
 
+#include <linux/types.h>
 #include <linux/pkt_sched.h>
 
 #define _TC_MAKE32(x) ((x))
@@ -179,8 +180,8 @@
 
 struct tc_u32_key
 {
- __u32 mask;
- __u32 val;
+ __be32 mask;
+ __be32 val;
  int off;
  int offmask;
 };
@@ -191,12 +192,12 @@
  unsigned char offshift;
  unsigned char nkeys;
 
- __u16 offmask;
+ __be16 offmask;
  __u16 off;
  short offoff;
 
  short hoff;
- __u32 hmask;
+ __be32 hmask;
  struct tc_u32_key keys[0];
 };
 
@@ -273,6 +274,7 @@
  TCA_FW_POLICE,
  TCA_FW_INDEV,
  TCA_FW_ACT,
+ TCA_FW_MASK,
  __TCA_FW_MAX
 };
 
@@ -295,6 +297,56 @@
 
 enum
 {
+ FLOW_KEY_SRC,
+ FLOW_KEY_DST,
+ FLOW_KEY_PROTO,
+ FLOW_KEY_PROTO_SRC,
+ FLOW_KEY_PROTO_DST,
+ FLOW_KEY_IIF,
+ FLOW_KEY_PRIORITY,
+ FLOW_KEY_MARK,
+ FLOW_KEY_NFCT,
+ FLOW_KEY_NFCT_SRC,
+ FLOW_KEY_NFCT_DST,
+ FLOW_KEY_NFCT_PROTO_SRC,
+ FLOW_KEY_NFCT_PROTO_DST,
+ FLOW_KEY_RTCLASSID,
+ FLOW_KEY_SKUID,
+ FLOW_KEY_SKGID,
+ FLOW_KEY_VLAN_TAG,
+ __FLOW_KEY_MAX,
+};
+
+#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1)
+
+enum
+{
+ FLOW_MODE_MAP,
+ FLOW_MODE_HASH,
+};
+
+enum
+{
+ TCA_FLOW_UNSPEC,
+ TCA_FLOW_KEYS,
+ TCA_FLOW_MODE,
+ TCA_FLOW_BASECLASS,
+ TCA_FLOW_RSHIFT,
+ TCA_FLOW_ADDEND,
+ TCA_FLOW_MASK,
+ TCA_FLOW_XOR,
+ TCA_FLOW_DIVISOR,
+ TCA_FLOW_ACT,
+ TCA_FLOW_POLICE,
+ TCA_FLOW_EMATCHES,
+ TCA_FLOW_PERTURB,
+ __TCA_FLOW_MAX
+};
+
+#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1)
+
+enum
+{
  TCA_BASIC_UNSPEC,
  TCA_BASIC_CLASSID,
  TCA_BASIC_EMATCHES,
@@ -305,6 +357,17 @@
 
 #define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1)
 
+enum
+{
+ TCA_CGROUP_UNSPEC,
+ TCA_CGROUP_ACT,
+ TCA_CGROUP_POLICE,
+ TCA_CGROUP_EMATCHES,
+ __TCA_CGROUP_MAX,
+};
+
+#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
+
 struct tcf_ematch_tree_hdr
 {
  __u16 nmatches;
@@ -346,16 +409,14 @@
 };
 #define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1)
 
-enum
-{
- TCF_EM_CONTAINER,
- TCF_EM_CMP,
- TCF_EM_NBYTE,
- TCF_EM_U32,
- TCF_EM_META,
- TCF_EM_TEXT,
- __TCF_EM_MAX
-};
+#define TCF_EM_CONTAINER 0
+#define TCF_EM_CMP 1
+#define TCF_EM_NBYTE 2
+#define TCF_EM_U32 3
+#define TCF_EM_META 4
+#define TCF_EM_TEXT 5
+#define TCF_EM_VLAN 6
+#define TCF_EM_MAX 6
 
 enum
 {
diff --git a/libc/kernel/common/linux/pkt_sched.h b/libc/kernel/common/linux/pkt_sched.h
index 1e15d83..0b2966a 100644
--- a/libc/kernel/common/linux/pkt_sched.h
+++ b/libc/kernel/common/linux/pkt_sched.h
@@ -12,6 +12,8 @@
 #ifndef __LINUX_PKT_SCHED_H
 #define __LINUX_PKT_SCHED_H
 
+#include <linux/types.h>
+
 #define TC_PRIO_BESTEFFORT 0
 #define TC_PRIO_FILLER 1
 #define TC_PRIO_BULK 2
@@ -53,12 +55,34 @@
 {
  unsigned char cell_log;
  unsigned char __reserved;
- unsigned short feature;
- short addend;
+ unsigned short overhead;
+ short cell_align;
  unsigned short mpu;
  __u32 rate;
 };
 
+#define TC_RTAB_SIZE 1024
+
+struct tc_sizespec {
+ unsigned char cell_log;
+ unsigned char size_log;
+ short cell_align;
+ int overhead;
+ unsigned int linklayer;
+ unsigned int mpu;
+ unsigned int mtu;
+ unsigned int tsize;
+};
+
+enum {
+ TCA_STAB_UNSPEC,
+ TCA_STAB_BASE,
+ TCA_STAB_DATA,
+ __TCA_STAB_MAX
+};
+
+#define TCA_STAB_MAX (__TCA_STAB_MAX - 1)
+
 struct tc_fifo_qopt
 {
  __u32 limit;
@@ -73,6 +97,11 @@
  __u8 priomap[TC_PRIO_MAX+1];
 };
 
+struct tc_multiq_qopt {
+ __u16 bands;
+ __u16 max_bands;
+};
+
 struct tc_tbf_qopt
 {
  struct tc_ratespec rate;
@@ -102,6 +131,11 @@
  unsigned flows;
 };
 
+struct tc_sfq_xstats
+{
+ __s32 allot;
+};
+
 enum
 {
  TCA_RED_UNSPEC,
@@ -402,4 +436,18 @@
 
 #define NETEM_DIST_SCALE 8192
 
+enum
+{
+ TCA_DRR_UNSPEC,
+ TCA_DRR_QUANTUM,
+ __TCA_DRR_MAX
+};
+
+#define TCA_DRR_MAX (__TCA_DRR_MAX - 1)
+
+struct tc_drr_stats
+{
+ __u32 deficit;
+};
+
 #endif
diff --git a/libc/kernel/common/linux/rtnetlink.h b/libc/kernel/common/linux/rtnetlink.h
index ddcffaa..e305505 100644
--- a/libc/kernel/common/linux/rtnetlink.h
+++ b/libc/kernel/common/linux/rtnetlink.h
@@ -12,7 +12,11 @@
 #ifndef __LINUX_RTNETLINK_H
 #define __LINUX_RTNETLINK_H
 
+#include <linux/types.h>
 #include <linux/netlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
 
 enum {
  RTM_BASE = 16,
@@ -85,8 +89,6 @@
 
  RTM_NEWPREFIX = 52,
 #define RTM_NEWPREFIX RTM_NEWPREFIX
- RTM_GETPREFIX = 54,
-#define RTM_GETPREFIX RTM_GETPREFIX
 
  RTM_GETMULTICAST = 58,
 #define RTM_GETMULTICAST RTM_GETMULTICAST
@@ -101,6 +103,21 @@
  RTM_SETNEIGHTBL,
 #define RTM_SETNEIGHTBL RTM_SETNEIGHTBL
 
+ RTM_NEWNDUSEROPT = 68,
+#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT
+
+ RTM_NEWADDRLABEL = 72,
+#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL
+ RTM_DELADDRLABEL,
+#define RTM_DELADDRLABEL RTM_DELADDRLABEL
+ RTM_GETADDRLABEL,
+#define RTM_GETADDRLABEL RTM_GETADDRLABEL
+
+ RTM_GETDCB = 78,
+#define RTM_GETDCB RTM_GETDCB
+ RTM_SETDCB,
+#define RTM_SETDCB RTM_SETDCB
+
  __RTM_MAX,
 #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
 };
@@ -172,6 +189,7 @@
 #define RTPROT_DNROUTED 13  
 #define RTPROT_XORP 14  
 #define RTPROT_NTK 15  
+#define RTPROT_DHCP 16  
 
 enum rt_scope_t
 {
@@ -192,12 +210,12 @@
 {
  RT_TABLE_UNSPEC=0,
 
+ RT_TABLE_COMPAT=252,
  RT_TABLE_DEFAULT=253,
  RT_TABLE_MAIN=254,
  RT_TABLE_LOCAL=255,
- __RT_TABLE_MAX
+ RT_TABLE_MAX=0xFFFFFFFF
 };
-#define RT_TABLE_MAX (__RT_TABLE_MAX - 1)
 
 enum rtattr_type_t
 {
@@ -216,6 +234,7 @@
  RTA_CACHEINFO,
  RTA_SESSION,
  RTA_MP_ALGO,
+ RTA_TABLE,
  __RTA_MAX
 };
 
@@ -286,6 +305,8 @@
 #define RTAX_INITCWND RTAX_INITCWND
  RTAX_FEATURES,
 #define RTAX_FEATURES RTAX_FEATURES
+ RTAX_RTO_MIN,
+#define RTAX_RTO_MIN RTAX_RTO_MIN
  __RTAX_MAX
 };
 
@@ -318,168 +339,6 @@
  } u;
 };
 
-struct ifaddrmsg
-{
- unsigned char ifa_family;
- unsigned char ifa_prefixlen;
- unsigned char ifa_flags;
- unsigned char ifa_scope;
- int ifa_index;
-};
-
-enum
-{
- IFA_UNSPEC,
- IFA_ADDRESS,
- IFA_LOCAL,
- IFA_LABEL,
- IFA_BROADCAST,
- IFA_ANYCAST,
- IFA_CACHEINFO,
- IFA_MULTICAST,
- __IFA_MAX
-};
-
-#define IFA_MAX (__IFA_MAX - 1)
-
-#define IFA_F_SECONDARY 0x01
-#define IFA_F_TEMPORARY IFA_F_SECONDARY
-
-#define IFA_F_DEPRECATED 0x20
-#define IFA_F_TENTATIVE 0x40
-#define IFA_F_PERMANENT 0x80
-
-struct ifa_cacheinfo
-{
- __u32 ifa_prefered;
- __u32 ifa_valid;
- __u32 cstamp;
- __u32 tstamp;
-};
-
-#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
-#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
-
-struct ndmsg
-{
- unsigned char ndm_family;
- unsigned char ndm_pad1;
- unsigned short ndm_pad2;
- int ndm_ifindex;
- __u16 ndm_state;
- __u8 ndm_flags;
- __u8 ndm_type;
-};
-
-enum
-{
- NDA_UNSPEC,
- NDA_DST,
- NDA_LLADDR,
- NDA_CACHEINFO,
- NDA_PROBES,
- __NDA_MAX
-};
-
-#define NDA_MAX (__NDA_MAX - 1)
-
-#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
-#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
-
-#define NTF_PROXY 0x08  
-#define NTF_ROUTER 0x80
-
-#define NUD_INCOMPLETE 0x01
-#define NUD_REACHABLE 0x02
-#define NUD_STALE 0x04
-#define NUD_DELAY 0x08
-#define NUD_PROBE 0x10
-#define NUD_FAILED 0x20
-
-#define NUD_NOARP 0x40
-#define NUD_PERMANENT 0x80
-#define NUD_NONE 0x00
-
-struct nda_cacheinfo
-{
- __u32 ndm_confirmed;
- __u32 ndm_used;
- __u32 ndm_updated;
- __u32 ndm_refcnt;
-};
-
-struct ndt_stats
-{
- __u64 ndts_allocs;
- __u64 ndts_destroys;
- __u64 ndts_hash_grows;
- __u64 ndts_res_failed;
- __u64 ndts_lookups;
- __u64 ndts_hits;
- __u64 ndts_rcv_probes_mcast;
- __u64 ndts_rcv_probes_ucast;
- __u64 ndts_periodic_gc_runs;
- __u64 ndts_forced_gc_runs;
-};
-
-enum {
- NDTPA_UNSPEC,
- NDTPA_IFINDEX,
- NDTPA_REFCNT,
- NDTPA_REACHABLE_TIME,
- NDTPA_BASE_REACHABLE_TIME,
- NDTPA_RETRANS_TIME,
- NDTPA_GC_STALETIME,
- NDTPA_DELAY_PROBE_TIME,
- NDTPA_QUEUE_LEN,
- NDTPA_APP_PROBES,
- NDTPA_UCAST_PROBES,
- NDTPA_MCAST_PROBES,
- NDTPA_ANYCAST_DELAY,
- NDTPA_PROXY_DELAY,
- NDTPA_PROXY_QLEN,
- NDTPA_LOCKTIME,
- __NDTPA_MAX
-};
-#define NDTPA_MAX (__NDTPA_MAX - 1)
-
-struct ndtmsg
-{
- __u8 ndtm_family;
- __u8 ndtm_pad1;
- __u16 ndtm_pad2;
-};
-
-struct ndt_config
-{
- __u16 ndtc_key_len;
- __u16 ndtc_entry_size;
- __u32 ndtc_entries;
- __u32 ndtc_last_flush;
- __u32 ndtc_last_rand;
- __u32 ndtc_hash_rnd;
- __u32 ndtc_hash_mask;
- __u32 ndtc_hash_chain_gc;
- __u32 ndtc_proxy_qlen;
-};
-
-enum {
- NDTA_UNSPEC,
- NDTA_NAME,
- NDTA_THRESH1,
- NDTA_THRESH2,
- NDTA_THRESH3,
- NDTA_CONFIG,
- NDTA_PARMS,
- NDTA_STATS,
- NDTA_GC_INTERVAL,
- __NDTA_MAX
-};
-#define NDTA_MAX (__NDTA_MAX - 1)
-
-#define NDTA_RTA(r) ((struct rtattr*)(((char*)(r)) +   NLMSG_ALIGN(sizeof(struct ndtmsg))))
-#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
-
 struct rtgenmsg
 {
  unsigned char rtgen_family;
@@ -523,103 +382,6 @@
  __u32 valid_time;
 };
 
-struct rtnl_link_stats
-{
- __u32 rx_packets;
- __u32 tx_packets;
- __u32 rx_bytes;
- __u32 tx_bytes;
- __u32 rx_errors;
- __u32 tx_errors;
- __u32 rx_dropped;
- __u32 tx_dropped;
- __u32 multicast;
- __u32 collisions;
-
- __u32 rx_length_errors;
- __u32 rx_over_errors;
- __u32 rx_crc_errors;
- __u32 rx_frame_errors;
- __u32 rx_fifo_errors;
- __u32 rx_missed_errors;
-
- __u32 tx_aborted_errors;
- __u32 tx_carrier_errors;
- __u32 tx_fifo_errors;
- __u32 tx_heartbeat_errors;
- __u32 tx_window_errors;
-
- __u32 rx_compressed;
- __u32 tx_compressed;
-};
-
-struct rtnl_link_ifmap
-{
- __u64 mem_start;
- __u64 mem_end;
- __u64 base_addr;
- __u16 irq;
- __u8 dma;
- __u8 port;
-};
-
-enum
-{
- IFLA_UNSPEC,
- IFLA_ADDRESS,
- IFLA_BROADCAST,
- IFLA_IFNAME,
- IFLA_MTU,
- IFLA_LINK,
- IFLA_QDISC,
- IFLA_STATS,
- IFLA_COST,
-#define IFLA_COST IFLA_COST
- IFLA_PRIORITY,
-#define IFLA_PRIORITY IFLA_PRIORITY
- IFLA_MASTER,
-#define IFLA_MASTER IFLA_MASTER
- IFLA_WIRELESS,
-#define IFLA_WIRELESS IFLA_WIRELESS
- IFLA_PROTINFO,
-#define IFLA_PROTINFO IFLA_PROTINFO
- IFLA_TXQLEN,
-#define IFLA_TXQLEN IFLA_TXQLEN
- IFLA_MAP,
-#define IFLA_MAP IFLA_MAP
- IFLA_WEIGHT,
-#define IFLA_WEIGHT IFLA_WEIGHT
- IFLA_OPERSTATE,
- IFLA_LINKMODE,
- __IFLA_MAX
-};
-
-#define IFLA_MAX (__IFLA_MAX - 1)
-
-#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
-#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
-
-enum
-{
- IFLA_INET6_UNSPEC,
- IFLA_INET6_FLAGS,
- IFLA_INET6_CONF,
- IFLA_INET6_STATS,
- IFLA_INET6_MCAST,
- IFLA_INET6_CACHEINFO,
- __IFLA_INET6_MAX
-};
-
-#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
-
-struct ifla_cacheinfo
-{
- __u32 max_reasm_len;
- __u32 tstamp;
- __u32 reachable_time;
- __u32 retrans_time;
-};
-
 struct tcmsg
 {
  unsigned char tcm_family;
@@ -641,6 +403,7 @@
  TCA_RATE,
  TCA_FCNT,
  TCA_STATS2,
+ TCA_STAB,
  __TCA_MAX
 };
 
@@ -649,6 +412,28 @@
 #define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
 #define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
 
+struct nduseroptmsg
+{
+ unsigned char nduseropt_family;
+ unsigned char nduseropt_pad1;
+ unsigned short nduseropt_opts_len;
+ int nduseropt_ifindex;
+ __u8 nduseropt_icmp_type;
+ __u8 nduseropt_icmp_code;
+ unsigned short nduseropt_pad2;
+ unsigned int nduseropt_pad3;
+
+};
+
+enum
+{
+ NDUSEROPT_UNSPEC,
+ NDUSEROPT_SRCADDR,
+ __NDUSEROPT_MAX
+};
+
+#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1)
+
 #define RTMGRP_LINK 1
 #define RTMGRP_NOTIFY 2
 #define RTMGRP_NEIGH 4
@@ -701,10 +486,19 @@
  RTNLGRP_NOP2,
  RTNLGRP_DECnet_ROUTE,
 #define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE
- RTNLGRP_NOP3,
+ RTNLGRP_DECnet_RULE,
+#define RTNLGRP_DECnet_RULE RTNLGRP_DECnet_RULE
  RTNLGRP_NOP4,
  RTNLGRP_IPV6_PREFIX,
 #define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX
+ RTNLGRP_IPV6_RULE,
+#define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE
+ RTNLGRP_ND_USEROPT,
+#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT
+ RTNLGRP_PHONET_IFADDR,
+#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
+ RTNLGRP_PHONET_ROUTE,
+#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
  __RTNLGRP_MAX
 };
 #define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
diff --git a/libc/kernel/common/linux/swab.h b/libc/kernel/common/linux/swab.h
new file mode 100644
index 0000000..8f7d0d6
--- /dev/null
+++ b/libc/kernel/common/linux/swab.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   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.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _LINUX_SWAB_H
+#define _LINUX_SWAB_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <asm/swab.h>
+
+#define ___constant_swab16(x) ((__u16)(   (((__u16)(x) & (__u16)0x00ffU) << 8) |   (((__u16)(x) & (__u16)0xff00U) >> 8)))
+
+#define ___constant_swab32(x) ((__u32)(   (((__u32)(x) & (__u32)0x000000ffUL) << 24) |   (((__u32)(x) & (__u32)0x0000ff00UL) << 8) |   (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) |   (((__u32)(x) & (__u32)0xff000000UL) >> 24)))
+
+#define ___constant_swab64(x) ((__u64)(   (((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) |   (((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) |   (((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) |   (((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) |   (((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) |   (((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) |   (((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) |   (((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56)))
+
+#define ___constant_swahw32(x) ((__u32)(   (((__u32)(x) & (__u32)0x0000ffffUL) << 16) |   (((__u32)(x) & (__u32)0xffff0000UL) >> 16)))
+
+#define ___constant_swahb32(x) ((__u32)(   (((__u32)(x) & (__u32)0x00ff00ffUL) << 8) |   (((__u32)(x) & (__u32)0xff00ff00UL) >> 8)))
+
+#ifdef __arch_swab16
+#else
+#endif
+#ifdef __arch_swab32
+#else
+#endif
+#ifdef __arch_swab64
+#elif defined(__SWAB_64_THRU_32__)
+#else
+#endif
+#ifdef __arch_swahw32
+#else
+#endif
+#ifdef __arch_swahb32
+#else
+#endif
+#define __swab16(x)   (__builtin_constant_p((__u16)(x)) ?   ___constant_swab16(x) :   __fswab16(x))
+#define __swab32(x)   (__builtin_constant_p((__u32)(x)) ?   ___constant_swab32(x) :   __fswab32(x))
+#define __swab64(x)   (__builtin_constant_p((__u64)(x)) ?   ___constant_swab64(x) :   __fswab64(x))
+#define __swahw32(x)   (__builtin_constant_p((__u32)(x)) ?   ___constant_swahw32(x) :   __fswahw32(x))
+#define __swahb32(x)   (__builtin_constant_p((__u32)(x)) ?   ___constant_swahb32(x) :   __fswahb32(x))
+#ifdef __arch_swab16p
+#else
+#endif
+#ifdef __arch_swab32p
+#else
+#endif
+#ifdef __arch_swab64p
+#else
+#endif
+#ifdef __arch_swahw32p
+#else
+#endif
+#ifdef __arch_swahb32p
+#else
+#endif
+#ifdef __arch_swab16s
+#else
+#endif
+#ifdef __arch_swab32s
+#else
+#endif
+#ifdef __arch_swab64s
+#else
+#endif
+#ifdef __arch_swahw32s
+#else
+#endif
+#ifdef __arch_swahb32s
+#else
+#endif
+#endif
diff --git a/libc/kernel/common/media/msm_camera.h b/libc/kernel/common/media/msm_camera.h
index a0b4a24..da3951b 100644
--- a/libc/kernel/common/media/msm_camera.h
+++ b/libc/kernel/common/media/msm_camera.h
@@ -70,6 +70,8 @@
 
 #define MSM_CAM_IOCTL_CTRL_COMMAND_2   _IOW(MSM_CAM_IOCTL_MAGIC, 24, struct msm_ctrl_cmd *)
 
+#define MSM_CAM_IOCTL_ENABLE_OUTPUT_IND   _IOW(MSM_CAM_IOCTL_MAGIC, 25, uint32_t *)
+
 #define MAX_SENSOR_NUM 3
 #define MAX_SENSOR_NAME 32
 
@@ -178,7 +180,7 @@
  uint32_t len;
  uint32_t y_off;
  uint32_t cbcr_off;
- uint8_t active;
+ uint8_t vfe_can_write;
 };
 
 struct outputCfg {
diff --git a/libc/netbsd/net/getaddrinfo.c b/libc/netbsd/net/getaddrinfo.c
index 1233cb8..51079ae 100644
--- a/libc/netbsd/net/getaddrinfo.c
+++ b/libc/netbsd/net/getaddrinfo.c
@@ -217,7 +217,6 @@
 
 static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
 	const struct addrinfo *);
-static void aisort(struct addrinfo *s, res_state res);
 static int _dns_getaddrinfo(void *, void *, va_list);
 static void _sethtent(FILE **);
 static void _endhtent(FILE **);
@@ -942,7 +941,7 @@
 		allownumeric = 1;
 		break;
 	case ANY:
-#if 1  /* ANDROID-SPECIFIC CHANGE TO MATCH GLIBC */	
+#if 1  /* ANDROID-SPECIFIC CHANGE TO MATCH GLIBC */
 		allownumeric = 1;
 #else
 		allownumeric = 0;
@@ -1259,35 +1258,366 @@
 	return NULL;
 }
 
-#define SORTEDADDR(p)	(((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr)
-#define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr)
+struct addrinfo_sort_elem {
+	struct addrinfo *ai;
+	int has_src_addr;
+	struct sockaddr_in6 src_addr;  /* Large enough to hold IPv4 or IPv6. */
+	int original_order;
+};
 
-static void
-aisort(struct addrinfo *s, res_state res)
+/*ARGSUSED*/
+static int
+_get_scope(const struct sockaddr *addr)
 {
-	struct addrinfo head, *t, *p;
-	int i;
+	if (addr->sa_family == AF_INET6) {
+		const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
+		if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)) {
+			return IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr);
+		} else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) ||
+			   IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) {
+			/*
+			 * RFC 4291 section 2.5.3 says loopback is to be treated as having
+			 * link-local scope.
+			 */
+			return IPV6_ADDR_SCOPE_LINKLOCAL;
+		} else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) {
+			return IPV6_ADDR_SCOPE_SITELOCAL;
+		} else {
+			return IPV6_ADDR_SCOPE_GLOBAL;
+		}
+	} else if (addr->sa_family == AF_INET) {
+		const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
+		unsigned long int na = ntohl(addr4->sin_addr.s_addr);
 
-	head.ai_next = NULL;
-	t = &head;
+		if (IN_LOOPBACK(na) ||                          /* 127.0.0.0/8 */
+		    (na & 0xffff0000) == 0xa9fe0000) {          /* 169.254.0.0/16 */
+			return IPV6_ADDR_SCOPE_LINKLOCAL;
+		} else if ((na & 0xff000000) == 0x0a000000 ||   /* 10.0.0.0/8 */
+			   (na & 0xfff00000) == 0xac100000 ||   /* 172.16.0.0/12 */
+			   (na & 0xffff0000) == 0xc0a80000) {   /* 192.168.0.0/16 */
+			return IPV6_ADDR_SCOPE_SITELOCAL;
+		} else {
+			return IPV6_ADDR_SCOPE_GLOBAL;
+		}
+	} else {
+		/*
+		 * This should never happen.
+		 * Return a scope with low priority as a last resort.
+		 */
+		return IPV6_ADDR_SCOPE_NODELOCAL;
+	}
+}
 
-	for (i = 0; i < res->nsort; i++) {
-		p = s;
-		while (p->ai_next) {
-			if ((p->ai_next->ai_family != AF_INET)
-			|| SORTMATCH(p, res->sort_list[i])) {
-				t->ai_next = p->ai_next;
-				t = t->ai_next;
-				p->ai_next = p->ai_next->ai_next;
-			} else {
-				p = p->ai_next;
+/* These macros are modelled after the ones in <netinet/in6.h>. */
+
+/* RFC 4380, section 2.6 */
+#define IN6_IS_ADDR_TEREDO(a)	 \
+	((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000)))
+
+/* RFC 3056, section 2. */
+#define IN6_IS_ADDR_6TO4(a)	 \
+	(((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
+
+/*
+ * Get the label for a given IPv4/IPv6 address.
+ * RFC 3484, section 2.1, plus Teredo added in with label 5.
+ */
+
+/*ARGSUSED*/
+static int
+_get_label(const struct sockaddr *addr)
+{
+	if (addr->sa_family == AF_INET) {
+		return 4;
+	} else if (addr->sa_family == AF_INET6) {
+		const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
+		if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
+			return 0;
+		} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
+			return 3;
+		} else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
+			return 5;
+		} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
+			return 2;
+		} else {
+			return 1;
+		}
+	} else {
+		/*
+		 * This should never happen.
+		 * Return a semi-random label as a last resort.
+		 */
+		return 1;
+	}
+}
+
+/*
+ * Get the precedence for a given IPv4/IPv6 address.
+ * RFC 3484, section 2.1, plus Teredo added in with precedence 25.
+ */
+
+/*ARGSUSED*/
+static int
+_get_precedence(const struct sockaddr *addr)
+{
+	if (addr->sa_family == AF_INET) {
+		return 10;
+	} else if (addr->sa_family == AF_INET6) {
+		const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
+		if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
+			return 50;
+		} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
+			return 20;
+		} else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
+			return 25;
+		} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
+			return 30;
+		} else {
+			return 40;
+		}
+	} else {
+		return 5;
+	}
+}
+
+/*
+ * Find number of matching initial bits between the two addresses a1 and a2.
+ */
+
+/*ARGSUSED*/
+static int
+_common_prefix_len(const struct in6_addr *a1, const struct in6_addr *a2)
+{
+	const char *p1 = (const char *)a1;
+	const char *p2 = (const char *)a2;
+	unsigned i;
+
+	for (i = 0; i < sizeof(*a1); ++i) {
+		int x, j;
+
+		if (p1[i] == p2[i]) {
+			continue;
+		}
+		x = p1[i] ^ p2[i];
+		for (j = 0; j < CHAR_BIT; ++j) {
+			if (x & (1 << (CHAR_BIT - 1))) {
+				return i * CHAR_BIT + j;
 			}
+			x <<= 1;
+		}
+	}
+	return sizeof(*a1) * CHAR_BIT;
+}
+
+/*
+ * Compare two source/destination address pairs.
+ * RFC 3484, section 6.
+ */
+
+/*ARGSUSED*/
+static int
+_rfc3484_compare(const void *ptr1, const void* ptr2)
+{
+	const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1;
+	const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2;
+	int scope_src1, scope_dst1, scope_match1;
+	int scope_src2, scope_dst2, scope_match2;
+	int label_src1, label_dst1, label_match1;
+	int label_src2, label_dst2, label_match2;
+	int precedence1, precedence2;
+	int prefixlen1, prefixlen2;
+
+	/* Rule 1: Avoid unusable destinations. */
+	if (a1->has_src_addr != a2->has_src_addr) {
+		return a2->has_src_addr - a1->has_src_addr;
+	}
+
+	/* Rule 2: Prefer matching scope. */
+	scope_src1 = _get_scope((const struct sockaddr *)&a1->src_addr);
+	scope_dst1 = _get_scope(a1->ai->ai_addr);
+	scope_match1 = (scope_src1 == scope_dst1);
+
+	scope_src2 = _get_scope((const struct sockaddr *)&a2->src_addr);
+	scope_dst2 = _get_scope(a2->ai->ai_addr);
+	scope_match2 = (scope_src2 == scope_dst2);
+
+	if (scope_match1 != scope_match2) {
+		return scope_match2 - scope_match1;
+	}
+
+	/*
+	 * Rule 3: Avoid deprecated addresses.
+	 * TODO(sesse): We don't currently have a good way of finding this.
+	 */
+
+	/*
+	 * Rule 4: Prefer home addresses.
+	 * TODO(sesse): We don't currently have a good way of finding this.
+	 */
+
+	/* Rule 5: Prefer matching label. */
+	label_src1 = _get_label((const struct sockaddr *)&a1->src_addr);
+	label_dst1 = _get_label(a1->ai->ai_addr);
+	label_match1 = (label_src1 == label_dst1);
+
+	label_src2 = _get_label((const struct sockaddr *)&a2->src_addr);
+	label_dst2 = _get_label(a2->ai->ai_addr);
+	label_match2 = (label_src2 == label_dst2);
+
+	if (label_match1 != label_match2) {
+		return label_match2 - label_match1;
+	}
+
+	/* Rule 6: Prefer higher precedence. */
+	precedence1 = _get_precedence(a1->ai->ai_addr);
+	precedence2 = _get_precedence(a2->ai->ai_addr);
+	if (precedence1 != precedence2) {
+		return precedence2 - precedence1;
+	}
+
+	/*
+	 * Rule 7: Prefer native transport.
+	 * TODO(sesse): We don't currently have a good way of finding this.
+	 */
+
+	/* Rule 8: Prefer smaller scope. */
+	if (scope_dst1 != scope_dst2) {
+		return scope_dst1 - scope_dst2;
+	}
+
+	/*
+	 * Rule 9: Use longest matching prefix.
+         * We implement this for IPv6 only, as the rules in RFC 3484 don't seem
+         * to work very well directly applied to IPv4. (glibc uses information from
+         * the routing table for a custom IPv4 implementation here.)
+	 */
+	if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 &&
+	    a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6) {
+		const struct sockaddr_in6 *a1_src = (const struct sockaddr_in6 *)&a1->src_addr;
+		const struct sockaddr_in6 *a1_dst = (const struct sockaddr_in6 *)a1->ai->ai_addr;
+		const struct sockaddr_in6 *a2_src = (const struct sockaddr_in6 *)&a2->src_addr;
+		const struct sockaddr_in6 *a2_dst = (const struct sockaddr_in6 *)a2->ai->ai_addr;
+		prefixlen1 = _common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr);
+		prefixlen2 = _common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr);
+		if (prefixlen1 != prefixlen2) {
+			return prefixlen2 - prefixlen1;
 		}
 	}
 
-	/* add rest of list and reset s to the new list*/
-	t->ai_next = s->ai_next;
-	s->ai_next = head.ai_next;
+	/*
+	 * Rule 10: Leave the order unchanged.
+	 * We need this since qsort() is not necessarily stable.
+	 */
+	return a1->original_order - a2->original_order;
+}
+
+/*
+ * Find the source address that will be used if trying to connect to the given
+ * address. src_addr must be large enough to hold a struct sockaddr_in6.
+ *
+ * Returns 1 if a source address was found, 0 if the address is unreachable,
+ * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are
+ * undefined.
+ */
+
+/*ARGSUSED*/
+static int
+_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr)
+{
+	int sock;
+	int ret;
+	socklen_t len;
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		len = sizeof(struct sockaddr_in);
+		break;
+	case AF_INET6:
+		len = sizeof(struct sockaddr_in6);
+		break;
+	default:
+		/* No known usable source address for non-INET families. */
+		return 0;
+	}
+
+	sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+	if (sock == -1) {
+		if (errno == EAFNOSUPPORT) {
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+
+	do {
+		ret = connect(sock, addr, len);
+	} while (ret == -1 && errno == EINTR);
+
+	if (ret == -1) {
+		close(sock);
+		return 0;
+	}
+
+	if (getsockname(sock, src_addr, &len) == -1) {
+		close(sock);
+		return -1;
+	}
+	close(sock);
+	return 1;
+}
+
+/*
+ * Sort the linked list starting at sentinel->ai_next in RFC3484 order.
+ * Will leave the list unchanged if an error occurs.
+ */
+
+/*ARGSUSED*/
+static void
+_rfc3484_sort(struct addrinfo *list_sentinel)
+{
+	struct addrinfo *cur;
+	int nelem = 0, i;
+	struct addrinfo_sort_elem *elems;
+
+	cur = list_sentinel->ai_next;
+	while (cur) {
+		++nelem;
+		cur = cur->ai_next;
+	}
+
+	elems = (struct addrinfo_sort_elem *)malloc(nelem * sizeof(struct addrinfo_sort_elem));
+	if (elems == NULL) {
+		goto error;
+	}
+
+	/*
+	 * Convert the linked list to an array that also contains the candidate
+	 * source address for each destination address.
+	 */
+	for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next) {
+		int has_src_addr;
+		assert(cur != NULL);
+		elems[i].ai = cur;
+		elems[i].original_order = i;
+
+		has_src_addr = _find_src_addr(cur->ai_addr, (struct sockaddr *)&elems[i].src_addr);
+		if (has_src_addr == -1) {
+			goto error;
+		}
+		elems[i].has_src_addr = has_src_addr;
+	}
+
+	/* Sort the addresses, and rearrange the linked list so it matches the sorted order. */
+	qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem), _rfc3484_compare);
+
+	list_sentinel->ai_next = elems[0].ai;
+	for (i = 0; i < nelem - 1; ++i) {
+		elems[i].ai->ai_next = elems[i + 1].ai;
+	}
+	elems[nelem - 1].ai->ai_next = NULL;
+
+error:
+	free(elems);
 }
 
 /*ARGSUSED*/
@@ -1401,8 +1731,7 @@
 		}
 	}
 
-	if (res->nsort)
-		aisort(&sentinel, res);
+	_rfc3484_sort(&sentinel);
 
 	__res_put_state(res);
 
diff --git a/libc/netbsd/resolv/res_cache.c b/libc/netbsd/resolv/res_cache.c
index 2c912de..2621a7b 100644
--- a/libc/netbsd/resolv/res_cache.c
+++ b/libc/netbsd/resolv/res_cache.c
@@ -251,7 +251,7 @@
         return p;
 
     va_start(args, format);
-    n = snprintf( p, avail, format, args);
+    n = vsnprintf( p, avail, format, args);
     va_end(args);
 
     /* certain C libraries return -1 in case of truncation */
diff --git a/libc/netbsd/resolv/res_init.c b/libc/netbsd/resolv/res_init.c
index 751603d..81e570f 100644
--- a/libc/netbsd/resolv/res_init.c
+++ b/libc/netbsd/resolv/res_init.c
@@ -198,6 +198,8 @@
 		if (pp > statp->dnsrch)
 			return 1;
 	}
+	statp->defdname[0] = '\0';  /* no default domain name on Android */
+	statp->dnsrch[0] = NULL;
 	return 0;
 }
 #endif
@@ -381,7 +383,7 @@
 
 	/* Add the domain search list */
 	havesearch = load_domain_search_list(statp);
-#else /* IGNORE resolv.conf */
+#else /* !ANDROID_CHANGES - IGNORE resolv.conf in Android */
 #define	MATCH(line, name) \
 	(!strncmp(line, name, sizeof(name) - 1) && \
 	(line[sizeof(name) - 1] == ' ' || \
@@ -534,7 +536,7 @@
 	    statp->nsort = nsort;
 	    (void) fclose(fp);
 	}
-#endif /* ANDROID_CHANGES */
+#endif /* !ANDROID_CHANGES */
 /*
  * Last chance to get a nameserver.  This should not normally
  * be necessary
diff --git a/libc/private/arpa_nameser.h b/libc/private/arpa_nameser.h
index 2d2a739..438dc04 100644
--- a/libc/private/arpa_nameser.h
+++ b/libc/private/arpa_nameser.h
@@ -566,4 +566,12 @@
 #include "arpa_nameser_compat.h"
 #endif
 
+#if 0
+#  include <logd.h>
+#  define  XLOG(...)   \
+    __libc_android_log_print(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__)
+#else
+#define  XLOG(...)   do {} while (0)
+#endif
+
 #endif /* !_ARPA_NAMESER_H_ */
diff --git a/libc/regex/cclass.h b/libc/regex/cclass.h
new file mode 100644
index 0000000..d105491
--- /dev/null
+++ b/libc/regex/cclass.h
@@ -0,0 +1,68 @@
+/*	$OpenBSD: cclass.h,v 1.5 2003/06/02 20:18:36 millert Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)cclass.h	8.3 (Berkeley) 3/20/94
+ */
+
+/* character-class table */
+static const struct cclass {
+	char *name;
+	char *chars;
+	char *multis;
+} cclasses[] = {
+	{ "alnum",	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789",				""} ,
+	{ "alpha",	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+					""} ,
+	{ "blank",	" \t",		""} ,
+	{ "cntrl",	"\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\
+\25\26\27\30\31\32\33\34\35\36\37\177",	""} ,
+	{ "digit",	"0123456789",	""} ,
+	{ "graph",	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+					""} ,
+	{ "lower",	"abcdefghijklmnopqrstuvwxyz",
+					""} ,
+	{ "print",	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ",
+					""} ,
+	{ "punct",	"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+					""} ,
+	{ "space",	"\t\n\v\f\r ",	""} ,
+	{ "upper",	"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+					""} ,
+	{ "xdigit",	"0123456789ABCDEFabcdef",
+					""} ,
+	{ NULL,		0,		"" }
+};
diff --git a/libc/regex/cname.h b/libc/regex/cname.h
new file mode 100644
index 0000000..b674b68
--- /dev/null
+++ b/libc/regex/cname.h
@@ -0,0 +1,139 @@
+/*	$OpenBSD: cname.h,v 1.5 2003/06/02 20:18:36 millert Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)cname.h	8.3 (Berkeley) 3/20/94
+ */
+
+/* character-name table */
+static const struct cname {
+	char *name;
+	char code;
+} cnames[] = {
+	{ "NUL",			'\0' },
+	{ "SOH",			'\001' },
+	{ "STX",			'\002' },
+	{ "ETX",			'\003' },
+	{ "EOT",			'\004' },
+	{ "ENQ",			'\005' },
+	{ "ACK",			'\006' },
+	{ "BEL",			'\007' },
+	{ "alert",			'\007' },
+	{ "BS",				'\010' },
+	{ "backspace",			'\b' },
+	{ "HT",				'\011' },
+	{ "tab",			'\t' },
+	{ "LF",				'\012' },
+	{ "newline",			'\n' },
+	{ "VT",				'\013' },
+	{ "vertical-tab",		'\v' },
+	{ "FF",				'\014' },
+	{ "form-feed",			'\f' },
+	{ "CR",				'\015' },
+	{ "carriage-return",		'\r' },
+	{ "SO",				'\016' },
+	{ "SI",				'\017' },
+	{ "DLE",			'\020' },
+	{ "DC1",			'\021' },
+	{ "DC2",			'\022' },
+	{ "DC3",			'\023' },
+	{ "DC4",			'\024' },
+	{ "NAK",			'\025' },
+	{ "SYN",			'\026' },
+	{ "ETB",			'\027' },
+	{ "CAN",			'\030' },
+	{ "EM",				'\031' },
+	{ "SUB",			'\032' },
+	{ "ESC",			'\033' },
+	{ "IS4",			'\034' },
+	{ "FS",				'\034' },
+	{ "IS3",			'\035' },
+	{ "GS",				'\035' },
+	{ "IS2",			'\036' },
+	{ "RS",				'\036' },
+	{ "IS1",			'\037' },
+	{ "US",				'\037' },
+	{ "space",			' ' },
+	{ "exclamation-mark",		'!' },
+	{ "quotation-mark",		'"' },
+	{ "number-sign",		'#' },
+	{ "dollar-sign",		'$' },
+	{ "percent-sign",		'%' },
+	{ "ampersand",			'&' },
+	{ "apostrophe",			'\'' },
+	{ "left-parenthesis",		'(' },
+	{ "right-parenthesis",		')' },
+	{ "asterisk",			'*' },
+	{ "plus-sign",			'+' },
+	{ "comma",			',' },
+	{ "hyphen",			'-' },
+	{ "hyphen-minus",		'-' },
+	{ "period",			'.' },
+	{ "full-stop",			'.' },
+	{ "slash",			'/' },
+	{ "solidus",			'/' },
+	{ "zero",			'0' },
+	{ "one",			'1' },
+	{ "two",			'2' },
+	{ "three",			'3' },
+	{ "four",			'4' },
+	{ "five",			'5' },
+	{ "six",			'6' },
+	{ "seven",			'7' },
+	{ "eight",			'8' },
+	{ "nine",			'9' },
+	{ "colon",			':' },
+	{ "semicolon",			';' },
+	{ "less-than-sign",		'<' },
+	{ "equals-sign",		'=' },
+	{ "greater-than-sign",		'>' },
+	{ "question-mark",		'?' },
+	{ "commercial-at",		'@' },
+	{ "left-square-bracket",	'[' },
+	{ "backslash",			'\\' },
+	{ "reverse-solidus",		'\\' },
+	{ "right-square-bracket",	']' },
+	{ "circumflex",			'^' },
+	{ "circumflex-accent",		'^' },
+	{ "underscore",			'_' },
+	{ "low-line",			'_' },
+	{ "grave-accent",		'`' },
+	{ "left-brace",			'{' },
+	{ "left-curly-bracket",		'{' },
+	{ "vertical-line",		'|' },
+	{ "right-brace",		'}' },
+	{ "right-curly-bracket",	'}' },
+	{ "tilde",			'~' },
+	{ "DEL",			'\177' },
+	{ NULL,				0 }
+};
diff --git a/libc/regex/engine.c b/libc/regex/engine.c
new file mode 100644
index 0000000..66be3c7
--- /dev/null
+++ b/libc/regex/engine.c
@@ -0,0 +1,1021 @@
+/*	$OpenBSD: engine.c,v 1.15 2005/08/05 13:03:00 espie Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)engine.c	8.5 (Berkeley) 3/20/94
+ */
+
+/*
+ * The matching engine and friends.  This file is #included by regexec.c
+ * after suitable #defines of a variety of macros used herein, so that
+ * different state representations can be used without duplicating masses
+ * of code.
+ */
+
+#ifdef SNAMES
+#define	matcher	smatcher
+#define	fast	sfast
+#define	slow	sslow
+#define	dissect	sdissect
+#define	backref	sbackref
+#define	step	sstep
+#define	print	sprint
+#define	at	sat
+#define	match	smat
+#define	nope	snope
+#endif
+#ifdef LNAMES
+#define	matcher	lmatcher
+#define	fast	lfast
+#define	slow	lslow
+#define	dissect	ldissect
+#define	backref	lbackref
+#define	step	lstep
+#define	print	lprint
+#define	at	lat
+#define	match	lmat
+#define	nope	lnope
+#endif
+
+/* another structure passed up and down to avoid zillions of parameters */
+struct match {
+	struct re_guts *g;
+	int eflags;
+	regmatch_t *pmatch;	/* [nsub+1] (0 element unused) */
+	char *offp;		/* offsets work from here */
+	char *beginp;		/* start of string -- virtual NUL precedes */
+	char *endp;		/* end of string -- virtual NUL here */
+	char *coldp;		/* can be no match starting before here */
+	char **lastpos;		/* [nplus+1] */
+	STATEVARS;
+	states st;		/* current states */
+	states fresh;		/* states for a fresh start */
+	states tmp;		/* temporary */
+	states empty;		/* empty set of states */
+};
+
+static int matcher(struct re_guts *, char *, size_t, regmatch_t[], int);
+static char *dissect(struct match *, char *, char *, sopno, sopno);
+static char *backref(struct match *, char *, char *, sopno, sopno, sopno, int);
+static char *fast(struct match *, char *, char *, sopno, sopno);
+static char *slow(struct match *, char *, char *, sopno, sopno);
+static states step(struct re_guts *, sopno, sopno, states, int, states);
+#define MAX_RECURSION	100
+#define	BOL	(OUT+1)
+#define	EOL	(BOL+1)
+#define	BOLEOL	(BOL+2)
+#define	NOTHING	(BOL+3)
+#define	BOW	(BOL+4)
+#define	EOW	(BOL+5)
+#define	CODEMAX	(BOL+5)		/* highest code used */
+#define	NONCHAR(c)	((c) > CHAR_MAX)
+#define	NNONCHAR	(CODEMAX-CHAR_MAX)
+#ifdef REDEBUG
+static void print(struct match *, char *, states, int, FILE *);
+#endif
+#ifdef REDEBUG
+static void at(struct match *, char *, char *, char *, sopno, sopno);
+#endif
+#ifdef REDEBUG
+static char *pchar(int);
+#endif
+
+#ifdef REDEBUG
+#define	SP(t, s, c)	print(m, t, s, c, stdout)
+#define	AT(t, p1, p2, s1, s2)	at(m, t, p1, p2, s1, s2)
+#define	NOTE(str)	{ if (m->eflags&REG_TRACE) (void)printf("=%s\n", (str)); }
+static int nope = 0;
+#else
+#define	SP(t, s, c)	/* nothing */
+#define	AT(t, p1, p2, s1, s2)	/* nothing */
+#define	NOTE(s)	/* nothing */
+#endif
+
+/*
+ - matcher - the actual matching engine
+ */
+static int			/* 0 success, REG_NOMATCH failure */
+matcher(struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[],
+    int eflags)
+{
+	char *endp;
+	int i;
+	struct match mv;
+	struct match *m = &mv;
+	char *dp;
+	const sopno gf = g->firststate+1;	/* +1 for OEND */
+	const sopno gl = g->laststate;
+	char *start;
+	char *stop;
+
+	/* simplify the situation where possible */
+	if (g->cflags&REG_NOSUB)
+		nmatch = 0;
+	if (eflags&REG_STARTEND) {
+		start = string + pmatch[0].rm_so;
+		stop = string + pmatch[0].rm_eo;
+	} else {
+		start = string;
+		stop = start + strlen(start);
+	}
+	if (stop < start)
+		return(REG_INVARG);
+
+	/* prescreening; this does wonders for this rather slow code */
+	if (g->must != NULL) {
+		for (dp = start; dp < stop; dp++)
+			if (*dp == g->must[0] && stop - dp >= g->mlen &&
+				memcmp(dp, g->must, (size_t)g->mlen) == 0)
+				break;
+		if (dp == stop)		/* we didn't find g->must */
+			return(REG_NOMATCH);
+	}
+
+	/* match struct setup */
+	m->g = g;
+	m->eflags = eflags;
+	m->pmatch = NULL;
+	m->lastpos = NULL;
+	m->offp = string;
+	m->beginp = start;
+	m->endp = stop;
+	STATESETUP(m, 4);
+	SETUP(m->st);
+	SETUP(m->fresh);
+	SETUP(m->tmp);
+	SETUP(m->empty);
+	CLEAR(m->empty);
+
+	/* this loop does only one repetition except for backrefs */
+	for (;;) {
+		endp = fast(m, start, stop, gf, gl);
+		if (endp == NULL) {		/* a miss */
+			free(m->pmatch);
+			free(m->lastpos);
+			STATETEARDOWN(m);
+			return(REG_NOMATCH);
+		}
+		if (nmatch == 0 && !g->backrefs)
+			break;		/* no further info needed */
+
+		/* where? */
+		assert(m->coldp != NULL);
+		for (;;) {
+			NOTE("finding start");
+			endp = slow(m, m->coldp, stop, gf, gl);
+			if (endp != NULL)
+				break;
+			assert(m->coldp < m->endp);
+			m->coldp++;
+		}
+		if (nmatch == 1 && !g->backrefs)
+			break;		/* no further info needed */
+
+		/* oh my, he wants the subexpressions... */
+		if (m->pmatch == NULL)
+			m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
+							sizeof(regmatch_t));
+		if (m->pmatch == NULL) {
+			STATETEARDOWN(m);
+			return(REG_ESPACE);
+		}
+		for (i = 1; i <= m->g->nsub; i++)
+			m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
+		if (!g->backrefs && !(m->eflags&REG_BACKR)) {
+			NOTE("dissecting");
+			dp = dissect(m, m->coldp, endp, gf, gl);
+		} else {
+			if (g->nplus > 0 && m->lastpos == NULL)
+				m->lastpos = (char **)malloc((g->nplus+1) *
+							sizeof(char *));
+			if (g->nplus > 0 && m->lastpos == NULL) {
+				free(m->pmatch);
+				STATETEARDOWN(m);
+				return(REG_ESPACE);
+			}
+			NOTE("backref dissect");
+			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
+		}
+		if (dp != NULL)
+			break;
+
+		/* uh-oh... we couldn't find a subexpression-level match */
+		assert(g->backrefs);	/* must be back references doing it */
+		assert(g->nplus == 0 || m->lastpos != NULL);
+		for (;;) {
+			if (dp != NULL || endp <= m->coldp)
+				break;		/* defeat */
+			NOTE("backoff");
+			endp = slow(m, m->coldp, endp-1, gf, gl);
+			if (endp == NULL)
+				break;		/* defeat */
+			/* try it on a shorter possibility */
+#ifndef NDEBUG
+			for (i = 1; i <= m->g->nsub; i++) {
+				assert(m->pmatch[i].rm_so == -1);
+				assert(m->pmatch[i].rm_eo == -1);
+			}
+#endif
+			NOTE("backoff dissect");
+			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
+		}
+		assert(dp == NULL || dp == endp);
+		if (dp != NULL)		/* found a shorter one */
+			break;
+
+		/* despite initial appearances, there is no match here */
+		NOTE("false alarm");
+		if (m->coldp == stop)
+			break;
+		start = m->coldp + 1;	/* recycle starting later */
+	}
+
+	/* fill in the details if requested */
+	if (nmatch > 0) {
+		pmatch[0].rm_so = m->coldp - m->offp;
+		pmatch[0].rm_eo = endp - m->offp;
+	}
+	if (nmatch > 1) {
+		assert(m->pmatch != NULL);
+		for (i = 1; i < nmatch; i++)
+			if (i <= m->g->nsub)
+				pmatch[i] = m->pmatch[i];
+			else {
+				pmatch[i].rm_so = -1;
+				pmatch[i].rm_eo = -1;
+			}
+	}
+
+	if (m->pmatch != NULL)
+		free((char *)m->pmatch);
+	if (m->lastpos != NULL)
+		free((char *)m->lastpos);
+	STATETEARDOWN(m);
+	return(0);
+}
+
+/*
+ - dissect - figure out what matched what, no back references
+ */
+static char *			/* == stop (success) always */
+dissect(struct match *m, char *start, char *stop, sopno startst, sopno stopst)
+{
+	int i;
+	sopno ss;	/* start sop of current subRE */
+	sopno es;	/* end sop of current subRE */
+	char *sp;	/* start of string matched by it */
+	char *stp;	/* string matched by it cannot pass here */
+	char *rest;	/* start of rest of string */
+	char *tail;	/* string unmatched by rest of RE */
+	sopno ssub;	/* start sop of subsubRE */
+	sopno esub;	/* end sop of subsubRE */
+	char *ssp;	/* start of string matched by subsubRE */
+	char *sep;	/* end of string matched by subsubRE */
+	char *oldssp;	/* previous ssp */
+	char *dp;
+
+	AT("diss", start, stop, startst, stopst);
+	sp = start;
+	for (ss = startst; ss < stopst; ss = es) {
+		/* identify end of subRE */
+		es = ss;
+		switch (OP(m->g->strip[es])) {
+		case OPLUS_:
+		case OQUEST_:
+			es += OPND(m->g->strip[es]);
+			break;
+		case OCH_:
+			while (OP(m->g->strip[es]) != O_CH)
+				es += OPND(m->g->strip[es]);
+			break;
+		}
+		es++;
+
+		/* figure out what it matched */
+		switch (OP(m->g->strip[ss])) {
+		case OEND:
+			assert(nope);
+			break;
+		case OCHAR:
+			sp++;
+			break;
+		case OBOL:
+		case OEOL:
+		case OBOW:
+		case OEOW:
+			break;
+		case OANY:
+		case OANYOF:
+			sp++;
+			break;
+		case OBACK_:
+		case O_BACK:
+			assert(nope);
+			break;
+		/* cases where length of match is hard to find */
+		case OQUEST_:
+			stp = stop;
+			for (;;) {
+				/* how long could this one be? */
+				rest = slow(m, sp, stp, ss, es);
+				assert(rest != NULL);	/* it did match */
+				/* could the rest match the rest? */
+				tail = slow(m, rest, stop, es, stopst);
+				if (tail == stop)
+					break;		/* yes! */
+				/* no -- try a shorter match for this one */
+				stp = rest - 1;
+				assert(stp >= sp);	/* it did work */
+			}
+			ssub = ss + 1;
+			esub = es - 1;
+			/* did innards match? */
+			if (slow(m, sp, rest, ssub, esub) != NULL) {
+				dp = dissect(m, sp, rest, ssub, esub);
+				assert(dp == rest);
+			} else		/* no */
+				assert(sp == rest);
+			sp = rest;
+			break;
+		case OPLUS_:
+			stp = stop;
+			for (;;) {
+				/* how long could this one be? */
+				rest = slow(m, sp, stp, ss, es);
+				assert(rest != NULL);	/* it did match */
+				/* could the rest match the rest? */
+				tail = slow(m, rest, stop, es, stopst);
+				if (tail == stop)
+					break;		/* yes! */
+				/* no -- try a shorter match for this one */
+				stp = rest - 1;
+				assert(stp >= sp);	/* it did work */
+			}
+			ssub = ss + 1;
+			esub = es - 1;
+			ssp = sp;
+			oldssp = ssp;
+			for (;;) {	/* find last match of innards */
+				sep = slow(m, ssp, rest, ssub, esub);
+				if (sep == NULL || sep == ssp)
+					break;	/* failed or matched null */
+				oldssp = ssp;	/* on to next try */
+				ssp = sep;
+			}
+			if (sep == NULL) {
+				/* last successful match */
+				sep = ssp;
+				ssp = oldssp;
+			}
+			assert(sep == rest);	/* must exhaust substring */
+			assert(slow(m, ssp, sep, ssub, esub) == rest);
+			dp = dissect(m, ssp, sep, ssub, esub);
+			assert(dp == sep);
+			sp = rest;
+			break;
+		case OCH_:
+			stp = stop;
+			for (;;) {
+				/* how long could this one be? */
+				rest = slow(m, sp, stp, ss, es);
+				assert(rest != NULL);	/* it did match */
+				/* could the rest match the rest? */
+				tail = slow(m, rest, stop, es, stopst);
+				if (tail == stop)
+					break;		/* yes! */
+				/* no -- try a shorter match for this one */
+				stp = rest - 1;
+				assert(stp >= sp);	/* it did work */
+			}
+			ssub = ss + 1;
+			esub = ss + OPND(m->g->strip[ss]) - 1;
+			assert(OP(m->g->strip[esub]) == OOR1);
+			for (;;) {	/* find first matching branch */
+				if (slow(m, sp, rest, ssub, esub) == rest)
+					break;	/* it matched all of it */
+				/* that one missed, try next one */
+				assert(OP(m->g->strip[esub]) == OOR1);
+				esub++;
+				assert(OP(m->g->strip[esub]) == OOR2);
+				ssub = esub + 1;
+				esub += OPND(m->g->strip[esub]);
+				if (OP(m->g->strip[esub]) == OOR2)
+					esub--;
+				else
+					assert(OP(m->g->strip[esub]) == O_CH);
+			}
+			dp = dissect(m, sp, rest, ssub, esub);
+			assert(dp == rest);
+			sp = rest;
+			break;
+		case O_PLUS:
+		case O_QUEST:
+		case OOR1:
+		case OOR2:
+		case O_CH:
+			assert(nope);
+			break;
+		case OLPAREN:
+			i = OPND(m->g->strip[ss]);
+			assert(0 < i && i <= m->g->nsub);
+			m->pmatch[i].rm_so = sp - m->offp;
+			break;
+		case ORPAREN:
+			i = OPND(m->g->strip[ss]);
+			assert(0 < i && i <= m->g->nsub);
+			m->pmatch[i].rm_eo = sp - m->offp;
+			break;
+		default:		/* uh oh */
+			assert(nope);
+			break;
+		}
+	}
+
+	assert(sp == stop);
+	return(sp);
+}
+
+/*
+ - backref - figure out what matched what, figuring in back references
+ */
+static char *			/* == stop (success) or NULL (failure) */
+backref(struct match *m, char *start, char *stop, sopno startst, sopno stopst,
+    sopno lev, int rec)			/* PLUS nesting level */
+{
+	int i;
+	sopno ss;	/* start sop of current subRE */
+	char *sp;	/* start of string matched by it */
+	sopno ssub;	/* start sop of subsubRE */
+	sopno esub;	/* end sop of subsubRE */
+	char *ssp;	/* start of string matched by subsubRE */
+	char *dp;
+	size_t len;
+	int hard;
+	sop s;
+	regoff_t offsave;
+	cset *cs;
+
+	AT("back", start, stop, startst, stopst);
+	sp = start;
+
+	/* get as far as we can with easy stuff */
+	hard = 0;
+	for (ss = startst; !hard && ss < stopst; ss++)
+		switch (OP(s = m->g->strip[ss])) {
+		case OCHAR:
+			if (sp == stop || *sp++ != (char)OPND(s))
+				return(NULL);
+			break;
+		case OANY:
+			if (sp == stop)
+				return(NULL);
+			sp++;
+			break;
+		case OANYOF:
+			cs = &m->g->sets[OPND(s)];
+			if (sp == stop || !CHIN(cs, *sp++))
+				return(NULL);
+			break;
+		case OBOL:
+			if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+					(sp < m->endp && *(sp-1) == '\n' &&
+						(m->g->cflags&REG_NEWLINE)) )
+				{ /* yes */ }
+			else
+				return(NULL);
+			break;
+		case OEOL:
+			if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+					(sp < m->endp && *sp == '\n' &&
+						(m->g->cflags&REG_NEWLINE)) )
+				{ /* yes */ }
+			else
+				return(NULL);
+			break;
+		case OBOW:
+			if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+					(sp < m->endp && *(sp-1) == '\n' &&
+						(m->g->cflags&REG_NEWLINE)) ||
+					(sp > m->beginp &&
+							!ISWORD(*(sp-1))) ) &&
+					(sp < m->endp && ISWORD(*sp)) )
+				{ /* yes */ }
+			else
+				return(NULL);
+			break;
+		case OEOW:
+			if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+					(sp < m->endp && *sp == '\n' &&
+						(m->g->cflags&REG_NEWLINE)) ||
+					(sp < m->endp && !ISWORD(*sp)) ) &&
+					(sp > m->beginp && ISWORD(*(sp-1))) )
+				{ /* yes */ }
+			else
+				return(NULL);
+			break;
+		case O_QUEST:
+			break;
+		case OOR1:	/* matches null but needs to skip */
+			ss++;
+			s = m->g->strip[ss];
+			do {
+				assert(OP(s) == OOR2);
+				ss += OPND(s);
+			} while (OP(s = m->g->strip[ss]) != O_CH);
+			/* note that the ss++ gets us past the O_CH */
+			break;
+		default:	/* have to make a choice */
+			hard = 1;
+			break;
+		}
+	if (!hard) {		/* that was it! */
+		if (sp != stop)
+			return(NULL);
+		return(sp);
+	}
+	ss--;			/* adjust for the for's final increment */
+
+	/* the hard stuff */
+	AT("hard", sp, stop, ss, stopst);
+	s = m->g->strip[ss];
+	switch (OP(s)) {
+	case OBACK_:		/* the vilest depths */
+		i = OPND(s);
+		assert(0 < i && i <= m->g->nsub);
+		if (m->pmatch[i].rm_eo == -1)
+			return(NULL);
+		assert(m->pmatch[i].rm_so != -1);
+		len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
+		if (len == 0 && rec++ > MAX_RECURSION)
+			return(NULL);
+		assert(stop - m->beginp >= len);
+		if (sp > stop - len)
+			return(NULL);	/* not enough left to match */
+		ssp = m->offp + m->pmatch[i].rm_so;
+		if (memcmp(sp, ssp, len) != 0)
+			return(NULL);
+		while (m->g->strip[ss] != SOP(O_BACK, i))
+			ss++;
+		return(backref(m, sp+len, stop, ss+1, stopst, lev, rec));
+		break;
+	case OQUEST_:		/* to null or not */
+		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
+		if (dp != NULL)
+			return(dp);	/* not */
+		return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec));
+		break;
+	case OPLUS_:
+		assert(m->lastpos != NULL);
+		assert(lev+1 <= m->g->nplus);
+		m->lastpos[lev+1] = sp;
+		return(backref(m, sp, stop, ss+1, stopst, lev+1, rec));
+		break;
+	case O_PLUS:
+		if (sp == m->lastpos[lev])	/* last pass matched null */
+			return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
+		/* try another pass */
+		m->lastpos[lev] = sp;
+		dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev, rec);
+		if (dp == NULL)
+			return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
+		else
+			return(dp);
+		break;
+	case OCH_:		/* find the right one, if any */
+		ssub = ss + 1;
+		esub = ss + OPND(s) - 1;
+		assert(OP(m->g->strip[esub]) == OOR1);
+		for (;;) {	/* find first matching branch */
+			dp = backref(m, sp, stop, ssub, esub, lev, rec);
+			if (dp != NULL)
+				return(dp);
+			/* that one missed, try next one */
+			if (OP(m->g->strip[esub]) == O_CH)
+				return(NULL);	/* there is none */
+			esub++;
+			assert(OP(m->g->strip[esub]) == OOR2);
+			ssub = esub + 1;
+			esub += OPND(m->g->strip[esub]);
+			if (OP(m->g->strip[esub]) == OOR2)
+				esub--;
+			else
+				assert(OP(m->g->strip[esub]) == O_CH);
+		}
+		break;
+	case OLPAREN:		/* must undo assignment if rest fails */
+		i = OPND(s);
+		assert(0 < i && i <= m->g->nsub);
+		offsave = m->pmatch[i].rm_so;
+		m->pmatch[i].rm_so = sp - m->offp;
+		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
+		if (dp != NULL)
+			return(dp);
+		m->pmatch[i].rm_so = offsave;
+		return(NULL);
+		break;
+	case ORPAREN:		/* must undo assignment if rest fails */
+		i = OPND(s);
+		assert(0 < i && i <= m->g->nsub);
+		offsave = m->pmatch[i].rm_eo;
+		m->pmatch[i].rm_eo = sp - m->offp;
+		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
+		if (dp != NULL)
+			return(dp);
+		m->pmatch[i].rm_eo = offsave;
+		return(NULL);
+		break;
+	default:		/* uh oh */
+		assert(nope);
+		break;
+	}
+
+	/* "can't happen" */
+	assert(nope);
+	/* NOTREACHED */
+	return 0;
+}
+
+/*
+ - fast - step through the string at top speed
+ */
+static char *			/* where tentative match ended, or NULL */
+fast(struct match *m, char *start, char *stop, sopno startst, sopno stopst)
+{
+	states st = m->st;
+	states fresh = m->fresh;
+	states tmp = m->tmp;
+	char *p = start;
+	int c = (start == m->beginp) ? OUT : *(start-1);
+	int lastc;	/* previous c */
+	int flagch;
+	int i;
+	char *coldp;	/* last p after which no match was underway */
+
+	CLEAR(st);
+	SET1(st, startst);
+	st = step(m->g, startst, stopst, st, NOTHING, st);
+	ASSIGN(fresh, st);
+	SP("start", st, *p);
+	coldp = NULL;
+	for (;;) {
+		/* next character */
+		lastc = c;
+		c = (p == m->endp) ? OUT : *p;
+		if (EQ(st, fresh))
+			coldp = p;
+
+		/* is there an EOL and/or BOL between lastc and c? */
+		flagch = '\0';
+		i = 0;
+		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+			flagch = BOL;
+			i = m->g->nbol;
+		}
+		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+			flagch = (flagch == BOL) ? BOLEOL : EOL;
+			i += m->g->neol;
+		}
+		if (i != 0) {
+			for (; i > 0; i--)
+				st = step(m->g, startst, stopst, st, flagch, st);
+			SP("boleol", st, c);
+		}
+
+		/* how about a word boundary? */
+		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+					(c != OUT && ISWORD(c)) ) {
+			flagch = BOW;
+		}
+		if ( (lastc != OUT && ISWORD(lastc)) &&
+				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+			flagch = EOW;
+		}
+		if (flagch == BOW || flagch == EOW) {
+			st = step(m->g, startst, stopst, st, flagch, st);
+			SP("boweow", st, c);
+		}
+
+		/* are we done? */
+		if (ISSET(st, stopst) || p == stop)
+			break;		/* NOTE BREAK OUT */
+
+		/* no, we must deal with this character */
+		ASSIGN(tmp, st);
+		ASSIGN(st, fresh);
+		assert(c != OUT);
+		st = step(m->g, startst, stopst, tmp, c, st);
+		SP("aft", st, c);
+		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+		p++;
+	}
+
+	assert(coldp != NULL);
+	m->coldp = coldp;
+	if (ISSET(st, stopst))
+		return(p+1);
+	else
+		return(NULL);
+}
+
+/*
+ - slow - step through the string more deliberately
+ */
+static char *			/* where it ended */
+slow(struct match *m, char *start, char *stop, sopno startst, sopno stopst)
+{
+	states st = m->st;
+	states empty = m->empty;
+	states tmp = m->tmp;
+	char *p = start;
+	int c = (start == m->beginp) ? OUT : *(start-1);
+	int lastc;	/* previous c */
+	int flagch;
+	int i;
+	char *matchp;	/* last p at which a match ended */
+
+	AT("slow", start, stop, startst, stopst);
+	CLEAR(st);
+	SET1(st, startst);
+	SP("sstart", st, *p);
+	st = step(m->g, startst, stopst, st, NOTHING, st);
+	matchp = NULL;
+	for (;;) {
+		/* next character */
+		lastc = c;
+		c = (p == m->endp) ? OUT : *p;
+
+		/* is there an EOL and/or BOL between lastc and c? */
+		flagch = '\0';
+		i = 0;
+		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+			flagch = BOL;
+			i = m->g->nbol;
+		}
+		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+			flagch = (flagch == BOL) ? BOLEOL : EOL;
+			i += m->g->neol;
+		}
+		if (i != 0) {
+			for (; i > 0; i--)
+				st = step(m->g, startst, stopst, st, flagch, st);
+			SP("sboleol", st, c);
+		}
+
+		/* how about a word boundary? */
+		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+					(c != OUT && ISWORD(c)) ) {
+			flagch = BOW;
+		}
+		if ( (lastc != OUT && ISWORD(lastc)) &&
+				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+			flagch = EOW;
+		}
+		if (flagch == BOW || flagch == EOW) {
+			st = step(m->g, startst, stopst, st, flagch, st);
+			SP("sboweow", st, c);
+		}
+
+		/* are we done? */
+		if (ISSET(st, stopst))
+			matchp = p;
+		if (EQ(st, empty) || p == stop)
+			break;		/* NOTE BREAK OUT */
+
+		/* no, we must deal with this character */
+		ASSIGN(tmp, st);
+		ASSIGN(st, empty);
+		assert(c != OUT);
+		st = step(m->g, startst, stopst, tmp, c, st);
+		SP("saft", st, c);
+		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+		p++;
+	}
+
+	return(matchp);
+}
+
+
+/*
+ - step - map set of states reachable before char to set reachable after
+ */
+static states
+step(struct re_guts *g,
+    sopno start,		/* start state within strip */
+    sopno stop,			/* state after stop state within strip */
+    states bef,			/* states reachable before */
+    int ch,			/* character or NONCHAR code */
+    states aft)			/* states already known reachable after */
+{
+	cset *cs;
+	sop s;
+	sopno pc;
+	onestate here;		/* note, macros know this name */
+	sopno look;
+	int i;
+
+	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
+		s = g->strip[pc];
+		switch (OP(s)) {
+		case OEND:
+			assert(pc == stop-1);
+			break;
+		case OCHAR:
+			/* only characters can match */
+			assert(!NONCHAR(ch) || ch != (char)OPND(s));
+			if (ch == (char)OPND(s))
+				FWD(aft, bef, 1);
+			break;
+		case OBOL:
+			if (ch == BOL || ch == BOLEOL)
+				FWD(aft, bef, 1);
+			break;
+		case OEOL:
+			if (ch == EOL || ch == BOLEOL)
+				FWD(aft, bef, 1);
+			break;
+		case OBOW:
+			if (ch == BOW)
+				FWD(aft, bef, 1);
+			break;
+		case OEOW:
+			if (ch == EOW)
+				FWD(aft, bef, 1);
+			break;
+		case OANY:
+			if (!NONCHAR(ch))
+				FWD(aft, bef, 1);
+			break;
+		case OANYOF:
+			cs = &g->sets[OPND(s)];
+			if (!NONCHAR(ch) && CHIN(cs, ch))
+				FWD(aft, bef, 1);
+			break;
+		case OBACK_:		/* ignored here */
+		case O_BACK:
+			FWD(aft, aft, 1);
+			break;
+		case OPLUS_:		/* forward, this is just an empty */
+			FWD(aft, aft, 1);
+			break;
+		case O_PLUS:		/* both forward and back */
+			FWD(aft, aft, 1);
+			i = ISSETBACK(aft, OPND(s));
+			BACK(aft, aft, OPND(s));
+			if (!i && ISSETBACK(aft, OPND(s))) {
+				/* oho, must reconsider loop body */
+				pc -= OPND(s) + 1;
+				INIT(here, pc);
+			}
+			break;
+		case OQUEST_:		/* two branches, both forward */
+			FWD(aft, aft, 1);
+			FWD(aft, aft, OPND(s));
+			break;
+		case O_QUEST:		/* just an empty */
+			FWD(aft, aft, 1);
+			break;
+		case OLPAREN:		/* not significant here */
+		case ORPAREN:
+			FWD(aft, aft, 1);
+			break;
+		case OCH_:		/* mark the first two branches */
+			FWD(aft, aft, 1);
+			assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+			FWD(aft, aft, OPND(s));
+			break;
+		case OOR1:		/* done a branch, find the O_CH */
+			if (ISSTATEIN(aft, here)) {
+				for (look = 1;
+						OP(s = g->strip[pc+look]) != O_CH;
+						look += OPND(s))
+					assert(OP(s) == OOR2);
+				FWD(aft, aft, look);
+			}
+			break;
+		case OOR2:		/* propagate OCH_'s marking */
+			FWD(aft, aft, 1);
+			if (OP(g->strip[pc+OPND(s)]) != O_CH) {
+				assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+				FWD(aft, aft, OPND(s));
+			}
+			break;
+		case O_CH:		/* just empty */
+			FWD(aft, aft, 1);
+			break;
+		default:		/* ooooops... */
+			assert(nope);
+			break;
+		}
+	}
+
+	return(aft);
+}
+
+#ifdef REDEBUG
+/*
+ - print - print a set of states
+ */
+static void
+print(struct match *m, char *caption, states st, int ch, FILE *d)
+{
+	struct re_guts *g = m->g;
+	int i;
+	int first = 1;
+
+	if (!(m->eflags&REG_TRACE))
+		return;
+
+	(void)fprintf(d, "%s", caption);
+	if (ch != '\0')
+		(void)fprintf(d, " %s", pchar(ch));
+	for (i = 0; i < g->nstates; i++)
+		if (ISSET(st, i)) {
+			(void)fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
+			first = 0;
+		}
+	(void)fprintf(d, "\n");
+}
+
+/* 
+ - at - print current situation
+ */
+static void
+at(struct match *m, char *title, char *start, char *stop, sopno startst,
+    sopno stopst)
+{
+	if (!(m->eflags&REG_TRACE))
+		return;
+
+	(void)printf("%s %s-", title, pchar(*start));
+	(void)printf("%s ", pchar(*stop));
+	(void)printf("%ld-%ld\n", (long)startst, (long)stopst);
+}
+
+#ifndef PCHARDONE
+#define	PCHARDONE	/* never again */
+/*
+ - pchar - make a character printable
+ *
+ * Is this identical to regchar() over in debug.c?  Well, yes.  But a
+ * duplicate here avoids having a debugging-capable regexec.o tied to
+ * a matching debug.o, and this is convenient.  It all disappears in
+ * the non-debug compilation anyway, so it doesn't matter much.
+ */
+static char *			/* -> representation */
+pchar(int ch)
+{
+	static char pbuf[10];
+
+	if (isprint(ch) || ch == ' ')
+		(void)snprintf(pbuf, sizeof pbuf, "%c", ch);
+	else
+		(void)snprintf(pbuf, sizeof pbuf, "\\%o", ch);
+	return(pbuf);
+}
+#endif
+#endif
+
+#undef	matcher
+#undef	fast
+#undef	slow
+#undef	dissect
+#undef	backref
+#undef	step
+#undef	print
+#undef	at
+#undef	match
+#undef	nope
diff --git a/libc/regex/regcomp.c b/libc/regex/regcomp.c
new file mode 100644
index 0000000..5b632c8
--- /dev/null
+++ b/libc/regex/regcomp.c
@@ -0,0 +1,1517 @@
+/*	$OpenBSD: regcomp.c,v 1.19 2008/02/23 08:13:07 otto Exp $ */
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)regcomp.c	8.5 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cclass.h"
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+	char *next;		/* next character in RE */
+	char *end;		/* end of string (-> NUL normally) */
+	int error;		/* has an error been seen? */
+	sop *strip;		/* malloced strip */
+	sopno ssize;		/* malloced strip size (allocated) */
+	sopno slen;		/* malloced strip length (used) */
+	int ncsalloc;		/* number of csets allocated */
+	struct re_guts *g;
+#	define	NPAREN	10	/* we need to remember () 1-9 for back refs */
+	sopno pbegin[NPAREN];	/* -> ( ([0] unused) */
+	sopno pend[NPAREN];	/* -> ) ([0] unused) */
+};
+
+static void p_ere(struct parse *, int);
+static void p_ere_exp(struct parse *);
+static void p_str(struct parse *);
+static void p_bre(struct parse *, int, int);
+static int p_simp_re(struct parse *, int);
+static int p_count(struct parse *);
+static void p_bracket(struct parse *);
+static void p_b_term(struct parse *, cset *);
+static void p_b_cclass(struct parse *, cset *);
+static void p_b_eclass(struct parse *, cset *);
+static char p_b_symbol(struct parse *);
+static char p_b_coll_elem(struct parse *, int);
+static char othercase(int);
+static void bothcases(struct parse *, int);
+static void ordinary(struct parse *, int);
+static void nonnewline(struct parse *);
+static void repeat(struct parse *, sopno, int, int);
+static int seterr(struct parse *, int);
+static cset *allocset(struct parse *);
+static void freeset(struct parse *, cset *);
+static int freezeset(struct parse *, cset *);
+static int firstch(struct parse *, cset *);
+static int nch(struct parse *, cset *);
+static void mcadd(struct parse *, cset *, char *);
+static void mcinvert(struct parse *, cset *);
+static void mccase(struct parse *, cset *);
+static int isinsets(struct re_guts *, int);
+static int samesets(struct re_guts *, int, int);
+static void categorize(struct parse *, struct re_guts *);
+static sopno dupl(struct parse *, sopno, sopno);
+static void doemit(struct parse *, sop, size_t);
+static void doinsert(struct parse *, sop, size_t, sopno);
+static void dofwd(struct parse *, sopno, sop);
+static void enlarge(struct parse *, sopno);
+static void stripsnug(struct parse *, struct re_guts *);
+static void findmust(struct parse *, struct re_guts *);
+static sopno pluscount(struct parse *, struct re_guts *);
+
+static char nuls[10];		/* place to point scanner in event of error */
+
+/*
+ * macros for use with parse structure
+ * BEWARE:  these know that the parse structure is named `p' !!!
+ */
+#define	PEEK()	(*p->next)
+#define	PEEK2()	(*(p->next+1))
+#define	MORE()	(p->next < p->end)
+#define	MORE2()	(p->next+1 < p->end)
+#define	SEE(c)	(MORE() && PEEK() == (c))
+#define	SEETWO(a, b)	(MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define	EAT(c)	((SEE(c)) ? (NEXT(), 1) : 0)
+#define	EATTWO(a, b)	((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define	NEXT()	(p->next++)
+#define	NEXT2()	(p->next += 2)
+#define	NEXTn(n)	(p->next += (n))
+#define	GETNEXT()	(*p->next++)
+#define	SETERROR(e)	seterr(p, (e))
+#define	REQUIRE(co, e)	((co) || SETERROR(e))
+#define	MUSTSEE(c, e)	(REQUIRE(MORE() && PEEK() == (c), e))
+#define	MUSTEAT(c, e)	(REQUIRE(MORE() && GETNEXT() == (c), e))
+#define	MUSTNOTSEE(c, e)	(REQUIRE(!MORE() || PEEK() != (c), e))
+#define	EMIT(op, sopnd)	doemit(p, (sop)(op), (size_t)(sopnd))
+#define	INSERT(op, pos)	doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define	AHEAD(pos)		dofwd(p, pos, HERE()-(pos))
+#define	ASTERN(sop, pos)	EMIT(sop, HERE()-pos)
+#define	HERE()		(p->slen)
+#define	THERE()		(p->slen - 1)
+#define	THERETHERE()	(p->slen - 2)
+#define	DROP(n)	(p->slen -= (n))
+
+#ifndef NDEBUG
+static int never = 0;		/* for use in asserts; shuts lint up */
+#else
+#define	never	0		/* some <assert.h>s have bugs too */
+#endif
+
+/*
+ - regcomp - interface for parser and compilation
+ */
+int				/* 0 success, otherwise REG_something */
+regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+	struct parse pa;
+	struct re_guts *g;
+	struct parse *p = &pa;
+	int i;
+	size_t len;
+#ifdef REDEBUG
+#	define	GOODFLAGS(f)	(f)
+#else
+#	define	GOODFLAGS(f)	((f)&~REG_DUMP)
+#endif
+
+	cflags = GOODFLAGS(cflags);
+	if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
+		return(REG_INVARG);
+
+	if (cflags&REG_PEND) {
+		if (preg->re_endp < pattern)
+			return(REG_INVARG);
+		len = preg->re_endp - pattern;
+	} else
+		len = strlen((char *)pattern);
+
+	/* do the mallocs early so failure handling is easy */
+	g = (struct re_guts *)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 = (sop *)calloc(p->ssize, sizeof(sop));
+	p->slen = 0;
+	if (p->strip == NULL) {
+		free((char *)g);
+		return(REG_ESPACE);
+	}
+
+	/* set things up */
+	p->g = g;
+	p->next = (char *)pattern;	/* convenience; we do not modify it */
+	p->end = p->next + len;
+	p->error = 0;
+	p->ncsalloc = 0;
+	for (i = 0; i < NPAREN; i++) {
+		p->pbegin[i] = 0;
+		p->pend[i] = 0;
+	}
+	g->csetsize = NC;
+	g->sets = NULL;
+	g->setbits = NULL;
+	g->ncsets = 0;
+	g->cflags = cflags;
+	g->iflags = 0;
+	g->nbol = 0;
+	g->neol = 0;
+	g->must = NULL;
+	g->mlen = 0;
+	g->nsub = 0;
+	g->ncategories = 1;	/* category 0 is "everything else" */
+	g->categories = &g->catspace[-(CHAR_MIN)];
+	(void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+	g->backrefs = 0;
+
+	/* do it */
+	EMIT(OEND, 0);
+	g->firststate = THERE();
+	if (cflags&REG_EXTENDED)
+		p_ere(p, OUT);
+	else if (cflags&REG_NOSPEC)
+		p_str(p);
+	else
+		p_bre(p, OUT, OUT);
+	EMIT(OEND, 0);
+	g->laststate = THERE();
+
+	/* tidy up loose ends and fill things in */
+	categorize(p, g);
+	stripsnug(p, g);
+	findmust(p, g);
+	g->nplus = pluscount(p, g);
+	g->magic = MAGIC2;
+	preg->re_nsub = g->nsub;
+	preg->re_g = g;
+	preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+	/* not debugging, so can't rely on the assert() in regexec() */
+	if (g->iflags&BAD)
+		SETERROR(REG_ASSERT);
+#endif
+
+	/* win or lose, we're done */
+	if (p->error != 0)	/* lose */
+		regfree(preg);
+	return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ */
+static void
+p_ere(struct parse *p, int stop)	/* character this ERE should end at */
+{
+	char c;
+	sopno prevback;
+	sopno prevfwd;
+	sopno conc;
+	int first = 1;		/* is this the first alternative? */
+
+	for (;;) {
+		/* do a bunch of concatenated expressions */
+		conc = HERE();
+		while (MORE() && (c = PEEK()) != '|' && c != stop)
+			p_ere_exp(p);
+		REQUIRE(HERE() != conc, REG_EMPTY);	/* require nonempty */
+
+		if (!EAT('|'))
+			break;		/* NOTE BREAK OUT */
+
+		if (first) {
+			INSERT(OCH_, conc);	/* offset is wrong */
+			prevfwd = conc;
+			prevback = conc;
+			first = 0;
+		}
+		ASTERN(OOR1, prevback);
+		prevback = THERE();
+		AHEAD(prevfwd);			/* fix previous offset */
+		prevfwd = HERE();
+		EMIT(OOR2, 0);			/* offset is very wrong */
+	}
+
+	if (!first) {		/* tail-end fixups */
+		AHEAD(prevfwd);
+		ASTERN(O_CH, prevback);
+	}
+
+	assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ */
+static void
+p_ere_exp(struct parse *p)
+{
+	char c;
+	sopno pos;
+	int count;
+	int count2;
+	sopno subno;
+	int wascaret = 0;
+
+	assert(MORE());		/* caller should have ensured this */
+	c = GETNEXT();
+
+	pos = HERE();
+	switch (c) {
+	case '(':
+		REQUIRE(MORE(), REG_EPAREN);
+		p->g->nsub++;
+		subno = p->g->nsub;
+		if (subno < NPAREN)
+			p->pbegin[subno] = HERE();
+		EMIT(OLPAREN, subno);
+		if (!SEE(')'))
+			p_ere(p, ')');
+		if (subno < NPAREN) {
+			p->pend[subno] = HERE();
+			assert(p->pend[subno] != 0);
+		}
+		EMIT(ORPAREN, subno);
+		MUSTEAT(')', REG_EPAREN);
+		break;
+#ifndef POSIX_MISTAKE
+	case ')':		/* happens only if no current unmatched ( */
+		/*
+		 * You may ask, why the ifndef?  Because I didn't notice
+		 * this until slightly too late for 1003.2, and none of the
+		 * other 1003.2 regular-expression reviewers noticed it at
+		 * all.  So an unmatched ) is legal POSIX, at least until
+		 * we can get it fixed.
+		 */
+		SETERROR(REG_EPAREN);
+		break;
+#endif
+	case '^':
+		EMIT(OBOL, 0);
+		p->g->iflags |= USEBOL;
+		p->g->nbol++;
+		wascaret = 1;
+		break;
+	case '$':
+		EMIT(OEOL, 0);
+		p->g->iflags |= USEEOL;
+		p->g->neol++;
+		break;
+	case '|':
+		SETERROR(REG_EMPTY);
+		break;
+	case '*':
+	case '+':
+	case '?':
+		SETERROR(REG_BADRPT);
+		break;
+	case '.':
+		if (p->g->cflags&REG_NEWLINE)
+			nonnewline(p);
+		else
+			EMIT(OANY, 0);
+		break;
+	case '[':
+		p_bracket(p);
+		break;
+	case '\\':
+		REQUIRE(MORE(), REG_EESCAPE);
+		c = GETNEXT();
+		ordinary(p, c);
+		break;
+	case '{':		/* okay as ordinary except if digit follows */
+		REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT);
+		/* FALLTHROUGH */
+	default:
+		ordinary(p, c);
+		break;
+	}
+
+	if (!MORE())
+		return;
+	c = PEEK();
+	/* we call { a repetition if followed by a digit */
+	if (!( c == '*' || c == '+' || c == '?' ||
+				(c == '{' && MORE2() && isdigit((uch)PEEK2())) ))
+		return;		/* no repetition, we're done */
+	NEXT();
+
+	REQUIRE(!wascaret, REG_BADRPT);
+	switch (c) {
+	case '*':	/* implemented as +? */
+		/* this case does not require the (y|) trick, noKLUDGE */
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		INSERT(OQUEST_, pos);
+		ASTERN(O_QUEST, pos);
+		break;
+	case '+':
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		break;
+	case '?':
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, pos);		/* offset slightly wrong */
+		ASTERN(OOR1, pos);		/* this one's right */
+		AHEAD(pos);			/* fix the OCH_ */
+		EMIT(OOR2, 0);			/* offset very wrong... */
+		AHEAD(THERE());			/* ...so fix it */
+		ASTERN(O_CH, THERETHERE());
+		break;
+	case '{':
+		count = p_count(p);
+		if (EAT(',')) {
+			if (isdigit((uch)PEEK())) {
+				count2 = p_count(p);
+				REQUIRE(count <= count2, REG_BADBR);
+			} else		/* single number with comma */
+				count2 = INFINITY;
+		} else		/* just a single number */
+			count2 = count;
+		repeat(p, pos, count, count2);
+		if (!EAT('}')) {	/* error heuristics */
+			while (MORE() && PEEK() != '}')
+				NEXT();
+			REQUIRE(MORE(), REG_EBRACE);
+			SETERROR(REG_BADBR);
+		}
+		break;
+	}
+
+	if (!MORE())
+		return;
+	c = PEEK();
+	if (!( c == '*' || c == '+' || c == '?' ||
+				(c == '{' && MORE2() && isdigit((uch)PEEK2())) ) )
+		return;
+	SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ */
+static void
+p_str(struct parse *p)
+{
+	REQUIRE(MORE(), REG_EMPTY);
+	while (MORE())
+		ordinary(p, GETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor.  The
+ * only undesirable side effect is that '$' gets included as a character
+ * category in such cases.  This is fairly harmless; not worth fixing.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(struct parse *p,
+    int end1,		/* first terminating character */
+    int end2)		/* second terminating character */
+{
+	sopno start = HERE();
+	int first = 1;			/* first subexpression? */
+	int wasdollar = 0;
+
+	if (EAT('^')) {
+		EMIT(OBOL, 0);
+		p->g->iflags |= USEBOL;
+		p->g->nbol++;
+	}
+	while (MORE() && !SEETWO(end1, end2)) {
+		wasdollar = p_simp_re(p, first);
+		first = 0;
+	}
+	if (wasdollar) {	/* oops, that was a trailing anchor */
+		DROP(1);
+		EMIT(OEOL, 0);
+		p->g->iflags |= USEEOL;
+		p->g->neol++;
+	}
+
+	REQUIRE(HERE() != start, REG_EMPTY);	/* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ */
+static int			/* was the simple RE an unbackslashed $? */
+p_simp_re(struct parse *p,
+    int starordinary)		/* is a leading * an ordinary character? */
+{
+	int c;
+	int count;
+	int count2;
+	sopno pos;
+	int i;
+	sopno subno;
+#	define	BACKSL	(1<<CHAR_BIT)
+
+	pos = HERE();		/* repetion op, if any, covers from here */
+
+	assert(MORE());		/* caller should have ensured this */
+	c = GETNEXT();
+	if (c == '\\') {
+		REQUIRE(MORE(), REG_EESCAPE);
+		c = BACKSL | GETNEXT();
+	}
+	switch (c) {
+	case '.':
+		if (p->g->cflags&REG_NEWLINE)
+			nonnewline(p);
+		else
+			EMIT(OANY, 0);
+		break;
+	case '[':
+		p_bracket(p);
+		break;
+	case BACKSL|'{':
+		SETERROR(REG_BADRPT);
+		break;
+	case BACKSL|'(':
+		p->g->nsub++;
+		subno = p->g->nsub;
+		if (subno < NPAREN)
+			p->pbegin[subno] = HERE();
+		EMIT(OLPAREN, subno);
+		/* the MORE here is an error heuristic */
+		if (MORE() && !SEETWO('\\', ')'))
+			p_bre(p, '\\', ')');
+		if (subno < NPAREN) {
+			p->pend[subno] = HERE();
+			assert(p->pend[subno] != 0);
+		}
+		EMIT(ORPAREN, subno);
+		REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+		break;
+	case BACKSL|')':	/* should not get here -- must be user */
+	case BACKSL|'}':
+		SETERROR(REG_EPAREN);
+		break;
+	case BACKSL|'1':
+	case BACKSL|'2':
+	case BACKSL|'3':
+	case BACKSL|'4':
+	case BACKSL|'5':
+	case BACKSL|'6':
+	case BACKSL|'7':
+	case BACKSL|'8':
+	case BACKSL|'9':
+		i = (c&~BACKSL) - '0';
+		assert(i < NPAREN);
+		if (p->pend[i] != 0) {
+			assert(i <= p->g->nsub);
+			EMIT(OBACK_, i);
+			assert(p->pbegin[i] != 0);
+			assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
+			assert(OP(p->strip[p->pend[i]]) == ORPAREN);
+			(void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+			EMIT(O_BACK, i);
+		} else
+			SETERROR(REG_ESUBREG);
+		p->g->backrefs = 1;
+		break;
+	case '*':
+		REQUIRE(starordinary, REG_BADRPT);
+		/* FALLTHROUGH */
+	default:
+		ordinary(p, (char)c);
+		break;
+	}
+
+	if (EAT('*')) {		/* implemented as +? */
+		/* this case does not require the (y|) trick, noKLUDGE */
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		INSERT(OQUEST_, pos);
+		ASTERN(O_QUEST, pos);
+	} else if (EATTWO('\\', '{')) {
+		count = p_count(p);
+		if (EAT(',')) {
+			if (MORE() && isdigit((uch)PEEK())) {
+				count2 = p_count(p);
+				REQUIRE(count <= count2, REG_BADBR);
+			} else		/* single number with comma */
+				count2 = INFINITY;
+		} else		/* just a single number */
+			count2 = count;
+		repeat(p, pos, count, count2);
+		if (!EATTWO('\\', '}')) {	/* error heuristics */
+			while (MORE() && !SEETWO('\\', '}'))
+				NEXT();
+			REQUIRE(MORE(), REG_EBRACE);
+			SETERROR(REG_BADBR);
+		}
+	} else if (c == '$')	/* $ (but not \$) ends it */
+		return(1);
+
+	return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ */
+static int			/* the value */
+p_count(struct parse *p)
+{
+	int count = 0;
+	int ndigits = 0;
+
+	while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) {
+		count = count*10 + (GETNEXT() - '0');
+		ndigits++;
+	}
+
+	REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+	return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ *
+ * Note a significant property of this code:  if the allocset() did SETERROR,
+ * no set operations are done.
+ */
+static void
+p_bracket(struct parse *p)
+{
+	cset *cs;
+	int invert = 0;
+
+	/* Dept of Truly Sickening Special-Case Kludges */
+	if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+		EMIT(OBOW, 0);
+		NEXTn(6);
+		return;
+	}
+	if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+		EMIT(OEOW, 0);
+		NEXTn(6);
+		return;
+	}
+
+	if ((cs = allocset(p)) == NULL) {
+		/* allocset did set error status in p */
+		return;
+	}
+
+	if (EAT('^'))
+		invert++;	/* make note to invert set at end */
+	if (EAT(']'))
+		CHadd(cs, ']');
+	else if (EAT('-'))
+		CHadd(cs, '-');
+	while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+		p_b_term(p, cs);
+	if (EAT('-'))
+		CHadd(cs, '-');
+	MUSTEAT(']', REG_EBRACK);
+
+	if (p->error != 0) {	/* don't mess things up further */
+		freeset(p, cs);
+		return;
+	}
+
+	if (p->g->cflags&REG_ICASE) {
+		int i;
+		int ci;
+
+		for (i = p->g->csetsize - 1; i >= 0; i--)
+			if (CHIN(cs, i) && isalpha(i)) {
+				ci = othercase(i);
+				if (ci != i)
+					CHadd(cs, ci);
+			}
+		if (cs->multis != NULL)
+			mccase(p, cs);
+	}
+	if (invert) {
+		int i;
+
+		for (i = p->g->csetsize - 1; i >= 0; i--)
+			if (CHIN(cs, i))
+				CHsub(cs, i);
+			else
+				CHadd(cs, i);
+		if (p->g->cflags&REG_NEWLINE)
+			CHsub(cs, '\n');
+		if (cs->multis != NULL)
+			mcinvert(p, cs);
+	}
+
+	assert(cs->multis == NULL);		/* xxx */
+
+	if (nch(p, cs) == 1) {		/* optimize singleton sets */
+		ordinary(p, firstch(p, cs));
+		freeset(p, cs);
+	} else
+		EMIT(OANYOF, freezeset(p, cs));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ */
+static void
+p_b_term(struct parse *p, cset *cs)
+{
+	char c;
+	char start, finish;
+	int i;
+
+	/* classify what we've got */
+	switch ((MORE()) ? PEEK() : '\0') {
+	case '[':
+		c = (MORE2()) ? PEEK2() : '\0';
+		break;
+	case '-':
+		SETERROR(REG_ERANGE);
+		return;			/* NOTE RETURN */
+		break;
+	default:
+		c = '\0';
+		break;
+	}
+
+	switch (c) {
+	case ':':		/* character class */
+		NEXT2();
+		REQUIRE(MORE(), REG_EBRACK);
+		c = PEEK();
+		REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+		p_b_cclass(p, cs);
+		REQUIRE(MORE(), REG_EBRACK);
+		REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+		break;
+	case '=':		/* equivalence class */
+		NEXT2();
+		REQUIRE(MORE(), REG_EBRACK);
+		c = PEEK();
+		REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+		p_b_eclass(p, cs);
+		REQUIRE(MORE(), REG_EBRACK);
+		REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+		break;
+	default:		/* symbol, ordinary character, or range */
+/* xxx revision needed for multichar stuff */
+		start = p_b_symbol(p);
+		if (SEE('-') && MORE2() && PEEK2() != ']') {
+			/* range */
+			NEXT();
+			if (EAT('-'))
+				finish = '-';
+			else
+				finish = p_b_symbol(p);
+		} else
+			finish = start;
+/* xxx what about signed chars here... */
+		REQUIRE(start <= finish, REG_ERANGE);
+		for (i = start; i <= finish; i++)
+			CHadd(cs, i);
+		break;
+	}
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ */
+static void
+p_b_cclass(struct parse *p, cset *cs)
+{
+	char *sp = p->next;
+	struct cclass *cp;
+	size_t len;
+	char *u;
+	char c;
+
+	while (MORE() && isalpha(PEEK()))
+		NEXT();
+	len = p->next - sp;
+	for (cp = cclasses; cp->name != NULL; cp++)
+		if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+			break;
+	if (cp->name == NULL) {
+		/* oops, didn't find it */
+		SETERROR(REG_ECTYPE);
+		return;
+	}
+
+	u = cp->chars;
+	while ((c = *u++) != '\0')
+		CHadd(cs, c);
+	for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+		MCadd(p, cs, u);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(struct parse *p, cset *cs)
+{
+	char c;
+
+	c = p_b_coll_elem(p, '=');
+	CHadd(cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ */
+static char			/* value of symbol */
+p_b_symbol(struct parse *p)
+{
+	char value;
+
+	REQUIRE(MORE(), REG_EBRACK);
+	if (!EATTWO('[', '.'))
+		return(GETNEXT());
+
+	/* collating symbol */
+	value = p_b_coll_elem(p, '.');
+	REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+	return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ */
+static char			/* value of collating element */
+p_b_coll_elem(struct parse *p,
+    int endc)			/* name ended by endc,']' */
+{
+	char *sp = p->next;
+	struct cname *cp;
+	int len;
+
+	while (MORE() && !SEETWO(endc, ']'))
+		NEXT();
+	if (!MORE()) {
+		SETERROR(REG_EBRACK);
+		return(0);
+	}
+	len = p->next - sp;
+	for (cp = cnames; cp->name != NULL; cp++)
+		if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+			return(cp->code);	/* known name */
+	if (len == 1)
+		return(*sp);	/* single character */
+	SETERROR(REG_ECOLLATE);			/* neither */
+	return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ */
+static char			/* if no counterpart, return ch */
+othercase(int ch)
+{
+	ch = (uch)ch;
+	assert(isalpha(ch));
+	if (isupper(ch))
+		return ((uch)tolower(ch));
+	else if (islower(ch))
+		return ((uch)toupper(ch));
+	else			/* peculiar, but could happen */
+		return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(struct parse *p, int ch)
+{
+	char *oldnext = p->next;
+	char *oldend = p->end;
+	char bracket[3];
+
+	ch = (uch)ch;
+	assert(othercase(ch) != ch);	/* p_bracket() would recurse */
+	p->next = bracket;
+	p->end = bracket+2;
+	bracket[0] = ch;
+	bracket[1] = ']';
+	bracket[2] = '\0';
+	p_bracket(p);
+	assert(p->next == bracket+2);
+	p->next = oldnext;
+	p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ */
+static void
+ordinary(struct parse *p, int ch)
+{
+	cat_t *cap = p->g->categories;
+
+	if ((p->g->cflags&REG_ICASE) && isalpha((uch)ch) && othercase(ch) != ch)
+		bothcases(p, ch);
+	else {
+		EMIT(OCHAR, (uch)ch);
+		if (cap[ch] == 0)
+			cap[ch] = p->g->ncategories++;
+	}
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(struct parse *p)
+{
+	char *oldnext = p->next;
+	char *oldend = p->end;
+	char bracket[4];
+
+	p->next = bracket;
+	p->end = bracket+3;
+	bracket[0] = '^';
+	bracket[1] = '\n';
+	bracket[2] = ']';
+	bracket[3] = '\0';
+	p_bracket(p);
+	assert(p->next == bracket+3);
+	p->next = oldnext;
+	p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ */
+static void
+repeat(struct parse *p,
+    sopno start,		/* operand from here to end of strip */
+    int from,			/* repeated from this number */
+    int to)			/* to this number of times (maybe INFINITY) */
+{
+	sopno finish = HERE();
+#	define	N	2
+#	define	INF	3
+#	define	REP(f, t)	((f)*8 + (t))
+#	define	MAP(n)	(((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+	sopno copy;
+
+	if (p->error != 0)	/* head off possible runaway recursion */
+		return;
+
+	assert(from <= to);
+
+	switch (REP(MAP(from), MAP(to))) {
+	case REP(0, 0):			/* must be user doing this */
+		DROP(finish-start);	/* drop the operand */
+		break;
+	case REP(0, 1):			/* as x{1,1}? */
+	case REP(0, N):			/* as x{1,n}? */
+	case REP(0, INF):		/* as x{1,}? */
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, start);		/* offset is wrong... */
+		repeat(p, start+1, 1, to);
+		ASTERN(OOR1, start);
+		AHEAD(start);			/* ... fix it */
+		EMIT(OOR2, 0);
+		AHEAD(THERE());
+		ASTERN(O_CH, THERETHERE());
+		break;
+	case REP(1, 1):			/* trivial case */
+		/* done */
+		break;
+	case REP(1, N):			/* as x?x{1,n-1} */
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, start);
+		ASTERN(OOR1, start);
+		AHEAD(start);
+		EMIT(OOR2, 0);			/* offset very wrong... */
+		AHEAD(THERE());			/* ...so fix it */
+		ASTERN(O_CH, THERETHERE());
+		copy = dupl(p, start+1, finish+1);
+		assert(copy == finish+4);
+		repeat(p, copy, 1, to-1);
+		break;
+	case REP(1, INF):		/* as x+ */
+		INSERT(OPLUS_, start);
+		ASTERN(O_PLUS, start);
+		break;
+	case REP(N, N):			/* as xx{m-1,n-1} */
+		copy = dupl(p, start, finish);
+		repeat(p, copy, from-1, to-1);
+		break;
+	case REP(N, INF):		/* as xx{n-1,INF} */
+		copy = dupl(p, start, finish);
+		repeat(p, copy, from-1, to);
+		break;
+	default:			/* "can't happen" */
+		SETERROR(REG_ASSERT);	/* just in case */
+		break;
+	}
+}
+
+/*
+ - seterr - set an error condition
+ */
+static int			/* useless but makes type checking happy */
+seterr(struct parse *p, int e)
+{
+	if (p->error == 0)	/* keep earliest error condition */
+		p->error = e;
+	p->next = nuls;		/* try to bring things to a halt */
+	p->end = nuls;
+	return(0);		/* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ */
+static cset *
+allocset(struct parse *p)
+{
+	int no = p->g->ncsets++;
+	size_t nc;
+	size_t nbytes;
+	cset *cs;
+	size_t css = (size_t)p->g->csetsize;
+	int i;
+
+	if (no >= p->ncsalloc) {	/* need another column of space */
+		void *ptr;
+
+		p->ncsalloc += CHAR_BIT;
+		nc = p->ncsalloc;
+		assert(nc % CHAR_BIT == 0);
+		nbytes = nc / CHAR_BIT * css;
+
+		ptr = (cset *)realloc((char *)p->g->sets, nc * sizeof(cset));
+		if (ptr == NULL)
+			goto nomem;
+		p->g->sets = ptr;
+
+		ptr = (uch *)realloc((char *)p->g->setbits, nbytes);
+		if (ptr == NULL)
+			goto nomem;
+		p->g->setbits = ptr;
+
+		for (i = 0; i < no; i++)
+			p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+
+		(void) memset((char *)p->g->setbits + (nbytes - css), 0, css);
+	}
+	/* XXX should not happen */
+	if (p->g->sets == NULL || p->g->setbits == NULL)
+		goto nomem;
+
+	cs = &p->g->sets[no];
+	cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+	cs->mask = 1 << ((no) % CHAR_BIT);
+	cs->hash = 0;
+	cs->smultis = 0;
+	cs->multis = NULL;
+
+	return(cs);
+nomem:
+	free(p->g->sets);
+	p->g->sets = NULL;
+	free(p->g->setbits);
+	p->g->setbits = NULL;
+
+	SETERROR(REG_ESPACE);
+	/* caller's responsibility not to do set ops */
+	return(NULL);
+}
+
+/*
+ - freeset - free a now-unused set
+ */
+static void
+freeset(struct parse *p, cset *cs)
+{
+	int i;
+	cset *top = &p->g->sets[p->g->ncsets];
+	size_t css = (size_t)p->g->csetsize;
+
+	for (i = 0; i < css; i++)
+		CHsub(cs, i);
+	if (cs == top-1)	/* recover only the easy case */
+		p->g->ncsets--;
+}
+
+/*
+ - freezeset - final processing on a set of characters
+ *
+ * The main task here is merging identical sets.  This is usually a waste
+ * of time (although the hash code minimizes the overhead), but can win
+ * big if REG_ICASE is being used.  REG_ICASE, by the way, is why the hash
+ * is done using addition rather than xor -- all ASCII [aA] sets xor to
+ * the same value!
+ */
+static int			/* set number */
+freezeset(struct parse *p, cset *cs)
+{
+	uch h = cs->hash;
+	int i;
+	cset *top = &p->g->sets[p->g->ncsets];
+	cset *cs2;
+	size_t css = (size_t)p->g->csetsize;
+
+	/* look for an earlier one which is the same */
+	for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
+		if (cs2->hash == h && cs2 != cs) {
+			/* maybe */
+			for (i = 0; i < css; i++)
+				if (!!CHIN(cs2, i) != !!CHIN(cs, i))
+					break;		/* no */
+			if (i == css)
+				break;			/* yes */
+		}
+
+	if (cs2 < top) {	/* found one */
+		freeset(p, cs);
+		cs = cs2;
+	}
+
+	return((int)(cs - p->g->sets));
+}
+
+/*
+ - firstch - return first character in a set (which must have at least one)
+ */
+static int			/* character; there is no "none" value */
+firstch(struct parse *p, cset *cs)
+{
+	int i;
+	size_t css = (size_t)p->g->csetsize;
+
+	for (i = 0; i < css; i++)
+		if (CHIN(cs, i))
+			return((char)i);
+	assert(never);
+	return(0);		/* arbitrary */
+}
+
+/*
+ - nch - number of characters in a set
+ */
+static int
+nch(struct parse *p, cset *cs)
+{
+	int i;
+	size_t css = (size_t)p->g->csetsize;
+	int n = 0;
+
+	for (i = 0; i < css; i++)
+		if (CHIN(cs, i))
+			n++;
+	return(n);
+}
+
+/*
+ - mcadd - add a collating element to a cset
+ */
+static void
+mcadd( struct parse *p, cset *cs, char *cp)
+{
+	size_t oldend = cs->smultis;
+	void *np;
+
+	cs->smultis += strlen(cp) + 1;
+	np = realloc(cs->multis, cs->smultis);
+	if (np == NULL) {
+		if (cs->multis)
+			free(cs->multis);
+		cs->multis = NULL;
+		SETERROR(REG_ESPACE);
+		return;
+	}
+	cs->multis = np;
+
+	strlcpy(cs->multis + oldend - 1, cp, cs->smultis - oldend + 1);
+}
+
+/*
+ - mcinvert - invert the list of collating elements in a cset
+ *
+ * This would have to know the set of possibilities.  Implementation
+ * is deferred.
+ */
+/* ARGSUSED */
+static void
+mcinvert(struct parse *p, cset *cs)
+{
+	assert(cs->multis == NULL);	/* xxx */
+}
+
+/*
+ - mccase - add case counterparts of the list of collating elements in a cset
+ *
+ * This would have to know the set of possibilities.  Implementation
+ * is deferred.
+ */
+/* ARGSUSED */
+static void
+mccase(struct parse *p, cset *cs)
+{
+	assert(cs->multis == NULL);	/* xxx */
+}
+
+/*
+ - isinsets - is this character in any sets?
+ */
+static int			/* predicate */
+isinsets(struct re_guts *g, int c)
+{
+	uch *col;
+	int i;
+	int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+	unsigned uc = (uch)c;
+
+	for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+		if (col[uc] != 0)
+			return(1);
+	return(0);
+}
+
+/*
+ - samesets - are these two characters in exactly the same sets?
+ */
+static int			/* predicate */
+samesets(struct re_guts *g, int c1, int c2)
+{
+	uch *col;
+	int i;
+	int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+	unsigned uc1 = (uch)c1;
+	unsigned uc2 = (uch)c2;
+
+	for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+		if (col[uc1] != col[uc2])
+			return(0);
+	return(1);
+}
+
+/*
+ - categorize - sort out character categories
+ */
+static void
+categorize(struct parse *p, struct re_guts *g)
+{
+	cat_t *cats = g->categories;
+	int c;
+	int c2;
+	cat_t cat;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+		if (cats[c] == 0 && isinsets(g, c)) {
+			cat = g->ncategories++;
+			cats[c] = cat;
+			for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+				if (cats[c2] == 0 && samesets(g, c, c2))
+					cats[c2] = cat;
+		}
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ */
+static sopno			/* start of duplicate */
+dupl(struct parse *p,
+    sopno start,		/* from here */
+    sopno finish)		/* to this less one */
+{
+	sopno ret = HERE();
+	sopno len = finish - start;
+
+	assert(finish >= start);
+	if (len == 0)
+		return(ret);
+	enlarge(p, p->ssize + len);	/* this many unexpected additions */
+	assert(p->ssize >= p->slen + len);
+	(void) memcpy((char *)(p->strip + p->slen),
+		(char *)(p->strip + start), (size_t)len*sizeof(sop));
+	p->slen += len;
+	return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures.  Maybe later.
+ */
+static void
+doemit(struct parse *p, sop op, size_t opnd)
+{
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	/* deal with oversize operands ("can't happen", more or less) */
+	assert(opnd < 1<<OPSHIFT);
+
+	/* deal with undersized strip */
+	if (p->slen >= p->ssize)
+		enlarge(p, (p->ssize+1) / 2 * 3);	/* +50% */
+	assert(p->slen < p->ssize);
+
+	/* finally, it's all reduced to the easy case */
+	p->strip[p->slen++] = SOP(op, opnd);
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ */
+static void
+doinsert(struct parse *p, sop op, size_t opnd, sopno pos)
+{
+	sopno sn;
+	sop s;
+	int i;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	sn = HERE();
+	EMIT(op, opnd);		/* do checks, ensure space */
+	assert(HERE() == sn+1);
+	s = p->strip[sn];
+
+	/* adjust paren pointers */
+	assert(pos > 0);
+	for (i = 1; i < NPAREN; i++) {
+		if (p->pbegin[i] >= pos) {
+			p->pbegin[i]++;
+		}
+		if (p->pend[i] >= pos) {
+			p->pend[i]++;
+		}
+	}
+
+	memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+						(HERE()-pos-1)*sizeof(sop));
+	p->strip[pos] = s;
+}
+
+/*
+ - dofwd - complete a forward reference
+ */
+static void
+dofwd(struct parse *p, sopno pos, sop value)
+{
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	assert(value < 1<<OPSHIFT);
+	p->strip[pos] = OP(p->strip[pos]) | value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ */
+static void
+enlarge(struct parse *p, sopno size)
+{
+	sop *sp;
+
+	if (p->ssize >= size)
+		return;
+
+	sp = (sop *)realloc(p->strip, size*sizeof(sop));
+	if (sp == NULL) {
+		SETERROR(REG_ESPACE);
+		return;
+	}
+	p->strip = sp;
+	p->ssize = size;
+}
+
+/*
+ - stripsnug - compact the strip
+ */
+static void
+stripsnug(struct parse *p, struct re_guts *g)
+{
+	g->nstates = p->slen;
+	g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop));
+	if (g->strip == NULL) {
+		SETERROR(REG_ESPACE);
+		g->strip = p->strip;
+	}
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences.  Someday.  This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(struct parse *p, struct re_guts *g)
+{
+	sop *scan;
+	sop *start;    /* start initialized in the default case, after that */
+	sop *newstart; /* newstart was initialized in the OCHAR case */
+	sopno newlen;
+	sop s;
+	char *cp;
+	sopno i;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	/* find the longest OCHAR sequence in strip */
+	newlen = 0;
+	scan = g->strip + 1;
+	do {
+		s = *scan++;
+		switch (OP(s)) {
+		case OCHAR:		/* sequence member */
+			if (newlen == 0)		/* new sequence */
+				newstart = scan - 1;
+			newlen++;
+			break;
+		case OPLUS_:		/* things that don't break one */
+		case OLPAREN:
+		case ORPAREN:
+			break;
+		case OQUEST_:		/* things that must be skipped */
+		case OCH_:
+			scan--;
+			do {
+				scan += OPND(s);
+				s = *scan;
+				/* assert() interferes w debug printouts */
+				if (OP(s) != O_QUEST && OP(s) != O_CH &&
+							OP(s) != OOR2) {
+					g->iflags |= BAD;
+					return;
+				}
+			} while (OP(s) != O_QUEST && OP(s) != O_CH);
+			/* fallthrough */
+		default:		/* things that break a sequence */
+			if (newlen > g->mlen) {		/* ends one */
+				start = newstart;
+				g->mlen = newlen;
+			}
+			newlen = 0;
+			break;
+		}
+	} while (OP(s) != OEND);
+
+	if (g->mlen == 0)		/* there isn't one */
+		return;
+
+	/* turn it into a character string */
+	g->must = malloc((size_t)g->mlen + 1);
+	if (g->must == NULL) {		/* argh; just forget it */
+		g->mlen = 0;
+		return;
+	}
+	cp = g->must;
+	scan = start;
+	for (i = g->mlen; i > 0; i--) {
+		while (OP(s = *scan++) != OCHAR)
+			continue;
+		assert(cp < g->must + g->mlen);
+		*cp++ = (char)OPND(s);
+	}
+	assert(cp == g->must + g->mlen);
+	*cp++ = '\0';		/* just on general principles */
+}
+
+/*
+ - pluscount - count + nesting
+ */
+static sopno			/* nesting depth */
+pluscount(struct parse *p, struct re_guts *g)
+{
+	sop *scan;
+	sop s;
+	sopno plusnest = 0;
+	sopno maxnest = 0;
+
+	if (p->error != 0)
+		return(0);	/* there may not be an OEND */
+
+	scan = g->strip + 1;
+	do {
+		s = *scan++;
+		switch (OP(s)) {
+		case OPLUS_:
+			plusnest++;
+			break;
+		case O_PLUS:
+			if (plusnest > maxnest)
+				maxnest = plusnest;
+			plusnest--;
+			break;
+		}
+	} while (OP(s) != OEND);
+	if (plusnest != 0)
+		g->iflags |= BAD;
+	return(maxnest);
+}
diff --git a/libc/regex/regerror.c b/libc/regex/regerror.c
new file mode 100644
index 0000000..894a939
--- /dev/null
+++ b/libc/regex/regerror.c
@@ -0,0 +1,130 @@
+/*	$OpenBSD: regerror.c,v 1.13 2005/08/05 13:03:00 espie Exp $ */
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)regerror.c	8.4 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+
+static char *regatoi(const regex_t *, char *, int);
+
+static const struct rerr {
+	int code;
+	char *name;
+	char *explain;
+} rerrs[] = {
+	{ REG_NOMATCH,	"REG_NOMATCH",	"regexec() failed to match" },
+	{ REG_BADPAT,	"REG_BADPAT",	"invalid regular expression" },
+	{ REG_ECOLLATE,	"REG_ECOLLATE",	"invalid collating element" },
+	{ REG_ECTYPE,	"REG_ECTYPE",	"invalid character class" },
+	{ REG_EESCAPE,	"REG_EESCAPE",	"trailing backslash (\\)" },
+	{ REG_ESUBREG,	"REG_ESUBREG",	"invalid backreference number" },
+	{ REG_EBRACK,	"REG_EBRACK",	"brackets ([ ]) not balanced" },
+	{ REG_EPAREN,	"REG_EPAREN",	"parentheses not balanced" },
+	{ REG_EBRACE,	"REG_EBRACE",	"braces not balanced" },
+	{ REG_BADBR,	"REG_BADBR",	"invalid repetition count(s)" },
+	{ REG_ERANGE,	"REG_ERANGE",	"invalid character range" },
+	{ REG_ESPACE,	"REG_ESPACE",	"out of memory" },
+	{ REG_BADRPT,	"REG_BADRPT",	"repetition-operator operand invalid" },
+	{ REG_EMPTY,	"REG_EMPTY",	"empty (sub)expression" },
+	{ REG_ASSERT,	"REG_ASSERT",	"\"can't happen\" -- you found a bug" },
+	{ REG_INVARG,	"REG_INVARG",	"invalid argument to regex routine" },
+	{ 0,		"",		"*** unknown regexp error code ***" }
+};
+
+/*
+ - regerror - the interface to error numbers
+ = extern size_t regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+	struct rerr *r;
+	size_t len;
+	int target = errcode &~ REG_ITOA;
+	char *s;
+	char convbuf[50];
+
+	if (errcode == REG_ATOI)
+		s = regatoi(preg, convbuf, sizeof convbuf);
+	else {
+		for (r = rerrs; r->code != 0; r++)
+			if (r->code == target)
+				break;
+
+		if (errcode&REG_ITOA) {
+			if (r->code != 0) {
+				assert(strlen(r->name) < sizeof(convbuf));
+				(void) strlcpy(convbuf, r->name, sizeof convbuf);
+			} else
+				(void)snprintf(convbuf, sizeof convbuf,
+				    "REG_0x%x", target);
+			s = convbuf;
+		} else
+			s = r->explain;
+	}
+
+	len = strlen(s) + 1;
+	if (errbuf_size > 0) {
+		strlcpy(errbuf, s, errbuf_size);
+	}
+
+	return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ */
+static char *
+regatoi(const regex_t *preg, char *localbuf, int localbufsize)
+{
+	struct rerr *r;
+
+	for (r = rerrs; r->code != 0; r++)
+		if (strcmp(r->name, preg->re_endp) == 0)
+			break;
+	if (r->code == 0)
+		return("0");
+
+	(void)snprintf(localbuf, localbufsize, "%d", r->code);
+	return(localbuf);
+}
diff --git a/libc/regex/regex2.h b/libc/regex/regex2.h
new file mode 100644
index 0000000..15e15bc
--- /dev/null
+++ b/libc/regex/regex2.h
@@ -0,0 +1,157 @@
+/*	$OpenBSD: regex2.h,v 1.7 2004/11/30 17:04:23 otto Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)regex2.h	8.4 (Berkeley) 3/20/94
+ */
+
+/*
+ * internals of regex_t
+ */
+#define	MAGIC1	((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker.  (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination.  Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ *   OOR1 and OOR2 are respectively the end and the beginning of one of
+ *   the branches.  Note that there is an implicit OOR2 following OCH_
+ *   and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef unsigned long sop;	/* strip operator */
+typedef long sopno;
+#define	OPRMASK	0xf8000000LU
+#define	OPDMASK	0x07ffffffLU
+#define	OPSHIFT	((unsigned)27)
+#define	OP(n)	((n)&OPRMASK)
+#define	OPND(n)	((n)&OPDMASK)
+#define	SOP(op, opnd)	((op)|(opnd))
+/* operators			   meaning	operand			*/
+/*						(back, fwd are offsets)	*/
+#define	OEND	(1LU<<OPSHIFT)	/* endmarker	-			*/
+#define	OCHAR	(2LU<<OPSHIFT)	/* character	unsigned char		*/
+#define	OBOL	(3LU<<OPSHIFT)	/* left anchor	-			*/
+#define	OEOL	(4LU<<OPSHIFT)	/* right anchor	-			*/
+#define	OANY	(5LU<<OPSHIFT)	/* .		-			*/
+#define	OANYOF	(6LU<<OPSHIFT)	/* [...]	set number		*/
+#define	OBACK_	(7LU<<OPSHIFT)	/* begin \d	paren number		*/
+#define	O_BACK	(8LU<<OPSHIFT)	/* end \d	paren number		*/
+#define	OPLUS_	(9LU<<OPSHIFT)	/* + prefix	fwd to suffix		*/
+#define	O_PLUS	(10LU<<OPSHIFT)	/* + suffix	back to prefix		*/
+#define	OQUEST_	(11LU<<OPSHIFT)	/* ? prefix	fwd to suffix		*/
+#define	O_QUEST	(12LU<<OPSHIFT)	/* ? suffix	back to prefix		*/
+#define	OLPAREN	(13LU<<OPSHIFT)	/* (		fwd to )		*/
+#define	ORPAREN	(14LU<<OPSHIFT)	/* )		back to (		*/
+#define	OCH_	(15LU<<OPSHIFT)	/* begin choice	fwd to OOR2		*/
+#define	OOR1	(16LU<<OPSHIFT)	/* | pt. 1	back to OOR1 or OCH_	*/
+#define	OOR2	(17LU<<OPSHIFT)	/* | pt. 2	fwd to OOR2 or O_CH	*/
+#define	O_CH	(18LU<<OPSHIFT)	/* end choice	back to OOR1		*/
+#define	OBOW	(19LU<<OPSHIFT)	/* begin word	-			*/
+#define	OEOW	(20LU<<OPSHIFT)	/* end word	-			*/
+
+/*
+ * Structure for [] character-set representation.  Character sets are
+ * done as bit vectors, grouped 8 to a byte vector for compactness.
+ * The individual set therefore has both a pointer to the byte vector
+ * and a mask to pick out the relevant bit of each byte.  A hash code
+ * simplifies testing whether two sets could be identical.
+ *
+ * This will get trickier for multicharacter collating elements.  As
+ * preliminary hooks for dealing with such things, we also carry along
+ * a string of multi-character elements, and decide the size of the
+ * vectors at run time.
+ */
+typedef struct {
+	uch *ptr;		/* -> uch [csetsize] */
+	uch mask;		/* bit within array */
+	uch hash;		/* hash code */
+	size_t smultis;
+	char *multis;		/* -> char[smulti]  ab\0cd\0ef\0\0 */
+} cset;
+/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
+#define	CHadd(cs, c)	((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c))
+#define	CHsub(cs, c)	((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c))
+#define	CHIN(cs, c)	((cs)->ptr[(uch)(c)] & (cs)->mask)
+#define	MCadd(p, cs, cp)	mcadd(p, cs, cp)	/* regcomp() internal fns */
+#define	MCsub(p, cs, cp)	mcsub(p, cs, cp)
+#define	MCin(p, cs, cp)	mcin(p, cs, cp)
+
+/* stuff for character categories */
+typedef unsigned char cat_t;
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+	int magic;
+#		define	MAGIC2	((('R'^0200)<<8)|'E')
+	sop *strip;		/* malloced area for strip */
+	int csetsize;		/* number of bits in a cset vector */
+	int ncsets;		/* number of csets in use */
+	cset *sets;		/* -> cset [ncsets] */
+	uch *setbits;		/* -> uch[csetsize][ncsets/CHAR_BIT] */
+	int cflags;		/* copy of regcomp() cflags argument */
+	sopno nstates;		/* = number of sops */
+	sopno firststate;	/* the initial OEND (normally 0) */
+	sopno laststate;	/* the final OEND */
+	int iflags;		/* internal flags */
+#		define	USEBOL	01	/* used ^ */
+#		define	USEEOL	02	/* used $ */
+#		define	BAD	04	/* something wrong */
+	int nbol;		/* number of ^ used */
+	int neol;		/* number of $ used */
+	int ncategories;	/* how many character categories */
+	cat_t *categories;	/* ->catspace[-CHAR_MIN] */
+	char *must;		/* match must contain this string */
+	int mlen;		/* length of must */
+	size_t nsub;		/* copy of re_nsub */
+	int backrefs;		/* does it use back references? */
+	sopno nplus;		/* how deep does it nest +s? */
+	/* catspace must be last */
+	cat_t catspace[1];	/* actually [NC] */
+};
+
+/* misc utilities */
+#define	OUT	(CHAR_MAX+1)	/* a non-character value */
+#define	ISWORD(c)	(isalnum(c) || (c) == '_')
diff --git a/libc/regex/regexec.c b/libc/regex/regexec.c
new file mode 100644
index 0000000..7b3bfc7
--- /dev/null
+++ b/libc/regex/regexec.c
@@ -0,0 +1,160 @@
+/*	$OpenBSD: regexec.c,v 1.11 2005/08/05 13:03:00 espie Exp $ */
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)regexec.c	8.3 (Berkeley) 3/20/94
+ */
+
+/*
+ * the outer shell of regexec()
+ *
+ * This file includes engine.c *twice*, after muchos fiddling with the
+ * macros that code uses.  This lets the same code operate on two different
+ * representations for state sets.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+/* macros for manipulating states, small version */
+#define	states	long
+#define	states1	states		/* for later use in regexec() decision */
+#define	CLEAR(v)	((v) = 0)
+#define	SET0(v, n)	((v) &= ~((unsigned long)1 << (n)))
+#define	SET1(v, n)	((v) |= (unsigned long)1 << (n))
+#define	ISSET(v, n)	(((v) & ((unsigned long)1 << (n))) != 0)
+#define	ASSIGN(d, s)	((d) = (s))
+#define	EQ(a, b)	((a) == (b))
+#define	STATEVARS	long dummy	/* dummy version */
+#define	STATESETUP(m, n)	/* nothing */
+#define	STATETEARDOWN(m)	/* nothing */
+#define	SETUP(v)	((v) = 0)
+#define	onestate	long
+#define	INIT(o, n)	((o) = (unsigned long)1 << (n))
+#define	INC(o)		((o) <<= 1)
+#define	ISSTATEIN(v, o)	(((v) & (o)) != 0)
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define	FWD(dst, src, n)	((dst) |= ((unsigned long)(src)&(here)) << (n))
+#define	BACK(dst, src, n)	((dst) |= ((unsigned long)(src)&(here)) >> (n))
+#define	ISSETBACK(v, n)		(((v) & ((unsigned long)here >> (n))) != 0)
+/* function names */
+#define SNAMES			/* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef	states
+#undef	CLEAR
+#undef	SET0
+#undef	SET1
+#undef	ISSET
+#undef	ASSIGN
+#undef	EQ
+#undef	STATEVARS
+#undef	STATESETUP
+#undef	STATETEARDOWN
+#undef	SETUP
+#undef	onestate
+#undef	INIT
+#undef	INC
+#undef	ISSTATEIN
+#undef	FWD
+#undef	BACK
+#undef	ISSETBACK
+#undef	SNAMES
+
+/* macros for manipulating states, large version */
+#define	states	char *
+#define	CLEAR(v)	memset(v, 0, m->g->nstates)
+#define	SET0(v, n)	((v)[n] = 0)
+#define	SET1(v, n)	((v)[n] = 1)
+#define	ISSET(v, n)	((v)[n])
+#define	ASSIGN(d, s)	memcpy(d, s, m->g->nstates)
+#define	EQ(a, b)	(memcmp(a, b, m->g->nstates) == 0)
+#define	STATEVARS	long vn; char *space
+#define	STATESETUP(m, nv)	{ (m)->space = malloc((nv)*(m)->g->nstates); \
+				if ((m)->space == NULL) return(REG_ESPACE); \
+				(m)->vn = 0; }
+#define	STATETEARDOWN(m)	{ free((m)->space); }
+#define	SETUP(v)	((v) = &m->space[m->vn++ * m->g->nstates])
+#define	onestate	long
+#define	INIT(o, n)	((o) = (n))
+#define	INC(o)	((o)++)
+#define	ISSTATEIN(v, o)	((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define	FWD(dst, src, n)	((dst)[here+(n)] |= (src)[here])
+#define	BACK(dst, src, n)	((dst)[here-(n)] |= (src)[here])
+#define	ISSETBACK(v, n)	((v)[here - (n)])
+/* function names */
+#define	LNAMES			/* flag */
+
+#include "engine.c"
+
+/*
+ - regexec - interface for matching
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call.  Also, by this point the matchers
+ * have been prototyped.
+ */
+int				/* 0 success, REG_NOMATCH failure */
+regexec(const regex_t *preg, const char *string, size_t nmatch,
+    regmatch_t pmatch[], int eflags)
+{
+	struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+#	define	GOODFLAGS(f)	(f)
+#else
+#	define	GOODFLAGS(f)	((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+	if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+		return(REG_BADPAT);
+	assert(!(g->iflags&BAD));
+	if (g->iflags&BAD)		/* backstop for no-debug case */
+		return(REG_BADPAT);
+	eflags = GOODFLAGS(eflags);
+
+	if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags&REG_LARGE))
+		return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
+	else
+		return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
+}
diff --git a/libc/regex/regfree.c b/libc/regex/regfree.c
new file mode 100644
index 0000000..a57eba3
--- /dev/null
+++ b/libc/regex/regfree.c
@@ -0,0 +1,71 @@
+/*	$OpenBSD: regfree.c,v 1.7 2005/08/05 13:03:00 espie Exp $ */
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)regfree.c	8.3 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - regfree - free everything
+ */
+void
+regfree(regex_t *preg)
+{
+	struct re_guts *g;
+
+	if (preg->re_magic != MAGIC1)	/* oops */
+		return;			/* nice to complain, but hard */
+
+	g = preg->re_g;
+	if (g == NULL || g->magic != MAGIC2)	/* oops again */
+		return;
+	preg->re_magic = 0;		/* mark it invalid */
+	g->magic = 0;			/* mark it invalid */
+
+	if (g->strip != NULL)
+		free((char *)g->strip);
+	if (g->sets != NULL)
+		free((char *)g->sets);
+	if (g->setbits != NULL)
+		free((char *)g->setbits);
+	if (g->must != NULL)
+		free(g->must);
+	free((char *)g);
+}
diff --git a/libc/regex/utils.h b/libc/regex/utils.h
new file mode 100644
index 0000000..3e184fc
--- /dev/null
+++ b/libc/regex/utils.h
@@ -0,0 +1,55 @@
+/*	$OpenBSD: utils.h,v 1.4 2003/06/02 20:18:36 millert Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * 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.
+ *
+ *	@(#)utils.h	8.3 (Berkeley) 3/20/94
+ */
+
+/* utility definitions */
+#define	DUPMAX		255
+#define	INFINITY	(DUPMAX + 1)
+#define	NC		(CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define	NDEBUG	/* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define	memmove(d, s, c)	bcopy(s, d, c)
+#endif
diff --git a/libc/stdlib/strtod.c b/libc/stdlib/strtod.c
index 7fb7112..b1f5868 100644
--- a/libc/stdlib/strtod.c
+++ b/libc/stdlib/strtod.c
@@ -378,6 +378,24 @@
 #endif
 #endif
 
+/* Special value used to indicate an invalid Bigint value,
+ * e.g. when a memory allocation fails. The idea is that we
+ * want to avoid introducing NULL checks everytime a bigint
+ * computation is performed. Also the NULL value can also be
+ * already used to indicate "value not initialized yet" and
+ * returning NULL might alter the execution code path in
+ * case of OOM.
+ */
+#define  BIGINT_INVALID   ((Bigint *)&bigint_invalid_value)
+
+static const Bigint bigint_invalid_value;
+
+
+/* Return BIGINT_INVALID on allocation failure.
+ *
+ * Most of the code here depends on the fact that this function
+ * never returns NULL.
+ */
  static Bigint *
 Balloc
 #ifdef KR_headers
@@ -397,11 +415,15 @@
 	else {
 		x = 1 << k;
 		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
+		if (rv == NULL) {
+		        rv = BIGINT_INVALID;
+			goto EXIT;
+		}
 		rv->k = k;
 		rv->maxwds = x;
 		}
 	rv->sign = rv->wds = 0;
-
+EXIT:
 	mutex_unlock(&freelist_mutex);
 
 	return rv;
@@ -415,7 +437,7 @@
 	(Bigint *v)
 #endif
 {
-	if (v) {
+	if (v && v != BIGINT_INVALID) {
 		mutex_lock(&freelist_mutex);
 
 		v->next = freelist[v->k];
@@ -425,8 +447,23 @@
 		}
 	}
 
-#define Bcopy(x,y) memcpy(&x->sign, &y->sign, \
-    y->wds*sizeof(Long) + 2*sizeof(int))
+#define Bcopy_valid(x,y) memcpy(&(x)->sign, &(y)->sign, \
+    (y)->wds*sizeof(Long) + 2*sizeof(int))
+
+#define Bcopy(x,y)  Bcopy_ptr(&(x),(y))
+
+ static void
+Bcopy_ptr(Bigint **px, Bigint *y)
+{
+	if (*px == BIGINT_INVALID)
+		return; /* no space to store copy */
+	if (y == BIGINT_INVALID) {
+		Bfree(*px); /* invalid input */
+		*px = BIGINT_INVALID;
+	} else {
+		Bcopy_valid(*px,y);
+	}
+}
 
  static Bigint *
 multadd
@@ -443,6 +480,9 @@
 #endif
 	Bigint *b1;
 
+	if (b == BIGINT_INVALID)
+		return b;
+
 	wds = b->wds;
 	x = b->x;
 	i = 0;
@@ -463,7 +503,11 @@
 	if (a) {
 		if (wds >= b->maxwds) {
 			b1 = Balloc(b->k+1);
-			Bcopy(b1, b);
+			if (b1 == BIGINT_INVALID) {
+				Bfree(b);
+				return b1;
+			}
+			Bcopy_valid(b1, b);
 			Bfree(b);
 			b = b1;
 			}
@@ -489,10 +533,15 @@
 	for(k = 0, y = 1; x > y; y <<= 1, k++) ;
 #ifdef Pack_32
 	b = Balloc(k);
+	if (b == BIGINT_INVALID)
+		return b;
 	b->x[0] = y9;
 	b->wds = 1;
 #else
 	b = Balloc(k+1);
+	if (b == BIGINT_INVALID)
+		return b;
+
 	b->x[0] = y9 & 0xffff;
 	b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
 #endif
@@ -604,8 +653,10 @@
 	Bigint *b;
 
 	b = Balloc(1);
-	b->x[0] = i;
-	b->wds = 1;
+	if (b != BIGINT_INVALID) {
+		b->x[0] = i;
+		b->wds = 1;
+		}
 	return b;
 	}
 
@@ -625,6 +676,9 @@
 	ULong z2;
 #endif
 
+	if (a == BIGINT_INVALID || b == BIGINT_INVALID)
+		return BIGINT_INVALID;
+
 	if (a->wds < b->wds) {
 		c = a;
 		a = b;
@@ -637,6 +691,8 @@
 	if (wc > a->maxwds)
 		k++;
 	c = Balloc(k);
+	if (c == BIGINT_INVALID)
+		return c;
 	for(x = c->x, xa = x + wc; x < xa; x++)
 		*x = 0;
 	xa = a->x;
@@ -711,6 +767,9 @@
 	int i;
 	static const int p05[3] = { 5, 25, 125 };
 
+	if (b == BIGINT_INVALID)
+		return b;
+
 	if ((i = k & 3) != 0)
 		b = multadd(b, p05[i-1], 0);
 
@@ -718,7 +777,12 @@
 		return b;
 	if (!(p5 = p5s)) {
 		/* first time */
-		p5 = p5s = i2b(625);
+		p5 = i2b(625);
+		if (p5 == BIGINT_INVALID) {
+			Bfree(b);
+			return p5;
+		}
+		p5s = p5;
 		p5->next = 0;
 		}
 	for(;;) {
@@ -730,7 +794,12 @@
 		if (!(k = (unsigned int) k >> 1))
 			break;
 		if (!(p51 = p5->next)) {
-			p51 = p5->next = mult(p5,p5);
+			p51 = mult(p5,p5);
+			if (p51 == BIGINT_INVALID) {
+				Bfree(b);
+				return p51;
+			}
+			p5->next = p51;
 			p51->next = 0;
 			}
 		p5 = p51;
@@ -750,6 +819,9 @@
 	Bigint *b1;
 	ULong *x, *x1, *xe, z;
 
+	if (b == BIGINT_INVALID)
+		return b;
+
 #ifdef Pack_32
 	n = (unsigned int)k >> 5;
 #else
@@ -760,6 +832,10 @@
 	for(i = b->maxwds; n1 > i; i <<= 1)
 		k1++;
 	b1 = Balloc(k1);
+	if (b1 == BIGINT_INVALID) {
+		Bfree(b);
+		return b1;
+	}
 	x1 = b1->x;
 	for(i = 0; i < n; i++)
 		*x1++ = 0;
@@ -809,6 +885,13 @@
 	ULong *xa, *xa0, *xb, *xb0;
 	int i, j;
 
+	if (a == BIGINT_INVALID || b == BIGINT_INVALID)
+#ifdef DEBUG
+		Bug("cmp called with a or b invalid");
+#else
+		return 0; /* equal - the best we can do right now */
+#endif
+
 	i = a->wds;
 	j = b->wds;
 #ifdef DEBUG
@@ -848,11 +931,16 @@
 	Long z;
 #endif
 
+	if (a == BIGINT_INVALID || b == BIGINT_INVALID)
+		return BIGINT_INVALID;
+
 	i = cmp(a,b);
 	if (!i) {
 		c = Balloc(0);
-		c->wds = 1;
-		c->x[0] = 0;
+		if (c != BIGINT_INVALID) {
+			c->wds = 1;
+			c->x[0] = 0;
+			}
 		return c;
 		}
 	if (i < 0) {
@@ -864,6 +952,8 @@
 	else
 		i = 0;
 	c = Balloc(a->k);
+	if (c == BIGINT_INVALID)
+		return c;
 	c->sign = i;
 	wa = a->wds;
 	xa = a->x;
@@ -972,6 +1062,9 @@
 #define d1 word1(d)
 #endif
 
+	if (a == BIGINT_INVALID)
+		return NAN;
+
 	xa0 = a->x;
 	xa = xa0 + a->wds;
 	y = *--xa;
@@ -1054,6 +1147,8 @@
 #else
 	b = Balloc(2);
 #endif
+	if (b == BIGINT_INVALID)
+		return b;
 	x = b->x;
 
 	z = d0 & Frac_mask;
@@ -1169,6 +1264,9 @@
 	_double da, db;
 	int k, ka, kb;
 
+	if (a == BIGINT_INVALID || b == BIGINT_INVALID)
+		return NAN; /* for lack of better value ? */
+
 	value(da) = b2d(a, &ka);
 	value(db) = b2d(b, &kb);
 #ifdef Pack_32
@@ -1821,6 +1919,9 @@
 	ULong si, zs;
 #endif
 
+	if (b == BIGINT_INVALID || S == BIGINT_INVALID)
+		return 0;
+
 	n = S->wds;
 #ifdef DEBUG
 	/*debug*/ if (b->wds > n)
@@ -2046,15 +2147,17 @@
 			!word1(d) && !(word0(d) & 0xfffff) ? "Infinity" :
 #endif
 				"NaN";
-        result = Balloc(strlen(s)+1);
-        s0 = (char *)(void *)result;
-        strcpy(s0, s);
-        if (rve)
-            *rve =
+		result = Balloc(strlen(s)+1);
+		if (result == BIGINT_INVALID)
+			return NULL;
+		s0 = (char *)(void *)result;
+		strcpy(s0, s);
+		if (rve)
+			*rve =
 #ifdef IEEE_Arith
-                s0[3] ? s0 + 8 :
+				s0[3] ? s0 + 8 :
 #endif
-                        s0 + 3;
+				s0 + 3;
 		return s0;
 		}
 #endif
@@ -2063,12 +2166,14 @@
 #endif
 	if (!value(d)) {
 		*decpt = 1;
-        result = Balloc(2);
-        s0 = (char *)(void *)result;
-        strcpy(s0, "0");
-        if (rve)
-            *rve = s0 + 1;
-        return s0;
+		result = Balloc(2);
+		if (result == BIGINT_INVALID)
+			return NULL;
+        	s0 = (char *)(void *)result;
+        	strcpy(s0, "0");
+        	if (rve)
+			*rve = s0 + 1;
+        	return s0;
 		}
 
 	b = d2b(value(d), &be, &bbits);
@@ -2199,6 +2304,10 @@
         // complicated way the block size need to be computed
         // buuurk....
 	result = Balloc(result_k);
+	if (result == BIGINT_INVALID) {
+		Bfree(b);
+		return NULL;
+	}
 	s = s0 = (char *)(void *)result;
 
 	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
@@ -2426,13 +2535,18 @@
 	 * and for all and pass them and a shift to quorem, so it
 	 * can do shifts and ors to compute the numerator for q.
 	 */
+	if (S == BIGINT_INVALID) {
+		i = 0;
+	} else {
 #ifdef Pack_32
-	if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
-		i = 32 - i;
+		if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
+			i = 32 - i;
 #else
-	if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
-		i = 16 - i;
+		if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+			i = 16 - i;
 #endif
+	}
+
 	if (i > 4) {
 		i -= 4;
 		b2 += i;
diff --git a/libc/stdlib/wchar.c b/libc/stdlib/wchar.c
index d805333..7722b34 100644
--- a/libc/stdlib/wchar.c
+++ b/libc/stdlib/wchar.c
@@ -227,6 +227,11 @@
     return len;
 }
 
+size_t mbstowcs(wchar_t *dst, const char *src, size_t len)
+{
+    return mbsrtowcs(dst, &src, len, NULL);
+}
+
 wint_t  putwc(wchar_t wc, FILE *stream)
 {
     return fputc((char)wc, stream);
@@ -339,6 +344,11 @@
     return len;
 }
 
+size_t wcstombs(char *dst, const wchar_t *src, size_t len)
+{
+    return wcsrtombs(dst, &src, len, NULL);
+}
+
 size_t wcsspn(const wchar_t *ws1, const wchar_t *ws2)
 {
     return strspn( (const char*)ws1, (const char*)ws2 );
diff --git a/libc/unistd/gethostname.c b/libc/unistd/gethostname.c
index 369d21e..5d3d7d9 100644
--- a/libc/unistd/gethostname.c
+++ b/libc/unistd/gethostname.c
@@ -41,11 +41,11 @@
         int  namelen = strlen(name.nodename);
 
         if ((int)buflen < namelen+1) {
-    errno = EINVAL;
+            errno = EINVAL;
             result = -1;
         } else {
             memcpy( buff, name.nodename, namelen+1 );
-  }
+        }
     }
     return result;
 }
diff --git a/libc/unistd/killpg.c b/libc/unistd/killpg.c
new file mode 100644
index 0000000..75b1ad9
--- /dev/null
+++ b/libc/unistd/killpg.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1989 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 <signal.h>
+#include <errno.h>
+
+/*
+ * Backwards-compatible killpg().
+ */
+int
+killpg(pid_t pgid, int sig)
+{
+	if (pgid == 1) {
+		errno = ESRCH;
+		return (-1);
+	}
+	return (kill(-pgid, sig));
+}
diff --git a/libc/unistd/ptsname_r.c b/libc/unistd/ptsname_r.c
index 1ed067b..2fa4c3d 100644
--- a/libc/unistd/ptsname_r.c
+++ b/libc/unistd/ptsname_r.c
@@ -32,7 +32,7 @@
 #include <errno.h>
 #include <string.h>
 
-char*  ptsname_r( int  fd, char*  buf, size_t  buflen)
+int    ptsname_r( int  fd, char*  buf, size_t  buflen)
 {
     unsigned int  pty_num;
     char          buff[64];
@@ -40,17 +40,19 @@
 
     if (buf == NULL) {
         errno = EINVAL;
-        return NULL;
+        return -1;
     }
 
-    if ( ioctl( fd, TIOCGPTN, &pty_num ) != 0 )
-        return NULL;
+    if ( ioctl( fd, TIOCGPTN, &pty_num ) != 0 ) {
+        errno = ENOTTY;
+        return -1;
+    }
 
     len = snprintf( buff, sizeof(buff), "/dev/pts/%u", pty_num );
     if (len+1 > (int)buflen) {
         errno = ERANGE;
-        return NULL;
+        return -1;
     }
     memcpy( buf, buff, len+1 );
-    return buf;
+    return 0;
 }
diff --git a/libc/unistd/seteuid.c b/libc/unistd/seteuid.c
index 42ee780..dd94932 100644
--- a/libc/unistd/seteuid.c
+++ b/libc/unistd/seteuid.c
@@ -29,5 +29,6 @@
 
 int seteuid(uid_t euid)
 {
-    return setresuid(-1, euid,-1);
+    cpuacct_add(euid);
+    return __setresuid(-1, euid,-1);
 }
diff --git a/libc/unistd/setresuid.c b/libc/unistd/setresuid.c
new file mode 100644
index 0000000..1964881
--- /dev/null
+++ b/libc/unistd/setresuid.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 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 <unistd.h>
+
+int setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+    cpuacct_add(euid);
+    return __setresuid(ruid, euid, suid);
+
+}
diff --git a/libc/unistd/setreuid.c b/libc/unistd/setreuid.c
new file mode 100644
index 0000000..04c2826
--- /dev/null
+++ b/libc/unistd/setreuid.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 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 <unistd.h>
+
+int setreuid(uid_t ruid, uid_t euid)
+{
+    cpuacct_add(euid);
+    return __setreuid(ruid, euid);
+}
diff --git a/libc/unistd/setuid.c b/libc/unistd/setuid.c
new file mode 100644
index 0000000..8ab637d
--- /dev/null
+++ b/libc/unistd/setuid.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 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 <unistd.h>
+
+int setuid(uid_t uid)
+{
+    cpuacct_add(uid);
+    return __setuid(uid);
+}
diff --git a/libc/unistd/usleep.c b/libc/unistd/usleep.c
index 75458b1..19e8ee8 100644
--- a/libc/unistd/usleep.c
+++ b/libc/unistd/usleep.c
@@ -28,7 +28,7 @@
 #include <time.h>
 #include <errno.h>
 
-void usleep(unsigned long usec)
+int usleep(unsigned long usec)
 {
   struct timespec ts;
 
@@ -43,10 +43,13 @@
 
   for (;;)
   {
-    if ( nanosleep( &ts, &ts ) >= 0 )
-        break;
+    if ( nanosleep( &ts, &ts ) == 0 )
+        return 0;
 
+    // We try again if the nanosleep failure is EINTR.
+    // The other possible failures are EINVAL (which we should pass through),
+    // and ENOSYS, which doesn't happen.
     if ( errno != EINTR )
-        break;
+        return -1;
   }
 }
diff --git a/linker/Android.mk b/linker/Android.mk
index 6c26eb3..4647c8f 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -4,6 +4,7 @@
 LOCAL_SRC_FILES:= \
 	arch/$(TARGET_ARCH)/begin.S \
 	linker.c \
+	linker_format.c \
 	rt.c \
 	dlfcn.c \
 	debugger.c \
@@ -13,7 +14,12 @@
 # SH-4A series virtual address range from 0x00000000 to 0x7FFFFFFF.
 LINKER_TEXT_BASE := 0x70000100
 else
-LINKER_TEXT_BASE := 0xB0000100
+# This is aligned to 4K page boundary so that both GNU ld and gold work.  Gold
+# actually produces a correct binary with starting address 0xB0000100 but the
+# extra objcopy step to rename symbols causes the resulting binary to be misaligned
+# and unloadable.  Increasing the alignment adds an extra 3840 bytes in padding
+# but switching to gold saves about 1M of space.
+LINKER_TEXT_BASE := 0xB0001000
 endif
 
 # The maximum size set aside for the linker, from
@@ -26,8 +32,16 @@
 LOCAL_CFLAGS += -DLINKER_TEXT_BASE=$(LINKER_TEXT_BASE)
 LOCAL_CFLAGS += -DLINKER_AREA_SIZE=$(LINKER_AREA_SIZE)
 
+# Set LINKER_DEBUG to either 1 or 0
+#
+LOCAL_CFLAGS += -DLINKER_DEBUG=0
+
 # we need to access the Bionic private header <bionic_tls.h>
-# in the linker
+# in the linker; duplicate the HAVE_ARM_TLS_REGISTER definition
+# from the libc build
+ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
+    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
 LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/private
 
 ifeq ($(TARGET_ARCH),arm)
diff --git a/linker/README.TXT b/linker/README.TXT
index 4fff14e..052a65b 100644
--- a/linker/README.TXT
+++ b/linker/README.TXT
@@ -112,3 +112,32 @@
 sections named ".ctors" and ".dtors", and the DT_INIT / DT_FINI functions
 are in charge of calling them explicitely.
 
+
+Debugging:
+----------
+
+It is possible to enable debug output in the dynamic linker. To do so,
+follow these steps:
+
+1/ Modify the line in Android.mk that says:
+
+    LOCAL_CFLAGS += -DLINKER_DEBUG=0
+
+  Into the following:
+
+    LOCAL_CFLAGS += -DLINKER_DEBUG=1
+
+2/ Force-rebuild the dynamic linker:
+
+    cd bionic/linker
+    mm -B
+
+3/ Rebuild a new system image.
+
+You can increase the verbosity of debug traces by defining the DEBUG
+environment variable to a numeric value from 0 to 2. This will only
+affect new processes being launched.
+
+By default, traces are sent to logcat, with the "linker" tag. You can
+change this to go to stdout instead by setting the definition of
+LINKER_DEBUG_TO_LOG to 0 in "linker_debug.h"
diff --git a/linker/debugger.c b/linker/debugger.c
index 5bb065c..1bd3cc8 100644
--- a/linker/debugger.c
+++ b/linker/debugger.c
@@ -32,6 +32,7 @@
 #include <ctype.h>
 #include <signal.h>
 #include <sys/mman.h>
+#include <errno.h>
 
 #include "linker.h"
 
@@ -40,6 +41,11 @@
 
 void notify_gdb_of_libraries();
 
+#define  RETRY_ON_EINTR(ret,cond) \
+    do { \
+        ret = (cond); \
+    } while (ret < 0 && errno == EINTR)
+
 void debugger_signal_handler(int n)
 {
     unsigned tid;
@@ -58,10 +64,15 @@
          * is paranoid and will verify that we are giving a tid
          * that's actually in our process
          */
-        write(s, &tid, sizeof(unsigned));
+        int  ret;
 
-        read(s, &tid, 1);
-        notify_gdb_of_libraries();
+        RETRY_ON_EINTR(ret, write(s, &tid, sizeof(unsigned)));
+        if (ret == sizeof(unsigned)) {
+            /* if the write failed, there is no point to read on
+             * the file descriptor. */
+            RETRY_ON_EINTR(ret, read(s, &tid, 1));
+            notify_gdb_of_libraries();
+        }
         close(s);
     }
 
diff --git a/linker/dlfcn.c b/linker/dlfcn.c
index dcadce5..10ecb13 100644
--- a/linker/dlfcn.c
+++ b/linker/dlfcn.c
@@ -17,6 +17,7 @@
 #include <pthread.h>
 #include <stdio.h>
 #include "linker.h"
+#include "linker_format.h"
 
 /* This file hijacks the symbols stubbed out in libdl.so. */
 
@@ -45,7 +46,7 @@
 
 static void set_dlerror(int err)
 {
-    snprintf(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err],
+    format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err],
              linker_get_error());
     dl_err_str = (const char *)&dl_err_buf[0];
 };
diff --git a/linker/linker.c b/linker/linker.c
index 87fb19b..6719b12 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008, 2009 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
 
 #include "linker.h"
 #include "linker_debug.h"
+#include "linker_format.h"
 
 #include "ba.h"
 
@@ -68,7 +69,6 @@
  *
  * open issues / todo:
  *
- * - should we do anything special for STB_WEAK symbols?
  * - are we doing everything we should for ARM_COPY relocations?
  * - cleaner error reporting
  * - after linking, set as much stuff as possible to READONLY
@@ -92,15 +92,15 @@
 #endif
 
 
-/* Set up for the buddy allocator managing the prelinked libraries. */
-static struct ba_bits ba_prelink_bitmap[(LIBLAST - LIBBASE) / LIBINC];
-static struct ba ba_prelink = {
+/* Set up for the buddy allocator managing the non-prelinked libraries. */
+static struct ba_bits ba_nonprelink_bitmap[(LIBLAST - LIBBASE) / LIBINC];
+static struct ba ba_nonprelink = {
     .base = LIBBASE,
     .size = LIBLAST - LIBBASE,
     .min_alloc = LIBINC,
     /* max_order will be determined automatically */
-    .bitmap = ba_prelink_bitmap,
-    .num_entries = sizeof(ba_prelink_bitmap)/sizeof(ba_prelink_bitmap[0]),
+    .bitmap = ba_nonprelink_bitmap,
+    .num_entries = sizeof(ba_nonprelink_bitmap)/sizeof(ba_nonprelink_bitmap[0]),
 };
 
 static inline int validate_soinfo(soinfo *si)
@@ -143,7 +143,7 @@
 static char __linker_dl_err_buf[768];
 #define DL_ERR(fmt, x...)                                                     \
     do {                                                                      \
-        snprintf(__linker_dl_err_buf, sizeof(__linker_dl_err_buf),            \
+        format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf),            \
                  "%s[%d]: " fmt, __func__, __LINE__, ##x);                    \
         ERROR(fmt "\n", ##x);                                                      \
     } while(0)
@@ -258,7 +258,7 @@
 
     if(strlen(name) >= SOINFO_NAME_LEN) {
         DL_ERR("%5d library name %s too long", pid, name);
-        return 0;
+        return NULL;
     }
 
     /* The freelist is populated when we call free_info(), which in turn is
@@ -406,20 +406,20 @@
         s = symtab + n;
         if(strcmp(strtab + s->st_name, name)) continue;
 
-            /* only concern ourselves with global symbols */
+            /* only concern ourselves with global and weak symbol definitions */
         switch(ELF32_ST_BIND(s->st_info)){
         case STB_GLOBAL:
+        case STB_WEAK:
                 /* no section == undefined */
             if(s->st_shndx == 0) continue;
 
-        case STB_WEAK:
             TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid,
                        name, si->name, s->st_value, s->st_size);
             return s;
         }
     }
 
-    return 0;
+    return NULL;
 }
 
 static unsigned elfhash(const char *_name)
@@ -437,25 +437,23 @@
 }
 
 static Elf32_Sym *
-_do_lookup_in_so(soinfo *si, const char *name, unsigned *elf_hash)
-{
-    if (*elf_hash == 0)
-        *elf_hash = elfhash(name);
-    return _elf_lookup (si, *elf_hash, name);
-}
-
-static Elf32_Sym *
 _do_lookup(soinfo *si, const char *name, unsigned *base)
 {
-    unsigned elf_hash = 0;
+    unsigned elf_hash = elfhash(name);
     Elf32_Sym *s;
     unsigned *d;
     soinfo *lsi = si;
 
     /* Look for symbols in the local scope first (the object who is
      * searching). This happens with C++ templates on i386 for some
-     * reason. */
-    s = _do_lookup_in_so(si, name, &elf_hash);
+     * reason.
+     *
+     * Notes on weak symbols:
+     * The ELF specs are ambigious about treatment of weak definitions in
+     * dynamic linking.  Some systems return the first definition found
+     * and some the first non-weak definition.   This is system dependent.
+     * Here we return the first definition found for simplicity.  */
+    s = _elf_lookup(si, elf_hash, name);
     if(s != NULL)
         goto done;
 
@@ -465,12 +463,12 @@
             if (!validate_soinfo(lsi)) {
                 DL_ERR("%5d bad DT_NEEDED pointer in %s",
                        pid, si->name);
-                return 0;
+                return NULL;
             }
 
             DEBUG("%5d %s: looking up %s in %s\n",
                   pid, si->name, name, lsi->name);
-            s = _do_lookup_in_so(lsi, name, &elf_hash);
+            s = _elf_lookup(lsi, elf_hash, name);
             if ((s != NULL) && (s->st_shndx != SHN_UNDEF))
                 goto done;
         }
@@ -485,7 +483,7 @@
         lsi = somain;
         DEBUG("%5d %s: looking up %s in executable %s\n",
               pid, si->name, name, lsi->name);
-        s = _do_lookup_in_so(lsi, name, &elf_hash);
+        s = _elf_lookup(lsi, elf_hash, name);
     }
 #endif
 
@@ -498,7 +496,7 @@
         return s;
     }
 
-    return 0;
+    return NULL;
 }
 
 /* This is used by dl_sym().  It performs symbol lookup only within the
@@ -506,15 +504,14 @@
  */
 Elf32_Sym *lookup_in_library(soinfo *si, const char *name)
 {
-    unsigned unused = 0;
-    return _do_lookup_in_so(si, name, &unused);
+    return _elf_lookup(si, elfhash(name), name);
 }
 
 /* This is used by dl_sym().  It performs a global symbol lookup.
  */
 Elf32_Sym *lookup(const char *name, soinfo **found)
 {
-    unsigned elf_hash = 0;
+    unsigned elf_hash = elfhash(name);
     Elf32_Sym *s = NULL;
     soinfo *si;
 
@@ -522,7 +519,7 @@
     {
         if(si->flags & FLAG_ERROR)
             continue;
-        s = _do_lookup_in_so(si, name, &elf_hash);
+        s = _elf_lookup(si, elf_hash, name);
         if (s != NULL) {
             *found = si;
             break;
@@ -535,7 +532,7 @@
         return s;
     }
 
-    return 0;
+    return NULL;
 }
 
 soinfo *find_containing_library(void *addr)
@@ -622,7 +619,7 @@
         return fd;
 
     for (path = ldpaths; *path; path++) {
-        n = snprintf(buf, sizeof(buf), "%s/%s", *path, name);
+        n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name);
         if (n < 0 || n >= (int)sizeof(buf)) {
             WARN("Ignoring very long library path: %s/%s\n", *path, name);
             continue;
@@ -631,7 +628,7 @@
             return fd;
     }
     for (path = sopaths; *path; path++) {
-        n = snprintf(buf, sizeof(buf), "%s/%s", *path, name);
+        n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name);
         if (n < 0 || n >= (int)sizeof(buf)) {
             WARN("Ignoring very long library path: %s/%s\n", *path, name);
             continue;
@@ -830,14 +827,14 @@
        for it from the buddy allocator, which manages the area between
        LIBBASE and LIBLAST.
     */
-    si->ba_index = ba_allocate(&ba_prelink, si->size);
+    si->ba_index = ba_allocate(&ba_nonprelink, si->size);
     if(si->ba_index >= 0) {
-        si->base = ba_start_addr(&ba_prelink, si->ba_index);
+        si->base = ba_start_addr(&ba_nonprelink, si->ba_index);
         PRINT("%5d mapping library '%s' at %08x (index %d) " \
               "through buddy allocator.\n",
               pid, si->name, si->base, si->ba_index);
         if (reserve_mem_region(si) < 0) {
-            ba_free(&ba_prelink, si->ba_index);
+            ba_free(&ba_nonprelink, si->ba_index);
             si->ba_index = -1;
             si->base = 0;
             goto err;
@@ -1133,7 +1130,7 @@
     /* Now actually load the library's segments into right places in memory */
     if (load_segments(fd, &__header[0], si) < 0) {
         if (si->ba_index >= 0) {
-            ba_free(&ba_prelink, si->ba_index);
+            ba_free(&ba_nonprelink, si->ba_index);
             si->ba_index = -1;
         }
         goto fail;
@@ -1236,7 +1233,7 @@
             PRINT("%5d releasing library '%s' address space at %08x "\
                   "through buddy allocator.\n",
                   pid, si->name, si->base);
-            ba_free(&ba_prelink, si->ba_index);
+            ba_free(&ba_nonprelink, si->ba_index);
         }
         notify_gdb_of_unload(si);
         free_info(si);
@@ -1275,10 +1272,64 @@
         if(sym != 0) {
             sym_name = (char *)(strtab + symtab[sym].st_name);
             s = _do_lookup(si, sym_name, &base);
-            if(s == 0) {
-                DL_ERR("%5d cannot locate '%s'...", pid, sym_name);
-                return -1;
-            }
+            if(s == NULL) {
+                /* We only allow an undefined symbol if this is a weak
+                   reference..   */
+                s = &symtab[sym];
+                if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
+                    DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name);
+                    return -1;
+                }
+
+                /* IHI0044C AAELF 4.5.1.1:
+
+                   Libraries are not searched to resolve weak references.
+                   It is not an error for a weak reference to remain
+                   unsatisfied.
+
+                   During linking, the value of an undefined weak reference is:
+                   - Zero if the relocation type is absolute
+                   - The address of the place if the relocation is pc-relative
+                   - The address of nominial base address if the relocation
+                     type is base-relative.
+                  */
+
+                switch (type) {
+#if defined(ANDROID_ARM_LINKER)
+                case R_ARM_JUMP_SLOT:
+                case R_ARM_GLOB_DAT:
+                case R_ARM_ABS32:
+                case R_ARM_RELATIVE:    /* Don't care. */
+                case R_ARM_NONE:        /* Don't care. */
+#elif defined(ANDROID_X86_LINKER)
+                case R_386_JUMP_SLOT:
+                case R_386_GLOB_DAT:
+                case R_386_32:
+                case R_386_RELATIVE:    /* Dont' care. */
+#endif /* ANDROID_*_LINKER */
+                    /* sym_addr was initialized to be zero above or relocation
+                       code below does not care about value of sym_addr.
+                       No need to do anything.  */
+                    break;
+
+#if defined(ANDROID_X86_LINKER)
+                case R_386_PC32:
+                    sym_addr = reloc;
+                    break;
+#endif /* ANDROID_X86_LINKER */
+
+#if defined(ANDROID_ARM_LINKER)
+                case R_ARM_COPY:
+                    /* Fall through.  Can't really copy if weak symbol is
+                       not found in run-time.  */
+#endif /* ANDROID_ARM_LINKER */
+                default:
+                    DL_ERR("%5d unknown weak reloc type %d @ %p (%d)\n",
+                                 pid, type, rel, (int) (rel - start));
+                    return -1;
+                }
+            } else {
+                /* We got a definition.  */
 #if 0
             if((base == 0) && (si->base != 0)){
                     /* linking from libraries to main image is bad */
@@ -1287,20 +1338,11 @@
                 return -1;
             }
 #endif
-            // st_shndx==SHN_UNDEF means an undefined symbol.
-            // st_value should be 0 then, except that the low bit of st_value is
-            // used to indicate whether the symbol points to an ARM or thumb function,
-            // and should be ignored in the following check.
-            if ((s->st_shndx == SHN_UNDEF) && ((s->st_value & ~1) != 0)) {
-                DL_ERR("%5d In '%s', symbol=%s shndx=%d && value=0x%08x. We do not "
-                      "handle this yet", pid, si->name, sym_name, s->st_shndx,
-                      s->st_value);
-                return -1;
-            }
-            sym_addr = (unsigned)(s->st_value + base);
+                sym_addr = (unsigned)(s->st_value + base);
+	    }
             COUNT_RELOC(RELOC_SYMBOL);
         } else {
-            s = 0;
+            s = NULL;
         }
 
 /* TODO: This is ugly. Split up the relocations by arch into
@@ -1950,7 +1992,7 @@
     return 0;
 
 fail:
-    ERROR("failed to link %s\n", si->name);
+    DL_ERR("failed to link %s\n", si->name);
     si->flags |= FLAG_ERROR;
     return -1;
 }
@@ -2080,7 +2122,7 @@
         vecs += 2;
     }
 
-    ba_init(&ba_prelink);
+    ba_init(&ba_nonprelink);
 
     si->base = 0;
     si->dynamic = (unsigned *)-1;
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 3f4fc4c..3f08303 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2010 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,17 @@
 
 #include <stdio.h>
 
-/* WARNING: For linker debugging only.. Be careful not to leave  any of
- * this on when submitting back to repository */
-#define LINKER_DEBUG         0
-#define TRACE_DEBUG          0
-#define DO_TRACE_LOOKUP      0
-#define DO_TRACE_RELO        0
+#ifndef LINKER_DEBUG
+#error LINKER_DEBUG should be defined to either 1 or 0 in Android.mk
+#endif
+
+/* set LINKER_DEBUG_TO_LOG to 1 to send the logs to logcat,
+ * or 0 to use stdout instead.
+ */
+#define LINKER_DEBUG_TO_LOG  1
+#define TRACE_DEBUG          1
+#define DO_TRACE_LOOKUP      1
+#define DO_TRACE_RELO        1
 #define TIMING               0
 #define STATS                0
 #define COUNT_PAGES          0
@@ -59,12 +64,21 @@
  * corruption when the linker uses printf().
  */
 #if LINKER_DEBUG
+#include "linker_format.h"
 extern int debug_verbosity;
-#warning "*** LINKER IS USING printf(); DO NOT CHECK THIS IN ***"
-#define _PRINTVF(v,f,x...)                                                \
-    do {                                                                  \
-        (debug_verbosity > (v)) && (printf(x), ((f) && fflush(stdout)));  \
+#if LINKER_DEBUG_TO_LOG
+extern int format_log(int, const char *, const char *, ...);
+#define _PRINTVF(v,f,x...)                                        \
+    do {                                                          \
+        if (debug_verbosity > (v)) format_log(5-(v),"linker",x);  \
     } while (0)
+#else /* !LINKER_DEBUG_TO_LOG */
+extern int format_fd(int, const char *, ...);
+#define _PRINTVF(v,f,x...)                           \
+    do {                                             \
+        if (debug_verbosity > (v)) format_fd(1, x);  \
+    } while (0)
+#endif /* !LINKER_DEBUG_TO_LOG */
 #else /* !LINKER_DEBUG */
 #define _PRINTVF(v,f,x...)   do {} while(0)
 #endif /* LINKER_DEBUG */
diff --git a/linker/linker_format.c b/linker/linker_format.c
new file mode 100644
index 0000000..4d00bd9
--- /dev/null
+++ b/linker/linker_format.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2010 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 <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "linker_format.h"
+#include "linker_debug.h"
+
+/* define UNIT_TESTS to build this file as a single executable that runs
+ * the formatter's unit tests
+ */
+#define xxUNIT_TESTS
+
+/*** Generic output sink
+ ***/
+
+typedef struct {
+    void *opaque;
+    void (*send)(void *opaque, const char *data, int len);
+} Out;
+
+static void
+out_send(Out *o, const void *data, size_t len)
+{
+    o->send(o->opaque, data, (int)len);
+}
+
+static void
+out_send_repeat(Out *o, char ch, int count)
+{
+    char pad[8];
+    const int padSize = (int)sizeof(pad);
+
+    memset(pad, ch, sizeof(pad));
+    while (count > 0) {
+        int avail = count;
+        if (avail > padSize) {
+            avail = padSize;
+        }
+        o->send(o->opaque, pad, avail);
+        count -= avail;
+    }
+}
+
+/* forward declaration */
+static void
+out_vformat(Out *o, const char *format, va_list args);
+
+/*** Bounded buffer output
+ ***/
+
+typedef struct {
+    Out out[1];
+    char *buffer;
+    char *pos;
+    char *end;
+    int total;
+} BufOut;
+
+static void
+buf_out_send(void *opaque, const char *data, int len)
+{
+    BufOut *bo = opaque;
+
+    if (len < 0)
+        len = strlen(data);
+
+    bo->total += len;
+
+    while (len > 0) {
+        int avail = bo->end - bo->pos;
+        if (avail == 0)
+            break;
+        if (avail > len)
+            avail = len;
+        memcpy(bo->pos, data, avail);
+        bo->pos += avail;
+        bo->pos[0] = '\0';
+        len -= avail;
+    }
+}
+
+static Out*
+buf_out_init(BufOut *bo, char *buffer, size_t size)
+{
+    if (size == 0)
+        return NULL;
+
+    bo->out->opaque = bo;
+    bo->out->send   = buf_out_send;
+    bo->buffer      = buffer;
+    bo->end         = buffer + size - 1;
+    bo->pos         = bo->buffer;
+    bo->pos[0]      = '\0';
+    bo->total       = 0;
+
+    return bo->out;
+}
+
+static int
+buf_out_length(BufOut *bo)
+{
+    return bo->total;
+}
+
+static int
+vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
+{
+    BufOut bo;
+    Out *out;
+
+    out = buf_out_init(&bo, buff, buffsize);
+    if (out == NULL)
+        return 0;
+
+    out_vformat(out, format, args);
+
+    return buf_out_length(&bo);
+}
+
+int
+format_buffer(char *buff, size_t buffsize, const char *format, ...)
+{
+    va_list args;
+    int ret;
+
+    va_start(args, format);
+    ret = vformat_buffer(buff, buffsize, format, args);
+    va_end(args);
+
+    return ret;
+}
+
+/* The __stack_chk_fail() function calls __libc_android_log_print()
+ * which calls vsnprintf().
+ *
+ * We define our version of the function here to avoid dragging
+ * about 25 KB of C library routines related to formatting.
+ */
+int
+vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
+{
+    return format_buffer(buff, bufsize, format, args);
+}
+
+#if LINKER_DEBUG
+
+#if !LINKER_DEBUG_TO_LOG
+
+/*** File descriptor output
+ ***/
+
+typedef struct {
+    Out out[1];
+    int fd;
+    int total;
+} FdOut;
+
+static void
+fd_out_send(void *opaque, const char *data, int len)
+{
+    FdOut *fdo = opaque;
+
+    if (len < 0)
+        len = strlen(data);
+
+    while (len > 0) {
+        int ret = write(fdo->fd, data, len);
+        if (ret < 0) {
+            if (errno == EINTR)
+                continue;
+            break;
+        }
+        data += ret;
+        len -= ret;
+        fdo->total += ret;
+    }
+}
+
+static Out*
+fd_out_init(FdOut *fdo, int  fd)
+{
+    fdo->out->opaque = fdo;
+    fdo->out->send = fd_out_send;
+    fdo->fd = fd;
+    fdo->total = 0;
+
+    return fdo->out;
+}
+
+static int
+fd_out_length(FdOut *fdo)
+{
+    return fdo->total;
+}
+
+
+int
+format_fd(int fd, const char *format, ...)
+{
+    FdOut fdo;
+    Out* out;
+    va_list args;
+
+    out = fd_out_init(&fdo, fd);
+    if (out == NULL)
+        return 0;
+
+    va_start(args, format);
+    out_vformat(out, format, args);
+    va_end(args);
+
+    return fd_out_length(&fdo);
+}
+
+#else /* LINKER_DEBUG_TO_LOG */
+
+/*** Log output
+ ***/
+
+/* We need our own version of __libc_android_log_vprint, otherwise
+ * the log output is completely broken. Probably due to the fact
+ * that the C library is not initialized yet.
+ *
+ * You can test that by setting CUSTOM_LOG_VPRINT to 0
+ */
+#define  CUSTOM_LOG_VPRINT  1
+
+#if CUSTOM_LOG_VPRINT
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+
+static int log_vprint(int prio, const char *tag, const char *fmt, va_list  args)
+{
+    char buf[1024];
+    int result;
+    static int log_fd = -1;
+
+    result = vformat_buffer(buf, sizeof buf, fmt, args);
+
+    if (log_fd < 0) {
+        log_fd = open("/dev/log/main", O_WRONLY);
+        if (log_fd < 0)
+            return result;
+    }
+
+    {
+        ssize_t ret;
+        struct iovec vec[3];
+
+        vec[0].iov_base = (unsigned char *) &prio;
+        vec[0].iov_len = 1;
+        vec[1].iov_base = (void *) tag;
+        vec[1].iov_len = strlen(tag) + 1;
+        vec[2].iov_base = (void *) buf;
+        vec[2].iov_len = strlen(buf) + 1;
+
+        do {
+            ret = writev(log_fd, vec, 3);
+        } while ((ret < 0) && (errno == EINTR));
+    }
+    return result;
+}
+
+#define  __libc_android_log_vprint  log_vprint
+
+#else /* !CUSTOM_LOG_VPRINT */
+
+extern int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
+
+#endif /* !CUSTOM_LOG_VPRINT */
+
+int
+format_log(int prio, const char *tag, const char *format, ...)
+{
+    int ret;
+    va_list  args;
+    va_start(args, format);
+    ret = __libc_android_log_vprint(prio, tag, format, args);
+    va_end(args);
+    return ret;
+}
+
+#endif /* LINKER_DEBUG_TO_LOG */
+
+#endif /* LINKER_DEBUG */
+
+/*** formatted output implementation
+ ***/
+
+/* Parse a decimal string from 'format + *ppos',
+ * return the value, and writes the new position past
+ * the decimal string in '*ppos' on exit.
+ *
+ * NOTE: Does *not* handle a sign prefix.
+ */
+static unsigned
+parse_decimal(const char *format, int *ppos)
+{
+    const char* p = format + *ppos;
+    unsigned result = 0;
+
+    for (;;) {
+        int ch = *p;
+        unsigned d = (unsigned)(ch - '0');
+
+        if (d >= 10U)
+            break;
+
+        result = result*10 + d;
+        p++;
+    }
+    *ppos = p - format;
+    return result;
+}
+
+/* write an octal/decimal/number into a bounded buffer.
+ * assumes that bufsize > 0, and 'digits' is a string of
+ * digits of at least 'base' values.
+ */
+static void
+format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits)
+{
+    char *pos = buffer;
+    char *end = buffer + bufsize - 1;
+
+    /* generate digit string in reverse order */
+    while (value) {
+        unsigned d = value % base;
+        value /= base;
+        if (pos < end) {
+            *pos++ = digits[d];
+        }
+    }
+
+    /* special case for 0 */
+    if (pos == buffer) {
+        if (pos < end) {
+            *pos++ = '0';
+        }
+    }
+    pos[0] = '\0';
+
+    /* now reverse digit string in-place */
+    end = pos - 1;
+    pos = buffer;
+    while (pos < end) {
+        int ch = pos[0];
+        pos[0] = end[0];
+        end[0] = (char) ch;
+        pos++;
+        end--;
+    }
+}
+
+/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
+static void
+format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
+{
+    if (isSigned && (int64_t)value < 0) {
+        buffer[0] = '-';
+        buffer += 1;
+        buffsize -= 1;
+        value = (uint64_t)(-(int64_t)value);
+    }
+
+    format_number(buffer, buffsize, value, base, "0123456789");
+}
+
+/* Write an octal into a buffer, assumes buffsize > 2 */
+static void
+format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
+{
+    format_integer(buffer, buffsize, value, 8, isSigned);
+}
+
+/* Write a decimal into a buffer, assumes buffsize > 2 */
+static void
+format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
+{
+    format_integer(buffer, buffsize, value, 10, isSigned);
+}
+
+/* Write an hexadecimal into a buffer, isCap is true for capital alphas.
+ * Assumes bufsize > 2 */
+static void
+format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap)
+{
+    const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef";
+
+    format_number(buffer, buffsize, value, 16, digits);
+}
+
+
+/* Perform formatted output to an output target 'o' */
+static void
+out_vformat(Out *o, const char *format, va_list args)
+{
+    int nn = 0, mm;
+    int padZero = 0;
+    int padLeft = 0;
+    char sign = '\0';
+    int width = -1;
+    int prec  = -1;
+    size_t bytelen = sizeof(int);
+    const char*  str;
+    int slen;
+    char buffer[32];  /* temporary buffer used to format numbers */
+
+    for (;;) {
+        char  c;
+
+        /* first, find all characters that are not 0 or '%' */
+        /* then send them to the output directly */
+        mm = nn;
+        do {
+            c = format[mm];
+            if (c == '\0' || c == '%')
+                break;
+            mm++;
+        } while (1);
+
+        if (mm > nn) {
+            out_send(o, format+nn, mm-nn);
+            nn = mm;
+        }
+
+        /* is this it ? then exit */
+        if (c == '\0')
+            break;
+
+        /* nope, we are at a '%' modifier */
+        nn++;  // skip it
+
+        /* parse flags */
+        for (;;) {
+            c = format[nn++];
+            if (c == '\0') {  /* single trailing '%' ? */
+                c = '%';
+                out_send(o, &c, 1);
+                return;
+            }
+            else if (c == '0') {
+                padZero = 1;
+                continue;
+            }
+            else if (c == '-') {
+                padLeft = 1;
+                continue;
+            }
+            else if (c == ' ' || c == '+') {
+                sign = c;
+                continue;
+            }
+            break;
+        }
+
+        /* parse field width */
+        if ((c >= '0' && c <= '9')) {
+            nn --;
+            width = (int)parse_decimal(format, &nn);
+            c = format[nn++];
+        }
+
+        /* parse precision */
+        if (c == '.') {
+            prec = (int)parse_decimal(format, &nn);
+            c = format[nn++];
+        }
+
+        /* length modifier */
+        switch (c) {
+        case 'h':
+            bytelen = sizeof(short);
+            if (format[nn] == 'h') {
+                bytelen = sizeof(char);
+                nn += 1;
+            }
+            c = format[nn++];
+            break;
+        case 'l':
+            bytelen = sizeof(long);
+            if (format[nn] == 'l') {
+                bytelen = sizeof(long long);
+                nn += 1;
+            }
+            c = format[nn++];
+            break;
+        case 'z':
+            bytelen = sizeof(size_t);
+            c = format[nn++];
+            break;
+        case 't':
+            bytelen = sizeof(ptrdiff_t);
+            c = format[nn++];
+            break;
+        case 'p':
+            bytelen = sizeof(void*);
+            c = format[nn++];
+        default:
+            ;
+        }
+
+        /* conversion specifier */
+        if (c == 's') {
+            /* string */
+            str = va_arg(args, const char*);
+        } else if (c == 'c') {
+            /* character */
+            /* NOTE: char is promoted to int when passed through the stack */
+            buffer[0] = (char) va_arg(args, int);
+            buffer[1] = '\0';
+            str = buffer;
+        } else if (c == 'p') {
+            uint64_t  value = (uint64_t)(ptrdiff_t) va_arg(args, void*);
+            buffer[0] = '0';
+            buffer[1] = 'x';
+            format_hex(buffer + 2, sizeof buffer-2, value, 0);
+            str = buffer;
+        } else {
+            /* integers - first read value from stack */
+            uint64_t value;
+            int isSigned = (c == 'd' || c == 'i' || c == 'o');
+
+            /* NOTE: int8_t and int16_t are promoted to int when passed
+             *       through the stack
+             */
+            switch (bytelen) {
+            case 1: value = (uint8_t)  va_arg(args, int); break;
+            case 2: value = (uint16_t) va_arg(args, int); break;
+            case 4: value = va_arg(args, uint32_t); break;
+            case 8: value = va_arg(args, uint64_t); break;
+            default: return;  /* should not happen */
+            }
+
+            /* sign extension, if needed */
+            if (isSigned) {
+                int shift = 64 - 8*bytelen;
+                value = (uint64_t)(((int64_t)(value << shift)) >> shift);
+            }
+
+            /* format the number properly into our buffer */
+            switch (c) {
+            case 'i': case 'd':
+                format_integer(buffer, sizeof buffer, value, 10, isSigned);
+                break;
+            case 'o':
+                format_integer(buffer, sizeof buffer, value, 8, isSigned);
+                break;
+            case 'x': case 'X':
+                format_hex(buffer, sizeof buffer, value, (c == 'X'));
+                break;
+            default:
+                buffer[0] = '\0';
+            }
+            /* then point to it */
+            str = buffer;
+        }
+
+        /* if we are here, 'str' points to the content that must be
+         * outputted. handle padding and alignment now */
+
+        slen = strlen(str);
+
+        if (slen < width && !padLeft) {
+            char padChar = padZero ? '0' : ' ';
+            out_send_repeat(o, padChar, width - slen);
+        }
+
+        out_send(o, str, slen);
+
+        if (slen < width && padLeft) {
+            char padChar = padZero ? '0' : ' ';
+            out_send_repeat(o, padChar, width - slen);
+        }
+    }
+}
+
+
+#ifdef UNIT_TESTS
+
+#include <stdio.h>
+
+static int   gFails = 0;
+
+#define  MARGIN  40
+
+#define  UTEST_CHECK(condition,message) \
+    printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
+    if (!(condition)) { \
+        printf("KO\n"); \
+        gFails += 1; \
+    } else { \
+        printf("ok\n"); \
+    }
+
+static void
+utest_BufOut(void)
+{
+    char buffer[16];
+    BufOut bo[1];
+    Out* out;
+    int ret;
+
+    buffer[0] = '1';
+    out = buf_out_init(bo, buffer, sizeof buffer);
+    UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte");
+    out_send(out, "abc", 3);
+    UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut");
+    out_send_repeat(out, 'X', 4);
+    UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut");
+    buffer[sizeof buffer-1] = 'x';
+    out_send_repeat(out, 'Y', 2*sizeof(buffer));
+    UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates");
+
+    out = buf_out_init(bo, buffer, sizeof buffer);
+    out_send_repeat(out, 'X', 2*sizeof(buffer));
+    ret = buf_out_length(bo);
+    UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow");
+}
+
+static void
+utest_expect(const char*  result, const char*  format, ...)
+{
+    va_list args;
+    BufOut bo[1];
+    char buffer[256];
+    Out* out = buf_out_init(bo, buffer, sizeof buffer);
+
+    printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
+    va_start(args, format);
+    out_vformat(out, format, args);
+    va_end(args);
+
+    if (strcmp(result, buffer)) {
+        printf("KO. got '%s' expecting '%s'\n", buffer, result);
+        gFails += 1;
+    } else {
+        printf("ok. got '%s'\n", result);
+    }
+}
+
+int  main(void)
+{
+    utest_BufOut();
+    utest_expect("", "");
+    utest_expect("a", "a");
+    utest_expect("01234", "01234", "");
+    utest_expect("01234", "%s", "01234");
+    utest_expect("aabbcc", "aa%scc", "bb");
+    utest_expect("a", "%c", 'a');
+    utest_expect("1234", "%d", 1234);
+    utest_expect("-8123", "%d", -8123);
+    utest_expect("16", "%hd", 0x7fff0010);
+    utest_expect("16", "%hhd", 0x7fffff10);
+    utest_expect("68719476736", "%lld", 0x1000000000);
+    utest_expect("70000", "%ld", 70000);
+    utest_expect("0xb0001234", "%p", (void*)0xb0001234);
+    utest_expect("12ab", "%x", 0x12ab);
+    utest_expect("12AB", "%X", 0x12ab);
+    utest_expect("00123456", "%08x", 0x123456);
+    utest_expect("01234", "0%d", 1234);
+    utest_expect(" 1234", "%5d", 1234);
+    utest_expect("01234", "%05d", 1234);
+    utest_expect("    1234", "%8d", 1234);
+    utest_expect("1234    ", "%-8d", 1234);
+    utest_expect("abcdef     ", "%-11s", "abcdef");
+    utest_expect("something:1234", "%s:%d", "something", 1234);
+    return gFails != 0;
+}
+
+#endif /* UNIT_TESTS */
diff --git a/linker/linker_format.h b/linker/linker_format.h
new file mode 100644
index 0000000..6ae2bad
--- /dev/null
+++ b/linker/linker_format.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 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 _LINKER_FORMAT_H
+#define _LINKER_FORMAT_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+/* Formatting routines for the dynamic linker's debug traces */
+/* We want to avoid dragging the whole C library fprintf()   */
+/* implementation into the dynamic linker since this creates */
+/* issues (it uses malloc()/free()) and increases code size  */
+
+int format_buffer(char *buffer, size_t bufsize, const char *format, ...);
+
+#endif /* _LINKER_FORMAT_H */