Merge "Load namespace configuration from ld.config.txt"
diff --git a/libc/SECCOMP_WHITELIST.TXT b/libc/SECCOMP_WHITELIST.TXT
index adbb176..f0e99e3 100644
--- a/libc/SECCOMP_WHITELIST.TXT
+++ b/libc/SECCOMP_WHITELIST.TXT
@@ -97,3 +97,6 @@
 
 # b/36435222
 int	remap_file_pages(void *addr, size_t size, int prot, size_t pgoff, int flags)	arm,x86,mips
+
+# b/36449658
+int	rename(const char *oldpath, const char *newpath)	arm,x86,mips
diff --git a/libc/include/bits/posix_limits.h b/libc/include/bits/posix_limits.h
index c498c69..db09bd7 100644
--- a/libc/include/bits/posix_limits.h
+++ b/libc/include/bits/posix_limits.h
@@ -31,20 +31,22 @@
 
 #include <sys/cdefs.h>
 
+#define __BIONIC_POSIX_FEATURE_SINCE(level) (((__ANDROID_API__) >= level) ? 200809L : -1)
+
 /* Any constant values here other than -1 or 200809L are explicitly specified by POSIX.1-2008. */
 /* Keep this list sorted by name. */
-#define _POSIX_ADVISORY_INFO        200809L
+#define _POSIX_ADVISORY_INFO __BIONIC_POSIX_FEATURE_SINCE(23) /* posix_memadvise arrived late. */
 #define _POSIX_AIO_LISTIO_MAX       2
 #define _POSIX_AIO_MAX              1
 #define _POSIX_ARG_MAX              4096
 #define _POSIX_ASYNCHRONOUS_IO      -1  /* not implemented */
-#define _POSIX_BARRIERS             200809L
+#define _POSIX_BARRIERS __BIONIC_POSIX_FEATURE_SINCE(24)
 #define _POSIX_CHILD_MAX            25
 #define _POSIX_CHOWN_RESTRICTED     1  /* yes, chown requires appropriate privileges */
 #define _POSIX_CLOCK_SELECTION      200809L
 #define _POSIX_CPUTIME              0  /* Use sysconf to detect support at runtime. */
 #define _POSIX_DELAYTIMER_MAX       32
-#define _POSIX_FSYNC                200809L  /* fdatasync() supported */
+#define _POSIX_FSYNC 200809L
 #define _POSIX_HOST_NAME_MAX        255
 #define _POSIX_IPV6                 200809L
 #define _POSIX_JOB_CONTROL          1  /* job control is a Linux feature */
@@ -53,8 +55,8 @@
 #define _POSIX_MAPPED_FILES         200809L  /* mmap-ed files supported */
 #define _POSIX_MAX_CANON            255
 #define _POSIX_MAX_INPUT            255
-#define _POSIX_MEMLOCK              200809L
-#define _POSIX_MEMLOCK_RANGE        200809L
+#define _POSIX_MEMLOCK __BIONIC_POSIX_FEATURE_SINCE(17) /* mlockall. */
+#define _POSIX_MEMLOCK_RANGE        200809L /* mlock. */
 #define _POSIX_MEMORY_PROTECTION    200809L
 #define _POSIX_MESSAGE_PASSING      -1  /* not implemented */
 #define _POSIX_MONOTONIC_CLOCK      0  /* the monotonic clock may be available; ask sysconf */
@@ -81,7 +83,7 @@
 #define _POSIX_SHELL                1   /* system() supported */
 #define _POSIX_SIGQUEUE_MAX         32
 #define _POSIX_SPAWN                -1  /* not implemented */
-#define _POSIX_SPIN_LOCKS           200809L
+#define _POSIX_SPIN_LOCKS __BIONIC_POSIX_FEATURE_SINCE(24)
 #define _POSIX_SPORADIC_SERVER      -1  /* not implemented */
 #define _POSIX_SSIZE_MAX            32767
 #define _POSIX_STREAM_MAX           8
@@ -103,7 +105,7 @@
 #define _POSIX_THREAD_SAFE_FUNCTIONS 200809L
 #define _POSIX_THREAD_SPORADIC_SERVER -1  /* not implemented */
 #define _POSIX_THREAD_THREADS_MAX   64
-#define _POSIX_TIMEOUTS             200809L
+#define _POSIX_TIMEOUTS __BIONIC_POSIX_FEATURE_SINCE(21) /* pthread_mutex_timedlock arrived late. */
 #define _POSIX_TIMERS               200809L  /* Posix timers are supported */
 #define _POSIX_TIMER_MAX            32
 #define _POSIX_TRACE                -1  /* not implemented */
diff --git a/libc/include/bits/pthread_types.h b/libc/include/bits/pthread_types.h
index 7fc379b..a173e3c 100644
--- a/libc/include/bits/pthread_types.h
+++ b/libc/include/bits/pthread_types.h
@@ -44,6 +44,7 @@
 #endif
 } pthread_attr_t;
 
+#if __ANDROID_API__ >= __ANDROID_API_N__
 typedef struct {
 #if defined(__LP64__)
   int64_t __private[4];
@@ -51,8 +52,11 @@
   int32_t __private[8];
 #endif
 } pthread_barrier_t;
+#endif
 
+#if __ANDROID_API__ >= __ANDROID_API_N__
 typedef int pthread_barrierattr_t;
+#endif
 
 typedef struct {
 #if defined(__LP64__)
@@ -88,6 +92,7 @@
 
 typedef long pthread_rwlockattr_t;
 
+#if __ANDROID_API__ >= __ANDROID_API_N__
 typedef struct {
 #if defined(__LP64__)
   int64_t __private;
@@ -95,6 +100,7 @@
   int32_t __private[2];
 #endif
 } pthread_spinlock_t;
+#endif
 
 typedef long pthread_t;
 
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 20fd566..ae4fdce 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -69,7 +69,9 @@
 
 #define PTHREAD_ONCE_INIT 0
 
+#if __ANDROID_API__ >= __ANDROID_API_N__
 #define PTHREAD_BARRIER_SERIAL_THREAD -1
+#endif
 
 #if defined(__LP64__)
 #define PTHREAD_STACK_MIN (4 * PAGE_SIZE)
@@ -178,23 +180,29 @@
 int pthread_rwlock_unlock(pthread_rwlock_t* _Nonnull);
 int pthread_rwlock_wrlock(pthread_rwlock_t* _Nonnull);
 
+#if __ANDROID_API__ >= __ANDROID_API_N__
 int pthread_barrierattr_init(pthread_barrierattr_t* _Nonnull attr) __INTRODUCED_IN(24);
 int pthread_barrierattr_destroy(pthread_barrierattr_t* _Nonnull attr) __INTRODUCED_IN(24);
 int pthread_barrierattr_getpshared(const pthread_barrierattr_t* _Nonnull attr,
                                    int* _Nonnull pshared) __INTRODUCED_IN(24);
 int pthread_barrierattr_setpshared(pthread_barrierattr_t* _Nonnull attr, int pshared)
   __INTRODUCED_IN(24);
+#endif
 
+#if __ANDROID_API__ >= __ANDROID_API_N__
 int pthread_barrier_init(pthread_barrier_t* _Nonnull, const pthread_barrierattr_t*, unsigned)
   __INTRODUCED_IN(24);
 int pthread_barrier_destroy(pthread_barrier_t* _Nonnull) __INTRODUCED_IN(24);
 int pthread_barrier_wait(pthread_barrier_t* _Nonnull) __INTRODUCED_IN(24);
+#endif
 
+#if __ANDROID_API__ >= __ANDROID_API_N__
 int pthread_spin_destroy(pthread_spinlock_t* _Nonnull) __INTRODUCED_IN(24);
 int pthread_spin_init(pthread_spinlock_t* _Nonnull, int) __INTRODUCED_IN(24);
 int pthread_spin_lock(pthread_spinlock_t* _Nonnull) __INTRODUCED_IN(24);
 int pthread_spin_trylock(pthread_spinlock_t* _Nonnull) __INTRODUCED_IN(24);
 int pthread_spin_unlock(pthread_spinlock_t* _Nonnull) __INTRODUCED_IN(24);
+#endif
 
 pthread_t pthread_self(void) __attribute_const__;
 
diff --git a/libc/seccomp/arm64_policy.cpp b/libc/seccomp/arm64_policy.cpp
index 0bf85a3..5eee365 100644
--- a/libc/seccomp/arm64_policy.cpp
+++ b/libc/seccomp/arm64_policy.cpp
@@ -5,7 +5,7 @@
 
 #include "seccomp_bpfs.h"
 const sock_filter arm64_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5, 0, 25),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5, 0, 26),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 13, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 7, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 3, 0),
diff --git a/libc/seccomp/arm_policy.cpp b/libc/seccomp/arm_policy.cpp
index 73fdda4..9f8b9fe 100644
--- a/libc/seccomp/arm_policy.cpp
+++ b/libc/seccomp/arm_policy.cpp
@@ -5,7 +5,7 @@
 
 #include "seccomp_bpfs.h"
 const sock_filter arm_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 123),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 124),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 143, 61, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 74, 31, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 15, 0),
@@ -23,7 +23,7 @@
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 109, 108), //ptrace
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 1, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 107, 106), //access
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 106, 105), //sync|kill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 39, 106, 105), //sync|kill|rename
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 7, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 3, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 1, 0),
diff --git a/libc/seccomp/mips64_policy.cpp b/libc/seccomp/mips64_policy.cpp
index 9439922..92f175a 100644
--- a/libc/seccomp/mips64_policy.cpp
+++ b/libc/seccomp/mips64_policy.cpp
@@ -5,7 +5,7 @@
 
 #include "seccomp_bpfs.h"
 const sock_filter mips64_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 77),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 78),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5168, 39, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 19, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5034, 9, 0),
diff --git a/libc/seccomp/mips_policy.cpp b/libc/seccomp/mips_policy.cpp
index 3ded9f7..01323ce 100644
--- a/libc/seccomp/mips_policy.cpp
+++ b/libc/seccomp/mips_policy.cpp
@@ -5,7 +5,7 @@
 
 #include "seccomp_bpfs.h"
 const sock_filter mips_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4001, 0, 107),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4001, 0, 108),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4131, 53, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4064, 27, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4036, 13, 0),
@@ -25,7 +25,7 @@
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4054, 7, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4045, 3, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4041, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4038, 88, 87), //sync|kill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4039, 88, 87), //sync|kill|rename
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4044, 87, 86), //dup|pipe|times
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4049, 1, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4048, 85, 84), //brk|setgid|getgid
diff --git a/libc/seccomp/x86_64_policy.cpp b/libc/seccomp/x86_64_policy.cpp
index e1f0aa3..69756c6 100644
--- a/libc/seccomp/x86_64_policy.cpp
+++ b/libc/seccomp/x86_64_policy.cpp
@@ -5,7 +5,7 @@
 
 #include "seccomp_bpfs.h"
 const sock_filter x86_64_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 79),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 80),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 157, 39, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 72, 19, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 32, 9, 0),
diff --git a/libc/seccomp/x86_policy.cpp b/libc/seccomp/x86_policy.cpp
index 77fe208..d9ee17b 100644
--- a/libc/seccomp/x86_policy.cpp
+++ b/libc/seccomp/x86_policy.cpp
@@ -5,7 +5,7 @@
 
 #include "seccomp_bpfs.h"
 const sock_filter x86_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 109),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 110),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 55, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 27, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 13, 0),
@@ -25,7 +25,7 @@
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 54, 7, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 3, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 90, 89), //sync|kill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 39, 90, 89), //sync|kill|rename
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 89, 88), //dup|pipe|times
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 1, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 87, 86), //brk
diff --git a/libc/tools/genseccomp.py b/libc/tools/genseccomp.py
index d9e0819..a8e551e 100755
--- a/libc/tools/genseccomp.py
+++ b/libc/tools/genseccomp.py
@@ -149,13 +149,14 @@
       bpf[i] = statement.format(fail=str(len(bpf) - i),
                                 allow=str(len(bpf) - i - 1))
 
-  # Add check that we aren't off the bottom of the syscalls
-  bpf.insert(0, BPF_JGE.format(ranges[0].begin, 0, str(len(bpf))) + ',')
 
   # Add the allow calls at the end. If the syscall is not matched, we will
   # continue. This allows the user to choose to match further syscalls, and
   # also to choose the action when we want to block
   bpf.append(BPF_ALLOW + ",")
+
+  # Add check that we aren't off the bottom of the syscalls
+  bpf.insert(0, BPF_JGE.format(ranges[0].begin, 0, str(len(bpf))) + ',')
   return bpf
 
 
diff --git a/libc/tools/test_genseccomp.py b/libc/tools/test_genseccomp.py
index 19672a1..73f768d 100755
--- a/libc/tools/test_genseccomp.py
+++ b/libc/tools/test_genseccomp.py
@@ -113,13 +113,13 @@
   def test_convert_ranges_to_bpf(self):
     ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
     bpf = genseccomp.convert_ranges_to_bpf(ranges)
-    self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 1),',
+    self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 2),',
                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0), //a|b',
                             'BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),'])
 
     ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
     bpf = genseccomp.convert_ranges_to_bpf(ranges)
-    self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 3),',
+    self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 4),',
                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),',
                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 2, 1), //a',
                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 1, 0), //b',
@@ -165,7 +165,7 @@
 
     #include "seccomp_bpfs.h"
     const sock_filter arm_filter[] = {
-    BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 0, 3),
+    BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 0, 4),
     BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 1, 0),
     BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 2, 1), //read
     BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 141, 1, 0), //_llseek
diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
index a2e8da6..c5932bc 100644
--- a/libc/zoneinfo/tzdata
+++ b/libc/zoneinfo/tzdata
Binary files differ
diff --git a/linker/Android.bp b/linker/Android.bp
index 2351e71..23138cf 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -40,35 +40,29 @@
             srcs: ["arch/arm/begin.S"],
 
             cflags: ["-D__work_around_b_24465209__"],
-            ldflags: ["-Wl,-dynamic-linker,/system/bin/linker"],
         },
         arm64: {
             srcs: ["arch/arm64/begin.S"],
-            ldflags: ["-Wl,-dynamic-linker,/system/bin/linker64"],
         },
         x86: {
             srcs: ["arch/x86/begin.c"],
 
             cflags: ["-D__work_around_b_24465209__"],
-            ldflags: ["-Wl,-dynamic-linker,/system/bin/linker"],
         },
         x86_64: {
             srcs: ["arch/x86_64/begin.S"],
-            ldflags: ["-Wl,-dynamic-linker,/system/bin/linker64"],
         },
         mips: {
             srcs: [
                 "arch/mips/begin.S",
                 "linker_mips.cpp",
             ],
-            ldflags: ["-Wl,-dynamic-linker,/system/bin/linker"],
         },
         mips64: {
             srcs: [
                 "arch/mips64/begin.S",
                 "linker_mips.cpp",
             ],
-            ldflags: ["-Wl,-dynamic-linker,/system/bin/linker64"],
         },
     },
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 27b812d..140f01c 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1676,6 +1676,8 @@
     root = root->get_local_group_root();
   }
 
+  ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
+
   if (!root->can_unload()) {
     TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
     return;
@@ -2002,6 +2004,7 @@
               const char* sym_ver,
               const void* caller_addr,
               void** symbol) {
+  ScopedTrace trace("dlsym");
 #if !defined(__LP64__)
   if (handle == nullptr) {
     DL_ERR("dlsym failed: library handle is null");
@@ -2077,6 +2080,7 @@
 }
 
 int do_dlclose(void* handle) {
+  ScopedTrace trace("dlclose");
   ProtectedDataGuard guard;
   soinfo* si = soinfo_from_handle(handle);
   if (si == nullptr) {
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 6870c03..40f82a1 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -479,26 +479,20 @@
 extern "C" ElfW(Addr) __linker_init(void* raw_args) {
   KernelArgumentBlock args(raw_args);
 
-  ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
+  // AT_BASE is set to 0 in the case when linker is run by iself
+  // so in order to link the linker it needs to calcuate AT_BASE
+  // using information at hand. The trick below takes advantage
+  // of the fact that the value of linktime_addr before relocations
+  // are run is an offset and this can be used to calculate AT_BASE.
+  static uintptr_t linktime_addr = reinterpret_cast<uintptr_t>(&linktime_addr);
+  ElfW(Addr) linker_addr = reinterpret_cast<uintptr_t>(&linktime_addr) - linktime_addr;
+
   ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
   ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
   ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
 
   soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);
 
-  // If the linker is not acting as PT_INTERP entry_point is equal to
-  // _start. Which means that the linker is running as an executable and
-  // already linked by PT_INTERP.
-  //
-  // This happens when user tries to run 'adb shell /system/bin/linker'
-  // see also https://code.google.com/p/android/issues/detail?id=63174
-  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
-    __libc_format_fd(STDOUT_FILENO,
-                     "This is %s, the helper program for dynamic executables.\n",
-                     args.argv[0]);
-    exit(0);
-  }
-
   linker_so.base = linker_addr;
   linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
   linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
@@ -545,6 +539,19 @@
   // Initialize the linker's own global variables
   linker_so.call_constructors();
 
+  // If the linker is not acting as PT_INTERP entry_point is equal to
+  // _start. Which means that the linker is running as an executable and
+  // already linked by PT_INTERP.
+  //
+  // This happens when user tries to run 'adb shell /system/bin/linker'
+  // see also https://code.google.com/p/android/issues/detail?id=63174
+  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
+    __libc_format_fd(STDOUT_FILENO,
+                     "This is %s, the helper program for dynamic executables.\n",
+                     args.argv[0]);
+    exit(0);
+  }
+
   // Initialize static variables. Note that in order to
   // get correct libdl_info we need to call constructors
   // before get_libdl_info().
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 15f2502..1d59dbb 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -426,7 +426,8 @@
   if (!constructors_called) {
     return;
   }
-  TRACE("\"%s\": calling destructors", get_realpath());
+
+  ScopedTrace trace((std::string("calling destructors: ") + get_realpath()).c_str());
 
   // DT_FINI_ARRAY must be parsed in reverse order.
   call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true, get_realpath());
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 0f24170..ad8444e 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1256,7 +1256,7 @@
 // Bionic specific tests
 #if defined(__BIONIC__)
 
-#if defined(__arm__) || defined(__i386__)
+#if defined(__arm__)
 const llvm::ELF::Elf32_Dyn* to_dynamic_table(const char* p) {
   return reinterpret_cast<const llvm::ELF::Elf32_Dyn*>(p);
 }
@@ -1320,7 +1320,7 @@
   validate_compatibility_of_native_library(path, elf);
 }
 
-// This is a test for app compatibility workaround for arm and x86 apps
+// This is a test for app compatibility workaround for arm apps
 // affected by http://b/24465209
 TEST(dlext, compat_elf_hash_and_relocation_tables) {
   validate_compatibility_of_native_library("libc.so");
@@ -1332,7 +1332,7 @@
   validate_compatibility_of_native_library("libjnigraphics.so");
 }
 
-#endif //  defined(__arm__) || defined(__i386__)
+#endif //  defined(__arm__)
 
 TEST(dlfcn, dt_runpath_absolute_path) {
   std::string libpath = get_testlib_root() + "/libtest_dt_runpath_d.so";
diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp
index afd9e7f..bb58ae4 100644
--- a/tests/stack_unwinding_test.cpp
+++ b/tests/stack_unwinding_test.cpp
@@ -90,15 +90,20 @@
 }
 
 static void verify_unwind_data(const UnwindData& unwind_data) {
-  EXPECT_GT(unwind_data.handler_frame_count, unwind_data.expected_frame_count);
+  // In order to avoid a false positive, the caller must have at least 2 frames
+  // outside of the signal handler. This avoids a case where the only frame
+  // right after the signal handler winds up being garbage.
+  EXPECT_GT(unwind_data.handler_frame_count, unwind_data.expected_frame_count + 1);
+
   EXPECT_EQ(unwind_data.handler_frame_count + 1, unwind_data.handler_one_deeper_frame_count);
 }
 
-TEST(stack_unwinding, unwind_through_signal_frame) {
+static void noinline UnwindTest() {
   g_unwind_data = {};
-  ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler);
 
   _Unwind_Backtrace(FrameCounter, &g_unwind_data.expected_frame_count);
+  ASSERT_LE(2, g_unwind_data.expected_frame_count)
+      << "The current call must contain at least 2 frames for the test to be valid.";
 
   ASSERT_EQ(0, kill(getpid(), SIGUSR1));
   while (!g_unwind_data.signal_handler_complete) {}
@@ -106,14 +111,15 @@
   verify_unwind_data(g_unwind_data);
 }
 
+TEST(stack_unwinding, unwind_through_signal_frame) {
+  ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler);
+
+  UnwindTest();
+}
+
 // On LP32, the SA_SIGINFO flag gets you __restore_rt instead of __restore.
 TEST(stack_unwinding, unwind_through_signal_frame_SA_SIGINFO) {
-  g_unwind_data = {};
   ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler, SA_SIGINFO);
 
-  _Unwind_Backtrace(FrameCounter, &g_unwind_data.expected_frame_count);
-  ASSERT_EQ(0, kill(getpid(), SIGUSR1));
-  while (!g_unwind_data.signal_handler_complete) {}
-
-  verify_unwind_data(g_unwind_data);
+  UnwindTest();
 }