merge in jb-mr1-release history after reset to jb-mr1-dev
diff --git a/libc/Android.mk b/libc/Android.mk
index c3759db..6a77deb 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -61,7 +61,6 @@
 	unistd/sigwait.c \
 	unistd/sleep.c \
 	unistd/statfs.c \
-	unistd/strsignal.c \
 	unistd/syslog.c \
 	unistd/system.c \
 	unistd/tcgetpgrp.c \
@@ -191,8 +190,6 @@
 	string/strcoll.c \
 	string/strcspn.c \
 	string/strdup.c \
-	string/strerror.c \
-	string/strerror_r.c \
 	string/strlcat.c \
 	string/strlcpy.c \
 	string/strncat.c \
@@ -291,6 +288,9 @@
 	bionic/sched_cpucount.c \
 	bionic/semaphore.c \
 	bionic/sha1.c \
+	bionic/strerror.cpp \
+	bionic/strerror_r.cpp \
+	bionic/strsignal.cpp \
 	bionic/stubs.cpp \
 	bionic/system_properties.c \
 	bionic/tdestroy.c \
@@ -331,7 +331,10 @@
 
 libc_upstream_netbsd_src_files := \
 	upstream-netbsd/libc/compat-43/creat.c \
+	upstream-netbsd/libc/gen/ftw.c \
+	upstream-netbsd/libc/gen/nftw.c \
 	upstream-netbsd/libc/gen/nice.c \
+	upstream-netbsd/libc/gen/psignal.c \
 	upstream-netbsd/libc/regex/regcomp.c \
 	upstream-netbsd/libc/regex/regerror.c \
 	upstream-netbsd/libc/regex/regexec.c \
@@ -916,7 +919,7 @@
 LOCAL_MODULE:= libc_malloc_debug_leak
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-LOCAL_SHARED_LIBRARIES := libc
+LOCAL_SHARED_LIBRARIES := libc libdl
 LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
diff --git a/libc/NOTICE b/libc/NOTICE
index 8bf4978..299f672 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -3421,6 +3421,26 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Sponsored in part by the Defense Advanced Research Projects
+Agency (DARPA) and Air Force Research Laboratory, Air Force
+Materiel Command, USAF, under agreement number F39502-99-1-0512.
+
+-------------------------------------------------------------------
+
 Copyright (c) 2004 The NetBSD Foundation, Inc.
 All rights reserved.
 
@@ -3931,6 +3951,34 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2012 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
 Copyright (c)1999 Citrus Project,
 All rights reserved.
 
diff --git a/libc/bionic/ThreadLocalBuffer.h b/libc/bionic/ThreadLocalBuffer.h
new file mode 100644
index 0000000..99acdba
--- /dev/null
+++ b/libc/bionic/ThreadLocalBuffer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 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 _BIONIC_THREAD_LOCAL_BUFFER_H_included
+#define _BIONIC_THREAD_LOCAL_BUFFER_H_included
+
+#include <malloc.h>
+#include <pthread.h>
+
+// libstdc++ currently contains __cxa_guard_acquire and __cxa_guard_release,
+// so we make do with macros instead of a C++ class.
+// TODO: move __cxa_guard_acquire and __cxa_guard_release into libc.
+
+#define GLOBAL_INIT_THREAD_LOCAL_BUFFER(name) \
+  static pthread_once_t name ## _once; \
+  static pthread_key_t name ## _key; \
+  static void name ## _key_destroy(void* buffer) { \
+    free(buffer); \
+  } \
+  static void name ## _key_init() { \
+    pthread_key_create(&name ## _key, name ## _key_destroy); \
+  }
+
+// Leaves "name_buffer" and "name_byte_count" defined and initialized.
+#define LOCAL_INIT_THREAD_LOCAL_BUFFER(type, name, byte_count) \
+  pthread_once(&name ## _once, name ## _key_init); \
+  type name ## _buffer = reinterpret_cast<type>(pthread_getspecific(name ## _key)); \
+  if (name ## _buffer == NULL) { \
+    name ## _buffer = reinterpret_cast<type>(malloc(byte_count)); \
+    pthread_setspecific(name ## _key, name ## _buffer); \
+  } \
+  const size_t name ## _buffer_size = byte_count
+
+#endif // _BIONIC_THREAD_LOCAL_BUFFER_H_included
diff --git a/libc/unistd/strsignal.c b/libc/bionic/strerror.cpp
similarity index 80%
rename from libc/unistd/strsignal.c
rename to libc/bionic/strerror.cpp
index 171de3d..036ec8d 100644
--- a/libc/unistd/strsignal.c
+++ b/libc/bionic/strerror.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,14 +25,14 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <signal.h>
-#include <string.h>
 
-char*
-strsignal(int  sig)
-{
-    if ((unsigned)sig < NSIG)
-        return (char*) sys_siglist[sig];
-    else
-        return "Invalid signal number";
+#include <string.h>
+#include "ThreadLocalBuffer.h"
+
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(strerror);
+
+char* strerror(int error_number) {
+  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, strerror, NL_TEXTMAX);
+  strerror_r(error_number, strerror_buffer, strerror_buffer_size);
+  return strerror_buffer;
 }
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
new file mode 100644
index 0000000..92235a5
--- /dev/null
+++ b/libc/bionic/strerror_r.cpp
@@ -0,0 +1,71 @@
+/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
+/* Public Domain <marc@snafu.org> */
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+struct Pair {
+  int code;
+  const char* msg;
+};
+
+static const char* __code_string_lookup(const Pair* strings, int code) {
+  for (size_t i = 0; strings[i].msg != NULL; ++i) {
+    if (strings[i].code == code) {
+      return strings[i].msg;
+    }
+  }
+  return NULL;
+}
+
+static const Pair _sys_error_strings[] = {
+#define  __BIONIC_ERRDEF(x,y,z)  { x, z },
+#include <sys/_errdefs.h>
+  { 0, NULL }
+};
+
+int strerror_r(int error_number, char* buf, size_t buf_len) {
+  int saved_errno = errno;
+  size_t length;
+
+  const char* error_name = __code_string_lookup(_sys_error_strings, error_number);
+  if (error_name != NULL) {
+    length = snprintf(buf, buf_len, "%s", error_name);
+  } else {
+    length = snprintf(buf, buf_len, "Unknown error %u", error_number);
+  }
+  if (length >= buf_len) {
+    errno = ERANGE;
+    return -1;
+  }
+
+  errno = saved_errno;
+  return 0;
+}
+
+static const Pair _sys_signal_strings[] = {
+#define  __BIONIC_SIGDEF(x,y,z)  { y, z },
+#include <sys/_sigdefs.h>
+  { 0, NULL }
+};
+
+extern "C" const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
+  const char* signal_name = __code_string_lookup(_sys_signal_strings, signal_number);
+  if (signal_name != NULL) {
+    return signal_name;
+  }
+
+  const char* prefix = "Unknown";
+  if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) {
+    prefix = "Real-time";
+    signal_number -= SIGRTMIN;
+  }
+  size_t length = snprintf(buf, buf_len, "%s signal %d", prefix, signal_number);
+  if (length >= buf_len) {
+    return NULL;
+  }
+  return buf;
+}
diff --git a/libc/unistd/strsignal.c b/libc/bionic/strsignal.cpp
similarity index 77%
copy from libc/unistd/strsignal.c
copy to libc/bionic/strsignal.cpp
index 171de3d..1cbec9b 100644
--- a/libc/unistd/strsignal.c
+++ b/libc/bionic/strsignal.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,14 +25,15 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <signal.h>
-#include <string.h>
 
-char*
-strsignal(int  sig)
-{
-    if ((unsigned)sig < NSIG)
-        return (char*) sys_siglist[sig];
-    else
-        return "Invalid signal number";
+#include <string.h>
+#include "ThreadLocalBuffer.h"
+
+extern "C" const char* __strsignal(int, char*, size_t);
+
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(strsignal);
+
+char* strsignal(int signal_number) {
+  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, strsignal, NL_TEXTMAX);
+  return const_cast<char*>(__strsignal(signal_number, strsignal_buffer, strsignal_buffer_size));
 }
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index a539b34..1cab7d3 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -264,25 +264,30 @@
   return (unsigned)(appid + userid*AID_USER);
 }
 
-static void print_app_uid_name(uid_t  uid, char* buffer, int bufferlen) {
-  uid_t appid = uid % AID_USER;
-  uid_t userid = uid / AID_USER;
-
-  if (appid < AID_ISOLATED_START) {
-    if (appid < AID_APP) {
-      for (size_t n = 0; n < android_id_count; n++) {
-        if (android_ids[n].aid == appid) {
-          snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name);
-          return;
-        }
+static void print_app_name_from_appid_userid(const uid_t appid,
+    const uid_t userid, char* buffer, const int bufferlen) {
+  if (appid >= AID_ISOLATED_START) {
+    snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
+  } else if (userid == 0 && appid >= AID_SHARED_GID_START) {
+    snprintf(buffer, bufferlen, "all_a%u", appid - AID_SHARED_GID_START);
+  } else if (appid < AID_APP) {
+    for (size_t n = 0; n < android_id_count; n++) {
+      if (android_ids[n].aid == appid) {
+        snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name);
+        return;
       }
     }
-    snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP);
   } else {
-    snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
+    snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP);
   }
 }
 
+static void print_app_name_from_uid(const uid_t uid, char* buffer, const int bufferlen) {
+  const uid_t appid = uid % AID_USER;
+  const uid_t userid = uid / AID_USER;
+  return print_app_name_from_appid_userid(appid, userid, buffer, bufferlen);
+}
+
 // Translate a uid into the corresponding name.
 // 0 to AID_APP-1                   -> "system", "radio", etc.
 // AID_APP to AID_ISOLATED_START-1  -> u0_a1234
@@ -297,10 +302,18 @@
     return NULL;
   }
 
-  print_app_uid_name(uid, state->app_name_buffer_,
-                     sizeof(state->app_name_buffer_));
+  const uid_t appid = uid % AID_USER;
+  const uid_t userid = uid / AID_USER;
 
-  snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/data");
+  print_app_name_from_appid_userid(appid, userid, state->app_name_buffer_,
+                                   sizeof(state->app_name_buffer_));
+
+  if (appid < AID_APP) {
+      snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
+  } else {
+      snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/data");
+  }
+
   snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
 
   pw->pw_name  = state->app_name_buffer_;
@@ -320,8 +333,8 @@
     return NULL;
   }
 
-  print_app_uid_name(gid, state->group_name_buffer_,
-                     sizeof(state->group_name_buffer_));
+  print_app_name_from_uid(gid, state->group_name_buffer_,
+                          sizeof(state->group_name_buffer_));
 
   group* gr = &state->group_;
   gr->gr_name   = state->group_name_buffer_;
diff --git a/libc/include/ftw.h b/libc/include/ftw.h
new file mode 100644
index 0000000..3bebea3
--- /dev/null
+++ b/libc/include/ftw.h
@@ -0,0 +1,62 @@
+/* $NetBSD: ftw.h,v 1.1 2005/12/30 23:07:33 agc Exp $ */
+
+/*	From OpenBSD: ftw.h,v 1.1 2003/07/21 21:13:18 millert Exp 	*/
+
+/*
+ * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#ifndef	_FTW_H
+#define	_FTW_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*
+ * Valid flags for the 3rd argument to the function that is passed as the
+ * second argument to ftw(3) and nftw(3).  Say it three times fast!
+ */
+#define	FTW_F		0	/* File.  */
+#define	FTW_D		1	/* Directory.  */
+#define	FTW_DNR		2	/* Directory without read permission.  */
+#define	FTW_DP		3	/* Directory with subdirectories visited.  */
+#define	FTW_NS		4	/* Unknown type; stat() failed.  */
+#define	FTW_SL		5	/* Symbolic link.  */
+#define	FTW_SLN		6	/* Sym link that names a nonexistent file.  */
+
+/*
+ * Flags for use as the 4th argument to nftw(3).  These may be ORed together.
+ */
+#define	FTW_PHYS	0x01	/* Physical walk, don't follow sym links.  */
+#define	FTW_MOUNT	0x02	/* The walk does not cross a mount point.  */
+#define	FTW_DEPTH	0x04	/* Subdirs visited before the dir itself. */
+#define	FTW_CHDIR	0x08	/* Change to a directory before reading it. */
+
+struct FTW {
+	int base;
+	int level;
+};
+
+__BEGIN_DECLS
+int	ftw(const char *, int (*)(const char *, const struct stat *, int), int);
+int	nftw(const char *, int (*)(const char *, const struct stat *, int,
+	    struct FTW *), int, int);
+__END_DECLS
+
+#endif	/* !_FTW_H */
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 91c3b00..6432c18 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -125,6 +125,8 @@
 extern int killpg(int pgrp, int sig);
 extern int sigaltstack(const stack_t *ss, stack_t *oss);
 
+extern void psiginfo(const siginfo_t* si, const char* message);
+extern void psignal(int signal_number, const char* message);
 
 __END_DECLS
 
diff --git a/libc/string/strerror.c b/libc/string/strerror.c
deleted file mode 100644
index b2ae001..0000000
--- a/libc/string/strerror.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*	$OpenBSD: strerror.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */
-/*
- * Copyright (c) 1988 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 <string.h>
-#include <limits.h>
-
-char *
-strerror(int num)
-{
-	static char buf[256];
-
-	(void)strerror_r(num, buf, sizeof(buf));
-	return (buf);
-}
diff --git a/libc/string/strerror_r.c b/libc/string/strerror_r.c
deleted file mode 100644
index 30841f3..0000000
--- a/libc/string/strerror_r.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
-/* Public Domain <marc@snafu.org> */
-
-#define sys_siglist	_sys_siglist
-
-#include <errno.h>
-#include <limits.h>
-#include <signal.h>
-#include <string.h>
-
-typedef struct {
-  int           code;
-  const char*   msg;
-} CodeString;
-
-static const char*
-__code_string_lookup( const CodeString*  strings,
-                      int                code )
-{
-    int  nn = 0;
-
-    for (;;)
-    {
-        if (strings[nn].msg == NULL)
-            break;
-
-        if (strings[nn].code == code)
-            return strings[nn].msg;
-
-        nn++;
-    }
-    return NULL;
-}
-
-
-static const CodeString  _sys_error_strings[] =
-{
-#define  __BIONIC_ERRDEF(x,y,z)  { x, z },
-#include <sys/_errdefs.h>
-    { 0, NULL }
-};
-
-static size_t
-__digits10(unsigned int num)
-{
-	size_t i = 0;
-
-	do {
-		num /= 10;
-		i++;
-	} while (num != 0);
-
-	return i;
-}
-
-static int
-__itoa(int num, int sign, char *buffer, size_t start, size_t end)
-{
-	size_t pos;
-	unsigned int a;
-	int neg;
-
-	if (sign && num < 0) {
-		a = -num;
-		neg = 1;
-	}
-	else {
-		a = num;
-		neg = 0;
-	}
-
-	pos = start + __digits10(a);
-	if (neg)
-	    pos++;
-
-	if (pos < end)
-		buffer[pos] = '\0';
-	else
-		return ERANGE;
-	pos--;
-	do {
-		buffer[pos] = (a % 10) + '0';
-		pos--;
-		a /= 10;
-	} while (a != 0);
-	if (neg)
-		buffer[pos] = '-';
-	return 0;
-}
-
-
-int
-strerror_r(int errnum, char *strerrbuf, size_t buflen)
-{
-    int          save_errno;
-    int          len, ret = 0;
-    const char*  msg;
-
-    save_errno = errno;
-    msg        = __code_string_lookup( _sys_error_strings, errnum );
-    if (msg != NULL) {
-        len = strlcpy(strerrbuf, msg, buflen);
-        if ((size_t)len >= buflen)
-            ret = ERANGE;
-    } else {
-        len = strlcpy(strerrbuf, "Unknown error: ", buflen);
-        if ((size_t)len >= buflen)
-            ret = ERANGE;
-        else {
-            int  ret = __itoa(errnum, 1, strerrbuf, len, buflen);
-
-            if (ret == 0)
-                ret = EINVAL;
-        }
-    }
-    return ret;
-}
-
-#if 0
-static const CodeString  _sys_signal_strings[] =
-{
-#define  SIGDEF(x,y,z)  { y, z },
-#include <sys/_sigdefs.h>
-};
-
-
-static int
-__num2string(int num, int sign, int setid, char *buf, size_t buflen,
-    char * list[], size_t max, const char *def)
-{
-	int ret = 0;
-	size_t len;
-
-	if (0 <= num && num < max) {
-		len = strlcpy(buf, def, buflen);
-		if (len >= buflen)
-			ret = ERANGE;
-	} else {
-		len = strlcpy(buf, def, buflen);
-		if (len >= buflen)
-			ret = ERANGE;
-		else {
-			ret = __itoa(num, sign, buf, len, buflen);
-			if (ret == 0)
-				ret = EINVAL;
-		}
-	}
-
-	return ret;
-}
-
-
-
-#define USIGPREFIX "Unknown signal: "
-
-char *
-__strsignal(int num, char *buf)
-{
-	__num2string(num, 0, 2, buf, NL_TEXTMAX, (char **)sys_siglist, NSIG,
-	    USIGPREFIX);
-	return buf;
-}
-#endif
diff --git a/libc/tools/generate-NOTICE.py b/libc/tools/generate-NOTICE.py
index 46152b9..b7d23f7 100755
--- a/libc/tools/generate-NOTICE.py
+++ b/libc/tools/generate-NOTICE.py
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 # Run with directory arguments from any directory, with no special setup required.
+# Or:
+# for i in libc libdl libm linker libstdc++ libthread_db ; do ./libc/tools/generate-NOTICE.py $i > $i/NOTICE ; done
 
 import ftplib
 import hashlib
diff --git a/libc/upstream-netbsd/extern.h b/libc/upstream-netbsd/extern.h
new file mode 100644
index 0000000..942e237
--- /dev/null
+++ b/libc/upstream-netbsd/extern.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BIONIC_NETBSD_EXTERN_H_included
+#define _BIONIC_NETBSD_EXTERN_H_included
+
+// Placeholder.
+
+#endif
diff --git a/libc/upstream-netbsd/libc/gen/ftw.c b/libc/upstream-netbsd/libc/gen/ftw.c
new file mode 100644
index 0000000..a7f6bbd
--- /dev/null
+++ b/libc/upstream-netbsd/libc/gen/ftw.c
@@ -0,0 +1,98 @@
+/* $NetBSD: ftw.c,v 1.1 2005/12/30 23:07:32 agc Exp $ */
+
+/*	From OpenBSD: ftw.c,v 1.2 2003/07/21 21:15:32 millert Exp 	*/
+
+/*
+ * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+#include <sys/cdefs.h>
+
+#ifndef lint
+__RCSID("$NetBSD: ftw.c,v 1.1 2005/12/30 23:07:32 agc Exp $");
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+#include <limits.h>
+
+int
+ftw(const char *path, int (*fn)(const char *, const struct stat *, int),
+    int nfds)
+{
+	/* LINTED */
+	char * const paths[2] = { __UNCONST(path), NULL };
+	FTSENT *cur;
+	FTS *ftsp;
+	int fnflag, error, sverrno;
+
+	/* XXX - nfds is currently unused */
+	if (nfds < 1 || nfds > OPEN_MAX) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	ftsp = fts_open(paths, FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
+	if (ftsp == NULL)
+		return (-1);
+	error = 0;
+	while ((cur = fts_read(ftsp)) != NULL) {
+		switch (cur->fts_info) {
+		case FTS_D:
+			fnflag = FTW_D;
+			break;
+		case FTS_DNR:
+			fnflag = FTW_DNR;
+			break;
+		case FTS_DP:
+			/* we only visit in preorder */
+			continue;
+		case FTS_F:
+		case FTS_DEFAULT:
+			fnflag = FTW_F;
+			break;
+		case FTS_NS:
+		case FTS_NSOK:
+		case FTS_SLNONE:
+			fnflag = FTW_NS;
+			break;
+		case FTS_SL:
+			fnflag = FTW_SL;
+			break;
+		case FTS_DC:
+			errno = ELOOP;
+			/* FALLTHROUGH */
+		default:
+			error = -1;
+			goto done;
+		}
+		error = fn(cur->fts_path, cur->fts_statp, fnflag);
+		if (error != 0)
+			break;
+	}
+done:
+	sverrno = errno;
+	if (fts_close(ftsp) != 0 && error == 0)
+		error = -1;
+	else
+		errno = sverrno;
+	return (error);
+}
diff --git a/libc/upstream-netbsd/libc/gen/nftw.c b/libc/upstream-netbsd/libc/gen/nftw.c
new file mode 100644
index 0000000..0e51342
--- /dev/null
+++ b/libc/upstream-netbsd/libc/gen/nftw.c
@@ -0,0 +1,114 @@
+/* $NetBSD */
+
+/*	From OpenBSD: nftw.c,v 1.2 2003/07/21 21:15:32 millert Exp 	*/
+
+/*
+ * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__RCSID("$NetBSD: nftw.c,v 1.1 2005/12/30 23:07:32 agc Exp $");
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+#include <limits.h>
+
+int
+nftw(const char *path, int (*fn)(const char *, const struct stat *, int,
+     struct FTW *), int nfds, int ftwflags)
+{
+	/* LINTED */
+	char * const paths[2] = { __UNCONST(path), NULL };
+	struct FTW f;
+	FTSENT *cur;
+	FTS *ftsp;
+	int ftsflags, fnflag, error, postorder, sverrno;
+
+	/* XXX - nfds is currently unused */
+	if (nfds < 1 || nfds > OPEN_MAX) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	ftsflags = FTS_COMFOLLOW;
+	if (!(ftwflags & FTW_CHDIR))
+		ftsflags |= FTS_NOCHDIR;
+	if (ftwflags & FTW_MOUNT)
+		ftsflags |= FTS_XDEV;
+	if (ftwflags & FTW_PHYS)
+		ftsflags |= FTS_PHYSICAL;
+	postorder = (ftwflags & FTW_DEPTH) != 0;
+	ftsp = fts_open(paths, ftsflags, NULL);
+	if (ftsp == NULL)
+		return (-1);
+	error = 0;
+	while ((cur = fts_read(ftsp)) != NULL) {
+		switch (cur->fts_info) {
+		case FTS_D:
+			if (postorder)
+				continue;
+			fnflag = FTW_D;
+			break;
+		case FTS_DNR:
+			fnflag = FTW_DNR;
+			break;
+		case FTS_DP:
+			if (!postorder)
+				continue;
+			fnflag = FTW_DP;
+			break;
+		case FTS_F:
+		case FTS_DEFAULT:
+			fnflag = FTW_F;
+			break;
+		case FTS_NS:
+		case FTS_NSOK:
+			fnflag = FTW_NS;
+			break;
+		case FTS_SL:
+			fnflag = FTW_SL;
+			break;
+		case FTS_SLNONE:
+			fnflag = FTW_SLN;
+			break;
+		case FTS_DC:
+			errno = ELOOP;
+			/* FALLTHROUGH */
+		default:
+			error = -1;
+			goto done;
+		}
+		f.base = cur->fts_pathlen - cur->fts_namelen;
+		f.level = cur->fts_level;
+		error = fn(cur->fts_path, cur->fts_statp, fnflag, &f);
+		if (error != 0)
+			break;
+	}
+done:
+	sverrno = errno;
+	(void) fts_close(ftsp);
+	errno = sverrno;
+	return (error);
+}
diff --git a/libc/upstream-netbsd/libc/gen/psignal.c b/libc/upstream-netbsd/libc/gen/psignal.c
new file mode 100644
index 0000000..4472be6
--- /dev/null
+++ b/libc/upstream-netbsd/libc/gen/psignal.c
@@ -0,0 +1,85 @@
+/*	$NetBSD: psignal.c,v 1.23 2012/03/13 21:13:36 christos Exp $	*/
+
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)psignal.c	8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: psignal.c,v 1.23 2012/03/13 21:13:36 christos Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <limits.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#ifdef __weak_alias
+__weak_alias(psignal,_psignal)
+#endif
+
+void
+psignal(int sig, const char *s)
+{
+	struct iovec *v;
+	struct iovec iov[4];
+	char buf[NL_TEXTMAX];
+
+	v = iov;
+	if (s && *s) {
+		v->iov_base = __UNCONST(s);
+		v->iov_len = strlen(s);
+		v++;
+		v->iov_base = __UNCONST(": ");
+		v->iov_len = 2;
+		v++;
+	}
+	v->iov_base = __UNCONST(__strsignal((int)sig, buf, sizeof(buf)));
+	v->iov_len = strlen(v->iov_base);
+	v++;
+	v->iov_base = __UNCONST("\n");
+	v->iov_len = 1;
+	(void)writev(STDERR_FILENO, iov, (int)((v - iov) + 1));
+}
+
+void
+psiginfo(const siginfo_t *si, const char *s)
+{
+	psignal(si->si_signo, s);
+}
diff --git a/libc/zoneinfo/zoneinfo.dat b/libc/zoneinfo/zoneinfo.dat
index 3d0b53c..4631c2c 100644
--- a/libc/zoneinfo/zoneinfo.dat
+++ b/libc/zoneinfo/zoneinfo.dat
Binary files differ
diff --git a/libc/zoneinfo/zoneinfo.idx b/libc/zoneinfo/zoneinfo.idx
index ac6bbc9..0e3b394 100644
--- a/libc/zoneinfo/zoneinfo.idx
+++ b/libc/zoneinfo/zoneinfo.idx
Binary files differ
diff --git a/libc/zoneinfo/zoneinfo.version b/libc/zoneinfo/zoneinfo.version
index f9e9d44..18a0c39 100644
--- a/libc/zoneinfo/zoneinfo.version
+++ b/libc/zoneinfo/zoneinfo.version
@@ -1 +1 @@
-2012e
+2012f
diff --git a/tests/Android.mk b/tests/Android.mk
index ae57d9b..be47585 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -22,34 +22,45 @@
     getcwd_test.cpp \
     pthread_test.cpp \
     regex_test.cpp \
+    string_test.cpp \
+    stubs_test.cpp \
+
+test_dynamic_ldflags = -Wl,--export-dynamic -Wl,-u,DlSymTestFunction
+test_dynamic_src_files = \
+    dlopen_test.cpp \
 
 # Build for the device (with bionic's .so). Run with:
 #   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
 include $(CLEAR_VARS)
 LOCAL_MODULE := bionic-unit-tests
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_LDFLAGS += $(test_dynamic_ldflags)
+LOCAL_SHARED_LIBRARIES += libdl
+LOCAL_SRC_FILES := $(test_src_files) $(test_dynamic_src_files)
 include $(BUILD_NATIVE_TEST)
 
 # Build for the device (with bionic's .a). Run with:
 #   adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static
 include $(CLEAR_VARS)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_STATIC_LIBRARIES += libstlport_static libstdc++ libm libc
 LOCAL_MODULE := bionic-unit-tests-static
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_STATIC_LIBRARIES += libstlport_static libstdc++ libm libc
 include $(BUILD_NATIVE_TEST)
 
 # Build for the host (with glibc).
 # Note that this will build against glibc, so it's not useful for testing
 # bionic's implementation, but it does let you use glibc as a reference
 # implementation for testing the tests themselves.
+ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
 include $(CLEAR_VARS)
 LOCAL_MODULE := bionic-unit-tests-glibc
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_LDFLAGS += -lpthread
-LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_LDFLAGS += -lpthread -ldl
+LOCAL_LDFLAGS += $(test_dynamic_ldflags)
+LOCAL_SRC_FILES := $(test_src_files) $(test_dynamic_src_files)
 include $(BUILD_HOST_NATIVE_TEST)
+endif
 
 endif # !BUILD_TINY_ANDROID
diff --git a/tests/dlopen_test.cpp b/tests/dlopen_test.cpp
new file mode 100644
index 0000000..c290b4d
--- /dev/null
+++ b/tests/dlopen_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <dlfcn.h>
+
+static bool gCalled = false;
+extern "C" void DlSymTestFunction() {
+  gCalled = true;
+}
+
+TEST(dlopen, dlsym_in_self) {
+  void* self = dlopen(NULL, RTLD_NOW);
+  ASSERT_TRUE(self != NULL);
+
+  void* sym = dlsym(self, "DlSymTestFunction");
+  ASSERT_TRUE(sym != NULL);
+
+  void (*function)() = reinterpret_cast<void(*)()>(sym);
+
+  gCalled = false;
+  function();
+  ASSERT_TRUE(gCalled);
+}
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
new file mode 100644
index 0000000..ea1491c
--- /dev/null
+++ b/tests/string_test.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <string.h>
+
+TEST(string, strerror) {
+  // Valid.
+  ASSERT_STREQ("Success", strerror(0));
+  ASSERT_STREQ("Operation not permitted", strerror(1));
+
+  // Invalid.
+  ASSERT_STREQ("Unknown error 4294967295", strerror(-1));
+  ASSERT_STREQ("Unknown error 1234", strerror(1234));
+}
+
+void* ConcurrentStrErrorFn(void* arg) {
+  bool equal = (strcmp("Unknown error 2002", strerror(2002)) == 0);
+  return reinterpret_cast<void*>(equal);
+}
+
+#if __BIONIC__ // glibc's strerror isn't thread safe, only its strsignal.
+TEST(string, strerror_concurrent) {
+  const char* strerror1001 = strerror(1001);
+  ASSERT_STREQ("Unknown error 1001", strerror1001);
+
+  pthread_t t;
+  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentStrErrorFn, NULL));
+  void* result;
+  ASSERT_EQ(0, pthread_join(t, &result));
+  ASSERT_TRUE(static_cast<bool>(result));
+
+  ASSERT_STREQ("Unknown error 1001", strerror1001);
+}
+#endif
+
+#if __BIONIC__ // glibc's strerror_r doesn't even have the same signature as the POSIX one.
+TEST(string, strerror_r) {
+  char buf[256];
+
+  // Valid.
+  ASSERT_EQ(0, strerror_r(0, buf, sizeof(buf)));
+  ASSERT_STREQ("Success", buf);
+  ASSERT_EQ(0, strerror_r(1, buf, sizeof(buf)));
+  ASSERT_STREQ("Operation not permitted", buf);
+
+  // Invalid.
+  ASSERT_EQ(0, strerror_r(-1, buf, sizeof(buf)));
+  ASSERT_STREQ("Unknown error 4294967295", buf);
+  ASSERT_EQ(0, strerror_r(1234, buf, sizeof(buf)));
+  ASSERT_STREQ("Unknown error 1234", buf);
+
+  // Buffer too small.
+  ASSERT_EQ(-1, strerror_r(0, buf, 2));
+  ASSERT_EQ(ERANGE, errno);
+}
+#endif
+
+TEST(string, strsignal) {
+  // A regular signal.
+  ASSERT_STREQ("Hangup", strsignal(1));
+
+  // A real-time signal.
+#ifdef __GLIBC__ // glibc reserves real-time signals for internal use, and doesn't count those.
+  ASSERT_STREQ("Real-time signal 14", strsignal(48));
+#else
+  ASSERT_STREQ("Real-time signal 16", strsignal(48));
+#endif
+
+  // Errors.
+  ASSERT_STREQ("Unknown signal -1", strsignal(-1)); // Too small.
+  ASSERT_STREQ("Unknown signal 0", strsignal(0)); // Still too small.
+  ASSERT_STREQ("Unknown signal 1234", strsignal(1234)); // Too large.
+}
+
+void* ConcurrentStrSignalFn(void* arg) {
+  bool equal = (strcmp("Unknown signal 2002", strsignal(2002)) == 0);
+  return reinterpret_cast<void*>(equal);
+}
+
+TEST(string, strsignal_concurrent) {
+  const char* strsignal1001 = strsignal(1001);
+  ASSERT_STREQ("Unknown signal 1001", strsignal1001);
+
+  pthread_t t;
+  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentStrSignalFn, NULL));
+  void* result;
+  ASSERT_EQ(0, pthread_join(t, &result));
+  ASSERT_TRUE(static_cast<bool>(result));
+
+  ASSERT_STREQ("Unknown signal 1001", strsignal1001);
+}
diff --git a/tests/stubs_test.cpp b/tests/stubs_test.cpp
new file mode 100644
index 0000000..d2d0ad8
--- /dev/null
+++ b/tests/stubs_test.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <pwd.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#if __BIONIC__
+
+#define CHECK_GETPWNAM_FOR(username, uid, uid_type) \
+    SCOPED_TRACE(username); \
+    ASSERT_NO_FATAL_FAILURE(check_getpwnam(username, uid, uid_type));
+
+typedef enum {
+  TYPE_SYSTEM,
+  TYPE_APP
+} uid_type_t;
+
+static void check_getpwnam(const char* username, int uid, uid_type_t uid_type) {
+  errno = 0;
+  passwd* pwd = getpwuid(uid);
+  ASSERT_TRUE(pwd != NULL);
+  ASSERT_EQ(errno, 0);
+  EXPECT_STREQ(username, pwd->pw_name);
+  EXPECT_EQ(uid, pwd->pw_uid);
+  EXPECT_EQ(uid, pwd->pw_gid);
+
+  if (uid_type == TYPE_SYSTEM) {
+    EXPECT_STREQ("/", pwd->pw_dir);
+  } else if (uid_type == TYPE_APP) {
+    EXPECT_STREQ("/data", pwd->pw_dir);
+  }
+
+  EXPECT_STREQ("/system/bin/sh", pwd->pw_shell);
+}
+
+TEST(getpwnam, system_id_root) {
+  CHECK_GETPWNAM_FOR("root", 0, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, system_id_system) {
+  CHECK_GETPWNAM_FOR("system", 1000, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, app_id_radio) {
+  CHECK_GETPWNAM_FOR("radio", 1001, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, app_id_nobody) {
+  CHECK_GETPWNAM_FOR("nobody", 9999, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, app_id_all_a0) {
+  CHECK_GETPWNAM_FOR("all_a0", 50000, TYPE_APP);
+}
+
+TEST(getpwnam, app_id_u1_a40000) {
+  CHECK_GETPWNAM_FOR("u1_a40000", 150000, TYPE_APP);
+}
+
+TEST(getpwnam, app_id_u0_a0) {
+  CHECK_GETPWNAM_FOR("u0_a0", 10000, TYPE_APP);
+}
+
+TEST(getpwnam, app_id_u0_a1234) {
+  CHECK_GETPWNAM_FOR("u0_a1234", 11234, TYPE_APP);
+}
+
+TEST(getpwnam, app_id_u0_a9999) {
+  CHECK_GETPWNAM_FOR("u0_a9999", 19999, TYPE_APP);
+}
+
+// nonsensical, but expected
+TEST(getpwnam, app_id_u1_root) {
+  CHECK_GETPWNAM_FOR("u1_root", 100000, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, app_id_u1_radio) {
+  CHECK_GETPWNAM_FOR("u1_radio", 101001, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, app_id_u1_a0) {
+  CHECK_GETPWNAM_FOR("u1_a0", 110000, TYPE_APP);
+}
+
+TEST(getpwnam, app_id_u1_i0) {
+  CHECK_GETPWNAM_FOR("u1_i0", 199000, TYPE_APP);
+}
+
+#endif /* __BIONIC__ */